@feelflow/ffid-sdk 10.0.0 → 10.1.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.
@@ -1374,7 +1374,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
1374
1374
  };
1375
1375
 
1376
1376
  // src/client/version-check.ts
1377
- var SDK_VERSION = "10.0.0";
1377
+ var SDK_VERSION = "10.1.0";
1378
1378
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1379
1379
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1380
1380
  function sdkHeaders() {
@@ -4609,6 +4609,50 @@ function createFFIDClient(config) {
4609
4609
  };
4610
4610
  }
4611
4611
 
4612
+ // src/client/authorization-error.ts
4613
+ var FFID_OAUTH_DENIAL_REASONS = [
4614
+ /** The user is not a member of the organization */
4615
+ "no_membership",
4616
+ /** The organization has no usable subscription for the service */
4617
+ "no_active_subscription",
4618
+ /** The organization has a subscription, but the user has no seat in it */
4619
+ "no_seat_assignment",
4620
+ /** The subscription has expired (canceled / past due beyond grace) */
4621
+ "subscription_expired",
4622
+ /** The flat plan's member limit is full, so no seat could be given */
4623
+ "member_limit_reached"
4624
+ ];
4625
+ function isFFIDOAuthDenialReason(value) {
4626
+ return typeof value === "string" && FFID_OAUTH_DENIAL_REASONS.includes(value);
4627
+ }
4628
+ var DEFAULT_AUTHORIZATION_ERROR_MESSAGE = "\u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F";
4629
+ function buildAuthorizationError(params) {
4630
+ const oauthError = params.get("error");
4631
+ if (!oauthError) return null;
4632
+ const rawReason = params.get("denial_reason");
4633
+ const errorDescription = params.get("error_description");
4634
+ const details = {
4635
+ source: "authorization",
4636
+ denialReason: isFFIDOAuthDenialReason(rawReason) ? rawReason : null,
4637
+ errorDescription
4638
+ };
4639
+ return {
4640
+ code: oauthError,
4641
+ message: errorDescription ?? DEFAULT_AUTHORIZATION_ERROR_MESSAGE,
4642
+ details: { ...details }
4643
+ };
4644
+ }
4645
+ function getFFIDAuthorizationError(error) {
4646
+ const details = error?.details;
4647
+ if (!error || !details || details.source !== "authorization") return null;
4648
+ const description = details.errorDescription;
4649
+ return {
4650
+ oauthError: error.code,
4651
+ denialReason: isFFIDOAuthDenialReason(details.denialReason) ? details.denialReason : null,
4652
+ errorDescription: typeof description === "string" ? description : null
4653
+ };
4654
+ }
4655
+
4612
4656
  // src/client/callback.ts
4613
4657
  var CALLBACK_ERROR_CODES = {
4614
4658
  /** Stored state missing or did not match the callback `state` (CSRF guard) */
@@ -4633,16 +4677,43 @@ function extractSearchParams(source) {
4633
4677
  return new URLSearchParams(query);
4634
4678
  }
4635
4679
  }
4636
- function cleanCallbackUrlParams(logger) {
4680
+ var CODE_CALLBACK_PARAMS = ["code", "state"];
4681
+ var ERROR_CALLBACK_CONSUMED_PARAMS = ["state"];
4682
+ function cleanCallbackUrlParams(logger, names) {
4637
4683
  try {
4638
4684
  const cleanUrl = new URL(window.location.href);
4639
- cleanUrl.searchParams.delete("code");
4640
- cleanUrl.searchParams.delete("state");
4685
+ for (const name of names) cleanUrl.searchParams.delete(name);
4641
4686
  window.history.replaceState({}, "", cleanUrl.toString());
4642
4687
  } catch (error) {
4643
4688
  logger.warn("handleRedirectCallback: URL \u306E\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
4644
4689
  }
4645
4690
  }
4691
+ function validateCallbackState(client, urlState) {
4692
+ const { logger } = client;
4693
+ const storedState = retrieveState(logger);
4694
+ if (storedState === null && urlState === null) return null;
4695
+ if (storedState !== null && storedState === urlState) return null;
4696
+ if (storedState === null && !isStateStorageAvailable()) {
4697
+ logger.error(
4698
+ "handleRedirectCallback: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 CSRF \u691C\u8A3C\u304C\u3067\u304D\u307E\u305B\u3093\uFF08iOS private mode \u7B49\uFF09"
4699
+ );
4700
+ return {
4701
+ error: client.createError(
4702
+ CALLBACK_ERROR_CODES.STATE_UNAVAILABLE,
4703
+ "OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30E2\u30FC\u30C9\u3084\u30B9\u30C8\u30EC\u30FC\u30B8\u8A2D\u5B9A\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044"
4704
+ )
4705
+ };
4706
+ }
4707
+ logger.error(
4708
+ "handleRedirectCallback: OAuth state mismatch or omitted (possible CSRF) \u2014 \u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002\u6D88\u8CBB\u6E08\u307F callback \u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u518D\u51E6\u7406\uFF08`cleanUrl: false` \u5229\u7528\u6642\u306E cleanup \u6F0F\u308C\u3084 reload \u7B49\uFF09\u3067\u3082\u767A\u751F\u3057\u307E\u3059"
4709
+ );
4710
+ return {
4711
+ error: client.createError(
4712
+ CALLBACK_ERROR_CODES.STATE_MISMATCH,
4713
+ "OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
4714
+ )
4715
+ };
4716
+ }
4646
4717
  async function handleRedirectCallback(client, options) {
4647
4718
  const { logger } = client;
4648
4719
  const hasWindow = typeof window !== "undefined";
@@ -4659,6 +4730,24 @@ async function handleRedirectCallback(client, options) {
4659
4730
  const params = extractSearchParams(source);
4660
4731
  const code = params.get("code");
4661
4732
  const urlState = params.get("state");
4733
+ const authorizationError = buildAuthorizationError(params);
4734
+ if (authorizationError && urlState !== null) {
4735
+ const stateError2 = validateCallbackState(client, urlState);
4736
+ if (stateError2) return stateError2;
4737
+ retrieveCodeVerifier(logger);
4738
+ logger.warn("handleRedirectCallback: \u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F:", {
4739
+ error: authorizationError.code,
4740
+ denialReason: params.get("denial_reason")
4741
+ });
4742
+ if (hasWindow) {
4743
+ if (options?.cleanUrl !== false) {
4744
+ cleanCallbackUrlParams(logger, ERROR_CALLBACK_CONSUMED_PARAMS);
4745
+ } else {
4746
+ logger.debug("handleRedirectCallback: cleanUrl=false \u306E\u305F\u3081 URL cleanup \u3092 consumer \u306B\u59D4\u8B72\u3057\u307E\u3057\u305F");
4747
+ }
4748
+ }
4749
+ return { error: authorizationError };
4750
+ }
4662
4751
  if (!code) {
4663
4752
  logger.warn("handleRedirectCallback: \u8A8D\u53EF\u30B3\u30FC\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
4664
4753
  return {
@@ -4668,37 +4757,13 @@ async function handleRedirectCallback(client, options) {
4668
4757
  )
4669
4758
  };
4670
4759
  }
4671
- const storedState = retrieveState(logger);
4672
- if (storedState !== null || urlState !== null) {
4673
- const stateMatches = storedState !== null && storedState === urlState;
4674
- if (!stateMatches) {
4675
- if (storedState === null && !isStateStorageAvailable()) {
4676
- logger.error(
4677
- "handleRedirectCallback: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 CSRF \u691C\u8A3C\u304C\u3067\u304D\u307E\u305B\u3093\uFF08iOS private mode \u7B49\uFF09"
4678
- );
4679
- return {
4680
- error: client.createError(
4681
- CALLBACK_ERROR_CODES.STATE_UNAVAILABLE,
4682
- "OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30E2\u30FC\u30C9\u3084\u30B9\u30C8\u30EC\u30FC\u30B8\u8A2D\u5B9A\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044"
4683
- )
4684
- };
4685
- }
4686
- logger.error(
4687
- "handleRedirectCallback: OAuth state mismatch or omitted (possible CSRF) \u2014 \u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002\u6D88\u8CBB\u6E08\u307F callback \u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u518D\u51E6\u7406\uFF08`cleanUrl: false` \u5229\u7528\u6642\u306E cleanup \u6F0F\u308C\u3084 reload \u7B49\uFF09\u3067\u3082\u767A\u751F\u3057\u307E\u3059"
4688
- );
4689
- return {
4690
- error: client.createError(
4691
- CALLBACK_ERROR_CODES.STATE_MISMATCH,
4692
- "OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
4693
- )
4694
- };
4695
- }
4696
- }
4760
+ const stateError = validateCallbackState(client, urlState);
4761
+ if (stateError) return stateError;
4697
4762
  const verifier = retrieveCodeVerifier(logger);
4698
4763
  const result = await client.exchangeCodeForTokens(code, verifier ?? void 0);
4699
4764
  if (!result.error && hasWindow) {
4700
4765
  if (options?.cleanUrl !== false) {
4701
- cleanCallbackUrlParams(logger);
4766
+ cleanCallbackUrlParams(logger, CODE_CALLBACK_PARAMS);
4702
4767
  } else {
4703
4768
  logger.debug("handleRedirectCallback: cleanUrl=false \u306E\u305F\u3081 URL cleanup \u3092 consumer \u306B\u59D4\u8B72\u3057\u307E\u3057\u305F");
4704
4769
  }
@@ -4707,6 +4772,13 @@ async function handleRedirectCallback(client, options) {
4707
4772
  }
4708
4773
  var DEFAULT_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
4709
4774
  var TOKEN_REFRESH_RATIO = 0.8;
4775
+ function resolveCallbackKey(params) {
4776
+ const code = params.get("code");
4777
+ if (code) return code;
4778
+ const error = params.get("error");
4779
+ const state = params.get("state");
4780
+ return error && state ? `error:${error}:${state}` : null;
4781
+ }
4710
4782
  var FFIDContext = createContext(null);
4711
4783
  var FFIDClientContext = createContext(null);
4712
4784
  function FFIDProvider({
@@ -4886,19 +4958,26 @@ function FFIDProvider({
4886
4958
  },
4887
4959
  [organizations, client]
4888
4960
  );
4889
- const handledCodeRef = useRef(null);
4961
+ const handledCallbackRef = useRef(null);
4962
+ const callbackPendingRef = useRef(false);
4963
+ const authorizationDeniedRef = useRef(false);
4890
4964
  useEffect(() => {
4891
4965
  if (client.authMode !== "token") return;
4892
4966
  if (typeof window === "undefined") return;
4893
- const urlParams = new URLSearchParams(window.location.search);
4894
- const code = urlParams.get("code");
4895
- if (!code) return;
4896
- if (handledCodeRef.current === code) return;
4897
- handledCodeRef.current = code;
4898
- client.logger.debug("Authorization code detected, exchanging for tokens");
4967
+ const callbackKey = resolveCallbackKey(new URLSearchParams(window.location.search));
4968
+ if (!callbackKey) return;
4969
+ if (handledCallbackRef.current === callbackKey) return;
4970
+ handledCallbackRef.current = callbackKey;
4971
+ callbackPendingRef.current = true;
4972
+ client.logger.debug("OAuth callback detected, handling it");
4899
4973
  handleRedirectCallback(client, { cleanUrl: cleanCallbackUrl }).then((result) => {
4900
4974
  if (result.error) {
4901
- client.logger.error("Token exchange failed:", result.error);
4975
+ if (getFFIDAuthorizationError(result.error)) {
4976
+ client.logger.warn("FFID \u304C\u30ED\u30B0\u30A4\u30F3\u3092\u62D2\u5426\u3057\u307E\u3057\u305F:", result.error);
4977
+ authorizationDeniedRef.current = true;
4978
+ } else {
4979
+ client.logger.error("Token exchange failed:", result.error);
4980
+ }
4902
4981
  if (result.error.code === FFID_ERROR_CODES.STATE_MISMATCH_ERROR && client.tokenStore.getTokens()) {
4903
4982
  client.logger.debug(
4904
4983
  "Stale callback rejected but stored tokens present, restoring session via refresh"
@@ -4916,13 +4995,15 @@ function FFIDProvider({
4916
4995
  }).catch((err) => {
4917
4996
  client.logger.error("Token exchange error:", err);
4918
4997
  setIsLoading(false);
4998
+ }).finally(() => {
4999
+ callbackPendingRef.current = false;
4919
5000
  });
4920
5001
  }, [client]);
4921
5002
  useEffect(() => {
4922
5003
  if (client.authMode === "token") {
5004
+ if (callbackPendingRef.current || authorizationDeniedRef.current) return;
4923
5005
  if (typeof window !== "undefined") {
4924
- const urlParams = new URLSearchParams(window.location.search);
4925
- if (urlParams.has("code")) {
5006
+ if (resolveCallbackKey(new URLSearchParams(window.location.search))) {
4926
5007
  return;
4927
5008
  }
4928
5009
  }
@@ -6737,4 +6818,4 @@ function FFIDInquiryForm({
6737
6818
  );
6738
6819
  }
6739
6820
 
6740
- export { ACCESS_GRANTING_EFFECTIVE_STATUSES, AGENCY_INVITE_COOKIE_MAX_AGE_SEC, AGENCY_INVITE_COOKIE_NAME, AGENCY_INVITE_TOKEN_PARAM, AGENCY_INVITE_TOKEN_REDACTION, BLOCKING_EFFECTIVE_STATUSES, CATALOG_HASH_PATTERN, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDCatalogHashError, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_CATALOG_ENVIRONMENTS, FFID_CATALOG_PUBLICATION_STATUSES, FFID_COMPANY_SIZE_CODES, FFID_CREDITS_CONSUME_MAX_AMOUNT, FFID_CREDITS_CONSUME_MIN_AMOUNT, FFID_CREDITS_ERROR_CODES, FFID_CREDITS_FEATURE_PATTERN, FFID_CREDITS_HISTORY_DEFAULT_LIMIT, FFID_CREDITS_HISTORY_MAX_LIMIT, FFID_CREDITS_HISTORY_MIN_LIMIT, FFID_CREDITS_IDEMPOTENCY_KEY_PATTERN, FFID_CREDITS_LOW_THRESHOLD_PERCENT, FFID_CREDITS_METADATA_MAX_BYTES, FFID_CREDIT_GRANT_KINDS, FFID_CREDIT_HISTORY_TYPES, FFID_CREDIT_PACK_MAX_QUANTITY, FFID_CREDIT_PACK_MIN_QUANTITY, FFID_ERROR_CODES, FFID_INDUSTRY_CODES, FFID_INQUIRY_ACQUISITION_SOURCES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB, FFID_ORGANIZATION_PROFILE_ERROR_CODES, FFID_SUBSCRIPTION_ERROR_CODES, canonicalizeCatalogValue, captureAgencyInviteToken, cleanupStateStorage, clearAgencyInviteToken, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, normalizeRedirectUri, readAgencyInviteCookie, readAgencyInviteToken, redactAgencyInviteToken, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
6821
+ export { ACCESS_GRANTING_EFFECTIVE_STATUSES, AGENCY_INVITE_COOKIE_MAX_AGE_SEC, AGENCY_INVITE_COOKIE_NAME, AGENCY_INVITE_TOKEN_PARAM, AGENCY_INVITE_TOKEN_REDACTION, BLOCKING_EFFECTIVE_STATUSES, CATALOG_HASH_PATTERN, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDCatalogHashError, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_CATALOG_ENVIRONMENTS, FFID_CATALOG_PUBLICATION_STATUSES, FFID_COMPANY_SIZE_CODES, FFID_CREDITS_CONSUME_MAX_AMOUNT, FFID_CREDITS_CONSUME_MIN_AMOUNT, FFID_CREDITS_ERROR_CODES, FFID_CREDITS_FEATURE_PATTERN, FFID_CREDITS_HISTORY_DEFAULT_LIMIT, FFID_CREDITS_HISTORY_MAX_LIMIT, FFID_CREDITS_HISTORY_MIN_LIMIT, FFID_CREDITS_IDEMPOTENCY_KEY_PATTERN, FFID_CREDITS_LOW_THRESHOLD_PERCENT, FFID_CREDITS_METADATA_MAX_BYTES, FFID_CREDIT_GRANT_KINDS, FFID_CREDIT_HISTORY_TYPES, FFID_CREDIT_PACK_MAX_QUANTITY, FFID_CREDIT_PACK_MIN_QUANTITY, FFID_ERROR_CODES, FFID_INDUSTRY_CODES, FFID_INQUIRY_ACQUISITION_SOURCES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB, FFID_OAUTH_DENIAL_REASONS, FFID_ORGANIZATION_PROFILE_ERROR_CODES, FFID_SUBSCRIPTION_ERROR_CODES, canonicalizeCatalogValue, captureAgencyInviteToken, cleanupStateStorage, clearAgencyInviteToken, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, getFFIDAuthorizationError, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, isFFIDOAuthDenialReason, normalizeRedirectUri, readAgencyInviteCookie, readAgencyInviteToken, redactAgencyInviteToken, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
@@ -1376,7 +1376,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
1376
1376
  };
1377
1377
 
1378
1378
  // src/client/version-check.ts
1379
- var SDK_VERSION = "10.0.0";
1379
+ var SDK_VERSION = "10.1.0";
1380
1380
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1381
1381
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1382
1382
  function sdkHeaders() {
@@ -4611,6 +4611,50 @@ function createFFIDClient(config) {
4611
4611
  };
4612
4612
  }
4613
4613
 
4614
+ // src/client/authorization-error.ts
4615
+ var FFID_OAUTH_DENIAL_REASONS = [
4616
+ /** The user is not a member of the organization */
4617
+ "no_membership",
4618
+ /** The organization has no usable subscription for the service */
4619
+ "no_active_subscription",
4620
+ /** The organization has a subscription, but the user has no seat in it */
4621
+ "no_seat_assignment",
4622
+ /** The subscription has expired (canceled / past due beyond grace) */
4623
+ "subscription_expired",
4624
+ /** The flat plan's member limit is full, so no seat could be given */
4625
+ "member_limit_reached"
4626
+ ];
4627
+ function isFFIDOAuthDenialReason(value) {
4628
+ return typeof value === "string" && FFID_OAUTH_DENIAL_REASONS.includes(value);
4629
+ }
4630
+ var DEFAULT_AUTHORIZATION_ERROR_MESSAGE = "\u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F";
4631
+ function buildAuthorizationError(params) {
4632
+ const oauthError = params.get("error");
4633
+ if (!oauthError) return null;
4634
+ const rawReason = params.get("denial_reason");
4635
+ const errorDescription = params.get("error_description");
4636
+ const details = {
4637
+ source: "authorization",
4638
+ denialReason: isFFIDOAuthDenialReason(rawReason) ? rawReason : null,
4639
+ errorDescription
4640
+ };
4641
+ return {
4642
+ code: oauthError,
4643
+ message: errorDescription ?? DEFAULT_AUTHORIZATION_ERROR_MESSAGE,
4644
+ details: { ...details }
4645
+ };
4646
+ }
4647
+ function getFFIDAuthorizationError(error) {
4648
+ const details = error?.details;
4649
+ if (!error || !details || details.source !== "authorization") return null;
4650
+ const description = details.errorDescription;
4651
+ return {
4652
+ oauthError: error.code,
4653
+ denialReason: isFFIDOAuthDenialReason(details.denialReason) ? details.denialReason : null,
4654
+ errorDescription: typeof description === "string" ? description : null
4655
+ };
4656
+ }
4657
+
4614
4658
  // src/client/callback.ts
4615
4659
  var CALLBACK_ERROR_CODES = {
4616
4660
  /** Stored state missing or did not match the callback `state` (CSRF guard) */
@@ -4635,16 +4679,43 @@ function extractSearchParams(source) {
4635
4679
  return new URLSearchParams(query);
4636
4680
  }
4637
4681
  }
4638
- function cleanCallbackUrlParams(logger) {
4682
+ var CODE_CALLBACK_PARAMS = ["code", "state"];
4683
+ var ERROR_CALLBACK_CONSUMED_PARAMS = ["state"];
4684
+ function cleanCallbackUrlParams(logger, names) {
4639
4685
  try {
4640
4686
  const cleanUrl = new URL(window.location.href);
4641
- cleanUrl.searchParams.delete("code");
4642
- cleanUrl.searchParams.delete("state");
4687
+ for (const name of names) cleanUrl.searchParams.delete(name);
4643
4688
  window.history.replaceState({}, "", cleanUrl.toString());
4644
4689
  } catch (error) {
4645
4690
  logger.warn("handleRedirectCallback: URL \u306E\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
4646
4691
  }
4647
4692
  }
4693
+ function validateCallbackState(client, urlState) {
4694
+ const { logger } = client;
4695
+ const storedState = retrieveState(logger);
4696
+ if (storedState === null && urlState === null) return null;
4697
+ if (storedState !== null && storedState === urlState) return null;
4698
+ if (storedState === null && !isStateStorageAvailable()) {
4699
+ logger.error(
4700
+ "handleRedirectCallback: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 CSRF \u691C\u8A3C\u304C\u3067\u304D\u307E\u305B\u3093\uFF08iOS private mode \u7B49\uFF09"
4701
+ );
4702
+ return {
4703
+ error: client.createError(
4704
+ CALLBACK_ERROR_CODES.STATE_UNAVAILABLE,
4705
+ "OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30E2\u30FC\u30C9\u3084\u30B9\u30C8\u30EC\u30FC\u30B8\u8A2D\u5B9A\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044"
4706
+ )
4707
+ };
4708
+ }
4709
+ logger.error(
4710
+ "handleRedirectCallback: OAuth state mismatch or omitted (possible CSRF) \u2014 \u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002\u6D88\u8CBB\u6E08\u307F callback \u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u518D\u51E6\u7406\uFF08`cleanUrl: false` \u5229\u7528\u6642\u306E cleanup \u6F0F\u308C\u3084 reload \u7B49\uFF09\u3067\u3082\u767A\u751F\u3057\u307E\u3059"
4711
+ );
4712
+ return {
4713
+ error: client.createError(
4714
+ CALLBACK_ERROR_CODES.STATE_MISMATCH,
4715
+ "OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
4716
+ )
4717
+ };
4718
+ }
4648
4719
  async function handleRedirectCallback(client, options) {
4649
4720
  const { logger } = client;
4650
4721
  const hasWindow = typeof window !== "undefined";
@@ -4661,6 +4732,24 @@ async function handleRedirectCallback(client, options) {
4661
4732
  const params = extractSearchParams(source);
4662
4733
  const code = params.get("code");
4663
4734
  const urlState = params.get("state");
4735
+ const authorizationError = buildAuthorizationError(params);
4736
+ if (authorizationError && urlState !== null) {
4737
+ const stateError2 = validateCallbackState(client, urlState);
4738
+ if (stateError2) return stateError2;
4739
+ retrieveCodeVerifier(logger);
4740
+ logger.warn("handleRedirectCallback: \u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F:", {
4741
+ error: authorizationError.code,
4742
+ denialReason: params.get("denial_reason")
4743
+ });
4744
+ if (hasWindow) {
4745
+ if (options?.cleanUrl !== false) {
4746
+ cleanCallbackUrlParams(logger, ERROR_CALLBACK_CONSUMED_PARAMS);
4747
+ } else {
4748
+ logger.debug("handleRedirectCallback: cleanUrl=false \u306E\u305F\u3081 URL cleanup \u3092 consumer \u306B\u59D4\u8B72\u3057\u307E\u3057\u305F");
4749
+ }
4750
+ }
4751
+ return { error: authorizationError };
4752
+ }
4664
4753
  if (!code) {
4665
4754
  logger.warn("handleRedirectCallback: \u8A8D\u53EF\u30B3\u30FC\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
4666
4755
  return {
@@ -4670,37 +4759,13 @@ async function handleRedirectCallback(client, options) {
4670
4759
  )
4671
4760
  };
4672
4761
  }
4673
- const storedState = retrieveState(logger);
4674
- if (storedState !== null || urlState !== null) {
4675
- const stateMatches = storedState !== null && storedState === urlState;
4676
- if (!stateMatches) {
4677
- if (storedState === null && !isStateStorageAvailable()) {
4678
- logger.error(
4679
- "handleRedirectCallback: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 CSRF \u691C\u8A3C\u304C\u3067\u304D\u307E\u305B\u3093\uFF08iOS private mode \u7B49\uFF09"
4680
- );
4681
- return {
4682
- error: client.createError(
4683
- CALLBACK_ERROR_CODES.STATE_UNAVAILABLE,
4684
- "OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30E2\u30FC\u30C9\u3084\u30B9\u30C8\u30EC\u30FC\u30B8\u8A2D\u5B9A\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044"
4685
- )
4686
- };
4687
- }
4688
- logger.error(
4689
- "handleRedirectCallback: OAuth state mismatch or omitted (possible CSRF) \u2014 \u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002\u6D88\u8CBB\u6E08\u307F callback \u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u518D\u51E6\u7406\uFF08`cleanUrl: false` \u5229\u7528\u6642\u306E cleanup \u6F0F\u308C\u3084 reload \u7B49\uFF09\u3067\u3082\u767A\u751F\u3057\u307E\u3059"
4690
- );
4691
- return {
4692
- error: client.createError(
4693
- CALLBACK_ERROR_CODES.STATE_MISMATCH,
4694
- "OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
4695
- )
4696
- };
4697
- }
4698
- }
4762
+ const stateError = validateCallbackState(client, urlState);
4763
+ if (stateError) return stateError;
4699
4764
  const verifier = retrieveCodeVerifier(logger);
4700
4765
  const result = await client.exchangeCodeForTokens(code, verifier ?? void 0);
4701
4766
  if (!result.error && hasWindow) {
4702
4767
  if (options?.cleanUrl !== false) {
4703
- cleanCallbackUrlParams(logger);
4768
+ cleanCallbackUrlParams(logger, CODE_CALLBACK_PARAMS);
4704
4769
  } else {
4705
4770
  logger.debug("handleRedirectCallback: cleanUrl=false \u306E\u305F\u3081 URL cleanup \u3092 consumer \u306B\u59D4\u8B72\u3057\u307E\u3057\u305F");
4706
4771
  }
@@ -4709,6 +4774,13 @@ async function handleRedirectCallback(client, options) {
4709
4774
  }
4710
4775
  var DEFAULT_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
4711
4776
  var TOKEN_REFRESH_RATIO = 0.8;
4777
+ function resolveCallbackKey(params) {
4778
+ const code = params.get("code");
4779
+ if (code) return code;
4780
+ const error = params.get("error");
4781
+ const state = params.get("state");
4782
+ return error && state ? `error:${error}:${state}` : null;
4783
+ }
4712
4784
  var FFIDContext = react.createContext(null);
4713
4785
  var FFIDClientContext = react.createContext(null);
4714
4786
  function FFIDProvider({
@@ -4888,19 +4960,26 @@ function FFIDProvider({
4888
4960
  },
4889
4961
  [organizations, client]
4890
4962
  );
4891
- const handledCodeRef = react.useRef(null);
4963
+ const handledCallbackRef = react.useRef(null);
4964
+ const callbackPendingRef = react.useRef(false);
4965
+ const authorizationDeniedRef = react.useRef(false);
4892
4966
  react.useEffect(() => {
4893
4967
  if (client.authMode !== "token") return;
4894
4968
  if (typeof window === "undefined") return;
4895
- const urlParams = new URLSearchParams(window.location.search);
4896
- const code = urlParams.get("code");
4897
- if (!code) return;
4898
- if (handledCodeRef.current === code) return;
4899
- handledCodeRef.current = code;
4900
- client.logger.debug("Authorization code detected, exchanging for tokens");
4969
+ const callbackKey = resolveCallbackKey(new URLSearchParams(window.location.search));
4970
+ if (!callbackKey) return;
4971
+ if (handledCallbackRef.current === callbackKey) return;
4972
+ handledCallbackRef.current = callbackKey;
4973
+ callbackPendingRef.current = true;
4974
+ client.logger.debug("OAuth callback detected, handling it");
4901
4975
  handleRedirectCallback(client, { cleanUrl: cleanCallbackUrl }).then((result) => {
4902
4976
  if (result.error) {
4903
- client.logger.error("Token exchange failed:", result.error);
4977
+ if (getFFIDAuthorizationError(result.error)) {
4978
+ client.logger.warn("FFID \u304C\u30ED\u30B0\u30A4\u30F3\u3092\u62D2\u5426\u3057\u307E\u3057\u305F:", result.error);
4979
+ authorizationDeniedRef.current = true;
4980
+ } else {
4981
+ client.logger.error("Token exchange failed:", result.error);
4982
+ }
4904
4983
  if (result.error.code === FFID_ERROR_CODES.STATE_MISMATCH_ERROR && client.tokenStore.getTokens()) {
4905
4984
  client.logger.debug(
4906
4985
  "Stale callback rejected but stored tokens present, restoring session via refresh"
@@ -4918,13 +4997,15 @@ function FFIDProvider({
4918
4997
  }).catch((err) => {
4919
4998
  client.logger.error("Token exchange error:", err);
4920
4999
  setIsLoading(false);
5000
+ }).finally(() => {
5001
+ callbackPendingRef.current = false;
4921
5002
  });
4922
5003
  }, [client]);
4923
5004
  react.useEffect(() => {
4924
5005
  if (client.authMode === "token") {
5006
+ if (callbackPendingRef.current || authorizationDeniedRef.current) return;
4925
5007
  if (typeof window !== "undefined") {
4926
- const urlParams = new URLSearchParams(window.location.search);
4927
- if (urlParams.has("code")) {
5008
+ if (resolveCallbackKey(new URLSearchParams(window.location.search))) {
4928
5009
  return;
4929
5010
  }
4930
5011
  }
@@ -6785,6 +6866,7 @@ exports.FFID_INQUIRY_CATEGORIES = FFID_INQUIRY_CATEGORIES;
6785
6866
  exports.FFID_INQUIRY_CATEGORIES_SITE_2026 = FFID_INQUIRY_CATEGORIES_SITE_2026;
6786
6867
  exports.FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES;
6787
6868
  exports.FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB;
6869
+ exports.FFID_OAUTH_DENIAL_REASONS = FFID_OAUTH_DENIAL_REASONS;
6788
6870
  exports.FFID_ORGANIZATION_PROFILE_ERROR_CODES = FFID_ORGANIZATION_PROFILE_ERROR_CODES;
6789
6871
  exports.FFID_SUBSCRIPTION_ERROR_CODES = FFID_SUBSCRIPTION_ERROR_CODES;
6790
6872
  exports.canonicalizeCatalogValue = canonicalizeCatalogValue;
@@ -6803,12 +6885,14 @@ exports.createFFIDClient = createFFIDClient;
6803
6885
  exports.createTokenStore = createTokenStore;
6804
6886
  exports.generateCodeChallenge = generateCodeChallenge;
6805
6887
  exports.generateCodeVerifier = generateCodeVerifier;
6888
+ exports.getFFIDAuthorizationError = getFFIDAuthorizationError;
6806
6889
  exports.handleRedirectCallback = handleRedirectCallback;
6807
6890
  exports.hasAccessFromUserinfo = hasAccessFromUserinfo;
6808
6891
  exports.hashCanonicalJson = hashCanonicalJson;
6809
6892
  exports.isBlockedFromUserinfo = isBlockedFromUserinfo;
6810
6893
  exports.isFFIDInquiryAcquisitionSource = isFFIDInquiryAcquisitionSource;
6811
6894
  exports.isFFIDInquiryCategorySite2026 = isFFIDInquiryCategorySite2026;
6895
+ exports.isFFIDOAuthDenialReason = isFFIDOAuthDenialReason;
6812
6896
  exports.normalizeRedirectUri = normalizeRedirectUri;
6813
6897
  exports.readAgencyInviteCookie = readAgencyInviteCookie;
6814
6898
  exports.readAgencyInviteToken = readAgencyInviteToken;
@@ -1,34 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var chunk2LU2F3F2_cjs = require('../chunk-2LU2F3F2.cjs');
3
+ var chunkVHOIA25Y_cjs = require('../chunk-VHOIA25Y.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunk2LU2F3F2_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkVHOIA25Y_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunk2LU2F3F2_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkVHOIA25Y_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDInquiryForm", {
16
16
  enumerable: true,
17
- get: function () { return chunk2LU2F3F2_cjs.FFIDInquiryForm; }
17
+ get: function () { return chunkVHOIA25Y_cjs.FFIDInquiryForm; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDLoginButton", {
20
20
  enumerable: true,
21
- get: function () { return chunk2LU2F3F2_cjs.FFIDLoginButton; }
21
+ get: function () { return chunkVHOIA25Y_cjs.FFIDLoginButton; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
24
24
  enumerable: true,
25
- get: function () { return chunk2LU2F3F2_cjs.FFIDOrganizationSwitcher; }
25
+ get: function () { return chunkVHOIA25Y_cjs.FFIDOrganizationSwitcher; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
28
28
  enumerable: true,
29
- get: function () { return chunk2LU2F3F2_cjs.FFIDSubscriptionBadge; }
29
+ get: function () { return chunkVHOIA25Y_cjs.FFIDSubscriptionBadge; }
30
30
  });
31
31
  Object.defineProperty(exports, "FFIDUserMenu", {
32
32
  enumerable: true,
33
- get: function () { return chunk2LU2F3F2_cjs.FFIDUserMenu; }
33
+ get: function () { return chunkVHOIA25Y_cjs.FFIDUserMenu; }
34
34
  });
@@ -1,3 +1,3 @@
1
- export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-KjewcNn1.cjs';
1
+ export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-CWGoIgYL.cjs';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1,3 +1,3 @@
1
- export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-KjewcNn1.js';
1
+ export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-CWGoIgYL.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-OXW6QSTO.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-ITSQIAO5.js';
@@ -1014,7 +1014,8 @@ type FFIDServiceAccessFailPolicy = 'failClosed';
1014
1014
  *
1015
1015
  * `member_limit_reached` (10.0.0) is FFID's denial reason when a flat plan's member
1016
1016
  * limit is full and the user has no seat. It reaches you through OAuth
1017
- * (`denial_reason` on authorize / userinfo / introspect); `checkServiceAccess()`
1017
+ * (`denial_reason` on the authorize redirect / userinfo 403; see
1018
+ * `FFIDOAuthDenialReason` for that vocabulary); `checkServiceAccess()`
1018
1019
  * derives its decision from `effectiveStatus` and never returns it, because a full
1019
1020
  * member limit does not change `hasAccess` (CREDITS_API §1-5). It is in this union so
1020
1021
  * one exhaustive `switch` over denial reasons covers both paths.
@@ -2886,4 +2887,4 @@ declare function createFFIDClient(config: FFIDConfig): {
2886
2887
  /** Type of the FFID client */
2887
2888
  type FFIDClient = ReturnType<typeof createFFIDClient>;
2888
2889
 
2889
- export { type FFIDProvisionedOrganization as $, type FFIDOrganization as A, type FFIDOrganizationLogoUploadResponse as B, type FFIDOrganizationMember as C, type FFIDOrganizationProfile as D, type FFIDOrganizationProfileErrorCode as E, type FFIDLogger as F, type FFIDOrganizationProfileResponse as G, type FFIDOtpSendResponse as H, type FFIDOtpVerifyResponse as I, type FFIDPasswordResetConfirmResponse as J, type FFIDPasswordResetResponse as K, type FFIDPasswordResetVerifyResponse as L, type FFIDProfileCallOptions as M, type FFIDProvisionMemberPlan as N, type FFIDProvisionMemberPlanStatus as O, type FFIDProvisionMemberResult as P, type FFIDProvisionMemberStatus as Q, type FFIDProvisionOrganizationDryRun as R, type FFIDProvisionOrganizationMemberInput as S, type FFIDProvisionOrganizationOutcome as T, type FFIDProvisionOrganizationParams as U, type FFIDProvisionOrganizationResponse as V, type FFIDProvisionUserDryRun as W, type FFIDProvisionUserOutcome as X, type FFIDProvisionUserParams as Y, type FFIDProvisionUserProfileInput as Z, type FFIDProvisionUserResponse as _, type FFIDError as a, type FFIDProvisionedUser as a0, type FFIDPublishedPlan as a1, type FFIDRemoveMemberResponse as a2, type FFIDResetSessionResponse as a3, type FFIDSubscription as a4, type FFIDUpdateMemberRoleResponse as a5, type FFIDUpdateUserProfileRequest as a6, type FFIDUploadOrganizationLogoParams as a7, type FFIDUpsertOrganizationProfileParams as a8, type FFIDUpsertOrganizationProfileRequest as a9, type FFIDUser as aa, type FFIDUserProfile as ab, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES as ac, FFID_CATALOG_ENVIRONMENTS as ad, FFID_CATALOG_PUBLICATION_STATUSES as ae, FFID_COMPANY_SIZE_CODES as af, FFID_INDUSTRY_CODES as ag, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES as ah, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB as ai, FFID_ORGANIZATION_PROFILE_ERROR_CODES as aj, type TokenData as ak, type TokenStore as al, createFFIDClient as am, createTokenStore as an, type FFIDCacheAdapter as b, type FFIDVerifyAccessTokenOptions as c, type FFIDApiResponse as d, type FFIDOAuthUserInfo as e, type FFIDCatalogEnvironment as f, type FFIDBillingInterval as g, type FFIDTaxBehavior as h, type FFIDPublishedCatalog as i, type FFIDAddMemberParams as j, type FFIDAddMemberRequest as k, type FFIDAddMemberResponse as l, type FFIDAllowedLogoMimeType as m, type FFIDAssignableMemberRole as n, type FFIDCacheConfig as o, type FFIDCatalogPublication as p, type FFIDCatalogPublicationStatus as q, type FFIDClient as r, type FFIDCompanySizeCode as s, type FFIDConfig as t, type FFIDIndustryCode as u, type FFIDListMembersResponse as v, type FFIDListingConsentInput as w, type FFIDLogoWallEntry as x, type FFIDLogoWallResponse as y, type FFIDMemberRole as z };
2890
+ export { type FFIDProvisionedOrganization as $, type FFIDOrganization as A, type FFIDOrganizationLogoUploadResponse as B, type FFIDOrganizationMember as C, type FFIDOrganizationProfile as D, type FFIDOrganizationProfileErrorCode as E, type FFIDError as F, type FFIDOrganizationProfileResponse as G, type FFIDOtpSendResponse as H, type FFIDOtpVerifyResponse as I, type FFIDPasswordResetConfirmResponse as J, type FFIDPasswordResetResponse as K, type FFIDPasswordResetVerifyResponse as L, type FFIDProfileCallOptions as M, type FFIDProvisionMemberPlan as N, type FFIDProvisionMemberPlanStatus as O, type FFIDProvisionMemberResult as P, type FFIDProvisionMemberStatus as Q, type FFIDProvisionOrganizationDryRun as R, type FFIDProvisionOrganizationMemberInput as S, type FFIDProvisionOrganizationOutcome as T, type FFIDProvisionOrganizationParams as U, type FFIDProvisionOrganizationResponse as V, type FFIDProvisionUserDryRun as W, type FFIDProvisionUserOutcome as X, type FFIDProvisionUserParams as Y, type FFIDProvisionUserProfileInput as Z, type FFIDProvisionUserResponse as _, type FFIDLogger as a, type FFIDProvisionedUser as a0, type FFIDPublishedPlan as a1, type FFIDRemoveMemberResponse as a2, type FFIDResetSessionResponse as a3, type FFIDSubscription as a4, type FFIDUpdateMemberRoleResponse as a5, type FFIDUpdateUserProfileRequest as a6, type FFIDUploadOrganizationLogoParams as a7, type FFIDUpsertOrganizationProfileParams as a8, type FFIDUpsertOrganizationProfileRequest as a9, type FFIDUser as aa, type FFIDUserProfile as ab, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES as ac, FFID_CATALOG_ENVIRONMENTS as ad, FFID_CATALOG_PUBLICATION_STATUSES as ae, FFID_COMPANY_SIZE_CODES as af, FFID_INDUSTRY_CODES as ag, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES as ah, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB as ai, FFID_ORGANIZATION_PROFILE_ERROR_CODES as aj, type TokenData as ak, type TokenStore as al, createFFIDClient as am, createTokenStore as an, type FFIDCacheAdapter as b, type FFIDVerifyAccessTokenOptions as c, type FFIDApiResponse as d, type FFIDOAuthUserInfo as e, type FFIDCatalogEnvironment as f, type FFIDBillingInterval as g, type FFIDTaxBehavior as h, type FFIDPublishedCatalog as i, type FFIDAddMemberParams as j, type FFIDAddMemberRequest as k, type FFIDAddMemberResponse as l, type FFIDAllowedLogoMimeType as m, type FFIDAssignableMemberRole as n, type FFIDCacheConfig as o, type FFIDCatalogPublication as p, type FFIDCatalogPublicationStatus as q, type FFIDClient as r, type FFIDCompanySizeCode as s, type FFIDConfig as t, type FFIDIndustryCode as u, type FFIDListMembersResponse as v, type FFIDListingConsentInput as w, type FFIDLogoWallEntry as x, type FFIDLogoWallResponse as y, type FFIDMemberRole as z };
@@ -1014,7 +1014,8 @@ type FFIDServiceAccessFailPolicy = 'failClosed';
1014
1014
  *
1015
1015
  * `member_limit_reached` (10.0.0) is FFID's denial reason when a flat plan's member
1016
1016
  * limit is full and the user has no seat. It reaches you through OAuth
1017
- * (`denial_reason` on authorize / userinfo / introspect); `checkServiceAccess()`
1017
+ * (`denial_reason` on the authorize redirect / userinfo 403; see
1018
+ * `FFIDOAuthDenialReason` for that vocabulary); `checkServiceAccess()`
1018
1019
  * derives its decision from `effectiveStatus` and never returns it, because a full
1019
1020
  * member limit does not change `hasAccess` (CREDITS_API §1-5). It is in this union so
1020
1021
  * one exhaustive `switch` over denial reasons covers both paths.
@@ -2886,4 +2887,4 @@ declare function createFFIDClient(config: FFIDConfig): {
2886
2887
  /** Type of the FFID client */
2887
2888
  type FFIDClient = ReturnType<typeof createFFIDClient>;
2888
2889
 
2889
- export { type FFIDProvisionedOrganization as $, type FFIDOrganization as A, type FFIDOrganizationLogoUploadResponse as B, type FFIDOrganizationMember as C, type FFIDOrganizationProfile as D, type FFIDOrganizationProfileErrorCode as E, type FFIDLogger as F, type FFIDOrganizationProfileResponse as G, type FFIDOtpSendResponse as H, type FFIDOtpVerifyResponse as I, type FFIDPasswordResetConfirmResponse as J, type FFIDPasswordResetResponse as K, type FFIDPasswordResetVerifyResponse as L, type FFIDProfileCallOptions as M, type FFIDProvisionMemberPlan as N, type FFIDProvisionMemberPlanStatus as O, type FFIDProvisionMemberResult as P, type FFIDProvisionMemberStatus as Q, type FFIDProvisionOrganizationDryRun as R, type FFIDProvisionOrganizationMemberInput as S, type FFIDProvisionOrganizationOutcome as T, type FFIDProvisionOrganizationParams as U, type FFIDProvisionOrganizationResponse as V, type FFIDProvisionUserDryRun as W, type FFIDProvisionUserOutcome as X, type FFIDProvisionUserParams as Y, type FFIDProvisionUserProfileInput as Z, type FFIDProvisionUserResponse as _, type FFIDError as a, type FFIDProvisionedUser as a0, type FFIDPublishedPlan as a1, type FFIDRemoveMemberResponse as a2, type FFIDResetSessionResponse as a3, type FFIDSubscription as a4, type FFIDUpdateMemberRoleResponse as a5, type FFIDUpdateUserProfileRequest as a6, type FFIDUploadOrganizationLogoParams as a7, type FFIDUpsertOrganizationProfileParams as a8, type FFIDUpsertOrganizationProfileRequest as a9, type FFIDUser as aa, type FFIDUserProfile as ab, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES as ac, FFID_CATALOG_ENVIRONMENTS as ad, FFID_CATALOG_PUBLICATION_STATUSES as ae, FFID_COMPANY_SIZE_CODES as af, FFID_INDUSTRY_CODES as ag, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES as ah, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB as ai, FFID_ORGANIZATION_PROFILE_ERROR_CODES as aj, type TokenData as ak, type TokenStore as al, createFFIDClient as am, createTokenStore as an, type FFIDCacheAdapter as b, type FFIDVerifyAccessTokenOptions as c, type FFIDApiResponse as d, type FFIDOAuthUserInfo as e, type FFIDCatalogEnvironment as f, type FFIDBillingInterval as g, type FFIDTaxBehavior as h, type FFIDPublishedCatalog as i, type FFIDAddMemberParams as j, type FFIDAddMemberRequest as k, type FFIDAddMemberResponse as l, type FFIDAllowedLogoMimeType as m, type FFIDAssignableMemberRole as n, type FFIDCacheConfig as o, type FFIDCatalogPublication as p, type FFIDCatalogPublicationStatus as q, type FFIDClient as r, type FFIDCompanySizeCode as s, type FFIDConfig as t, type FFIDIndustryCode as u, type FFIDListMembersResponse as v, type FFIDListingConsentInput as w, type FFIDLogoWallEntry as x, type FFIDLogoWallResponse as y, type FFIDMemberRole as z };
2890
+ export { type FFIDProvisionedOrganization as $, type FFIDOrganization as A, type FFIDOrganizationLogoUploadResponse as B, type FFIDOrganizationMember as C, type FFIDOrganizationProfile as D, type FFIDOrganizationProfileErrorCode as E, type FFIDError as F, type FFIDOrganizationProfileResponse as G, type FFIDOtpSendResponse as H, type FFIDOtpVerifyResponse as I, type FFIDPasswordResetConfirmResponse as J, type FFIDPasswordResetResponse as K, type FFIDPasswordResetVerifyResponse as L, type FFIDProfileCallOptions as M, type FFIDProvisionMemberPlan as N, type FFIDProvisionMemberPlanStatus as O, type FFIDProvisionMemberResult as P, type FFIDProvisionMemberStatus as Q, type FFIDProvisionOrganizationDryRun as R, type FFIDProvisionOrganizationMemberInput as S, type FFIDProvisionOrganizationOutcome as T, type FFIDProvisionOrganizationParams as U, type FFIDProvisionOrganizationResponse as V, type FFIDProvisionUserDryRun as W, type FFIDProvisionUserOutcome as X, type FFIDProvisionUserParams as Y, type FFIDProvisionUserProfileInput as Z, type FFIDProvisionUserResponse as _, type FFIDLogger as a, type FFIDProvisionedUser as a0, type FFIDPublishedPlan as a1, type FFIDRemoveMemberResponse as a2, type FFIDResetSessionResponse as a3, type FFIDSubscription as a4, type FFIDUpdateMemberRoleResponse as a5, type FFIDUpdateUserProfileRequest as a6, type FFIDUploadOrganizationLogoParams as a7, type FFIDUpsertOrganizationProfileParams as a8, type FFIDUpsertOrganizationProfileRequest as a9, type FFIDUser as aa, type FFIDUserProfile as ab, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES as ac, FFID_CATALOG_ENVIRONMENTS as ad, FFID_CATALOG_PUBLICATION_STATUSES as ae, FFID_COMPANY_SIZE_CODES as af, FFID_INDUSTRY_CODES as ag, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES as ah, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB as ai, FFID_ORGANIZATION_PROFILE_ERROR_CODES as aj, type TokenData as ak, type TokenStore as al, createFFIDClient as am, createTokenStore as an, type FFIDCacheAdapter as b, type FFIDVerifyAccessTokenOptions as c, type FFIDApiResponse as d, type FFIDOAuthUserInfo as e, type FFIDCatalogEnvironment as f, type FFIDBillingInterval as g, type FFIDTaxBehavior as h, type FFIDPublishedCatalog as i, type FFIDAddMemberParams as j, type FFIDAddMemberRequest as k, type FFIDAddMemberResponse as l, type FFIDAllowedLogoMimeType as m, type FFIDAssignableMemberRole as n, type FFIDCacheConfig as o, type FFIDCatalogPublication as p, type FFIDCatalogPublicationStatus as q, type FFIDClient as r, type FFIDCompanySizeCode as s, type FFIDConfig as t, type FFIDIndustryCode as u, type FFIDListMembersResponse as v, type FFIDListingConsentInput as w, type FFIDLogoWallEntry as x, type FFIDLogoWallResponse as y, type FFIDMemberRole as z };
@@ -962,7 +962,8 @@ type FFIDServiceAccessFailPolicy = 'failClosed';
962
962
  *
963
963
  * `member_limit_reached` (10.0.0) is FFID's denial reason when a flat plan's member
964
964
  * limit is full and the user has no seat. It reaches you through OAuth
965
- * (`denial_reason` on authorize / userinfo / introspect); `checkServiceAccess()`
965
+ * (`denial_reason` on the authorize redirect / userinfo 403; see
966
+ * `FFIDOAuthDenialReason` for that vocabulary); `checkServiceAccess()`
966
967
  * derives its decision from `effectiveStatus` and never returns it, because a full
967
968
  * member limit does not change `hasAccess` (CREDITS_API §1-5). It is in this union so
968
969
  * one exhaustive `switch` over denial reasons covers both paths.