@insforge/sdk 1.2.6 → 1.2.8-dev.0

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.
package/dist/index.js CHANGED
@@ -325,6 +325,7 @@ var TokenManager = class {
325
325
  // src/lib/http-client.ts
326
326
  var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
327
327
  var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
328
+ var REFRESHABLE_AUTH_ERROR_CODE = "AUTH_UNAUTHORIZED";
328
329
  function serializeBody(method, body, headers) {
329
330
  if (body === void 0) return void 0;
330
331
  if (method === "GET" || method === "HEAD") return void 0;
@@ -379,12 +380,11 @@ var HttpClient = class {
379
380
  */
380
381
  constructor(config, tokenManager, logger) {
381
382
  this.userToken = null;
382
- this.autoRefreshToken = true;
383
383
  this.isRefreshing = false;
384
384
  this.refreshPromise = null;
385
385
  this.refreshToken = null;
386
+ this.config = config;
386
387
  this.baseUrl = config.baseUrl || "http://localhost:7130";
387
- this.autoRefreshToken = config.autoRefreshToken ?? true;
388
388
  this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
389
389
  this.anonKey = config.anonKey;
390
390
  this.defaultHeaders = {
@@ -434,48 +434,19 @@ var HttpClient = class {
434
434
  const jitter = base * (0.85 + Math.random() * 0.3);
435
435
  return Math.round(jitter);
436
436
  }
437
- /**
438
- * Performs an HTTP request with automatic retry and timeout handling.
439
- * Retries on network errors and 5xx server errors with exponential backoff.
440
- * Client errors (4xx) and timeouts are thrown immediately without retry.
441
- * @param method - HTTP method (GET, POST, PUT, PATCH, DELETE).
442
- * @param path - API path relative to the base URL.
443
- * @param options - Optional request configuration including headers, body, and query params.
444
- * @returns Parsed response data.
445
- * @throws {InsForgeError} On timeout, network failure, or HTTP error responses.
446
- */
447
- async handleRequest(method, path, options = {}) {
437
+ shouldRefreshAccessToken(statusCode, errorCode, options = {}) {
438
+ return statusCode === 401 && errorCode === REFRESHABLE_AUTH_ERROR_CODE && !(this.config.isServerMode ?? !!this.config.edgeFunctionToken) && !options.skipAuthRefresh && this.userToken !== null;
439
+ }
440
+ async fetchWithRetry(args) {
448
441
  const {
449
- params,
450
- headers = {},
442
+ method,
443
+ url,
444
+ headers,
451
445
  body,
452
- signal: callerSignal,
453
- ...fetchOptions
454
- } = options;
455
- const url = this.buildUrl(path, params);
456
- const startTime = Date.now();
457
- const canRetry = IDEMPOTENT_METHODS.has(method.toUpperCase()) || options.idempotent === true;
458
- const maxAttempts = canRetry ? this.retryCount : 0;
459
- const requestHeaders = {
460
- ...this.defaultHeaders
461
- };
462
- const authToken = this.userToken || this.anonKey;
463
- if (authToken) {
464
- requestHeaders["Authorization"] = `Bearer ${authToken}`;
465
- }
466
- const processedBody = serializeBody(method, body, requestHeaders);
467
- if (headers instanceof Headers) {
468
- headers.forEach((value, key) => {
469
- requestHeaders[key] = value;
470
- });
471
- } else if (Array.isArray(headers)) {
472
- headers.forEach(([key, value]) => {
473
- requestHeaders[key] = value;
474
- });
475
- } else {
476
- Object.assign(requestHeaders, headers);
477
- }
478
- this.logger.logRequest(method, url, requestHeaders, processedBody);
446
+ fetchOptions,
447
+ callerSignal,
448
+ maxAttempts
449
+ } = args;
479
450
  let lastError;
480
451
  for (let attempt = 0; attempt <= maxAttempts; attempt++) {
481
452
  if (attempt > 0) {
@@ -527,8 +498,8 @@ var HttpClient = class {
527
498
  try {
528
499
  const response = await this.fetch(url, {
529
500
  method,
530
- headers: requestHeaders,
531
- body: processedBody,
501
+ headers,
502
+ body,
532
503
  ...fetchOptions,
533
504
  ...controller ? { signal: controller.signal } : {}
534
505
  });
@@ -542,31 +513,8 @@ var HttpClient = class {
542
513
  );
543
514
  continue;
544
515
  }
545
- let data;
546
- try {
547
- data = await parseResponse(response);
548
- } catch (err) {
549
- if (timer !== void 0) clearTimeout(timer);
550
- if (err instanceof InsForgeError) {
551
- this.logger.logResponse(
552
- method,
553
- url,
554
- err.statusCode || response.status,
555
- Date.now() - startTime,
556
- err
557
- );
558
- }
559
- throw err;
560
- }
561
516
  if (timer !== void 0) clearTimeout(timer);
562
- this.logger.logResponse(
563
- method,
564
- url,
565
- response.status,
566
- Date.now() - startTime,
567
- data
568
- );
569
- return data;
517
+ return response;
570
518
  } catch (err) {
571
519
  if (timer !== void 0) clearTimeout(timer);
572
520
  if (err?.name === "AbortError") {
@@ -579,9 +527,6 @@ var HttpClient = class {
579
527
  }
580
528
  throw err;
581
529
  }
582
- if (err instanceof InsForgeError) {
583
- throw err;
584
- }
585
530
  if (attempt < maxAttempts) {
586
531
  lastError = err;
587
532
  continue;
@@ -599,33 +544,176 @@ var HttpClient = class {
599
544
  "NETWORK_ERROR"
600
545
  );
601
546
  }
547
+ /**
548
+ * Performs an HTTP request with automatic retry and timeout handling.
549
+ * Retries on network errors and 5xx server errors with exponential backoff.
550
+ * Client errors (4xx) and timeouts are thrown immediately without retry.
551
+ * @param method - HTTP method (GET, POST, PUT, PATCH, DELETE).
552
+ * @param path - API path relative to the base URL.
553
+ * @param options - Optional request configuration including headers, body, and query params.
554
+ * @returns Parsed response data.
555
+ * @throws {InsForgeError} On timeout, network failure, or HTTP error responses.
556
+ */
557
+ async handleRequest(method, path, options = {}) {
558
+ const {
559
+ params,
560
+ headers = {},
561
+ body,
562
+ skipAuthRefresh: _skipAuthRefresh,
563
+ signal: callerSignal,
564
+ ...fetchOptions
565
+ } = options;
566
+ const url = this.buildUrl(path, params);
567
+ const startTime = Date.now();
568
+ const canRetry = IDEMPOTENT_METHODS.has(method.toUpperCase()) || options.idempotent === true;
569
+ const maxAttempts = canRetry ? this.retryCount : 0;
570
+ const requestHeaders = {
571
+ ...this.defaultHeaders
572
+ };
573
+ const authToken = this.userToken || this.anonKey;
574
+ if (authToken) {
575
+ requestHeaders["Authorization"] = `Bearer ${authToken}`;
576
+ }
577
+ const processedBody = serializeBody(method, body, requestHeaders);
578
+ if (headers instanceof Headers) {
579
+ headers.forEach((value, key) => {
580
+ requestHeaders[key] = value;
581
+ });
582
+ } else if (Array.isArray(headers)) {
583
+ headers.forEach(([key, value]) => {
584
+ requestHeaders[key] = value;
585
+ });
586
+ } else {
587
+ Object.assign(requestHeaders, headers);
588
+ }
589
+ this.logger.logRequest(method, url, requestHeaders, processedBody);
590
+ const response = await this.fetchWithRetry({
591
+ method,
592
+ url,
593
+ headers: requestHeaders,
594
+ body: processedBody,
595
+ fetchOptions,
596
+ callerSignal,
597
+ maxAttempts
598
+ });
599
+ let data;
600
+ try {
601
+ data = await parseResponse(response);
602
+ } catch (err) {
603
+ if (err instanceof InsForgeError) {
604
+ this.logger.logResponse(
605
+ method,
606
+ url,
607
+ err.statusCode || response.status,
608
+ Date.now() - startTime,
609
+ err
610
+ );
611
+ }
612
+ throw err;
613
+ }
614
+ this.logger.logResponse(
615
+ method,
616
+ url,
617
+ response.status,
618
+ Date.now() - startTime,
619
+ data
620
+ );
621
+ return data;
622
+ }
602
623
  async request(method, path, options = {}) {
603
624
  try {
604
625
  return await this.handleRequest(method, path, { ...options });
605
626
  } catch (error) {
606
- if (error instanceof InsForgeError && error.statusCode === 401 && error.error === "INVALID_TOKEN" && this.autoRefreshToken) {
627
+ if (error instanceof InsForgeError && this.shouldRefreshAccessToken(error.statusCode, error.error, options)) {
607
628
  try {
608
- const newTokenData = await this.handleTokenRefresh();
609
- this.setAuthToken(newTokenData.accessToken);
610
- this.tokenManager.saveSession(newTokenData);
611
- if (newTokenData.csrfToken) {
612
- setCsrfToken(newTokenData.csrfToken);
613
- }
614
- if (newTokenData.refreshToken) {
615
- this.setRefreshToken(newTokenData.refreshToken);
616
- }
617
- return await this.handleRequest(method, path, { ...options });
629
+ await this.refreshAndSaveSession();
618
630
  } catch (error2) {
619
- this.tokenManager.clearSession();
620
- this.userToken = null;
621
- this.refreshToken = null;
622
- clearCsrfToken();
631
+ this.clearAuthSession();
623
632
  throw error2;
624
633
  }
634
+ return await this.handleRequest(method, path, { ...options });
625
635
  }
626
636
  throw error;
627
637
  }
628
638
  }
639
+ /**
640
+ * Performs an SDK-configured fetch and returns the raw Response.
641
+ * This is used by clients such as postgrest-js that need to own response
642
+ * parsing while still sharing SDK auth and refresh behavior.
643
+ */
644
+ async rawFetch(input, init, options = {}) {
645
+ const request = typeof Request !== "undefined" && input instanceof Request ? input : void 0;
646
+ const {
647
+ method: initMethod,
648
+ headers: initHeaders,
649
+ body: initBody,
650
+ signal: initSignal,
651
+ ...fetchOptions
652
+ } = init ?? {};
653
+ const method = initMethod ?? request?.method ?? "GET";
654
+ const url = request?.url ?? input.toString();
655
+ const startTime = Date.now();
656
+ const headers = new Headers(this.getHeaders());
657
+ request?.headers.forEach((value, key) => {
658
+ headers.set(key, value);
659
+ });
660
+ new Headers(initHeaders).forEach((value, key) => {
661
+ headers.set(key, value);
662
+ });
663
+ const requestHeaders = {};
664
+ headers.forEach((value, key) => {
665
+ requestHeaders[key] = value;
666
+ });
667
+ const body = initBody ?? request?.body ?? void 0;
668
+ const callerSignal = initSignal ?? request?.signal;
669
+ const maxAttempts = IDEMPOTENT_METHODS.has(method.toUpperCase()) ? this.retryCount : 0;
670
+ this.logger.logRequest(method, url, requestHeaders, body);
671
+ const response = await this.fetchWithRetry({
672
+ method,
673
+ url,
674
+ headers: requestHeaders,
675
+ body,
676
+ fetchOptions,
677
+ callerSignal,
678
+ maxAttempts
679
+ });
680
+ this.logger.logResponse(
681
+ method,
682
+ url,
683
+ response.status,
684
+ Date.now() - startTime
685
+ );
686
+ let errorCode = null;
687
+ if (response.status === 401) {
688
+ try {
689
+ const data = await response.clone().json();
690
+ if (data && typeof data === "object") {
691
+ const candidate = data.error ?? data.code;
692
+ if (typeof candidate === "string") {
693
+ errorCode = candidate;
694
+ }
695
+ }
696
+ } catch {
697
+ }
698
+ }
699
+ if (!this.shouldRefreshAccessToken(response.status, errorCode, options)) {
700
+ return response;
701
+ }
702
+ let newTokenData;
703
+ try {
704
+ newTokenData = await this.refreshAndSaveSession();
705
+ } catch (error) {
706
+ this.clearAuthSession();
707
+ throw error;
708
+ }
709
+ const retryHeaders = new Headers(initHeaders);
710
+ retryHeaders.set("Authorization", `Bearer ${newTokenData.accessToken}`);
711
+ return await this.rawFetch(
712
+ input,
713
+ { ...init, headers: retryHeaders },
714
+ { skipAuthRefresh: true }
715
+ );
716
+ }
629
717
  /** Performs a GET request. */
630
718
  get(path, options) {
631
719
  return this.request("GET", path, options);
@@ -662,7 +750,7 @@ var HttpClient = class {
662
750
  }
663
751
  return headers;
664
752
  }
665
- async handleTokenRefresh() {
753
+ async refreshAccessToken() {
666
754
  if (this.isRefreshing) {
667
755
  return this.refreshPromise;
668
756
  }
@@ -673,7 +761,7 @@ var HttpClient = class {
673
761
  const body = this.refreshToken ? { refreshToken: this.refreshToken } : void 0;
674
762
  const response = await this.handleRequest(
675
763
  "POST",
676
- "/api/auth/sessions/current",
764
+ this.refreshToken ? "/api/auth/refresh?client_type=mobile" : "/api/auth/refresh",
677
765
  {
678
766
  body,
679
767
  headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {},
@@ -688,6 +776,24 @@ var HttpClient = class {
688
776
  })();
689
777
  return this.refreshPromise;
690
778
  }
779
+ async refreshAndSaveSession() {
780
+ const newTokenData = await this.refreshAccessToken();
781
+ this.setAuthToken(newTokenData.accessToken);
782
+ this.tokenManager.saveSession(newTokenData);
783
+ if (newTokenData.csrfToken) {
784
+ setCsrfToken(newTokenData.csrfToken);
785
+ }
786
+ if (newTokenData.refreshToken) {
787
+ this.setRefreshToken(newTokenData.refreshToken);
788
+ }
789
+ return newTokenData;
790
+ }
791
+ clearAuthSession() {
792
+ this.tokenManager.clearSession();
793
+ this.userToken = null;
794
+ this.refreshToken = null;
795
+ clearCsrfToken();
796
+ }
691
797
  };
692
798
 
693
799
  // src/modules/auth/helpers.ts
@@ -816,7 +922,7 @@ var Auth = class {
816
922
  const response = await this.http.post(
817
923
  this.isServerMode() ? "/api/auth/users?client_type=mobile" : "/api/auth/users",
818
924
  request,
819
- { credentials: "include" }
925
+ { credentials: "include", skipAuthRefresh: true }
820
926
  );
821
927
  if (response.accessToken && response.user) {
822
928
  this.saveSessionFromResponse(response);
@@ -834,7 +940,7 @@ var Auth = class {
834
940
  const response = await this.http.post(
835
941
  this.isServerMode() ? "/api/auth/sessions?client_type=mobile" : "/api/auth/sessions",
836
942
  request,
837
- { credentials: "include" }
943
+ { credentials: "include", skipAuthRefresh: true }
838
944
  );
839
945
  this.saveSessionFromResponse(response);
840
946
  if (response.refreshToken) {
@@ -851,7 +957,7 @@ var Auth = class {
851
957
  await this.http.post(
852
958
  this.isServerMode() ? "/api/auth/logout?client_type=mobile" : "/api/auth/logout",
853
959
  void 0,
854
- { credentials: "include" }
960
+ { credentials: "include", skipAuthRefresh: true }
855
961
  );
856
962
  } catch {
857
963
  }
@@ -888,7 +994,8 @@ var Auth = class {
888
994
  );
889
995
  const oauthPath = isBuiltInProvider ? `/api/auth/oauth/${providerKey}` : `/api/auth/oauth/custom/${providerKey}`;
890
996
  const response = await this.http.get(oauthPath, {
891
- params
997
+ params,
998
+ skipAuthRefresh: true
892
999
  });
893
1000
  if (!this.isServerMode() && typeof window !== "undefined" && !skipBrowserRedirect) {
894
1001
  window.location.href = response.authUrl;
@@ -936,7 +1043,7 @@ var Auth = class {
936
1043
  const response = await this.http.post(
937
1044
  this.isServerMode() ? "/api/auth/oauth/exchange?client_type=mobile" : "/api/auth/oauth/exchange",
938
1045
  request,
939
- { credentials: "include" }
1046
+ { credentials: "include", skipAuthRefresh: true }
940
1047
  );
941
1048
  this.saveSessionFromResponse(response);
942
1049
  return {
@@ -963,7 +1070,7 @@ var Auth = class {
963
1070
  const response = await this.http.post(
964
1071
  "/api/auth/id-token?client_type=mobile",
965
1072
  { provider, token },
966
- { credentials: "include" }
1073
+ { credentials: "include", skipAuthRefresh: true }
967
1074
  );
968
1075
  this.saveSessionFromResponse(response);
969
1076
  if (response.refreshToken) {
@@ -1010,7 +1117,8 @@ var Auth = class {
1010
1117
  this.isServerMode() ? { refresh_token: options?.refreshToken } : void 0,
1011
1118
  {
1012
1119
  headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {},
1013
- credentials: "include"
1120
+ credentials: "include",
1121
+ skipAuthRefresh: true
1014
1122
  }
1015
1123
  );
1016
1124
  if (response.accessToken) {
@@ -1113,7 +1221,9 @@ var Auth = class {
1113
1221
  // ============================================================================
1114
1222
  async resendVerificationEmail(request) {
1115
1223
  try {
1116
- const response = await this.http.post("/api/auth/email/send-verification", request);
1224
+ const response = await this.http.post("/api/auth/email/send-verification", request, {
1225
+ skipAuthRefresh: true
1226
+ });
1117
1227
  return { data: response, error: null };
1118
1228
  } catch (error) {
1119
1229
  return wrapError(
@@ -1127,7 +1237,7 @@ var Auth = class {
1127
1237
  const response = await this.http.post(
1128
1238
  this.isServerMode() ? "/api/auth/email/verify?client_type=mobile" : "/api/auth/email/verify",
1129
1239
  request,
1130
- { credentials: "include" }
1240
+ { credentials: "include", skipAuthRefresh: true }
1131
1241
  );
1132
1242
  this.saveSessionFromResponse(response);
1133
1243
  if (response.refreshToken) {
@@ -1146,7 +1256,9 @@ var Auth = class {
1146
1256
  // ============================================================================
1147
1257
  async sendResetPasswordEmail(request) {
1148
1258
  try {
1149
- const response = await this.http.post("/api/auth/email/send-reset-password", request);
1259
+ const response = await this.http.post("/api/auth/email/send-reset-password", request, {
1260
+ skipAuthRefresh: true
1261
+ });
1150
1262
  return { data: response, error: null };
1151
1263
  } catch (error) {
1152
1264
  return wrapError(
@@ -1159,7 +1271,8 @@ var Auth = class {
1159
1271
  try {
1160
1272
  const response = await this.http.post(
1161
1273
  "/api/auth/email/exchange-reset-password-token",
1162
- request
1274
+ request,
1275
+ { skipAuthRefresh: true }
1163
1276
  );
1164
1277
  return { data: response, error: null };
1165
1278
  } catch (error) {
@@ -1173,7 +1286,8 @@ var Auth = class {
1173
1286
  try {
1174
1287
  const response = await this.http.post(
1175
1288
  "/api/auth/email/reset-password",
1176
- request
1289
+ request,
1290
+ { skipAuthRefresh: true }
1177
1291
  );
1178
1292
  return { data: response, error: null };
1179
1293
  } catch (error) {
@@ -1189,7 +1303,8 @@ var Auth = class {
1189
1303
  async getPublicAuthConfig() {
1190
1304
  try {
1191
1305
  const response = await this.http.get(
1192
- "/api/auth/public-config"
1306
+ "/api/auth/public-config",
1307
+ { skipAuthRefresh: true }
1193
1308
  );
1194
1309
  return { data: response, error: null };
1195
1310
  } catch (error) {
@@ -1203,7 +1318,7 @@ var Auth = class {
1203
1318
 
1204
1319
  // src/modules/database-postgrest.ts
1205
1320
  var import_postgrest_js = require("@supabase/postgrest-js");
1206
- function createInsForgePostgrestFetch(httpClient, tokenManager) {
1321
+ function createInsForgePostgrestFetch(httpClient) {
1207
1322
  return async (input, init) => {
1208
1323
  const url = typeof input === "string" ? input : input.toString();
1209
1324
  const urlObj = new URL(url);
@@ -1211,14 +1326,11 @@ function createInsForgePostgrestFetch(httpClient, tokenManager) {
1211
1326
  const rpcMatch = pathname.match(/^rpc\/(.+)$/);
1212
1327
  const endpoint = rpcMatch ? `/api/database/rpc/${rpcMatch[1]}` : `/api/database/records/${pathname}`;
1213
1328
  const insforgeUrl = `${httpClient.baseUrl}${endpoint}${urlObj.search}`;
1214
- const token = tokenManager.getAccessToken();
1215
- const httpHeaders = httpClient.getHeaders();
1216
- const authToken = token || httpHeaders["Authorization"]?.replace("Bearer ", "");
1217
- const headers = new Headers(init?.headers);
1218
- if (authToken && !headers.has("Authorization")) {
1219
- headers.set("Authorization", `Bearer ${authToken}`);
1220
- }
1221
- const response = await fetch(insforgeUrl, {
1329
+ const headers = new Headers(httpClient.getHeaders());
1330
+ new Headers(init?.headers).forEach((value, key) => {
1331
+ headers.set(key, value);
1332
+ });
1333
+ const response = await httpClient.rawFetch(insforgeUrl, {
1222
1334
  ...init,
1223
1335
  headers
1224
1336
  });
@@ -1226,42 +1338,42 @@ function createInsForgePostgrestFetch(httpClient, tokenManager) {
1226
1338
  };
1227
1339
  }
1228
1340
  var Database = class {
1229
- constructor(httpClient, tokenManager) {
1341
+ constructor(httpClient) {
1230
1342
  this.postgrest = new import_postgrest_js.PostgrestClient("http://dummy", {
1231
- fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
1343
+ fetch: createInsForgePostgrestFetch(httpClient),
1232
1344
  headers: {}
1233
1345
  });
1234
1346
  }
1235
1347
  /**
1236
1348
  * Create a query builder for a table
1237
- *
1349
+ *
1238
1350
  * @example
1239
1351
  * // Basic query
1240
1352
  * const { data, error } = await client.database
1241
1353
  * .from('posts')
1242
1354
  * .select('*')
1243
1355
  * .eq('user_id', userId);
1244
- *
1356
+ *
1245
1357
  * // With count (Supabase style!)
1246
1358
  * const { data, error, count } = await client.database
1247
1359
  * .from('posts')
1248
1360
  * .select('*', { count: 'exact' })
1249
1361
  * .range(0, 9);
1250
- *
1362
+ *
1251
1363
  * // Just get count, no data
1252
1364
  * const { count } = await client.database
1253
1365
  * .from('posts')
1254
1366
  * .select('*', { count: 'exact', head: true });
1255
- *
1367
+ *
1256
1368
  * // Complex queries with OR
1257
1369
  * const { data } = await client.database
1258
1370
  * .from('posts')
1259
1371
  * .select('*, users!inner(*)')
1260
1372
  * .or('status.eq.active,status.eq.pending');
1261
- *
1373
+ *
1262
1374
  * // All features work:
1263
1375
  * - Nested selects
1264
- * - Foreign key expansion
1376
+ * - Foreign key expansion
1265
1377
  * - OR/AND/NOT conditions
1266
1378
  * - Count with head
1267
1379
  * - Range pagination
@@ -2302,8 +2414,7 @@ var Payments = class {
2302
2414
  *
2303
2415
  * @example
2304
2416
  * ```typescript
2305
- * const { data, error } = await client.payments.createCheckoutSession({
2306
- * environment: 'test',
2417
+ * const { data, error } = await client.payments.createCheckoutSession('test', {
2307
2418
  * mode: 'payment',
2308
2419
  * lineItems: [{ stripePriceId: 'price_123', quantity: 1 }],
2309
2420
  * successUrl: `${window.location.origin}/success`,
@@ -2315,10 +2426,10 @@ var Payments = class {
2315
2426
  * }
2316
2427
  * ```
2317
2428
  */
2318
- async createCheckoutSession(request) {
2429
+ async createCheckoutSession(environment, request) {
2319
2430
  try {
2320
2431
  const data = await this.http.post(
2321
- "/api/payments/checkout-sessions",
2432
+ `/api/payments/${encodeURIComponent(environment)}/checkout-sessions`,
2322
2433
  request,
2323
2434
  { idempotent: !!request.idempotencyKey }
2324
2435
  );
@@ -2333,10 +2444,10 @@ var Payments = class {
2333
2444
  /**
2334
2445
  * Create a Stripe Billing Portal Session for a mapped billing subject.
2335
2446
  */
2336
- async createCustomerPortalSession(request) {
2447
+ async createCustomerPortalSession(environment, request) {
2337
2448
  try {
2338
2449
  const data = await this.http.post(
2339
- "/api/payments/customer-portal-sessions",
2450
+ `/api/payments/${encodeURIComponent(environment)}/customer-portal-sessions`,
2340
2451
  request
2341
2452
  );
2342
2453
  return { data, error: null };
@@ -2362,7 +2473,7 @@ var InsForgeClient = class {
2362
2473
  this.auth = new Auth(this.http, this.tokenManager, {
2363
2474
  isServerMode: config.isServerMode ?? !!config.edgeFunctionToken
2364
2475
  });
2365
- this.database = new Database(this.http, this.tokenManager);
2476
+ this.database = new Database(this.http);
2366
2477
  this.storage = new Storage(this.http);
2367
2478
  this.ai = new AI(this.http);
2368
2479
  this.functions = new Functions(this.http, config.functionsUrl);
@@ -2386,6 +2497,37 @@ var InsForgeClient = class {
2386
2497
  getHttpClient() {
2387
2498
  return this.http;
2388
2499
  }
2500
+ /**
2501
+ * Set the access token used by every SDK surface. Updates both the HTTP
2502
+ * client (database / storage / functions / AI / emails) and the realtime
2503
+ * token manager (which fires `onTokenChange` to reconnect the WebSocket
2504
+ * with the new bearer). Pass `null` to clear.
2505
+ *
2506
+ * Use this when an external auth provider (Better Auth, Clerk, Auth0,
2507
+ * WorkOS, Kinde, Stytch, …) issues the JWT and you need to keep the
2508
+ * long-lived InsForge client in sync. Without this, you'd have to call
2509
+ * `client.getHttpClient().setAuthToken(token)` AND reach into the private
2510
+ * `client.realtime.tokenManager.setAccessToken(token)` separately —
2511
+ * forgetting the second one silently breaks realtime auth.
2512
+ *
2513
+ * @example
2514
+ * ```typescript
2515
+ * // Refresh a third-party-issued JWT periodically
2516
+ * const { token } = await fetch('/api/insforge-token').then((r) => r.json());
2517
+ * client.setAccessToken(token);
2518
+ *
2519
+ * // Sign-out
2520
+ * client.setAccessToken(null);
2521
+ * ```
2522
+ */
2523
+ setAccessToken(token) {
2524
+ this.http.setAuthToken(token);
2525
+ if (token === null) {
2526
+ this.tokenManager.clearSession();
2527
+ } else {
2528
+ this.tokenManager.setAccessToken(token);
2529
+ }
2530
+ }
2389
2531
  /**
2390
2532
  * Future modules will be added here:
2391
2533
  * - database: Database operations