@stackframe/js 2.8.56 → 2.8.59

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/esm/index.js.map +1 -1
  2. package/dist/esm/integrations/convex/component/convex.config.js.map +1 -1
  3. package/dist/esm/integrations/convex.js.map +1 -1
  4. package/dist/esm/lib/auth.js.map +1 -1
  5. package/dist/esm/lib/cookie.js.map +1 -1
  6. package/dist/esm/lib/stack-app/api-keys/index.js.map +1 -1
  7. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +235 -0
  8. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  9. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +133 -23
  10. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  11. package/dist/esm/lib/stack-app/apps/implementations/common.js +2 -1
  12. package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
  13. package/dist/esm/lib/stack-app/apps/implementations/index.js.map +1 -1
  14. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +31 -23
  15. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  16. package/dist/esm/lib/stack-app/apps/index.js.map +1 -1
  17. package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  18. package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  19. package/dist/esm/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  20. package/dist/esm/lib/stack-app/common.js.map +1 -1
  21. package/dist/esm/lib/stack-app/contact-channels/index.js.map +1 -1
  22. package/dist/esm/lib/stack-app/email-templates/index.js.map +1 -1
  23. package/dist/esm/lib/stack-app/index.js.map +1 -1
  24. package/dist/esm/lib/stack-app/internal-api-keys/index.js.map +1 -1
  25. package/dist/esm/lib/stack-app/permissions/index.js.map +1 -1
  26. package/dist/esm/lib/stack-app/projects/index.js +4 -0
  27. package/dist/esm/lib/stack-app/projects/index.js.map +1 -1
  28. package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
  29. package/dist/esm/lib/stack-app/users/index.js +13 -12
  30. package/dist/esm/lib/stack-app/users/index.js.map +1 -1
  31. package/dist/esm/utils/url.js.map +1 -1
  32. package/dist/index.d.mts +285 -17
  33. package/dist/index.d.ts +285 -17
  34. package/dist/index.js.map +1 -1
  35. package/dist/integrations/convex/component/convex.config.js.map +1 -1
  36. package/dist/integrations/convex.js.map +1 -1
  37. package/dist/lib/auth.js.map +1 -1
  38. package/dist/lib/cookie.js.map +1 -1
  39. package/dist/lib/stack-app/api-keys/index.js.map +1 -1
  40. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +235 -0
  41. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  42. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +132 -22
  43. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  44. package/dist/lib/stack-app/apps/implementations/common.js +2 -1
  45. package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
  46. package/dist/lib/stack-app/apps/implementations/index.js.map +1 -1
  47. package/dist/lib/stack-app/apps/implementations/server-app-impl.js +29 -21
  48. package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  49. package/dist/lib/stack-app/apps/index.js.map +1 -1
  50. package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  51. package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  52. package/dist/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  53. package/dist/lib/stack-app/common.js.map +1 -1
  54. package/dist/lib/stack-app/connected-accounts/index.js.map +1 -1
  55. package/dist/lib/stack-app/contact-channels/index.js.map +1 -1
  56. package/dist/lib/stack-app/customers/index.js.map +1 -1
  57. package/dist/lib/stack-app/data-vault/index.js.map +1 -1
  58. package/dist/lib/stack-app/email/index.js.map +1 -1
  59. package/dist/lib/stack-app/email-templates/index.js.map +1 -1
  60. package/dist/lib/stack-app/index.js.map +1 -1
  61. package/dist/lib/stack-app/internal-api-keys/index.js.map +1 -1
  62. package/dist/lib/stack-app/notification-categories/index.js.map +1 -1
  63. package/dist/lib/stack-app/permissions/index.js.map +1 -1
  64. package/dist/lib/stack-app/project-configs/index.js.map +1 -1
  65. package/dist/lib/stack-app/projects/index.js +4 -0
  66. package/dist/lib/stack-app/projects/index.js.map +1 -1
  67. package/dist/lib/stack-app/teams/index.js.map +1 -1
  68. package/dist/lib/stack-app/users/index.js +15 -14
  69. package/dist/lib/stack-app/users/index.js.map +1 -1
  70. package/dist/utils/url.js.map +1 -1
  71. package/package.json +14 -13
  72. package/CHANGELOG.md +0 -2072
@@ -204,6 +204,11 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
204
204
  }, session);
205
205
  }
206
206
  );
207
+ this._customerBillingCache = (0, import_common2.createCacheBySession)(
208
+ async (session, [customerType, customerId]) => {
209
+ return await this._interface.getCustomerBilling(customerType, customerId, session);
210
+ }
211
+ );
207
212
  this._convexPartialUserCache = (0, import_common2.createCache)(
208
213
  async ([ctx]) => await this._getPartialUserFromConvex(ctx)
209
214
  );
@@ -431,7 +436,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
431
436
  if (!(0, import_env.isBrowserLike)()) {
432
437
  throw new import_errors.StackAssertionError("Cannot get browser cookies on the server!");
433
438
  }
434
- return cookie.parse(document.cookie || "");
439
+ return cookie.parseCookie(document.cookie || "");
435
440
  }
436
441
  _getRefreshTokenCookieNamePatterns() {
437
442
  return {
@@ -629,7 +634,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
629
634
  });
630
635
  }
631
636
  const cookieHeader = tokenStoreInit.headers.get("cookie");
632
- const parsed = cookie.parse(cookieHeader || "");
637
+ const parsed = cookie.parseCookie(cookieHeader || "");
633
638
  const res = new import_stores.Store(this._getTokensFromCookies(parsed));
634
639
  this._requestTokenStores.set(tokenStoreInit, res);
635
640
  return res;
@@ -921,23 +926,48 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
921
926
  displayName: item.product.display_name,
922
927
  customerType: item.product.customer_type,
923
928
  isServerOnly: item.product.server_only,
924
- stackable: item.product.stackable
929
+ stackable: item.product.stackable,
930
+ type: item.type,
931
+ subscription: item.subscription ? {
932
+ currentPeriodEnd: item.subscription.current_period_end ? new Date(item.subscription.current_period_end) : null,
933
+ cancelAtPeriodEnd: item.subscription.cancel_at_period_end,
934
+ isCancelable: item.subscription.is_cancelable
935
+ } : null,
936
+ switchOptions: item.switch_options?.map((option) => ({
937
+ productId: option.product_id,
938
+ displayName: option.product.display_name,
939
+ prices: option.product.prices
940
+ }))
925
941
  }));
926
942
  return Object.assign(products, { nextCursor: response.pagination.next_cursor ?? null });
927
943
  }
944
+ _customerBillingFromResponse(response) {
945
+ return {
946
+ hasCustomer: response.has_customer,
947
+ defaultPaymentMethod: response.default_payment_method
948
+ };
949
+ }
928
950
  _createAuth(session) {
929
951
  const app = this;
930
952
  return {
931
953
  _internalSession: session,
932
954
  currentSession: {
933
955
  async getTokens() {
934
- const tokens = await session.getOrFetchLikelyValidTokens(2e4);
956
+ const tokens = await session.getOrFetchLikelyValidTokens(2e4, 75e3);
935
957
  return {
936
958
  accessToken: tokens?.accessToken.token ?? null,
937
959
  refreshToken: tokens?.refreshToken?.token ?? null
938
960
  };
939
961
  }
940
962
  },
963
+ async getAccessToken() {
964
+ const tokens = await this.currentSession.getTokens();
965
+ return tokens.accessToken;
966
+ },
967
+ async getRefreshToken() {
968
+ const tokens = await this.currentSession.getTokens();
969
+ return tokens.refreshToken;
970
+ },
941
971
  async getAuthHeaders() {
942
972
  return {
943
973
  "x-stack-auth": JSON.stringify(await this.getAuthJson())
@@ -987,6 +1017,8 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
987
1017
  passkeyAuthEnabled: crud.passkey_auth_enabled,
988
1018
  isMultiFactorRequired: crud.requires_totp_mfa,
989
1019
  isAnonymous: crud.is_anonymous,
1020
+ isRestricted: crud.is_restricted,
1021
+ restrictedReason: crud.restricted_reason,
990
1022
  toClientJson() {
991
1023
  return crud;
992
1024
  }
@@ -1013,7 +1045,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1013
1045
  return this.update({ clientMetadata: metadata });
1014
1046
  },
1015
1047
  async setSelectedTeam(team) {
1016
- await this.update({ selectedTeamId: team?.id ?? null });
1048
+ await this.update({ selectedTeamId: typeof team === "string" ? team : team?.id ?? null });
1017
1049
  },
1018
1050
  getConnectedAccount,
1019
1051
  async getTeam(teamId) {
@@ -1181,8 +1213,25 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1181
1213
  }
1182
1214
  _createCustomer(userIdOrTeamId, type, session) {
1183
1215
  const app = this;
1216
+ const effectiveSession = session ?? app._interface.createSession({ refreshToken: null });
1184
1217
  const customerOptions = type === "user" ? { userId: userIdOrTeamId } : { teamId: userIdOrTeamId };
1185
1218
  return {
1219
+ async getBilling() {
1220
+ const response = import_results.Result.orThrow(await app._customerBillingCache.getOrWait([effectiveSession, type, userIdOrTeamId], "write-only"));
1221
+ return app._customerBillingFromResponse(response);
1222
+ },
1223
+ async createPaymentMethodSetupIntent() {
1224
+ const body = await app._interface.createCustomerPaymentMethodSetupIntent(type, userIdOrTeamId, effectiveSession);
1225
+ return {
1226
+ clientSecret: body.client_secret,
1227
+ stripeAccountId: body.stripe_account_id
1228
+ };
1229
+ },
1230
+ async setDefaultPaymentMethodFromSetupIntent(setupIntentId) {
1231
+ const body = await app._interface.setDefaultCustomerPaymentMethodFromSetupIntent(type, userIdOrTeamId, setupIntentId, effectiveSession);
1232
+ await app._customerBillingCache.refresh([effectiveSession, type, userIdOrTeamId]);
1233
+ return body.default_payment_method;
1234
+ },
1186
1235
  async getItem(itemId) {
1187
1236
  return await app.getItem({ itemId, ...customerOptions });
1188
1237
  },
@@ -1190,7 +1239,23 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1190
1239
  return await app.listProducts({ ...options, ...customerOptions });
1191
1240
  },
1192
1241
  async createCheckoutUrl(options) {
1193
- return await app._interface.createCheckoutUrl(type, userIdOrTeamId, options.productId, session, options.returnUrl);
1242
+ return await app._interface.createCheckoutUrl(type, userIdOrTeamId, options.productId, effectiveSession, options.returnUrl);
1243
+ },
1244
+ async switchSubscription(options) {
1245
+ await app._interface.switchSubscription({
1246
+ customer_type: type,
1247
+ customer_id: userIdOrTeamId,
1248
+ from_product_id: options.fromProductId,
1249
+ to_product_id: options.toProductId,
1250
+ price_id: options.priceId,
1251
+ quantity: options.quantity
1252
+ }, effectiveSession);
1253
+ await app._customerBillingCache.refresh([effectiveSession, type, userIdOrTeamId]);
1254
+ if (type === "user") {
1255
+ await app._userProductsCache.invalidateWhere(([cachedSession, userId]) => cachedSession === effectiveSession && userId === userIdOrTeamId);
1256
+ } else {
1257
+ await app._teamProductsCache.invalidateWhere(([cachedSession, teamId]) => cachedSession === effectiveSession && teamId === userIdOrTeamId);
1258
+ }
1194
1259
  }
1195
1260
  };
1196
1261
  }
@@ -1218,16 +1283,33 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1218
1283
  const response = import_results.Result.orThrow(await this._customProductsCache.getOrWait([session, options.customCustomerId, options.cursor ?? null, options.limit ?? null], "write-only"));
1219
1284
  return this._customerProductsFromResponse(response);
1220
1285
  }
1286
+ async cancelSubscription(options) {
1287
+ const session = await this._getSession();
1288
+ const user = await this.getUser();
1289
+ if (!user) {
1290
+ throw new import_stack_shared.KnownErrors.UserAuthenticationRequired();
1291
+ }
1292
+ const customerType = "teamId" in options ? "team" : "user";
1293
+ const customerId = "teamId" in options ? options.teamId : user.id;
1294
+ await this._interface.cancelSubscription({
1295
+ customer_type: customerType,
1296
+ customer_id: customerId,
1297
+ product_id: options.productId
1298
+ }, session);
1299
+ if (customerType === "user") {
1300
+ await this._userProductsCache.invalidateWhere(([cachedSession, userId]) => cachedSession === session && userId === customerId);
1301
+ } else {
1302
+ await this._teamProductsCache.invalidateWhere(([cachedSession, teamId]) => cachedSession === session && teamId === customerId);
1303
+ }
1304
+ }
1221
1305
  _currentUserFromCrud(crud, session) {
1222
- const currentUser = {
1306
+ const currentUser = (0, import_users.withUserDestructureGuard)({
1223
1307
  ...this._createBaseUser(crud),
1224
1308
  ...this._createAuth(session),
1225
1309
  ...this._createUserExtraFromCurrent(crud, session),
1226
1310
  ...this._isInternalProject() ? this._createInternalUserExtra(session) : {},
1227
1311
  ...this._createCustomer(crud.id, "user", session)
1228
- };
1229
- (0, import_users.attachUserDestructureGuard)(currentUser);
1230
- Object.freeze(currentUser);
1312
+ });
1231
1313
  return currentUser;
1232
1314
  }
1233
1315
  _clientSessionFromCrud(crud) {
@@ -1300,7 +1382,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1300
1382
  const queryParams = new URLSearchParams(window.location.search);
1301
1383
  url = queryParams.get("after_auth_return_to") || url;
1302
1384
  }
1303
- } else if (handlerName === "signIn" || handlerName === "signUp") {
1385
+ } else if (handlerName === "signIn" || handlerName === "signUp" || handlerName === "onboarding") {
1304
1386
  if (isReactServer || typeof window === "undefined") {
1305
1387
  } else {
1306
1388
  const currentUrl = new URL(window.location.href);
@@ -1349,6 +1431,9 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1349
1431
  async redirectToAfterSignUp(options) {
1350
1432
  return await this._redirectToHandler("afterSignUp", options);
1351
1433
  }
1434
+ async redirectToOnboarding(options) {
1435
+ return await this._redirectToHandler("onboarding", options);
1436
+ }
1352
1437
  async redirectToAfterSignOut(options) {
1353
1438
  return await this._redirectToHandler("afterSignOut", options);
1354
1439
  }
@@ -1414,16 +1499,22 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1414
1499
  return result;
1415
1500
  }
1416
1501
  async getUser(options) {
1502
+ if (options?.or === "anonymous" && options.includeRestricted === false) {
1503
+ throw new Error("Cannot use { or: 'anonymous' } with { includeRestricted: false }. Anonymous users implicitly include restricted users.");
1504
+ }
1417
1505
  this._ensurePersistentTokenStore(options?.tokenStore);
1418
1506
  const session = await this._getSession(options?.tokenStore);
1419
1507
  let crud = import_results.Result.orThrow(await this._currentUserCache.getOrWait([session], "write-only"));
1420
- if (crud?.is_anonymous && options?.or !== "anonymous" && options?.or !== "anonymous-if-exists[deprecated]") {
1421
- crud = null;
1422
- }
1423
- if (crud === null) {
1508
+ const includeAnonymous = options?.or === "anonymous" || options?.or === "anonymous-if-exists[deprecated]";
1509
+ const includeRestricted = options?.includeRestricted === true || includeAnonymous;
1510
+ if (crud === null || crud.is_anonymous && !includeAnonymous || crud.is_restricted && !includeRestricted) {
1424
1511
  switch (options?.or) {
1425
1512
  case "redirect": {
1426
- await this.redirectToSignIn({ replace: true });
1513
+ if (!crud?.is_anonymous && crud?.is_restricted) {
1514
+ await this.redirectToOnboarding({ replace: true });
1515
+ } else {
1516
+ await this.redirectToSignIn({ replace: true });
1517
+ }
1427
1518
  break;
1428
1519
  }
1429
1520
  case "throw": {
@@ -1431,7 +1522,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1431
1522
  }
1432
1523
  case "anonymous": {
1433
1524
  const tokens = await this._signUpAnonymously();
1434
- return await this.getUser({ tokenStore: tokens, or: "anonymous-if-exists[deprecated]" }) ?? (0, import_errors.throwErr)("Something went wrong while signing up anonymously");
1525
+ return await this.getUser({ tokenStore: tokens, or: "anonymous-if-exists[deprecated]", includeRestricted: true }) ?? (0, import_errors.throwErr)("Something went wrong while signing up anonymously");
1435
1526
  }
1436
1527
  case void 0:
1437
1528
  case "anonymous-if-exists[deprecated]":
@@ -1443,7 +1534,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1443
1534
  return crud && this._currentUserFromCrud(crud, session);
1444
1535
  }
1445
1536
  _getTokenPartialUserFromSession(session, options) {
1446
- const accessToken = session.getAccessTokenIfNotExpiredYet(0);
1537
+ const accessToken = session.getAccessTokenIfNotExpiredYet(0, null);
1447
1538
  if (!accessToken) {
1448
1539
  return null;
1449
1540
  }
@@ -1456,7 +1547,9 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1456
1547
  primaryEmail: accessToken.payload.email,
1457
1548
  displayName: accessToken.payload.name,
1458
1549
  primaryEmailVerified: accessToken.payload.email_verified,
1459
- isAnonymous
1550
+ isAnonymous,
1551
+ isRestricted: accessToken.payload.is_restricted,
1552
+ restrictedReason: accessToken.payload.restricted_reason
1460
1553
  };
1461
1554
  }
1462
1555
  async _getPartialUserFromConvex(ctx) {
@@ -1469,7 +1562,9 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1469
1562
  displayName: auth.name ?? null,
1470
1563
  primaryEmail: auth.email ?? null,
1471
1564
  primaryEmailVerified: auth.email_verified,
1472
- isAnonymous: auth.is_anonymous
1565
+ isAnonymous: auth.is_anonymous,
1566
+ isRestricted: auth.is_restricted,
1567
+ restrictedReason: auth.restricted_reason ?? null
1473
1568
  };
1474
1569
  }
1475
1570
  async getPartialUser(options) {
@@ -1491,7 +1586,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1491
1586
  return async (args) => {
1492
1587
  const session = await this._getSession(options.tokenStore ?? this._tokenStoreInit);
1493
1588
  if (!args.forceRefreshToken) {
1494
- const tokens2 = await session.getOrFetchLikelyValidTokens(2e4);
1589
+ const tokens2 = await session.getOrFetchLikelyValidTokens(2e4, 75e3);
1495
1590
  return tokens2?.accessToken.token ?? null;
1496
1591
  }
1497
1592
  const tokens = await session.fetchNewTokens();
@@ -1500,7 +1595,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
1500
1595
  }
1501
1596
  async getConvexHttpClientAuth(options) {
1502
1597
  const session = await this._getSession(options.tokenStore);
1503
- const tokens = await session.getOrFetchLikelyValidTokens(2e4);
1598
+ const tokens = await session.getOrFetchLikelyValidTokens(2e4, 75e3);
1504
1599
  return tokens?.accessToken.token ?? "";
1505
1600
  }
1506
1601
  async _updateClientUser(update, session) {
@@ -1847,6 +1942,20 @@ ${url}`);
1847
1942
  await user.signOut({ redirectUrl: options?.redirectUrl });
1848
1943
  }
1849
1944
  }
1945
+ async getAccessToken(options) {
1946
+ const user = await this.getUser({ tokenStore: options?.tokenStore ?? void 0 });
1947
+ if (user) {
1948
+ return await user.getAccessToken();
1949
+ }
1950
+ return null;
1951
+ }
1952
+ async getRefreshToken(options) {
1953
+ const user = await this.getUser({ tokenStore: options?.tokenStore ?? void 0 });
1954
+ if (user) {
1955
+ return await user.getRefreshToken();
1956
+ }
1957
+ return null;
1958
+ }
1850
1959
  async getAuthHeaders(options) {
1851
1960
  return {
1852
1961
  "x-stack-auth": JSON.stringify(await this.getAuthJson(options))
@@ -1883,6 +1992,7 @@ ${url}`);
1883
1992
  }
1884
1993
  async _refreshUser(session) {
1885
1994
  await this._refreshSession(session);
1995
+ session.suggestAccessTokenExpired();
1886
1996
  }
1887
1997
  async _refreshSession(session) {
1888
1998
  await this._currentUserCache.refresh([session]);