@feelflow/ffid-sdk 4.1.0 → 4.3.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 +66 -0
- package/dist/{chunk-P7HSNT4U.js → chunk-35UOD62N.js} +156 -3
- package/dist/{chunk-OYCNHBMG.cjs → chunk-5MO7G2JW.cjs} +156 -3
- 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-ZcJhRbD6.d.cts → ffid-client-BaStAONh.d.ts} +110 -11
- package/dist/{ffid-client-ZcJhRbD6.d.ts → ffid-client-DgprK2ec.d.cts} +110 -11
- package/dist/{index-Cn8-3hgb.d.cts → index-CInGR4I9.d.cts} +102 -11
- package/dist/{index-Cn8-3hgb.d.ts → index-CInGR4I9.d.ts} +102 -11
- package/dist/index.cjs +32 -32
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +156 -3
- package/dist/server/index.d.cts +3 -2
- package/dist/server/index.d.ts +3 -2
- package/dist/server/index.js +156 -3
- package/dist/server/test/index.d.cts +2 -1
- package/dist/server/test/index.d.ts +2 -1
- package/dist/types-5g_Bg6Ey.d.cts +37 -0
- package/dist/types-5g_Bg6Ey.d.ts +37 -0
- package/dist/webhooks/index.d.cts +18 -0
- package/dist/webhooks/index.d.ts +18 -0
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -704,6 +704,7 @@ function createSubscriptionMethods(deps) {
|
|
|
704
704
|
var EXT_MEMBERS_ENDPOINT = "/api/v1/organizations/ext/members";
|
|
705
705
|
function createMembersMethods(deps) {
|
|
706
706
|
const { fetchWithAuth, createError, serviceCode } = deps;
|
|
707
|
+
const assignableRoles = /* @__PURE__ */ new Set(["admin", "member", "viewer"]);
|
|
707
708
|
function buildQuery(organizationId) {
|
|
708
709
|
return new URLSearchParams({ organizationId, serviceCode }).toString();
|
|
709
710
|
}
|
|
@@ -717,6 +718,37 @@ function createMembersMethods(deps) {
|
|
|
717
718
|
`${EXT_MEMBERS_ENDPOINT}?${buildQuery(params.organizationId)}`
|
|
718
719
|
);
|
|
719
720
|
}
|
|
721
|
+
function normalizeAddMemberArgs(paramsOrOrganizationId, data) {
|
|
722
|
+
if (typeof paramsOrOrganizationId === "string") {
|
|
723
|
+
const params = {
|
|
724
|
+
organizationId: paramsOrOrganizationId,
|
|
725
|
+
email: data?.email ?? ""
|
|
726
|
+
};
|
|
727
|
+
if (data?.role !== void 0) params.role = data.role;
|
|
728
|
+
return params;
|
|
729
|
+
}
|
|
730
|
+
return paramsOrOrganizationId;
|
|
731
|
+
}
|
|
732
|
+
async function addMember(paramsOrOrganizationId, data) {
|
|
733
|
+
const params = normalizeAddMemberArgs(paramsOrOrganizationId, data);
|
|
734
|
+
if (!params.organizationId || !params.email) {
|
|
735
|
+
return {
|
|
736
|
+
error: createError("VALIDATION_ERROR", "organizationId \u3068 email \u306F\u5FC5\u9808\u3067\u3059")
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
if (params.role !== void 0 && !assignableRoles.has(params.role)) {
|
|
740
|
+
return {
|
|
741
|
+
error: createError("VALIDATION_ERROR", "role \u306F admin\u3001member\u3001viewer \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044")
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
return fetchWithAuth(
|
|
745
|
+
`${EXT_MEMBERS_ENDPOINT}?${buildQuery(params.organizationId)}`,
|
|
746
|
+
{
|
|
747
|
+
method: "POST",
|
|
748
|
+
body: JSON.stringify({ email: params.email, role: params.role })
|
|
749
|
+
}
|
|
750
|
+
);
|
|
751
|
+
}
|
|
720
752
|
async function updateMemberRole(params) {
|
|
721
753
|
if (!params.organizationId || !params.userId) {
|
|
722
754
|
return {
|
|
@@ -749,7 +781,7 @@ function createMembersMethods(deps) {
|
|
|
749
781
|
}
|
|
750
782
|
);
|
|
751
783
|
}
|
|
752
|
-
return { listMembers, updateMemberRole, removeMember };
|
|
784
|
+
return { listMembers, addMember, updateMemberRole, removeMember };
|
|
753
785
|
}
|
|
754
786
|
|
|
755
787
|
// src/client/profile-methods.ts
|
|
@@ -802,7 +834,7 @@ function createProfileMethods(deps) {
|
|
|
802
834
|
}
|
|
803
835
|
|
|
804
836
|
// src/client/version-check.ts
|
|
805
|
-
var SDK_VERSION = "4.
|
|
837
|
+
var SDK_VERSION = "4.3.0";
|
|
806
838
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
807
839
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
808
840
|
function sdkHeaders() {
|
|
@@ -2179,6 +2211,73 @@ var FFID_ERROR_CODES = {
|
|
|
2179
2211
|
TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
|
|
2180
2212
|
};
|
|
2181
2213
|
var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
2214
|
+
var DEFAULT_ALLOW_GRACE = true;
|
|
2215
|
+
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2216
|
+
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2217
|
+
var ACCESS_GRANTING_EFFECTIVE_STATUSES = ["active", "past_due_grace"];
|
|
2218
|
+
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
2219
|
+
"blocked",
|
|
2220
|
+
"canceled",
|
|
2221
|
+
"expired",
|
|
2222
|
+
"trial_expired"
|
|
2223
|
+
];
|
|
2224
|
+
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2225
|
+
if (params.hasAccess) {
|
|
2226
|
+
return null;
|
|
2227
|
+
}
|
|
2228
|
+
if (params.effectiveStatus === null) {
|
|
2229
|
+
return "no_subscription";
|
|
2230
|
+
}
|
|
2231
|
+
if (params.isGrace && !allowGrace) {
|
|
2232
|
+
return "grace_disallowed";
|
|
2233
|
+
}
|
|
2234
|
+
if (params.effectiveStatus === "active" || params.effectiveStatus === "past_due_grace") {
|
|
2235
|
+
return "blocked";
|
|
2236
|
+
}
|
|
2237
|
+
return params.effectiveStatus;
|
|
2238
|
+
}
|
|
2239
|
+
function toServiceAccessDecision(response, allowGrace) {
|
|
2240
|
+
const effectiveStatus = response.effectiveStatus ?? null;
|
|
2241
|
+
const serverHasAccess = response.hasAccess ?? (effectiveStatus !== null && ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
2242
|
+
const isGrace = response.isGrace ?? effectiveStatus === "past_due_grace";
|
|
2243
|
+
const hasAccess = serverHasAccess && (allowGrace || !isGrace);
|
|
2244
|
+
const isBlocked = response.isBlocked ?? (effectiveStatus === null || effectiveStatus !== null && BLOCKING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
2245
|
+
return {
|
|
2246
|
+
hasAccess,
|
|
2247
|
+
effectiveStatus,
|
|
2248
|
+
isGrace,
|
|
2249
|
+
isBlocked: isBlocked || !hasAccess,
|
|
2250
|
+
allowGrace,
|
|
2251
|
+
failPolicy: DEFAULT_SERVICE_ACCESS_FAIL_POLICY,
|
|
2252
|
+
denialReason: resolveServiceAccessDenialReason({ effectiveStatus, hasAccess, isGrace }, allowGrace),
|
|
2253
|
+
organizationId: response.organizationId,
|
|
2254
|
+
subscriptionId: response.subscriptionId,
|
|
2255
|
+
status: response.status,
|
|
2256
|
+
planCode: response.planCode,
|
|
2257
|
+
currentPeriodEnd: response.currentPeriodEnd,
|
|
2258
|
+
gracePeriodEndsAt: response.gracePeriodEndsAt ?? null,
|
|
2259
|
+
reactivatable: response.reactivatable ?? false
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
function failClosedServiceAccessDecision(params, error) {
|
|
2263
|
+
return {
|
|
2264
|
+
hasAccess: false,
|
|
2265
|
+
effectiveStatus: null,
|
|
2266
|
+
isGrace: false,
|
|
2267
|
+
isBlocked: true,
|
|
2268
|
+
allowGrace: params.allowGrace ?? DEFAULT_ALLOW_GRACE,
|
|
2269
|
+
failPolicy: DEFAULT_SERVICE_ACCESS_FAIL_POLICY,
|
|
2270
|
+
denialReason: "ffid_unreachable",
|
|
2271
|
+
organizationId: params.organizationId || null,
|
|
2272
|
+
subscriptionId: null,
|
|
2273
|
+
status: null,
|
|
2274
|
+
planCode: null,
|
|
2275
|
+
currentPeriodEnd: null,
|
|
2276
|
+
gracePeriodEndsAt: null,
|
|
2277
|
+
reactivatable: false,
|
|
2278
|
+
error
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2182
2281
|
function resolveRedirectUri(raw, logger) {
|
|
2183
2282
|
if (raw === null) return null;
|
|
2184
2283
|
try {
|
|
@@ -2417,6 +2516,57 @@ function createFFIDClient(config) {
|
|
|
2417
2516
|
`${EXT_CHECK_ENDPOINT}?${query.toString()}`
|
|
2418
2517
|
);
|
|
2419
2518
|
}
|
|
2519
|
+
async function checkServiceAccess(params) {
|
|
2520
|
+
const failPolicy = params.failPolicy ?? DEFAULT_SERVICE_ACCESS_FAIL_POLICY;
|
|
2521
|
+
if (failPolicy !== DEFAULT_SERVICE_ACCESS_FAIL_POLICY) {
|
|
2522
|
+
return {
|
|
2523
|
+
error: createError(
|
|
2524
|
+
"VALIDATION_ERROR",
|
|
2525
|
+
`failPolicy \u306F ${DEFAULT_SERVICE_ACCESS_FAIL_POLICY} \u306E\u307F\u6307\u5B9A\u3067\u304D\u307E\u3059`
|
|
2526
|
+
)
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
const subscriptionParams = {
|
|
2530
|
+
organizationId: params.organizationId
|
|
2531
|
+
};
|
|
2532
|
+
if (params.userId !== void 0) {
|
|
2533
|
+
subscriptionParams.userId = params.userId;
|
|
2534
|
+
}
|
|
2535
|
+
const subscriptionResult = await checkSubscription(subscriptionParams);
|
|
2536
|
+
if (subscriptionResult.error) {
|
|
2537
|
+
if (subscriptionResult.error.code === "VALIDATION_ERROR") {
|
|
2538
|
+
return { error: subscriptionResult.error };
|
|
2539
|
+
}
|
|
2540
|
+
return {
|
|
2541
|
+
data: failClosedServiceAccessDecision(params, subscriptionResult.error)
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2544
|
+
return {
|
|
2545
|
+
data: toServiceAccessDecision(
|
|
2546
|
+
subscriptionResult.data,
|
|
2547
|
+
params.allowGrace ?? DEFAULT_ALLOW_GRACE
|
|
2548
|
+
)
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
async function requireServiceAccess(params) {
|
|
2552
|
+
const result = await checkServiceAccess(params);
|
|
2553
|
+
if (result.error) {
|
|
2554
|
+
return result;
|
|
2555
|
+
}
|
|
2556
|
+
if (!result.data.hasAccess) {
|
|
2557
|
+
const error = createError(
|
|
2558
|
+
SERVICE_ACCESS_DENIED_CODE,
|
|
2559
|
+
`FFID service access denied: ${result.data.denialReason ?? "unknown"}`
|
|
2560
|
+
);
|
|
2561
|
+
if (result.data.error) {
|
|
2562
|
+
error.details = { cause: result.data.error };
|
|
2563
|
+
}
|
|
2564
|
+
return {
|
|
2565
|
+
error
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
return result;
|
|
2569
|
+
}
|
|
2420
2570
|
const { createCheckoutSession, createPortalSession } = createBillingMethods({
|
|
2421
2571
|
fetchWithAuth,
|
|
2422
2572
|
createError
|
|
@@ -2434,7 +2584,7 @@ function createFFIDClient(config) {
|
|
|
2434
2584
|
fetchWithAuth,
|
|
2435
2585
|
createError
|
|
2436
2586
|
});
|
|
2437
|
-
const { listMembers, updateMemberRole, removeMember } = createMembersMethods({
|
|
2587
|
+
const { listMembers, addMember, updateMemberRole, removeMember } = createMembersMethods({
|
|
2438
2588
|
fetchWithAuth,
|
|
2439
2589
|
createError,
|
|
2440
2590
|
serviceCode: config.serviceCode
|
|
@@ -2515,7 +2665,10 @@ function createFFIDClient(config) {
|
|
|
2515
2665
|
exchangeCodeForTokens,
|
|
2516
2666
|
refreshAccessToken,
|
|
2517
2667
|
checkSubscription,
|
|
2668
|
+
checkServiceAccess,
|
|
2669
|
+
requireServiceAccess,
|
|
2518
2670
|
listMembers,
|
|
2671
|
+
addMember,
|
|
2519
2672
|
updateMemberRole,
|
|
2520
2673
|
removeMember,
|
|
2521
2674
|
getProfile,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-DgprK2ec.cjs';
|
|
2
|
+
import '../../types-5g_Bg6Ey.cjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* FFID SDK - Test mode client (E2E / integration test bypass)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-BaStAONh.js';
|
|
2
|
+
import '../../types-5g_Bg6Ey.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* FFID SDK - Test mode client (E2E / integration test bypass)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription access-control types (Chain of Pacts / Issue #2443).
|
|
3
|
+
*
|
|
4
|
+
* Defines `EffectiveSubscriptionStatus` — the semantic status surfaced by
|
|
5
|
+
* `/api/v1/subscriptions/ext/check` for external services that need a single
|
|
6
|
+
* value to drive access-control decisions. Mirrors the server-side type in
|
|
7
|
+
* `src/lib/common/subscription-helpers.ts` so the FFID backend, SDK, and
|
|
8
|
+
* consuming services agree on the same vocabulary.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Semantic subscription status used for access-control decisions by external
|
|
12
|
+
* services.
|
|
13
|
+
*
|
|
14
|
+
* Unlike the raw DB `FFIDSubscriptionStatus` (which keeps the Stripe-aligned
|
|
15
|
+
* status machine, e.g. `past_due` / `incomplete` / `incomplete_expired`), this
|
|
16
|
+
* narrowed union flattens dunning-window vs. hard-block cases so callers can
|
|
17
|
+
* branch on a single value:
|
|
18
|
+
*
|
|
19
|
+
* - `active` — normal paying subscription; grant full access.
|
|
20
|
+
* - `past_due_grace` — payment failed but FFID is still retrying. Service
|
|
21
|
+
* SHOULD keep access and surface a recovery banner.
|
|
22
|
+
* - `blocked` — payment dunning exhausted (`past_due` over grace,
|
|
23
|
+
* `unpaid`, `incomplete_expired`, `paused`, `incomplete`). Deny access.
|
|
24
|
+
* - `canceled` — contract ended (voluntary or auto-cancel). Deny access;
|
|
25
|
+
* check the accompanying `reactivatable` flag before showing a restart CTA.
|
|
26
|
+
* - `trial_expired` — `status = 'trialing'` but the trial end is in the past.
|
|
27
|
+
* DB row is still `trialing`; deny access and prompt for a paid plan.
|
|
28
|
+
* - `expired` — `status = 'active'` but `current_period_end` is in the past.
|
|
29
|
+
* This is the FFID-internal runtime-expired case (see
|
|
30
|
+
* `getEffectiveSubscriptionStatus` on the server). Deny access.
|
|
31
|
+
*
|
|
32
|
+
* @see /api/v1/subscriptions/ext/check
|
|
33
|
+
* @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
|
|
34
|
+
*/
|
|
35
|
+
type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
36
|
+
|
|
37
|
+
export type { EffectiveSubscriptionStatus as E };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription access-control types (Chain of Pacts / Issue #2443).
|
|
3
|
+
*
|
|
4
|
+
* Defines `EffectiveSubscriptionStatus` — the semantic status surfaced by
|
|
5
|
+
* `/api/v1/subscriptions/ext/check` for external services that need a single
|
|
6
|
+
* value to drive access-control decisions. Mirrors the server-side type in
|
|
7
|
+
* `src/lib/common/subscription-helpers.ts` so the FFID backend, SDK, and
|
|
8
|
+
* consuming services agree on the same vocabulary.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Semantic subscription status used for access-control decisions by external
|
|
12
|
+
* services.
|
|
13
|
+
*
|
|
14
|
+
* Unlike the raw DB `FFIDSubscriptionStatus` (which keeps the Stripe-aligned
|
|
15
|
+
* status machine, e.g. `past_due` / `incomplete` / `incomplete_expired`), this
|
|
16
|
+
* narrowed union flattens dunning-window vs. hard-block cases so callers can
|
|
17
|
+
* branch on a single value:
|
|
18
|
+
*
|
|
19
|
+
* - `active` — normal paying subscription; grant full access.
|
|
20
|
+
* - `past_due_grace` — payment failed but FFID is still retrying. Service
|
|
21
|
+
* SHOULD keep access and surface a recovery banner.
|
|
22
|
+
* - `blocked` — payment dunning exhausted (`past_due` over grace,
|
|
23
|
+
* `unpaid`, `incomplete_expired`, `paused`, `incomplete`). Deny access.
|
|
24
|
+
* - `canceled` — contract ended (voluntary or auto-cancel). Deny access;
|
|
25
|
+
* check the accompanying `reactivatable` flag before showing a restart CTA.
|
|
26
|
+
* - `trial_expired` — `status = 'trialing'` but the trial end is in the past.
|
|
27
|
+
* DB row is still `trialing`; deny access and prompt for a paid plan.
|
|
28
|
+
* - `expired` — `status = 'active'` but `current_period_end` is in the past.
|
|
29
|
+
* This is the FFID-internal runtime-expired case (see
|
|
30
|
+
* `getEffectiveSubscriptionStatus` on the server). Deny access.
|
|
31
|
+
*
|
|
32
|
+
* @see /api/v1/subscriptions/ext/check
|
|
33
|
+
* @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
|
|
34
|
+
*/
|
|
35
|
+
type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
|
|
36
|
+
|
|
37
|
+
export type { EffectiveSubscriptionStatus as E };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { E as EffectiveSubscriptionStatus } from '../types-5g_Bg6Ey.cjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* FFID Webhook SDK Constants
|
|
3
5
|
*
|
|
@@ -43,6 +45,7 @@ declare class FFIDWebhookPayloadError extends FFIDWebhookError {
|
|
|
43
45
|
* Types for receiving and verifying FeelFlow ID webhook events.
|
|
44
46
|
* Used by external services to handle real-time event notifications.
|
|
45
47
|
*/
|
|
48
|
+
|
|
46
49
|
/** All supported webhook event types */
|
|
47
50
|
type FFIDWebhookEventType = 'subscription.created' | 'subscription.updated' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'test.ping';
|
|
48
51
|
interface FFIDSubscriptionCreatedPayload {
|
|
@@ -50,6 +53,8 @@ interface FFIDSubscriptionCreatedPayload {
|
|
|
50
53
|
organizationId?: string;
|
|
51
54
|
plan?: string;
|
|
52
55
|
status?: string;
|
|
56
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
57
|
+
gracePeriodEndsAt?: string | null;
|
|
53
58
|
}
|
|
54
59
|
interface FFIDSubscriptionUpdatedPayload {
|
|
55
60
|
subscriptionId: string;
|
|
@@ -57,6 +62,8 @@ interface FFIDSubscriptionUpdatedPayload {
|
|
|
57
62
|
plan?: string;
|
|
58
63
|
previousPlan?: string;
|
|
59
64
|
status?: string;
|
|
65
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
66
|
+
gracePeriodEndsAt?: string | null;
|
|
60
67
|
}
|
|
61
68
|
interface FFIDSubscriptionCanceledPayload {
|
|
62
69
|
/** FFID subscription UUID. */
|
|
@@ -86,6 +93,10 @@ interface FFIDSubscriptionCanceledPayload {
|
|
|
86
93
|
* when Stripe runs out the paid period before emitting the deletion event.
|
|
87
94
|
*/
|
|
88
95
|
expiredAt?: string;
|
|
96
|
+
/** Cancellation always leaves the canonical access-control status as `canceled`. */
|
|
97
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
98
|
+
/** Always null for cancellation events because no grace window remains. */
|
|
99
|
+
gracePeriodEndsAt?: string | null;
|
|
89
100
|
}
|
|
90
101
|
interface FFIDSubscriptionDowngradeScheduledPayload {
|
|
91
102
|
/** FFID subscription UUID. */
|
|
@@ -172,6 +183,13 @@ interface FFIDSubscriptionPaymentFailedPayload {
|
|
|
172
183
|
* `null` means already blocking.
|
|
173
184
|
*/
|
|
174
185
|
graceUntil?: string | null;
|
|
186
|
+
/** Canonical FFID access-control status derived from payment-failure severity. */
|
|
187
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
188
|
+
/**
|
|
189
|
+
* Alias of `graceUntil` for canonical access payloads; services should prefer
|
|
190
|
+
* this field when sharing code with `/subscriptions/ext/check`.
|
|
191
|
+
*/
|
|
192
|
+
gracePeriodEndsAt?: string | null;
|
|
175
193
|
/**
|
|
176
194
|
* `true` when the FFID server could not resolve `stripeSubscriptionId` to an
|
|
177
195
|
* FFID subscription row (e.g. race with a not-yet-synced sub, or invoice
|
package/dist/webhooks/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { E as EffectiveSubscriptionStatus } from '../types-5g_Bg6Ey.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* FFID Webhook SDK Constants
|
|
3
5
|
*
|
|
@@ -43,6 +45,7 @@ declare class FFIDWebhookPayloadError extends FFIDWebhookError {
|
|
|
43
45
|
* Types for receiving and verifying FeelFlow ID webhook events.
|
|
44
46
|
* Used by external services to handle real-time event notifications.
|
|
45
47
|
*/
|
|
48
|
+
|
|
46
49
|
/** All supported webhook event types */
|
|
47
50
|
type FFIDWebhookEventType = 'subscription.created' | 'subscription.updated' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'test.ping';
|
|
48
51
|
interface FFIDSubscriptionCreatedPayload {
|
|
@@ -50,6 +53,8 @@ interface FFIDSubscriptionCreatedPayload {
|
|
|
50
53
|
organizationId?: string;
|
|
51
54
|
plan?: string;
|
|
52
55
|
status?: string;
|
|
56
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
57
|
+
gracePeriodEndsAt?: string | null;
|
|
53
58
|
}
|
|
54
59
|
interface FFIDSubscriptionUpdatedPayload {
|
|
55
60
|
subscriptionId: string;
|
|
@@ -57,6 +62,8 @@ interface FFIDSubscriptionUpdatedPayload {
|
|
|
57
62
|
plan?: string;
|
|
58
63
|
previousPlan?: string;
|
|
59
64
|
status?: string;
|
|
65
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
66
|
+
gracePeriodEndsAt?: string | null;
|
|
60
67
|
}
|
|
61
68
|
interface FFIDSubscriptionCanceledPayload {
|
|
62
69
|
/** FFID subscription UUID. */
|
|
@@ -86,6 +93,10 @@ interface FFIDSubscriptionCanceledPayload {
|
|
|
86
93
|
* when Stripe runs out the paid period before emitting the deletion event.
|
|
87
94
|
*/
|
|
88
95
|
expiredAt?: string;
|
|
96
|
+
/** Cancellation always leaves the canonical access-control status as `canceled`. */
|
|
97
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
98
|
+
/** Always null for cancellation events because no grace window remains. */
|
|
99
|
+
gracePeriodEndsAt?: string | null;
|
|
89
100
|
}
|
|
90
101
|
interface FFIDSubscriptionDowngradeScheduledPayload {
|
|
91
102
|
/** FFID subscription UUID. */
|
|
@@ -172,6 +183,13 @@ interface FFIDSubscriptionPaymentFailedPayload {
|
|
|
172
183
|
* `null` means already blocking.
|
|
173
184
|
*/
|
|
174
185
|
graceUntil?: string | null;
|
|
186
|
+
/** Canonical FFID access-control status derived from payment-failure severity. */
|
|
187
|
+
effectiveStatus?: EffectiveSubscriptionStatus;
|
|
188
|
+
/**
|
|
189
|
+
* Alias of `graceUntil` for canonical access payloads; services should prefer
|
|
190
|
+
* this field when sharing code with `/subscriptions/ext/check`.
|
|
191
|
+
*/
|
|
192
|
+
gracePeriodEndsAt?: string | null;
|
|
175
193
|
/**
|
|
176
194
|
* `true` when the FFID server could not resolve `stripeSubscriptionId` to an
|
|
177
195
|
* FFID subscription row (e.g. race with a not-yet-synced sub, or invoice
|