@feelflow/ffid-sdk 5.24.1 → 5.24.3

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.
@@ -1228,8 +1228,35 @@ function createNonContractMethods(deps) {
1228
1228
  };
1229
1229
  }
1230
1230
 
1231
+ // src/shared/token-response.ts
1232
+ function invalidTokenFields(tokenResponse) {
1233
+ const invalid = [];
1234
+ if (typeof tokenResponse.access_token !== "string" || tokenResponse.access_token.length === 0) {
1235
+ invalid.push("access_token");
1236
+ }
1237
+ if (typeof tokenResponse.refresh_token !== "string" || tokenResponse.refresh_token.length === 0) {
1238
+ invalid.push("refresh_token");
1239
+ }
1240
+ if (typeof tokenResponse.expires_in !== "number" || !Number.isFinite(tokenResponse.expires_in) || tokenResponse.expires_in <= 0) {
1241
+ invalid.push("expires_in");
1242
+ }
1243
+ return invalid;
1244
+ }
1245
+ function hasValidatedTokens(tokenResponse) {
1246
+ return invalidTokenFields(tokenResponse).length === 0;
1247
+ }
1248
+ function validateTokenResponse(tokenResponse) {
1249
+ if (hasValidatedTokens(tokenResponse)) {
1250
+ return { ok: true, tokens: tokenResponse };
1251
+ }
1252
+ return {
1253
+ ok: false,
1254
+ message: `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u4E0D\u6B63\u306A\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u3059: ${invalidTokenFields(tokenResponse).join(", ")}`
1255
+ };
1256
+ }
1257
+
1231
1258
  // src/client/version-check.ts
1232
- var SDK_VERSION = "5.24.1";
1259
+ var SDK_VERSION = "5.24.3";
1233
1260
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1234
1261
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1235
1262
  function sdkHeaders() {
@@ -1276,22 +1303,6 @@ npm install @feelflow/ffid-sdk@latest \u3067\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8
1276
1303
  var OAUTH_TOKEN_ENDPOINT = "/api/v1/oauth/token";
1277
1304
  var OAUTH_REVOKE_ENDPOINT = "/api/v1/oauth/revoke";
1278
1305
  var MS_PER_SECOND = 1e3;
1279
- function validateTokenResponse(tokenResponse) {
1280
- const invalid = [];
1281
- if (!tokenResponse.access_token) {
1282
- invalid.push("access_token");
1283
- }
1284
- if (!tokenResponse.refresh_token) {
1285
- invalid.push("refresh_token");
1286
- }
1287
- if (typeof tokenResponse.expires_in !== "number" || !Number.isFinite(tokenResponse.expires_in) || tokenResponse.expires_in <= 0) {
1288
- invalid.push("expires_in");
1289
- }
1290
- if (invalid.length > 0) {
1291
- return `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u4E0D\u6B63\u306A\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u3059: ${invalid.join(", ")}`;
1292
- }
1293
- return null;
1294
- }
1295
1306
  function createOAuthTokenMethods(deps) {
1296
1307
  const {
1297
1308
  baseUrl,
@@ -1379,20 +1390,20 @@ function createOAuthTokenMethods(deps) {
1379
1390
  }
1380
1391
  };
1381
1392
  }
1382
- const validationError = validateTokenResponse(tokenResponse);
1383
- if (validationError) {
1384
- logger.error("Token exchange validation failed:", validationError);
1393
+ const validation = validateTokenResponse(tokenResponse);
1394
+ if (!validation.ok) {
1395
+ logger.error("Token exchange validation failed:", validation.message);
1385
1396
  return {
1386
1397
  error: {
1387
1398
  code: errorCodes.TOKEN_EXCHANGE_ERROR,
1388
- message: validationError
1399
+ message: validation.message
1389
1400
  }
1390
1401
  };
1391
1402
  }
1392
1403
  tokenStore.setTokens({
1393
- accessToken: tokenResponse.access_token,
1394
- refreshToken: tokenResponse.refresh_token,
1395
- expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
1404
+ accessToken: validation.tokens.access_token,
1405
+ refreshToken: validation.tokens.refresh_token,
1406
+ expiresAt: Date.now() + validation.tokens.expires_in * MS_PER_SECOND
1396
1407
  });
1397
1408
  logger.debug("Token exchange successful");
1398
1409
  return { data: void 0 };
@@ -1457,20 +1468,20 @@ function createOAuthTokenMethods(deps) {
1457
1468
  }
1458
1469
  };
1459
1470
  }
1460
- const validationError = validateTokenResponse(tokenResponse);
1461
- if (validationError) {
1462
- logger.error("Token refresh validation failed:", validationError);
1471
+ const validation = validateTokenResponse(tokenResponse);
1472
+ if (!validation.ok) {
1473
+ logger.error("Token refresh validation failed:", validation.message);
1463
1474
  return {
1464
1475
  error: {
1465
1476
  code: errorCodes.TOKEN_REFRESH_ERROR,
1466
- message: validationError
1477
+ message: validation.message
1467
1478
  }
1468
1479
  };
1469
1480
  }
1470
1481
  tokenStore.setTokens({
1471
- accessToken: tokenResponse.access_token,
1472
- refreshToken: tokenResponse.refresh_token,
1473
- expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
1482
+ accessToken: validation.tokens.access_token,
1483
+ refreshToken: validation.tokens.refresh_token,
1484
+ expiresAt: Date.now() + validation.tokens.expires_in * MS_PER_SECOND
1474
1485
  });
1475
1486
  logger.debug("Token refresh successful");
1476
1487
  return { data: void 0 };
@@ -3012,10 +3023,16 @@ function createFFIDClient(config) {
3012
3023
  }
3013
3024
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
3014
3025
  const resolvedRedirectUri = resolveRedirectUri(rawRedirectUri, logger);
3015
- const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
3026
+ const tokenStore = authMode === "token" ? config.tokenStore ?? createTokenStore() : createTokenStore("memory");
3016
3027
  function createError(code, message) {
3017
3028
  return { code, message };
3018
3029
  }
3030
+ function getAccessToken() {
3031
+ if (authMode !== "token") return null;
3032
+ if (tokenStore.isAccessTokenExpired()) return null;
3033
+ const accessToken = tokenStore.getTokens()?.accessToken;
3034
+ return accessToken && accessToken.length > 0 ? accessToken : null;
3035
+ }
3019
3036
  function buildFetchOptions(options, authOverride) {
3020
3037
  if (authOverride) {
3021
3038
  return {
@@ -3425,6 +3442,11 @@ function createFFIDClient(config) {
3425
3442
  inquiry,
3426
3443
  /** Token store (token mode only) */
3427
3444
  tokenStore,
3445
+ /**
3446
+ * Return the currently-valid access token, or null (token mode only; #4318).
3447
+ * Live-reads the store and applies the 30s expiry buffer.
3448
+ */
3449
+ getAccessToken,
3428
3450
  /** Resolved auth mode */
3429
3451
  authMode,
3430
3452
  /** Resolved logger instance */
@@ -3549,6 +3571,7 @@ function FFIDProvider({
3549
3571
  authMode,
3550
3572
  clientId,
3551
3573
  timeout,
3574
+ tokenStore,
3552
3575
  cleanCallbackUrl = true
3553
3576
  }) {
3554
3577
  const [user, setUser] = react.useState(null);
@@ -3574,9 +3597,10 @@ function FFIDProvider({
3574
3597
  logger,
3575
3598
  authMode,
3576
3599
  clientId,
3577
- timeout
3600
+ timeout,
3601
+ tokenStore
3578
3602
  }),
3579
- [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId, timeout]
3603
+ [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId, timeout, tokenStore]
3580
3604
  );
3581
3605
  const refresh = react.useCallback(async () => {
3582
3606
  client.logger.debug("Refreshing session...");
@@ -3790,7 +3814,10 @@ function FFIDProvider({
3790
3814
  login,
3791
3815
  logout,
3792
3816
  switchOrganization,
3793
- refresh
3817
+ refresh,
3818
+ // Stable across renders (client is memoized): live-reads the shared store
3819
+ // so refreshed/cleared tokens are reflected without host polling (#4318).
3820
+ getAccessToken: client.getAccessToken
3794
3821
  }),
3795
3822
  [
3796
3823
  user,
@@ -3802,7 +3829,8 @@ function FFIDProvider({
3802
3829
  login,
3803
3830
  logout,
3804
3831
  switchOrganization,
3805
- refresh
3832
+ refresh,
3833
+ client
3806
3834
  ]
3807
3835
  );
3808
3836
  return /* @__PURE__ */ jsxRuntime.jsx(FFIDClientContext.Provider, { value: client, children: /* @__PURE__ */ jsxRuntime.jsx(FFIDContext.Provider, { value: contextValue, children }) });
@@ -3841,6 +3869,7 @@ function useFFID() {
3841
3869
  switchAccount: client.switchAccount,
3842
3870
  switchOrganization: context.switchOrganization,
3843
3871
  refresh: context.refresh,
3872
+ getAccessToken: context.getAccessToken,
3844
3873
  getLoginUrl: client.getLoginUrl,
3845
3874
  getSignupUrl: client.getSignupUrl,
3846
3875
  getSubscribeUrl: client.getSubscribeUrl,
@@ -1226,8 +1226,35 @@ function createNonContractMethods(deps) {
1226
1226
  };
1227
1227
  }
1228
1228
 
1229
+ // src/shared/token-response.ts
1230
+ function invalidTokenFields(tokenResponse) {
1231
+ const invalid = [];
1232
+ if (typeof tokenResponse.access_token !== "string" || tokenResponse.access_token.length === 0) {
1233
+ invalid.push("access_token");
1234
+ }
1235
+ if (typeof tokenResponse.refresh_token !== "string" || tokenResponse.refresh_token.length === 0) {
1236
+ invalid.push("refresh_token");
1237
+ }
1238
+ if (typeof tokenResponse.expires_in !== "number" || !Number.isFinite(tokenResponse.expires_in) || tokenResponse.expires_in <= 0) {
1239
+ invalid.push("expires_in");
1240
+ }
1241
+ return invalid;
1242
+ }
1243
+ function hasValidatedTokens(tokenResponse) {
1244
+ return invalidTokenFields(tokenResponse).length === 0;
1245
+ }
1246
+ function validateTokenResponse(tokenResponse) {
1247
+ if (hasValidatedTokens(tokenResponse)) {
1248
+ return { ok: true, tokens: tokenResponse };
1249
+ }
1250
+ return {
1251
+ ok: false,
1252
+ message: `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u4E0D\u6B63\u306A\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u3059: ${invalidTokenFields(tokenResponse).join(", ")}`
1253
+ };
1254
+ }
1255
+
1229
1256
  // src/client/version-check.ts
1230
- var SDK_VERSION = "5.24.1";
1257
+ var SDK_VERSION = "5.24.3";
1231
1258
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1232
1259
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1233
1260
  function sdkHeaders() {
@@ -1274,22 +1301,6 @@ npm install @feelflow/ffid-sdk@latest \u3067\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8
1274
1301
  var OAUTH_TOKEN_ENDPOINT = "/api/v1/oauth/token";
1275
1302
  var OAUTH_REVOKE_ENDPOINT = "/api/v1/oauth/revoke";
1276
1303
  var MS_PER_SECOND = 1e3;
1277
- function validateTokenResponse(tokenResponse) {
1278
- const invalid = [];
1279
- if (!tokenResponse.access_token) {
1280
- invalid.push("access_token");
1281
- }
1282
- if (!tokenResponse.refresh_token) {
1283
- invalid.push("refresh_token");
1284
- }
1285
- if (typeof tokenResponse.expires_in !== "number" || !Number.isFinite(tokenResponse.expires_in) || tokenResponse.expires_in <= 0) {
1286
- invalid.push("expires_in");
1287
- }
1288
- if (invalid.length > 0) {
1289
- return `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u4E0D\u6B63\u306A\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u3059: ${invalid.join(", ")}`;
1290
- }
1291
- return null;
1292
- }
1293
1304
  function createOAuthTokenMethods(deps) {
1294
1305
  const {
1295
1306
  baseUrl,
@@ -1377,20 +1388,20 @@ function createOAuthTokenMethods(deps) {
1377
1388
  }
1378
1389
  };
1379
1390
  }
1380
- const validationError = validateTokenResponse(tokenResponse);
1381
- if (validationError) {
1382
- logger.error("Token exchange validation failed:", validationError);
1391
+ const validation = validateTokenResponse(tokenResponse);
1392
+ if (!validation.ok) {
1393
+ logger.error("Token exchange validation failed:", validation.message);
1383
1394
  return {
1384
1395
  error: {
1385
1396
  code: errorCodes.TOKEN_EXCHANGE_ERROR,
1386
- message: validationError
1397
+ message: validation.message
1387
1398
  }
1388
1399
  };
1389
1400
  }
1390
1401
  tokenStore.setTokens({
1391
- accessToken: tokenResponse.access_token,
1392
- refreshToken: tokenResponse.refresh_token,
1393
- expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
1402
+ accessToken: validation.tokens.access_token,
1403
+ refreshToken: validation.tokens.refresh_token,
1404
+ expiresAt: Date.now() + validation.tokens.expires_in * MS_PER_SECOND
1394
1405
  });
1395
1406
  logger.debug("Token exchange successful");
1396
1407
  return { data: void 0 };
@@ -1455,20 +1466,20 @@ function createOAuthTokenMethods(deps) {
1455
1466
  }
1456
1467
  };
1457
1468
  }
1458
- const validationError = validateTokenResponse(tokenResponse);
1459
- if (validationError) {
1460
- logger.error("Token refresh validation failed:", validationError);
1469
+ const validation = validateTokenResponse(tokenResponse);
1470
+ if (!validation.ok) {
1471
+ logger.error("Token refresh validation failed:", validation.message);
1461
1472
  return {
1462
1473
  error: {
1463
1474
  code: errorCodes.TOKEN_REFRESH_ERROR,
1464
- message: validationError
1475
+ message: validation.message
1465
1476
  }
1466
1477
  };
1467
1478
  }
1468
1479
  tokenStore.setTokens({
1469
- accessToken: tokenResponse.access_token,
1470
- refreshToken: tokenResponse.refresh_token,
1471
- expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
1480
+ accessToken: validation.tokens.access_token,
1481
+ refreshToken: validation.tokens.refresh_token,
1482
+ expiresAt: Date.now() + validation.tokens.expires_in * MS_PER_SECOND
1472
1483
  });
1473
1484
  logger.debug("Token refresh successful");
1474
1485
  return { data: void 0 };
@@ -3010,10 +3021,16 @@ function createFFIDClient(config) {
3010
3021
  }
3011
3022
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
3012
3023
  const resolvedRedirectUri = resolveRedirectUri(rawRedirectUri, logger);
3013
- const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
3024
+ const tokenStore = authMode === "token" ? config.tokenStore ?? createTokenStore() : createTokenStore("memory");
3014
3025
  function createError(code, message) {
3015
3026
  return { code, message };
3016
3027
  }
3028
+ function getAccessToken() {
3029
+ if (authMode !== "token") return null;
3030
+ if (tokenStore.isAccessTokenExpired()) return null;
3031
+ const accessToken = tokenStore.getTokens()?.accessToken;
3032
+ return accessToken && accessToken.length > 0 ? accessToken : null;
3033
+ }
3017
3034
  function buildFetchOptions(options, authOverride) {
3018
3035
  if (authOverride) {
3019
3036
  return {
@@ -3423,6 +3440,11 @@ function createFFIDClient(config) {
3423
3440
  inquiry,
3424
3441
  /** Token store (token mode only) */
3425
3442
  tokenStore,
3443
+ /**
3444
+ * Return the currently-valid access token, or null (token mode only; #4318).
3445
+ * Live-reads the store and applies the 30s expiry buffer.
3446
+ */
3447
+ getAccessToken,
3426
3448
  /** Resolved auth mode */
3427
3449
  authMode,
3428
3450
  /** Resolved logger instance */
@@ -3547,6 +3569,7 @@ function FFIDProvider({
3547
3569
  authMode,
3548
3570
  clientId,
3549
3571
  timeout,
3572
+ tokenStore,
3550
3573
  cleanCallbackUrl = true
3551
3574
  }) {
3552
3575
  const [user, setUser] = useState(null);
@@ -3572,9 +3595,10 @@ function FFIDProvider({
3572
3595
  logger,
3573
3596
  authMode,
3574
3597
  clientId,
3575
- timeout
3598
+ timeout,
3599
+ tokenStore
3576
3600
  }),
3577
- [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId, timeout]
3601
+ [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId, timeout, tokenStore]
3578
3602
  );
3579
3603
  const refresh = useCallback(async () => {
3580
3604
  client.logger.debug("Refreshing session...");
@@ -3788,7 +3812,10 @@ function FFIDProvider({
3788
3812
  login,
3789
3813
  logout,
3790
3814
  switchOrganization,
3791
- refresh
3815
+ refresh,
3816
+ // Stable across renders (client is memoized): live-reads the shared store
3817
+ // so refreshed/cleared tokens are reflected without host polling (#4318).
3818
+ getAccessToken: client.getAccessToken
3792
3819
  }),
3793
3820
  [
3794
3821
  user,
@@ -3800,7 +3827,8 @@ function FFIDProvider({
3800
3827
  login,
3801
3828
  logout,
3802
3829
  switchOrganization,
3803
- refresh
3830
+ refresh,
3831
+ client
3804
3832
  ]
3805
3833
  );
3806
3834
  return /* @__PURE__ */ jsx(FFIDClientContext.Provider, { value: client, children: /* @__PURE__ */ jsx(FFIDContext.Provider, { value: contextValue, children }) });
@@ -3839,6 +3867,7 @@ function useFFID() {
3839
3867
  switchAccount: client.switchAccount,
3840
3868
  switchOrganization: context.switchOrganization,
3841
3869
  refresh: context.refresh,
3870
+ getAccessToken: context.getAccessToken,
3842
3871
  getLoginUrl: client.getLoginUrl,
3843
3872
  getSignupUrl: client.getSignupUrl,
3844
3873
  getSubscribeUrl: client.getSubscribeUrl,
@@ -1,34 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var chunkL5SBAHY3_cjs = require('../chunk-L5SBAHY3.cjs');
3
+ var chunkAMVL7J2G_cjs = require('../chunk-AMVL7J2G.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunkL5SBAHY3_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkAMVL7J2G_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunkL5SBAHY3_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkAMVL7J2G_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDInquiryForm", {
16
16
  enumerable: true,
17
- get: function () { return chunkL5SBAHY3_cjs.FFIDInquiryForm; }
17
+ get: function () { return chunkAMVL7J2G_cjs.FFIDInquiryForm; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDLoginButton", {
20
20
  enumerable: true,
21
- get: function () { return chunkL5SBAHY3_cjs.FFIDLoginButton; }
21
+ get: function () { return chunkAMVL7J2G_cjs.FFIDLoginButton; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
24
24
  enumerable: true,
25
- get: function () { return chunkL5SBAHY3_cjs.FFIDOrganizationSwitcher; }
25
+ get: function () { return chunkAMVL7J2G_cjs.FFIDOrganizationSwitcher; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
28
28
  enumerable: true,
29
- get: function () { return chunkL5SBAHY3_cjs.FFIDSubscriptionBadge; }
29
+ get: function () { return chunkAMVL7J2G_cjs.FFIDSubscriptionBadge; }
30
30
  });
31
31
  Object.defineProperty(exports, "FFIDUserMenu", {
32
32
  enumerable: true,
33
- get: function () { return chunkL5SBAHY3_cjs.FFIDUserMenu; }
33
+ get: function () { return chunkAMVL7J2G_cjs.FFIDUserMenu; }
34
34
  });
@@ -1,3 +1,3 @@
1
- export { H as FFIDAnnouncementBadge, ai as FFIDAnnouncementBadgeClassNames, aj as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, ak as FFIDAnnouncementListClassNames, al as FFIDAnnouncementListProps, S as FFIDInquiryForm, T as FFIDInquiryFormCategoryItem, U as FFIDInquiryFormClassNames, V as FFIDInquiryFormLegalLayout, W as FFIDInquiryFormOrganization, X as FFIDInquiryFormPlaceholderContext, Y as FFIDInquiryFormPrefill, Z as FFIDInquiryFormProps, _ as FFIDInquiryFormSubmitData, $ as FFIDInquiryFormSubmitResult, a1 as FFIDLoginButton, am as FFIDLoginButtonProps, a4 as FFIDOrganizationSwitcher, an as FFIDOrganizationSwitcherClassNames, ao as FFIDOrganizationSwitcherProps, a9 as FFIDSubscriptionBadge, ap as FFIDSubscriptionBadgeClassNames, aq as FFIDSubscriptionBadgeProps, ab as FFIDUserMenu, ar as FFIDUserMenuClassNames, as as FFIDUserMenuProps } from '../index-GqflEaKi.cjs';
1
+ export { H as FFIDAnnouncementBadge, al as FFIDAnnouncementBadgeClassNames, am as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, an as FFIDAnnouncementListClassNames, ao as FFIDAnnouncementListProps, S as FFIDInquiryForm, U as FFIDInquiryFormCategoryItem, V as FFIDInquiryFormClassNames, W as FFIDInquiryFormLegalLayout, X as FFIDInquiryFormOrganization, Y as FFIDInquiryFormPlaceholderContext, Z as FFIDInquiryFormPrefill, _ as FFIDInquiryFormProps, $ as FFIDInquiryFormSubmitData, a0 as FFIDInquiryFormSubmitResult, a2 as FFIDLoginButton, ap as FFIDLoginButtonProps, a5 as FFIDOrganizationSwitcher, aq as FFIDOrganizationSwitcherClassNames, ar as FFIDOrganizationSwitcherProps, aa as FFIDSubscriptionBadge, as as FFIDSubscriptionBadgeClassNames, at as FFIDSubscriptionBadgeProps, ac as FFIDUserMenu, au as FFIDUserMenuClassNames, av as FFIDUserMenuProps } from '../index-BRMn6xT0.cjs';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1,3 +1,3 @@
1
- export { H as FFIDAnnouncementBadge, ai as FFIDAnnouncementBadgeClassNames, aj as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, ak as FFIDAnnouncementListClassNames, al as FFIDAnnouncementListProps, S as FFIDInquiryForm, T as FFIDInquiryFormCategoryItem, U as FFIDInquiryFormClassNames, V as FFIDInquiryFormLegalLayout, W as FFIDInquiryFormOrganization, X as FFIDInquiryFormPlaceholderContext, Y as FFIDInquiryFormPrefill, Z as FFIDInquiryFormProps, _ as FFIDInquiryFormSubmitData, $ as FFIDInquiryFormSubmitResult, a1 as FFIDLoginButton, am as FFIDLoginButtonProps, a4 as FFIDOrganizationSwitcher, an as FFIDOrganizationSwitcherClassNames, ao as FFIDOrganizationSwitcherProps, a9 as FFIDSubscriptionBadge, ap as FFIDSubscriptionBadgeClassNames, aq as FFIDSubscriptionBadgeProps, ab as FFIDUserMenu, ar as FFIDUserMenuClassNames, as as FFIDUserMenuProps } from '../index-GqflEaKi.js';
1
+ export { H as FFIDAnnouncementBadge, al as FFIDAnnouncementBadgeClassNames, am as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, an as FFIDAnnouncementListClassNames, ao as FFIDAnnouncementListProps, S as FFIDInquiryForm, U as FFIDInquiryFormCategoryItem, V as FFIDInquiryFormClassNames, W as FFIDInquiryFormLegalLayout, X as FFIDInquiryFormOrganization, Y as FFIDInquiryFormPlaceholderContext, Z as FFIDInquiryFormPrefill, _ as FFIDInquiryFormProps, $ as FFIDInquiryFormSubmitData, a0 as FFIDInquiryFormSubmitResult, a2 as FFIDLoginButton, ap as FFIDLoginButtonProps, a5 as FFIDOrganizationSwitcher, aq as FFIDOrganizationSwitcherClassNames, ar as FFIDOrganizationSwitcherProps, aa as FFIDSubscriptionBadge, as as FFIDSubscriptionBadgeClassNames, at as FFIDSubscriptionBadgeProps, ac as FFIDUserMenu, au as FFIDUserMenuClassNames, av as FFIDUserMenuProps } from '../index-BRMn6xT0.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-C4RNFEME.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-O3HGRALD.js';
@@ -270,6 +270,47 @@ interface FFIDServiceAccessDecision {
270
270
  error?: FFIDServiceAccessError;
271
271
  }
272
272
 
273
+ /**
274
+ * Token Store
275
+ *
276
+ * Manages OAuth 2.0 tokens (access + refresh) with dual-storage support.
277
+ * Falls back to in-memory storage when localStorage is unavailable
278
+ * (e.g., Safari private browsing mode).
279
+ */
280
+ /**
281
+ * Token data stored by the token store
282
+ */
283
+ interface TokenData {
284
+ /** OAuth 2.0 access token */
285
+ accessToken: string;
286
+ /** OAuth 2.0 refresh token */
287
+ refreshToken: string;
288
+ /** Expiration timestamp in milliseconds (Unix epoch) */
289
+ expiresAt: number;
290
+ }
291
+ /**
292
+ * Token store interface for managing OAuth tokens
293
+ */
294
+ interface TokenStore {
295
+ /** Get stored tokens (null if not stored) */
296
+ getTokens(): TokenData | null;
297
+ /** Store new tokens */
298
+ setTokens(tokens: TokenData): void;
299
+ /** Clear all stored tokens */
300
+ clearTokens(): void;
301
+ /** Check if access token is expired (with 30s buffer) */
302
+ isAccessTokenExpired(): boolean;
303
+ }
304
+ /**
305
+ * Create a token store with the specified storage type.
306
+ *
307
+ * When storageType is 'localStorage' (default in browser), falls back
308
+ * to memory if localStorage is not available (e.g., Safari private mode).
309
+ *
310
+ * @param storageType - 'localStorage' (default) or 'memory'
311
+ */
312
+ declare function createTokenStore(storageType?: 'localStorage' | 'memory'): TokenStore;
313
+
273
314
  /**
274
315
  * Billing checkout / portal session types.
275
316
  *
@@ -1608,6 +1649,29 @@ interface FFIDConfig {
1608
1649
  * @default undefined (no timeout, uses fetch default)
1609
1650
  */
1610
1651
  timeout?: number | undefined;
1652
+ /**
1653
+ * Token mode only: inject a shared {@link TokenStore} instance so the SDK and
1654
+ * the host app read/write the *same* token source (#4318).
1655
+ *
1656
+ * By default the client creates its own store internally
1657
+ * (`createTokenStore()` in `token` mode, `createTokenStore('memory')`
1658
+ * otherwise). That is fine when `localStorage` is available, because a
1659
+ * separately-created `localStorage` store still points at the same
1660
+ * `ffid_tokens` key. But when `localStorage` is unavailable (e.g. Safari
1661
+ * Private Mode) the SDK falls back to an *in-memory* store, and a store the
1662
+ * host app creates independently is a **different** object — so the app would
1663
+ * see the user as signed-out even though the SDK holds valid tokens.
1664
+ *
1665
+ * Passing a single instance here (typically `createTokenStore()` created once
1666
+ * by the host) guarantees both sides share one source of truth regardless of
1667
+ * storage backend. Prefer reading the token via `useFFID().getAccessToken()`
1668
+ * so refresh/logout stay reflected without the host polling the store.
1669
+ *
1670
+ * Ignored in `cookie` and `service-key` modes (neither exposes a browser
1671
+ * access-token store). When omitted, behavior is unchanged from previous
1672
+ * versions.
1673
+ */
1674
+ tokenStore?: TokenStore | undefined;
1611
1675
  }
1612
1676
  /**
1613
1677
  * OIDC `prompt` values the SDK forwards to FFID `/oauth/authorize` (#4027).
@@ -1850,47 +1914,6 @@ interface FFIDGetLoginHistoryParams {
1850
1914
  limit?: number;
1851
1915
  }
1852
1916
 
1853
- /**
1854
- * Token Store
1855
- *
1856
- * Manages OAuth 2.0 tokens (access + refresh) with dual-storage support.
1857
- * Falls back to in-memory storage when localStorage is unavailable
1858
- * (e.g., Safari private browsing mode).
1859
- */
1860
- /**
1861
- * Token data stored by the token store
1862
- */
1863
- interface TokenData {
1864
- /** OAuth 2.0 access token */
1865
- accessToken: string;
1866
- /** OAuth 2.0 refresh token */
1867
- refreshToken: string;
1868
- /** Expiration timestamp in milliseconds (Unix epoch) */
1869
- expiresAt: number;
1870
- }
1871
- /**
1872
- * Token store interface for managing OAuth tokens
1873
- */
1874
- interface TokenStore {
1875
- /** Get stored tokens (null if not stored) */
1876
- getTokens(): TokenData | null;
1877
- /** Store new tokens */
1878
- setTokens(tokens: TokenData): void;
1879
- /** Clear all stored tokens */
1880
- clearTokens(): void;
1881
- /** Check if access token is expired (with 30s buffer) */
1882
- isAccessTokenExpired(): boolean;
1883
- }
1884
- /**
1885
- * Create a token store with the specified storage type.
1886
- *
1887
- * When storageType is 'localStorage' (default in browser), falls back
1888
- * to memory if localStorage is not available (e.g., Safari private mode).
1889
- *
1890
- * @param storageType - 'localStorage' (default) or 'memory'
1891
- */
1892
- declare function createTokenStore(storageType?: 'localStorage' | 'memory'): TokenStore;
1893
-
1894
1917
  /** OAuth token operations - exchangeCodeForTokens / refreshAccessToken / signOutToken */
1895
1918
 
1896
1919
  /**
@@ -2065,6 +2088,11 @@ declare function createFFIDClient(config: FFIDConfig): {
2065
2088
  };
2066
2089
  /** Token store (token mode only) */
2067
2090
  tokenStore: TokenStore;
2091
+ /**
2092
+ * Return the currently-valid access token, or null (token mode only; #4318).
2093
+ * Live-reads the store and applies the 30s expiry buffer.
2094
+ */
2095
+ getAccessToken: () => string | null;
2068
2096
  /** Resolved auth mode */
2069
2097
  authMode: FFIDAuthMode;
2070
2098
  /** Resolved logger instance */