@feelflow/ffid-sdk 5.9.0 → 5.12.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.
Files changed (33) hide show
  1. package/dist/{FFIDCookieLink-CE01gYc4.d.cts → FFIDCookieLink-D1WwE_ZO.d.cts} +5 -0
  2. package/dist/{FFIDCookieLink-CE01gYc4.d.ts → FFIDCookieLink-D1WwE_ZO.d.ts} +5 -0
  3. package/dist/{chunk-A6MOPB7D.cjs → chunk-AOJDV3UO.cjs} +88 -3
  4. package/dist/{chunk-KENJXMSG.js → chunk-KB2JG64Z.js} +88 -4
  5. package/dist/{chunk-KJ7FUNA6.js → chunk-M4N2PUX6.js} +64 -32
  6. package/dist/{chunk-Q5SZVLNB.cjs → chunk-R5WSZMUL.cjs} +64 -32
  7. package/dist/components/index.cjs +8 -8
  8. package/dist/components/index.d.cts +1 -1
  9. package/dist/components/index.d.ts +1 -1
  10. package/dist/components/index.js +1 -1
  11. package/dist/consent/index.cjs +64 -64
  12. package/dist/consent/index.d.cts +2 -2
  13. package/dist/consent/index.d.ts +2 -2
  14. package/dist/consent/index.js +1 -1
  15. package/dist/{ffid-client-gboJROw0.d.ts → ffid-client-5IprSUVR.d.ts} +169 -42
  16. package/dist/{ffid-client-DRjzfAaS.d.cts → ffid-client-Dx4oc4Cw.d.cts} +169 -42
  17. package/dist/{index-DSvX4q8E.d.cts → index-DqsWKU16.d.cts} +11 -43
  18. package/dist/{index-DSvX4q8E.d.ts → index-DqsWKU16.d.ts} +11 -43
  19. package/dist/index.cjs +61 -57
  20. package/dist/index.d.cts +172 -4
  21. package/dist/index.d.ts +172 -4
  22. package/dist/index.js +3 -3
  23. package/dist/server/index.cjs +78 -3
  24. package/dist/server/index.d.cts +3 -3
  25. package/dist/server/index.d.ts +3 -3
  26. package/dist/server/index.js +78 -3
  27. package/dist/server/test/index.d.cts +2 -2
  28. package/dist/server/test/index.d.ts +2 -2
  29. package/dist/{types-BYdtyO_2.d.cts → types-BeVl-z12.d.cts} +10 -1
  30. package/dist/{types-BYdtyO_2.d.ts → types-BeVl-z12.d.ts} +10 -1
  31. package/dist/webhooks/index.d.cts +1 -1
  32. package/dist/webhooks/index.d.ts +1 -1
  33. package/package.json +1 -1
@@ -898,6 +898,11 @@ declare function useFFIDConsentPreferences(): UseFFIDConsentPreferencesReturn;
898
898
  * was removed in v5.2.1 (#3289) because it overrode `setIsBannerOpen(false)`
899
899
  * for fresh visitors and silently kept the banner mounted on "あとで" click.
900
900
  *
901
+ * Consent submissions close the banner OPTIMISTICALLY (#3614): the provider
902
+ * flips `isBannerOpen=false` before the POST settles, so the click feels
903
+ * instant. On a failed POST the provider re-opens the banner with `error`
904
+ * set, which this component renders as the retry surface.
905
+ *
901
906
  * Four buttons (spec §6.2):
902
907
  * 1. "すべて同意" (Accept all)
903
908
  * 2. "同意しない" (Necessary only — `necessary=true` is enforced by ePrivacy
@@ -898,6 +898,11 @@ declare function useFFIDConsentPreferences(): UseFFIDConsentPreferencesReturn;
898
898
  * was removed in v5.2.1 (#3289) because it overrode `setIsBannerOpen(false)`
899
899
  * for fresh visitors and silently kept the banner mounted on "あとで" click.
900
900
  *
901
+ * Consent submissions close the banner OPTIMISTICALLY (#3614): the provider
902
+ * flips `isBannerOpen=false` before the POST settles, so the click feels
903
+ * instant. On a failed POST the provider re-opens the banner with `error`
904
+ * set, which this component renders as the retry surface.
905
+ *
901
906
  * Four buttons (spec §6.2):
902
907
  * 1. "すべて同意" (Accept all)
903
908
  * 2. "同意しない" (Necessary only — `necessary=true` is enforced by ePrivacy
@@ -436,6 +436,8 @@ function createVerifyAccessToken(deps) {
436
436
  // src/client/billing-methods.ts
437
437
  var BILLING_CHECKOUT_ENDPOINT = "/api/v1/billing/checkout";
438
438
  var BILLING_PORTAL_ENDPOINT = "/api/v1/billing/portal";
439
+ var EXT_INVOICES_ENDPOINT = "/api/v1/billing/ext/invoices";
440
+ var EXT_RETRY_PAYMENT_ENDPOINT = "/api/v1/billing/ext/retry-payment";
439
441
  function createBillingMethods(deps) {
440
442
  const { fetchWithAuth, createError } = deps;
441
443
  async function createCheckoutSession(params) {
@@ -477,7 +479,31 @@ function createBillingMethods(deps) {
477
479
  `${BILLING_PORTAL_ENDPOINT}?${query.toString()}`
478
480
  );
479
481
  }
480
- return { createCheckoutSession, createPortalSession };
482
+ async function listInvoices(params) {
483
+ if (!params.organizationId) {
484
+ return { error: createError("VALIDATION_ERROR", "organizationId \u306F\u5FC5\u9808\u3067\u3059") };
485
+ }
486
+ const query = new URLSearchParams({ organizationId: params.organizationId });
487
+ return fetchWithAuth(`${EXT_INVOICES_ENDPOINT}?${query.toString()}`);
488
+ }
489
+ async function getInvoice(params) {
490
+ if (!params.invoiceId) {
491
+ return { error: createError("VALIDATION_ERROR", "invoiceId \u306F\u5FC5\u9808\u3067\u3059") };
492
+ }
493
+ return fetchWithAuth(
494
+ `${EXT_INVOICES_ENDPOINT}/${encodeURIComponent(params.invoiceId)}`
495
+ );
496
+ }
497
+ async function retryPayment(params) {
498
+ if (!params.organizationId) {
499
+ return { error: createError("VALIDATION_ERROR", "organizationId \u306F\u5FC5\u9808\u3067\u3059") };
500
+ }
501
+ return fetchWithAuth(EXT_RETRY_PAYMENT_ENDPOINT, {
502
+ method: "POST",
503
+ body: JSON.stringify({ organizationId: params.organizationId })
504
+ });
505
+ }
506
+ return { createCheckoutSession, createPortalSession, listInvoices, getInvoice, retryPayment };
481
507
  }
482
508
 
483
509
  // src/client/subscription-methods.ts
@@ -819,6 +845,45 @@ function createMembersMethods(deps) {
819
845
  return { listMembers, addMember, updateMemberRole, removeMember };
820
846
  }
821
847
 
848
+ // src/client/seat-methods.ts
849
+ function seatsEndpoint(subscriptionId) {
850
+ return `/api/v1/subscriptions/ext/${encodeURIComponent(subscriptionId)}/seats/assignments`;
851
+ }
852
+ function createSeatMethods(deps) {
853
+ const { fetchWithAuth, createError } = deps;
854
+ async function listSeatAssignments(params) {
855
+ if (!params.subscriptionId) {
856
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
857
+ }
858
+ return fetchWithAuth(seatsEndpoint(params.subscriptionId));
859
+ }
860
+ async function assignSeats(params) {
861
+ if (!params.subscriptionId) {
862
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
863
+ }
864
+ if (!Array.isArray(params.userIds) || params.userIds.length === 0) {
865
+ return { error: createError("VALIDATION_ERROR", "userIds \u306F 1 \u4EF6\u4EE5\u4E0A\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044") };
866
+ }
867
+ return fetchWithAuth(seatsEndpoint(params.subscriptionId), {
868
+ method: "POST",
869
+ body: JSON.stringify({ userIds: params.userIds })
870
+ });
871
+ }
872
+ async function unassignSeat(params) {
873
+ if (!params.subscriptionId) {
874
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
875
+ }
876
+ if (!params.userId) {
877
+ return { error: createError("VALIDATION_ERROR", "userId \u306F\u5FC5\u9808\u3067\u3059") };
878
+ }
879
+ return fetchWithAuth(
880
+ `${seatsEndpoint(params.subscriptionId)}/${encodeURIComponent(params.userId)}`,
881
+ { method: "DELETE" }
882
+ );
883
+ }
884
+ return { listSeatAssignments, assignSeats, unassignSeat };
885
+ }
886
+
822
887
  // src/client/profile-methods.ts
823
888
  var EXT_PROFILE_ENDPOINT = "/api/v1/users/ext/me";
824
889
  function resolveAuthOverride(options, createError) {
@@ -869,7 +934,7 @@ function createProfileMethods(deps) {
869
934
  }
870
935
 
871
936
  // src/client/version-check.ts
872
- var SDK_VERSION = "5.9.0";
937
+ var SDK_VERSION = "5.12.0";
873
938
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
874
939
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
875
940
  function sdkHeaders() {
@@ -2259,6 +2324,15 @@ function createInquiryMethods(deps) {
2259
2324
  }
2260
2325
 
2261
2326
  // src/subscriptions/types.ts
2327
+ var EFFECTIVE_SUBSCRIPTION_STATUSES = [
2328
+ "active",
2329
+ "active_canceling",
2330
+ "past_due_grace",
2331
+ "blocked",
2332
+ "canceled",
2333
+ "trial_expired",
2334
+ "expired"
2335
+ ];
2262
2336
  var PAST_DUE_GRACE_PERIOD_DAYS = 7;
2263
2337
  var HOURS_PER_DAY = 24;
2264
2338
  var MINUTES_PER_HOUR = 60;
@@ -2719,7 +2793,11 @@ function createFFIDClient(config) {
2719
2793
  }
2720
2794
  return result;
2721
2795
  }
2722
- const { createCheckoutSession, createPortalSession } = createBillingMethods({
2796
+ const { createCheckoutSession, createPortalSession, listInvoices, getInvoice, retryPayment } = createBillingMethods({
2797
+ fetchWithAuth,
2798
+ createError
2799
+ });
2800
+ const { listSeatAssignments, assignSeats, unassignSeat } = createSeatMethods({
2723
2801
  fetchWithAuth,
2724
2802
  createError
2725
2803
  });
@@ -2828,6 +2906,12 @@ function createFFIDClient(config) {
2828
2906
  getAnalyticsConfig,
2829
2907
  createCheckoutSession,
2830
2908
  createPortalSession,
2909
+ listInvoices,
2910
+ getInvoice,
2911
+ retryPayment,
2912
+ listSeatAssignments,
2913
+ assignSeats,
2914
+ unassignSeat,
2831
2915
  listPlans,
2832
2916
  getSubscription,
2833
2917
  subscribe,
@@ -4860,6 +4944,7 @@ exports.ACCESS_GRANTING_EFFECTIVE_STATUSES = ACCESS_GRANTING_EFFECTIVE_STATUSES;
4860
4944
  exports.BLOCKING_EFFECTIVE_STATUSES = BLOCKING_EFFECTIVE_STATUSES;
4861
4945
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
4862
4946
  exports.DEFAULT_OAUTH_SCOPES = DEFAULT_OAUTH_SCOPES;
4947
+ exports.EFFECTIVE_SUBSCRIPTION_STATUSES = EFFECTIVE_SUBSCRIPTION_STATUSES;
4863
4948
  exports.FFIDAnnouncementBadge = FFIDAnnouncementBadge;
4864
4949
  exports.FFIDAnnouncementList = FFIDAnnouncementList;
4865
4950
  exports.FFIDInquiryForm = FFIDInquiryForm;
@@ -434,6 +434,8 @@ function createVerifyAccessToken(deps) {
434
434
  // src/client/billing-methods.ts
435
435
  var BILLING_CHECKOUT_ENDPOINT = "/api/v1/billing/checkout";
436
436
  var BILLING_PORTAL_ENDPOINT = "/api/v1/billing/portal";
437
+ var EXT_INVOICES_ENDPOINT = "/api/v1/billing/ext/invoices";
438
+ var EXT_RETRY_PAYMENT_ENDPOINT = "/api/v1/billing/ext/retry-payment";
437
439
  function createBillingMethods(deps) {
438
440
  const { fetchWithAuth, createError } = deps;
439
441
  async function createCheckoutSession(params) {
@@ -475,7 +477,31 @@ function createBillingMethods(deps) {
475
477
  `${BILLING_PORTAL_ENDPOINT}?${query.toString()}`
476
478
  );
477
479
  }
478
- return { createCheckoutSession, createPortalSession };
480
+ async function listInvoices(params) {
481
+ if (!params.organizationId) {
482
+ return { error: createError("VALIDATION_ERROR", "organizationId \u306F\u5FC5\u9808\u3067\u3059") };
483
+ }
484
+ const query = new URLSearchParams({ organizationId: params.organizationId });
485
+ return fetchWithAuth(`${EXT_INVOICES_ENDPOINT}?${query.toString()}`);
486
+ }
487
+ async function getInvoice(params) {
488
+ if (!params.invoiceId) {
489
+ return { error: createError("VALIDATION_ERROR", "invoiceId \u306F\u5FC5\u9808\u3067\u3059") };
490
+ }
491
+ return fetchWithAuth(
492
+ `${EXT_INVOICES_ENDPOINT}/${encodeURIComponent(params.invoiceId)}`
493
+ );
494
+ }
495
+ async function retryPayment(params) {
496
+ if (!params.organizationId) {
497
+ return { error: createError("VALIDATION_ERROR", "organizationId \u306F\u5FC5\u9808\u3067\u3059") };
498
+ }
499
+ return fetchWithAuth(EXT_RETRY_PAYMENT_ENDPOINT, {
500
+ method: "POST",
501
+ body: JSON.stringify({ organizationId: params.organizationId })
502
+ });
503
+ }
504
+ return { createCheckoutSession, createPortalSession, listInvoices, getInvoice, retryPayment };
479
505
  }
480
506
 
481
507
  // src/client/subscription-methods.ts
@@ -817,6 +843,45 @@ function createMembersMethods(deps) {
817
843
  return { listMembers, addMember, updateMemberRole, removeMember };
818
844
  }
819
845
 
846
+ // src/client/seat-methods.ts
847
+ function seatsEndpoint(subscriptionId) {
848
+ return `/api/v1/subscriptions/ext/${encodeURIComponent(subscriptionId)}/seats/assignments`;
849
+ }
850
+ function createSeatMethods(deps) {
851
+ const { fetchWithAuth, createError } = deps;
852
+ async function listSeatAssignments(params) {
853
+ if (!params.subscriptionId) {
854
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
855
+ }
856
+ return fetchWithAuth(seatsEndpoint(params.subscriptionId));
857
+ }
858
+ async function assignSeats(params) {
859
+ if (!params.subscriptionId) {
860
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
861
+ }
862
+ if (!Array.isArray(params.userIds) || params.userIds.length === 0) {
863
+ return { error: createError("VALIDATION_ERROR", "userIds \u306F 1 \u4EF6\u4EE5\u4E0A\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044") };
864
+ }
865
+ return fetchWithAuth(seatsEndpoint(params.subscriptionId), {
866
+ method: "POST",
867
+ body: JSON.stringify({ userIds: params.userIds })
868
+ });
869
+ }
870
+ async function unassignSeat(params) {
871
+ if (!params.subscriptionId) {
872
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
873
+ }
874
+ if (!params.userId) {
875
+ return { error: createError("VALIDATION_ERROR", "userId \u306F\u5FC5\u9808\u3067\u3059") };
876
+ }
877
+ return fetchWithAuth(
878
+ `${seatsEndpoint(params.subscriptionId)}/${encodeURIComponent(params.userId)}`,
879
+ { method: "DELETE" }
880
+ );
881
+ }
882
+ return { listSeatAssignments, assignSeats, unassignSeat };
883
+ }
884
+
820
885
  // src/client/profile-methods.ts
821
886
  var EXT_PROFILE_ENDPOINT = "/api/v1/users/ext/me";
822
887
  function resolveAuthOverride(options, createError) {
@@ -867,7 +932,7 @@ function createProfileMethods(deps) {
867
932
  }
868
933
 
869
934
  // src/client/version-check.ts
870
- var SDK_VERSION = "5.9.0";
935
+ var SDK_VERSION = "5.12.0";
871
936
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
872
937
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
873
938
  function sdkHeaders() {
@@ -2257,6 +2322,15 @@ function createInquiryMethods(deps) {
2257
2322
  }
2258
2323
 
2259
2324
  // src/subscriptions/types.ts
2325
+ var EFFECTIVE_SUBSCRIPTION_STATUSES = [
2326
+ "active",
2327
+ "active_canceling",
2328
+ "past_due_grace",
2329
+ "blocked",
2330
+ "canceled",
2331
+ "trial_expired",
2332
+ "expired"
2333
+ ];
2260
2334
  var PAST_DUE_GRACE_PERIOD_DAYS = 7;
2261
2335
  var HOURS_PER_DAY = 24;
2262
2336
  var MINUTES_PER_HOUR = 60;
@@ -2717,7 +2791,11 @@ function createFFIDClient(config) {
2717
2791
  }
2718
2792
  return result;
2719
2793
  }
2720
- const { createCheckoutSession, createPortalSession } = createBillingMethods({
2794
+ const { createCheckoutSession, createPortalSession, listInvoices, getInvoice, retryPayment } = createBillingMethods({
2795
+ fetchWithAuth,
2796
+ createError
2797
+ });
2798
+ const { listSeatAssignments, assignSeats, unassignSeat } = createSeatMethods({
2721
2799
  fetchWithAuth,
2722
2800
  createError
2723
2801
  });
@@ -2826,6 +2904,12 @@ function createFFIDClient(config) {
2826
2904
  getAnalyticsConfig,
2827
2905
  createCheckoutSession,
2828
2906
  createPortalSession,
2907
+ listInvoices,
2908
+ getInvoice,
2909
+ retryPayment,
2910
+ listSeatAssignments,
2911
+ assignSeats,
2912
+ unassignSeat,
2829
2913
  listPlans,
2830
2914
  getSubscription,
2831
2915
  subscribe,
@@ -4854,4 +4938,4 @@ function FFIDInquiryForm({
4854
4938
  );
4855
4939
  }
4856
4940
 
4857
- export { ACCESS_GRANTING_EFFECTIVE_STATUSES, BLOCKING_EFFECTIVE_STATUSES, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, computeEffectiveStatusFromSession, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, hasAccessFromUserinfo, isBlockedFromUserinfo, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
4941
+ export { ACCESS_GRANTING_EFFECTIVE_STATUSES, BLOCKING_EFFECTIVE_STATUSES, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, computeEffectiveStatusFromSession, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, hasAccessFromUserinfo, isBlockedFromUserinfo, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
@@ -798,6 +798,7 @@ function createConsentClient(opts) {
798
798
  };
799
799
  if (reqOpts.body !== void 0) init.body = JSON.stringify(reqOpts.body);
800
800
  if (reqOpts.signal) init.signal = reqOpts.signal;
801
+ if (reqOpts.keepalive && !reqOpts.signal) init.keepalive = true;
801
802
  let res;
802
803
  for (let attempt = 0; attempt <= maxAutoRetry429; attempt++) {
803
804
  const fetched = await performFetch(url, init);
@@ -879,6 +880,10 @@ function createConsentClient(opts) {
879
880
  source,
880
881
  cookie_policy_version: cookiePolicyVersion
881
882
  },
883
+ // The banner closes before this POST settles (optimistic close,
884
+ // #3614) — keepalive keeps the audit-trail write alive across a
885
+ // quick page navigation.
886
+ keepalive: true,
882
887
  ...signal ? { signal } : {}
883
888
  },
884
889
  (json) => {
@@ -1215,6 +1220,16 @@ function FFIDAnalyticsProvider({
1215
1220
  cancelled = true;
1216
1221
  };
1217
1222
  }, []);
1223
+ useEffect(() => {
1224
+ if (!isBannerOpen || policy !== null) return;
1225
+ let cancelled = false;
1226
+ void clientRef.current.getDocument().then((result) => {
1227
+ if (!cancelled && result.ok) setPolicy(result.value);
1228
+ });
1229
+ return () => {
1230
+ cancelled = true;
1231
+ };
1232
+ }, [isBannerOpen, policy]);
1218
1233
  const ensurePolicyVersion = useCallback(async () => {
1219
1234
  if (policy) return { ok: true, version: policy.version };
1220
1235
  const client = clientRef.current;
@@ -1229,18 +1244,38 @@ function FFIDAnalyticsProvider({
1229
1244
  }, [onError, policy]);
1230
1245
  const submitFromBanner = useCallback(
1231
1246
  async (cats) => {
1232
- const version = await ensurePolicyVersion();
1233
- if (!version.ok) return { ok: false, error: version.error };
1234
- const client = clientRef.current;
1235
- const result = await client.submit(cats, "banner", version.version);
1236
- if (!result.ok && result.error.code === "cookie_consent_policy_outdated") {
1237
- setPolicy(null);
1247
+ setIsBannerOpen(false);
1248
+ let recordedOk = false;
1249
+ try {
1250
+ const version = await ensurePolicyVersion();
1251
+ if (!version.ok) {
1252
+ setIsBannerOpen(true);
1253
+ return { ok: false, error: version.error };
1254
+ }
1255
+ const client = clientRef.current;
1256
+ const result = await client.submit(cats, "banner", version.version);
1257
+ if (!result.ok && result.error.code === "cookie_consent_policy_outdated") {
1258
+ setPolicy(null);
1259
+ }
1260
+ recordedOk = result.ok;
1261
+ handleResult(result);
1262
+ if (!result.ok) setIsBannerOpen(true);
1263
+ return result;
1264
+ } catch (err) {
1265
+ if (!recordedOk) {
1266
+ const escapeError = err instanceof FFIDConsentError ? err : new FFIDConsentError(
1267
+ "cookie_consent_capture_failed",
1268
+ DEFAULT_CONSENT_ERROR_MESSAGES.cookie_consent_capture_failed,
1269
+ { cause: err }
1270
+ );
1271
+ setError(escapeError);
1272
+ setIsBannerOpen(true);
1273
+ onError?.(escapeError);
1274
+ }
1275
+ throw err;
1238
1276
  }
1239
- handleResult(result);
1240
- if (result.ok) setIsBannerOpen(false);
1241
- return result;
1242
1277
  },
1243
- [ensurePolicyVersion, handleResult]
1278
+ [ensurePolicyVersion, handleResult, onError]
1244
1279
  );
1245
1280
  const acceptAll = useCallback(
1246
1281
  () => submitFromBanner({
@@ -1486,16 +1521,13 @@ function FFIDCookieBanner({
1486
1521
  error
1487
1522
  } = useFFIDConsent();
1488
1523
  const [pendingAction, setPendingAction] = useState(null);
1489
- const isSubmitting = pendingAction !== null;
1524
+ const isOpeningPreferences = pendingAction !== null;
1490
1525
  const runBannerSubmit = async (action, submit) => {
1491
- if (isSubmitting) return;
1492
- setPendingAction(action);
1526
+ if (isOpeningPreferences) return;
1493
1527
  try {
1494
- const result = await submit();
1495
- if (!result.ok) setPendingAction(null);
1528
+ await submit();
1496
1529
  } catch (err) {
1497
1530
  console.error(`[FFIDCookieBanner] ${action} action failed`, err);
1498
- setPendingAction(null);
1499
1531
  }
1500
1532
  };
1501
1533
  const handleAcceptAll = () => runBannerSubmit("accept-all", acceptAll);
@@ -1503,7 +1535,7 @@ function FFIDCookieBanner({
1503
1535
  await runBannerSubmit("necessary-only", acceptNecessaryOnly);
1504
1536
  };
1505
1537
  const handleOpenPreferences = async () => {
1506
- if (isSubmitting) return;
1538
+ if (isOpeningPreferences) return;
1507
1539
  setPendingAction("preferences");
1508
1540
  try {
1509
1541
  await openPreferences();
@@ -1520,7 +1552,7 @@ function FFIDCookieBanner({
1520
1552
  role: "dialog",
1521
1553
  "aria-modal": "false",
1522
1554
  "aria-label": "Cookie \u540C\u610F",
1523
- "aria-busy": isSubmitting,
1555
+ "aria-busy": isOpeningPreferences,
1524
1556
  className: className ?? classNames?.root,
1525
1557
  style: style ?? DEFAULT_STYLE,
1526
1558
  "data-testid": "ffid-cookie-banner",
@@ -1547,15 +1579,15 @@ function FFIDCookieBanner({
1547
1579
  className: classNames?.primaryButton,
1548
1580
  style: {
1549
1581
  ...DEFAULT_PRIMARY_STYLE,
1550
- cursor: isSubmitting ? "wait" : DEFAULT_PRIMARY_STYLE.cursor
1582
+ cursor: isOpeningPreferences ? "wait" : DEFAULT_PRIMARY_STYLE.cursor
1551
1583
  },
1552
- disabled: isSubmitting,
1553
- "aria-disabled": isSubmitting,
1584
+ disabled: isOpeningPreferences,
1585
+ "aria-disabled": isOpeningPreferences,
1554
1586
  onClick: () => {
1555
1587
  void handleAcceptAll();
1556
1588
  },
1557
1589
  "data-testid": "ffid-cookie-banner-accept-all",
1558
- children: pendingAction === "accept-all" ? "\u4FDD\u5B58\u4E2D..." : acceptAllLabel ?? "\u3059\u3079\u3066\u540C\u610F"
1590
+ children: acceptAllLabel ?? "\u3059\u3079\u3066\u540C\u610F"
1559
1591
  }
1560
1592
  ),
1561
1593
  /* @__PURE__ */ jsx(
@@ -1565,15 +1597,15 @@ function FFIDCookieBanner({
1565
1597
  className: classNames?.secondaryButton,
1566
1598
  style: {
1567
1599
  ...DEFAULT_BUTTON_STYLE,
1568
- cursor: isSubmitting ? "wait" : DEFAULT_BUTTON_STYLE.cursor
1600
+ cursor: isOpeningPreferences ? "wait" : DEFAULT_BUTTON_STYLE.cursor
1569
1601
  },
1570
- disabled: isSubmitting,
1571
- "aria-disabled": isSubmitting,
1602
+ disabled: isOpeningPreferences,
1603
+ "aria-disabled": isOpeningPreferences,
1572
1604
  onClick: () => {
1573
1605
  void handleAcceptNecessaryOnly();
1574
1606
  },
1575
1607
  "data-testid": "ffid-cookie-banner-necessary-only",
1576
- children: pendingAction === "necessary-only" ? "\u4FDD\u5B58\u4E2D..." : necessaryOnlyLabel ?? "\u540C\u610F\u3057\u306A\u3044"
1608
+ children: necessaryOnlyLabel ?? "\u540C\u610F\u3057\u306A\u3044"
1577
1609
  }
1578
1610
  ),
1579
1611
  /* @__PURE__ */ jsx(
@@ -1583,10 +1615,10 @@ function FFIDCookieBanner({
1583
1615
  className: classNames?.linkButton,
1584
1616
  style: {
1585
1617
  ...DEFAULT_BUTTON_STYLE,
1586
- cursor: isSubmitting ? "wait" : DEFAULT_BUTTON_STYLE.cursor
1618
+ cursor: isOpeningPreferences ? "wait" : DEFAULT_BUTTON_STYLE.cursor
1587
1619
  },
1588
- disabled: isSubmitting,
1589
- "aria-disabled": isSubmitting,
1620
+ disabled: isOpeningPreferences,
1621
+ "aria-disabled": isOpeningPreferences,
1590
1622
  onClick: () => {
1591
1623
  void handleOpenPreferences();
1592
1624
  },
@@ -1601,10 +1633,10 @@ function FFIDCookieBanner({
1601
1633
  className: classNames?.closeButton,
1602
1634
  style: {
1603
1635
  ...DEFAULT_BUTTON_STYLE,
1604
- cursor: isSubmitting ? "wait" : DEFAULT_BUTTON_STYLE.cursor
1636
+ cursor: isOpeningPreferences ? "wait" : DEFAULT_BUTTON_STYLE.cursor
1605
1637
  },
1606
- disabled: isSubmitting,
1607
- "aria-disabled": isSubmitting,
1638
+ disabled: isOpeningPreferences,
1639
+ "aria-disabled": isOpeningPreferences,
1608
1640
  onClick: () => {
1609
1641
  closeBanner();
1610
1642
  },