@feelflow/ffid-sdk 5.5.0 → 5.7.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.
@@ -837,7 +837,7 @@ function createProfileMethods(deps) {
837
837
  }
838
838
 
839
839
  // src/client/version-check.ts
840
- var SDK_VERSION = "5.5.0";
840
+ var SDK_VERSION = "5.7.0";
841
841
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
842
842
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
843
843
  function sdkHeaders() {
@@ -2190,6 +2190,7 @@ function createInquiryMethods(deps) {
2190
2190
  // src/subscriptions/userinfo-helpers.ts
2191
2191
  var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
2192
2192
  "active",
2193
+ "active_canceling",
2193
2194
  "past_due_grace"
2194
2195
  ];
2195
2196
  var BLOCKING_EFFECTIVE_STATUSES = [
@@ -2229,6 +2230,12 @@ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
2229
2230
  var DEFAULT_ALLOW_GRACE = true;
2230
2231
  var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
2231
2232
  var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
2233
+ var DENIAL_REASON_BY_DENYING_STATUS = {
2234
+ blocked: "blocked",
2235
+ canceled: "canceled",
2236
+ expired: "expired",
2237
+ trial_expired: "trial_expired"
2238
+ };
2232
2239
  function resolveServiceAccessDenialReason(params, allowGrace) {
2233
2240
  if (params.hasAccess) {
2234
2241
  return null;
@@ -2239,10 +2246,10 @@ function resolveServiceAccessDenialReason(params, allowGrace) {
2239
2246
  if (params.isGrace && !allowGrace) {
2240
2247
  return "grace_disallowed";
2241
2248
  }
2242
- if (params.effectiveStatus === "active" || params.effectiveStatus === "past_due_grace") {
2249
+ if (ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(params.effectiveStatus)) {
2243
2250
  return "blocked";
2244
2251
  }
2245
- return params.effectiveStatus;
2252
+ return DENIAL_REASON_BY_DENYING_STATUS[params.effectiveStatus];
2246
2253
  }
2247
2254
  function toServiceAccessDecision(response, allowGrace) {
2248
2255
  const effectiveStatus = response.effectiveStatus ?? null;
@@ -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-CARfFhtf.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-CARfFhtf.cjs';
1
+ import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-CknwTgly.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-CknwTgly.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-5g_Bg6Ey.cjs';
5
+ import '../types-s3y11uT6.cjs';
6
6
 
7
7
  /** Token verification - verifyAccessToken() implementation */
8
8
 
@@ -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-w1s-JnFf.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-w1s-JnFf.js';
1
+ import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-C0k2PTbO.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-C0k2PTbO.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-5g_Bg6Ey.js';
5
+ import '../types-s3y11uT6.js';
6
6
 
7
7
  /** Token verification - verifyAccessToken() implementation */
8
8
 
@@ -836,7 +836,7 @@ function createProfileMethods(deps) {
836
836
  }
837
837
 
838
838
  // src/client/version-check.ts
839
- var SDK_VERSION = "5.5.0";
839
+ var SDK_VERSION = "5.7.0";
840
840
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
841
841
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
842
842
  function sdkHeaders() {
@@ -2189,6 +2189,7 @@ function createInquiryMethods(deps) {
2189
2189
  // src/subscriptions/userinfo-helpers.ts
2190
2190
  var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
2191
2191
  "active",
2192
+ "active_canceling",
2192
2193
  "past_due_grace"
2193
2194
  ];
2194
2195
  var BLOCKING_EFFECTIVE_STATUSES = [
@@ -2228,6 +2229,12 @@ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
2228
2229
  var DEFAULT_ALLOW_GRACE = true;
2229
2230
  var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
2230
2231
  var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
2232
+ var DENIAL_REASON_BY_DENYING_STATUS = {
2233
+ blocked: "blocked",
2234
+ canceled: "canceled",
2235
+ expired: "expired",
2236
+ trial_expired: "trial_expired"
2237
+ };
2231
2238
  function resolveServiceAccessDenialReason(params, allowGrace) {
2232
2239
  if (params.hasAccess) {
2233
2240
  return null;
@@ -2238,10 +2245,10 @@ function resolveServiceAccessDenialReason(params, allowGrace) {
2238
2245
  if (params.isGrace && !allowGrace) {
2239
2246
  return "grace_disallowed";
2240
2247
  }
2241
- if (params.effectiveStatus === "active" || params.effectiveStatus === "past_due_grace") {
2248
+ if (ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(params.effectiveStatus)) {
2242
2249
  return "blocked";
2243
2250
  }
2244
- return params.effectiveStatus;
2251
+ return DENIAL_REASON_BY_DENYING_STATUS[params.effectiveStatus];
2245
2252
  }
2246
2253
  function toServiceAccessDecision(response, allowGrace) {
2247
2254
  const effectiveStatus = response.effectiveStatus ?? null;
@@ -1,5 +1,5 @@
1
- import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-CARfFhtf.cjs';
2
- import '../../types-5g_Bg6Ey.cjs';
1
+ import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-CknwTgly.cjs';
2
+ import '../../types-s3y11uT6.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-w1s-JnFf.js';
2
- import '../../types-5g_Bg6Ey.js';
1
+ import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-C0k2PTbO.js';
2
+ import '../../types-s3y11uT6.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,26 @@
29
33
  * This is the FFID-internal runtime-expired case (see
30
34
  * `getEffectiveSubscriptionStatus` on the server). Deny access.
31
35
  *
36
+ * **SDK / server asymmetry — `active_canceling` is session-only (#3460).**
37
+ * The backend `EffectiveSubscriptionStatus` in
38
+ * `src/lib/common/subscription-helpers.ts` does NOT currently include
39
+ * `active_canceling`; cancellation-scheduled subscriptions surface as plain
40
+ * `'active'` on `/api/v1/subscriptions/ext/check` and `/oauth/userinfo`, and
41
+ * consumers that branch on the server verdict will not see the new literal.
42
+ * The SDK enriches `computeEffectiveStatusFromSession` with
43
+ * `cancelAtPeriodEnd` (carried on `FFIDSubscription` for FFID backends from
44
+ * #3460 onward — older backends omit the field and the helper defaults to
45
+ * `false`, preserving the pre-#3460 `'active'` verdict) so `useSubscription`
46
+ * can surface a "cancellation scheduled" badge without waiting for an
47
+ * `/ext/check` round-trip. The asymmetry is safe because the new literal is
48
+ * access-granting (no security regression on the userinfo path); when the
49
+ * server's `EffectiveSubscriptionStatus` is later extended to emit
50
+ * `active_canceling`, this docstring MUST be updated to drop the
51
+ * session-only note.
52
+ *
32
53
  * @see /api/v1/subscriptions/ext/check
33
54
  * @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
34
55
  */
35
- type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
56
+ type EffectiveSubscriptionStatus = 'active' | 'active_canceling' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
36
57
 
37
58
  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,26 @@
29
33
  * This is the FFID-internal runtime-expired case (see
30
34
  * `getEffectiveSubscriptionStatus` on the server). Deny access.
31
35
  *
36
+ * **SDK / server asymmetry — `active_canceling` is session-only (#3460).**
37
+ * The backend `EffectiveSubscriptionStatus` in
38
+ * `src/lib/common/subscription-helpers.ts` does NOT currently include
39
+ * `active_canceling`; cancellation-scheduled subscriptions surface as plain
40
+ * `'active'` on `/api/v1/subscriptions/ext/check` and `/oauth/userinfo`, and
41
+ * consumers that branch on the server verdict will not see the new literal.
42
+ * The SDK enriches `computeEffectiveStatusFromSession` with
43
+ * `cancelAtPeriodEnd` (carried on `FFIDSubscription` for FFID backends from
44
+ * #3460 onward — older backends omit the field and the helper defaults to
45
+ * `false`, preserving the pre-#3460 `'active'` verdict) so `useSubscription`
46
+ * can surface a "cancellation scheduled" badge without waiting for an
47
+ * `/ext/check` round-trip. The asymmetry is safe because the new literal is
48
+ * access-granting (no security regression on the userinfo path); when the
49
+ * server's `EffectiveSubscriptionStatus` is later extended to emit
50
+ * `active_canceling`, this docstring MUST be updated to drop the
51
+ * session-only note.
52
+ *
32
53
  * @see /api/v1/subscriptions/ext/check
33
54
  * @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md
34
55
  */
35
- type EffectiveSubscriptionStatus = 'active' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
56
+ type EffectiveSubscriptionStatus = 'active' | 'active_canceling' | 'past_due_grace' | 'blocked' | 'canceled' | 'trial_expired' | 'expired';
36
57
 
37
58
  export type { EffectiveSubscriptionStatus as E };
@@ -1,4 +1,4 @@
1
- import { E as EffectiveSubscriptionStatus } from '../types-5g_Bg6Ey.cjs';
1
+ import { E as EffectiveSubscriptionStatus } from '../types-s3y11uT6.cjs';
2
2
 
3
3
  /**
4
4
  * FFID Webhook SDK Constants
@@ -1,4 +1,4 @@
1
- import { E as EffectiveSubscriptionStatus } from '../types-5g_Bg6Ey.js';
1
+ import { E as EffectiveSubscriptionStatus } from '../types-s3y11uT6.js';
2
2
 
3
3
  /**
4
4
  * FFID Webhook SDK Constants
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feelflow/ffid-sdk",
3
- "version": "5.5.0",
3
+ "version": "5.7.0",
4
4
  "description": "FeelFlow ID Platform SDK for React/Next.js applications",
5
5
  "keywords": [
6
6
  "feelflow",