@hexclave/js 1.0.125 → 1.0.126

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 (99) hide show
  1. package/dist/{admin-app-impl-D9hrl67H.d.ts → admin-app-impl-Df-WtGg0.d.ts} +29 -13
  2. package/dist/admin-app-impl-Df-WtGg0.d.ts.map +1 -0
  3. package/dist/clickmap/clickmap-core.d.ts +1 -1
  4. package/dist/clickmap/index.d.ts +1 -1
  5. package/dist/{client-app-DLFxr4f7.d.ts → client-app-C7Tnf0n1.d.ts} +34 -6
  6. package/dist/client-app-C7Tnf0n1.d.ts.map +1 -0
  7. package/dist/{common-BDyEKSM6.d.ts → common-Dii3iHJR.d.ts} +15 -3
  8. package/dist/common-Dii3iHJR.d.ts.map +1 -0
  9. package/dist/{common-CRu2FsO9.d.ts → common-GgG4l8fG.d.ts} +2 -2
  10. package/dist/{common-CRu2FsO9.d.ts.map → common-GgG4l8fG.d.ts.map} +1 -1
  11. package/dist/dev-tool/dev-tool-core.d.ts +1 -1
  12. package/dist/dev-tool/index.d.ts +1 -1
  13. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +4 -4
  14. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  15. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +18 -2
  16. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  17. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.d.ts +1 -0
  18. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.js +382 -0
  19. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.js.map +1 -0
  20. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.d.ts +1 -0
  21. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.js +66 -0
  22. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.js.map +1 -0
  23. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +66 -14
  24. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  25. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
  26. package/dist/esm/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.d.ts +31 -0
  27. package/dist/esm/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.d.ts.map +1 -0
  28. package/dist/esm/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.js +115 -0
  29. package/dist/esm/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.js.map +1 -0
  30. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +16 -1
  31. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  32. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  33. package/dist/esm/lib/hexclave-app/common.d.ts +14 -2
  34. package/dist/esm/lib/hexclave-app/common.d.ts.map +1 -1
  35. package/dist/esm/lib/hexclave-app/common.js +17 -1
  36. package/dist/esm/lib/hexclave-app/common.js.map +1 -1
  37. package/dist/esm/lib/hexclave-app/index.d.ts +2 -2
  38. package/dist/esm/lib/hexclave-app/index.js +2 -2
  39. package/dist/esm/lib/hexclave-app/users/index.d.ts +14 -1
  40. package/dist/esm/lib/hexclave-app/users/index.d.ts.map +1 -1
  41. package/dist/esm/lib/hexclave-app/users/index.js.map +1 -1
  42. package/dist/{index-ZiEXZJBF.d.ts → index-BTa6Yu7N.d.ts} +2 -2
  43. package/dist/{index-ZiEXZJBF.d.ts.map → index-BTa6Yu7N.d.ts.map} +1 -1
  44. package/dist/{index-DLPccxVU.d.ts → index-DlOcbI9W.d.ts} +2 -2
  45. package/dist/{index-DLPccxVU.d.ts.map → index-DlOcbI9W.d.ts.map} +1 -1
  46. package/dist/index.d.ts +4 -4
  47. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
  48. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  49. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.d.ts +1 -0
  50. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.js +381 -0
  51. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.js.map +1 -0
  52. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.d.ts +1 -0
  53. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.js +65 -0
  54. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.js.map +1 -0
  55. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +65 -13
  56. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  57. package/dist/lib/hexclave-app/apps/implementations/common.d.ts +1 -1
  58. package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
  59. package/dist/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.d.ts +31 -0
  60. package/dist/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.d.ts.map +1 -0
  61. package/dist/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.js +117 -0
  62. package/dist/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.js.map +1 -0
  63. package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  64. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.d.ts +1 -1
  65. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  66. package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
  67. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
  68. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
  69. package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  70. package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
  71. package/dist/lib/hexclave-app/common.d.ts +2 -2
  72. package/dist/lib/hexclave-app/common.js +19 -0
  73. package/dist/lib/hexclave-app/common.js.map +1 -1
  74. package/dist/lib/hexclave-app/customers/index.d.ts +1 -1
  75. package/dist/lib/hexclave-app/data-vault/index.d.ts +1 -1
  76. package/dist/lib/hexclave-app/index.d.ts +4 -4
  77. package/dist/lib/hexclave-app/index.js +18 -0
  78. package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
  79. package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
  80. package/dist/lib/hexclave-app/url-targets.d.ts +1 -1
  81. package/dist/lib/hexclave-app/users/index.d.ts +1 -1
  82. package/dist/lib/hexclave-app/users/index.js.map +1 -1
  83. package/dist/pushed-config-error-overlay/index.d.ts +1 -1
  84. package/dist/{redirect-page-urls-C2CXwCcv.d.ts → redirect-page-urls-DCSFN6dg.d.ts} +2 -2
  85. package/dist/{redirect-page-urls-C2CXwCcv.d.ts.map → redirect-page-urls-DCSFN6dg.d.ts.map} +1 -1
  86. package/dist/{url-targets-BJgkwPGW.d.ts → url-targets-DYLcHumF.d.ts} +2 -2
  87. package/dist/{url-targets-BJgkwPGW.d.ts.map → url-targets-DYLcHumF.d.ts.map} +1 -1
  88. package/package.json +2 -2
  89. package/src/lib/hexclave-app/apps/implementations/client-app-impl.external-token-store.test.ts +425 -0
  90. package/src/lib/hexclave-app/apps/implementations/client-app-impl.init-analytics.test.ts +79 -0
  91. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +124 -13
  92. package/src/lib/hexclave-app/apps/implementations/external-token-store-session-adapter.ts +190 -0
  93. package/src/lib/hexclave-app/apps/interfaces/client-app.ts +17 -0
  94. package/src/lib/hexclave-app/common.ts +33 -0
  95. package/src/lib/hexclave-app/index.ts +4 -0
  96. package/src/lib/hexclave-app/users/index.ts +13 -1
  97. package/dist/admin-app-impl-D9hrl67H.d.ts.map +0 -1
  98. package/dist/client-app-DLFxr4f7.d.ts.map +0 -1
  99. package/dist/common-BDyEKSM6.d.ts.map +0 -1
@@ -11,7 +11,6 @@ import { deepPlainEquals, omit } from "@hexclave/shared/dist/utils/objects";
11
11
  import { decodeBase32, decodeBase64, encodeBase32, encodeBase64 } from "@hexclave/shared/dist/utils/bytes";
12
12
  import { hexclaveAppInternalsSymbol } from "../../common.js";
13
13
  import { adminProjectCreateOptionsToCrud } from "../../projects/index.js";
14
- import { InternalSession } from "@hexclave/shared/dist/sessions";
15
14
  import { Store } from "@hexclave/shared/dist/utils/stores";
16
15
  import { crossDomainAuthQueryParams, getCrossDomainHandoffParamsFromCurrentUrl, planRedirectToHandler } from "./redirect-page-urls.js";
17
16
  import { BROWSER_ACTION_QUERY_PARAM } from "@hexclave/shared/dist/utils/browser-action-snippets";
@@ -32,9 +31,10 @@ import { teamCreateOptionsToCrud, teamUpdateOptionsToCrud } from "../../teams/in
32
31
  import { buildCliAuthConfirmUrl, getHostedHandlerUrl, isHostedHandlerUrlForProject, resolveHandlerUrls } from "../../url-targets.js";
33
32
  import { userUpdateOptionsToCrud, withUserDestructureGuard } from "../../users/index.js";
34
33
  import { EventTracker } from "./event-tracker.js";
34
+ import { ExternalTokenStoreSessionAdapter, isExternalTokenStore } from "./external-token-store-session-adapter.js";
35
35
  import { augmentUrlWithPersistedRedirectBackState, getRawAfterAuthReturnTo, saveRedirectBackStateFromUrl } from "./redirect-back-state.js";
36
36
  import { recordRedirectAndThrowIfLoopDetected } from "./redirect-loop-breaker.js";
37
- import { SessionRecorder, analyticsOptionsFromJson, analyticsOptionsToJson, getSessionReplayOptions } from "./session-replay.js";
37
+ import { SessionRecorder, analyticsOptionsFromJson, analyticsOptionsToJson, getSessionReplayOptions, isAnalyticsNotEnabledError } from "./session-replay.js";
38
38
  import { mountClickmapOverlay } from "../../../../clickmap/index.js";
39
39
  import { mountDevTool } from "../../../../dev-tool/index.js";
40
40
  import { mountPushedConfigErrorOverlay } from "../../../../pushed-config-error-overlay/index.js";
@@ -134,6 +134,9 @@ function throwSetupError(error) {
134
134
  showSetupErrorOverlay(error);
135
135
  throw error;
136
136
  }
137
+ function createAnalyticsAppDisabledOnProjectError() {
138
+ return /* @__PURE__ */ new Error("initAnalytics() was called, but the Analytics app is not enabled on this Hexclave project, so the backend rejects all analytics uploads. Enable the Analytics app in the Hexclave dashboard (or in hexclave.config.ts), or remove the initAnalytics() call if this is intentional.");
139
+ }
137
140
  function getRedirectHelperInstruction(handlerName) {
138
141
  if (handlerName === "handler") return "Use a page-specific redirect helper such as app.redirectToSignIn() instead.";
139
142
  return `Use app.${`redirectTo${handlerName.slice(0, 1).toUpperCase()}${handlerName.slice(1)}`}() instead.`;
@@ -275,6 +278,8 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
275
278
  this._uniqueIdentifier = void 0;
276
279
  this._sessionRecorder = null;
277
280
  this._eventTracker = null;
281
+ this._initAnalyticsCalled = false;
282
+ this._analyticsAppDisabledOnProject = false;
278
283
  this._pendingSignOut = null;
279
284
  this.__DEMO_ENABLE_SLIGHT_FETCH_DELAY = false;
280
285
  this._ownedAdminApps = new DependenciesMap();
@@ -474,6 +479,10 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
474
479
  prepareRequest: async () => {}
475
480
  });
476
481
  }
482
+ this._externalTokenStoreSessionAdapter = new ExternalTokenStoreSessionAdapter((sessionOptions) => this._interface.createSession(sessionOptions), async (providerId, token) => {
483
+ const exchange = await this._interface.exchangeExternalAuthToken(providerId, token);
484
+ return Result.orThrow(exchange).accessToken;
485
+ });
477
486
  this._tokenStoreInit = resolvedOptions.tokenStore;
478
487
  this._redirectMethod = resolvedOptions.redirectMethod || (isBrowserLike() ? "window" : "none");
479
488
  this._urlOptions = resolvedOptions.urls ?? {};
@@ -497,22 +506,22 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
497
506
  })) return await this._getSession();
498
507
  return (await this.getUser({ or: "anonymous" }))._internalSession;
499
508
  };
500
- const analyticsEnabled = this._analyticsOptions?.enabled !== false;
509
+ const recordsAnalytics = this._getAnalyticsDisabledReason() == null && isBrowserLike();
501
510
  const sessionReplayOptions = getSessionReplayOptions(this._analyticsOptions);
502
- if (analyticsEnabled && isBrowserLike() && this._hasPersistentTokenStore() && sessionReplayOptions.enabled) {
511
+ if (recordsAnalytics && sessionReplayOptions.enabled) {
503
512
  this._sessionRecorder = new SessionRecorder({
504
513
  projectId: this.projectId,
505
514
  sendBatch: async (body, opts) => {
506
- return await this._interface.sendSessionReplayBatch(body, await getAnalyticsSession(), opts);
515
+ return this._handleAnalyticsUploadResult(await this._interface.sendSessionReplayBatch(body, await getAnalyticsSession(), opts));
507
516
  }
508
517
  }, sessionReplayOptions);
509
518
  this._sessionRecorder.start();
510
519
  }
511
- if (analyticsEnabled && isBrowserLike() && this._hasPersistentTokenStore()) {
520
+ if (recordsAnalytics) {
512
521
  this._eventTracker = new EventTracker({
513
522
  projectId: this.projectId,
514
523
  sendBatch: async (body, opts) => {
515
- return await this._interface.sendAnalyticsEventBatch(body, await getAnalyticsSession(), opts);
524
+ return this._handleAnalyticsUploadResult(await this._interface.sendAnalyticsEventBatch(body, await getAnalyticsSession(), opts));
516
525
  }
517
526
  });
518
527
  this._eventTracker.start();
@@ -1080,6 +1089,9 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
1080
1089
  case "memory": return this._memoryTokenStore;
1081
1090
  default:
1082
1091
  if (tokenStoreInit === null) return createEmptyTokenStore();
1092
+ else if (typeof tokenStoreInit === "object" && isExternalTokenStore(tokenStoreInit)) return this._externalTokenStoreSessionAdapter.getOrCreateTokenStore(tokenStoreInit, (store, previousSessionKey) => {
1093
+ this._sessionsByTokenStoreAndSessionKey.get(store)?.get(previousSessionKey)?.suggestAccessTokenExpired();
1094
+ });
1083
1095
  else if (typeof tokenStoreInit === "object" && "headers" in tokenStoreInit) {
1084
1096
  if (this._requestTokenStores.has(tokenStoreInit)) return this._requestTokenStores.get(tokenStoreInit);
1085
1097
  const authorizationHeader = getHeaderValueFromRequestLikeHeaders(tokenStoreInit.headers, "authorization");
@@ -1121,27 +1133,27 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
1121
1133
  throw new Error(`Invalid token store ${tokenStoreInit}`);
1122
1134
  }
1123
1135
  }
1136
+ _getSessionKeyForTokenStore(tokenStore, tokenObj) {
1137
+ return this._externalTokenStoreSessionAdapter.getSessionKey(tokenStore, tokenObj);
1138
+ }
1124
1139
  /**
1125
1140
  * @param overrideTokenObj The tokens to build the session for, if they haven't been written to the token store yet
1126
1141
  * (so we can warm a sign-in's session before the token store publishes it).
1127
1142
  */
1128
1143
  _getSessionFromTokenStore(tokenStore, overrideTokenObj) {
1129
1144
  const tokenObj = overrideTokenObj ?? tokenStore.get();
1130
- const sessionKey = InternalSession.calculateSessionKey(tokenObj);
1145
+ const sessionKey = this._getSessionKeyForTokenStore(tokenStore, tokenObj);
1131
1146
  const existing = sessionKey ? this._sessionsByTokenStoreAndSessionKey.get(tokenStore)?.get(sessionKey) : null;
1132
1147
  if (existing) return existing;
1133
- const session = this._interface.createSession({
1134
- refreshToken: tokenObj.refreshToken,
1135
- accessToken: tokenObj.accessToken
1136
- });
1148
+ const session = this._externalTokenStoreSessionAdapter.createSessionForTokenStore(tokenStore, tokenObj, sessionKey);
1137
1149
  session.onAccessTokenChange((newAccessToken) => {
1138
- tokenStore.update((old) => InternalSession.calculateSessionKey(old) === sessionKey ? {
1150
+ tokenStore.update((old) => this._getSessionKeyForTokenStore(tokenStore, old) === sessionKey ? {
1139
1151
  ...old,
1140
1152
  accessToken: newAccessToken?.token ?? null
1141
1153
  } : old);
1142
1154
  });
1143
1155
  session.onInvalidate(() => {
1144
- tokenStore.update((old) => InternalSession.calculateSessionKey(old) === sessionKey ? {
1156
+ tokenStore.update((old) => this._getSessionKeyForTokenStore(tokenStore, old) === sessionKey ? {
1145
1157
  ...old,
1146
1158
  accessToken: null,
1147
1159
  refreshToken: null
@@ -1159,6 +1171,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
1159
1171
  }
1160
1172
  async _signInToAccountWithTokens(tokens) {
1161
1173
  if (!("accessToken" in tokens) || !("refreshToken" in tokens)) throw new HexclaveAssertionError("Invalid tokens object; can't sign in with this", { tokens });
1174
+ if (this.isExternalAuthApp()) throw new Error("This app authenticates through an external provider and cannot sign in with Hexclave tokens. Sign in through the provider instead.");
1162
1175
  const attemptId = ++this._signInAttemptCounter;
1163
1176
  const tokenStore = this._getOrCreateTokenStore(await this._createCookieHelper());
1164
1177
  const session = this._getSessionFromTokenStore(tokenStore, tokens);
@@ -1507,6 +1520,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
1507
1520
  emailAuthEnabled: crud.auth_with_email,
1508
1521
  otpAuthEnabled: crud.otp_auth_enabled,
1509
1522
  oauthProviders: crud.oauth_providers,
1523
+ externalAuthProviders: crud.external_auth_providers,
1510
1524
  passkeyAuthEnabled: crud.passkey_auth_enabled,
1511
1525
  isMultiFactorRequired: crud.requires_totp_mfa,
1512
1526
  isAnonymous: crud.is_anonymous,
@@ -2315,6 +2329,37 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
2315
2329
  }
2316
2330
  return crud && this._currentUserFromCrud(crud, session);
2317
2331
  }
2332
+ isExternalAuthApp() {
2333
+ return typeof this._tokenStoreInit === "object" && this._tokenStoreInit != null && isExternalTokenStore(this._tokenStoreInit);
2334
+ }
2335
+ initAnalytics() {
2336
+ this._initAnalyticsCalled = true;
2337
+ const disabledReason = this._getAnalyticsDisabledReason();
2338
+ if (disabledReason != null) throw new Error(`initAnalytics() was called, but this Hexclave app will not record analytics because ${disabledReason}. Remove the initAnalytics() call if this is intentional.`);
2339
+ if (this._analyticsAppDisabledOnProject) throw createAnalyticsAppDisabledOnProjectError();
2340
+ if (isBrowserLike() && this._eventTracker == null) throw new HexclaveAssertionError("initAnalytics() was called in the browser and _getAnalyticsDisabledReason() returned null, but the constructor did not start the event tracker. The two must agree on when analytics are recorded.");
2341
+ }
2342
+ /**
2343
+ * Returns why this app will never record analytics, or null if it records them whenever it runs in a browser. The
2344
+ * constructor and initAnalytics() both use this, so that the conditions under which analytics start and the
2345
+ * conditions under which initAnalytics() throws can't drift apart.
2346
+ *
2347
+ * Whether the Analytics app is enabled on the project is not part of this, as the client only learns that once the
2348
+ * backend rejects an upload; see _handleAnalyticsUploadResult.
2349
+ */
2350
+ _getAnalyticsDisabledReason() {
2351
+ if (this._analyticsOptions?.enabled === false) return "the `analytics.enabled` constructor option is set to false";
2352
+ if (this._options.automaticSideEffects === false) return "the `automaticSideEffects` constructor option is set to false, which also disables analytics";
2353
+ if (!this._hasPersistentTokenStore()) return "the `tokenStore` constructor option is null; analytics require a persistent token store such as \"cookie\" (or \"nextjs-cookie\" in Next.js)";
2354
+ return null;
2355
+ }
2356
+ _handleAnalyticsUploadResult(result) {
2357
+ if (result.status === "error" && isAnalyticsNotEnabledError(result.error) && !this._analyticsAppDisabledOnProject) {
2358
+ this._analyticsAppDisabledOnProject = true;
2359
+ if (this._initAnalyticsCalled) captureError("initAnalytics", createAnalyticsAppDisabledOnProjectError());
2360
+ }
2361
+ return result;
2362
+ }
2318
2363
  _getTokenPartialUserFromSession(session, options) {
2319
2364
  const accessToken = session.getAccessTokenIfNotExpiredYet(0, null);
2320
2365
  if (!accessToken) return null;
@@ -2325,6 +2370,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
2325
2370
  primaryEmail: accessToken.payload.email,
2326
2371
  displayName: accessToken.payload.name,
2327
2372
  primaryEmailVerified: accessToken.payload.email_verified,
2373
+ selectedTeamId: accessToken.payload.selected_team_id,
2328
2374
  isAnonymous,
2329
2375
  isMultiFactorRequired: accessToken.payload.requires_totp_mfa,
2330
2376
  isRestricted: accessToken.payload.is_restricted,
@@ -2334,11 +2380,14 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
2334
2380
  async _getPartialUserFromConvex(ctx) {
2335
2381
  const auth = await ctx.auth.getUserIdentity();
2336
2382
  if (!auth) return null;
2383
+ const selectedTeamId = auth.selected_team_id ?? null;
2384
+ if (selectedTeamId !== null && typeof selectedTeamId !== "string") throw new HexclaveAssertionError("Expected the Convex selected_team_id claim to be a string or null.");
2337
2385
  return {
2338
2386
  id: auth.subject,
2339
2387
  displayName: auth.name ?? null,
2340
2388
  primaryEmail: auth.email ?? null,
2341
2389
  primaryEmailVerified: auth.email_verified,
2390
+ selectedTeamId,
2342
2391
  isAnonymous: auth.is_anonymous,
2343
2392
  isMultiFactorRequired: auth.requires_totp_mfa,
2344
2393
  isRestricted: auth.is_restricted,
@@ -2678,6 +2727,8 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
2678
2727
  const previousSignOut = this._pendingSignOut;
2679
2728
  const signOutOperation = (async () => {
2680
2729
  await previousSignOut;
2730
+ const externalTokenStore = this._externalTokenStoreSessionAdapter.getExternalTokenStoreForSession(session);
2731
+ if (externalTokenStore != null) throw new HexclaveAssertionError(`Cannot sign out an externally authenticated session through Hexclave. Sign out through the ${externalTokenStore.providerId} provider instead.`);
2681
2732
  await this._interface.signOut(session);
2682
2733
  if (options?.redirectUrl) await this._redirectTo({
2683
2734
  url: options.redirectUrl,
@@ -2798,6 +2849,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
2798
2849
  return {
2799
2850
  toClientJson: () => {
2800
2851
  if (typeof this._redirectMethod !== "string") throw new HexclaveAssertionError("Cannot serialize to JSON from an application with a non-string redirect method");
2852
+ if (typeof this._tokenStoreInit === "object" && this._tokenStoreInit != null && isExternalTokenStore(this._tokenStoreInit)) throw new HexclaveAssertionError("Cannot serialize an app with an external token store because its callbacks are not serializable. Construct this app in the client runtime instead.");
2801
2853
  const publishableClientKey = "publishableClientKey" in this._interface.options ? this._interface.options.publishableClientKey : void 0;
2802
2854
  return {
2803
2855
  baseUrl: this._options.baseUrl,