feat(api): Add payments with Polar.sh (#264)

## Description
<!-- Briefly describe the purpose and scope of your changes -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a new subscription API endpoint for managing subscriptions
and products.
- Enhanced subscription management with new entities and
functionalities.
- Added functionality to retrieve current timestamps in both local and
UTC formats.
- Added Polar.sh integration with customer portal and checkout session
creation APIs.

- **Refactor**
- Redesigned team details to now present members and subscription
information instead of a plan type.
  - Enhanced member management by incorporating role assignments.
- Streamlined user data handling and removed legacy subscription event
logic.
  - Simplified error handling in actor functions for better clarity.
  - Updated plan types and UI labels to reflect new subscription tiers.
  - Improved database indexing for Steam user data.

- **Chores**
- Updated the database schema with new tables and fields to support
subscription, team, and member enhancements.
  - Extended identifier prefixes to broaden system integration.
- Added new secrets related to pricing plans in infrastructure
configuration.
  - Configured API and auth routing with new domain and routing rules.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Wanjohi
2025-04-18 14:24:19 +03:00
committed by GitHub
parent 76d27e4708
commit 47e61599bb
40 changed files with 3304 additions and 425 deletions

View File

@@ -109,43 +109,34 @@ export function assertActor<T extends Actor["type"]>(type: T) {
return actor as Extract<Actor, { type: T }>;
}
/**
* Returns the current actor's team ID.
*
* @returns The team ID associated with the current actor.
* @throws {VisibleError} If the current actor does not have a {@link teamID} property.
*/
export function useTeam() {
const actor = useActor();
if ("teamID" in actor.properties) return actor.properties.teamID;
throw new Error(`Expected actor to have teamID`);
}
export function useMachine() {
const actor = useActor();
if ("machineID" in actor.properties) return actor.properties.fingerprint;
throw new Error(`Expected actor to have fingerprint`);
throw new VisibleError(
"authentication",
ErrorCodes.Authentication.UNAUTHORIZED,
`Expected actor to have teamID`
);
}
/**
* Asserts that the current user possesses the specified flag.
* Returns the fingerprint of the current actor if the actor has a machine identity.
*
* This function executes a database transaction that queries the user table for the current user's flags.
* If the flags are missing, it throws a {@link VisibleError} with the code {@link ErrorCodes.Validation.MISSING_REQUIRED_FIELD}
* and a message indicating that the required flag is absent.
*
* @param flag - The name of the user flag to verify.
*
* @throws {VisibleError} If the user's flag is missing.
* @returns The fingerprint of the current machine actor.
* @throws {VisibleError} If the current actor does not have a machine identity.
*/
export async function assertUserFlag(flag: keyof UserFlags) {
return useTransaction((tx) =>
tx
.select({ flags: userTable.flags })
.from(userTable)
.where(eq(userTable.id, useUserID()))
.then((rows) => {
const flags = rows[0]?.flags;
if (!flags)
throw new VisibleError(
"not_found",
ErrorCodes.Validation.MISSING_REQUIRED_FIELD,
"Actor does not have " + flag + " flag",
);
}),
export function useMachine() {
const actor = useActor();
if ("machineID" in actor.properties) return actor.properties.fingerprint;
throw new VisibleError(
"authentication",
ErrorCodes.Authentication.UNAUTHORIZED,
`Expected actor to have fingerprint`
);
}