@hexclave/js 1.0.25 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/dev-tool/dev-tool-core.js +1 -1
  2. package/dist/dev-tool/dev-tool-core.js.map +1 -1
  3. package/dist/esm/dev-tool/dev-tool-core.js +1 -1
  4. package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
  5. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +6 -0
  6. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  7. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js +29 -1
  8. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
  9. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
  10. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  11. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +9 -8
  12. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  13. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +1 -1
  14. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts +1 -0
  15. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
  16. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js +44 -19
  17. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
  18. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.test.js +97 -8
  19. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.test.js.map +1 -1
  20. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts +2 -1
  21. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
  22. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
  23. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  24. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  25. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  26. package/dist/esm/lib/hexclave-app/index.d.ts +2 -1
  27. package/dist/esm/lib/hexclave-app/plan-usage/index.d.ts +27 -0
  28. package/dist/esm/lib/hexclave-app/plan-usage/index.d.ts.map +1 -0
  29. package/dist/esm/lib/hexclave-app/plan-usage/index.js +1 -0
  30. package/dist/esm/lib/hexclave-app/projects/index.d.ts +1 -0
  31. package/dist/esm/lib/hexclave-app/projects/index.d.ts.map +1 -1
  32. package/dist/esm/lib/hexclave-app/projects/index.js.map +1 -1
  33. package/dist/index.d.ts +2 -1
  34. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +6 -0
  35. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  36. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js +29 -1
  37. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
  38. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
  39. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  40. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +9 -8
  41. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  42. package/dist/lib/hexclave-app/apps/implementations/common.js +1 -1
  43. package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts +1 -0
  44. package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
  45. package/dist/lib/hexclave-app/apps/implementations/session-replay.js +43 -18
  46. package/dist/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
  47. package/dist/lib/hexclave-app/apps/implementations/session-replay.test.js +97 -8
  48. package/dist/lib/hexclave-app/apps/implementations/session-replay.test.js.map +1 -1
  49. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +2 -1
  50. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
  51. package/dist/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
  52. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  53. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  54. package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  55. package/dist/lib/hexclave-app/index.d.ts +2 -1
  56. package/dist/lib/hexclave-app/plan-usage/index.d.ts +27 -0
  57. package/dist/lib/hexclave-app/plan-usage/index.d.ts.map +1 -0
  58. package/dist/lib/hexclave-app/plan-usage/index.js +0 -0
  59. package/dist/lib/hexclave-app/projects/index.d.ts +1 -0
  60. package/dist/lib/hexclave-app/projects/index.d.ts.map +1 -1
  61. package/dist/lib/hexclave-app/projects/index.js.map +1 -1
  62. package/package.json +2 -2
  63. package/src/dev-tool/dev-tool-core.ts +1 -1
  64. package/src/lib/hexclave-app/apps/implementations/admin-app-impl.ts +34 -1
  65. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +9 -8
  66. package/src/lib/hexclave-app/apps/implementations/session-replay.test.ts +123 -4
  67. package/src/lib/hexclave-app/apps/implementations/session-replay.ts +63 -29
  68. package/src/lib/hexclave-app/apps/interfaces/admin-app.ts +2 -0
  69. package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
  70. package/src/lib/hexclave-app/index.ts +8 -0
  71. package/src/lib/hexclave-app/plan-usage/index.ts +29 -0
  72. package/src/lib/hexclave-app/projects/index.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"client-app.js","names":["_HexclaveClientAppImpl"],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/client-app.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared\";\nimport { CurrentUserCrud } from \"@hexclave/shared/dist/interface/crud/current-user\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { AsyncStoreProperty, AuthLike, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, ResolvedHandlerUrls, hexclaveAppInternalsSymbol, TokenStoreInit } from \"../../common\";\nimport type { RequestListener } from \"@hexclave/shared/dist/interface/client-interface\";\nimport { CustomerInvoicesList, CustomerInvoicesRequestOptions, CustomerProductsList, CustomerProductsRequestOptions, Item } from \"../../customers\";\nimport { Project } from \"../../projects\";\nimport { ProjectCurrentUser, SyncedPartialUser, TokenPartialUser } from \"../../users\";\nimport { _HexclaveClientAppImpl } from \"../implementations\";\nimport { AnalyticsOptions } from \"../implementations/session-replay\";\n\n/** @deprecated Use `HexclaveClientAppConstructorOptions` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = {\n baseUrl?: string | { browser: string, server: string },\n extraRequestHeaders?: Record<string, string>,\n projectId?: ProjectId,\n publishableClientKey?: string,\n urls?: HandlerUrlOptions,\n oauthScopesOnSignIn?: Partial<OAuthScopesOnSignIn>,\n tokenStore?: TokenStoreInit<HasTokenStore>,\n redirectMethod?: RedirectMethod,\n inheritsFrom?: StackClientApp<any, any>,\n\n /**\n * Whether to show the Hexclave dev tool indicator in browser-like environments.\n *\n * - `true`: always show\n * - `false`: never show\n * - `\"auto\"` (default): show based on NODE_ENV or origin heuristics\n */\n devTool?: boolean | \"auto\",\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 /**\n * Options for analytics and session recording. Replays are enabled by default;\n * set `{ replays: { enabled: false } }` to opt out.\n */\n analytics?: AnalyticsOptions,\n} & (\n { tokenStore: TokenStoreInit<HasTokenStore> } | { tokenStore?: undefined, inheritsFrom: StackClientApp<HasTokenStore, any> }\n) & (\n string extends ProjectId ? unknown : ({ projectId: ProjectId } | { inheritsFrom: StackClientApp<any, ProjectId> })\n);\n\n\n/** @deprecated Use `HexclaveClientAppJson` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { 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\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = (\n & {\n readonly projectId: ProjectId,\n\n /**\n * The version of the Hexclave SDK.\n */\n readonly version: string,\n\n /**\n * @deprecated Do not use `app.urls` for navigation. It is static and does not include runtime redirect-back,\n * cross-domain auth, or sign-out state. Use the matching `redirectToXyz()` method instead, for example\n * `redirectToSignIn()`, `redirectToSignUp()`, `redirectToSignOut()`, or `redirectToAccountSettings()`.\n */\n readonly urls: Readonly<ResolvedHandlerUrls>,\n\n signInWithOAuth(provider: string, options?: { returnTo?: string }): Promise<void>,\n signInWithCredential(options: { email: string, password: string, noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"EmailPasswordMismatch\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signUpWithCredential(options: {\n email: string,\n password: string,\n noRedirect?: boolean,\n } & ({ noVerificationCallback: true } | { noVerificationCallback?: false, verificationCallbackUrl?: string })): Promise<Result<undefined, KnownErrors[\"UserWithEmailAlreadyExists\"] | KnownErrors[\"PasswordRequirementsNotMet\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n signInWithPasskey(): Promise<Result<undefined, KnownErrors[\"PasskeyAuthenticationFailed\"] | KnownErrors[\"InvalidTotpCode\"] | KnownErrors[\"PasskeyWebAuthnError\"]>>,\n callOAuthCallback(): Promise<boolean>,\n promptCliLogin(options: { appUrl: string, expiresInMillis?: number, anonRefreshToken?: string, promptLink?: (url: string, loginCode: string) => void }): Promise<Result<string, KnownErrors[\"CliAuthError\"] | KnownErrors[\"CliAuthExpiredError\"] | KnownErrors[\"CliAuthUsedError\"]>>,\n sendForgotPasswordEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<undefined, KnownErrors[\"UserNotFound\"]>>,\n sendMagicLinkEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<{ nonce: string }, KnownErrors[\"RedirectUrlNotWhitelisted\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n resetPassword(options: { code: string, password: string }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyPasswordResetCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyTeamInvitationCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n acceptTeamInvitation(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n getTeamInvitationDetails(code: string): Promise<Result<{ teamDisplayName: string }, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n verifyEmail(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n signInWithMagicLink(code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signInWithMfa(otp: string, code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n\n redirectToOAuthCallback(): Promise<void>,\n\n getConvexClientAuth(options: HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }): (args: { forceRefreshToken: boolean }) => Promise<string | null>,\n getConvexHttpClientAuth(options: { tokenStore: TokenStoreInit }): Promise<string>,\n\n\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'throw' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'anonymous' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentUser<ProjectId> | null>,\n\n cancelSubscription(options: { productId: string, subscriptionId?: string } | { productId: string, subscriptionId?: string, teamId: string }): Promise<void>,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'token' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'convex' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore>): Promise<SyncedPartialUser | TokenPartialUser | null>,\n\n [hexclaveAppInternalsSymbol]: {\n toClientJson(): StackClientAppJson<HasTokenStore, ProjectId>,\n setCurrentUser(userJsonPromise: Promise<CurrentUserCrud['Client']['Read'] | null>): void,\n getConstructorOptions(): StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { inheritsFrom?: undefined },\n sendSessionReplayBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n sendAnalyticsEventBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n addRequestListener(listener: RequestListener): () => void,\n sendRequest(path: string, requestOptions: RequestInit, requestType?: \"client\" | \"server\" | \"admin\"): Promise<Response>,\n getRedirectMethod(): RedirectMethod,\n redirectToUrl(url: string | URL, options?: { replace?: boolean }): Promise<void>,\n redirectToHandler(handlerName: keyof HandlerUrls, options?: RedirectToOptions): Promise<void>,\n signInWithTokens(tokens: { accessToken: string, refreshToken: string }): Promise<void>,\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<keyof Omit<HandlerUrls, 'handler' | 'oauthCallback'>>}`]: (options?: RedirectToOptions) => Promise<void> }\n & AuthLike<HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }>\n);\n/** @deprecated Use `HexclaveClientAppConstructor` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackClientAppConstructorOptions<HasTokenStore, ProjectId>): StackClientApp<HasTokenStore, ProjectId>,\n new(options: StackClientAppConstructorOptions<boolean, string>): StackClientApp<boolean, string>,\n\n [hexclaveAppInternalsSymbol]: {\n fromClientJson<HasTokenStore extends boolean, ProjectId extends string>(\n json: StackClientAppJson<HasTokenStore, ProjectId>\n ): StackClientApp<HasTokenStore, ProjectId>,\n },\n};\nexport type HexclaveClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppJson<HasTokenStore, ProjectId>;\nexport type HexclaveClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = StackClientApp<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppConstructor = StackClientAppConstructor;\nexport const HexclaveClientApp: HexclaveClientAppConstructor = _HexclaveClientAppImpl;\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport const StackClientApp: StackClientAppConstructor = HexclaveClientApp;\n"],"mappings":";;;;;AA4KA,MAAa,oBAAkDA;;AAE/D,MAAa,iBAA4C"}
1
+ {"version":3,"file":"client-app.js","names":["_HexclaveClientAppImpl"],"sources":["../../../../../src/lib/hexclave-app/apps/interfaces/client-app.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownErrors } from \"@hexclave/shared\";\nimport { CurrentUserCrud } from \"@hexclave/shared/dist/interface/crud/current-user\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { AsyncStoreProperty, AuthLike, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, ResolvedHandlerUrls, hexclaveAppInternalsSymbol, TokenStoreInit } from \"../../common\";\nimport type { RequestListener } from \"@hexclave/shared/dist/interface/client-interface\";\nimport { CustomerInvoicesList, CustomerInvoicesRequestOptions, CustomerProductsList, CustomerProductsRequestOptions, Item } from \"../../customers\";\nimport { Project } from \"../../projects\";\nimport { ProjectCurrentUser, SyncedPartialUser, TokenPartialUser } from \"../../users\";\nimport { _HexclaveClientAppImpl } from \"../implementations\";\nimport { AnalyticsOptions } from \"../implementations/session-replay\";\n\n/** @deprecated Use `HexclaveClientAppConstructorOptions` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = {\n baseUrl?: string | { browser: string, server: string },\n extraRequestHeaders?: Record<string, string>,\n projectId?: ProjectId,\n publishableClientKey?: string,\n urls?: HandlerUrlOptions,\n oauthScopesOnSignIn?: Partial<OAuthScopesOnSignIn>,\n tokenStore?: TokenStoreInit<HasTokenStore>,\n redirectMethod?: RedirectMethod,\n inheritsFrom?: StackClientApp<any, any>,\n\n /**\n * Whether to show the Hexclave dev tool indicator in browser-like environments.\n *\n * - `true`: always show\n * - `false`: never show\n * - `\"auto\"` (default): show based on NODE_ENV or origin heuristics\n */\n devTool?: boolean | \"auto\",\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 /**\n * Options for analytics and session recording. Replays are enabled by default;\n * set `{ replays: { enabled: false } }` to opt out.\n */\n analytics?: AnalyticsOptions,\n} & (\n { tokenStore: TokenStoreInit<HasTokenStore> } | { tokenStore?: undefined, inheritsFrom: StackClientApp<HasTokenStore, any> }\n) & (\n string extends ProjectId ? unknown : ({ projectId: ProjectId } | { inheritsFrom: StackClientApp<any, ProjectId> })\n);\n\n\n/** @deprecated Use `HexclaveClientAppJson` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { 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\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = (\n & {\n readonly projectId: ProjectId,\n\n /**\n * The version of the Hexclave SDK.\n */\n readonly version: string,\n\n /**\n * @deprecated Do not use `app.urls` for navigation. It is static and does not include runtime redirect-back,\n * cross-domain auth, or sign-out state. Use the matching `redirectToXyz()` method instead, for example\n * `redirectToSignIn()`, `redirectToSignUp()`, `redirectToSignOut()`, or `redirectToAccountSettings()`.\n */\n readonly urls: Readonly<ResolvedHandlerUrls>,\n\n signInWithOAuth(provider: string, options?: { returnTo?: string }): Promise<void>,\n signInWithCredential(options: { email: string, password: string, noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"EmailPasswordMismatch\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signUpWithCredential(options: {\n email: string,\n password: string,\n noRedirect?: boolean,\n } & ({ noVerificationCallback: true } | { noVerificationCallback?: false, verificationCallbackUrl?: string })): Promise<Result<undefined, KnownErrors[\"UserWithEmailAlreadyExists\"] | KnownErrors[\"PasswordRequirementsNotMet\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n signInWithPasskey(): Promise<Result<undefined, KnownErrors[\"PasskeyAuthenticationFailed\"] | KnownErrors[\"InvalidTotpCode\"] | KnownErrors[\"PasskeyWebAuthnError\"]>>,\n callOAuthCallback(): Promise<boolean>,\n promptCliLogin(options: { appUrl: string, expiresInMillis?: number, anonRefreshToken?: string, promptLink?: (url: string, loginCode: string) => void }): Promise<Result<string, KnownErrors[\"CliAuthError\"] | KnownErrors[\"CliAuthExpiredError\"] | KnownErrors[\"CliAuthUsedError\"]>>,\n sendForgotPasswordEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<undefined, KnownErrors[\"UserNotFound\"]>>,\n sendMagicLinkEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<{ nonce: string }, KnownErrors[\"RedirectUrlNotWhitelisted\"] | KnownErrors[\"BotChallengeFailed\"]>>,\n resetPassword(options: { code: string, password: string }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyPasswordResetCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n verifyTeamInvitationCode(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n acceptTeamInvitation(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n getTeamInvitationDetails(code: string): Promise<Result<{ teamDisplayName: string }, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"TeamInvitationEmailMismatch\"]>>,\n verifyEmail(code: string): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"]>>,\n signInWithMagicLink(code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n signInWithMfa(otp: string, code: string, options?: { noRedirect?: boolean }): Promise<Result<undefined, KnownErrors[\"VerificationCodeError\"] | KnownErrors[\"InvalidTotpCode\"]>>,\n\n redirectToOAuthCallback(): Promise<void>,\n\n getConvexClientAuth(options: HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }): (args: { forceRefreshToken: boolean }) => Promise<string | null>,\n getConvexHttpClientAuth(options: { tokenStore: TokenStoreInit }): Promise<string>,\n\n\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'redirect' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'throw' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options: GetCurrentUserOptions<HasTokenStore> & { or: 'anonymous' }): Promise<ProjectCurrentUser<ProjectId>>,\n getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentUser<ProjectId> | null>,\n\n cancelSubscription(options: { productId: string, subscriptionId?: string } | { productId: string, subscriptionId?: string, teamId: string }): Promise<void>,\n\n // note: we don't special-case 'anonymous' here to return non-null, see GetPartialUserOptions for more details\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'token' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & { from: 'convex' }): Promise<TokenPartialUser | null>,\n getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore>): Promise<SyncedPartialUser | TokenPartialUser | null>,\n\n [hexclaveAppInternalsSymbol]: {\n toClientJson(): StackClientAppJson<HasTokenStore, ProjectId>,\n setCurrentUser(userJsonPromise: Promise<CurrentUserCrud['Client']['Read'] | null>): void,\n getConstructorOptions(): StackClientAppConstructorOptions<HasTokenStore, ProjectId> & { inheritsFrom?: undefined },\n sendSessionReplayBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n sendAnalyticsEventBatch(body: string, options: { keepalive: boolean }): Promise<Result<Response, Error>>,\n addRequestListener(listener: RequestListener): () => void,\n sendRequest(path: string, requestOptions: RequestInit, requestType?: \"client\" | \"server\" | \"admin\"): Promise<Response>,\n getUrls(): Readonly<ResolvedHandlerUrls>,\n getRedirectMethod(): RedirectMethod,\n redirectToUrl(url: string | URL, options?: { replace?: boolean }): Promise<void>,\n redirectToHandler(handlerName: keyof HandlerUrls, options?: RedirectToOptions): Promise<void>,\n signInWithTokens(tokens: { accessToken: string, refreshToken: string }): Promise<void>,\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<keyof Omit<HandlerUrls, 'handler' | 'oauthCallback'>>}`]: (options?: RedirectToOptions) => Promise<void> }\n & AuthLike<HasTokenStore extends false ? { tokenStore: TokenStoreInit } : { tokenStore?: TokenStoreInit }>\n);\n/** @deprecated Use `HexclaveClientAppConstructor` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport type StackClientAppConstructor = {\n new <\n TokenStoreType extends string,\n HasTokenStore extends (TokenStoreType extends {} ? true : boolean),\n ProjectId extends string\n >(options: StackClientAppConstructorOptions<HasTokenStore, ProjectId>): StackClientApp<HasTokenStore, ProjectId>,\n new(options: StackClientAppConstructorOptions<boolean, string>): StackClientApp<boolean, string>,\n\n [hexclaveAppInternalsSymbol]: {\n fromClientJson<HasTokenStore extends boolean, ProjectId extends string>(\n json: StackClientAppJson<HasTokenStore, ProjectId>\n ): StackClientApp<HasTokenStore, ProjectId>,\n },\n};\nexport type HexclaveClientAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppConstructorOptions<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppJson<HasTokenStore extends boolean, ProjectId extends string> = StackClientAppJson<HasTokenStore, ProjectId>;\nexport type HexclaveClientApp<HasTokenStore extends boolean = boolean, ProjectId extends string = string> = StackClientApp<HasTokenStore, ProjectId>;\nexport type HexclaveClientAppConstructor = StackClientAppConstructor;\nexport const HexclaveClientApp: HexclaveClientAppConstructor = _HexclaveClientAppImpl;\n/** @deprecated Use `HexclaveClientApp` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */\nexport const StackClientApp: StackClientAppConstructor = HexclaveClientApp;\n"],"mappings":";;;;;AA6KA,MAAa,oBAAkDA;;AAE/D,MAAa,iBAA4C"}
@@ -2,6 +2,7 @@ import { GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSig
2
2
  import { AdminEmailOutbox, AdminEmailOutboxRecipient, AdminEmailOutboxSimpleStatus, AdminEmailOutboxStatus, AdminSendAttemptError, AdminSentEmail } from "./email/index.js";
3
3
  import { InternalApiKey, InternalApiKeyBase, InternalApiKeyBaseCrudRead, InternalApiKeyCreateOptions, InternalApiKeyFirstView } from "./internal-api-keys/index.js";
4
4
  import { AdminProjectPermission, AdminProjectPermissionDefinition, AdminProjectPermissionDefinitionCreateOptions, AdminProjectPermissionDefinitionUpdateOptions, AdminTeamPermission, AdminTeamPermissionDefinition, AdminTeamPermissionDefinitionCreateOptions, AdminTeamPermissionDefinitionUpdateOptions } from "./permissions/index.js";
5
+ import { PlanUsage, PlanUsageKind, PlanUsageNextPlanId, PlanUsagePlanId, PlanUsageRow } from "./plan-usage/index.js";
5
6
  import { Connection, OAuthConnection } from "./connected-accounts/index.js";
6
7
  import { ContactChannel, ServerContactChannel } from "./contact-channels/index.js";
7
8
  import { Auth, CurrentInternalServerUser, CurrentInternalUser, CurrentServerUser, CurrentUser, OAuthProvider, ServerOAuthProvider, ServerUser, User } from "./users/index.js";
@@ -12,4 +13,4 @@ import { AdminDomainConfig, AdminEmailConfig, AdminOAuthProviderConfig, AdminPro
12
13
  import { AdminOwnedProject, AdminProject, AdminProjectCreateOptions, AdminProjectUpdateOptions, Project, PushedConfigSource } from "./projects/index.js";
13
14
  import { HexclaveClientApp, HexclaveClientAppConstructor, HexclaveClientAppConstructorOptions, HexclaveClientAppJson, StackClientApp, StackClientAppConstructor, StackClientAppConstructorOptions, StackClientAppJson } from "./apps/interfaces/client-app.js";
14
15
  import { getPagePrompt } from "./url-targets.js";
15
- export { type AdminDomainConfig, type AdminEmailConfig, type AdminEmailOutbox, type AdminEmailOutboxRecipient, type AdminEmailOutboxSimpleStatus, type AdminEmailOutboxStatus, type AdminOAuthProviderConfig, type AdminOwnedProject, type AdminProject, type AdminProjectConfig, type AdminProjectConfigUpdateOptions, type AdminProjectCreateOptions, type AdminProjectPermission, type AdminProjectPermissionDefinition, type AdminProjectPermissionDefinitionCreateOptions, type AdminProjectPermissionDefinitionUpdateOptions, type AdminProjectUpdateOptions, type AdminSendAttemptError, type AdminSentEmail, type AdminTeamPermission, type AdminTeamPermissionDefinition, type AdminTeamPermissionDefinitionCreateOptions, type AdminTeamPermissionDefinitionUpdateOptions, type Auth, type Connection, type ContactChannel, type CurrentInternalServerUser, type CurrentInternalUser, type CurrentServerUser, type CurrentUser, type EditableTeamMemberProfile, type EmailOutboxListOptions, type EmailOutboxListResult, type EmailOutboxUpdateOptions, type GetCurrentUserOptions, type GetCurrentUserOptions as GetUserOptions, type HandlerUrlOptions, type HandlerUrls, HexclaveAdminApp, type HexclaveAdminAppConstructor, type HexclaveAdminAppConstructorOptions, HexclaveClientApp, type HexclaveClientAppConstructor, type HexclaveClientAppConstructorOptions, type HexclaveClientAppJson, HexclaveServerApp, type HexclaveServerAppConstructor, type HexclaveServerAppConstructorOptions, type InternalApiKey, type InternalApiKeyBase, type InternalApiKeyBaseCrudRead, type InternalApiKeyCreateOptions, type InternalApiKeyFirstView, type OAuthConnection, type OAuthProvider, type OAuthProviderConfig, type OAuthScopesOnSignIn, type Project, type ProjectConfig, type PushedConfigSource, type ReceivedTeamInvitation, type ResolvedHandlerUrls, type SentTeamInvitation, type ServerContactChannel, type ServerListUsersOptions, type ServerOAuthProvider, type ServerTeam, type ServerTeamCreateOptions, type ServerTeamMemberProfile, type ServerTeamUpdateOptions, type ServerTeamUser, type ServerUser, StackAdminApp, type StackAdminAppConstructor, type StackAdminAppConstructorOptions, StackClientApp, type StackClientAppConstructor, type StackClientAppConstructorOptions, type StackClientAppJson, StackServerApp, type StackServerAppConstructor, type StackServerAppConstructorOptions, type Team, type TeamCreateOptions, type TeamInvitation, type TeamMemberProfile, type TeamUpdateOptions, type TeamUser, type User, getPagePrompt, hexclaveAppInternalsSymbol };
16
+ export { type AdminDomainConfig, type AdminEmailConfig, type AdminEmailOutbox, type AdminEmailOutboxRecipient, type AdminEmailOutboxSimpleStatus, type AdminEmailOutboxStatus, type AdminOAuthProviderConfig, type AdminOwnedProject, type AdminProject, type AdminProjectConfig, type AdminProjectConfigUpdateOptions, type AdminProjectCreateOptions, type AdminProjectPermission, type AdminProjectPermissionDefinition, type AdminProjectPermissionDefinitionCreateOptions, type AdminProjectPermissionDefinitionUpdateOptions, type AdminProjectUpdateOptions, type AdminSendAttemptError, type AdminSentEmail, type AdminTeamPermission, type AdminTeamPermissionDefinition, type AdminTeamPermissionDefinitionCreateOptions, type AdminTeamPermissionDefinitionUpdateOptions, type Auth, type Connection, type ContactChannel, type CurrentInternalServerUser, type CurrentInternalUser, type CurrentServerUser, type CurrentUser, type EditableTeamMemberProfile, type EmailOutboxListOptions, type EmailOutboxListResult, type EmailOutboxUpdateOptions, type GetCurrentUserOptions, type GetCurrentUserOptions as GetUserOptions, type HandlerUrlOptions, type HandlerUrls, HexclaveAdminApp, type HexclaveAdminAppConstructor, type HexclaveAdminAppConstructorOptions, HexclaveClientApp, type HexclaveClientAppConstructor, type HexclaveClientAppConstructorOptions, type HexclaveClientAppJson, HexclaveServerApp, type HexclaveServerAppConstructor, type HexclaveServerAppConstructorOptions, type InternalApiKey, type InternalApiKeyBase, type InternalApiKeyBaseCrudRead, type InternalApiKeyCreateOptions, type InternalApiKeyFirstView, type OAuthConnection, type OAuthProvider, type OAuthProviderConfig, type OAuthScopesOnSignIn, type PlanUsage, type PlanUsageKind, type PlanUsageNextPlanId, type PlanUsagePlanId, type PlanUsageRow, type Project, type ProjectConfig, type PushedConfigSource, type ReceivedTeamInvitation, type ResolvedHandlerUrls, type SentTeamInvitation, type ServerContactChannel, type ServerListUsersOptions, type ServerOAuthProvider, type ServerTeam, type ServerTeamCreateOptions, type ServerTeamMemberProfile, type ServerTeamUpdateOptions, type ServerTeamUser, type ServerUser, StackAdminApp, type StackAdminAppConstructor, type StackAdminAppConstructorOptions, StackClientApp, type StackClientAppConstructor, type StackClientAppConstructorOptions, type StackClientAppJson, StackServerApp, type StackServerAppConstructor, type StackServerAppConstructorOptions, type Team, type TeamCreateOptions, type TeamInvitation, type TeamMemberProfile, type TeamUpdateOptions, type TeamUser, type User, getPagePrompt, hexclaveAppInternalsSymbol };
@@ -0,0 +1,27 @@
1
+ //#region src/lib/hexclave-app/plan-usage/index.d.ts
2
+ type PlanUsageKind = "current" | "metered" | "capability";
3
+ type PlanUsagePlanId = "free" | "team" | "growth";
4
+ type PlanUsageNextPlanId = "team" | "growth";
5
+ type PlanUsageRow = {
6
+ itemId: string;
7
+ displayName: string;
8
+ kind: PlanUsageKind;
9
+ used: number | null;
10
+ limit: number | null;
11
+ remaining: number | null;
12
+ overage: number | null;
13
+ isUnlimited: boolean;
14
+ };
15
+ type PlanUsage = {
16
+ ownerTeamId: string;
17
+ ownerTeamDisplayName: string;
18
+ planId: PlanUsagePlanId;
19
+ planDisplayName: string;
20
+ periodStart: Date;
21
+ periodEnd: Date;
22
+ nextPlanId: PlanUsageNextPlanId | null;
23
+ rows: PlanUsageRow[];
24
+ };
25
+ //#endregion
26
+ export { PlanUsage, PlanUsageKind, PlanUsageNextPlanId, PlanUsagePlanId, PlanUsageRow };
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/plan-usage/index.ts"],"mappings":";KAIY,aAAA;AAAA,KACA,eAAA;AAAA,KACA,mBAAA;AAAA,KAEA,YAAA;EACV,MAAA;EACA,WAAA;EACA,IAAA,EAAM,aAAA;EACN,IAAA;EACA,KAAA;EACA,SAAA;EACA,OAAA;EACA,WAAA;AAAA;AAAA,KAGU,SAAA;EACV,WAAA;EACA,oBAAA;EACA,MAAA,EAAQ,eAAA;EACR,eAAA;EACA,WAAA,EAAa,IAAA;EACb,SAAA,EAAW,IAAA;EACX,UAAA,EAAY,mBAAA;EACZ,IAAA,EAAM,YAAA;AAAA"}
File without changes
@@ -49,6 +49,7 @@ type AdminProject = {
49
49
  readonly isDevelopmentEnvironment: boolean;
50
50
  readonly ownerTeamId: string | null;
51
51
  readonly onboardingStatus: ProjectOnboardingStatus;
52
+ readonly onboardingState: NonNullable<ProjectsCrud["Admin"]["Read"]["onboarding_state"]> | null;
52
53
  readonly logoUrl: string | null | undefined;
53
54
  readonly logoFullUrl: string | null | undefined;
54
55
  readonly logoDarkModeUrl: string | null | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/projects/index.ts"],"mappings":";;;;;;;;;;AAgBA;;KAAY,kBAAA;EACN,IAAA;EAA4B,KAAA;EAAe,IAAA;EAAc,MAAA;EAAgB,UAAA;EAAoB,cAAA;EAAwB,YAAA;AAAA;EACrH,IAAA;AAAA;EACA,IAAA;AAAA;AAAA,KAEM,iBAAA;EAAiB;;;EAI3B,MAAA,EAAQ,kBAAA;AAAA;AAAA,KAIE,OAAA;EAAA,SACD,EAAA;EAAA,SACA,WAAA;EAAA,SACA,iBAAA;IAAqB,OAAA;EAAA;EAAA,SACrB,cAAA;IAAkB,OAAA;EAAA;EAAA,SAClB,MAAA,EAAQ,aAAA;AAAA;AAAA,KAGP,YAAA;EAAA,SACD,EAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA;EAAA,SACA,SAAA,EAAW,IAAA;EAAA,SACX,gBAAA;EAAA,SACA,wBAAA;EAAA,SACA,WAAA;EAAA,SACA,gBAAA,EAAkB,uBAAA;EAAA,SAClB,OAAA;EAAA,SACA,WAAA;EAAA,SACA,eAAA;EAAA,SACA,mBAAA;EAAA,SAEA,MAAA,EAAQ,kBAAA;EAEjB,MAAA,CAAO,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,yBAAA,GAA4B,OAAA;EAC/D,MAAA,CAAO,IAAA,EAAM,YAAA,GAAe,OAAA;EAE5B,SAAA,CAAU,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,cAAA;EAY7B;;;;;;;EAFV,YAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA+BA;;;;;;;;;;EAnBH,UAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,EACR,OAAA,EAAS,iBAAA,GACR,OAAA;EAoDyB;;;;;;;;;;EAxC5B,kBAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA5DM;;;;;;;;EAsET,qBAAA,CAAsB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,kBAAA;EA/D1C;;;;EAqET,wBAAA,CAAyB,IAAA,EAAM,YAAA,GAAe,OAAA;EA/D9C;;;;;;;EAwEA,uBAAA,CAAwB,IAAA,EAAM,YAAA,EAAc,KAAA,4BAAiC,IAAA,aAAiB,OAAA;EAvEvF;;;;EA6EP,iBAAA,CAAkB,IAAA,EAAM,YAAA,EAAc,KAAA,6BAAkC,OAAA,CAAQ,MAAA;EA3EjD;;;;EAiF/B,qBAAA,CAAsB,IAAA,EAAM,YAAA,EAAc,KAAA,4BAAiC,MAAA,EAAQ,MAAA,oBAA0B,OAAA;EAE7G,uBAAA,CAAwB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,mBAAA;AAAA,IACnD,OAAA;AAAA,KAEQ,iBAAA;EAAA,SACD,GAAA,EAAK,aAAA;AAAA,IACZ,YAAA;AAAA,KAEQ,yBAAA;EACV,WAAA;EACA,WAAA;EACA,gBAAA;EACA,gBAAA,GAAmB,uBAAA;EAjEhB;;;EAqEH,2BAAA;EACA,OAAA;EACA,WAAA;EACA,eAAA;EACA,mBAAA;EACA,MAAA,GAAS,+BAAA;AAAA;AAAA,iBAEK,+BAAA,CAAgC,OAAA,EAAS,yBAAA,GAA4B,YAAA;AAAA,KAgEzE,yBAAA,GAA4B,IAAA,CAAK,yBAAA;EAC3C,WAAA;EACA,MAAA;EACA,wBAAA;AAAA;AAAA,iBAEc,+BAAA,CAAgC,OAAA,EAAS,yBAAA,GAA4B,qBAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/projects/index.ts"],"mappings":";;;;;;;;;;AAgBA;;KAAY,kBAAA;EACN,IAAA;EAA4B,KAAA;EAAe,IAAA;EAAc,MAAA;EAAgB,UAAA;EAAoB,cAAA;EAAwB,YAAA;AAAA;EACrH,IAAA;AAAA;EACA,IAAA;AAAA;AAAA,KAEM,iBAAA;EAAiB;;;EAI3B,MAAA,EAAQ,kBAAA;AAAA;AAAA,KAIE,OAAA;EAAA,SACD,EAAA;EAAA,SACA,WAAA;EAAA,SACA,iBAAA;IAAqB,OAAA;EAAA;EAAA,SACrB,cAAA;IAAkB,OAAA;EAAA;EAAA,SAClB,MAAA,EAAQ,aAAA;AAAA;AAAA,KAGP,YAAA;EAAA,SACD,EAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA;EAAA,SACA,SAAA,EAAW,IAAA;EAAA,SACX,gBAAA;EAAA,SACA,wBAAA;EAAA,SACA,WAAA;EAAA,SACA,gBAAA,EAAkB,uBAAA;EAAA,SAClB,eAAA,EAAiB,WAAA,CAAY,YAAA;EAAA,SAC7B,OAAA;EAAA,SACA,WAAA;EAAA,SACA,eAAA;EAAA,SACA,mBAAA;EAAA,SAEA,MAAA,EAAQ,kBAAA;EAEjB,MAAA,CAAO,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,yBAAA,GAA4B,OAAA;EAC/D,MAAA,CAAO,IAAA,EAAM,YAAA,GAAe,OAAA;EAE5B,SAAA,CAAU,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,cAAA;EAW/B;;;;;;;EADR,YAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA8BO;;;;;;;;;;EAlBV,UAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,EACR,OAAA,EAAS,iBAAA,GACR,OAAA;EA8CqE;;;;;;;;;;EAlCxE,kBAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA9DM;;;;;;;;EAwET,qBAAA,CAAsB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,kBAAA;EAjE1C;;;;EAuET,wBAAA,CAAyB,IAAA,EAAM,YAAA,GAAe,OAAA;EApErC;;;;;;;EA6ET,uBAAA,CAAwB,IAAA,EAAM,YAAA,EAAc,KAAA,4BAAiC,IAAA,aAAiB,OAAA;EAxEnE;;;;EA8E3B,iBAAA,CAAkB,IAAA,EAAM,YAAA,EAAc,KAAA,6BAAkC,OAAA,CAAQ,MAAA;EA7EpD;;;;EAmF5B,qBAAA,CAAsB,IAAA,EAAM,YAAA,EAAc,KAAA,4BAAiC,MAAA,EAAQ,MAAA,oBAA0B,OAAA;EAE7G,uBAAA,CAAwB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,mBAAA;AAAA,IACnD,OAAA;AAAA,KAEQ,iBAAA;EAAA,SACD,GAAA,EAAK,aAAA;AAAA,IACZ,YAAA;AAAA,KAEQ,yBAAA;EACV,WAAA;EACA,WAAA;EACA,gBAAA;EACA,gBAAA,GAAmB,uBAAA;EAnET;;;EAuEV,2BAAA;EACA,OAAA;EACA,WAAA;EACA,eAAA;EACA,mBAAA;EACA,MAAA,GAAS,+BAAA;AAAA;AAAA,iBAEK,+BAAA,CAAgC,OAAA,EAAS,yBAAA,GAA4B,YAAA;AAAA,KAgEzE,yBAAA,GAA4B,IAAA,CAAK,yBAAA;EAC3C,WAAA;EACA,MAAA;EACA,wBAAA;AAAA;AAAA,iBAEc,+BAAA,CAAgC,OAAA,EAAS,yBAAA,GAA4B,qBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/lib/hexclave-app/projects/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { ProductionModeError } from \"@hexclave/shared/dist/helpers/production-mode\";\nimport { AdminUserProjectsCrud, ProjectsCrud } from \"@hexclave/shared/dist/interface/crud/projects\";\nimport { ProjectOnboardingStatus } from \"@hexclave/shared/dist/schema-fields\";\n\nimport { CompleteConfig, EnvironmentConfigNormalizedOverride, EnvironmentConfigOverrideOverride } from \"@hexclave/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, workflowPath?: 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 pushedConfigError: { message: string } | null,\n readonly configWarnings: { message: 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 isDevelopmentEnvironment: boolean,\n readonly ownerTeamId: string | null,\n readonly onboardingStatus: ProjectOnboardingStatus,\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<void>,\n delete(this: AdminProject): Promise<void>,\n\n getConfig(this: AdminProject): Promise<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 ): Promise<void>,\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 options: PushConfigOptions,\n ): Promise<void>,\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 ): Promise<void>,\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<PushedConfigSource>,\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<void>,\n\n /**\n * Resets (removes) specific keys from the config override at the specified level.\n * Uses the same nested key logic as the override algorithm: resetting key \"a.b\" also resets \"a.b.c\".\n *\n * This is useful when updating the pushed config (branch level) and wanting to remove the same keys\n * from the environment config override so that the branch config values take precedence.\n */\n resetConfigOverrideKeys(this: AdminProject, level: \"branch\" | \"environment\", keys: string[]): Promise<void>,\n\n /**\n * Gets the raw config override at the specified level (before merging/defaults).\n * Useful for inspecting exactly what's been set at each level.\n */\n getConfigOverride(this: AdminProject, level: \"branch\" | \"environment\"): Promise<Record<string, unknown>>,\n\n /**\n * Replaces the entire config override at the specified level.\n * For branch level, preserves the existing source metadata.\n */\n replaceConfigOverride(this: AdminProject, level: \"branch\" | \"environment\", config: Record<string, unknown>): Promise<void>,\n\n getProductionModeErrors(this: AdminProject): Promise<ProductionModeError[]>,\n} & Project;\n\nexport type AdminOwnedProject = {\n readonly app: StackAdminApp<false>,\n} & AdminProject;\n\nexport type AdminProjectUpdateOptions = {\n displayName?: string,\n description?: string,\n isProductionMode?: boolean,\n onboardingStatus?: ProjectOnboardingStatus,\n /**\n * Updates `project.requirePublishableClientKey` in the project-level config override.\n */\n requirePublishableClientKey?: 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 onboarding_status: options.onboardingStatus,\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\n ?.filter((p): p is Exclude<typeof p, { type: 'custom_oidc' }> => p.type !== 'custom_oidc')\n .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<AdminProjectUpdateOptions, 'displayName'> & {\n displayName: string,\n teamId: string,\n isDevelopmentEnvironment?: boolean,\n};\nexport function adminProjectCreateOptionsToCrud(options: AdminProjectCreateOptions): AdminUserProjectsCrud[\"Server\"][\"Create\"] {\n return {\n ...adminProjectUpdateOptionsToCrud(options),\n display_name: options.displayName,\n is_development_environment: options.isDevelopmentEnvironment,\n owner_team_id: options.teamId,\n };\n}\n"],"mappings":";;;AAiKA,SAAgB,gCAAgC,SAAqE;AACnH,QAAO;EACL,cAAc,QAAQ;EACtB,aAAa,QAAQ;EACrB,oBAAoB,QAAQ;EAC5B,mBAAmB,QAAQ;EAC3B,UAAU,QAAQ;EAClB,eAAe,QAAQ;EACvB,oBAAoB,QAAQ;EAC5B,yBAAyB,QAAQ;EAKjC,QAAQ;GACN,SAAS,QAAQ,QAAQ,SAAS,KAAK,OAAO;IAC5C,QAAQ,EAAE;IACV,cAAc,EAAE;IACjB,EAAE;GACH,iBAAiB,QAAQ,QAAQ,gBAC7B,QAAQ,MAAuD,EAAE,SAAS,cAAc,CACzF,KAAK,OAAO;IACX,IAAI,EAAE;IACN,MAAM,EAAE;IACR,GAAI,EAAE,SAAS,cAAc;KAC3B,WAAW,EAAE;KACb,eAAe,EAAE;KACjB,oBAAoB,EAAE;KACtB,qBAAqB,EAAE;KACvB,kBAAkB,EAAE;KACrB;IACF,EAAE;GACL,cAAc,QAAQ,QAAQ,gBAC5B,QAAQ,OAAO,YAAY,SAAS,WAAW,EAC7C,MAAM,UACP,GAAG;IACF,MAAM;IACN,MAAM,QAAQ,OAAO,YAAY;IACjC,MAAM,QAAQ,OAAO,YAAY;IACjC,UAAU,QAAQ,OAAO,YAAY;IACrC,UAAU,QAAQ,OAAO,YAAY;IACrC,aAAa,QAAQ,OAAO,YAAY;IACxC,cAAc,QAAQ,OAAO,YAAY;IAC1C;GAEH,aAAa,QAAQ,QAAQ;GAC7B,iBAAiB,QAAQ,QAAQ;GACjC,oBAAoB,QAAQ,QAAQ;GACpC,oBAAoB,QAAQ,QAAQ;GACpC,iBAAiB,QAAQ,QAAQ;GACjC,iBAAiB,QAAQ,QAAQ;GACjC,wBAAwB,QAAQ,QAAQ;GACxC,8BAA8B,QAAQ,QAAQ;GAC9C,8BAA8B,QAAQ,QAAQ;GAC9C,kCAAkC,QAAQ,QAAQ;GAClD,iCAAiC,QAAQ,QAAQ;GACjD,0BAA0B,QAAQ,QAAQ;GAC1C,8BAA8B,QAAQ,QAAQ;GAC9C,qBAAqB,QAAQ,QAAQ;GACrC,qBAAqB,QAAQ,QAAQ;GACtC;EACF;;AAQH,SAAgB,gCAAgC,SAA+E;AAC7H,QAAO;EACL,GAAG,gCAAgC,QAAQ;EAC3C,cAAc,QAAQ;EACtB,4BAA4B,QAAQ;EACpC,eAAe,QAAQ;EACxB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/lib/hexclave-app/projects/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { ProductionModeError } from \"@hexclave/shared/dist/helpers/production-mode\";\nimport { AdminUserProjectsCrud, ProjectsCrud } from \"@hexclave/shared/dist/interface/crud/projects\";\nimport { ProjectOnboardingStatus } from \"@hexclave/shared/dist/schema-fields\";\n\nimport { CompleteConfig, EnvironmentConfigNormalizedOverride, EnvironmentConfigOverrideOverride } from \"@hexclave/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, workflowPath?: 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 pushedConfigError: { message: string } | null,\n readonly configWarnings: { message: 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 isDevelopmentEnvironment: boolean,\n readonly ownerTeamId: string | null,\n readonly onboardingStatus: ProjectOnboardingStatus,\n readonly onboardingState: NonNullable<ProjectsCrud[\"Admin\"][\"Read\"][\"onboarding_state\"]> | 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<void>,\n delete(this: AdminProject): Promise<void>,\n\n getConfig(this: AdminProject): Promise<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 ): Promise<void>,\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 options: PushConfigOptions,\n ): Promise<void>,\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 ): Promise<void>,\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<PushedConfigSource>,\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<void>,\n\n /**\n * Resets (removes) specific keys from the config override at the specified level.\n * Uses the same nested key logic as the override algorithm: resetting key \"a.b\" also resets \"a.b.c\".\n *\n * This is useful when updating the pushed config (branch level) and wanting to remove the same keys\n * from the environment config override so that the branch config values take precedence.\n */\n resetConfigOverrideKeys(this: AdminProject, level: \"branch\" | \"environment\", keys: string[]): Promise<void>,\n\n /**\n * Gets the raw config override at the specified level (before merging/defaults).\n * Useful for inspecting exactly what's been set at each level.\n */\n getConfigOverride(this: AdminProject, level: \"branch\" | \"environment\"): Promise<Record<string, unknown>>,\n\n /**\n * Replaces the entire config override at the specified level.\n * For branch level, preserves the existing source metadata.\n */\n replaceConfigOverride(this: AdminProject, level: \"branch\" | \"environment\", config: Record<string, unknown>): Promise<void>,\n\n getProductionModeErrors(this: AdminProject): Promise<ProductionModeError[]>,\n} & Project;\n\nexport type AdminOwnedProject = {\n readonly app: StackAdminApp<false>,\n} & AdminProject;\n\nexport type AdminProjectUpdateOptions = {\n displayName?: string,\n description?: string,\n isProductionMode?: boolean,\n onboardingStatus?: ProjectOnboardingStatus,\n /**\n * Updates `project.requirePublishableClientKey` in the project-level config override.\n */\n requirePublishableClientKey?: 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 onboarding_status: options.onboardingStatus,\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\n ?.filter((p): p is Exclude<typeof p, { type: 'custom_oidc' }> => p.type !== 'custom_oidc')\n .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<AdminProjectUpdateOptions, 'displayName'> & {\n displayName: string,\n teamId: string,\n isDevelopmentEnvironment?: boolean,\n};\nexport function adminProjectCreateOptionsToCrud(options: AdminProjectCreateOptions): AdminUserProjectsCrud[\"Server\"][\"Create\"] {\n return {\n ...adminProjectUpdateOptionsToCrud(options),\n display_name: options.displayName,\n is_development_environment: options.isDevelopmentEnvironment,\n owner_team_id: options.teamId,\n };\n}\n"],"mappings":";;;AAkKA,SAAgB,gCAAgC,SAAqE;AACnH,QAAO;EACL,cAAc,QAAQ;EACtB,aAAa,QAAQ;EACrB,oBAAoB,QAAQ;EAC5B,mBAAmB,QAAQ;EAC3B,UAAU,QAAQ;EAClB,eAAe,QAAQ;EACvB,oBAAoB,QAAQ;EAC5B,yBAAyB,QAAQ;EAKjC,QAAQ;GACN,SAAS,QAAQ,QAAQ,SAAS,KAAK,OAAO;IAC5C,QAAQ,EAAE;IACV,cAAc,EAAE;IACjB,EAAE;GACH,iBAAiB,QAAQ,QAAQ,gBAC7B,QAAQ,MAAuD,EAAE,SAAS,cAAc,CACzF,KAAK,OAAO;IACX,IAAI,EAAE;IACN,MAAM,EAAE;IACR,GAAI,EAAE,SAAS,cAAc;KAC3B,WAAW,EAAE;KACb,eAAe,EAAE;KACjB,oBAAoB,EAAE;KACtB,qBAAqB,EAAE;KACvB,kBAAkB,EAAE;KACrB;IACF,EAAE;GACL,cAAc,QAAQ,QAAQ,gBAC5B,QAAQ,OAAO,YAAY,SAAS,WAAW,EAC7C,MAAM,UACP,GAAG;IACF,MAAM;IACN,MAAM,QAAQ,OAAO,YAAY;IACjC,MAAM,QAAQ,OAAO,YAAY;IACjC,UAAU,QAAQ,OAAO,YAAY;IACrC,UAAU,QAAQ,OAAO,YAAY;IACrC,aAAa,QAAQ,OAAO,YAAY;IACxC,cAAc,QAAQ,OAAO,YAAY;IAC1C;GAEH,aAAa,QAAQ,QAAQ;GAC7B,iBAAiB,QAAQ,QAAQ;GACjC,oBAAoB,QAAQ,QAAQ;GACpC,oBAAoB,QAAQ,QAAQ;GACpC,iBAAiB,QAAQ,QAAQ;GACjC,iBAAiB,QAAQ,QAAQ;GACjC,wBAAwB,QAAQ,QAAQ;GACxC,8BAA8B,QAAQ,QAAQ;GAC9C,8BAA8B,QAAQ,QAAQ;GAC9C,kCAAkC,QAAQ,QAAQ;GAClD,iCAAiC,QAAQ,QAAQ;GACjD,0BAA0B,QAAQ,QAAQ;GAC1C,8BAA8B,QAAQ,QAAQ;GAC9C,qBAAqB,QAAQ,QAAQ;GACrC,qBAAqB,QAAQ,QAAQ;GACtC;EACF;;AAQH,SAAgB,gCAAgC,SAA+E;AAC7H,QAAO;EACL,GAAG,gCAAgC,QAAQ;EAC3C,cAAc,QAAQ;EACtB,4BAA4B,QAAQ;EACpC,eAAe,QAAQ;EACxB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)",
3
3
  "name": "@hexclave/js",
4
- "version": "1.0.25",
4
+ "version": "1.0.27",
5
5
  "repository": "https://github.com/hexclave/hexclave",
6
6
  "sideEffects": false,
7
7
  "main": "./dist/index.js",
@@ -66,7 +66,7 @@
66
66
  "rrweb": "^1.1.3",
67
67
  "tsx": "^4.21.0",
68
68
  "yup": "^1.7.1",
69
- "@hexclave/shared": "1.0.25"
69
+ "@hexclave/shared": "1.0.27"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@quetzallabs/i18n": "^0.1.19",
@@ -1851,7 +1851,7 @@ function createSupportTab(app: StackClientApp<true>): HTMLElement {
1851
1851
  function createComponentsTab(app: StackClientApp<true>): HTMLElement {
1852
1852
  const container = h('div', { className: 'sdt-pg-layout' });
1853
1853
  const apiBaseUrl = resolveApiBaseUrl(app);
1854
- const urls = app.urls;
1854
+ const urls = app[hexclaveAppInternalsSymbol].getUrls();
1855
1855
  const urlOptions: HandlerUrlOptions = app[hexclaveAppInternalsSymbol].getConstructorOptions().urls ?? {};
1856
1856
 
1857
1857
  const PAGE_ENTRIES: { key: keyof HandlerUrls; label: string }[] = [
@@ -23,6 +23,7 @@ import { EmailConfig, hexclaveAppInternalsSymbol } from "../../common";
23
23
  import { AdminEmailTemplate } from "../../email-templates";
24
24
  import { InternalApiKey, InternalApiKeyBase, InternalApiKeyBaseCrudRead, InternalApiKeyCreateOptions, InternalApiKeyFirstView, internalApiKeyCreateOptionsToCrud } from "../../internal-api-keys";
25
25
  import { AdminProjectPermission, AdminProjectPermissionDefinition, AdminProjectPermissionDefinitionCreateOptions, AdminProjectPermissionDefinitionUpdateOptions, AdminTeamPermission, AdminTeamPermissionDefinition, AdminTeamPermissionDefinitionCreateOptions, AdminTeamPermissionDefinitionUpdateOptions, adminProjectPermissionDefinitionCreateOptionsToCrud, adminProjectPermissionDefinitionUpdateOptionsToCrud, adminTeamPermissionDefinitionCreateOptionsToCrud, adminTeamPermissionDefinitionUpdateOptionsToCrud } from "../../permissions";
26
+ import type { PlanUsage } from "../../plan-usage";
26
27
  import { AdminOwnedProject, AdminProject, AdminProjectUpdateOptions, PushConfigOptions, adminProjectUpdateOptionsToCrud } from "../../projects";
27
28
  import type { AdminSessionReplay, AdminSessionReplayChunk, ListSessionReplayChunksOptions, ListSessionReplayChunksResult, ListSessionReplaysOptions, ListSessionReplaysResult, SessionReplayAllEventsResult } from "../../session-replays";
28
29
  import { ManagedEmailProviderListItem, ManagedEmailProviderSetupResult, ManagedEmailProviderStatus, EmailOutboxUpdateOptions, StackAdminApp, StackAdminAppConstructorOptions } from "../interfaces/admin-app";
@@ -35,6 +36,7 @@ import * as yup from "yup";
35
36
  import { PushedConfigSource } from "../../projects";
36
37
 
37
38
  type BranchConfigSourceApi = yup.InferType<typeof branchConfigSourceSchema>;
39
+ type PlanUsageResponse = Awaited<ReturnType<HexclaveAdminInterface["getPlanUsage"]>>;
38
40
  /**
39
41
  * Converts a PushedConfigSource (SDK camelCase) to BranchConfigSourceApi (API snake_case).
40
42
  */
@@ -77,6 +79,9 @@ export class _HexclaveAdminAppImplIncomplete<HasTokenStore extends boolean, Proj
77
79
  private readonly _adminProjectCache = createCache(async () => {
78
80
  return await this._interface.getProject();
79
81
  });
82
+ private readonly _planUsageCache = createCache(async () => {
83
+ return await this._interface.getPlanUsage();
84
+ });
80
85
  private readonly _internalApiKeysCache = createCache(async () => {
81
86
  const res = await this._interface.listInternalApiKeys();
82
87
  return res;
@@ -194,6 +199,7 @@ export class _HexclaveAdminAppImplIncomplete<HasTokenStore extends boolean, Proj
194
199
  isDevelopmentEnvironment: data.is_development_environment,
195
200
  ownerTeamId: data.owner_team_id,
196
201
  onboardingStatus: data.onboarding_status,
202
+ onboardingState: data.onboarding_state ?? null,
197
203
  logoUrl: data.logo_url,
198
204
  logoFullUrl: data.logo_full_url,
199
205
  logoDarkModeUrl: data.logo_dark_mode_url,
@@ -328,6 +334,28 @@ export class _HexclaveAdminAppImplIncomplete<HasTokenStore extends boolean, Proj
328
334
  };
329
335
  }
330
336
 
337
+ _planUsageFromCrud(data: PlanUsageResponse): PlanUsage {
338
+ return {
339
+ ownerTeamId: data.owner_team_id,
340
+ ownerTeamDisplayName: data.owner_team_display_name,
341
+ planId: data.plan_id,
342
+ planDisplayName: data.plan_display_name,
343
+ periodStart: new Date(data.period_start_millis),
344
+ periodEnd: new Date(data.period_end_millis),
345
+ nextPlanId: data.next_plan_id,
346
+ rows: data.rows.map((row) => ({
347
+ itemId: row.item_id,
348
+ displayName: row.display_name,
349
+ kind: row.kind,
350
+ used: row.used,
351
+ limit: row.limit,
352
+ remaining: row.remaining,
353
+ overage: row.overage,
354
+ isUnlimited: row.is_unlimited,
355
+ })),
356
+ };
357
+ }
358
+
331
359
  override async getProject(): Promise<AdminProject> {
332
360
  return this._adminProjectFromCrud(
333
361
  Result.orThrow(await this._adminProjectCache.getOrWait([], "write-only")),
@@ -336,6 +364,11 @@ export class _HexclaveAdminAppImplIncomplete<HasTokenStore extends boolean, Proj
336
364
  }
337
365
 
338
366
 
367
+ async getPlanUsage(): Promise<PlanUsage> {
368
+ return this._planUsageFromCrud(Result.orThrow(await this._planUsageCache.getOrWait([], "write-only")));
369
+ }
370
+
371
+
339
372
  protected _createInternalApiKeyBaseFromCrud(data: InternalApiKeyBaseCrudRead): InternalApiKeyBase {
340
373
  const app = this;
341
374
  return {
@@ -1036,7 +1069,7 @@ export class _HexclaveAdminAppImplIncomplete<HasTokenStore extends boolean, Proj
1036
1069
 
1037
1070
 
1038
1071
  async getStripeAccountInfo(): Promise<null | { account_id: string, charges_enabled: boolean, details_submitted: boolean, payouts_enabled: boolean }> {
1039
- return await this._interface.getStripeAccountInfo();
1072
+ return Result.orThrow(await this._stripeAccountInfoCache.getOrWait([], "write-only"));
1040
1073
  }
1041
1074
 
1042
1075
 
@@ -345,7 +345,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
345
345
  {
346
346
  provider,
347
347
  redirectUrl: this._getOAuthCallbackRedirectUri(),
348
- errorRedirectUrl: this.urls.error,
348
+ errorRedirectUrl: this._getUrls().error,
349
349
  providerScope: mergeScopeStrings(scopeString, (this._oauthScopesOnSignIn[provider as ProviderType] ?? []).join(" ")),
350
350
  },
351
351
  session,
@@ -547,7 +547,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
547
547
  {
548
548
  provider: options.providerId,
549
549
  redirectUrl: this._getOAuthCallbackRedirectUri(),
550
- errorRedirectUrl: this.urls.error,
550
+ errorRedirectUrl: this._getUrls().error,
551
551
  providerScope: mergeScopeStrings(options.scope || "", (this._oauthScopesOnSignIn[options.providerId] ?? []).join(" ")),
552
552
  },
553
553
  options.session,
@@ -825,7 +825,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
825
825
 
826
826
  protected _getOAuthCallbackRedirectUri(): string {
827
827
  if (!this._isOAuthCallbackUrlHosted()) {
828
- return this.urls.oauthCallback;
828
+ return this._getUrls().oauthCallback;
829
829
  }
830
830
  if (typeof window === "undefined") {
831
831
  throw new HexclaveAssertionError("Hosted OAuth callback URLs require a browser environment to use the current URL as the redirect URI");
@@ -2757,13 +2757,13 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
2757
2757
  async redirectToMfa(options?: RedirectToOptions) { return await this._redirectToHandler("mfa", options); }
2758
2758
 
2759
2759
  async sendForgotPasswordEmail(email: string, options?: { callbackUrl?: string }): Promise<Result<undefined, KnownErrors["UserNotFound"]>> {
2760
- return await this._interface.sendForgotPasswordEmail(email, options?.callbackUrl ?? constructRedirectUrl(this.urls.passwordReset, "callbackUrl"));
2760
+ return await this._interface.sendForgotPasswordEmail(email, options?.callbackUrl ?? constructRedirectUrl(this._getUrls().passwordReset, "callbackUrl"));
2761
2761
  }
2762
2762
 
2763
2763
  async sendMagicLinkEmail(email: string, options?: {
2764
2764
  callbackUrl?: string,
2765
2765
  }): Promise<Result<{ nonce: string }, KnownErrors["RedirectUrlNotWhitelisted"] | KnownErrors["BotChallengeFailed"]>> {
2766
- const callbackUrl = options?.callbackUrl ?? constructRedirectUrl(this.urls.magicLinkCallback, "callbackUrl");
2766
+ const callbackUrl = options?.callbackUrl ?? constructRedirectUrl(this._getUrls().magicLinkCallback, "callbackUrl");
2767
2767
  return await this._executeResultWithBotChallengeFlow({
2768
2768
  action: "send_magic_link_email",
2769
2769
  execute: async (challenge) => {
@@ -2973,7 +2973,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
2973
2973
  return await this._interface.authorizeOAuth({
2974
2974
  provider,
2975
2975
  redirectUrl: constructRedirectUrl(this._getOAuthCallbackRedirectUri(), "redirectUrl"),
2976
- errorRedirectUrl: constructRedirectUrl(this.urls.error, "errorRedirectUrl"),
2976
+ errorRedirectUrl: constructRedirectUrl(this._getUrls().error, "errorRedirectUrl"),
2977
2977
  afterCallbackRedirectUrl,
2978
2978
  type: "authenticate",
2979
2979
  providerScope: this._oauthScopesOnSignIn[provider]?.join(" "),
@@ -3093,7 +3093,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
3093
3093
  }
3094
3094
  this._ensurePersistentTokenStore();
3095
3095
  const session = await this._getSession();
3096
- const emailVerificationRedirectUrl = options.noVerificationCallback ? undefined : options.verificationCallbackUrl ?? constructRedirectUrl(this.urls.emailVerification, "verificationCallbackUrl");
3096
+ const emailVerificationRedirectUrl = options.noVerificationCallback ? undefined : options.verificationCallbackUrl ?? constructRedirectUrl(this._getUrls().emailVerification, "verificationCallbackUrl");
3097
3097
 
3098
3098
  const executeSignUp = async (challenge: { token?: string, phase?: "invisible" | "visible", unavailable?: true }) => {
3099
3099
  let result = await this._interface.signUpWithCredential(
@@ -3256,7 +3256,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
3256
3256
 
3257
3257
  // Step 2: Open the browser for the user to authenticate and display the verification code
3258
3258
  const url = buildCliAuthConfirmUrl({
3259
- cliAuthConfirmUrl: this.urls.cliAuthConfirm,
3259
+ cliAuthConfirmUrl: this._getUrls().cliAuthConfirm,
3260
3260
  appUrl: options.appUrl,
3261
3261
  loginCode,
3262
3262
  });
@@ -3653,6 +3653,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
3653
3653
  ) => {
3654
3654
  return await this._interface.sendClientRequest(path, requestOptions, await this._getSession(), requestType);
3655
3655
  },
3656
+ getUrls: () => this._getUrls(),
3656
3657
  getRedirectMethod: () => this._redirectMethod ?? throwErr("Redirect method should have been initialized in the Stack client app constructor"),
3657
3658
  redirectToUrl: async (url: string | URL, options?: { replace?: boolean }) => {
3658
3659
  await this._redirectTo({ url, ...options });
@@ -74,8 +74,11 @@ describe("SessionRecorder flush", () => {
74
74
  const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
75
75
 
76
76
  try {
77
+ const event1 = { type: 2, timestamp: Date.now(), data: {} };
77
78
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
78
- (recorder as any)._events = [{ type: 2, timestamp: Date.now(), data: {} }];
79
+ (recorder as any)._events = [event1];
80
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
81
+ (recorder as any)._eventSizes = [JSON.stringify(event1).length];
79
82
 
80
83
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
81
84
  (recorder as any)._tick();
@@ -86,8 +89,11 @@ describe("SessionRecorder flush", () => {
86
89
 
87
90
  // Unlike ANALYTICS_NOT_ENABLED, ad blocker errors do NOT disable the
88
91
  // recorder — subsequent flushes continue attempting delivery.
92
+ const event2 = { type: 3, timestamp: Date.now(), data: {} };
93
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
94
+ (recorder as any)._events = [event2];
89
95
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
90
- (recorder as any)._events = [{ type: 3, timestamp: Date.now(), data: {} }];
96
+ (recorder as any)._eventSizes = [JSON.stringify(event2).length];
91
97
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
92
98
  (recorder as any)._tick();
93
99
  await vi.advanceTimersByTimeAsync(0);
@@ -101,6 +107,113 @@ describe("SessionRecorder flush", () => {
101
107
  }
102
108
  });
103
109
 
110
+ it("splits large batches into multiple requests to stay under server 1MB limit", async () => {
111
+ vi.useFakeTimers();
112
+
113
+ const storageKey = `hexclave:session-replay:v1:test-project`;
114
+ localStorage.setItem(storageKey, JSON.stringify({
115
+ session_id: "test-session",
116
+ created_at_ms: Date.now(),
117
+ last_activity_ms: Date.now(),
118
+ }));
119
+
120
+ const sentBodies: string[] = [];
121
+ const recorder = new SessionRecorder(
122
+ {
123
+ projectId: "test-project",
124
+ sendBatch: async (body) => {
125
+ sentBodies.push(body);
126
+ return Result.ok(new Response("ok", { status: 200 }));
127
+ },
128
+ },
129
+ {},
130
+ );
131
+
132
+ try {
133
+ // Create events that together exceed 900KB (the per-batch cap).
134
+ // Each event is ~500KB, so two events (~1MB) must be split into two batches.
135
+ const largeData = "x".repeat(500_000);
136
+ const event1 = { type: 2, timestamp: Date.now(), data: largeData };
137
+ const event2 = { type: 3, timestamp: Date.now(), data: largeData };
138
+
139
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
140
+ (recorder as any)._events = [event1, event2];
141
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
142
+ (recorder as any)._eventSizes = [JSON.stringify(event1).length, JSON.stringify(event2).length];
143
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
144
+ (recorder as any)._approxBytes = JSON.stringify(event1).length + JSON.stringify(event2).length;
145
+
146
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
147
+ (recorder as any)._tick();
148
+ await vi.advanceTimersByTimeAsync(0);
149
+
150
+ // Should have sent two separate batches
151
+ expect(sentBodies).toHaveLength(2);
152
+
153
+ // Each batch should contain exactly one event
154
+ const batch1 = JSON.parse(sentBodies[0]);
155
+ const batch2 = JSON.parse(sentBodies[1]);
156
+ expect(batch1.events).toHaveLength(1);
157
+ expect(batch2.events).toHaveLength(1);
158
+
159
+ // They should have different batch IDs
160
+ expect(batch1.batch_id).not.toBe(batch2.batch_id);
161
+ } finally {
162
+ recorder.stop();
163
+ localStorage.removeItem(storageKey);
164
+ vi.useRealTimers();
165
+ }
166
+ });
167
+
168
+ it("sends a single oversized event alone without dropping it", async () => {
169
+ vi.useFakeTimers();
170
+
171
+ const storageKey = `hexclave:session-replay:v1:test-project`;
172
+ localStorage.setItem(storageKey, JSON.stringify({
173
+ session_id: "test-session",
174
+ created_at_ms: Date.now(),
175
+ last_activity_ms: Date.now(),
176
+ }));
177
+
178
+ const sentBodies: string[] = [];
179
+ const recorder = new SessionRecorder(
180
+ {
181
+ projectId: "test-project",
182
+ sendBatch: async (body) => {
183
+ sentBodies.push(body);
184
+ return Result.ok(new Response("ok", { status: 200 }));
185
+ },
186
+ },
187
+ {},
188
+ );
189
+
190
+ try {
191
+ // A single event larger than 900KB — should still be sent (not dropped)
192
+ const hugeData = "y".repeat(1_000_000);
193
+ const hugeEvent = { type: 2, timestamp: Date.now(), data: hugeData };
194
+
195
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
196
+ (recorder as any)._events = [hugeEvent];
197
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
198
+ (recorder as any)._eventSizes = [JSON.stringify(hugeEvent).length];
199
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
200
+ (recorder as any)._approxBytes = JSON.stringify(hugeEvent).length;
201
+
202
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
203
+ (recorder as any)._tick();
204
+ await vi.advanceTimersByTimeAsync(0);
205
+
206
+ // Should still send the event (the server may reject it, but we don't drop it client-side)
207
+ expect(sentBodies).toHaveLength(1);
208
+ const batch = JSON.parse(sentBodies[0]);
209
+ expect(batch.events).toHaveLength(1);
210
+ } finally {
211
+ recorder.stop();
212
+ localStorage.removeItem(storageKey);
213
+ vi.useRealTimers();
214
+ }
215
+ });
216
+
104
217
  it("silently disables when client interface returns ANALYTICS_NOT_ENABLED as an error", async () => {
105
218
  vi.useFakeTimers();
106
219
 
@@ -126,8 +239,11 @@ describe("SessionRecorder flush", () => {
126
239
  const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
127
240
 
128
241
  try {
242
+ const event1 = { type: 2, timestamp: Date.now(), data: {} };
129
243
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
130
- (recorder as any)._events = [{ type: 2, timestamp: Date.now(), data: {} }];
244
+ (recorder as any)._events = [event1];
245
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
246
+ (recorder as any)._eventSizes = [JSON.stringify(event1).length];
131
247
 
132
248
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
133
249
  (recorder as any)._tick();
@@ -136,8 +252,11 @@ describe("SessionRecorder flush", () => {
136
252
  expect(sentBodies).toHaveLength(1);
137
253
  expect(warnSpy).not.toHaveBeenCalled();
138
254
 
255
+ const event2 = { type: 3, timestamp: Date.now(), data: {} };
256
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
257
+ (recorder as any)._events = [event2];
139
258
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
140
- (recorder as any)._events = [{ type: 3, timestamp: Date.now(), data: {} }];
259
+ (recorder as any)._eventSizes = [JSON.stringify(event2).length];
141
260
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
142
261
  (recorder as any)._tick();
143
262
  await vi.advanceTimersByTimeAsync(0);