@hexclave/js 1.0.19 → 1.0.20

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 (43) hide show
  1. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  2. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +34 -5
  3. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  4. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
  5. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  6. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +24 -4
  7. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  8. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +1 -1
  9. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +2 -2
  10. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  11. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +3 -2
  12. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  13. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  14. package/dist/esm/lib/hexclave-app/project-configs/index.d.ts +7 -0
  15. package/dist/esm/lib/hexclave-app/project-configs/index.d.ts.map +1 -1
  16. package/dist/esm/lib/hexclave-app/projects/index.d.ts.map +1 -1
  17. package/dist/esm/lib/hexclave-app/projects/index.js +1 -1
  18. package/dist/esm/lib/hexclave-app/projects/index.js.map +1 -1
  19. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  20. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +34 -5
  21. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  22. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
  23. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  24. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +24 -4
  25. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  26. package/dist/lib/hexclave-app/apps/implementations/common.js +1 -1
  27. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +2 -2
  28. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  29. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +3 -2
  30. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  31. package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  32. package/dist/lib/hexclave-app/project-configs/index.d.ts +7 -0
  33. package/dist/lib/hexclave-app/project-configs/index.d.ts.map +1 -1
  34. package/dist/lib/hexclave-app/projects/index.d.ts.map +1 -1
  35. package/dist/lib/hexclave-app/projects/index.js +1 -1
  36. package/dist/lib/hexclave-app/projects/index.js.map +1 -1
  37. package/package.json +2 -2
  38. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +36 -0
  39. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +43 -4
  40. package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +2 -2
  41. package/src/lib/hexclave-app/apps/interfaces/client-app.ts +3 -2
  42. package/src/lib/hexclave-app/project-configs/index.ts +8 -0
  43. package/src/lib/hexclave-app/projects/index.ts +13 -11
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/project-configs/index.ts"],"mappings":";;;KAMY,aAAA;EAAA,SACD,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,gBAAA;EAAA,SACA,cAAA;EAAA,SACA,yBAAA;EAAA,SACA,yBAAA;EAAA,SACA,cAAA,EAAgB,mBAAA;EAAA,SAChB,gBAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,mBAAA;EAAA,SACD,EAAA;AAAA;;;;KAMC,kBAAA;EAAA,SACD,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,gBAAA;EAAA,SACA,cAAA;EAAA,SACA,yBAAA;EAAA,SACA,yBAAA;EAAA,SACA,cAAA;EAAA,SACA,cAAA,EAAgB,wBAAA;EAAA,SAChB,WAAA,GAAc,gBAAA;EAAA,SACd,UAAA;EAAA,SACA,OAAA,EAAS,iBAAA;EAAA,SACT,kBAAA;EAAA,SACA,6BAAA,EAA+B,mBAAA;EAAA,SAC/B,4BAAA,EAA8B,mBAAA;EAAA,SAC9B,sBAAA,EAAwB,mBAAA;EAAA,SACxB,yBAAA;EAAA,SACA,gBAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,gBAAA;EAER,IAAA;EACA,UAAA;EACA,WAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;AAAA;EAGA,IAAA;AAAA;AAAA,KAIQ,iBAAA;EACV,MAAA;EACA,WAAA;AAAA;AAAA,KAGU,wBAAA;EACV,EAAA;AAAA;EAEM,IAAA;AAAA;EAEF,IAAA;EACA,QAAA;EACA,YAAA;EACA,gBAAA;EACA,iBAAA;EACA,cAAA;AAAA,KAEA,mBAAA;AAAA,KAEM,+BAAA;EACV,OAAA;IACE,MAAA;IACA,WAAA;EAAA;EAEF,cAAA,GAAiB,wBAAA;EACjB,aAAA;EACA,iBAAA;EACA,gBAAA;EACA,cAAA;EACA,yBAAA;EACA,yBAAA;EACA,cAAA;EACA,kBAAA;EACA,WAAA,GAAc,gBAAA;EACd,UAAA;EACA,6BAAA;IAAkC,EAAA;EAAA;EAClC,4BAAA;IAAiC,EAAA;EAAA;EACjC,sBAAA;IAA2B,EAAA;EAAA;EAC3B,yBAAA;EACA,gBAAA;EACA,gBAAA;AAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/lib/hexclave-app/project-configs/index.ts"],"mappings":";;;KAMY,aAAA;EAAA,SACD,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,gBAAA;EAAA,SACA,cAAA;EAAA,SACA,yBAAA;EAAA,SACA,yBAAA;EAAA,SACA,cAAA,EAAgB,mBAAA;EAAA,SAChB,gBAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,mBAAA;EAAA,SACD,EAAA;AAAA;;;;KAMC,kBAAA;EAAA,SACD,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,gBAAA;EAAA,SACA,cAAA;EAAA,SACA,yBAAA;EAAA,SACA,yBAAA;EAAA,SACA,cAAA;EAAA,SACA,cAAA,EAAgB,wBAAA;EAAA,SAChB,WAAA,GAAc,gBAAA;EAAA,SACd,UAAA;EAAA,SACA,OAAA,EAAS,iBAAA;EAAA,SACT,kBAAA;EAAA,SACA,6BAAA,EAA+B,mBAAA;EAAA,SAC/B,4BAAA,EAA8B,mBAAA;EAAA,SAC9B,sBAAA,EAAwB,mBAAA;EAAA,SACxB,yBAAA;EAAA,SACA,gBAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,gBAAA;EAER,IAAA;EACA,UAAA;EACA,WAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;AAAA;EAGA,IAAA;AAAA;AAAA,KAIQ,iBAAA;EACV,MAAA;EACA,WAAA;AAAA;AAAA,KAGU,wBAAA;EACV,EAAA;AAAA;EAEM,IAAA;AAAA;EAEF,IAAA;EACA,QAAA;EACA,YAAA;EACA,gBAAA;EACA,iBAAA;EACA,cAAA;AAAA;EAGA,IAAA;EACA,QAAA;EACA,YAAA;EACA,SAAA;EACA,KAAA;EACA,WAAA;AAAA,KAEA,mBAAA;AAAA,KAEM,+BAAA;EACV,OAAA;IACE,MAAA;IACA,WAAA;EAAA;EAEF,cAAA,GAAiB,wBAAA;EACjB,aAAA;EACA,iBAAA;EACA,gBAAA;EACA,cAAA;EACA,yBAAA;EACA,yBAAA;EACA,cAAA;EACA,kBAAA;EACA,WAAA,GAAc,gBAAA;EACd,UAAA;EACA,6BAAA;IAAkC,EAAA;EAAA;EAClC,4BAAA;IAAiC,EAAA;EAAA;EACjC,sBAAA;IAA2B,EAAA;EAAA;EAC3B,yBAAA;EACA,gBAAA;EACA,gBAAA;AAAA"}
@@ -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,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;EAAR;;;;;;;EAU/B,YAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA6BK;;;;;;;;;;EAjBR,UAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,EACR,OAAA,EAAS,iBAAA,GACR,OAAA;EA8C6E;;;;;;;;;;EAlChF,kBAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA9DM;;;;;;;;EAwET,qBAAA,CAAsB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,kBAAA;EAjExB;;;;EAuE3B,wBAAA,CAAyB,IAAA,EAAM,YAAA,GAAe,OAAA;EAjErC;;;;;;;EA0ET,uBAAA,CAAwB,IAAA,EAAM,YAAA,EAAc,KAAA,4BAAiC,IAAA,aAAiB,OAAA;EAvE9F;;;;EA6EA,iBAAA,CAAkB,IAAA,EAAM,YAAA,EAAc,KAAA,6BAAkC,OAAA,CAAQ,MAAA;EA3EhE;;;;EAiFhB,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;EAlER;;;EAsEX,2BAAA;EACA,OAAA;EACA,WAAA;EACA,eAAA;EACA,mBAAA;EACA,MAAA,GAAS,+BAAA;AAAA;AAAA,iBAEK,+BAAA,CAAgC,OAAA,EAAS,yBAAA,GAA4B,YAAA;AAAA,KA8DzE,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,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;EAAR;;;;;;;EAU/B,YAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA6BK;;;;;;;;;;EAjBR,UAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,EACR,OAAA,EAAS,iBAAA,GACR,OAAA;EA8C6E;;;;;;;;;;EAlChF,kBAAA,CACE,IAAA,EAAM,YAAA,EACN,MAAA,EAAQ,iCAAA,GACP,OAAA;EA9DM;;;;;;;;EAwET,qBAAA,CAAsB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,kBAAA;EAjExB;;;;EAuE3B,wBAAA,CAAyB,IAAA,EAAM,YAAA,GAAe,OAAA;EAjErC;;;;;;;EA0ET,uBAAA,CAAwB,IAAA,EAAM,YAAA,EAAc,KAAA,4BAAiC,IAAA,aAAiB,OAAA;EAvE9F;;;;EA6EA,iBAAA,CAAkB,IAAA,EAAM,YAAA,EAAc,KAAA,6BAAkC,OAAA,CAAQ,MAAA;EA3EhE;;;;EAiFhB,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;EAlER;;;EAsEX,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"}
@@ -16,7 +16,7 @@ function adminProjectUpdateOptionsToCrud(options) {
16
16
  domain: d.domain,
17
17
  handler_path: d.handlerPath
18
18
  })),
19
- oauth_providers: options.config?.oauthProviders?.map((p) => ({
19
+ oauth_providers: options.config?.oauthProviders?.filter((p) => p.type !== "custom_oidc").map((p) => ({
20
20
  id: p.id,
21
21
  type: p.type,
22
22
  ...p.type === "standard" && {
@@ -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 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?.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":";;;AA+JA,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,gBAAgB,KAAK,OAAO;IAC3D,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;GACH,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 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":";;;AA+JA,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.19",
4
+ "version": "1.0.20",
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.19"
69
+ "@hexclave/shared": "1.0.20"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@quetzallabs/i18n": "^0.1.19",
@@ -273,6 +273,8 @@ describe("StackClientApp cross-domain auth", () => {
273
273
  protocol: "https:",
274
274
  hostname: "demo.stack-auth.com",
275
275
  },
276
+ addEventListener: () => {},
277
+ removeEventListener: () => {},
276
278
  } as any;
277
279
 
278
280
  const clientApp = new StackClientApp({
@@ -460,6 +462,40 @@ describe("StackClientApp cross-domain auth", () => {
460
462
  }
461
463
  });
462
464
 
465
+ it("throws when public app.urls reads would return hosted component URLs", () => {
466
+ const clientApp = new StackClientApp({
467
+ baseUrl: "http://localhost:12345",
468
+ projectId: "00000000-0000-4000-8000-000000000003",
469
+ publishableClientKey: "stack-pk-test",
470
+ tokenStore: "memory",
471
+ redirectMethod: "window",
472
+ urls: {
473
+ default: { type: "hosted" },
474
+ },
475
+ noAutomaticPrefetch: true,
476
+ });
477
+
478
+ expect(() => clientApp.urls.signIn).toThrowError(/app\.urls\.signIn cannot be used when this app is configured to use hosted components.*Use app\.redirectToSignIn\(\) instead/s);
479
+ expect(() => clientApp.urls.signOut).toThrowError(/app\.urls\.signOut cannot be used when this app is configured to use hosted components.*Use app\.redirectToSignOut\(\) instead/s);
480
+ expect(clientApp.urls.afterSignIn).toBe("/");
481
+ });
482
+
483
+ it("keeps public app.urls reads available for non-hosted targets", () => {
484
+ const clientApp = new StackClientApp({
485
+ baseUrl: "http://localhost:12345",
486
+ projectId: "00000000-0000-4000-8000-000000000003",
487
+ publishableClientKey: "stack-pk-test",
488
+ tokenStore: "memory",
489
+ redirectMethod: "window",
490
+ urls: {
491
+ handler: "/custom-handler",
492
+ },
493
+ noAutomaticPrefetch: true,
494
+ });
495
+
496
+ expect(clientApp.urls.signIn).toBe("/custom-handler/sign-in");
497
+ });
498
+
463
499
  it("keeps default hosted signOut() on the source domain when afterSignOut is not configured", async () => {
464
500
  const clientApp = new StackClientApp({
465
501
  baseUrl: "http://localhost:12345",
@@ -84,6 +84,38 @@ const nestedCrossDomainAuthQueryParams = {
84
84
  afterCallbackRedirectUrl: "after_callback_redirect_url",
85
85
  } as const;
86
86
 
87
+ function getRedirectHelperInstruction(handlerName: string): string {
88
+ if (handlerName === "handler") {
89
+ return "Use a page-specific redirect helper such as app.redirectToSignIn() instead.";
90
+ }
91
+ const redirectMethodName = `redirectTo${handlerName.slice(0, 1).toUpperCase()}${handlerName.slice(1)}`;
92
+ return `Use app.${redirectMethodName}() instead.`;
93
+ }
94
+
95
+ function createUrlsForPublicAccess(options: {
96
+ urls: ResolvedHandlerUrls,
97
+ projectId: string,
98
+ }): Readonly<ResolvedHandlerUrls> {
99
+ const hostedUrlNames = new Set(
100
+ Object.entries(options.urls)
101
+ .filter(([, url]) => isHostedHandlerUrlForProject({ url, projectId: options.projectId }))
102
+ .map(([handlerName]) => handlerName),
103
+ );
104
+
105
+ return new Proxy(options.urls, {
106
+ get(target, property, receiver) {
107
+ if (typeof property === "string" && hostedUrlNames.has(property)) {
108
+ throw new Error(
109
+ `app.urls.${property} cannot be used when this app is configured to use hosted components. ` +
110
+ "`app.urls` is static and does not include the runtime redirect-back, cross-domain auth, or sign-out state required by hosted components. " +
111
+ getRedirectHelperInstruction(property),
112
+ );
113
+ }
114
+ return Reflect.get(target, property, receiver);
115
+ },
116
+ });
117
+ }
118
+
87
119
  const oauthCallbackResponseQueryParams = ["code", "state", "error", "error_description", "errorCode", "message", "details"] as const;
88
120
 
89
121
  const allClientApps = new Map<string, [checkString: string | undefined, app: StackClientApp<any, any>]>();
@@ -1630,7 +1662,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
1630
1662
  teamId: crud.id,
1631
1663
  email: options.email,
1632
1664
  session,
1633
- callbackUrl: options.callbackUrl ?? constructRedirectUrl(app.urls.teamInvitation, "callbackUrl"),
1665
+ callbackUrl: options.callbackUrl ?? constructRedirectUrl(app._getUrls().teamInvitation, "callbackUrl"),
1634
1666
  });
1635
1667
  await app._teamInvitationsCache.refresh([session, crud.id]);
1636
1668
  },
@@ -1682,7 +1714,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
1682
1714
  async sendVerificationEmail(options?: { callbackUrl?: string }) {
1683
1715
  await app._interface.sendCurrentUserContactChannelVerificationEmail(
1684
1716
  crud.id,
1685
- options?.callbackUrl || constructRedirectUrl(app.urls.emailVerification, "callbackUrl"),
1717
+ options?.callbackUrl || constructRedirectUrl(app._getUrls().emailVerification, "callbackUrl"),
1686
1718
  session
1687
1719
  );
1688
1720
  },
@@ -1959,7 +1991,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
1959
1991
  {
1960
1992
  provider,
1961
1993
  redirectUrl: app._getOAuthCallbackRedirectUri(),
1962
- errorRedirectUrl: app.urls.error,
1994
+ errorRedirectUrl: app._getUrls().error,
1963
1995
  providerScope: mergeScopeStrings(scopeString, (app._oauthScopesOnSignIn[provider as ProviderType] ?? []).join(" ")),
1964
1996
  },
1965
1997
  session,
@@ -2046,7 +2078,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
2046
2078
  }
2047
2079
  return await app._interface.sendVerificationEmail(
2048
2080
  crud.primary_email,
2049
- options?.callbackUrl ?? constructRedirectUrl(app.urls.emailVerification, "callbackUrl"),
2081
+ options?.callbackUrl ?? constructRedirectUrl(app._getUrls().emailVerification, "callbackUrl"),
2050
2082
  session
2051
2083
  );
2052
2084
  },
@@ -2437,6 +2469,13 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
2437
2469
  }
2438
2470
 
2439
2471
  get urls(): Readonly<ResolvedHandlerUrls> {
2472
+ return createUrlsForPublicAccess({
2473
+ urls: this._getUrls(),
2474
+ projectId: this.projectId,
2475
+ });
2476
+ }
2477
+
2478
+ protected _getUrls(): Readonly<ResolvedHandlerUrls> {
2440
2479
  return getUrls(this._urlOptions, { projectId: this.projectId });
2441
2480
  }
2442
2481
 
@@ -356,7 +356,7 @@ export class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pro
356
356
  isPrimary: crud.is_primary,
357
357
  usedForAuth: crud.used_for_auth,
358
358
  async sendVerificationEmail(options?: { callbackUrl?: string }) {
359
- await app._interface.sendServerContactChannelVerificationEmail(userId, crud.id, options?.callbackUrl ?? constructRedirectUrl(app.urls.emailVerification, "callbackUrl"));
359
+ await app._interface.sendServerContactChannelVerificationEmail(userId, crud.id, options?.callbackUrl ?? constructRedirectUrl(app._getUrls().emailVerification, "callbackUrl"));
360
360
  },
361
361
  async update(data: ServerContactChannelUpdateOptions) {
362
362
  await app._interface.updateServerContactChannel(userId, crud.id, serverContactChannelUpdateOptionsToCrud(data));
@@ -922,7 +922,7 @@ export class _HexclaveServerAppImplIncomplete<HasTokenStore extends boolean, Pro
922
922
  await app._interface.sendServerTeamInvitation({
923
923
  teamId: crud.id,
924
924
  email: options.email,
925
- callbackUrl: options.callbackUrl ?? constructRedirectUrl(app.urls.teamInvitation, "callbackUrl"),
925
+ callbackUrl: options.callbackUrl ?? constructRedirectUrl(app._getUrls().teamInvitation, "callbackUrl"),
926
926
  });
927
927
  await app._serverTeamInvitationsCache.refresh([crud.id]);
928
928
  },
@@ -68,8 +68,9 @@ export type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId ex
68
68
  readonly version: string,
69
69
 
70
70
  /**
71
- * @deprecated `app.urls` is static and does not include runtime redirect-back parameters.
72
- * For navigation, prefer `redirectToXyz()` methods (for example `redirectToSignIn()`).
71
+ * @deprecated Do not use `app.urls` for navigation. It is static and does not include runtime redirect-back,
72
+ * cross-domain auth, or sign-out state. Use the matching `redirectToXyz()` method instead, for example
73
+ * `redirectToSignIn()`, `redirectToSignUp()`, `redirectToSignOut()`, or `redirectToAccountSettings()`.
73
74
  */
74
75
  readonly urls: Readonly<ResolvedHandlerUrls>,
75
76
 
@@ -76,6 +76,14 @@ export type AdminOAuthProviderConfig = {
76
76
  microsoftTenantId?: string,
77
77
  appleBundleIds?: string[],
78
78
  }
79
+ | {
80
+ type: 'custom_oidc',
81
+ clientId: string,
82
+ clientSecret: string,
83
+ issuerUrl: string,
84
+ scope?: string,
85
+ displayName?: string,
86
+ }
79
87
  ) & OAuthProviderConfig;
80
88
 
81
89
  export type AdminProjectConfigUpdateOptions = {
@@ -176,17 +176,19 @@ export function adminProjectUpdateOptionsToCrud(options: AdminProjectUpdateOptio
176
176
  domain: d.domain,
177
177
  handler_path: d.handlerPath
178
178
  })),
179
- oauth_providers: options.config?.oauthProviders?.map((p) => ({
180
- id: p.id as any,
181
- type: p.type,
182
- ...(p.type === 'standard' && {
183
- client_id: p.clientId,
184
- client_secret: p.clientSecret,
185
- facebook_config_id: p.facebookConfigId,
186
- microsoft_tenant_id: p.microsoftTenantId,
187
- apple_bundle_ids: p.appleBundleIds,
188
- }),
189
- })),
179
+ oauth_providers: options.config?.oauthProviders
180
+ ?.filter((p): p is Exclude<typeof p, { type: 'custom_oidc' }> => p.type !== 'custom_oidc')
181
+ .map((p) => ({
182
+ id: p.id as any,
183
+ type: p.type,
184
+ ...(p.type === 'standard' && {
185
+ client_id: p.clientId,
186
+ client_secret: p.clientSecret,
187
+ facebook_config_id: p.facebookConfigId,
188
+ microsoft_tenant_id: p.microsoftTenantId,
189
+ apple_bundle_ids: p.appleBundleIds,
190
+ }),
191
+ })),
190
192
  email_config: options.config?.emailConfig && (
191
193
  options.config.emailConfig.type === 'shared' ? {
192
194
  type: 'shared',