@feelflow/ffid-sdk 5.6.0 → 5.8.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/dist/{chunk-WGSEZSZI.cjs → chunk-MRHDPB7H.cjs} +32 -8
- package/dist/{chunk-4SJKXEYB.js → chunk-Z6COUAR6.js} +32 -8
- 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-CmxQxkoK.d.cts → ffid-client-BhopNmnq.d.cts} +30 -1
- package/dist/{ffid-client-BXl7Dop7.d.ts → ffid-client-DoGYvIll.d.ts} +30 -1
- package/dist/{index-_oO5sHjX.d.cts → index-DeegKrLW.d.cts} +47 -1
- package/dist/{index-_oO5sHjX.d.ts → index-DeegKrLW.d.ts} +47 -1
- package/dist/index.cjs +36 -36
- package/dist/index.d.cts +27 -3
- package/dist/index.d.ts +27 -3
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +26 -5
- package/dist/server/index.d.cts +3 -3
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.js +26 -5
- package/dist/server/test/index.d.cts +2 -2
- package/dist/server/test/index.d.ts +2 -2
- package/dist/{types-5g_Bg6Ey.d.cts → types-BYdtyO_2.d.cts} +18 -1
- package/dist/{types-5g_Bg6Ey.d.ts → types-BYdtyO_2.d.ts} +18 -1
- package/dist/webhooks/index.d.cts +1 -1
- package/dist/webhooks/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -130,7 +130,15 @@ function normalizeUserinfo(raw) {
|
|
|
130
130
|
seatModel: raw.subscription.seat_model ?? null,
|
|
131
131
|
memberRole: raw.subscription.member_role ?? null,
|
|
132
132
|
organizationId: raw.subscription.organization_id ?? null,
|
|
133
|
-
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false
|
|
133
|
+
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false,
|
|
134
|
+
// #3464: legacy FFID (< this issue) omits the field on the wire.
|
|
135
|
+
// The "unknown" axis is unused — no consumer differentiates "server
|
|
136
|
+
// didn't tell us" from "definitely not scheduled" because the
|
|
137
|
+
// companion `effectiveStatus` already returns `'active'` (not
|
|
138
|
+
// `'active_canceling'`) for legacy backends. Defaulting to `false`
|
|
139
|
+
// here keeps the downstream contract a plain boolean.
|
|
140
|
+
cancelAtPeriodEnd: raw.subscription.cancel_at_period_end ?? false,
|
|
141
|
+
currentPeriodEnd: raw.subscription.current_period_end ?? null
|
|
134
142
|
} : void 0
|
|
135
143
|
};
|
|
136
144
|
}
|
|
@@ -147,8 +155,14 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
|
|
|
147
155
|
planCode: subscription.planCode,
|
|
148
156
|
planName: subscription.planCode,
|
|
149
157
|
status: subscription.status,
|
|
150
|
-
|
|
158
|
+
// #3464: userinfo now carries `current_period_end` and
|
|
159
|
+
// `cancel_at_period_end`. Pre-#3464 FFID backends still omit them on
|
|
160
|
+
// the wire (`currentPeriodEnd === null` / `cancelAtPeriodEnd === false`
|
|
161
|
+
// after `normalizeUserinfo` defaults), so the session helper sees
|
|
162
|
+
// plain `'active'` — identical to pre-#3464 behaviour.
|
|
163
|
+
currentPeriodEnd: subscription.currentPeriodEnd,
|
|
151
164
|
trialEnd: null,
|
|
165
|
+
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
|
|
152
166
|
seatModel: subscription.seatModel ?? void 0,
|
|
153
167
|
memberRole: subscription.memberRole ?? void 0,
|
|
154
168
|
organizationId: subscription.organizationId
|
|
@@ -842,7 +856,7 @@ function createProfileMethods(deps) {
|
|
|
842
856
|
}
|
|
843
857
|
|
|
844
858
|
// src/client/version-check.ts
|
|
845
|
-
var SDK_VERSION = "5.
|
|
859
|
+
var SDK_VERSION = "5.8.0";
|
|
846
860
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
847
861
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
848
862
|
function sdkHeaders() {
|
|
@@ -2247,7 +2261,7 @@ function isExpired(isoTimestamp, nowMs) {
|
|
|
2247
2261
|
return parsed < nowMs;
|
|
2248
2262
|
}
|
|
2249
2263
|
function computeEffectiveStatusFromSession(input, nowMs = Date.now()) {
|
|
2250
|
-
const { status, currentPeriodEnd, trialEnd, pastDueSince } = input;
|
|
2264
|
+
const { status, currentPeriodEnd, trialEnd, pastDueSince, cancelAtPeriodEnd = false } = input;
|
|
2251
2265
|
switch (status) {
|
|
2252
2266
|
case "trialing": {
|
|
2253
2267
|
const relevantEnd = trialEnd ?? currentPeriodEnd;
|
|
@@ -2256,7 +2270,8 @@ function computeEffectiveStatusFromSession(input, nowMs = Date.now()) {
|
|
|
2256
2270
|
}
|
|
2257
2271
|
case "active": {
|
|
2258
2272
|
const expired = isExpired(currentPeriodEnd, nowMs);
|
|
2259
|
-
|
|
2273
|
+
if (expired === true) return "expired";
|
|
2274
|
+
return cancelAtPeriodEnd ? "active_canceling" : "active";
|
|
2260
2275
|
}
|
|
2261
2276
|
case "past_due": {
|
|
2262
2277
|
const baselineIso = pastDueSince ?? currentPeriodEnd;
|
|
@@ -2285,6 +2300,7 @@ function computeEffectiveStatusFromSession(input, nowMs = Date.now()) {
|
|
|
2285
2300
|
// src/subscriptions/userinfo-helpers.ts
|
|
2286
2301
|
var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
|
|
2287
2302
|
"active",
|
|
2303
|
+
"active_canceling",
|
|
2288
2304
|
"past_due_grace"
|
|
2289
2305
|
];
|
|
2290
2306
|
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
@@ -2338,6 +2354,12 @@ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
|
2338
2354
|
var DEFAULT_ALLOW_GRACE = true;
|
|
2339
2355
|
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2340
2356
|
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2357
|
+
var DENIAL_REASON_BY_DENYING_STATUS = {
|
|
2358
|
+
blocked: "blocked",
|
|
2359
|
+
canceled: "canceled",
|
|
2360
|
+
expired: "expired",
|
|
2361
|
+
trial_expired: "trial_expired"
|
|
2362
|
+
};
|
|
2341
2363
|
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2342
2364
|
if (params.hasAccess) {
|
|
2343
2365
|
return null;
|
|
@@ -2348,10 +2370,10 @@ function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
|
2348
2370
|
if (params.isGrace && !allowGrace) {
|
|
2349
2371
|
return "grace_disallowed";
|
|
2350
2372
|
}
|
|
2351
|
-
if (
|
|
2373
|
+
if (ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(params.effectiveStatus)) {
|
|
2352
2374
|
return "blocked";
|
|
2353
2375
|
}
|
|
2354
|
-
return params.effectiveStatus;
|
|
2376
|
+
return DENIAL_REASON_BY_DENYING_STATUS[params.effectiveStatus];
|
|
2355
2377
|
}
|
|
2356
2378
|
function toServiceAccessDecision(response, allowGrace) {
|
|
2357
2379
|
const effectiveStatus = response.effectiveStatus ?? null;
|
|
@@ -3522,6 +3544,7 @@ function FFIDOrganizationSwitcher({
|
|
|
3522
3544
|
}
|
|
3523
3545
|
var ACCESS_GRANTING_STATUSES = [
|
|
3524
3546
|
"active",
|
|
3547
|
+
"active_canceling",
|
|
3525
3548
|
"past_due_grace"
|
|
3526
3549
|
];
|
|
3527
3550
|
var BLOCKING_STATUSES = [
|
|
@@ -3558,7 +3581,8 @@ function useSubscription() {
|
|
|
3558
3581
|
// のため `computeEffectiveStatusFromSession` 内で currentPeriodEnd を
|
|
3559
3582
|
// fallback に使う (Stripe は period end 近辺で past_due にする)。
|
|
3560
3583
|
// Canonical な verdict が必要な consumer は `/ext/check` を直接呼ぶ。
|
|
3561
|
-
pastDueSince: void 0
|
|
3584
|
+
pastDueSince: void 0,
|
|
3585
|
+
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd
|
|
3562
3586
|
});
|
|
3563
3587
|
}, [subscription]);
|
|
3564
3588
|
const isGrace = effectiveStatus === "past_due_grace";
|
|
@@ -128,7 +128,15 @@ function normalizeUserinfo(raw) {
|
|
|
128
128
|
seatModel: raw.subscription.seat_model ?? null,
|
|
129
129
|
memberRole: raw.subscription.member_role ?? null,
|
|
130
130
|
organizationId: raw.subscription.organization_id ?? null,
|
|
131
|
-
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false
|
|
131
|
+
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false,
|
|
132
|
+
// #3464: legacy FFID (< this issue) omits the field on the wire.
|
|
133
|
+
// The "unknown" axis is unused — no consumer differentiates "server
|
|
134
|
+
// didn't tell us" from "definitely not scheduled" because the
|
|
135
|
+
// companion `effectiveStatus` already returns `'active'` (not
|
|
136
|
+
// `'active_canceling'`) for legacy backends. Defaulting to `false`
|
|
137
|
+
// here keeps the downstream contract a plain boolean.
|
|
138
|
+
cancelAtPeriodEnd: raw.subscription.cancel_at_period_end ?? false,
|
|
139
|
+
currentPeriodEnd: raw.subscription.current_period_end ?? null
|
|
132
140
|
} : void 0
|
|
133
141
|
};
|
|
134
142
|
}
|
|
@@ -145,8 +153,14 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
|
|
|
145
153
|
planCode: subscription.planCode,
|
|
146
154
|
planName: subscription.planCode,
|
|
147
155
|
status: subscription.status,
|
|
148
|
-
|
|
156
|
+
// #3464: userinfo now carries `current_period_end` and
|
|
157
|
+
// `cancel_at_period_end`. Pre-#3464 FFID backends still omit them on
|
|
158
|
+
// the wire (`currentPeriodEnd === null` / `cancelAtPeriodEnd === false`
|
|
159
|
+
// after `normalizeUserinfo` defaults), so the session helper sees
|
|
160
|
+
// plain `'active'` — identical to pre-#3464 behaviour.
|
|
161
|
+
currentPeriodEnd: subscription.currentPeriodEnd,
|
|
149
162
|
trialEnd: null,
|
|
163
|
+
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
|
|
150
164
|
seatModel: subscription.seatModel ?? void 0,
|
|
151
165
|
memberRole: subscription.memberRole ?? void 0,
|
|
152
166
|
organizationId: subscription.organizationId
|
|
@@ -840,7 +854,7 @@ function createProfileMethods(deps) {
|
|
|
840
854
|
}
|
|
841
855
|
|
|
842
856
|
// src/client/version-check.ts
|
|
843
|
-
var SDK_VERSION = "5.
|
|
857
|
+
var SDK_VERSION = "5.8.0";
|
|
844
858
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
845
859
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
846
860
|
function sdkHeaders() {
|
|
@@ -2245,7 +2259,7 @@ function isExpired(isoTimestamp, nowMs) {
|
|
|
2245
2259
|
return parsed < nowMs;
|
|
2246
2260
|
}
|
|
2247
2261
|
function computeEffectiveStatusFromSession(input, nowMs = Date.now()) {
|
|
2248
|
-
const { status, currentPeriodEnd, trialEnd, pastDueSince } = input;
|
|
2262
|
+
const { status, currentPeriodEnd, trialEnd, pastDueSince, cancelAtPeriodEnd = false } = input;
|
|
2249
2263
|
switch (status) {
|
|
2250
2264
|
case "trialing": {
|
|
2251
2265
|
const relevantEnd = trialEnd ?? currentPeriodEnd;
|
|
@@ -2254,7 +2268,8 @@ function computeEffectiveStatusFromSession(input, nowMs = Date.now()) {
|
|
|
2254
2268
|
}
|
|
2255
2269
|
case "active": {
|
|
2256
2270
|
const expired = isExpired(currentPeriodEnd, nowMs);
|
|
2257
|
-
|
|
2271
|
+
if (expired === true) return "expired";
|
|
2272
|
+
return cancelAtPeriodEnd ? "active_canceling" : "active";
|
|
2258
2273
|
}
|
|
2259
2274
|
case "past_due": {
|
|
2260
2275
|
const baselineIso = pastDueSince ?? currentPeriodEnd;
|
|
@@ -2283,6 +2298,7 @@ function computeEffectiveStatusFromSession(input, nowMs = Date.now()) {
|
|
|
2283
2298
|
// src/subscriptions/userinfo-helpers.ts
|
|
2284
2299
|
var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
|
|
2285
2300
|
"active",
|
|
2301
|
+
"active_canceling",
|
|
2286
2302
|
"past_due_grace"
|
|
2287
2303
|
];
|
|
2288
2304
|
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
@@ -2336,6 +2352,12 @@ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
|
2336
2352
|
var DEFAULT_ALLOW_GRACE = true;
|
|
2337
2353
|
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2338
2354
|
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2355
|
+
var DENIAL_REASON_BY_DENYING_STATUS = {
|
|
2356
|
+
blocked: "blocked",
|
|
2357
|
+
canceled: "canceled",
|
|
2358
|
+
expired: "expired",
|
|
2359
|
+
trial_expired: "trial_expired"
|
|
2360
|
+
};
|
|
2339
2361
|
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2340
2362
|
if (params.hasAccess) {
|
|
2341
2363
|
return null;
|
|
@@ -2346,10 +2368,10 @@ function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
|
2346
2368
|
if (params.isGrace && !allowGrace) {
|
|
2347
2369
|
return "grace_disallowed";
|
|
2348
2370
|
}
|
|
2349
|
-
if (
|
|
2371
|
+
if (ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(params.effectiveStatus)) {
|
|
2350
2372
|
return "blocked";
|
|
2351
2373
|
}
|
|
2352
|
-
return params.effectiveStatus;
|
|
2374
|
+
return DENIAL_REASON_BY_DENYING_STATUS[params.effectiveStatus];
|
|
2353
2375
|
}
|
|
2354
2376
|
function toServiceAccessDecision(response, allowGrace) {
|
|
2355
2377
|
const effectiveStatus = response.effectiveStatus ?? null;
|
|
@@ -3520,6 +3542,7 @@ function FFIDOrganizationSwitcher({
|
|
|
3520
3542
|
}
|
|
3521
3543
|
var ACCESS_GRANTING_STATUSES = [
|
|
3522
3544
|
"active",
|
|
3545
|
+
"active_canceling",
|
|
3523
3546
|
"past_due_grace"
|
|
3524
3547
|
];
|
|
3525
3548
|
var BLOCKING_STATUSES = [
|
|
@@ -3556,7 +3579,8 @@ function useSubscription() {
|
|
|
3556
3579
|
// のため `computeEffectiveStatusFromSession` 内で currentPeriodEnd を
|
|
3557
3580
|
// fallback に使う (Stripe は period end 近辺で past_due にする)。
|
|
3558
3581
|
// Canonical な verdict が必要な consumer は `/ext/check` を直接呼ぶ。
|
|
3559
|
-
pastDueSince: void 0
|
|
3582
|
+
pastDueSince: void 0,
|
|
3583
|
+
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd
|
|
3560
3584
|
});
|
|
3561
3585
|
}, [subscription]);
|
|
3562
3586
|
const isGrace = effectiveStatus === "past_due_grace";
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkMRHDPB7H_cjs = require('../chunk-MRHDPB7H.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 chunkMRHDPB7H_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDInquiryForm; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDLoginButton; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDOrganizationSwitcher; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDSubscriptionBadge; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDUserMenu; }
|
|
34
34
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { M as FFIDAnnouncementBadge, al as FFIDAnnouncementBadgeClassNames, am as FFIDAnnouncementBadgeProps, N as FFIDAnnouncementList, an as FFIDAnnouncementListClassNames, ao as FFIDAnnouncementListProps, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, ap as FFIDLoginButtonProps, a7 as FFIDOrganizationSwitcher, aq as FFIDOrganizationSwitcherClassNames, ar as FFIDOrganizationSwitcherProps, ac as FFIDSubscriptionBadge, as as FFIDSubscriptionBadgeClassNames, at as FFIDSubscriptionBadgeProps, ae as FFIDUserMenu, au as FFIDUserMenuClassNames, av as FFIDUserMenuProps } from '../index-
|
|
1
|
+
export { M as FFIDAnnouncementBadge, al as FFIDAnnouncementBadgeClassNames, am as FFIDAnnouncementBadgeProps, N as FFIDAnnouncementList, an as FFIDAnnouncementListClassNames, ao as FFIDAnnouncementListProps, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, ap as FFIDLoginButtonProps, a7 as FFIDOrganizationSwitcher, aq as FFIDOrganizationSwitcherClassNames, ar as FFIDOrganizationSwitcherProps, ac as FFIDSubscriptionBadge, as as FFIDSubscriptionBadgeClassNames, at as FFIDSubscriptionBadgeProps, ae as FFIDUserMenu, au as FFIDUserMenuClassNames, av as FFIDUserMenuProps } from '../index-DeegKrLW.cjs';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import 'react';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { M as FFIDAnnouncementBadge, al as FFIDAnnouncementBadgeClassNames, am as FFIDAnnouncementBadgeProps, N as FFIDAnnouncementList, an as FFIDAnnouncementListClassNames, ao as FFIDAnnouncementListProps, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, ap as FFIDLoginButtonProps, a7 as FFIDOrganizationSwitcher, aq as FFIDOrganizationSwitcherClassNames, ar as FFIDOrganizationSwitcherProps, ac as FFIDSubscriptionBadge, as as FFIDSubscriptionBadgeClassNames, at as FFIDSubscriptionBadgeProps, ae as FFIDUserMenu, au as FFIDUserMenuClassNames, av as FFIDUserMenuProps } from '../index-
|
|
1
|
+
export { M as FFIDAnnouncementBadge, al as FFIDAnnouncementBadgeClassNames, am as FFIDAnnouncementBadgeProps, N as FFIDAnnouncementList, an as FFIDAnnouncementListClassNames, ao as FFIDAnnouncementListProps, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, ap as FFIDLoginButtonProps, a7 as FFIDOrganizationSwitcher, aq as FFIDOrganizationSwitcherClassNames, ar as FFIDOrganizationSwitcherProps, ac as FFIDSubscriptionBadge, as as FFIDSubscriptionBadgeClassNames, at as FFIDSubscriptionBadgeProps, ae as FFIDUserMenu, au as FFIDUserMenuClassNames, av as FFIDUserMenuProps } from '../index-DeegKrLW.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-Z6COUAR6.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EffectiveSubscriptionStatus } from './types-
|
|
1
|
+
import { E as EffectiveSubscriptionStatus } from './types-BYdtyO_2.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Inquiry types exposed by the FFID SDK.
|
|
@@ -724,6 +724,16 @@ interface FFIDSubscription {
|
|
|
724
724
|
currentPeriodEnd: string | null;
|
|
725
725
|
/** Trial end date (null if not a trial or no trial_end set) */
|
|
726
726
|
trialEnd: string | null;
|
|
727
|
+
/**
|
|
728
|
+
* Whether the subscription is scheduled to cancel at the end of the current
|
|
729
|
+
* billing period (Stripe `cancel_at_period_end`). Optional for backward
|
|
730
|
+
* compatibility with FFID backends that pre-date #3460 — when absent,
|
|
731
|
+
* `useSubscription` treats the value as `false` and surfaces plain `active`.
|
|
732
|
+
* When `true` and the period has not yet ended, `effectiveStatus` becomes
|
|
733
|
+
* `active_canceling` so consumers can render a cancellation-scheduled badge
|
|
734
|
+
* + reactivation CTA without losing access.
|
|
735
|
+
*/
|
|
736
|
+
cancelAtPeriodEnd?: boolean;
|
|
727
737
|
/** Service seat model (available when sourced from OAuth userinfo) */
|
|
728
738
|
seatModel?: FFIDSeatModel | undefined;
|
|
729
739
|
/** Member role in the resolved organization context */
|
|
@@ -748,6 +758,25 @@ interface FFIDOAuthUserInfoSubscription {
|
|
|
748
758
|
memberRole: FFIDOAuthUserInfoMemberRole | null;
|
|
749
759
|
organizationId: string | null;
|
|
750
760
|
hasSeatAssignment: boolean | null;
|
|
761
|
+
/**
|
|
762
|
+
* Stripe `cancel_at_period_end` (#3464, SDK 5.8.0). `true` while the
|
|
763
|
+
* subscription is scheduled to terminate at `currentPeriodEnd`. The
|
|
764
|
+
* `normalizeUserinfo` boundary defaults the wire field to `false` when
|
|
765
|
+
* the server omits it (older FFID pre-#3464), so consumers always see
|
|
766
|
+
* a plain boolean and never branch on an "unknown" sentinel — the
|
|
767
|
+
* companion `effectiveStatus` already returns `'active'` (not
|
|
768
|
+
* `'active_canceling'`) for legacy backends since `cancel_at_period_end`
|
|
769
|
+
* is implicitly false there.
|
|
770
|
+
*/
|
|
771
|
+
cancelAtPeriodEnd: boolean;
|
|
772
|
+
/**
|
|
773
|
+
* ISO timestamp of the current billing period end (#3464, SDK 5.8.0).
|
|
774
|
+
* `null` for free / seatless plans, or when serving an older FFID
|
|
775
|
+
* (pre-#3464) that does not populate the field. Exposed so callers
|
|
776
|
+
* can display the cancellation effective date without an `/ext/check`
|
|
777
|
+
* round-trip.
|
|
778
|
+
*/
|
|
779
|
+
currentPeriodEnd: string | null;
|
|
751
780
|
}
|
|
752
781
|
/**
|
|
753
782
|
* Unified user-identity shape returned by `getSession()` (→ `/oauth/userinfo`)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EffectiveSubscriptionStatus } from './types-
|
|
1
|
+
import { E as EffectiveSubscriptionStatus } from './types-BYdtyO_2.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Inquiry types exposed by the FFID SDK.
|
|
@@ -724,6 +724,16 @@ interface FFIDSubscription {
|
|
|
724
724
|
currentPeriodEnd: string | null;
|
|
725
725
|
/** Trial end date (null if not a trial or no trial_end set) */
|
|
726
726
|
trialEnd: string | null;
|
|
727
|
+
/**
|
|
728
|
+
* Whether the subscription is scheduled to cancel at the end of the current
|
|
729
|
+
* billing period (Stripe `cancel_at_period_end`). Optional for backward
|
|
730
|
+
* compatibility with FFID backends that pre-date #3460 — when absent,
|
|
731
|
+
* `useSubscription` treats the value as `false` and surfaces plain `active`.
|
|
732
|
+
* When `true` and the period has not yet ended, `effectiveStatus` becomes
|
|
733
|
+
* `active_canceling` so consumers can render a cancellation-scheduled badge
|
|
734
|
+
* + reactivation CTA without losing access.
|
|
735
|
+
*/
|
|
736
|
+
cancelAtPeriodEnd?: boolean;
|
|
727
737
|
/** Service seat model (available when sourced from OAuth userinfo) */
|
|
728
738
|
seatModel?: FFIDSeatModel | undefined;
|
|
729
739
|
/** Member role in the resolved organization context */
|
|
@@ -748,6 +758,25 @@ interface FFIDOAuthUserInfoSubscription {
|
|
|
748
758
|
memberRole: FFIDOAuthUserInfoMemberRole | null;
|
|
749
759
|
organizationId: string | null;
|
|
750
760
|
hasSeatAssignment: boolean | null;
|
|
761
|
+
/**
|
|
762
|
+
* Stripe `cancel_at_period_end` (#3464, SDK 5.8.0). `true` while the
|
|
763
|
+
* subscription is scheduled to terminate at `currentPeriodEnd`. The
|
|
764
|
+
* `normalizeUserinfo` boundary defaults the wire field to `false` when
|
|
765
|
+
* the server omits it (older FFID pre-#3464), so consumers always see
|
|
766
|
+
* a plain boolean and never branch on an "unknown" sentinel — the
|
|
767
|
+
* companion `effectiveStatus` already returns `'active'` (not
|
|
768
|
+
* `'active_canceling'`) for legacy backends since `cancel_at_period_end`
|
|
769
|
+
* is implicitly false there.
|
|
770
|
+
*/
|
|
771
|
+
cancelAtPeriodEnd: boolean;
|
|
772
|
+
/**
|
|
773
|
+
* ISO timestamp of the current billing period end (#3464, SDK 5.8.0).
|
|
774
|
+
* `null` for free / seatless plans, or when serving an older FFID
|
|
775
|
+
* (pre-#3464) that does not populate the field. Exposed so callers
|
|
776
|
+
* can display the cancellation effective date without an `/ext/check`
|
|
777
|
+
* round-trip.
|
|
778
|
+
*/
|
|
779
|
+
currentPeriodEnd: string | null;
|
|
751
780
|
}
|
|
752
781
|
/**
|
|
753
782
|
* Unified user-identity shape returned by `getSession()` (→ `/oauth/userinfo`)
|
|
@@ -41,6 +41,10 @@ interface FFIDCacheConfig {
|
|
|
41
41
|
* branch on a single value:
|
|
42
42
|
*
|
|
43
43
|
* - `active` — normal paying subscription; grant full access.
|
|
44
|
+
* - `active_canceling` — paying subscription with `cancel_at_period_end=true`.
|
|
45
|
+
* Access stays live until `currentPeriodEnd`; callers SHOULD surface a
|
|
46
|
+
* "cancellation scheduled" badge and a reactivation CTA. Session-only
|
|
47
|
+
* refinement of `active` — see the asymmetry note below.
|
|
44
48
|
* - `past_due_grace` — payment failed but FFID is still retrying. Service
|
|
45
49
|
* SHOULD keep access and surface a recovery banner.
|
|
46
50
|
* - `blocked` — payment dunning exhausted (`past_due` over grace,
|
|
@@ -53,10 +57,23 @@ interface FFIDCacheConfig {
|
|
|
53
57
|
* This is the FFID-internal runtime-expired case (see
|
|
54
58
|
* `getEffectiveSubscriptionStatus` on the server). Deny access.
|
|
55
59
|
*
|
|
60
|
+
* **`active_canceling` is mirrored on the server (#3464, SDK 5.8.0).**
|
|
61
|
+
* Earlier (#3460, SDK 5.7.0) the literal was a session-only enrichment;
|
|
62
|
+
* since FFID #3464 the backend `EffectiveSubscriptionStatus` and both
|
|
63
|
+
* `/api/v1/subscriptions/ext/check` + `/oauth/userinfo` emit
|
|
64
|
+
* `active_canceling` directly when `cancel_at_period_end=true` and the
|
|
65
|
+
* period is still live. SDK consumers receive the same literal whether
|
|
66
|
+
* they read it from the session-derived `computeEffectiveStatusFromSession`
|
|
67
|
+
* or the server-derived `effectiveStatus` on the userinfo / ext-check
|
|
68
|
+
* paths. Pre-#3464 FFID backends omit `cancelAtPeriodEnd` on the wire; the
|
|
69
|
+
* SDK `normalizeUserinfo` boundary defaults it to `false`, so downstream
|
|
70
|
+
* consumers see a plain boolean and `computeEffectiveStatus` returns the
|
|
71
|
+
* original `'active'` verdict for legacy deployments.
|
|
72
|
+
*
|
|
56
73
|
* @see /api/v1/subscriptions/ext/check
|
|
57
74
|
* @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
|
|
58
75
|
*/
|
|
59
|
-
type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
76
|
+
type EffectiveSubscriptionStatus = 'active' | 'active_canceling' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
60
77
|
|
|
61
78
|
/**
|
|
62
79
|
* Canonical service-access types for subscription lifecycle decisions.
|
|
@@ -230,6 +247,16 @@ interface FFIDSubscription {
|
|
|
230
247
|
currentPeriodEnd: string | null;
|
|
231
248
|
/** Trial end date (null if not a trial or no trial_end set) */
|
|
232
249
|
trialEnd: string | null;
|
|
250
|
+
/**
|
|
251
|
+
* Whether the subscription is scheduled to cancel at the end of the current
|
|
252
|
+
* billing period (Stripe `cancel_at_period_end`). Optional for backward
|
|
253
|
+
* compatibility with FFID backends that pre-date #3460 — when absent,
|
|
254
|
+
* `useSubscription` treats the value as `false` and surfaces plain `active`.
|
|
255
|
+
* When `true` and the period has not yet ended, `effectiveStatus` becomes
|
|
256
|
+
* `active_canceling` so consumers can render a cancellation-scheduled badge
|
|
257
|
+
* + reactivation CTA without losing access.
|
|
258
|
+
*/
|
|
259
|
+
cancelAtPeriodEnd?: boolean;
|
|
233
260
|
/** Service seat model (available when sourced from OAuth userinfo) */
|
|
234
261
|
seatModel?: FFIDSeatModel | undefined;
|
|
235
262
|
/** Member role in the resolved organization context */
|
|
@@ -254,6 +281,25 @@ interface FFIDOAuthUserInfoSubscription {
|
|
|
254
281
|
memberRole: FFIDOAuthUserInfoMemberRole | null;
|
|
255
282
|
organizationId: string | null;
|
|
256
283
|
hasSeatAssignment: boolean | null;
|
|
284
|
+
/**
|
|
285
|
+
* Stripe `cancel_at_period_end` (#3464, SDK 5.8.0). `true` while the
|
|
286
|
+
* subscription is scheduled to terminate at `currentPeriodEnd`. The
|
|
287
|
+
* `normalizeUserinfo` boundary defaults the wire field to `false` when
|
|
288
|
+
* the server omits it (older FFID pre-#3464), so consumers always see
|
|
289
|
+
* a plain boolean and never branch on an "unknown" sentinel — the
|
|
290
|
+
* companion `effectiveStatus` already returns `'active'` (not
|
|
291
|
+
* `'active_canceling'`) for legacy backends since `cancel_at_period_end`
|
|
292
|
+
* is implicitly false there.
|
|
293
|
+
*/
|
|
294
|
+
cancelAtPeriodEnd: boolean;
|
|
295
|
+
/**
|
|
296
|
+
* ISO timestamp of the current billing period end (#3464, SDK 5.8.0).
|
|
297
|
+
* `null` for free / seatless plans, or when serving an older FFID
|
|
298
|
+
* (pre-#3464) that does not populate the field. Exposed so callers
|
|
299
|
+
* can display the cancellation effective date without an `/ext/check`
|
|
300
|
+
* round-trip.
|
|
301
|
+
*/
|
|
302
|
+
currentPeriodEnd: string | null;
|
|
257
303
|
}
|
|
258
304
|
/**
|
|
259
305
|
* Unified user-identity shape returned by `getSession()` (→ `/oauth/userinfo`)
|
|
@@ -41,6 +41,10 @@ interface FFIDCacheConfig {
|
|
|
41
41
|
* branch on a single value:
|
|
42
42
|
*
|
|
43
43
|
* - `active` — normal paying subscription; grant full access.
|
|
44
|
+
* - `active_canceling` — paying subscription with `cancel_at_period_end=true`.
|
|
45
|
+
* Access stays live until `currentPeriodEnd`; callers SHOULD surface a
|
|
46
|
+
* "cancellation scheduled" badge and a reactivation CTA. Session-only
|
|
47
|
+
* refinement of `active` — see the asymmetry note below.
|
|
44
48
|
* - `past_due_grace` — payment failed but FFID is still retrying. Service
|
|
45
49
|
* SHOULD keep access and surface a recovery banner.
|
|
46
50
|
* - `blocked` — payment dunning exhausted (`past_due` over grace,
|
|
@@ -53,10 +57,23 @@ interface FFIDCacheConfig {
|
|
|
53
57
|
* This is the FFID-internal runtime-expired case (see
|
|
54
58
|
* `getEffectiveSubscriptionStatus` on the server). Deny access.
|
|
55
59
|
*
|
|
60
|
+
* **`active_canceling` is mirrored on the server (#3464, SDK 5.8.0).**
|
|
61
|
+
* Earlier (#3460, SDK 5.7.0) the literal was a session-only enrichment;
|
|
62
|
+
* since FFID #3464 the backend `EffectiveSubscriptionStatus` and both
|
|
63
|
+
* `/api/v1/subscriptions/ext/check` + `/oauth/userinfo` emit
|
|
64
|
+
* `active_canceling` directly when `cancel_at_period_end=true` and the
|
|
65
|
+
* period is still live. SDK consumers receive the same literal whether
|
|
66
|
+
* they read it from the session-derived `computeEffectiveStatusFromSession`
|
|
67
|
+
* or the server-derived `effectiveStatus` on the userinfo / ext-check
|
|
68
|
+
* paths. Pre-#3464 FFID backends omit `cancelAtPeriodEnd` on the wire; the
|
|
69
|
+
* SDK `normalizeUserinfo` boundary defaults it to `false`, so downstream
|
|
70
|
+
* consumers see a plain boolean and `computeEffectiveStatus` returns the
|
|
71
|
+
* original `'active'` verdict for legacy deployments.
|
|
72
|
+
*
|
|
56
73
|
* @see /api/v1/subscriptions/ext/check
|
|
57
74
|
* @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
|
|
58
75
|
*/
|
|
59
|
-
type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
76
|
+
type EffectiveSubscriptionStatus = 'active' | 'active_canceling' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
60
77
|
|
|
61
78
|
/**
|
|
62
79
|
* Canonical service-access types for subscription lifecycle decisions.
|
|
@@ -230,6 +247,16 @@ interface FFIDSubscription {
|
|
|
230
247
|
currentPeriodEnd: string | null;
|
|
231
248
|
/** Trial end date (null if not a trial or no trial_end set) */
|
|
232
249
|
trialEnd: string | null;
|
|
250
|
+
/**
|
|
251
|
+
* Whether the subscription is scheduled to cancel at the end of the current
|
|
252
|
+
* billing period (Stripe `cancel_at_period_end`). Optional for backward
|
|
253
|
+
* compatibility with FFID backends that pre-date #3460 — when absent,
|
|
254
|
+
* `useSubscription` treats the value as `false` and surfaces plain `active`.
|
|
255
|
+
* When `true` and the period has not yet ended, `effectiveStatus` becomes
|
|
256
|
+
* `active_canceling` so consumers can render a cancellation-scheduled badge
|
|
257
|
+
* + reactivation CTA without losing access.
|
|
258
|
+
*/
|
|
259
|
+
cancelAtPeriodEnd?: boolean;
|
|
233
260
|
/** Service seat model (available when sourced from OAuth userinfo) */
|
|
234
261
|
seatModel?: FFIDSeatModel | undefined;
|
|
235
262
|
/** Member role in the resolved organization context */
|
|
@@ -254,6 +281,25 @@ interface FFIDOAuthUserInfoSubscription {
|
|
|
254
281
|
memberRole: FFIDOAuthUserInfoMemberRole | null;
|
|
255
282
|
organizationId: string | null;
|
|
256
283
|
hasSeatAssignment: boolean | null;
|
|
284
|
+
/**
|
|
285
|
+
* Stripe `cancel_at_period_end` (#3464, SDK 5.8.0). `true` while the
|
|
286
|
+
* subscription is scheduled to terminate at `currentPeriodEnd`. The
|
|
287
|
+
* `normalizeUserinfo` boundary defaults the wire field to `false` when
|
|
288
|
+
* the server omits it (older FFID pre-#3464), so consumers always see
|
|
289
|
+
* a plain boolean and never branch on an "unknown" sentinel — the
|
|
290
|
+
* companion `effectiveStatus` already returns `'active'` (not
|
|
291
|
+
* `'active_canceling'`) for legacy backends since `cancel_at_period_end`
|
|
292
|
+
* is implicitly false there.
|
|
293
|
+
*/
|
|
294
|
+
cancelAtPeriodEnd: boolean;
|
|
295
|
+
/**
|
|
296
|
+
* ISO timestamp of the current billing period end (#3464, SDK 5.8.0).
|
|
297
|
+
* `null` for free / seatless plans, or when serving an older FFID
|
|
298
|
+
* (pre-#3464) that does not populate the field. Exposed so callers
|
|
299
|
+
* can display the cancellation effective date without an `/ext/check`
|
|
300
|
+
* round-trip.
|
|
301
|
+
*/
|
|
302
|
+
currentPeriodEnd: string | null;
|
|
257
303
|
}
|
|
258
304
|
/**
|
|
259
305
|
* Unified user-identity shape returned by `getSession()` (→ `/oauth/userinfo`)
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkMRHDPB7H_cjs = require('./chunk-MRHDPB7H.cjs');
|
|
4
4
|
var chunkQ5SZVLNB_cjs = require('./chunk-Q5SZVLNB.cjs');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -54,8 +54,8 @@ function defaultRedirect(url) {
|
|
|
54
54
|
}
|
|
55
55
|
function useRequireActiveSubscription(options) {
|
|
56
56
|
const { redirectTo, allowGrace = true, onRedirect } = options;
|
|
57
|
-
const { isLoading, error } =
|
|
58
|
-
const { effectiveStatus, isBlocked, isGrace } =
|
|
57
|
+
const { isLoading, error } = chunkMRHDPB7H_cjs.useFFIDContext();
|
|
58
|
+
const { effectiveStatus, isBlocked, isGrace } = chunkMRHDPB7H_cjs.useSubscription();
|
|
59
59
|
const hasFetchError = error !== null && effectiveStatus === null;
|
|
60
60
|
const shouldRedirect = !isLoading && !hasFetchError && (isBlocked || !allowGrace && isGrace || effectiveStatus === null);
|
|
61
61
|
react.useEffect(() => {
|
|
@@ -76,7 +76,7 @@ function useRequireActiveSubscription(options) {
|
|
|
76
76
|
}
|
|
77
77
|
function withFFIDAuth(Component, options = {}) {
|
|
78
78
|
const WrappedComponent = (props) => {
|
|
79
|
-
const { isLoading, isAuthenticated, login } =
|
|
79
|
+
const { isLoading, isAuthenticated, login } = chunkMRHDPB7H_cjs.useFFIDContext();
|
|
80
80
|
const hasRedirected = react.useRef(false);
|
|
81
81
|
react.useEffect(() => {
|
|
82
82
|
if (!isLoading && !isAuthenticated && options.redirectToLogin && !hasRedirected.current) {
|
|
@@ -105,131 +105,131 @@ var FFID_NEWSLETTER_DISPATCH_MAX_RECIPIENTS = 1e3;
|
|
|
105
105
|
|
|
106
106
|
Object.defineProperty(exports, "ACCESS_GRANTING_EFFECTIVE_STATUSES", {
|
|
107
107
|
enumerable: true,
|
|
108
|
-
get: function () { return
|
|
108
|
+
get: function () { return chunkMRHDPB7H_cjs.ACCESS_GRANTING_EFFECTIVE_STATUSES; }
|
|
109
109
|
});
|
|
110
110
|
Object.defineProperty(exports, "BLOCKING_EFFECTIVE_STATUSES", {
|
|
111
111
|
enumerable: true,
|
|
112
|
-
get: function () { return
|
|
112
|
+
get: function () { return chunkMRHDPB7H_cjs.BLOCKING_EFFECTIVE_STATUSES; }
|
|
113
113
|
});
|
|
114
114
|
Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
|
|
115
115
|
enumerable: true,
|
|
116
|
-
get: function () { return
|
|
116
|
+
get: function () { return chunkMRHDPB7H_cjs.DEFAULT_API_BASE_URL; }
|
|
117
117
|
});
|
|
118
118
|
Object.defineProperty(exports, "DEFAULT_OAUTH_SCOPES", {
|
|
119
119
|
enumerable: true,
|
|
120
|
-
get: function () { return
|
|
120
|
+
get: function () { return chunkMRHDPB7H_cjs.DEFAULT_OAUTH_SCOPES; }
|
|
121
121
|
});
|
|
122
122
|
Object.defineProperty(exports, "FFIDAnnouncementBadge", {
|
|
123
123
|
enumerable: true,
|
|
124
|
-
get: function () { return
|
|
124
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDAnnouncementBadge; }
|
|
125
125
|
});
|
|
126
126
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
127
127
|
enumerable: true,
|
|
128
|
-
get: function () { return
|
|
128
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDAnnouncementList; }
|
|
129
129
|
});
|
|
130
130
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
131
131
|
enumerable: true,
|
|
132
|
-
get: function () { return
|
|
132
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDInquiryForm; }
|
|
133
133
|
});
|
|
134
134
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
135
135
|
enumerable: true,
|
|
136
|
-
get: function () { return
|
|
136
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDLoginButton; }
|
|
137
137
|
});
|
|
138
138
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
139
139
|
enumerable: true,
|
|
140
|
-
get: function () { return
|
|
140
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDOrganizationSwitcher; }
|
|
141
141
|
});
|
|
142
142
|
Object.defineProperty(exports, "FFIDProvider", {
|
|
143
143
|
enumerable: true,
|
|
144
|
-
get: function () { return
|
|
144
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDProvider; }
|
|
145
145
|
});
|
|
146
146
|
Object.defineProperty(exports, "FFIDSDKError", {
|
|
147
147
|
enumerable: true,
|
|
148
|
-
get: function () { return
|
|
148
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDSDKError; }
|
|
149
149
|
});
|
|
150
150
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
151
151
|
enumerable: true,
|
|
152
|
-
get: function () { return
|
|
152
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDSubscriptionBadge; }
|
|
153
153
|
});
|
|
154
154
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
155
155
|
enumerable: true,
|
|
156
|
-
get: function () { return
|
|
156
|
+
get: function () { return chunkMRHDPB7H_cjs.FFIDUserMenu; }
|
|
157
157
|
});
|
|
158
158
|
Object.defineProperty(exports, "FFID_ANNOUNCEMENTS_ERROR_CODES", {
|
|
159
159
|
enumerable: true,
|
|
160
|
-
get: function () { return
|
|
160
|
+
get: function () { return chunkMRHDPB7H_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
|
|
161
161
|
});
|
|
162
162
|
Object.defineProperty(exports, "FFID_INQUIRY_CATEGORIES", {
|
|
163
163
|
enumerable: true,
|
|
164
|
-
get: function () { return
|
|
164
|
+
get: function () { return chunkMRHDPB7H_cjs.FFID_INQUIRY_CATEGORIES; }
|
|
165
165
|
});
|
|
166
166
|
Object.defineProperty(exports, "FFID_INQUIRY_CATEGORIES_SITE_2026", {
|
|
167
167
|
enumerable: true,
|
|
168
|
-
get: function () { return
|
|
168
|
+
get: function () { return chunkMRHDPB7H_cjs.FFID_INQUIRY_CATEGORIES_SITE_2026; }
|
|
169
169
|
});
|
|
170
170
|
Object.defineProperty(exports, "computeEffectiveStatusFromSession", {
|
|
171
171
|
enumerable: true,
|
|
172
|
-
get: function () { return
|
|
172
|
+
get: function () { return chunkMRHDPB7H_cjs.computeEffectiveStatusFromSession; }
|
|
173
173
|
});
|
|
174
174
|
Object.defineProperty(exports, "createFFIDAnnouncementsClient", {
|
|
175
175
|
enumerable: true,
|
|
176
|
-
get: function () { return
|
|
176
|
+
get: function () { return chunkMRHDPB7H_cjs.createFFIDAnnouncementsClient; }
|
|
177
177
|
});
|
|
178
178
|
Object.defineProperty(exports, "createFFIDClient", {
|
|
179
179
|
enumerable: true,
|
|
180
|
-
get: function () { return
|
|
180
|
+
get: function () { return chunkMRHDPB7H_cjs.createFFIDClient; }
|
|
181
181
|
});
|
|
182
182
|
Object.defineProperty(exports, "createTokenStore", {
|
|
183
183
|
enumerable: true,
|
|
184
|
-
get: function () { return
|
|
184
|
+
get: function () { return chunkMRHDPB7H_cjs.createTokenStore; }
|
|
185
185
|
});
|
|
186
186
|
Object.defineProperty(exports, "generateCodeChallenge", {
|
|
187
187
|
enumerable: true,
|
|
188
|
-
get: function () { return
|
|
188
|
+
get: function () { return chunkMRHDPB7H_cjs.generateCodeChallenge; }
|
|
189
189
|
});
|
|
190
190
|
Object.defineProperty(exports, "generateCodeVerifier", {
|
|
191
191
|
enumerable: true,
|
|
192
|
-
get: function () { return
|
|
192
|
+
get: function () { return chunkMRHDPB7H_cjs.generateCodeVerifier; }
|
|
193
193
|
});
|
|
194
194
|
Object.defineProperty(exports, "hasAccessFromUserinfo", {
|
|
195
195
|
enumerable: true,
|
|
196
|
-
get: function () { return
|
|
196
|
+
get: function () { return chunkMRHDPB7H_cjs.hasAccessFromUserinfo; }
|
|
197
197
|
});
|
|
198
198
|
Object.defineProperty(exports, "isBlockedFromUserinfo", {
|
|
199
199
|
enumerable: true,
|
|
200
|
-
get: function () { return
|
|
200
|
+
get: function () { return chunkMRHDPB7H_cjs.isBlockedFromUserinfo; }
|
|
201
201
|
});
|
|
202
202
|
Object.defineProperty(exports, "isFFIDInquiryCategorySite2026", {
|
|
203
203
|
enumerable: true,
|
|
204
|
-
get: function () { return
|
|
204
|
+
get: function () { return chunkMRHDPB7H_cjs.isFFIDInquiryCategorySite2026; }
|
|
205
205
|
});
|
|
206
206
|
Object.defineProperty(exports, "normalizeRedirectUri", {
|
|
207
207
|
enumerable: true,
|
|
208
|
-
get: function () { return
|
|
208
|
+
get: function () { return chunkMRHDPB7H_cjs.normalizeRedirectUri; }
|
|
209
209
|
});
|
|
210
210
|
Object.defineProperty(exports, "retrieveCodeVerifier", {
|
|
211
211
|
enumerable: true,
|
|
212
|
-
get: function () { return
|
|
212
|
+
get: function () { return chunkMRHDPB7H_cjs.retrieveCodeVerifier; }
|
|
213
213
|
});
|
|
214
214
|
Object.defineProperty(exports, "storeCodeVerifier", {
|
|
215
215
|
enumerable: true,
|
|
216
|
-
get: function () { return
|
|
216
|
+
get: function () { return chunkMRHDPB7H_cjs.storeCodeVerifier; }
|
|
217
217
|
});
|
|
218
218
|
Object.defineProperty(exports, "useFFID", {
|
|
219
219
|
enumerable: true,
|
|
220
|
-
get: function () { return
|
|
220
|
+
get: function () { return chunkMRHDPB7H_cjs.useFFID; }
|
|
221
221
|
});
|
|
222
222
|
Object.defineProperty(exports, "useFFIDAnnouncements", {
|
|
223
223
|
enumerable: true,
|
|
224
|
-
get: function () { return
|
|
224
|
+
get: function () { return chunkMRHDPB7H_cjs.useFFIDAnnouncements; }
|
|
225
225
|
});
|
|
226
226
|
Object.defineProperty(exports, "useSubscription", {
|
|
227
227
|
enumerable: true,
|
|
228
|
-
get: function () { return
|
|
228
|
+
get: function () { return chunkMRHDPB7H_cjs.useSubscription; }
|
|
229
229
|
});
|
|
230
230
|
Object.defineProperty(exports, "withSubscription", {
|
|
231
231
|
enumerable: true,
|
|
232
|
-
get: function () { return
|
|
232
|
+
get: function () { return chunkMRHDPB7H_cjs.withSubscription; }
|
|
233
233
|
});
|
|
234
234
|
Object.defineProperty(exports, "ALL_DENIED_EXCEPT_NECESSARY", {
|
|
235
235
|
enumerable: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FFIDSubscriptionStatus, a as FFIDConfig, b as FFIDApiResponse, c as FFIDSessionResponse, d as FFIDRedirectResult, e as FFIDError, f as FFIDSubscriptionCheckResponse, g as FFIDCheckServiceAccessParams, h as FFIDServiceAccessDecision, i as FFIDProfileCallOptions, j as FFIDUserProfile, k as FFIDUpdateUserProfileRequest, l as FFIDAnalyticsConfig, m as FFIDCreateCheckoutParams, n as FFIDCheckoutSessionResponse, o as FFIDCreatePortalParams, p as FFIDPortalSessionResponse, q as FFIDVerifyAccessTokenOptions, r as FFIDOAuthUserInfo, s as FFIDInquiryCreateParams, t as FFIDInquiryCreateResponse, u as FFIDAuthMode, v as FFIDLogger, w as FFIDCacheAdapter, x as FFIDUser, y as FFIDOrganization, z as FFIDSubscription, A as FFIDSubscriptionContextValue, E as EffectiveSubscriptionStatus, B as FFIDOAuthUserInfoSubscription, C as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, D as FFIDAnnouncementsApiResponse, G as AnnouncementListResponse, H as FFIDAnnouncementsLogger } from './index-
|
|
2
|
-
export { I as Announcement, J as AnnouncementStatus, K as AnnouncementType, M as FFIDAnnouncementBadge, N as FFIDAnnouncementList, O as FFIDAnnouncementsError, P as FFIDAnnouncementsErrorCode, Q as FFIDAnnouncementsServerResponse, R as FFIDCacheConfig, S as FFIDContextValue, T as FFIDInquiryCategory, U as FFIDInquiryCategorySite2026, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a3 as FFIDJwtClaims, a4 as FFIDLoginButton, a5 as FFIDOAuthTokenResponse, a6 as FFIDOAuthUserInfoMemberRole, a7 as FFIDOrganizationSwitcher, a8 as FFIDRedirectErrorCode, a9 as FFIDSeatModel, aa as FFIDServiceAccessDenialReason, ab as FFIDServiceAccessFailPolicy, ac as FFIDSubscriptionBadge, ad as FFIDTokenIntrospectionResponse, ae as FFIDUserMenu, af as FFID_INQUIRY_CATEGORIES, ag as FFID_INQUIRY_CATEGORIES_SITE_2026, ah as UseFFIDAnnouncementsOptions, ai as UseFFIDAnnouncementsReturn, aj as isFFIDInquiryCategorySite2026, ak as useFFIDAnnouncements } from './index-
|
|
1
|
+
import { F as FFIDSubscriptionStatus, a as FFIDConfig, b as FFIDApiResponse, c as FFIDSessionResponse, d as FFIDRedirectResult, e as FFIDError, f as FFIDSubscriptionCheckResponse, g as FFIDCheckServiceAccessParams, h as FFIDServiceAccessDecision, i as FFIDProfileCallOptions, j as FFIDUserProfile, k as FFIDUpdateUserProfileRequest, l as FFIDAnalyticsConfig, m as FFIDCreateCheckoutParams, n as FFIDCheckoutSessionResponse, o as FFIDCreatePortalParams, p as FFIDPortalSessionResponse, q as FFIDVerifyAccessTokenOptions, r as FFIDOAuthUserInfo, s as FFIDInquiryCreateParams, t as FFIDInquiryCreateResponse, u as FFIDAuthMode, v as FFIDLogger, w as FFIDCacheAdapter, x as FFIDUser, y as FFIDOrganization, z as FFIDSubscription, A as FFIDSubscriptionContextValue, E as EffectiveSubscriptionStatus, B as FFIDOAuthUserInfoSubscription, C as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, D as FFIDAnnouncementsApiResponse, G as AnnouncementListResponse, H as FFIDAnnouncementsLogger } from './index-DeegKrLW.cjs';
|
|
2
|
+
export { I as Announcement, J as AnnouncementStatus, K as AnnouncementType, M as FFIDAnnouncementBadge, N as FFIDAnnouncementList, O as FFIDAnnouncementsError, P as FFIDAnnouncementsErrorCode, Q as FFIDAnnouncementsServerResponse, R as FFIDCacheConfig, S as FFIDContextValue, T as FFIDInquiryCategory, U as FFIDInquiryCategorySite2026, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a3 as FFIDJwtClaims, a4 as FFIDLoginButton, a5 as FFIDOAuthTokenResponse, a6 as FFIDOAuthUserInfoMemberRole, a7 as FFIDOrganizationSwitcher, a8 as FFIDRedirectErrorCode, a9 as FFIDSeatModel, aa as FFIDServiceAccessDenialReason, ab as FFIDServiceAccessFailPolicy, ac as FFIDSubscriptionBadge, ad as FFIDTokenIntrospectionResponse, ae as FFIDUserMenu, af as FFID_INQUIRY_CATEGORIES, ag as FFID_INQUIRY_CATEGORIES_SITE_2026, ah as UseFFIDAnnouncementsOptions, ai as UseFFIDAnnouncementsReturn, aj as isFFIDInquiryCategorySite2026, ak as useFFIDAnnouncements } from './index-DeegKrLW.cjs';
|
|
3
3
|
export { A as ALL_DENIED_EXCEPT_NECESSARY, i as CONSENT_COOKIE_NAME, j as CONSENT_DISMISSAL_TIMESTAMP_KEY, l as COOKIE_VERSION, D as DEFAULT_CONSENT_ERROR_MESSAGES, o as FFIDAnalyticsProvider, p as FFIDAnalyticsProviderProps, c as FFIDConsentCategories, r as FFIDConsentCategoryCode, e as FFIDConsentCategoryMetadata, w as FFIDConsentError, x as FFIDConsentErrorCode, y as FFIDConsentMergeStrategy, B as FFIDConsentMergeWarning, E as FFIDConsentMergeWarningEvent, F as FFIDConsentResult, I as FFIDConsentSource, a as FFIDConsentState, d as FFIDConsentSyncResult, M as FFIDCookieBanner, N as FFIDCookieBannerClassNames, O as FFIDCookieBannerProps, Q as FFIDCookieLink, R as FFIDCookieLinkProps, f as FFIDCookiePolicy, T as FFIDCookieSettings, U as FFIDCookieSettingsClassNames, V as FFIDCookieSettingsProps, _ as FFID_CONSENT_ERROR_CODES, ae as UseFFIDConsentPreferencesReturn, af as UseFFIDConsentReturn, ag as clearConsentDismissalTimestamp, aj as decodeConsentCookie, al as encodeConsentCookie, an as readConsentCookie, ao as readConsentDismissalTimestamp, aq as useFFIDConsent, ar as useFFIDConsentPreferences, as as writeConsentCookie, at as writeConsentDismissalTimestamp } from './FFIDCookieLink-CE01gYc4.cjs';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import { ReactNode, ComponentType, FC } from 'react';
|
|
@@ -1089,6 +1089,21 @@ interface ComputeEffectiveStatusInput {
|
|
|
1089
1089
|
* `blocked`.
|
|
1090
1090
|
*/
|
|
1091
1091
|
pastDueSince?: string | null | undefined;
|
|
1092
|
+
/**
|
|
1093
|
+
* Whether the subscription is scheduled to cancel at the end of the
|
|
1094
|
+
* current billing period (`cancel_at_period_end=true` in Stripe).
|
|
1095
|
+
*
|
|
1096
|
+
* Optional / defaults to `false` for backward compatibility — pre-#3460
|
|
1097
|
+
* callers (and pre-#3464 FFID backends that omit the field on the wire)
|
|
1098
|
+
* do not pass this field and MUST keep observing `'active'` for the
|
|
1099
|
+
* same inputs. When `true` and the period has not yet ended, the
|
|
1100
|
+
* `'active'` branch returns `'active_canceling'` so consumers can render
|
|
1101
|
+
* a "cancellation scheduled" badge + reactivation CTA without losing
|
|
1102
|
+
* access. Outside `case 'active'` the field is intentionally ignored,
|
|
1103
|
+
* so any non-`active` DB status is unaffected regardless of what Stripe
|
|
1104
|
+
* sets.
|
|
1105
|
+
*/
|
|
1106
|
+
cancelAtPeriodEnd?: boolean | undefined;
|
|
1092
1107
|
}
|
|
1093
1108
|
/**
|
|
1094
1109
|
* Compute an `EffectiveSubscriptionStatus` from the fields available in the
|
|
@@ -1131,6 +1146,14 @@ declare function computeEffectiveStatusFromSession(input: ComputeEffectiveStatus
|
|
|
1131
1146
|
* caller that needs to fan in on the same access predicate. Mirrors the FFID
|
|
1132
1147
|
* backend constants in `src/app/api/v1/subscriptions/ext/check/route.ts`
|
|
1133
1148
|
* (route-local) — change there forces a sync here in the same PR.
|
|
1149
|
+
*
|
|
1150
|
+
* `active_canceling` (post-#3464, server-mirrored since SDK 5.8.0) is
|
|
1151
|
+
* access-granting: the FFID backend now emits the literal on
|
|
1152
|
+
* `/oauth/userinfo` and `/ext/check` when `cancel_at_period_end=true` and
|
|
1153
|
+
* the period is still live. `hasAccessFromUserinfo` treats it identically
|
|
1154
|
+
* to `active`; `isBlockedFromUserinfo` returns `false` for it. Callers
|
|
1155
|
+
* that want to render a "cancellation scheduled" badge should branch on
|
|
1156
|
+
* the literal directly.
|
|
1134
1157
|
*/
|
|
1135
1158
|
declare const ACCESS_GRANTING_EFFECTIVE_STATUSES: readonly EffectiveSubscriptionStatus[];
|
|
1136
1159
|
/**
|
|
@@ -1145,7 +1168,8 @@ declare const BLOCKING_EFFECTIVE_STATUSES: readonly EffectiveSubscriptionStatus[
|
|
|
1145
1168
|
* Decide whether the `/oauth/userinfo` subscription summary grants access.
|
|
1146
1169
|
*
|
|
1147
1170
|
* Returns `true` iff `sub.effectiveStatus` is in
|
|
1148
|
-
* {@link ACCESS_GRANTING_EFFECTIVE_STATUSES} (`active
|
|
1171
|
+
* {@link ACCESS_GRANTING_EFFECTIVE_STATUSES} (`active`, `active_canceling`,
|
|
1172
|
+
* or `past_due_grace`).
|
|
1149
1173
|
*
|
|
1150
1174
|
* Conservative fallback rules (security-critical — treat as part of the
|
|
1151
1175
|
* contract, not implementation detail):
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FFIDSubscriptionStatus, a as FFIDConfig, b as FFIDApiResponse, c as FFIDSessionResponse, d as FFIDRedirectResult, e as FFIDError, f as FFIDSubscriptionCheckResponse, g as FFIDCheckServiceAccessParams, h as FFIDServiceAccessDecision, i as FFIDProfileCallOptions, j as FFIDUserProfile, k as FFIDUpdateUserProfileRequest, l as FFIDAnalyticsConfig, m as FFIDCreateCheckoutParams, n as FFIDCheckoutSessionResponse, o as FFIDCreatePortalParams, p as FFIDPortalSessionResponse, q as FFIDVerifyAccessTokenOptions, r as FFIDOAuthUserInfo, s as FFIDInquiryCreateParams, t as FFIDInquiryCreateResponse, u as FFIDAuthMode, v as FFIDLogger, w as FFIDCacheAdapter, x as FFIDUser, y as FFIDOrganization, z as FFIDSubscription, A as FFIDSubscriptionContextValue, E as EffectiveSubscriptionStatus, B as FFIDOAuthUserInfoSubscription, C as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, D as FFIDAnnouncementsApiResponse, G as AnnouncementListResponse, H as FFIDAnnouncementsLogger } from './index-
|
|
2
|
-
export { I as Announcement, J as AnnouncementStatus, K as AnnouncementType, M as FFIDAnnouncementBadge, N as FFIDAnnouncementList, O as FFIDAnnouncementsError, P as FFIDAnnouncementsErrorCode, Q as FFIDAnnouncementsServerResponse, R as FFIDCacheConfig, S as FFIDContextValue, T as FFIDInquiryCategory, U as FFIDInquiryCategorySite2026, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a3 as FFIDJwtClaims, a4 as FFIDLoginButton, a5 as FFIDOAuthTokenResponse, a6 as FFIDOAuthUserInfoMemberRole, a7 as FFIDOrganizationSwitcher, a8 as FFIDRedirectErrorCode, a9 as FFIDSeatModel, aa as FFIDServiceAccessDenialReason, ab as FFIDServiceAccessFailPolicy, ac as FFIDSubscriptionBadge, ad as FFIDTokenIntrospectionResponse, ae as FFIDUserMenu, af as FFID_INQUIRY_CATEGORIES, ag as FFID_INQUIRY_CATEGORIES_SITE_2026, ah as UseFFIDAnnouncementsOptions, ai as UseFFIDAnnouncementsReturn, aj as isFFIDInquiryCategorySite2026, ak as useFFIDAnnouncements } from './index-
|
|
1
|
+
import { F as FFIDSubscriptionStatus, a as FFIDConfig, b as FFIDApiResponse, c as FFIDSessionResponse, d as FFIDRedirectResult, e as FFIDError, f as FFIDSubscriptionCheckResponse, g as FFIDCheckServiceAccessParams, h as FFIDServiceAccessDecision, i as FFIDProfileCallOptions, j as FFIDUserProfile, k as FFIDUpdateUserProfileRequest, l as FFIDAnalyticsConfig, m as FFIDCreateCheckoutParams, n as FFIDCheckoutSessionResponse, o as FFIDCreatePortalParams, p as FFIDPortalSessionResponse, q as FFIDVerifyAccessTokenOptions, r as FFIDOAuthUserInfo, s as FFIDInquiryCreateParams, t as FFIDInquiryCreateResponse, u as FFIDAuthMode, v as FFIDLogger, w as FFIDCacheAdapter, x as FFIDUser, y as FFIDOrganization, z as FFIDSubscription, A as FFIDSubscriptionContextValue, E as EffectiveSubscriptionStatus, B as FFIDOAuthUserInfoSubscription, C as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, D as FFIDAnnouncementsApiResponse, G as AnnouncementListResponse, H as FFIDAnnouncementsLogger } from './index-DeegKrLW.js';
|
|
2
|
+
export { I as Announcement, J as AnnouncementStatus, K as AnnouncementType, M as FFIDAnnouncementBadge, N as FFIDAnnouncementList, O as FFIDAnnouncementsError, P as FFIDAnnouncementsErrorCode, Q as FFIDAnnouncementsServerResponse, R as FFIDCacheConfig, S as FFIDContextValue, T as FFIDInquiryCategory, U as FFIDInquiryCategorySite2026, V as FFIDInquiryForm, W as FFIDInquiryFormCategoryItem, X as FFIDInquiryFormClassNames, Y as FFIDInquiryFormLegalLayout, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a3 as FFIDJwtClaims, a4 as FFIDLoginButton, a5 as FFIDOAuthTokenResponse, a6 as FFIDOAuthUserInfoMemberRole, a7 as FFIDOrganizationSwitcher, a8 as FFIDRedirectErrorCode, a9 as FFIDSeatModel, aa as FFIDServiceAccessDenialReason, ab as FFIDServiceAccessFailPolicy, ac as FFIDSubscriptionBadge, ad as FFIDTokenIntrospectionResponse, ae as FFIDUserMenu, af as FFID_INQUIRY_CATEGORIES, ag as FFID_INQUIRY_CATEGORIES_SITE_2026, ah as UseFFIDAnnouncementsOptions, ai as UseFFIDAnnouncementsReturn, aj as isFFIDInquiryCategorySite2026, ak as useFFIDAnnouncements } from './index-DeegKrLW.js';
|
|
3
3
|
export { A as ALL_DENIED_EXCEPT_NECESSARY, i as CONSENT_COOKIE_NAME, j as CONSENT_DISMISSAL_TIMESTAMP_KEY, l as COOKIE_VERSION, D as DEFAULT_CONSENT_ERROR_MESSAGES, o as FFIDAnalyticsProvider, p as FFIDAnalyticsProviderProps, c as FFIDConsentCategories, r as FFIDConsentCategoryCode, e as FFIDConsentCategoryMetadata, w as FFIDConsentError, x as FFIDConsentErrorCode, y as FFIDConsentMergeStrategy, B as FFIDConsentMergeWarning, E as FFIDConsentMergeWarningEvent, F as FFIDConsentResult, I as FFIDConsentSource, a as FFIDConsentState, d as FFIDConsentSyncResult, M as FFIDCookieBanner, N as FFIDCookieBannerClassNames, O as FFIDCookieBannerProps, Q as FFIDCookieLink, R as FFIDCookieLinkProps, f as FFIDCookiePolicy, T as FFIDCookieSettings, U as FFIDCookieSettingsClassNames, V as FFIDCookieSettingsProps, _ as FFID_CONSENT_ERROR_CODES, ae as UseFFIDConsentPreferencesReturn, af as UseFFIDConsentReturn, ag as clearConsentDismissalTimestamp, aj as decodeConsentCookie, al as encodeConsentCookie, an as readConsentCookie, ao as readConsentDismissalTimestamp, aq as useFFIDConsent, ar as useFFIDConsentPreferences, as as writeConsentCookie, at as writeConsentDismissalTimestamp } from './FFIDCookieLink-CE01gYc4.js';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import { ReactNode, ComponentType, FC } from 'react';
|
|
@@ -1089,6 +1089,21 @@ interface ComputeEffectiveStatusInput {
|
|
|
1089
1089
|
* `blocked`.
|
|
1090
1090
|
*/
|
|
1091
1091
|
pastDueSince?: string | null | undefined;
|
|
1092
|
+
/**
|
|
1093
|
+
* Whether the subscription is scheduled to cancel at the end of the
|
|
1094
|
+
* current billing period (`cancel_at_period_end=true` in Stripe).
|
|
1095
|
+
*
|
|
1096
|
+
* Optional / defaults to `false` for backward compatibility — pre-#3460
|
|
1097
|
+
* callers (and pre-#3464 FFID backends that omit the field on the wire)
|
|
1098
|
+
* do not pass this field and MUST keep observing `'active'` for the
|
|
1099
|
+
* same inputs. When `true` and the period has not yet ended, the
|
|
1100
|
+
* `'active'` branch returns `'active_canceling'` so consumers can render
|
|
1101
|
+
* a "cancellation scheduled" badge + reactivation CTA without losing
|
|
1102
|
+
* access. Outside `case 'active'` the field is intentionally ignored,
|
|
1103
|
+
* so any non-`active` DB status is unaffected regardless of what Stripe
|
|
1104
|
+
* sets.
|
|
1105
|
+
*/
|
|
1106
|
+
cancelAtPeriodEnd?: boolean | undefined;
|
|
1092
1107
|
}
|
|
1093
1108
|
/**
|
|
1094
1109
|
* Compute an `EffectiveSubscriptionStatus` from the fields available in the
|
|
@@ -1131,6 +1146,14 @@ declare function computeEffectiveStatusFromSession(input: ComputeEffectiveStatus
|
|
|
1131
1146
|
* caller that needs to fan in on the same access predicate. Mirrors the FFID
|
|
1132
1147
|
* backend constants in `src/app/api/v1/subscriptions/ext/check/route.ts`
|
|
1133
1148
|
* (route-local) — change there forces a sync here in the same PR.
|
|
1149
|
+
*
|
|
1150
|
+
* `active_canceling` (post-#3464, server-mirrored since SDK 5.8.0) is
|
|
1151
|
+
* access-granting: the FFID backend now emits the literal on
|
|
1152
|
+
* `/oauth/userinfo` and `/ext/check` when `cancel_at_period_end=true` and
|
|
1153
|
+
* the period is still live. `hasAccessFromUserinfo` treats it identically
|
|
1154
|
+
* to `active`; `isBlockedFromUserinfo` returns `false` for it. Callers
|
|
1155
|
+
* that want to render a "cancellation scheduled" badge should branch on
|
|
1156
|
+
* the literal directly.
|
|
1134
1157
|
*/
|
|
1135
1158
|
declare const ACCESS_GRANTING_EFFECTIVE_STATUSES: readonly EffectiveSubscriptionStatus[];
|
|
1136
1159
|
/**
|
|
@@ -1145,7 +1168,8 @@ declare const BLOCKING_EFFECTIVE_STATUSES: readonly EffectiveSubscriptionStatus[
|
|
|
1145
1168
|
* Decide whether the `/oauth/userinfo` subscription summary grants access.
|
|
1146
1169
|
*
|
|
1147
1170
|
* Returns `true` iff `sub.effectiveStatus` is in
|
|
1148
|
-
* {@link ACCESS_GRANTING_EFFECTIVE_STATUSES} (`active
|
|
1171
|
+
* {@link ACCESS_GRANTING_EFFECTIVE_STATUSES} (`active`, `active_canceling`,
|
|
1172
|
+
* or `past_due_grace`).
|
|
1149
1173
|
*
|
|
1150
1174
|
* Conservative fallback rules (security-critical — treat as part of the
|
|
1151
1175
|
* contract, not implementation detail):
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useFFIDContext, useSubscription } from './chunk-
|
|
2
|
-
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, useSubscription, withSubscription } from './chunk-
|
|
1
|
+
import { useFFIDContext, useSubscription } from './chunk-Z6COUAR6.js';
|
|
2
|
+
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, useSubscription, withSubscription } from './chunk-Z6COUAR6.js';
|
|
3
3
|
export { ALL_DENIED_EXCEPT_NECESSARY, CONSENT_COOKIE_NAME, CONSENT_DISMISSAL_TIMESTAMP_KEY, COOKIE_VERSION, DEFAULT_CONSENT_ERROR_MESSAGES, FFIDAnalyticsProvider, FFIDConsentError, FFIDCookieBanner, FFIDCookieLink, FFIDCookieSettings, FFID_CONSENT_ERROR_CODES, clearConsentDismissalTimestamp, decodeConsentCookie, encodeConsentCookie, readConsentCookie, readConsentDismissalTimestamp, useFFIDConsent, useFFIDConsentPreferences, writeConsentCookie, writeConsentDismissalTimestamp } from './chunk-KJ7FUNA6.js';
|
|
4
4
|
import { useEffect, useRef } from 'react';
|
|
5
5
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
package/dist/server/index.cjs
CHANGED
|
@@ -125,7 +125,15 @@ function normalizeUserinfo(raw) {
|
|
|
125
125
|
seatModel: raw.subscription.seat_model ?? null,
|
|
126
126
|
memberRole: raw.subscription.member_role ?? null,
|
|
127
127
|
organizationId: raw.subscription.organization_id ?? null,
|
|
128
|
-
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false
|
|
128
|
+
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false,
|
|
129
|
+
// #3464: legacy FFID (< this issue) omits the field on the wire.
|
|
130
|
+
// The "unknown" axis is unused — no consumer differentiates "server
|
|
131
|
+
// didn't tell us" from "definitely not scheduled" because the
|
|
132
|
+
// companion `effectiveStatus` already returns `'active'` (not
|
|
133
|
+
// `'active_canceling'`) for legacy backends. Defaulting to `false`
|
|
134
|
+
// here keeps the downstream contract a plain boolean.
|
|
135
|
+
cancelAtPeriodEnd: raw.subscription.cancel_at_period_end ?? false,
|
|
136
|
+
currentPeriodEnd: raw.subscription.current_period_end ?? null
|
|
129
137
|
} : void 0
|
|
130
138
|
};
|
|
131
139
|
}
|
|
@@ -142,8 +150,14 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
|
|
|
142
150
|
planCode: subscription.planCode,
|
|
143
151
|
planName: subscription.planCode,
|
|
144
152
|
status: subscription.status,
|
|
145
|
-
|
|
153
|
+
// #3464: userinfo now carries `current_period_end` and
|
|
154
|
+
// `cancel_at_period_end`. Pre-#3464 FFID backends still omit them on
|
|
155
|
+
// the wire (`currentPeriodEnd === null` / `cancelAtPeriodEnd === false`
|
|
156
|
+
// after `normalizeUserinfo` defaults), so the session helper sees
|
|
157
|
+
// plain `'active'` — identical to pre-#3464 behaviour.
|
|
158
|
+
currentPeriodEnd: subscription.currentPeriodEnd,
|
|
146
159
|
trialEnd: null,
|
|
160
|
+
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
|
|
147
161
|
seatModel: subscription.seatModel ?? void 0,
|
|
148
162
|
memberRole: subscription.memberRole ?? void 0,
|
|
149
163
|
organizationId: subscription.organizationId
|
|
@@ -837,7 +851,7 @@ function createProfileMethods(deps) {
|
|
|
837
851
|
}
|
|
838
852
|
|
|
839
853
|
// src/client/version-check.ts
|
|
840
|
-
var SDK_VERSION = "5.
|
|
854
|
+
var SDK_VERSION = "5.8.0";
|
|
841
855
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
842
856
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
843
857
|
function sdkHeaders() {
|
|
@@ -2190,6 +2204,7 @@ function createInquiryMethods(deps) {
|
|
|
2190
2204
|
// src/subscriptions/userinfo-helpers.ts
|
|
2191
2205
|
var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
|
|
2192
2206
|
"active",
|
|
2207
|
+
"active_canceling",
|
|
2193
2208
|
"past_due_grace"
|
|
2194
2209
|
];
|
|
2195
2210
|
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
@@ -2229,6 +2244,12 @@ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
|
2229
2244
|
var DEFAULT_ALLOW_GRACE = true;
|
|
2230
2245
|
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2231
2246
|
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2247
|
+
var DENIAL_REASON_BY_DENYING_STATUS = {
|
|
2248
|
+
blocked: "blocked",
|
|
2249
|
+
canceled: "canceled",
|
|
2250
|
+
expired: "expired",
|
|
2251
|
+
trial_expired: "trial_expired"
|
|
2252
|
+
};
|
|
2232
2253
|
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2233
2254
|
if (params.hasAccess) {
|
|
2234
2255
|
return null;
|
|
@@ -2239,10 +2260,10 @@ function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
|
2239
2260
|
if (params.isGrace && !allowGrace) {
|
|
2240
2261
|
return "grace_disallowed";
|
|
2241
2262
|
}
|
|
2242
|
-
if (
|
|
2263
|
+
if (ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(params.effectiveStatus)) {
|
|
2243
2264
|
return "blocked";
|
|
2244
2265
|
}
|
|
2245
|
-
return params.effectiveStatus;
|
|
2266
|
+
return DENIAL_REASON_BY_DENYING_STATUS[params.effectiveStatus];
|
|
2246
2267
|
}
|
|
2247
2268
|
function toServiceAccessDecision(response, allowGrace) {
|
|
2248
2269
|
const effectiveStatus = response.effectiveStatus ?? null;
|
package/dist/server/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-
|
|
2
|
-
export { f as FFIDAddMemberParams, g as FFIDAddMemberRequest, h as FFIDAddMemberResponse, i as FFIDAssignableMemberRole, j as FFIDCacheConfig, k as FFIDClient, l as FFIDConfig, m as FFIDListMembersResponse, n as FFIDMemberRole, o as FFIDOrganization, p as FFIDOrganizationMember, q as FFIDOtpSendResponse, r as FFIDOtpVerifyResponse, s as FFIDPasswordResetConfirmResponse, t as FFIDPasswordResetResponse, u as FFIDPasswordResetVerifyResponse, v as FFIDProfileCallOptions, w as FFIDRemoveMemberResponse, x as FFIDResetSessionResponse, y as FFIDSubscription, z as FFIDUpdateMemberRoleResponse, A as FFIDUpdateUserProfileRequest, B as FFIDUser, C as FFIDUserProfile, T as TokenData, D as TokenStore, E as createFFIDClient, G as createTokenStore } from '../ffid-client-
|
|
1
|
+
import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-BhopNmnq.cjs';
|
|
2
|
+
export { f as FFIDAddMemberParams, g as FFIDAddMemberRequest, h as FFIDAddMemberResponse, i as FFIDAssignableMemberRole, j as FFIDCacheConfig, k as FFIDClient, l as FFIDConfig, m as FFIDListMembersResponse, n as FFIDMemberRole, o as FFIDOrganization, p as FFIDOrganizationMember, q as FFIDOtpSendResponse, r as FFIDOtpVerifyResponse, s as FFIDPasswordResetConfirmResponse, t as FFIDPasswordResetResponse, u as FFIDPasswordResetVerifyResponse, v as FFIDProfileCallOptions, w as FFIDRemoveMemberResponse, x as FFIDResetSessionResponse, y as FFIDSubscription, z as FFIDUpdateMemberRoleResponse, A as FFIDUpdateUserProfileRequest, B as FFIDUser, C as FFIDUserProfile, T as TokenData, D as TokenStore, E as createFFIDClient, G as createTokenStore } from '../ffid-client-BhopNmnq.cjs';
|
|
3
3
|
export { D as DEFAULT_API_BASE_URL, a as DEFAULT_OAUTH_SCOPES } from '../constants-D61jqRIO.cjs';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-BYdtyO_2.cjs';
|
|
6
6
|
|
|
7
7
|
/** Token verification - verifyAccessToken() implementation */
|
|
8
8
|
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-
|
|
2
|
-
export { f as FFIDAddMemberParams, g as FFIDAddMemberRequest, h as FFIDAddMemberResponse, i as FFIDAssignableMemberRole, j as FFIDCacheConfig, k as FFIDClient, l as FFIDConfig, m as FFIDListMembersResponse, n as FFIDMemberRole, o as FFIDOrganization, p as FFIDOrganizationMember, q as FFIDOtpSendResponse, r as FFIDOtpVerifyResponse, s as FFIDPasswordResetConfirmResponse, t as FFIDPasswordResetResponse, u as FFIDPasswordResetVerifyResponse, v as FFIDProfileCallOptions, w as FFIDRemoveMemberResponse, x as FFIDResetSessionResponse, y as FFIDSubscription, z as FFIDUpdateMemberRoleResponse, A as FFIDUpdateUserProfileRequest, B as FFIDUser, C as FFIDUserProfile, T as TokenData, D as TokenStore, E as createFFIDClient, G as createTokenStore } from '../ffid-client-
|
|
1
|
+
import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-DoGYvIll.js';
|
|
2
|
+
export { f as FFIDAddMemberParams, g as FFIDAddMemberRequest, h as FFIDAddMemberResponse, i as FFIDAssignableMemberRole, j as FFIDCacheConfig, k as FFIDClient, l as FFIDConfig, m as FFIDListMembersResponse, n as FFIDMemberRole, o as FFIDOrganization, p as FFIDOrganizationMember, q as FFIDOtpSendResponse, r as FFIDOtpVerifyResponse, s as FFIDPasswordResetConfirmResponse, t as FFIDPasswordResetResponse, u as FFIDPasswordResetVerifyResponse, v as FFIDProfileCallOptions, w as FFIDRemoveMemberResponse, x as FFIDResetSessionResponse, y as FFIDSubscription, z as FFIDUpdateMemberRoleResponse, A as FFIDUpdateUserProfileRequest, B as FFIDUser, C as FFIDUserProfile, T as TokenData, D as TokenStore, E as createFFIDClient, G as createTokenStore } from '../ffid-client-DoGYvIll.js';
|
|
3
3
|
export { D as DEFAULT_API_BASE_URL, a as DEFAULT_OAUTH_SCOPES } from '../constants-D61jqRIO.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-BYdtyO_2.js';
|
|
6
6
|
|
|
7
7
|
/** Token verification - verifyAccessToken() implementation */
|
|
8
8
|
|
package/dist/server/index.js
CHANGED
|
@@ -124,7 +124,15 @@ function normalizeUserinfo(raw) {
|
|
|
124
124
|
seatModel: raw.subscription.seat_model ?? null,
|
|
125
125
|
memberRole: raw.subscription.member_role ?? null,
|
|
126
126
|
organizationId: raw.subscription.organization_id ?? null,
|
|
127
|
-
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false
|
|
127
|
+
hasSeatAssignment: raw.subscription.has_seat_assignment ?? false,
|
|
128
|
+
// #3464: legacy FFID (< this issue) omits the field on the wire.
|
|
129
|
+
// The "unknown" axis is unused — no consumer differentiates "server
|
|
130
|
+
// didn't tell us" from "definitely not scheduled" because the
|
|
131
|
+
// companion `effectiveStatus` already returns `'active'` (not
|
|
132
|
+
// `'active_canceling'`) for legacy backends. Defaulting to `false`
|
|
133
|
+
// here keeps the downstream contract a plain boolean.
|
|
134
|
+
cancelAtPeriodEnd: raw.subscription.cancel_at_period_end ?? false,
|
|
135
|
+
currentPeriodEnd: raw.subscription.current_period_end ?? null
|
|
128
136
|
} : void 0
|
|
129
137
|
};
|
|
130
138
|
}
|
|
@@ -141,8 +149,14 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
|
|
|
141
149
|
planCode: subscription.planCode,
|
|
142
150
|
planName: subscription.planCode,
|
|
143
151
|
status: subscription.status,
|
|
144
|
-
|
|
152
|
+
// #3464: userinfo now carries `current_period_end` and
|
|
153
|
+
// `cancel_at_period_end`. Pre-#3464 FFID backends still omit them on
|
|
154
|
+
// the wire (`currentPeriodEnd === null` / `cancelAtPeriodEnd === false`
|
|
155
|
+
// after `normalizeUserinfo` defaults), so the session helper sees
|
|
156
|
+
// plain `'active'` — identical to pre-#3464 behaviour.
|
|
157
|
+
currentPeriodEnd: subscription.currentPeriodEnd,
|
|
145
158
|
trialEnd: null,
|
|
159
|
+
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
|
|
146
160
|
seatModel: subscription.seatModel ?? void 0,
|
|
147
161
|
memberRole: subscription.memberRole ?? void 0,
|
|
148
162
|
organizationId: subscription.organizationId
|
|
@@ -836,7 +850,7 @@ function createProfileMethods(deps) {
|
|
|
836
850
|
}
|
|
837
851
|
|
|
838
852
|
// src/client/version-check.ts
|
|
839
|
-
var SDK_VERSION = "5.
|
|
853
|
+
var SDK_VERSION = "5.8.0";
|
|
840
854
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
841
855
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
842
856
|
function sdkHeaders() {
|
|
@@ -2189,6 +2203,7 @@ function createInquiryMethods(deps) {
|
|
|
2189
2203
|
// src/subscriptions/userinfo-helpers.ts
|
|
2190
2204
|
var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
|
|
2191
2205
|
"active",
|
|
2206
|
+
"active_canceling",
|
|
2192
2207
|
"past_due_grace"
|
|
2193
2208
|
];
|
|
2194
2209
|
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
@@ -2228,6 +2243,12 @@ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
|
2228
2243
|
var DEFAULT_ALLOW_GRACE = true;
|
|
2229
2244
|
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2230
2245
|
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2246
|
+
var DENIAL_REASON_BY_DENYING_STATUS = {
|
|
2247
|
+
blocked: "blocked",
|
|
2248
|
+
canceled: "canceled",
|
|
2249
|
+
expired: "expired",
|
|
2250
|
+
trial_expired: "trial_expired"
|
|
2251
|
+
};
|
|
2231
2252
|
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2232
2253
|
if (params.hasAccess) {
|
|
2233
2254
|
return null;
|
|
@@ -2238,10 +2259,10 @@ function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
|
2238
2259
|
if (params.isGrace && !allowGrace) {
|
|
2239
2260
|
return "grace_disallowed";
|
|
2240
2261
|
}
|
|
2241
|
-
if (
|
|
2262
|
+
if (ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(params.effectiveStatus)) {
|
|
2242
2263
|
return "blocked";
|
|
2243
2264
|
}
|
|
2244
|
-
return params.effectiveStatus;
|
|
2265
|
+
return DENIAL_REASON_BY_DENYING_STATUS[params.effectiveStatus];
|
|
2245
2266
|
}
|
|
2246
2267
|
function toServiceAccessDecision(response, allowGrace) {
|
|
2247
2268
|
const effectiveStatus = response.effectiveStatus ?? null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-
|
|
2
|
-
import '../../types-
|
|
1
|
+
import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-BhopNmnq.cjs';
|
|
2
|
+
import '../../types-BYdtyO_2.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* FFID SDK - Test mode client (E2E / integration test bypass)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-
|
|
2
|
-
import '../../types-
|
|
1
|
+
import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-DoGYvIll.js';
|
|
2
|
+
import '../../types-BYdtyO_2.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* FFID SDK - Test mode client (E2E / integration test bypass)
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
* branch on a single value:
|
|
18
18
|
*
|
|
19
19
|
* - `active` — normal paying subscription; grant full access.
|
|
20
|
+
* - `active_canceling` — paying subscription with `cancel_at_period_end=true`.
|
|
21
|
+
* Access stays live until `currentPeriodEnd`; callers SHOULD surface a
|
|
22
|
+
* "cancellation scheduled" badge and a reactivation CTA. Session-only
|
|
23
|
+
* refinement of `active` — see the asymmetry note below.
|
|
20
24
|
* - `past_due_grace` — payment failed but FFID is still retrying. Service
|
|
21
25
|
* SHOULD keep access and surface a recovery banner.
|
|
22
26
|
* - `blocked` — payment dunning exhausted (`past_due` over grace,
|
|
@@ -29,9 +33,22 @@
|
|
|
29
33
|
* This is the FFID-internal runtime-expired case (see
|
|
30
34
|
* `getEffectiveSubscriptionStatus` on the server). Deny access.
|
|
31
35
|
*
|
|
36
|
+
* **`active_canceling` is mirrored on the server (#3464, SDK 5.8.0).**
|
|
37
|
+
* Earlier (#3460, SDK 5.7.0) the literal was a session-only enrichment;
|
|
38
|
+
* since FFID #3464 the backend `EffectiveSubscriptionStatus` and both
|
|
39
|
+
* `/api/v1/subscriptions/ext/check` + `/oauth/userinfo` emit
|
|
40
|
+
* `active_canceling` directly when `cancel_at_period_end=true` and the
|
|
41
|
+
* period is still live. SDK consumers receive the same literal whether
|
|
42
|
+
* they read it from the session-derived `computeEffectiveStatusFromSession`
|
|
43
|
+
* or the server-derived `effectiveStatus` on the userinfo / ext-check
|
|
44
|
+
* paths. Pre-#3464 FFID backends omit `cancelAtPeriodEnd` on the wire; the
|
|
45
|
+
* SDK `normalizeUserinfo` boundary defaults it to `false`, so downstream
|
|
46
|
+
* consumers see a plain boolean and `computeEffectiveStatus` returns the
|
|
47
|
+
* original `'active'` verdict for legacy deployments.
|
|
48
|
+
*
|
|
32
49
|
* @see /api/v1/subscriptions/ext/check
|
|
33
50
|
* @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
|
|
34
51
|
*/
|
|
35
|
-
type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
52
|
+
type EffectiveSubscriptionStatus = 'active' | 'active_canceling' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
36
53
|
|
|
37
54
|
export type { EffectiveSubscriptionStatus as E };
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
* branch on a single value:
|
|
18
18
|
*
|
|
19
19
|
* - `active` — normal paying subscription; grant full access.
|
|
20
|
+
* - `active_canceling` — paying subscription with `cancel_at_period_end=true`.
|
|
21
|
+
* Access stays live until `currentPeriodEnd`; callers SHOULD surface a
|
|
22
|
+
* "cancellation scheduled" badge and a reactivation CTA. Session-only
|
|
23
|
+
* refinement of `active` — see the asymmetry note below.
|
|
20
24
|
* - `past_due_grace` — payment failed but FFID is still retrying. Service
|
|
21
25
|
* SHOULD keep access and surface a recovery banner.
|
|
22
26
|
* - `blocked` — payment dunning exhausted (`past_due` over grace,
|
|
@@ -29,9 +33,22 @@
|
|
|
29
33
|
* This is the FFID-internal runtime-expired case (see
|
|
30
34
|
* `getEffectiveSubscriptionStatus` on the server). Deny access.
|
|
31
35
|
*
|
|
36
|
+
* **`active_canceling` is mirrored on the server (#3464, SDK 5.8.0).**
|
|
37
|
+
* Earlier (#3460, SDK 5.7.0) the literal was a session-only enrichment;
|
|
38
|
+
* since FFID #3464 the backend `EffectiveSubscriptionStatus` and both
|
|
39
|
+
* `/api/v1/subscriptions/ext/check` + `/oauth/userinfo` emit
|
|
40
|
+
* `active_canceling` directly when `cancel_at_period_end=true` and the
|
|
41
|
+
* period is still live. SDK consumers receive the same literal whether
|
|
42
|
+
* they read it from the session-derived `computeEffectiveStatusFromSession`
|
|
43
|
+
* or the server-derived `effectiveStatus` on the userinfo / ext-check
|
|
44
|
+
* paths. Pre-#3464 FFID backends omit `cancelAtPeriodEnd` on the wire; the
|
|
45
|
+
* SDK `normalizeUserinfo` boundary defaults it to `false`, so downstream
|
|
46
|
+
* consumers see a plain boolean and `computeEffectiveStatus` returns the
|
|
47
|
+
* original `'active'` verdict for legacy deployments.
|
|
48
|
+
*
|
|
32
49
|
* @see /api/v1/subscriptions/ext/check
|
|
33
50
|
* @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
|
|
34
51
|
*/
|
|
35
|
-
type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
52
|
+
type EffectiveSubscriptionStatus = 'active' | 'active_canceling' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
36
53
|
|
|
37
54
|
export type { EffectiveSubscriptionStatus as E };
|
package/dist/webhooks/index.d.ts
CHANGED