@feelflow/ffid-sdk 7.2.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.
- package/README.md +115 -5
- package/dist/{chunk-SOZ2B2ZL.cjs → chunk-RNCK5E3Y.cjs} +204 -12
- package/dist/{chunk-E2AJAVX6.js → chunk-YKBAFPX5.js} +195 -13
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-QNEFA3mv.d.ts → ffid-client-5GAPcRIG.d.ts} +105 -23
- package/dist/{ffid-client-BFgoVPOZ.d.cts → ffid-client-BaEmw7jP.d.cts} +105 -23
- package/dist/{index-BMKhKhzF.d.cts → index-BG7g99pK.d.cts} +1 -0
- package/dist/{index-BMKhKhzF.d.ts → index-BG7g99pK.d.ts} +1 -0
- package/dist/index.cjs +104 -64
- package/dist/index.d.cts +378 -26
- package/dist/index.d.ts +378 -26
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +128 -10
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +128 -10
- package/dist/server/test/index.d.cts +1 -1
- package/dist/server/test/index.d.ts +1 -1
- package/dist/webhooks/index.d.cts +55 -6
- package/dist/webhooks/index.d.ts +55 -6
- package/package.json +1 -1
|
@@ -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:
|
|
161
|
+
companyName: null,
|
|
162
162
|
department: raw.department ?? null,
|
|
163
163
|
position: raw.position ?? null,
|
|
164
164
|
phoneNumber: raw.phone_number ?? null,
|
|
@@ -467,7 +467,7 @@ function createVerifyAccessToken(deps) {
|
|
|
467
467
|
email_verified: introspectResponse.email_verified,
|
|
468
468
|
name: introspectResponse.name ?? null,
|
|
469
469
|
picture: introspectResponse.picture ?? null,
|
|
470
|
-
company_name:
|
|
470
|
+
company_name: null,
|
|
471
471
|
department: introspectResponse.department ?? null,
|
|
472
472
|
position: introspectResponse.position ?? null,
|
|
473
473
|
phone_number: introspectResponse.phone_number ?? null,
|
|
@@ -718,6 +718,24 @@ function validateSeatChangePreview(preview) {
|
|
|
718
718
|
`SDK: server returned malformed SeatChangePreview \u2014 estimateReason must be one of 'no_stripe_data' | 'custom_pricing' | 'stripe_error' (got ${JSON.stringify(p.estimateReason)})`
|
|
719
719
|
);
|
|
720
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
|
+
}
|
|
721
739
|
if (!Array.isArray(p.lineItems)) {
|
|
722
740
|
throw new FFIDSDKError(
|
|
723
741
|
MALFORMED_SEAT_PREVIEW_CODE,
|
|
@@ -1358,7 +1376,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
|
|
|
1358
1376
|
};
|
|
1359
1377
|
|
|
1360
1378
|
// src/client/version-check.ts
|
|
1361
|
-
var SDK_VERSION = "
|
|
1379
|
+
var SDK_VERSION = "8.0.0";
|
|
1362
1380
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1363
1381
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1364
1382
|
function sdkHeaders() {
|
|
@@ -2612,6 +2630,129 @@ function cleanupStateStorage(logger) {
|
|
|
2612
2630
|
}
|
|
2613
2631
|
}
|
|
2614
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
|
+
|
|
2615
2756
|
// src/client/redirect.ts
|
|
2616
2757
|
var OAUTH_AUTHORIZE_ENDPOINT = "/api/v1/oauth/authorize";
|
|
2617
2758
|
var AUTH_LOGOUT_ENDPOINT = "/api/v1/auth/logout";
|
|
@@ -2624,6 +2765,7 @@ var REDIRECT_LOOP_WINDOW_MS = 6e4;
|
|
|
2624
2765
|
var REDIRECT_LOOP_THRESHOLD = 3;
|
|
2625
2766
|
var storageReadFailureLogged = false;
|
|
2626
2767
|
var storageWriteFailureLogged = false;
|
|
2768
|
+
var ssrInviteTokenUnavailableLogged = false;
|
|
2627
2769
|
function isLoopDetectionDegraded() {
|
|
2628
2770
|
return storageReadFailureLogged || storageWriteFailureLogged;
|
|
2629
2771
|
}
|
|
@@ -2802,12 +2944,16 @@ function createRedirectMethods(deps) {
|
|
|
2802
2944
|
}
|
|
2803
2945
|
if (options?.screenHint === SCREEN_HINT_SIGNUP) {
|
|
2804
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
|
+
}
|
|
2805
2951
|
}
|
|
2806
2952
|
if (options?.prompt) {
|
|
2807
2953
|
params.set("prompt", options.prompt);
|
|
2808
2954
|
}
|
|
2809
2955
|
const authorizeUrl = `${baseUrl}${OAUTH_AUTHORIZE_ENDPOINT}?${params.toString()}`;
|
|
2810
|
-
logger.debug("Redirecting to authorize:", authorizeUrl);
|
|
2956
|
+
logger.debug("Redirecting to authorize:", redactAgencyInviteToken(authorizeUrl));
|
|
2811
2957
|
recordRedirectAttempt(authorizeKey, now, logger);
|
|
2812
2958
|
try {
|
|
2813
2959
|
window.location.href = authorizeUrl;
|
|
@@ -2826,7 +2972,7 @@ function createRedirectMethods(deps) {
|
|
|
2826
2972
|
return redirectToAuthorize(options);
|
|
2827
2973
|
}
|
|
2828
2974
|
const targetUrl = options?.screenHint === SCREEN_HINT_SIGNUP ? getSignupUrl() : getLoginUrl(void 0, options?.prompt ? { prompt: options.prompt } : void 0);
|
|
2829
|
-
logger.debug("Redirecting to auth page:", targetUrl);
|
|
2975
|
+
logger.debug("Redirecting to auth page:", redactAgencyInviteToken(targetUrl));
|
|
2830
2976
|
window.location.href = targetUrl;
|
|
2831
2977
|
return { success: true };
|
|
2832
2978
|
}
|
|
@@ -2843,7 +2989,7 @@ function createRedirectMethods(deps) {
|
|
|
2843
2989
|
const promptSuffix = options?.prompt ? `&prompt=${encodeURIComponent(options.prompt)}` : "";
|
|
2844
2990
|
return `${baseUrl}/login?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}${promptSuffix}`;
|
|
2845
2991
|
}
|
|
2846
|
-
function getSignupUrl(redirectUrl) {
|
|
2992
|
+
function getSignupUrl(redirectUrl, options) {
|
|
2847
2993
|
let redirect;
|
|
2848
2994
|
if (redirectUrl != null) {
|
|
2849
2995
|
redirect = redirectUrl;
|
|
@@ -2853,7 +2999,22 @@ function createRedirectMethods(deps) {
|
|
|
2853
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");
|
|
2854
3000
|
redirect = "";
|
|
2855
3001
|
}
|
|
2856
|
-
|
|
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
|
+
);
|
|
2857
3018
|
}
|
|
2858
3019
|
function getLogoutUrl(postLogoutRedirectUri) {
|
|
2859
3020
|
const url = new URL(`${baseUrl}${AUTH_LOGOUT_ENDPOINT}`);
|
|
@@ -2869,7 +3030,7 @@ function createRedirectMethods(deps) {
|
|
|
2869
3030
|
return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
|
|
2870
3031
|
}
|
|
2871
3032
|
const logoutUrl = getLogoutUrl(postLogoutRedirectUri);
|
|
2872
|
-
logger.debug("Redirecting to logout:", logoutUrl);
|
|
3033
|
+
logger.debug("Redirecting to logout:", redactAgencyInviteToken(logoutUrl));
|
|
2873
3034
|
window.location.href = logoutUrl;
|
|
2874
3035
|
return { success: true };
|
|
2875
3036
|
}
|
|
@@ -3482,11 +3643,11 @@ var EFFECTIVE_SUBSCRIPTION_STATUSES = [
|
|
|
3482
3643
|
"expired"
|
|
3483
3644
|
];
|
|
3484
3645
|
var PAST_DUE_GRACE_PERIOD_DAYS = 7;
|
|
3485
|
-
var
|
|
3486
|
-
var
|
|
3487
|
-
var
|
|
3646
|
+
var HOURS_PER_DAY2 = 24;
|
|
3647
|
+
var MINUTES_PER_HOUR2 = 60;
|
|
3648
|
+
var SECONDS_PER_MINUTE2 = 60;
|
|
3488
3649
|
var MS_PER_SECOND2 = 1e3;
|
|
3489
|
-
var MS_PER_DAY =
|
|
3650
|
+
var MS_PER_DAY = HOURS_PER_DAY2 * MINUTES_PER_HOUR2 * SECONDS_PER_MINUTE2 * MS_PER_SECOND2;
|
|
3490
3651
|
|
|
3491
3652
|
// src/subscriptions/compute-effective-status.ts
|
|
3492
3653
|
function isExpired(isoTimestamp, nowMs) {
|
|
@@ -3639,6 +3800,18 @@ var FFID_ERROR_CODES = {
|
|
|
3639
3800
|
TOKEN_EXPIRED: "TOKEN_EXPIRED",
|
|
3640
3801
|
STATE_MISMATCH_ERROR: "STATE_MISMATCH_ERROR"
|
|
3641
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
|
+
};
|
|
3642
3815
|
|
|
3643
3816
|
// src/client/ffid-client.ts
|
|
3644
3817
|
var UNAUTHORIZED_STATUS2 = 401;
|
|
@@ -4322,6 +4495,15 @@ function FFIDProvider({
|
|
|
4322
4495
|
}),
|
|
4323
4496
|
[serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId, timeout, tokenStore]
|
|
4324
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]);
|
|
4325
4507
|
const refresh = useCallback(async () => {
|
|
4326
4508
|
client.logger.debug("Refreshing session...");
|
|
4327
4509
|
try {
|
|
@@ -6297,4 +6479,4 @@ function FFIDInquiryForm({
|
|
|
6297
6479
|
);
|
|
6298
6480
|
}
|
|
6299
6481
|
|
|
6300
|
-
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
|
|
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
|
|
9
|
+
get: function () { return chunkRNCK5E3Y_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkRNCK5E3Y_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkRNCK5E3Y_cjs.FFIDInquiryForm; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkRNCK5E3Y_cjs.FFIDLoginButton; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkRNCK5E3Y_cjs.FFIDOrganizationSwitcher; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkRNCK5E3Y_cjs.FFIDSubscriptionBadge; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
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-
|
|
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-
|
|
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';
|
package/dist/components/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
* - `false`: immediate change. `effectiveDate` is always `null
|
|
626
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
663
|
-
*
|
|
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`
|
|
668
|
-
*
|
|
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
|
-
*
|
|
680
|
-
* (
|
|
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
|
|
758
|
+
/** true when proratedAmount is a local estimate rather than Stripe invoice/proration data */
|
|
688
759
|
isEstimate: boolean;
|
|
689
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
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>>;
|