@feelflow/ffid-sdk 7.1.0 → 8.0.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.
@@ -158,7 +158,7 @@ function normalizeUserinfo(raw) {
158
158
  emailVerified: raw.email_verified,
159
159
  name: raw.name,
160
160
  picture: raw.picture,
161
- companyName: raw.company_name ?? null,
161
+ companyName: null,
162
162
  department: raw.department ?? null,
163
163
  position: raw.position ?? null,
164
164
  phoneNumber: raw.phone_number ?? null,
@@ -226,13 +226,18 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
226
226
  ];
227
227
  }
228
228
  var JWKS_ENDPOINT = "/.well-known/jwks.json";
229
- var JWT_ISSUER = "https://id.feelflow.net";
229
+ var LEGACY_JWT_ISSUER = "https://id.feelflow.net";
230
230
  var JWT_ALGORITHM = "ES256";
231
231
  var JWT_CLOCK_TOLERANCE_SECONDS = 30;
232
+ function resolveAcceptedIssuers(baseUrl) {
233
+ const deployedOrigin = new URL(baseUrl).origin;
234
+ return deployedOrigin === LEGACY_JWT_ISSUER ? [LEGACY_JWT_ISSUER] : [deployedOrigin, LEGACY_JWT_ISSUER];
235
+ }
232
236
  function createJwtVerifier(deps) {
233
237
  const { baseUrl, serviceCode, logger, createError, errorCodes } = deps;
234
238
  const jwksUrl = new URL(JWKS_ENDPOINT, baseUrl);
235
239
  const jwks = createRemoteJWKSet(jwksUrl);
240
+ const acceptedIssuers = resolveAcceptedIssuers(baseUrl);
236
241
  async function verifyJwt(accessToken) {
237
242
  if (!accessToken || !accessToken.trim()) {
238
243
  return {
@@ -245,7 +250,7 @@ function createJwtVerifier(deps) {
245
250
  try {
246
251
  const { payload } = await jwtVerify(accessToken, jwks, {
247
252
  algorithms: [JWT_ALGORITHM],
248
- issuer: JWT_ISSUER,
253
+ issuer: acceptedIssuers,
249
254
  audience: serviceCode,
250
255
  clockTolerance: JWT_CLOCK_TOLERANCE_SECONDS
251
256
  });
@@ -462,7 +467,7 @@ function createVerifyAccessToken(deps) {
462
467
  email_verified: introspectResponse.email_verified,
463
468
  name: introspectResponse.name ?? null,
464
469
  picture: introspectResponse.picture ?? null,
465
- company_name: introspectResponse.company_name ?? null,
470
+ company_name: null,
466
471
  department: introspectResponse.department ?? null,
467
472
  position: introspectResponse.position ?? null,
468
473
  phone_number: introspectResponse.phone_number ?? null,
@@ -713,6 +718,24 @@ function validateSeatChangePreview(preview) {
713
718
  `SDK: server returned malformed SeatChangePreview \u2014 estimateReason must be one of 'no_stripe_data' | 'custom_pricing' | 'stripe_error' (got ${JSON.stringify(p.estimateReason)})`
714
719
  );
715
720
  }
721
+ if (p.willApplyAtPeriodEnd !== void 0 && typeof p.willApplyAtPeriodEnd !== "boolean") {
722
+ throw new FFIDSDKError(
723
+ MALFORMED_SEAT_PREVIEW_CODE,
724
+ `SDK: server returned malformed SeatChangePreview \u2014 willApplyAtPeriodEnd must be boolean when present (got ${typeof p.willApplyAtPeriodEnd})`
725
+ );
726
+ }
727
+ if (p.effectiveDate !== void 0 && p.effectiveDate !== null && typeof p.effectiveDate !== "string") {
728
+ throw new FFIDSDKError(
729
+ MALFORMED_SEAT_PREVIEW_CODE,
730
+ `SDK: server returned malformed SeatChangePreview \u2014 effectiveDate must be string or null when present (got ${typeof p.effectiveDate})`
731
+ );
732
+ }
733
+ if (p.willApplyAtPeriodEnd === true && p.proratedAmount !== 0) {
734
+ throw new FFIDSDKError(
735
+ MALFORMED_SEAT_PREVIEW_CODE,
736
+ `SDK: server returned malformed SeatChangePreview \u2014 willApplyAtPeriodEnd=true requires proratedAmount=0 (got ${JSON.stringify(p.proratedAmount)})`
737
+ );
738
+ }
716
739
  if (!Array.isArray(p.lineItems)) {
717
740
  throw new FFIDSDKError(
718
741
  MALFORMED_SEAT_PREVIEW_CODE,
@@ -1353,7 +1376,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
1353
1376
  };
1354
1377
 
1355
1378
  // src/client/version-check.ts
1356
- var SDK_VERSION = "7.1.0";
1379
+ var SDK_VERSION = "8.0.0";
1357
1380
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1358
1381
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1359
1382
  function sdkHeaders() {
@@ -2607,6 +2630,129 @@ function cleanupStateStorage(logger) {
2607
2630
  }
2608
2631
  }
2609
2632
 
2633
+ // src/client/agency-invite-token.ts
2634
+ var AGENCY_INVITE_TOKEN_PARAM = "invite";
2635
+ var AGENCY_INVITE_COOKIE_NAME = "ffid_invite";
2636
+ var SECONDS_PER_MINUTE = 60;
2637
+ var MINUTES_PER_HOUR = 60;
2638
+ var HOURS_PER_DAY = 24;
2639
+ var RETENTION_DAYS = 30;
2640
+ var AGENCY_INVITE_COOKIE_MAX_AGE_SEC = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * RETENTION_DAYS;
2641
+ var AGENCY_INVITE_TOKEN_REDACTION = "[REDACTED]";
2642
+ function hasDocument() {
2643
+ return typeof document !== "undefined";
2644
+ }
2645
+ function defaultSecure() {
2646
+ if (typeof process === "undefined") return true;
2647
+ return process.env?.NODE_ENV === "production";
2648
+ }
2649
+ function toQueryString(source) {
2650
+ const queryStart = source.indexOf("?");
2651
+ if (queryStart < 0) return "";
2652
+ const afterQuery = source.slice(queryStart);
2653
+ const fragmentStart = afterQuery.indexOf("#");
2654
+ return fragmentStart < 0 ? afterQuery : afterQuery.slice(0, fragmentStart);
2655
+ }
2656
+ function readTokenFromUrl(options) {
2657
+ const source = options.url ?? (typeof window !== "undefined" ? window.location.search : void 0);
2658
+ if (source === void 0) return void 0;
2659
+ const params = new URLSearchParams(toQueryString(source));
2660
+ return params.get(AGENCY_INVITE_TOKEN_PARAM)?.trim() || void 0;
2661
+ }
2662
+ function readAgencyInviteCookie() {
2663
+ if (!hasDocument()) return void 0;
2664
+ const prefix = `${AGENCY_INVITE_COOKIE_NAME}=`;
2665
+ const raw = document.cookie.split(";").map((entry) => entry.trim()).find((entry) => entry.startsWith(prefix));
2666
+ if (!raw) return void 0;
2667
+ try {
2668
+ return decodeURIComponent(raw.slice(prefix.length)).trim() || void 0;
2669
+ } catch {
2670
+ return void 0;
2671
+ }
2672
+ }
2673
+ function readAgencyInviteToken(options = {}) {
2674
+ return readTokenFromUrl(options) ?? readAgencyInviteCookie();
2675
+ }
2676
+ function buildAgencyInviteCookie(value, maxAgeSec, options) {
2677
+ const attrs = [
2678
+ `${AGENCY_INVITE_COOKIE_NAME}=${value}`,
2679
+ `Max-Age=${maxAgeSec}`,
2680
+ `Path=${options.path ?? "/"}`,
2681
+ "SameSite=Lax"
2682
+ ];
2683
+ if (options.domain) attrs.push(`Domain=${options.domain}`);
2684
+ if (options.secure ?? defaultSecure()) attrs.push("Secure");
2685
+ return attrs.join("; ");
2686
+ }
2687
+ function writeAgencyInviteCookie(token, options) {
2688
+ if (!hasDocument()) return void 0;
2689
+ document.cookie = buildAgencyInviteCookie(
2690
+ encodeURIComponent(token),
2691
+ AGENCY_INVITE_COOKIE_MAX_AGE_SEC,
2692
+ options
2693
+ );
2694
+ return readAgencyInviteCookie() === token;
2695
+ }
2696
+ function clearAgencyInviteToken(options = {}) {
2697
+ if (!hasDocument()) return void 0;
2698
+ const CLEAR_MAX_AGE = 0;
2699
+ document.cookie = buildAgencyInviteCookie("", CLEAR_MAX_AGE, options);
2700
+ return readAgencyInviteCookie() === void 0;
2701
+ }
2702
+ function captureAgencyInviteToken(options = {}) {
2703
+ const fromUrl = readTokenFromUrl(options);
2704
+ if (fromUrl !== void 0) {
2705
+ return { source: "url", token: fromUrl, persisted: writeAgencyInviteCookie(fromUrl, options) };
2706
+ }
2707
+ const fromCookie = readAgencyInviteCookie();
2708
+ return fromCookie !== void 0 ? { source: "cookie", token: fromCookie, persisted: void 0 } : { source: "none", token: void 0, persisted: void 0 };
2709
+ }
2710
+ var REDACT_BOUNDARIES = [
2711
+ "%2526",
2712
+ "%2523",
2713
+ "%253B",
2714
+ "%26",
2715
+ "%23",
2716
+ "%3B",
2717
+ "&",
2718
+ "#",
2719
+ ";"
2720
+ ];
2721
+ var REDACT_LEADS = ["%253F", "%3F", "?", ...REDACT_BOUNDARIES];
2722
+ var REDACT_SEPARATORS = ["%253D", "%3D", "="];
2723
+ function escapeForRegExp(literal) {
2724
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2725
+ }
2726
+ var REDACT_PATTERN = new RegExp(
2727
+ [
2728
+ // 先頭区切り。`\b` が使えないのは、入れ子形 (`%3Finvite%3D`) では `F` と `i` が
2729
+ // どちらも単語文字なので単語境界が存在しないため。
2730
+ `(^|${REDACT_LEADS.map(escapeForRegExp).join("|")})`,
2731
+ // パラメータ名と区切りはキャプチャして再出力する。`i` フラグがあるので、
2732
+ // 入力の `INVITE=` / `%3d` などの元の表記を保つ必要がある。
2733
+ `(${AGENCY_INVITE_TOKEN_PARAM})`,
2734
+ `(${REDACT_SEPARATORS.map(escapeForRegExp).join("|")})`,
2735
+ // 値。境界の直前まで貪欲に食う。`\s` は終端にしない — 生の空白や改行を含む
2736
+ // トークンでマスクが途中で切れ、後半が漏れる。
2737
+ `(?:(?!${REDACT_BOUNDARIES.map(escapeForRegExp).join("|")})[^&#;])*`
2738
+ ].join(""),
2739
+ "gi"
2740
+ );
2741
+ function redactAgencyInviteToken(url) {
2742
+ return url.replace(
2743
+ REDACT_PATTERN,
2744
+ // 文字列 replacement(`'$1$2$3[REDACTED]'`)にしないのは、
2745
+ // `AGENCY_INVITE_TOKEN_REDACTION` に `$` が入った瞬間に置換パターンとして
2746
+ // 解釈される罠を作らないため。
2747
+ (_match, lead, name, separator) => `${lead}${name}${separator}${AGENCY_INVITE_TOKEN_REDACTION}`
2748
+ );
2749
+ }
2750
+ function appendAgencyInviteToken(signupUrl, token) {
2751
+ if (token === void 0) return signupUrl;
2752
+ const separator = signupUrl.includes("?") ? "&" : "?";
2753
+ return `${signupUrl}${separator}${AGENCY_INVITE_TOKEN_PARAM}=${encodeURIComponent(token)}`;
2754
+ }
2755
+
2610
2756
  // src/client/redirect.ts
2611
2757
  var OAUTH_AUTHORIZE_ENDPOINT = "/api/v1/oauth/authorize";
2612
2758
  var AUTH_LOGOUT_ENDPOINT = "/api/v1/auth/logout";
@@ -2619,6 +2765,7 @@ var REDIRECT_LOOP_WINDOW_MS = 6e4;
2619
2765
  var REDIRECT_LOOP_THRESHOLD = 3;
2620
2766
  var storageReadFailureLogged = false;
2621
2767
  var storageWriteFailureLogged = false;
2768
+ var ssrInviteTokenUnavailableLogged = false;
2622
2769
  function isLoopDetectionDegraded() {
2623
2770
  return storageReadFailureLogged || storageWriteFailureLogged;
2624
2771
  }
@@ -2797,12 +2944,16 @@ function createRedirectMethods(deps) {
2797
2944
  }
2798
2945
  if (options?.screenHint === SCREEN_HINT_SIGNUP) {
2799
2946
  params.set(SCREEN_HINT_PARAM, SCREEN_HINT_SIGNUP);
2947
+ const inviteToken = readAgencyInviteToken();
2948
+ if (inviteToken !== void 0) {
2949
+ params.set(AGENCY_INVITE_TOKEN_PARAM, inviteToken);
2950
+ }
2800
2951
  }
2801
2952
  if (options?.prompt) {
2802
2953
  params.set("prompt", options.prompt);
2803
2954
  }
2804
2955
  const authorizeUrl = `${baseUrl}${OAUTH_AUTHORIZE_ENDPOINT}?${params.toString()}`;
2805
- logger.debug("Redirecting to authorize:", authorizeUrl);
2956
+ logger.debug("Redirecting to authorize:", redactAgencyInviteToken(authorizeUrl));
2806
2957
  recordRedirectAttempt(authorizeKey, now, logger);
2807
2958
  try {
2808
2959
  window.location.href = authorizeUrl;
@@ -2821,7 +2972,7 @@ function createRedirectMethods(deps) {
2821
2972
  return redirectToAuthorize(options);
2822
2973
  }
2823
2974
  const targetUrl = options?.screenHint === SCREEN_HINT_SIGNUP ? getSignupUrl() : getLoginUrl(void 0, options?.prompt ? { prompt: options.prompt } : void 0);
2824
- logger.debug("Redirecting to auth page:", targetUrl);
2975
+ logger.debug("Redirecting to auth page:", redactAgencyInviteToken(targetUrl));
2825
2976
  window.location.href = targetUrl;
2826
2977
  return { success: true };
2827
2978
  }
@@ -2838,7 +2989,7 @@ function createRedirectMethods(deps) {
2838
2989
  const promptSuffix = options?.prompt ? `&prompt=${encodeURIComponent(options.prompt)}` : "";
2839
2990
  return `${baseUrl}/login?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}${promptSuffix}`;
2840
2991
  }
2841
- function getSignupUrl(redirectUrl) {
2992
+ function getSignupUrl(redirectUrl, options) {
2842
2993
  let redirect;
2843
2994
  if (redirectUrl != null) {
2844
2995
  redirect = redirectUrl;
@@ -2848,7 +2999,22 @@ function createRedirectMethods(deps) {
2848
2999
  logger.warn("getSignupUrl: SSR \u74B0\u5883\u3067 redirectUrl \u304C\u672A\u6307\u5B9A\u306E\u305F\u3081\u7A7A\u6587\u5B57\u306B\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059");
2849
3000
  redirect = "";
2850
3001
  }
2851
- return `${baseUrl}/signup?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}`;
3002
+ let inviteToken = options?.inviteToken;
3003
+ if (inviteToken === void 0) {
3004
+ inviteToken = readAgencyInviteToken();
3005
+ if (inviteToken === void 0 && typeof window === "undefined") {
3006
+ if (!ssrInviteTokenUnavailableLogged) {
3007
+ ssrInviteTokenUnavailableLogged = true;
3008
+ logger.warn(
3009
+ "[FFID SDK] getSignupUrl: SSR \u3067\u306F\u62DB\u5F85\u30C8\u30FC\u30AF\u30F3\uFF08invite\uFF09\u3092\u8AAD\u3081\u307E\u305B\u3093\u3002\u4EE3\u7406\u5E97\u306E\u62DB\u5F85\u30EA\u30F3\u30AF\u3092\u4F7F\u3046\u5834\u5408\u306F options.inviteToken \u306B\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F7F\u3063\u3066\u3044\u306A\u3044\u5834\u5408\u306F\u3053\u306E\u8B66\u544A\u3092\u7121\u8996\u3057\u3066\u3088\u3044\uFF09"
3010
+ );
3011
+ }
3012
+ }
3013
+ }
3014
+ return appendAgencyInviteToken(
3015
+ `${baseUrl}/signup?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}`,
3016
+ inviteToken
3017
+ );
2852
3018
  }
2853
3019
  function getLogoutUrl(postLogoutRedirectUri) {
2854
3020
  const url = new URL(`${baseUrl}${AUTH_LOGOUT_ENDPOINT}`);
@@ -2864,7 +3030,7 @@ function createRedirectMethods(deps) {
2864
3030
  return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
2865
3031
  }
2866
3032
  const logoutUrl = getLogoutUrl(postLogoutRedirectUri);
2867
- logger.debug("Redirecting to logout:", logoutUrl);
3033
+ logger.debug("Redirecting to logout:", redactAgencyInviteToken(logoutUrl));
2868
3034
  window.location.href = logoutUrl;
2869
3035
  return { success: true };
2870
3036
  }
@@ -3477,11 +3643,11 @@ var EFFECTIVE_SUBSCRIPTION_STATUSES = [
3477
3643
  "expired"
3478
3644
  ];
3479
3645
  var PAST_DUE_GRACE_PERIOD_DAYS = 7;
3480
- var HOURS_PER_DAY = 24;
3481
- var MINUTES_PER_HOUR = 60;
3482
- var SECONDS_PER_MINUTE = 60;
3646
+ var HOURS_PER_DAY2 = 24;
3647
+ var MINUTES_PER_HOUR2 = 60;
3648
+ var SECONDS_PER_MINUTE2 = 60;
3483
3649
  var MS_PER_SECOND2 = 1e3;
3484
- var MS_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MS_PER_SECOND2;
3650
+ var MS_PER_DAY = HOURS_PER_DAY2 * MINUTES_PER_HOUR2 * SECONDS_PER_MINUTE2 * MS_PER_SECOND2;
3485
3651
 
3486
3652
  // src/subscriptions/compute-effective-status.ts
3487
3653
  function isExpired(isoTimestamp, nowMs) {
@@ -3634,6 +3800,18 @@ var FFID_ERROR_CODES = {
3634
3800
  TOKEN_EXPIRED: "TOKEN_EXPIRED",
3635
3801
  STATE_MISMATCH_ERROR: "STATE_MISMATCH_ERROR"
3636
3802
  };
3803
+ var FFID_SUBSCRIPTION_ERROR_CODES = {
3804
+ CANCELLATION_SCHEDULED: "CANCELLATION_SCHEDULED",
3805
+ PENDING_CHANGE_EXISTS: "PENDING_CHANGE_EXISTS",
3806
+ CHANGE_DIRECTION_MIXED: "CHANGE_DIRECTION_MIXED",
3807
+ CHANGE_PAYMENT_FAILED: "CHANGE_PAYMENT_FAILED",
3808
+ SAME_PLAN_SELECTED: "SAME_PLAN_SELECTED",
3809
+ NO_PENDING_DOWNGRADE: "NO_PENDING_DOWNGRADE",
3810
+ SUBSCRIPTION_NOT_CANCELABLE: "SUBSCRIPTION_NOT_CANCELABLE",
3811
+ SUBSCRIPTION_ALREADY_CANCELED: "SUBSCRIPTION_ALREADY_CANCELED",
3812
+ FREE_DOWNGRADE_NOT_ALLOWED: "FREE_DOWNGRADE_NOT_ALLOWED",
3813
+ PAYMENT_METHOD_REQUIRED: "PAYMENT_METHOD_REQUIRED"
3814
+ };
3637
3815
 
3638
3816
  // src/client/ffid-client.ts
3639
3817
  var UNAUTHORIZED_STATUS2 = 401;
@@ -4317,6 +4495,15 @@ function FFIDProvider({
4317
4495
  }),
4318
4496
  [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId, timeout, tokenStore]
4319
4497
  );
4498
+ useEffect(() => {
4499
+ const captured = captureAgencyInviteToken();
4500
+ if (captured.persisted === false) {
4501
+ client.logger.debug(
4502
+ "[FFID SDK] \u62DB\u5F85\u30C8\u30FC\u30AF\u30F3\u306E cookie \u4FDD\u6301\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF08\u5225\u30DA\u30FC\u30B8\u3078\u56DE\u904A\u3059\u308B\u3068\u4EE3\u7406\u5E97\u306E\u7D10\u4ED8\u3051\u304C\u5931\u308F\u308C\u307E\u3059\uFF09",
4503
+ { source: captured.source }
4504
+ );
4505
+ }
4506
+ }, [client]);
4320
4507
  const refresh = useCallback(async () => {
4321
4508
  client.logger.debug("Refreshing session...");
4322
4509
  try {
@@ -6292,4 +6479,4 @@ function FFIDInquiryForm({
6292
6479
  );
6293
6480
  }
6294
6481
 
6295
- export { ACCESS_GRANTING_EFFECTIVE_STATUSES, 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_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, canonicalizeCatalogValue, cleanupStateStorage, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
6482
+ 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_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 };
@@ -1,34 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var chunkCI4N7KJK_cjs = require('../chunk-CI4N7KJK.cjs');
3
+ var chunkRNCK5E3Y_cjs = require('../chunk-RNCK5E3Y.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunkCI4N7KJK_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunkCI4N7KJK_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDInquiryForm", {
16
16
  enumerable: true,
17
- get: function () { return chunkCI4N7KJK_cjs.FFIDInquiryForm; }
17
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDInquiryForm; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDLoginButton", {
20
20
  enumerable: true,
21
- get: function () { return chunkCI4N7KJK_cjs.FFIDLoginButton; }
21
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDLoginButton; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
24
24
  enumerable: true,
25
- get: function () { return chunkCI4N7KJK_cjs.FFIDOrganizationSwitcher; }
25
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDOrganizationSwitcher; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
28
28
  enumerable: true,
29
- get: function () { return chunkCI4N7KJK_cjs.FFIDSubscriptionBadge; }
29
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDSubscriptionBadge; }
30
30
  });
31
31
  Object.defineProperty(exports, "FFIDUserMenu", {
32
32
  enumerable: true,
33
- get: function () { return chunkCI4N7KJK_cjs.FFIDUserMenu; }
33
+ get: function () { return chunkRNCK5E3Y_cjs.FFIDUserMenu; }
34
34
  });
@@ -1,3 +1,3 @@
1
- export { H as FFIDAnnouncementBadge, an as FFIDAnnouncementBadgeClassNames, ao as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, ap as FFIDAnnouncementListClassNames, aq as FFIDAnnouncementListProps, U as FFIDInquiryForm, V as FFIDInquiryFormCategoryItem, W as FFIDInquiryFormClassNames, X as FFIDInquiryFormLegalLayout, Y as FFIDInquiryFormOrganization, Z as FFIDInquiryFormPlaceholderContext, _ as FFIDInquiryFormPrefill, $ as FFIDInquiryFormProps, a0 as FFIDInquiryFormSubmitData, a1 as FFIDInquiryFormSubmitResult, a3 as FFIDLoginButton, ar as FFIDLoginButtonProps, a5 as FFIDOrganizationSwitcher, as as FFIDOrganizationSwitcherClassNames, at as FFIDOrganizationSwitcherProps, ab as FFIDSubscriptionBadge, au as FFIDSubscriptionBadgeClassNames, av as FFIDSubscriptionBadgeProps, ac as FFIDUserMenu, aw as FFIDUserMenuClassNames, ax as FFIDUserMenuProps } from '../index-BMKhKhzF.cjs';
1
+ export { H as FFIDAnnouncementBadge, an as FFIDAnnouncementBadgeClassNames, ao as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, ap as FFIDAnnouncementListClassNames, aq as FFIDAnnouncementListProps, U as FFIDInquiryForm, V as FFIDInquiryFormCategoryItem, W as FFIDInquiryFormClassNames, X as FFIDInquiryFormLegalLayout, Y as FFIDInquiryFormOrganization, Z as FFIDInquiryFormPlaceholderContext, _ as FFIDInquiryFormPrefill, $ as FFIDInquiryFormProps, a0 as FFIDInquiryFormSubmitData, a1 as FFIDInquiryFormSubmitResult, a3 as FFIDLoginButton, ar as FFIDLoginButtonProps, a5 as FFIDOrganizationSwitcher, as as FFIDOrganizationSwitcherClassNames, at as FFIDOrganizationSwitcherProps, ab as FFIDSubscriptionBadge, au as FFIDSubscriptionBadgeClassNames, av as FFIDSubscriptionBadgeProps, ac as FFIDUserMenu, aw as FFIDUserMenuClassNames, ax as FFIDUserMenuProps } from '../index-BG7g99pK.cjs';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1,3 +1,3 @@
1
- export { H as FFIDAnnouncementBadge, an as FFIDAnnouncementBadgeClassNames, ao as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, ap as FFIDAnnouncementListClassNames, aq as FFIDAnnouncementListProps, U as FFIDInquiryForm, V as FFIDInquiryFormCategoryItem, W as FFIDInquiryFormClassNames, X as FFIDInquiryFormLegalLayout, Y as FFIDInquiryFormOrganization, Z as FFIDInquiryFormPlaceholderContext, _ as FFIDInquiryFormPrefill, $ as FFIDInquiryFormProps, a0 as FFIDInquiryFormSubmitData, a1 as FFIDInquiryFormSubmitResult, a3 as FFIDLoginButton, ar as FFIDLoginButtonProps, a5 as FFIDOrganizationSwitcher, as as FFIDOrganizationSwitcherClassNames, at as FFIDOrganizationSwitcherProps, ab as FFIDSubscriptionBadge, au as FFIDSubscriptionBadgeClassNames, av as FFIDSubscriptionBadgeProps, ac as FFIDUserMenu, aw as FFIDUserMenuClassNames, ax as FFIDUserMenuProps } from '../index-BMKhKhzF.js';
1
+ export { H as FFIDAnnouncementBadge, an as FFIDAnnouncementBadgeClassNames, ao as FFIDAnnouncementBadgeProps, I as FFIDAnnouncementList, ap as FFIDAnnouncementListClassNames, aq as FFIDAnnouncementListProps, U as FFIDInquiryForm, V as FFIDInquiryFormCategoryItem, W as FFIDInquiryFormClassNames, X as FFIDInquiryFormLegalLayout, Y as FFIDInquiryFormOrganization, Z as FFIDInquiryFormPlaceholderContext, _ as FFIDInquiryFormPrefill, $ as FFIDInquiryFormProps, a0 as FFIDInquiryFormSubmitData, a1 as FFIDInquiryFormSubmitResult, a3 as FFIDLoginButton, ar as FFIDLoginButtonProps, a5 as FFIDOrganizationSwitcher, as as FFIDOrganizationSwitcherClassNames, at as FFIDOrganizationSwitcherProps, ab as FFIDSubscriptionBadge, au as FFIDSubscriptionBadgeClassNames, av as FFIDSubscriptionBadgeProps, ac as FFIDUserMenu, aw as FFIDUserMenuClassNames, ax as FFIDUserMenuProps } from '../index-BG7g99pK.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-Y4TUICQZ.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-YKBAFPX5.js';
@@ -450,12 +450,31 @@ interface FFIDSubscriptionDetail {
450
450
  trialStart: string | null;
451
451
  trialEnd: string | null;
452
452
  canceledAt: string | null;
453
+ /**
454
+ * `true` while a cancellation is reserved until the period end. `status` stays
455
+ * `active` until then; the subscription becomes `canceled` at `currentPeriodEnd`.
456
+ * The reservation can only be withdrawn in the FFID portal (there is no SDK method).
457
+ */
453
458
  cancelAtPeriodEnd: boolean;
454
- /** Pending period-end downgrade info (null = no scheduled downgrade) */
459
+ /**
460
+ * Change reserved until the period end (null = nothing reserved).
461
+ *
462
+ * Every decrease — a lower plan, paid → free, fewer seats, yearly → monthly — is
463
+ * reserved instead of applied immediately (FFID #6327). The current plan, seats and
464
+ * interval stay in effect until `scheduledAt`. Withdraw it with `cancelPendingDowngrade()`.
465
+ */
455
466
  pendingDowngrade: {
467
+ /** Plan in effect after the period end. Equals `planCode` for a seat-only or interval-only reservation. */
456
468
  planCode: string;
457
469
  planName: string;
470
+ /** Billing interval in effect after the period end */
458
471
  billingInterval: FFIDBillingInterval;
472
+ /**
473
+ * Seat count in effect after the period end. `null` = the seat count does not change.
474
+ * Seat reductions are made in the FFID portal; this lets you show them (8.0.0).
475
+ * FFID servers released before #6327 omit it, so compare with `== null` at runtime.
476
+ */
477
+ quantity: number | null;
459
478
  scheduledAt: string;
460
479
  requestedAt: string;
461
480
  } | null;
@@ -522,7 +541,17 @@ interface FFIDChangePlanParams {
522
541
  /** New billing interval (default: keeps current) */
523
542
  billingInterval?: FFIDBillingInterval;
524
543
  }
525
- /** Response from change plan endpoint */
544
+ /**
545
+ * Response from change plan endpoint.
546
+ *
547
+ * - An increase (higher plan / monthly → yearly) applies immediately and the difference up to
548
+ * the current period end is charged now. `pendingDowngrade` is absent.
549
+ * - A decrease (lower plan / paid → free / yearly → monthly) is reserved until the period end:
550
+ * `pendingDowngrade` is present and `subscription.planCode` is still the current plan.
551
+ * Nothing is charged or refunded. A contract that cannot be reserved still changes
552
+ * immediately, without a refund: one with no period end, or a paid → paid decrease on a
553
+ * contract without a Stripe subscription.
554
+ */
526
555
  interface FFIDChangePlanResponse {
527
556
  message: string;
528
557
  subscription: {
@@ -535,7 +564,7 @@ interface FFIDChangePlanResponse {
535
564
  status: FFIDSubscriptionStatus;
536
565
  isUpgrade: boolean;
537
566
  };
538
- /** Present when downgrade is scheduled for period end instead of immediate */
567
+ /** Present when the change is a decrease reserved until the period end */
539
568
  pendingDowngrade?: {
540
569
  planCode: string;
541
570
  planName: string;
@@ -551,17 +580,41 @@ interface FFIDCancelSubscriptionParams {
551
580
  /** Additional cancellation details */
552
581
  reasonDetails?: string;
553
582
  }
554
- /** Response from cancel subscription endpoint */
583
+ /**
584
+ * Response from cancel subscription endpoint.
585
+ *
586
+ * Since 8.0.0 a contract billed through Stripe is **reserved** for cancellation at the period
587
+ * end (FFID #6327): `status` stays `active`, `cancelAtPeriodEnd` is `true` and `cancelAt` is the
588
+ * period end. Access continues until then and nothing is refunded. A contract that cannot be
589
+ * reserved (no Stripe subscription, no period end yet, or Stripe not configured on FFID) is
590
+ * canceled immediately (`status: 'canceled'`, `cancelAtPeriodEnd: false`, `cancelAt: null`).
591
+ * Branch on `cancelAtPeriodEnd`, not on whether the contract uses Stripe.
592
+ *
593
+ * Do not treat this response as "access revoked". The `subscription.canceled` webhook arrives
594
+ * at reservation (`source: 'user_initiated'`) and again at the period end
595
+ * (`source: 'stripe_confirmed'`); see `FFIDSubscriptionCanceledPayload`.
596
+ */
555
597
  interface FFIDCancelSubscriptionResponse {
556
598
  message: string;
557
599
  subscription: {
558
600
  id: string;
559
601
  organizationId: string;
602
+ /** `active` while the cancellation is reserved; `canceled` only for an immediate cancellation */
560
603
  status: FFIDSubscriptionStatus;
561
604
  canceledAt: string | null;
605
+ /** `true` when the cancellation is reserved until the period end */
606
+ cancelAtPeriodEnd: boolean;
607
+ /** When the reserved cancellation takes effect (the period end). `null` for an immediate cancellation */
608
+ cancelAt: string | null;
562
609
  };
563
610
  }
564
- /** Response from cancel pending downgrade endpoint */
611
+ /**
612
+ * Response from cancel pending downgrade endpoint.
613
+ *
614
+ * Withdraws the reserved change on the Stripe side as well, so the current plan, seats and
615
+ * interval simply continue after the period end. It does not withdraw a reserved
616
+ * cancellation — that is done in the FFID portal.
617
+ */
565
618
  interface FFIDCancelPendingDowngradeResponse {
566
619
  message: string;
567
620
  subscription: {
@@ -616,14 +669,18 @@ interface FFIDPlanChangePreviewBase {
616
669
  lineItems: FFIDPlanChangeLineItem[];
617
670
  }
618
671
  /**
619
- * Plan change proration preview.
672
+ * Plan change proration preview. It is computed with the same rules as `changePlan()`.
620
673
  *
621
674
  * `willApplyAtPeriodEnd` is a discriminant that constrains related fields at the type level:
622
- * - `true`: period-end-deferred downgrade. `proratedAmount` is always 0; `effectiveDate` mirrors
623
- * the subscription's `currentPeriodEnd` (may be `null` when the subscription has no active
624
- * billing cycle yet — e.g. a pre-Stripe trial or a subscription whose billing cycle is unset).
625
- * - `false`: immediate change. `effectiveDate` is always `null`; `proratedAmount` is the live
626
- * (possibly Stripe-refined) day-basis difference.
675
+ * - `true`: a decrease reserved until the period end. `proratedAmount` is always 0 (nothing is
676
+ * charged or refunded now); `effectiveDate` mirrors the subscription's `currentPeriodEnd`
677
+ * (may be `null` when the subscription has no active billing cycle yet).
678
+ * - `false`: immediate change. `effectiveDate` is always `null`. For an increase,
679
+ * `proratedAmount` is the difference up to the current period end that is charged now
680
+ * (possibly Stripe-refined). A decrease on a contract that cannot be reserved also lands here:
681
+ * `0` for a contract without a Stripe subscription (no refund), but Stripe's prorated amount —
682
+ * negative, credited on the next invoice — for a Stripe contract with no period end yet
683
+ * (e.g. during a trial).
627
684
  */
628
685
  type FFIDPlanChangePreview = FFIDPlanChangePreviewBase & ({
629
686
  willApplyAtPeriodEnd: true;
@@ -633,7 +690,7 @@ type FFIDPlanChangePreview = FFIDPlanChangePreviewBase & ({
633
690
  } | {
634
691
  willApplyAtPeriodEnd: false;
635
692
  effectiveDate: null;
636
- /** Prorated difference charged within the current billing period */
693
+ /** Difference up to the current period end charged now (see the type doc for the decrease cases) */
637
694
  proratedAmount: number;
638
695
  });
639
696
  /** Response from plan change preview endpoint */
@@ -658,14 +715,27 @@ interface FFIDSeatChangeLineItem {
658
715
  * Sister type to `FFIDPlanChangePreview`. The shared `type` discriminant lets
659
716
  * consumers narrow a preview payload without inspecting unrelated fields.
660
717
  *
718
+ * - `willApplyAtPeriodEnd=true`: a seat reduction reserved until the period end.
719
+ * `proratedAmount` is 0 and `effectiveDate` is when the new seat count applies.
720
+ * - Otherwise the change applies immediately. For an increase, `proratedAmount` is the amount
721
+ * charged now up to the current period end. A reduction that cannot be reserved is normally
722
+ * `0`, but can be negative (a credit on the next invoice) for a Stripe contract with no period
723
+ * end yet or when only the contract unit price is known.
661
724
  * - `isEstimate=true` (default when Stripe is not configured or data is unavailable):
662
- * `proratedAmount` is computed locally as `(newQuantity - currentQuantity) * unitPrice`.
663
- * - `isEstimate=false`: `proratedAmount` reflects Stripe's live proration calculation.
725
+ * `proratedAmount` is computed locally. `isEstimate=false`: it reflects Stripe's live
726
+ * proration calculation.
664
727
  *
665
728
  * `nextInvoiceAmount` is always a local estimate (`unitPrice * newQuantity`).
666
729
  *
667
- * `pricingUnavailable=true` indicates the plan uses custom pricing with a zero unit
668
- * price (Enterprise). Consumers should hide monetary amounts in this case.
730
+ * `pricingUnavailable=true` means custom pricing or an unverified contracted Stripe
731
+ * Price. Hide amounts; zero is not a quote. `custom_pricing` permits the existing
732
+ * unbilled seat-change flow. Require another preview before confirmation only when
733
+ * pricing is unavailable and the reason is not `custom_pricing`. `stripe_error` also
734
+ * covers invoice/address failures after the contract price is known; use
735
+ * `pricingUnavailable`, not the reason alone, to decide whether to hide amounts.
736
+ * `no_stripe_data` means invoice proration is unavailable even if the contract unit
737
+ * price is known. Portal seat PUT independently enforces subscription limits;
738
+ * external consumers should guide users to the FFID portal for seat changes.
669
739
  */
670
740
  interface FFIDSeatChangePreview {
671
741
  /** Discriminant for preview response variants (pairs with `FFIDPlanChangePreview.type`) */
@@ -676,20 +746,28 @@ interface FFIDSeatChangePreview {
676
746
  unitPrice: number;
677
747
  billingInterval: FFIDBillingInterval;
678
748
  /**
679
- * Prorated cost for the current billing period. Negative when seats are decreased
680
- * (credit). `0` when `pricingUnavailable === true` (Enterprise custom pricing).
749
+ * Amount charged now for the rest of the current billing period. A reserved seat reduction
750
+ * (`willApplyAtPeriodEnd: true`) is always `0`; see the type doc for reductions that cannot
751
+ * be reserved. Also `0` when `pricingUnavailable === true`; hide it instead of quoting zero.
681
752
  */
682
753
  proratedAmount: number;
683
754
  /** Next invoice full amount — always a local estimate (`unitPrice * newQuantity`) */
684
755
  nextInvoiceAmount: number;
685
756
  nextInvoiceDate: string | null;
686
757
  currency: FFIDSupportedCurrency;
687
- /** true when proratedAmount is estimated from local prices rather than Stripe proration data */
758
+ /** true when proratedAmount is a local estimate rather than Stripe invoice/proration data */
688
759
  isEstimate: boolean;
689
- /** true when unit price is 0 due to custom pricing (Enterprise) — hide monetary amounts */
760
+ /** Hide amounts: custom pricing or contracted Stripe Price could not be verified. */
690
761
  pricingUnavailable?: boolean;
691
762
  /** Reason why `isEstimate` is true. Only meaningful when `isEstimate === true`. */
692
763
  estimateReason?: 'no_stripe_data' | 'custom_pricing' | 'stripe_error';
764
+ /**
765
+ * `true` when the seat reduction would be reserved until the period end (8.0.0).
766
+ * Absent or `false` = the change applies immediately.
767
+ */
768
+ willApplyAtPeriodEnd?: boolean;
769
+ /** When the reserved seat count applies (present when `willApplyAtPeriodEnd` is `true`) */
770
+ effectiveDate?: string | null;
693
771
  lineItems: FFIDSeatChangeLineItem[];
694
772
  }
695
773
  /** Response from seat change preview endpoint */
@@ -774,6 +852,7 @@ interface FFIDProvisionUserProfileInput {
774
852
  /** Display name (1–255 chars). */
775
853
  displayName?: string;
776
854
  /** Company name (≤255 chars). */
855
+ /** @deprecated Accepted for compatibility but ignored by FFID. */
777
856
  companyName?: string;
778
857
  /** Department (≤255 chars). */
779
858
  department?: string;
@@ -1475,7 +1554,7 @@ interface FFIDUserProfile {
1475
1554
  avatarUrl: string | null;
1476
1555
  /** Phone number (nullable when not set) */
1477
1556
  phone: string | null;
1478
- /** Company name (nullable when not set) */
1557
+ /** @deprecated Individual employer name is retired; this field is always null. Use the organization entity's name. */
1479
1558
  companyName: string | null;
1480
1559
  /** Department (nullable when not set) */
1481
1560
  department: string | null;
@@ -1556,7 +1635,7 @@ interface FFIDUpdateUserProfileRequest {
1556
1635
  displayName?: string | null;
1557
1636
  /** Phone number (null clears the field) */
1558
1637
  phone?: string | null;
1559
- /** Company name (null clears the field) */
1638
+ /** @deprecated Accepted for compatibility but ignored. Use the organization entity's name. */
1560
1639
  companyName?: string | null;
1561
1640
  /** Department (null clears the field) */
1562
1641
  department?: string | null;
@@ -1922,6 +2001,7 @@ interface FFIDOAuthUserInfo {
1922
2001
  emailVerified?: boolean | undefined;
1923
2002
  name: string | null;
1924
2003
  picture: string | null;
2004
+ /** @deprecated Individual employer name is retired; always null. Use organizationName. */
1925
2005
  companyName?: string | null | undefined;
1926
2006
  department?: string | null | undefined;
1927
2007
  position?: string | null | undefined;
@@ -2356,7 +2436,9 @@ declare function createFFIDClient(config: FFIDConfig): {
2356
2436
  prompt?: FFIDPrompt;
2357
2437
  }) => string;
2358
2438
  getLogoutUrl: (postLogoutRedirectUri?: string) => string;
2359
- getSignupUrl: (redirectUrl?: string) => string;
2439
+ getSignupUrl: (redirectUrl?: string, options?: {
2440
+ inviteToken?: string;
2441
+ }) => string;
2360
2442
  createError: (code: string, message: string) => FFIDError;
2361
2443
  exchangeCodeForTokens: (code: string, codeVerifier?: string, opts?: ExchangeCodeForTokensOptions) => Promise<FFIDApiResponse<void>>;
2362
2444
  refreshAccessToken: () => Promise<FFIDApiResponse<void>>;