diff --git a/apps/dashboard/src/generated/bundled-type-definitions.ts b/apps/dashboard/src/generated/bundled-type-definitions.ts new file mode 100644 index 000000000..e2b053f63 --- /dev/null +++ b/apps/dashboard/src/generated/bundled-type-definitions.ts @@ -0,0 +1,91 @@ +// This file is auto-generated by scripts/bundle-type-definitions.ts +// Do not edit manually - changes will be overwritten +// Last generated: 2026-02-13T17:47:51.287Z + +export type TypeDefinitionFile = { + path: string, + content: string, +}; + +export const BUNDLED_TYPE_DEFINITIONS: TypeDefinitionFile[] = [ + { + "path": "index.ts", + "content": "export {\n StackAdminApp, StackClientApp,\n StackServerApp\n} from \"./apps\";\nexport type {\n StackAdminAppConstructor,\n StackAdminAppConstructorOptions,\n StackClientAppConstructor,\n StackClientAppConstructorOptions,\n StackClientAppJson,\n StackServerAppConstructor,\n StackServerAppConstructorOptions\n} from \"./apps\";\n\nexport type {\n EmailOutboxListOptions,\n EmailOutboxListResult,\n EmailOutboxUpdateOptions\n} from \"./apps/interfaces/admin-app\";\n\nexport type {\n ProjectConfig\n} from \"./project-configs\";\n\nexport type {\n InternalApiKey,\n InternalApiKeyBase,\n InternalApiKeyBaseCrudRead,\n InternalApiKeyCreateOptions,\n InternalApiKeyFirstView\n} from \"./internal-api-keys\";\n\nexport {\n stackAppInternalsSymbol\n} from \"./common\";\nexport type {\n GetCurrentUserOptions,\n /** @deprecated Use GetCurrentUserOptions instead */\n GetCurrentUserOptions as GetUserOptions,\n HandlerUrls,\n OAuthScopesOnSignIn\n} from \"./common\";\n\nexport type {\n Connection,\n OAuthConnection\n} from \"./connected-accounts\";\n\nexport type {\n ContactChannel,\n ServerContactChannel\n} from \"./contact-channels\";\n\nexport type {\n AdminEmailOutbox,\n AdminEmailOutboxRecipient,\n AdminEmailOutboxSimpleStatus,\n AdminEmailOutboxStatus,\n AdminSentEmail\n} from \"./email\";\n\nexport type {\n AdminProjectPermission,\n AdminProjectPermissionDefinition,\n AdminProjectPermissionDefinitionCreateOptions,\n AdminProjectPermissionDefinitionUpdateOptions, AdminTeamPermission,\n AdminTeamPermissionDefinition,\n AdminTeamPermissionDefinitionCreateOptions,\n AdminTeamPermissionDefinitionUpdateOptions\n} from \"./permissions\";\n\nexport type {\n AdminDomainConfig,\n AdminEmailConfig,\n AdminOAuthProviderConfig,\n AdminProjectConfig,\n AdminProjectConfigUpdateOptions,\n OAuthProviderConfig\n} from \"./project-configs\";\n\nexport type {\n AdminOwnedProject,\n AdminProject,\n AdminProjectCreateOptions,\n AdminProjectUpdateOptions,\n Project,\n PushedConfigSource\n} from \"./projects\";\n\nexport type {\n EditableTeamMemberProfile,\n ServerListUsersOptions,\n ServerTeam,\n ServerTeamCreateOptions,\n ServerTeamMemberProfile,\n ServerTeamUpdateOptions,\n ServerTeamUser,\n Team,\n TeamCreateOptions,\n TeamInvitation,\n TeamMemberProfile,\n TeamUpdateOptions,\n TeamUser\n} from \"./teams\";\n\nexport type {\n Auth,\n CurrentInternalServerUser,\n CurrentInternalUser,\n CurrentServerUser,\n CurrentUser,\n OAuthProvider,\n ServerOAuthProvider,\n ServerUser,\n User\n} from \"./users\";\n\n" + }, + { + "path": "common.ts", + "content": "import { ProviderType } from \"@stackframe/stack-shared/dist/utils/oauth\";\nimport type { GenericQueryCtx, UserIdentity } from \"convex/server\";\n\nexport type RedirectToOptions = {\n replace?: boolean,\n noRedirectBack?: boolean,\n};\n\nexport type AsyncStoreProperty =\n & { [key in `${IsMultiple extends true ? \"list\" : \"get\"}${Capitalize}`]: (...args: Args) => Promise }\n & { [key in `use${Capitalize}`]: (...args: Args) => Value } // THIS_LINE_PLATFORM react-like\n\nexport type EmailConfig = {\n host: string,\n port: number,\n username: string,\n password: string,\n senderEmail: string,\n senderName: string,\n}\n\nexport type RedirectMethod = \"window\"\n | \"nextjs\" // THIS_LINE_PLATFORM next\n | \"none\"\n | {\n useNavigate: () => (to: string) => void,\n navigate?: (to: string) => void,\n }\n\n\nexport type GetCurrentUserOptions =\n & {\n or?: 'redirect' | 'throw' | 'return-null' | 'anonymous' | /** @deprecated */ 'anonymous-if-exists[deprecated]',\n /**\n * Whether to include restricted users (users who haven't completed onboarding requirements like email verification).\n * By default, restricted users are filtered out (treated similar to anonymous users).\n *\n * Note: This option cannot be set to false when `or: 'anonymous'` is used, as all anonymous users are also restricted.\n *\n * @default false\n */\n includeRestricted?: boolean,\n tokenStore?: TokenStoreInit,\n }\n & (HasTokenStore extends false ? {\n tokenStore: TokenStoreInit,\n } : {});\n\nexport type ConvexCtx =\n| GenericQueryCtx\n| { auth: { getUserIdentity: () => Promise } };\n\nexport type GetCurrentPartialUserOptions =\n & {\n or?: 'return-null' | 'anonymous', // note: unlike normal getUser, 'anonymous' still returns null sometimes (eg. if no token is present)\n tokenStore?: TokenStoreInit,\n }\n & (\n | {\n from: 'token',\n }\n | {\n from: 'convex',\n ctx: ConvexCtx,\n }\n )\n & (HasTokenStore extends false ? {\n tokenStore: TokenStoreInit,\n } : {});\n\nexport type RequestLike = {\n headers: {\n get: (name: string) => string | null,\n },\n};\n\nexport type TokenStoreInit =\n HasTokenStore extends true ? (\n | \"cookie\"\n | \"nextjs-cookie\"\n | \"memory\"\n | RequestLike\n | { accessToken: string, refreshToken: string }\n )\n : HasTokenStore extends false ? null\n : TokenStoreInit | TokenStoreInit;\n\nexport type HandlerUrls = {\n handler: string,\n signIn: string,\n signUp: string,\n afterSignIn: string,\n afterSignUp: string,\n signOut: string,\n afterSignOut: string,\n emailVerification: string,\n passwordReset: string,\n forgotPassword: string,\n home: string,\n oauthCallback: string,\n magicLinkCallback: string,\n accountSettings: string,\n teamInvitation: string,\n mfa: string,\n error: string,\n onboarding: string,\n}\n\nexport type OAuthScopesOnSignIn = {\n [key in ProviderType]: string[];\n};\n\n/**\n * Contains the authentication methods without session-related fields.\n * Used for apps that have token storage capabilities.\n */\nexport type AuthLike = {\n signOut(options?: { redirectUrl?: URL | string } & ExtraOptions): Promise,\n signOut(options?: { redirectUrl?: URL | string }): Promise,\n\n /**\n * Returns the current access token, or null if the user is not signed in.\n *\n * The access token is a short-lived JWT that can be used to authenticate requests to external servers.\n * It will be automatically refreshed when it expires.\n */\n getAccessToken(options?: {} & ExtraOptions): Promise,\n useAccessToken(options?: {} & ExtraOptions): string | null, // THIS_LINE_PLATFORM react-like\n\n /**\n * Returns the current refresh token, or null if the user is not signed in.\n *\n * The refresh token is a long-lived token that can be used to obtain new access tokens.\n * It should be kept secret and never exposed to the client.\n */\n getRefreshToken(options?: {} & ExtraOptions): Promise,\n useRefreshToken(options?: {} & ExtraOptions): string | null, // THIS_LINE_PLATFORM react-like\n\n /**\n * Returns headers for sending authenticated HTTP requests to external servers. Most commonly used in cross-origin\n * requests. Similar to `getAuthJson`, but specifically for HTTP requests.\n *\n * If you are using `tokenStore: \"cookie\"`, you don't need this for same-origin requests. However, most\n * browsers now disable third-party cookies by default, so we must pass authentication tokens by header instead\n * if the client and server are on different origins.\n *\n * This function returns a header object that can be used with `fetch` or other HTTP request libraries to send\n * authenticated requests.\n *\n * On the server, you can then pass in the `Request` object to the `tokenStore` option\n * of your Stack app. Please note that CORS does not allow most headers by default, so you\n * must include `x-stack-auth` in the [`Access-Control-Allow-Headers` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers)\n * of the CORS preflight response.\n *\n * If you are not using HTTP (and hence cannot set headers), you will need to use the `getAccessToken()` and\n * `getRefreshToken()` functions instead.\n *\n * Example:\n *\n * ```ts\n * // client\n * const res = await fetch(\"https://api.example.com\", {\n * headers: {\n * ...await stackApp.getAuthHeaders()\n * // you can also add your own headers here\n * },\n * });\n *\n * // server\n * function handleRequest(req: Request) {\n * const user = await stackServerApp.getUser({ tokenStore: req });\n * return new Response(\"Welcome, \" + user.displayName);\n * }\n * ```\n */\n getAuthHeaders(options?: {} & ExtraOptions): Promise<{ \"x-stack-auth\": string }>,\n useAuthHeaders(options?: {} & ExtraOptions): { \"x-stack-auth\": string }, // THIS_LINE_PLATFORM react-like\n\n /**\n * @deprecated Use `getAccessToken()` and `getRefreshToken()` instead.\n *\n * Creates a JSON-serializable object containing the information to authenticate a user on an external server.\n * Similar to `getAuthHeaders`, but returns an object that can be sent over any protocol instead of just\n * HTTP headers.\n *\n * While `getAuthHeaders` is the recommended way to send authentication tokens over HTTP, your app may use\n * a different protocol, for example WebSockets or gRPC. This function returns a token object that can be JSON-serialized and sent to the server in any way you like.\n *\n * On the server, you can pass in this token object into the `tokenStore` option to fetch user details.\n *\n * Example:\n *\n * ```ts\n * // client\n * const res = await rpcCall(rpcEndpoint, {\n * data: {\n * auth: await stackApp.getAuthJson(),\n * },\n * });\n *\n * // server\n * function handleRequest(data) {\n * const user = await stackServerApp.getUser({ tokenStore: data.auth });\n * return new Response(\"Welcome, \" + user.displayName);\n * }\n * ```\n */\n getAuthJson(options?: {} & ExtraOptions): Promise<{ accessToken: string | null, refreshToken: string | null }>,\n /** @deprecated Use `useAccessToken()` and `useRefreshToken()` instead. */\n useAuthJson(options?: {} & ExtraOptions): { accessToken: string | null, refreshToken: string | null }, // THIS_LINE_PLATFORM react-like\n};\n\n/** @internal */\nexport const stackAppInternalsSymbol = Symbol.for(\"StackAuth--DO-NOT-USE-OR-YOU-WILL-BE-FIRED--StackAppInternals\");\n" + }, + { + "path": "users/index.ts", + "content": "import { KnownErrors } from \"@stackframe/stack-shared\";\nimport { CurrentUserCrud } from \"@stackframe/stack-shared/dist/interface/crud/current-user\";\nimport { UsersCrud } from \"@stackframe/stack-shared/dist/interface/crud/users\";\nimport { InternalSession } from \"@stackframe/stack-shared/dist/sessions\";\nimport { encodeBase64 } from \"@stackframe/stack-shared/dist/utils/bytes\";\nimport { GeoInfo } from \"@stackframe/stack-shared/dist/utils/geo\";\nimport { ReadonlyJson } from \"@stackframe/stack-shared/dist/utils/json\";\nimport { ProviderType } from \"@stackframe/stack-shared/dist/utils/oauth\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { ApiKeyCreationOptions, UserApiKey, UserApiKeyFirstView } from \"../api-keys\";\nimport { AsyncStoreProperty, AuthLike } from \"../common\";\nimport { OAuthConnection } from \"../connected-accounts\";\nimport { ContactChannel, ContactChannelCreateOptions, ServerContactChannel, ServerContactChannelCreateOptions } from \"../contact-channels\";\nimport { Customer } from \"../customers\";\nimport { NotificationCategory } from \"../notification-categories\";\nimport { AdminTeamPermission, TeamPermission } from \"../permissions\";\nimport { AdminOwnedProject, AdminProjectCreateOptions } from \"../projects\";\nimport { EditableTeamMemberProfile, ServerTeam, ServerTeamCreateOptions, Team, TeamCreateOptions } from \"../teams\";\n\nconst userGetterErrorMessage = \"Stack Auth: useUser() already returns the user object. Use `const user = useUser()` (or `const user = await app.getUser()`) instead of destructuring it like `const { user } = ...`.\";\n\nexport function withUserDestructureGuard(target: T): T {\n Object.freeze(target);\n return new Proxy(target, {\n get(target, prop, receiver) {\n if (prop === \"user\") {\n return guardGetter();\n }\n return target[prop as keyof T];\n },\n });\n}\n\nfunction guardGetter(): never {\n throw new Error(userGetterErrorMessage);\n}\n\nexport type OAuthProvider = {\n readonly id: string,\n readonly type: string,\n readonly userId: string,\n readonly accountId?: string,\n readonly email?: string,\n readonly allowSignIn: boolean,\n readonly allowConnectedAccounts: boolean,\n update(data: { allowSignIn?: boolean, allowConnectedAccounts?: boolean }): Promise\n >>,\n delete(): Promise,\n};\n\nexport type ServerOAuthProvider = {\n readonly id: string,\n readonly type: string,\n readonly userId: string,\n readonly accountId: string,\n readonly email?: string,\n readonly allowSignIn: boolean,\n readonly allowConnectedAccounts: boolean,\n update(data: { accountId?: string, email?: string, allowSignIn?: boolean, allowConnectedAccounts?: boolean }): Promise\n >>,\n delete(): Promise,\n};\n\n\n/**\n * Contains everything related to the current user session.\n */\nexport type Auth = AuthLike<{}> & {\n readonly _internalSession: InternalSession,\n readonly currentSession: {\n getTokens(): Promise<{ accessToken: string | null, refreshToken: string | null }>,\n useTokens(): { accessToken: string | null, refreshToken: string | null }, // THIS_LINE_PLATFORM react-like\n },\n};\n\n/**\n * ```\n * +----------+-------------+-------------------+\n * | \\ | !Server | Server |\n * +----------+-------------+-------------------+\n * | !Session | User | ServerUser |\n * | Session | CurrentUser | CurrentServerUser |\n * +----------+-------------+-------------------+\n * ```\n *\n * The fields on each of these types are available iff:\n * BaseUser: true\n * Auth: Session\n * ServerBaseUser: Server\n * UserExtra: Session OR Server\n *\n * The types are defined as follows (in the typescript manner):\n * User = BaseUser\n * CurrentUser = BaseUser & Auth & UserExtra\n * ServerUser = BaseUser & ServerBaseUser & UserExtra\n * CurrentServerUser = BaseUser & ServerBaseUser & Auth & UserExtra\n **/\n\nexport type BaseUser = {\n readonly id: string,\n\n readonly displayName: string | null,\n\n /**\n * The user's email address.\n *\n * Note: This might NOT be unique across multiple users, so always use `id` for unique identification.\n */\n readonly primaryEmail: string | null,\n readonly primaryEmailVerified: boolean,\n readonly profileImageUrl: string | null,\n\n readonly signedUpAt: Date,\n\n readonly clientMetadata: any,\n readonly clientReadOnlyMetadata: any,\n\n /**\n * Whether the user has a password set.\n */\n readonly hasPassword: boolean,\n readonly otpAuthEnabled: boolean,\n readonly passkeyAuthEnabled: boolean,\n\n readonly isMultiFactorRequired: boolean,\n readonly isAnonymous: boolean,\n /**\n * Whether the user is in restricted state (signed up but hasn't completed onboarding requirements).\n * For example, if email verification is required but the user hasn't verified their email yet.\n */\n readonly isRestricted: boolean,\n /**\n * The reason why the user is restricted, e.g., { type: \"email_not_verified\" }, { type: \"anonymous\" }, or { type: \"restricted_by_administrator\" }.\n * Null if the user is not restricted.\n */\n readonly restrictedReason: { type: \"anonymous\" | \"email_not_verified\" | \"restricted_by_administrator\" } | null,\n toClientJson(): CurrentUserCrud[\"Client\"][\"Read\"],\n\n /**\n * @deprecated, use contact channel's usedForAuth instead\n */\n readonly emailAuthEnabled: boolean,\n /**\n * @deprecated\n */\n readonly oauthProviders: readonly { id: string }[],\n}\n\nexport type UserExtra = {\n setDisplayName(displayName: string | null): Promise,\n /** @deprecated Use contact channel's sendVerificationEmail instead */\n sendVerificationEmail(): Promise,\n setClientMetadata(metadata: any): Promise,\n updatePassword(options: { oldPassword: string, newPassword: string}): Promise,\n setPassword(options: { password: string }): Promise,\n\n /**\n * A shorthand method to update multiple fields of the user at once.\n */\n update(update: UserUpdateOptions): Promise,\n\n useContactChannels(): ContactChannel[], // THIS_LINE_PLATFORM react-like\n listContactChannels(): Promise,\n createContactChannel(data: ContactChannelCreateOptions): Promise,\n\n useNotificationCategories(): NotificationCategory[], // THIS_LINE_PLATFORM react-like\n listNotificationCategories(): Promise,\n\n delete(): Promise,\n\n getConnectedAccount(id: ProviderType, options: { or: 'redirect', scopes?: string[] }): Promise,\n getConnectedAccount(id: ProviderType, options?: { or?: 'redirect' | 'throw' | 'return-null', scopes?: string[] }): Promise,\n\n // IF_PLATFORM react-like\n useConnectedAccount(id: ProviderType, options: { or: 'redirect', scopes?: string[] }): OAuthConnection,\n useConnectedAccount(id: ProviderType, options?: { or?: 'redirect' | 'throw' | 'return-null', scopes?: string[] }): OAuthConnection | null,\n // END_PLATFORM\n\n hasPermission(scope: Team, permissionId: string): Promise,\n hasPermission(permissionId: string): Promise,\n\n getPermission(scope: Team, permissionId: string): Promise,\n getPermission(permissionId: string): Promise,\n\n listPermissions(scope: Team, options?: { recursive?: boolean }): Promise,\n listPermissions(options?: { recursive?: boolean }): Promise,\n\n // IF_PLATFORM react-like\n usePermissions(scope: Team, options?: { recursive?: boolean }): TeamPermission[],\n usePermissions(options?: { recursive?: boolean }): TeamPermission[],\n\n usePermission(scope: Team, permissionId: string): TeamPermission | null,\n usePermission(permissionId: string): TeamPermission | null,\n // END_PLATFORM\n\n readonly selectedTeam: Team | null,\n setSelectedTeam(teamOrId: string | Team | null): Promise,\n createTeam(data: TeamCreateOptions): Promise,\n leaveTeam(team: Team): Promise,\n\n getActiveSessions(): Promise,\n revokeSession(sessionId: string): Promise,\n getTeamProfile(team: Team): Promise,\n useTeamProfile(team: Team): EditableTeamMemberProfile, // THIS_LINE_PLATFORM react-like\n\n createApiKey(options: ApiKeyCreationOptions<\"user\">): Promise,\n\n useOAuthProviders(): OAuthProvider[], // THIS_LINE_PLATFORM react-like\n listOAuthProviders(): Promise,\n\n useOAuthProvider(id: string): OAuthProvider | null, // THIS_LINE_PLATFORM react-like\n getOAuthProvider(id: string): Promise,\n\n registerPasskey(options?: { hostname?: string }): Promise>,\n}\n& AsyncStoreProperty<\"apiKeys\", [], UserApiKey[], true>\n& AsyncStoreProperty<\"team\", [id: string], Team | null, false>\n& AsyncStoreProperty<\"teams\", [], Team[], true>\n& AsyncStoreProperty<\"permission\", [scope: Team, permissionId: string, options?: { recursive?: boolean }], TeamPermission | null, false>\n& AsyncStoreProperty<\"permissions\", [scope: Team, options?: { recursive?: boolean }], TeamPermission[], true>;\n\nexport type InternalUserExtra =\n & {\n createProject(newProject: AdminProjectCreateOptions): Promise,\n transferProject(projectIdToTransfer: string, newTeamId: string): Promise,\n }\n & AsyncStoreProperty<\"ownedProjects\", [], AdminOwnedProject[], true>\n\nexport type User = BaseUser;\n\nexport type CurrentUser = BaseUser & Auth & UserExtra & Customer;\n\nexport type CurrentInternalUser = CurrentUser & InternalUserExtra;\n\nexport type ProjectCurrentUser = ProjectId extends \"internal\" ? CurrentInternalUser : CurrentUser;\n\nexport type TokenPartialUser = Pick<\n User,\n | \"id\"\n | \"displayName\"\n | \"primaryEmail\"\n | \"primaryEmailVerified\"\n | \"isAnonymous\"\n | \"isRestricted\"\n | \"restrictedReason\"\n>\n\nexport type SyncedPartialUser = TokenPartialUser & Pick<\n User,\n | \"id\"\n | \"displayName\"\n | \"primaryEmail\"\n | \"primaryEmailVerified\"\n | \"profileImageUrl\"\n | \"signedUpAt\"\n | \"clientMetadata\"\n | \"clientReadOnlyMetadata\"\n | \"isAnonymous\"\n | \"hasPassword\"\n | \"isRestricted\"\n | \"restrictedReason\"\n>;\n\n\nexport type ActiveSession = {\n id: string,\n userId: string,\n createdAt: Date,\n isImpersonation: boolean,\n lastUsedAt: Date | undefined,\n isCurrentSession: boolean,\n geoInfo?: GeoInfo,\n};\n\nexport type UserUpdateOptions = {\n displayName?: string | null,\n clientMetadata?: ReadonlyJson,\n selectedTeamId?: string | null,\n totpMultiFactorSecret?: Uint8Array | null,\n profileImageUrl?: string | null,\n otpAuthEnabled?: boolean,\n passkeyAuthEnabled?: boolean,\n primaryEmail?: string | null,\n}\nexport function userUpdateOptionsToCrud(options: UserUpdateOptions): CurrentUserCrud[\"Client\"][\"Update\"] {\n return {\n display_name: options.displayName,\n client_metadata: options.clientMetadata,\n selected_team_id: options.selectedTeamId,\n totp_secret_base64: options.totpMultiFactorSecret != null ? encodeBase64(options.totpMultiFactorSecret) : options.totpMultiFactorSecret,\n profile_image_url: options.profileImageUrl,\n otp_auth_enabled: options.otpAuthEnabled,\n passkey_auth_enabled: options.passkeyAuthEnabled,\n primary_email: options.primaryEmail,\n };\n}\n\n\nexport type ServerBaseUser = {\n setPrimaryEmail(email: string | null, options?: { verified?: boolean | undefined }): Promise,\n\n readonly lastActiveAt: Date,\n\n readonly serverMetadata: any,\n setServerMetadata(metadata: any): Promise,\n setClientReadOnlyMetadata(metadata: any): Promise,\n\n /** Whether the user is restricted by an administrator. Can be set manually or by sign-up rules. */\n readonly restrictedByAdmin: boolean,\n /** Public reason shown to the user explaining why they are restricted. Optional. */\n readonly restrictedByAdminReason: string | null,\n /** Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above. */\n readonly restrictedByAdminPrivateDetails: string | null,\n\n createTeam(data: Omit): Promise,\n\n useContactChannels(): ServerContactChannel[], // THIS_LINE_PLATFORM react-like\n listContactChannels(): Promise,\n createContactChannel(data: ServerContactChannelCreateOptions): Promise,\n\n update(user: ServerUserUpdateOptions): Promise,\n\n grantPermission(scope: Team, permissionId: string): Promise,\n grantPermission(permissionId: string): Promise,\n\n revokePermission(scope: Team, permissionId: string): Promise,\n revokePermission(permissionId: string): Promise,\n\n getPermission(scope: Team, permissionId: string): Promise,\n getPermission(permissionId: string): Promise,\n\n hasPermission(scope: Team, permissionId: string): Promise,\n hasPermission(permissionId: string): Promise,\n\n listPermissions(scope: Team, options?: { recursive?: boolean }): Promise,\n listPermissions(options?: { recursive?: boolean }): Promise,\n\n // IF_PLATFORM react-like\n usePermissions(scope: Team, options?: { recursive?: boolean }): TeamPermission[],\n usePermissions(options?: { recursive?: boolean }): TeamPermission[],\n\n usePermission(scope: Team, permissionId: string): TeamPermission | null,\n usePermission(permissionId: string): TeamPermission | null,\n // END_PLATFORM\n\n useOAuthProviders(): ServerOAuthProvider[], // THIS_LINE_PLATFORM react-like\n listOAuthProviders(): Promise,\n\n useOAuthProvider(id: string): ServerOAuthProvider | null, // THIS_LINE_PLATFORM react-like\n getOAuthProvider(id: string): Promise,\n\n /**\n * Creates a new session object with a refresh token for this user. Can be used to impersonate them.\n */\n createSession(options?: { expiresInMillis?: number, isImpersonation?: boolean }): Promise<{\n getTokens(): Promise<{ accessToken: string | null, refreshToken: string | null }>,\n }>,\n}\n& AsyncStoreProperty<\"team\", [id: string], ServerTeam | null, false>\n& AsyncStoreProperty<\"teams\", [], ServerTeam[], true>\n& AsyncStoreProperty<\"permission\", [scope: Team, permissionId: string, options?: { direct?: boolean }], AdminTeamPermission | null, false>\n& AsyncStoreProperty<\"permissions\", [scope: Team, options?: { direct?: boolean }], AdminTeamPermission[], true>;\n\n/**\n * A user including sensitive fields that should only be used on the server, never sent to the client\n * (such as sensitive information and serverMetadata).\n */\nexport type ServerUser = ServerBaseUser & BaseUser & UserExtra & Customer;\n\nexport type CurrentServerUser = Auth & ServerUser;\n\nexport type CurrentInternalServerUser = CurrentServerUser & InternalUserExtra;\n\nexport type ProjectCurrentServerUser = ProjectId extends \"internal\" ? CurrentInternalServerUser : CurrentServerUser;\n\nexport type SyncedPartialServerUser = SyncedPartialUser & Pick<\n ServerUser,\n | \"serverMetadata\"\n>;\n\nexport type ServerUserUpdateOptions = {\n primaryEmail?: string | null,\n primaryEmailVerified?: boolean,\n primaryEmailAuthEnabled?: boolean,\n clientReadOnlyMetadata?: ReadonlyJson,\n serverMetadata?: ReadonlyJson,\n password?: string,\n restrictedByAdmin?: boolean,\n restrictedByAdminReason?: string | null,\n restrictedByAdminPrivateDetails?: string | null,\n} & UserUpdateOptions;\nexport function serverUserUpdateOptionsToCrud(options: ServerUserUpdateOptions): CurrentUserCrud[\"Server\"][\"Update\"] {\n // Base update options\n const baseUpdate: CurrentUserCrud[\"Server\"][\"Update\"] = {\n display_name: options.displayName,\n primary_email: options.primaryEmail,\n client_metadata: options.clientMetadata,\n client_read_only_metadata: options.clientReadOnlyMetadata,\n server_metadata: options.serverMetadata,\n selected_team_id: options.selectedTeamId,\n primary_email_auth_enabled: options.primaryEmailAuthEnabled,\n primary_email_verified: options.primaryEmailVerified,\n password: options.password,\n profile_image_url: options.profileImageUrl,\n totp_secret_base64: options.totpMultiFactorSecret != null ? encodeBase64(options.totpMultiFactorSecret) : options.totpMultiFactorSecret,\n };\n // Add admin restriction fields (may not be in generated types yet but will be at runtime)\n return {\n ...baseUpdate,\n restricted_by_admin: options.restrictedByAdmin,\n restricted_by_admin_reason: options.restrictedByAdminReason,\n restricted_by_admin_private_details: options.restrictedByAdminPrivateDetails,\n } as CurrentUserCrud[\"Server\"][\"Update\"];\n}\n\n\nexport type ServerUserCreateOptions = {\n primaryEmail?: string | null,\n primaryEmailAuthEnabled?: boolean,\n password?: string,\n otpAuthEnabled?: boolean,\n displayName?: string,\n primaryEmailVerified?: boolean,\n clientMetadata?: any,\n clientReadOnlyMetadata?: any,\n serverMetadata?: any,\n}\nexport function serverUserCreateOptionsToCrud(options: ServerUserCreateOptions): UsersCrud[\"Server\"][\"Create\"] {\n return {\n primary_email: options.primaryEmail,\n password: options.password,\n otp_auth_enabled: options.otpAuthEnabled,\n primary_email_auth_enabled: options.primaryEmailAuthEnabled,\n display_name: options.displayName,\n primary_email_verified: options.primaryEmailVerified,\n client_metadata: options.clientMetadata,\n client_read_only_metadata: options.clientReadOnlyMetadata,\n server_metadata: options.serverMetadata,\n };\n}\n" + }, + { + "path": "teams/index.ts", + "content": "import { TeamsCrud } from \"@stackframe/stack-shared/dist/interface/crud/teams\";\nimport { ReadonlyJson } from \"@stackframe/stack-shared/dist/utils/json\";\n\nimport { ApiKeyCreationOptions, TeamApiKey, TeamApiKeyFirstView } from \"../api-keys\";\nimport { AsyncStoreProperty } from \"../common\";\nimport { Customer } from \"../customers\";\nimport { ServerUser } from \"../users\";\n\n\nexport type TeamMemberProfile = {\n displayName: string | null,\n profileImageUrl: string | null,\n}\n\nexport type TeamMemberProfileUpdateOptions = {\n displayName?: string,\n profileImageUrl?: string | null,\n};\n\nexport type EditableTeamMemberProfile = TeamMemberProfile & {\n update(update: TeamMemberProfileUpdateOptions): Promise,\n}\n\nexport type TeamUser = {\n id: string,\n teamProfile: TeamMemberProfile,\n}\n\nexport type TeamInvitation = {\n id: string,\n recipientEmail: string | null,\n expiresAt: Date,\n revoke(): Promise,\n}\n\nexport type Team = {\n id: string,\n displayName: string,\n profileImageUrl: string | null,\n clientMetadata: any,\n clientReadOnlyMetadata: any,\n inviteUser(options: { email: string, callbackUrl?: string }): Promise,\n listUsers(): Promise,\n useUsers(): TeamUser[], // THIS_LINE_PLATFORM react-like\n listInvitations(): Promise,\n useInvitations(): TeamInvitation[], // THIS_LINE_PLATFORM react-like\n update(update: TeamUpdateOptions): Promise,\n delete(): Promise,\n createApiKey(options: ApiKeyCreationOptions<\"team\">): Promise,\n} & AsyncStoreProperty<\"apiKeys\", [], TeamApiKey[], true> & Customer;\n\nexport type TeamUpdateOptions = {\n displayName?: string,\n profileImageUrl?: string | null,\n clientMetadata?: ReadonlyJson,\n};\nexport function teamUpdateOptionsToCrud(options: TeamUpdateOptions): TeamsCrud[\"Client\"][\"Update\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n client_metadata: options.clientMetadata,\n };\n}\n\nexport type TeamCreateOptions = {\n displayName: string,\n profileImageUrl?: string,\n}\nexport function teamCreateOptionsToCrud(options: TeamCreateOptions, creatorUserId: string): TeamsCrud[\"Client\"][\"Create\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n creator_user_id: creatorUserId,\n };\n}\n\n\nexport type ServerTeamMemberProfile = TeamMemberProfile;\n\nexport type ServerTeamUser = ServerUser & {\n teamProfile: ServerTeamMemberProfile,\n}\n\nexport type ServerTeam = {\n createdAt: Date,\n serverMetadata: any,\n listUsers(): Promise,\n useUsers(): ServerUser[], // THIS_LINE_PLATFORM react-like\n update(update: ServerTeamUpdateOptions): Promise,\n delete(): Promise,\n addUser(userId: string): Promise,\n inviteUser(options: { email: string, callbackUrl?: string }): Promise,\n removeUser(userId: string): Promise,\n} & Team;\n\nexport type ServerListUsersOptions = {\n cursor?: string,\n limit?: number,\n orderBy?: 'signedUpAt',\n desc?: boolean,\n query?: string,\n /**\n * Whether to include restricted users (users who haven't completed onboarding requirements).\n * Defaults to false.\n */\n includeRestricted?: boolean,\n /**\n * Whether to include anonymous users (and restricted users).\n * Defaults to false.\n */\n includeAnonymous?: boolean,\n};\n\nexport type ServerTeamCreateOptions = TeamCreateOptions & {\n creatorUserId?: string,\n};\nexport function serverTeamCreateOptionsToCrud(options: ServerTeamCreateOptions): TeamsCrud[\"Server\"][\"Create\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n creator_user_id: options.creatorUserId,\n };\n}\n\nexport type ServerTeamUpdateOptions = TeamUpdateOptions & {\n clientReadOnlyMetadata?: ReadonlyJson,\n serverMetadata?: ReadonlyJson,\n};\nexport function serverTeamUpdateOptionsToCrud(options: ServerTeamUpdateOptions): TeamsCrud[\"Server\"][\"Update\"] {\n return {\n display_name: options.displayName,\n profile_image_url: options.profileImageUrl,\n client_metadata: options.clientMetadata,\n client_read_only_metadata: options.clientReadOnlyMetadata,\n server_metadata: options.serverMetadata,\n };\n}\n" + }, + { + "path": "projects/index.ts", + "content": "import { ProductionModeError } from \"@stackframe/stack-shared/dist/helpers/production-mode\";\nimport { AdminUserProjectsCrud, ProjectsCrud } from \"@stackframe/stack-shared/dist/interface/crud/projects\";\n\nimport { CompleteConfig, EnvironmentConfigNormalizedOverride, EnvironmentConfigOverrideOverride } from \"@stackframe/stack-shared/dist/config/schema\";\nimport { StackAdminApp } from \"../apps/interfaces/admin-app\";\nimport { AdminProjectConfig, AdminProjectConfigUpdateOptions, ProjectConfig } from \"../project-configs\";\n\n/**\n * SDK type for pushed config source (camelCase for SDK).\n * Represents where the branch config was pushed from.\n */\nexport type PushedConfigSource =\n | { type: \"pushed-from-github\", owner: string, repo: string, branch: string, commitHash: string, configFilePath: string }\n | { type: \"pushed-from-unknown\" }\n | { type: \"unlinked\" };\n\nexport type PushConfigOptions = {\n /**\n * The source of this config push.\n */\n source: PushedConfigSource,\n};\n\n\nexport type Project = {\n readonly id: string,\n readonly displayName: string,\n readonly config: ProjectConfig,\n};\n\nexport type AdminProject = {\n readonly id: string,\n readonly displayName: string,\n readonly description: string | null,\n readonly createdAt: Date,\n readonly isProductionMode: boolean,\n readonly ownerTeamId: string | null,\n readonly logoUrl: string | null | undefined,\n readonly logoFullUrl: string | null | undefined,\n readonly logoDarkModeUrl: string | null | undefined,\n readonly logoFullDarkModeUrl: string | null | undefined,\n\n readonly config: AdminProjectConfig,\n\n update(this: AdminProject, update: AdminProjectUpdateOptions): Promise,\n delete(this: AdminProject): Promise,\n\n getConfig(this: AdminProject): Promise,\n // NEXT_LINE_PLATFORM react-like\n useConfig(this: AdminProject): CompleteConfig,\n\n /**\n * Updates the environment's config by merging the provided config into the existing config.\n *\n * Changes made with `updateConfig` always take precedence over those made with `pushConfig`, even if the `pushConfig`\n * config was pushed after the changes were made with `updateConfig`. This is best for environment-specific\n * configuration like secrets, API keys, and other values that you wouldn't push into a source repository.\n */\n // We have some strict types here in order to prevent accidental overwriting of a top-level property of a config object\n updateConfig(\n this: AdminProject,\n config: EnvironmentConfigOverrideOverride & {\n [K in keyof EnvironmentConfigNormalizedOverride]: \"............................ERROR MESSAGE AFTER THIS LINE............................ You have attempted to update a config object with a top-level property in it (for example `emails`). This is very likely a mistake, and you probably meant to update a nested property instead (for example `emails.server`). If you really meant to update a top-level property (resetting all nested properties to their defaults), cast as any (the code will work at runtime) ............................ERROR MESSAGE BEFORE THIS LINE............................\";\n }\n ): Promise,\n\n /**\n * Pushes a config, replacing any previous config pushed with `pushConfig`.\n *\n * **Note:** This function does **not** replace any changes made with `updateConfig`. Changes made with\n * `updateConfig` always take precedence over those made with `pushConfig`, even if the `pushConfig`\n * config was pushed after the changes were made with `updateConfig`.\n *\n * This is useful for programmatically deploying configuration. More often than not, you'll want to use\n * `updateConfig` instead.\n */\n pushConfig(\n this: AdminProject,\n config: EnvironmentConfigOverrideOverride & {\n [K in keyof EnvironmentConfigNormalizedOverride]: \"............................ERROR MESSAGE AFTER THIS LINE............................ You have attempted to update a config object with a top-level property in it (for example `emails`). This is very likely a mistake, and you probably meant to update a nested property instead (for example `emails.server`). If you really meant to update a top-level property (resetting all nested properties to their defaults), cast as any (the code will work at runtime) ............................ERROR MESSAGE BEFORE THIS LINE............................\";\n },\n options: PushConfigOptions,\n ): Promise,\n\n /**\n * Updates the pushed config by merging the provided config into the existing pushed config.\n *\n * **Warning:** This is almost always **not** the function you want to call. Changes made with\n * `updatePushedConfig` will be replaced entirely the next time `pushConfig` is called. Consider using\n * `pushConfig` to set the full pushed config, or `updateConfig` for environment-specific values that\n * should persist across pushes.\n *\n * This function is useful for making temporary modifications to the pushed config before the next push.\n */\n updatePushedConfig(\n this: AdminProject,\n config: EnvironmentConfigOverrideOverride & {\n [K in keyof EnvironmentConfigNormalizedOverride]: \"............................ERROR MESSAGE AFTER THIS LINE............................ You have attempted to update a config object with a top-level property in it (for example `emails`). This is very likely a mistake, and you probably meant to update a nested property instead (for example `emails.server`). If you really meant to update a top-level property (resetting all nested properties to their defaults), cast as any (the code will work at runtime) ............................ERROR MESSAGE BEFORE THIS LINE............................\";\n }\n ): Promise,\n\n /**\n * Gets the source metadata for the pushed config, indicating where it was pushed from.\n *\n * The source can be:\n * - `pushed-from-github`: Config was pushed from a GitHub repository\n * - `pushed-from-unknown`: Config was pushed via CLI but source details unknown\n * - `unlinked`: Config can be edited directly on the dashboard\n */\n getPushedConfigSource(this: AdminProject): Promise,\n\n /**\n * Unlinks the pushed config source, setting it to \"unlinked\".\n * This allows the config to be edited directly on the dashboard without external push restrictions.\n */\n unlinkPushedConfigSource(this: AdminProject): Promise,\n\n getProductionModeErrors(this: AdminProject): Promise,\n // NEXT_LINE_PLATFORM react-like\n useProductionModeErrors(this: AdminProject): ProductionModeError[],\n} & Project;\n\nexport type AdminOwnedProject = {\n readonly app: StackAdminApp,\n} & AdminProject;\n\nexport type AdminProjectUpdateOptions = {\n displayName?: string,\n description?: string,\n isProductionMode?: boolean,\n logoUrl?: string | null,\n logoFullUrl?: string | null,\n logoDarkModeUrl?: string | null,\n logoFullDarkModeUrl?: string | null,\n config?: AdminProjectConfigUpdateOptions,\n};\nexport function adminProjectUpdateOptionsToCrud(options: AdminProjectUpdateOptions): ProjectsCrud[\"Admin\"][\"Update\"] {\n return {\n display_name: options.displayName,\n description: options.description,\n is_production_mode: options.isProductionMode,\n logo_url: options.logoUrl,\n logo_full_url: options.logoFullUrl,\n logo_dark_mode_url: options.logoDarkModeUrl,\n logo_full_dark_mode_url: options.logoFullDarkModeUrl,\n /**\n * NOTE: Do not update this config anymore. It's been superseded by the new config in schema.ts.\n * @deprecated\n */\n config: {\n domains: options.config?.domains?.map((d) => ({\n domain: d.domain,\n handler_path: d.handlerPath\n })),\n oauth_providers: options.config?.oauthProviders?.map((p) => ({\n id: p.id as any,\n type: p.type,\n ...(p.type === 'standard' && {\n client_id: p.clientId,\n client_secret: p.clientSecret,\n facebook_config_id: p.facebookConfigId,\n microsoft_tenant_id: p.microsoftTenantId,\n apple_bundle_ids: p.appleBundleIds,\n }),\n })),\n email_config: options.config?.emailConfig && (\n options.config.emailConfig.type === 'shared' ? {\n type: 'shared',\n } : {\n type: 'standard',\n host: options.config.emailConfig.host,\n port: options.config.emailConfig.port,\n username: options.config.emailConfig.username,\n password: options.config.emailConfig.password,\n sender_name: options.config.emailConfig.senderName,\n sender_email: options.config.emailConfig.senderEmail,\n }\n ),\n email_theme: options.config?.emailTheme,\n sign_up_enabled: options.config?.signUpEnabled,\n credential_enabled: options.config?.credentialEnabled,\n magic_link_enabled: options.config?.magicLinkEnabled,\n passkey_enabled: options.config?.passkeyEnabled,\n allow_localhost: options.config?.allowLocalhost,\n create_team_on_sign_up: options.config?.createTeamOnSignUp,\n client_team_creation_enabled: options.config?.clientTeamCreationEnabled,\n client_user_deletion_enabled: options.config?.clientUserDeletionEnabled,\n team_creator_default_permissions: options.config?.teamCreatorDefaultPermissions,\n team_member_default_permissions: options.config?.teamMemberDefaultPermissions,\n user_default_permissions: options.config?.userDefaultPermissions,\n oauth_account_merge_strategy: options.config?.oauthAccountMergeStrategy,\n allow_user_api_keys: options.config?.allowUserApiKeys,\n allow_team_api_keys: options.config?.allowTeamApiKeys,\n },\n };\n}\n\nexport type AdminProjectCreateOptions = Omit & {\n displayName: string,\n teamId: string,\n};\nexport function adminProjectCreateOptionsToCrud(options: AdminProjectCreateOptions): AdminUserProjectsCrud[\"Server\"][\"Create\"] {\n return {\n ...adminProjectUpdateOptionsToCrud(options),\n display_name: options.displayName,\n owner_team_id: options.teamId,\n };\n}\n" + }, + { + "path": "project-configs/index.ts", + "content": "import { AdminTeamPermission } from \"../permissions\";\n\nexport type ProjectConfig = {\n readonly signUpEnabled: boolean,\n readonly credentialEnabled: boolean,\n readonly magicLinkEnabled: boolean,\n readonly passkeyEnabled: boolean,\n readonly clientTeamCreationEnabled: boolean,\n readonly clientUserDeletionEnabled: boolean,\n readonly oauthProviders: OAuthProviderConfig[],\n readonly allowUserApiKeys: boolean,\n readonly allowTeamApiKeys: boolean,\n};\n\nexport type OAuthProviderConfig = {\n readonly id: string,\n};\n\n/**\n * @deprecated This type is deprecated. Use the new config override setup instead.\n */\nexport type AdminProjectConfig = {\n readonly signUpEnabled: boolean,\n readonly credentialEnabled: boolean,\n readonly magicLinkEnabled: boolean,\n readonly passkeyEnabled: boolean,\n readonly clientTeamCreationEnabled: boolean,\n readonly clientUserDeletionEnabled: boolean,\n readonly allowLocalhost: boolean,\n readonly oauthProviders: AdminOAuthProviderConfig[],\n readonly emailConfig?: AdminEmailConfig,\n readonly emailTheme: string,\n readonly domains: AdminDomainConfig[],\n readonly createTeamOnSignUp: boolean,\n readonly teamCreatorDefaultPermissions: AdminTeamPermission[],\n readonly teamMemberDefaultPermissions: AdminTeamPermission[],\n readonly userDefaultPermissions: AdminTeamPermission[],\n readonly oauthAccountMergeStrategy: 'link_method' | 'raise_error' | 'allow_duplicates',\n readonly allowUserApiKeys: boolean,\n readonly allowTeamApiKeys: boolean,\n};\n\nexport type AdminEmailConfig = (\n {\n type: \"standard\" | \"resend\",\n senderName: string,\n senderEmail: string,\n host: string,\n port: number,\n username: string,\n password: string,\n }\n | {\n type: \"shared\",\n }\n);\n\nexport type AdminDomainConfig = {\n domain: string,\n handlerPath: string,\n};\n\nexport type AdminOAuthProviderConfig = {\n id: string,\n} & (\n | { type: 'shared' }\n | {\n type: 'standard',\n clientId: string,\n clientSecret: string,\n facebookConfigId?: string,\n microsoftTenantId?: string,\n appleBundleIds?: string[],\n }\n ) & OAuthProviderConfig;\n\nexport type AdminProjectConfigUpdateOptions = {\n domains?: {\n domain: string,\n handlerPath: string,\n }[],\n oauthProviders?: AdminOAuthProviderConfig[],\n signUpEnabled?: boolean,\n credentialEnabled?: boolean,\n magicLinkEnabled?: boolean,\n passkeyEnabled?: boolean,\n clientTeamCreationEnabled?: boolean,\n clientUserDeletionEnabled?: boolean,\n allowLocalhost?: boolean,\n createTeamOnSignUp?: boolean,\n emailConfig?: AdminEmailConfig,\n emailTheme?: string,\n teamCreatorDefaultPermissions?: { id: string }[],\n teamMemberDefaultPermissions?: { id: string }[],\n userDefaultPermissions?: { id: string }[],\n oauthAccountMergeStrategy?: 'link_method' | 'raise_error' | 'allow_duplicates',\n allowUserApiKeys?: boolean,\n allowTeamApiKeys?: boolean,\n};\n" + }, + { + "path": "permissions/index.ts", + "content": "import { ProjectPermissionDefinitionsCrud } from \"@stackframe/stack-shared/dist/interface/crud/project-permissions\";\nimport { TeamPermissionDefinitionsCrud } from \"@stackframe/stack-shared/dist/interface/crud/team-permissions\";\n\n\nexport type TeamPermission = {\n id: string,\n};\n\nexport type AdminTeamPermission = TeamPermission;\n\nexport type AdminTeamPermissionDefinition = {\n id: string,\n description?: string,\n containedPermissionIds: string[],\n isDefaultUserPermission?: boolean,\n};\n\nexport type AdminTeamPermissionDefinitionCreateOptions = {\n id: string,\n description?: string,\n containedPermissionIds: string[],\n isDefaultUserPermission?: boolean,\n};\nexport function adminTeamPermissionDefinitionCreateOptionsToCrud(options: AdminTeamPermissionDefinitionCreateOptions): TeamPermissionDefinitionsCrud[\"Admin\"][\"Create\"] {\n return {\n id: options.id,\n description: options.description,\n contained_permission_ids: options.containedPermissionIds,\n };\n}\n\nexport type AdminTeamPermissionDefinitionUpdateOptions = Pick, \"description\" | \"containedPermissionIds\">;\nexport function adminTeamPermissionDefinitionUpdateOptionsToCrud(options: AdminTeamPermissionDefinitionUpdateOptions): TeamPermissionDefinitionsCrud[\"Admin\"][\"Update\"] {\n return {\n description: options.description,\n contained_permission_ids: options.containedPermissionIds,\n };\n}\n\nexport type ProjectPermission = {\n id: string,\n};\n\nexport type AdminProjectPermission = ProjectPermission;\n\nexport type AdminProjectPermissionDefinition = {\n id: string,\n description?: string,\n containedPermissionIds: string[],\n};\n\nexport type AdminProjectPermissionDefinitionCreateOptions = {\n id: string,\n description?: string,\n containedPermissionIds: string[],\n};\nexport function adminProjectPermissionDefinitionCreateOptionsToCrud(options: AdminProjectPermissionDefinitionCreateOptions): ProjectPermissionDefinitionsCrud[\"Admin\"][\"Create\"] {\n return {\n id: options.id,\n description: options.description,\n contained_permission_ids: options.containedPermissionIds,\n };\n}\n\nexport type AdminProjectPermissionDefinitionUpdateOptions = Pick, \"description\" | \"containedPermissionIds\">;\nexport function adminProjectPermissionDefinitionUpdateOptionsToCrud(options: AdminProjectPermissionDefinitionUpdateOptions): ProjectPermissionDefinitionsCrud[\"Admin\"][\"Update\"] {\n return {\n description: options.description,\n contained_permission_ids: options.containedPermissionIds,\n };\n}\n" + }, + { + "path": "notification-categories/index.ts", + "content": "export type NotificationCategory = {\n id: string,\n name: string,\n enabled: boolean,\n canDisable: boolean,\n\n setEnabled(enabled: boolean): Promise,\n}\n" + }, + { + "path": "internal-api-keys/index.ts", + "content": "\nimport { InternalApiKeyCreateCrudRequest } from \"@stackframe/stack-shared/dist/interface/admin-interface\";\nimport { InternalApiKeysCrud } from \"@stackframe/stack-shared/dist/interface/crud/internal-api-keys\";\n\nexport type InternalApiKeyBase = {\n id: string,\n description: string,\n expiresAt: Date,\n manuallyRevokedAt: Date | null,\n createdAt: Date,\n isValid(): boolean,\n whyInvalid(): \"expired\" | \"manually-revoked\" | null,\n revoke(): Promise,\n};\n\nexport type InternalApiKeyBaseCrudRead = Pick;\n\nexport type InternalApiKeyFirstView = {\n publishableClientKey?: string,\n secretServerKey?: string,\n superSecretAdminKey?: string,\n} & InternalApiKeyBase;\n\nexport type InternalApiKey = {\n publishableClientKey: null | {\n lastFour: string,\n },\n secretServerKey: null | {\n lastFour: string,\n },\n superSecretAdminKey: null | {\n lastFour: string,\n },\n} & InternalApiKeyBase;\n\nexport type InternalApiKeyCreateOptions = {\n description: string,\n expiresAt: Date,\n hasPublishableClientKey: boolean,\n hasSecretServerKey: boolean,\n hasSuperSecretAdminKey: boolean,\n};\nexport function internalApiKeyCreateOptionsToCrud(options: InternalApiKeyCreateOptions): InternalApiKeyCreateCrudRequest {\n return {\n description: options.description,\n expires_at_millis: options.expiresAt.getTime(),\n has_publishable_client_key: options.hasPublishableClientKey,\n has_secret_server_key: options.hasSecretServerKey,\n has_super_secret_admin_key: options.hasSuperSecretAdminKey,\n };\n}\n" + }, + { + "path": "customers/index.ts", + "content": "import { inlineProductSchema } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport * as yup from \"yup\";\nimport { AsyncStoreProperty } from \"../common\";\n\nexport type InlineProduct = yup.InferType;\n\nexport type Item = {\n displayName: string,\n /**\n * May be negative.\n */\n quantity: number,\n /**\n * Equal to Math.max(0, quantity).\n */\n nonNegativeQuantity: number,\n};\n\nexport type ServerItem = Item & {\n increaseQuantity(amount: number): Promise,\n /**\n * Decreases the quantity by the given amount.\n *\n * Note that you may want to use tryDecreaseQuantity instead, as it will prevent the quantity from going below 0 in a race-condition-free way.\n */\n decreaseQuantity(amount: number): Promise,\n /**\n * Decreases the quantity by the given amount and returns true if the result is non-negative; returns false and does nothing if the result would be negative.\n *\n * Most useful for pre-paid credits.\n */\n tryDecreaseQuantity(amount: number): Promise,\n};\n\nexport type CustomerProduct = {\n id: string | null,\n quantity: number,\n displayName: string,\n customerType: \"user\" | \"team\" | \"custom\",\n isServerOnly: boolean,\n stackable: boolean,\n type: \"one_time\" | \"subscription\",\n subscription: null | {\n currentPeriodEnd: Date | null,\n cancelAtPeriodEnd: boolean,\n isCancelable: boolean,\n },\n switchOptions?: Array<{\n productId: string,\n displayName: string,\n prices: InlineProduct[\"prices\"],\n }>,\n};\n\nexport type CustomerProductsList = CustomerProduct[] & {\n nextCursor: string | null,\n};\n\nexport type CustomerProductsListOptions = {\n cursor?: string,\n limit?: number,\n};\n\nexport type CustomerProductsRequestOptions =\n | ({ userId: string } & CustomerProductsListOptions)\n | ({ teamId: string } & CustomerProductsListOptions)\n | ({ customCustomerId: string } & CustomerProductsListOptions);\n\nexport type CustomerInvoiceStatus = \"draft\" | \"open\" | \"paid\" | \"uncollectible\" | \"void\" | null;\n\nexport type CustomerInvoice = {\n createdAt: Date,\n status: CustomerInvoiceStatus,\n amountTotal: number,\n hostedInvoiceUrl: string | null,\n};\n\nexport type CustomerInvoicesList = CustomerInvoice[] & {\n nextCursor: string | null,\n};\n\nexport type CustomerInvoicesListOptions = {\n cursor?: string,\n limit?: number,\n};\n\nexport type CustomerInvoicesRequestOptions =\n | ({ userId: string } & CustomerInvoicesListOptions)\n | ({ teamId: string } & CustomerInvoicesListOptions);\n\nexport type CustomerDefaultPaymentMethod = {\n id: string,\n brand: string | null,\n last4: string | null,\n exp_month: number | null,\n exp_year: number | null,\n} | null;\n\nexport type CustomerBilling = {\n hasCustomer: boolean,\n defaultPaymentMethod: CustomerDefaultPaymentMethod,\n};\n\nexport type CustomerPaymentMethodSetupIntent = {\n clientSecret: string,\n stripeAccountId: string,\n};\n\nexport type Customer =\n & {\n readonly id: string,\n\n createCheckoutUrl(options: (\n | { productId: string, returnUrl?: string }\n | (IsServer extends true ? { product: InlineProduct, returnUrl?: string } : never)\n )): Promise,\n\n createPaymentMethodSetupIntent(): Promise,\n\n setDefaultPaymentMethodFromSetupIntent(setupIntentId: string): Promise,\n\n switchSubscription(options: { fromProductId: string, toProductId: string, priceId?: string, quantity?: number }): Promise,\n }\n & AsyncStoreProperty<\n \"billing\",\n [],\n CustomerBilling,\n false\n >\n & AsyncStoreProperty<\n \"item\",\n [itemId: string],\n IsServer extends true ? ServerItem : Item,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options?: CustomerProductsListOptions],\n CustomerProductsList,\n true\n >\n & AsyncStoreProperty<\n \"invoices\",\n [options?: CustomerInvoicesListOptions],\n CustomerInvoicesList,\n true\n >\n & (IsServer extends true ? {\n grantProduct(\n product: { productId: string, quantity?: number } | { product: InlineProduct, quantity?: number },\n ): Promise,\n } : {});\n" + }, + { + "path": "contact-channels/index.ts", + "content": "import { ContactChannelsCrud } from \"@stackframe/stack-shared/dist/interface/crud/contact-channels\";\n\n\nexport type ContactChannel = {\n id: string,\n value: string,\n type: 'email',\n isPrimary: boolean,\n isVerified: boolean,\n usedForAuth: boolean,\n\n sendVerificationEmail(options?: { callbackUrl?: string }): Promise,\n update(data: ContactChannelUpdateOptions): Promise,\n delete(): Promise,\n}\n\nexport type ContactChannelCreateOptions = {\n value: string,\n type: 'email',\n usedForAuth: boolean,\n isPrimary?: boolean,\n}\n\nexport function contactChannelCreateOptionsToCrud(userId: string, options: ContactChannelCreateOptions): ContactChannelsCrud[\"Client\"][\"Create\"] {\n return {\n value: options.value,\n type: options.type,\n used_for_auth: options.usedForAuth,\n is_primary: options.isPrimary,\n user_id: userId,\n };\n}\n\nexport type ContactChannelUpdateOptions = {\n usedForAuth?: boolean,\n value?: string,\n isPrimary?: boolean,\n}\n\nexport function contactChannelUpdateOptionsToCrud(options: ContactChannelUpdateOptions): ContactChannelsCrud[\"Client\"][\"Update\"] {\n return {\n value: options.value,\n used_for_auth: options.usedForAuth,\n is_primary: options.isPrimary,\n };\n}\n\nexport type ServerContactChannel = ContactChannel & {\n update(data: ServerContactChannelUpdateOptions): Promise,\n}\nexport type ServerContactChannelUpdateOptions = ContactChannelUpdateOptions & {\n isVerified?: boolean,\n}\n\nexport function serverContactChannelUpdateOptionsToCrud(options: ServerContactChannelUpdateOptions): ContactChannelsCrud[\"Server\"][\"Update\"] {\n return {\n value: options.value,\n is_verified: options.isVerified,\n used_for_auth: options.usedForAuth,\n is_primary: options.isPrimary,\n };\n}\n\nexport type ServerContactChannelCreateOptions = ContactChannelCreateOptions & {\n isVerified?: boolean,\n}\nexport function serverContactChannelCreateOptionsToCrud(userId: string, options: ServerContactChannelCreateOptions): ContactChannelsCrud[\"Server\"][\"Create\"] {\n return {\n type: options.type,\n value: options.value,\n is_verified: options.isVerified,\n user_id: userId,\n used_for_auth: options.usedForAuth,\n is_primary: options.isPrimary,\n };\n}\n" + }, + { + "path": "connected-accounts/index.ts", + "content": "\n\nexport type Connection = {\n id: string,\n};\n\nexport type OAuthConnection = {\n getAccessToken(): Promise<{ accessToken: string }>,\n useAccessToken(): { accessToken: string }, // THIS_LINE_PLATFORM react-like\n} & Connection;\n" + }, + { + "path": "email-templates/index.ts", + "content": "import { EmailTemplateCrud, EmailTemplateType } from \"@stackframe/stack-shared/dist/interface/crud/email-templates\";\n\n\nexport type AdminEmailTemplate = {\n type: EmailTemplateType,\n subject: string,\n content: any,\n isDefault: boolean,\n}\n\nexport type AdminEmailTemplateUpdateOptions = {\n subject?: string,\n content?: any,\n};\nexport function adminEmailTemplateUpdateOptionsToCrud(options: AdminEmailTemplateUpdateOptions): EmailTemplateCrud['Admin']['Update'] {\n return {\n subject: options.subject,\n content: options.content,\n };\n}\n" + }, + { + "path": "email/index.ts", + "content": "import { XOR } from \"@stackframe/stack-shared/dist/utils/types\";\n\nexport type AdminSentEmail = {\n id: string,\n to: string[],\n subject: string,\n recipient: string, // We'll derive this from to[0] for display\n sentAt: Date, // We'll derive this from sent_at_millis for display\n error?: unknown,\n}\n\nexport type AdminEmailOutboxRecipient =\n | { type: \"user-primary-email\", userId: string }\n | { type: \"user-custom-emails\", userId: string, emails: string[] }\n | { type: \"custom-emails\", emails: string[] };\n\nexport type AdminEmailOutboxStatus =\n | \"paused\"\n | \"preparing\"\n | \"rendering\"\n | \"render-error\"\n | \"scheduled\"\n | \"queued\"\n | \"sending\"\n | \"server-error\"\n | \"skipped\"\n | \"bounced\"\n | \"delivery-delayed\"\n | \"sent\"\n | \"opened\"\n | \"clicked\"\n | \"marked-as-spam\";\n\nexport type AdminEmailOutboxSimpleStatus =\n | \"in-progress\"\n | \"ok\"\n | \"error\";\n\n// =============================== BASE TYPES ===============================\n\n// Base fields present on all emails\ntype AdminEmailOutboxBase = {\n id: string,\n createdAt: Date,\n updatedAt: Date,\n to: AdminEmailOutboxRecipient,\n scheduledAt: Date,\n isPaused: false,\n hasRendered: false,\n hasDelivered: false,\n};\n\n// Fields available after rendering completes successfully\n// Use Omit to properly override hasRendered from base\ntype AdminEmailOutboxRenderedFields = Omit & {\n hasRendered: true,\n startedRenderingAt: Date,\n renderedAt: Date,\n subject: string,\n html: string | null,\n text: string | null,\n isTransactional: boolean,\n isHighPriority: boolean,\n notificationCategoryId: string | null,\n};\n\n// Fields available after sending starts\ntype AdminEmailOutboxStartedSendingFields = AdminEmailOutboxRenderedFields & {\n startedSendingAt: Date,\n};\n\n// Fields available after delivery completes\n// Use Omit to properly override hasDelivered from base (inherited through chain)\ntype AdminEmailOutboxFinishedDeliveringFields = Omit & {\n hasDelivered: true,\n deliveredAt: Date,\n};\n\n// =============================== STATUS-SPECIFIC TYPES ===============================\n\n// Use Omit to properly override isPaused from base\nexport type AdminEmailOutboxPaused = Omit & {\n status: \"paused\",\n simpleStatus: \"in-progress\",\n isPaused: true,\n};\n\nexport type AdminEmailOutboxPreparing = AdminEmailOutboxBase & {\n status: \"preparing\",\n simpleStatus: \"in-progress\",\n};\n\nexport type AdminEmailOutboxRendering = AdminEmailOutboxBase & {\n status: \"rendering\",\n simpleStatus: \"in-progress\",\n startedRenderingAt: Date,\n};\n\nexport type AdminEmailOutboxRenderError = AdminEmailOutboxBase & {\n status: \"render-error\",\n simpleStatus: \"error\",\n startedRenderingAt: Date,\n renderedAt: Date,\n renderError: string,\n};\n\nexport type AdminEmailOutboxScheduled = AdminEmailOutboxRenderedFields & {\n status: \"scheduled\",\n simpleStatus: \"in-progress\",\n};\n\nexport type AdminEmailOutboxQueued = AdminEmailOutboxRenderedFields & {\n status: \"queued\",\n simpleStatus: \"in-progress\",\n};\n\nexport type AdminEmailOutboxSending = AdminEmailOutboxStartedSendingFields & {\n status: \"sending\",\n simpleStatus: \"in-progress\",\n};\n\nexport type AdminEmailOutboxServerError = AdminEmailOutboxStartedSendingFields & {\n status: \"server-error\",\n simpleStatus: \"error\",\n errorAt: Date,\n serverError: string,\n};\n\n// SKIPPED can happen at any time, so rendering/sending fields are optional\n// Use Omit to properly override hasRendered from base (can be true or false when skipped)\nexport type AdminEmailOutboxSkipped = Omit & {\n status: \"skipped\",\n simpleStatus: \"ok\",\n hasRendered: boolean,\n skippedAt: Date,\n skippedReason: string,\n skippedDetails: Record,\n // Optional fields depending on when skipped\n startedRenderingAt?: Date,\n renderedAt?: Date,\n subject?: string,\n html?: string | null,\n text?: string | null,\n isTransactional?: boolean,\n isHighPriority?: boolean,\n notificationCategoryId?: string | null,\n startedSendingAt?: Date,\n};\n\nexport type AdminEmailOutboxBounced = AdminEmailOutboxStartedSendingFields & {\n status: \"bounced\",\n simpleStatus: \"error\",\n bouncedAt: Date,\n};\n\nexport type AdminEmailOutboxDeliveryDelayed = AdminEmailOutboxStartedSendingFields & {\n status: \"delivery-delayed\",\n simpleStatus: \"ok\",\n deliveryDelayedAt: Date,\n};\n\nexport type AdminEmailOutboxSent = AdminEmailOutboxFinishedDeliveringFields & {\n status: \"sent\",\n simpleStatus: \"ok\",\n canHaveDeliveryInfo: boolean,\n};\n\nexport type AdminEmailOutboxOpened = AdminEmailOutboxFinishedDeliveringFields & {\n status: \"opened\",\n simpleStatus: \"ok\",\n openedAt: Date,\n canHaveDeliveryInfo: true,\n};\n\nexport type AdminEmailOutboxClicked = AdminEmailOutboxFinishedDeliveringFields & {\n status: \"clicked\",\n simpleStatus: \"ok\",\n clickedAt: Date,\n canHaveDeliveryInfo: true,\n};\n\nexport type AdminEmailOutboxMarkedAsSpam = AdminEmailOutboxFinishedDeliveringFields & {\n status: \"marked-as-spam\",\n simpleStatus: \"ok\",\n markedAsSpamAt: Date,\n canHaveDeliveryInfo: true,\n};\n\n// =============================== DISCRIMINATED UNION ===============================\n\nexport type AdminEmailOutbox =\n | AdminEmailOutboxPaused\n | AdminEmailOutboxPreparing\n | AdminEmailOutboxRendering\n | AdminEmailOutboxRenderError\n | AdminEmailOutboxScheduled\n | AdminEmailOutboxQueued\n | AdminEmailOutboxSending\n | AdminEmailOutboxServerError\n | AdminEmailOutboxSkipped\n | AdminEmailOutboxBounced\n | AdminEmailOutboxDeliveryDelayed\n | AdminEmailOutboxSent\n | AdminEmailOutboxOpened\n | AdminEmailOutboxClicked\n | AdminEmailOutboxMarkedAsSpam;\n\ntype SendEmailOptionsBase = {\n themeId?: string | null | false,\n subject?: string,\n notificationCategoryName?: string,\n}\n\n\nexport type SendEmailOptions = SendEmailOptionsBase\n & XOR<[\n { userIds: string[] },\n { allUsers: true }\n ]>\n & XOR<[\n { html: string },\n {\n templateId: string,\n variables?: Record,\n },\n { draftId: string }\n ]>\n\nexport type EmailDeliveryWindowStats = {\n sent: number,\n bounced: number,\n marked_as_spam: number,\n};\n\nexport type EmailDeliveryStats = {\n hour: EmailDeliveryWindowStats,\n day: EmailDeliveryWindowStats,\n week: EmailDeliveryWindowStats,\n month: EmailDeliveryWindowStats,\n};\n\nexport type EmailDeliveryCapacity = {\n rate_per_second: number,\n penalty_factor: number,\n};\n\nexport type EmailDeliveryInfo = {\n stats: EmailDeliveryStats,\n capacity: EmailDeliveryCapacity,\n};\n" + }, + { + "path": "data-vault/index.ts", + "content": "import { AsyncStoreProperty } from \"../common\";\n\nexport type DataVaultStore =\n & {\n id: string,\n setValue: (key: string, value: string, options: { secret: string }) => Promise,\n }\n & AsyncStoreProperty<\"value\", [key: string, options: { secret: string }], string | null, false>;\n" + }, + { + "path": "apps/index.ts", + "content": "export {\n StackClientApp\n} from \"./interfaces/client-app\";\nexport type {\n StackClientAppConstructor,\n StackClientAppConstructorOptions,\n StackClientAppJson\n} from \"./interfaces/client-app\";\n\nexport {\n StackServerApp\n} from \"./interfaces/server-app\";\nexport type {\n StackServerAppConstructor,\n StackServerAppConstructorOptions\n} from \"./interfaces/server-app\";\n\nexport {\n StackAdminApp\n} from \"./interfaces/admin-app\";\nexport type {\n StackAdminAppConstructor,\n StackAdminAppConstructorOptions\n} from \"./interfaces/admin-app\";\n\n" + }, + { + "path": "api-keys/index.ts", + "content": "import { TeamApiKeysCrud, UserApiKeysCrud, teamApiKeysCreateInputSchema, userApiKeysCreateInputSchema } from \"@stackframe/stack-shared/dist/interface/crud/project-api-keys\";\nimport { filterUndefined } from \"@stackframe/stack-shared/dist/utils/objects\";\nimport { IfAndOnlyIf, PrettifyType } from \"@stackframe/stack-shared/dist/utils/types\";\nimport type * as yup from \"yup\";\n\nexport type ApiKeyType = \"user\" | \"team\";\n\nexport type ApiKey =\n & {\n id: string,\n description: string,\n expiresAt?: Date,\n manuallyRevokedAt?: Date | null,\n createdAt: Date,\n value: IfAndOnlyIf,\n update(options: ApiKeyUpdateOptions): Promise,\n revoke: () => Promise,\n isValid: () => boolean,\n whyInvalid: () => \"manually-revoked\" | \"expired\" | null,\n }\n & (\n | (\"user\" extends Type ? { type: \"user\", userId: string } : never)\n | (\"team\" extends Type ? { type: \"team\", teamId: string } : never)\n );\n\nexport type UserApiKeyFirstView = PrettifyType>;\nexport type UserApiKey = PrettifyType>;\n\nexport type TeamApiKeyFirstView = PrettifyType>;\nexport type TeamApiKey = PrettifyType>;\n\nexport type ApiKeyCreationOptions =\n & {\n description: string,\n expiresAt: Date | null,\n /**\n * Whether the API key should be considered public. A public API key will not be detected by the secret scanner, which\n * automatically revokes API keys when it detects that they may have been exposed to the public.\n */\n isPublic?: boolean,\n };\nexport function apiKeyCreationOptionsToCrud(type: \"user\", userId: string, options: ApiKeyCreationOptions<\"user\">): Promise>;\nexport function apiKeyCreationOptionsToCrud(type: \"team\", teamId: string, options: ApiKeyCreationOptions<\"team\">): Promise>;\nexport function apiKeyCreationOptionsToCrud(type: ApiKeyType, userIdOrTeamId: string, options: ApiKeyCreationOptions): Promise | yup.InferType>;\nexport async function apiKeyCreationOptionsToCrud(type: ApiKeyType, userIdOrTeamId: string, options: ApiKeyCreationOptions): Promise | yup.InferType> {\n return {\n description: options.description,\n expires_at_millis: options.expiresAt == null ? options.expiresAt : options.expiresAt.getTime(),\n is_public: options.isPublic,\n ...(type === \"user\" ? { user_id: userIdOrTeamId } : { team_id: userIdOrTeamId }),\n };\n}\n\n\nexport type ApiKeyUpdateOptions = {\n description?: string,\n expiresAt?: Date | null,\n revoked?: boolean,\n};\nexport function apiKeyUpdateOptionsToCrud(type: \"user\", options: ApiKeyUpdateOptions<\"user\">): Promise;\nexport function apiKeyUpdateOptionsToCrud(type: \"team\", options: ApiKeyUpdateOptions<\"team\">): Promise;\nexport function apiKeyUpdateOptionsToCrud(type: ApiKeyType, options: ApiKeyUpdateOptions): Promise;\nexport async function apiKeyUpdateOptionsToCrud(type: ApiKeyType, options: ApiKeyUpdateOptions): Promise {\n return filterUndefined({\n description: options.description,\n expires_at_millis: options.expiresAt == null ? options.expiresAt : options.expiresAt.getTime(),\n revoked: options.revoked,\n });\n}\n" + }, + { + "path": "apps/interfaces/server-app.ts", + "content": "import { KnownErrors } from \"@stackframe/stack-shared\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport type { GenericQueryCtx } from \"convex/server\";\nimport { AsyncStoreProperty, GetCurrentPartialUserOptions, GetCurrentUserOptions } from \"../../common\";\nimport { CustomerProductsList, CustomerProductsRequestOptions, InlineProduct, ServerItem } from \"../../customers\";\nimport { DataVaultStore } from \"../../data-vault\";\nimport { EmailDeliveryInfo, SendEmailOptions } from \"../../email\";\nimport { ServerListUsersOptions, ServerTeam, ServerTeamCreateOptions } from \"../../teams\";\nimport { ProjectCurrentServerUser, ServerOAuthProvider, ServerUser, ServerUserCreateOptions, SyncedPartialServerUser, TokenPartialUser } from \"../../users\";\nimport { _StackServerAppImpl } from \"../implementations\";\nimport { StackClientApp, StackClientAppConstructorOptions } from \"./client-app\";\n\n\nexport type StackServerAppConstructorOptions = StackClientAppConstructorOptions & {\n secretServerKey?: string,\n};\n\nexport type StackServerApp = (\n & {\n createTeam(data: ServerTeamCreateOptions): Promise,\n /**\n * @deprecated use `getUser()` instead\n */\n getServerUser(): Promise | null>,\n\n createUser(options: ServerUserCreateOptions): Promise,\n grantProduct(options: (\n ({ userId: string } | { teamId: string } | { customCustomerId: string }) &\n ({ productId: string } | { product: InlineProduct }) &\n { quantity?: number }\n )): Promise,\n\n // IF_PLATFORM react-like\n useUser(options: GetCurrentUserOptions & { or: 'redirect' }): ProjectCurrentServerUser,\n useUser(options: GetCurrentUserOptions & { or: 'throw' }): ProjectCurrentServerUser,\n useUser(options: GetCurrentUserOptions & { or: 'anonymous' }): ProjectCurrentServerUser,\n useUser(options?: GetCurrentUserOptions): ProjectCurrentServerUser | null,\n useUser(id: string): ServerUser | null,\n useUser(options: { apiKey: string, or?: \"return-null\" | \"anonymous\" }): ServerUser | null,\n useUser(options: { from: \"convex\", ctx: GenericQueryCtx, or?: \"return-null\" | \"anonymous\" }): ServerUser | null,\n // END_PLATFORM\n\n getUser(options: GetCurrentUserOptions & { or: 'redirect' }): Promise>,\n getUser(options: GetCurrentUserOptions & { or: 'throw' }): Promise>,\n getUser(options: GetCurrentUserOptions & { or: 'anonymous' }): Promise>,\n getUser(options?: GetCurrentUserOptions): Promise | null>,\n getUser(id: string): Promise,\n getUser(options: { apiKey: string, or?: \"return-null\" | \"anonymous\" }): Promise,\n getUser(options: { from: \"convex\", ctx: GenericQueryCtx, or?: \"return-null\" | \"anonymous\" }): Promise,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions & { from: 'token' }): Promise,\n getPartialUser(options: GetCurrentPartialUserOptions & { from: 'convex' }): Promise,\n getPartialUser(options: GetCurrentPartialUserOptions): Promise,\n // IF_PLATFORM react-like\n usePartialUser(options: GetCurrentPartialUserOptions & { from: 'token' }): TokenPartialUser | null,\n usePartialUser(options: GetCurrentPartialUserOptions & { from: 'convex' }): TokenPartialUser | null,\n usePartialUser(options: GetCurrentPartialUserOptions): SyncedPartialServerUser | TokenPartialUser | null,\n // END_PLATFORM\n // IF_PLATFORM react-like\n useTeam(id: string): ServerTeam | null,\n useTeam(options: { apiKey: string }): ServerTeam | null,\n // END_PLATFORM\n getTeam(id: string): Promise,\n getTeam(options: { apiKey: string }): Promise,\n\n\n useUsers(options?: ServerListUsersOptions): ServerUser[] & { nextCursor: string | null }, // THIS_LINE_PLATFORM react-like\n listUsers(options?: ServerListUsersOptions): Promise,\n\n // TODO this should actually be on ServerUser\n createOAuthProvider(options: {\n userId: string,\n accountId: string,\n providerConfigId: string,\n email: string,\n allowSignIn: boolean,\n allowConnectedAccounts: boolean,\n }): Promise>>,\n\n sendEmail(options: SendEmailOptions): Promise,\n\n getEmailDeliveryStats(): Promise,\n // IF_PLATFORM react-like\n useEmailDeliveryStats(): EmailDeliveryInfo,\n // END_PLATFORM\n }\n & AsyncStoreProperty<\"user\", [id: string], ServerUser | null, false>\n & Omit, \"listUsers\" | \"useUsers\">\n & AsyncStoreProperty<\"teams\", [], ServerTeam[], true>\n & AsyncStoreProperty<\"dataVaultStore\", [id: string], DataVaultStore, false>\n & AsyncStoreProperty<\n \"item\",\n [{ itemId: string, userId: string } | { itemId: string, teamId: string } | { itemId: string, customCustomerId: string }],\n ServerItem,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options: CustomerProductsRequestOptions],\n CustomerProductsList,\n true\n >\n & StackClientApp\n);\nexport type StackServerAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackServerAppConstructorOptions): StackServerApp,\n new (options: StackServerAppConstructorOptions): StackServerApp,\n};\nexport const StackServerApp: StackServerAppConstructor = _StackServerAppImpl;\n" + }, + { + "path": "apps/interfaces/client-app.ts", + "content": "import { KnownErrors } from \"@stackframe/stack-shared\";\nimport { CurrentUserCrud } from \"@stackframe/stack-shared/dist/interface/crud/current-user\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { AsyncStoreProperty, AuthLike, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, TokenStoreInit, stackAppInternalsSymbol } from \"../../common\";\nimport { CustomerInvoicesList, CustomerInvoicesRequestOptions, CustomerProductsList, CustomerProductsRequestOptions, Item } from \"../../customers\";\nimport { Project } from \"../../projects\";\nimport { ProjectCurrentUser, SyncedPartialUser, TokenPartialUser } from \"../../users\";\nimport { _StackClientAppImpl } from \"../implementations\";\n\nexport type StackClientAppConstructorOptions = {\n baseUrl?: string | { browser: string, server: string },\n extraRequestHeaders?: Record,\n projectId?: ProjectId,\n publishableClientKey?: string,\n urls?: Partial,\n oauthScopesOnSignIn?: Partial,\n tokenStore?: TokenStoreInit,\n redirectMethod?: RedirectMethod,\n inheritsFrom?: StackClientApp,\n\n /**\n * By default, the Stack app will automatically prefetch some data from Stack's server when this app is first\n * constructed. This improves the performance of your app, but will create network requests that are unnecessary if\n * the app is never used or disposed of immediately. To disable this behavior, set this option to true.\n */\n noAutomaticPrefetch?: boolean,\n} & (\n { tokenStore: TokenStoreInit } | { tokenStore?: undefined, inheritsFrom: StackClientApp }\n) & (\n string extends ProjectId ? unknown : ({ projectId: ProjectId } | { inheritsFrom: StackClientApp })\n);\n\n\nexport type StackClientAppJson = StackClientAppConstructorOptions & { inheritsFrom?: undefined } & {\n uniqueIdentifier: string,\n // note: if you add more fields here, make sure to ensure the checkString in the constructor has/doesn't have them\n};\n\nexport type StackClientApp = (\n & {\n readonly projectId: ProjectId,\n\n readonly urls: Readonly,\n\n signInWithOAuth(provider: string, options?: { returnTo?: string }): Promise,\n signInWithCredential(options: { email: string, password: string, noRedirect?: boolean }): Promise>,\n signUpWithCredential(options: { email: string, password: string, noRedirect?: boolean } & ({ noVerificationCallback: true } | { noVerificationCallback?: false, verificationCallbackUrl?: string })): Promise>,\n signInWithPasskey(): Promise>,\n callOAuthCallback(): Promise,\n promptCliLogin(options: { appUrl: string, expiresInMillis?: number }): Promise>,\n sendForgotPasswordEmail(email: string, options?: { callbackUrl?: string }): Promise>,\n sendMagicLinkEmail(email: string, options?: { callbackUrl?: string }): Promise>,\n resetPassword(options: { code: string, password: string }): Promise>,\n verifyPasswordResetCode(code: string): Promise>,\n verifyTeamInvitationCode(code: string): Promise>,\n acceptTeamInvitation(code: string): Promise>,\n getTeamInvitationDetails(code: string): Promise>,\n verifyEmail(code: string): Promise>,\n signInWithMagicLink(code: string, options?: { noRedirect?: boolean }): Promise>,\n signInWithMfa(otp: string, code: string, options?: { noRedirect?: boolean }): Promise>,\n\n redirectToOAuthCallback(): Promise,\n\n getConvexClientAuth(options: HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }): (args: { forceRefreshToken: boolean }) => Promise,\n getConvexHttpClientAuth(options: { tokenStore: TokenStoreInit }): Promise,\n\n // IF_PLATFORM react-like\n useUser(options: GetCurrentUserOptions & { or: 'redirect' }): ProjectCurrentUser,\n useUser(options: GetCurrentUserOptions & { or: 'throw' }): ProjectCurrentUser,\n useUser(options: GetCurrentUserOptions & { or: 'anonymous' }): ProjectCurrentUser,\n useUser(options?: GetCurrentUserOptions): ProjectCurrentUser | null,\n // END_PLATFORM\n\n getUser(options: GetCurrentUserOptions & { or: 'redirect' }): Promise>,\n getUser(options: GetCurrentUserOptions & { or: 'throw' }): Promise>,\n getUser(options: GetCurrentUserOptions & { or: 'anonymous' }): Promise>,\n getUser(options?: GetCurrentUserOptions): Promise | null>,\n\n cancelSubscription(options: { productId: string } | { productId: string, teamId: string }): Promise,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions & { from: 'token' }): Promise,\n getPartialUser(options: GetCurrentPartialUserOptions & { from: 'convex' }): Promise,\n getPartialUser(options: GetCurrentPartialUserOptions): Promise,\n // IF_PLATFORM react-like\n usePartialUser(options: GetCurrentPartialUserOptions & { from: 'token' }): TokenPartialUser | null,\n usePartialUser(options: GetCurrentPartialUserOptions & { from: 'convex' }): TokenPartialUser | null,\n usePartialUser(options: GetCurrentPartialUserOptions): SyncedPartialUser | TokenPartialUser | null,\n // END_PLATFORM\n useNavigate(): (to: string) => void, // THIS_LINE_PLATFORM react-like\n\n [stackAppInternalsSymbol]: {\n toClientJson(): StackClientAppJson,\n setCurrentUser(userJsonPromise: Promise): void,\n getConstructorOptions(): StackClientAppConstructorOptions & { inheritsFrom?: undefined },\n },\n }\n & AsyncStoreProperty<\"project\", [], Project, false>\n & AsyncStoreProperty<\n \"item\",\n [{ itemId: string, userId: string } | { itemId: string, teamId: string } | { itemId: string, customCustomerId: string }],\n Item,\n false\n >\n & AsyncStoreProperty<\n \"products\",\n [options: CustomerProductsRequestOptions],\n CustomerProductsList,\n true\n >\n & AsyncStoreProperty<\n \"invoices\",\n [options: CustomerInvoicesRequestOptions],\n CustomerInvoicesList,\n true\n >\n & { [K in `redirectTo${Capitalize>}`]: (options?: RedirectToOptions) => Promise }\n & AuthLike\n);\nexport type StackClientAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackClientAppConstructorOptions): StackClientApp,\n new(options: StackClientAppConstructorOptions): StackClientApp,\n\n [stackAppInternalsSymbol]: {\n fromClientJson(\n json: StackClientAppJson\n ): StackClientApp,\n },\n};\nexport const StackClientApp: StackClientAppConstructor = _StackClientAppImpl;\n" + }, + { + "path": "apps/interfaces/admin-app.ts", + "content": "import { ChatContent } from \"@stackframe/stack-shared/dist/interface/admin-interface\";\nimport { AnalyticsQueryOptions, AnalyticsQueryResponse } from \"@stackframe/stack-shared/dist/interface/crud/analytics\";\nimport type { Transaction, TransactionType } from \"@stackframe/stack-shared/dist/interface/crud/transactions\";\nimport { InternalSession } from \"@stackframe/stack-shared/dist/sessions\";\nimport type { MoneyAmount } from \"@stackframe/stack-shared/dist/utils/currency-constants\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { AsyncStoreProperty, EmailConfig } from \"../../common\";\nimport { AdminEmailOutbox, AdminSentEmail } from \"../../email\";\nimport { InternalApiKey, InternalApiKeyCreateOptions, InternalApiKeyFirstView } from \"../../internal-api-keys\";\nimport { AdminProjectPermission, AdminProjectPermissionDefinition, AdminProjectPermissionDefinitionCreateOptions, AdminProjectPermissionDefinitionUpdateOptions, AdminTeamPermission, AdminTeamPermissionDefinition, AdminTeamPermissionDefinitionCreateOptions, AdminTeamPermissionDefinitionUpdateOptions } from \"../../permissions\";\nimport { AdminProject } from \"../../projects\";\nimport { _StackAdminAppImpl } from \"../implementations\";\nimport { StackServerApp, StackServerAppConstructorOptions } from \"./server-app\";\n\nexport type EmailOutboxListOptions = {\n status?: string,\n simpleStatus?: string,\n limit?: number,\n cursor?: string,\n};\n\nexport type EmailOutboxListResult = {\n items: AdminEmailOutbox[],\n nextCursor: string | null,\n};\n\nexport type EmailOutboxUpdateOptions = {\n isPaused?: boolean,\n scheduledAtMillis?: number,\n cancel?: boolean,\n};\n\n\nexport type StackAdminAppConstructorOptions = (\n & StackServerAppConstructorOptions\n & {\n superSecretAdminKey?: string,\n projectOwnerSession?: InternalSession,\n }\n);\n\n\nexport type StackAdminApp = (\n & AsyncStoreProperty<\"project\", [], AdminProject, false>\n & AsyncStoreProperty<\"internalApiKeys\", [], InternalApiKey[], true>\n & AsyncStoreProperty<\"teamPermissionDefinitions\", [], AdminTeamPermissionDefinition[], true>\n & AsyncStoreProperty<\"projectPermissionDefinitions\", [], AdminProjectPermissionDefinition[], true>\n & AsyncStoreProperty<\"emailThemes\", [], { id: string, displayName: string }[], true>\n & AsyncStoreProperty<\"emailPreview\", [{ themeId?: string | null | false, themeTsxSource?: string, templateId?: string, templateTsxSource?: string }], string, false>\n & AsyncStoreProperty<\"emailTemplates\", [], { id: string, displayName: string, themeId?: string, tsxSource: string }[], true>\n & AsyncStoreProperty<\"emailDrafts\", [], { id: string, displayName: string, themeId: string | undefined | false, tsxSource: string, sentAt: Date | null }[], true>\n & AsyncStoreProperty<\"stripeAccountInfo\", [], { account_id: string, charges_enabled: boolean, details_submitted: boolean, payouts_enabled: boolean } | null, false>\n & AsyncStoreProperty<\n \"transactions\",\n [{\n cursor?: string,\n limit?: number,\n type?: TransactionType,\n customerType?: 'user' | 'team' | 'custom',\n }],\n { transactions: Transaction[], nextCursor: string | null },\n true\n >\n & {\n createInternalApiKey(options: InternalApiKeyCreateOptions): Promise,\n\n createTeamPermissionDefinition(data: AdminTeamPermissionDefinitionCreateOptions): Promise,\n updateTeamPermissionDefinition(permissionId: string, data: AdminTeamPermissionDefinitionUpdateOptions): Promise,\n deleteTeamPermissionDefinition(permissionId: string): Promise,\n\n createProjectPermissionDefinition(data: AdminProjectPermissionDefinitionCreateOptions): Promise,\n updateProjectPermissionDefinition(permissionId: string, data: AdminProjectPermissionDefinitionUpdateOptions): Promise,\n deleteProjectPermissionDefinition(permissionId: string): Promise,\n\n useSvixToken(): { token: string, url: string | undefined }, // THIS_LINE_PLATFORM react-like\n\n sendTestEmail(options: {\n recipientEmail: string,\n emailConfig: EmailConfig,\n }): Promise>,\n\n sendTestWebhook(options: { endpointId: string }): Promise>,\n\n sendSignInInvitationEmail(email: string, callbackUrl: string): Promise,\n\n listSentEmails(): Promise,\n\n useEmailTheme(id: string): { displayName: string, tsxSource: string }, // THIS_LINE_PLATFORM react-like\n createEmailTheme(displayName: string): Promise<{ id: string }>,\n updateEmailTheme(id: string, tsxSource: string): Promise,\n\n sendChatMessage(\n threadId: string,\n contextType: \"email-theme\" | \"email-template\" | \"email-draft\",\n messages: Array<{ role: string, content: any }>,\n abortSignal?: AbortSignal,\n ): Promise<{ content: ChatContent }>,\n saveChatMessage(threadId: string, message: any): Promise,\n listChatMessages(threadId: string): Promise<{ messages: Array }>,\n updateEmailTemplate(id: string, tsxSource: string, themeId: string | null | false): Promise<{ renderedHtml: string }>,\n createEmailTemplate(displayName: string): Promise<{ id: string }>,\n\n setupPayments(): Promise<{ url: string }>,\n createStripeWidgetAccountSession(): Promise<{ client_secret: string }>,\n getPaymentMethodConfigs(): Promise<{ configId: string, methods: Array<{ id: string, name: string, enabled: boolean, available: boolean, overridable: boolean }> } | null>,\n updatePaymentMethodConfigs(configId: string, updates: Record): Promise,\n createEmailDraft(options: { displayName: string, themeId?: string | undefined | false, tsxSource?: string }): Promise<{ id: string }>,\n updateEmailDraft(id: string, data: { displayName?: string, themeId?: string | undefined | false, tsxSource?: string }): Promise,\n createItemQuantityChange(options: (\n { userId: string, itemId: string, quantity: number, expiresAt?: string, description?: string } |\n { teamId: string, itemId: string, quantity: number, expiresAt?: string, description?: string } |\n { customCustomerId: string, itemId: string, quantity: number, expiresAt?: string, description?: string }\n )): Promise,\n refundTransaction(options: {\n type: \"subscription\" | \"one-time-purchase\",\n id: string,\n refundEntries: Array<{ entryIndex: number, quantity: number, amountUsd: MoneyAmount }>,\n }): Promise,\n queryAnalytics(options: AnalyticsQueryOptions): Promise,\n\n // Email Outbox methods\n listOutboxEmails(options?: EmailOutboxListOptions): Promise,\n getOutboxEmail(id: string): Promise,\n updateOutboxEmail(id: string, options: EmailOutboxUpdateOptions): Promise,\n pauseOutboxEmail(id: string): Promise,\n unpauseOutboxEmail(id: string): Promise,\n cancelOutboxEmail(id: string): Promise,\n }\n & StackServerApp\n);\nexport type StackAdminAppConstructor = {\n new <\n HasTokenStore extends boolean,\n ProjectId extends string\n >(options: StackAdminAppConstructorOptions): StackAdminApp,\n new(options: StackAdminAppConstructorOptions): StackAdminApp,\n};\nexport const StackAdminApp: StackAdminAppConstructor = _StackAdminAppImpl;\n" + } +]; diff --git a/apps/e2e/tests/js/email.test.ts b/apps/e2e/tests/js/email.test.ts index e7f54e344..aed338dc2 100644 --- a/apps/e2e/tests/js/email.test.ts +++ b/apps/e2e/tests/js/email.test.ts @@ -188,7 +188,8 @@ it("should provide delivery statistics", async ({ expect }) => { }); // wait until the email is sent - await wait(5000); + // TODO: use the equivalent of waitForMessagesWithSubject + await wait(10_000); const info = await serverApp.getEmailDeliveryStats();