@feelflow/ffid-sdk 5.7.0 → 5.9.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/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkFXIDKFXQ_cjs = require('./chunk-FXIDKFXQ.cjs');
3
+ var chunkA6MOPB7D_cjs = require('./chunk-A6MOPB7D.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 } = chunkFXIDKFXQ_cjs.useFFIDContext();
58
- const { effectiveStatus, isBlocked, isGrace } = chunkFXIDKFXQ_cjs.useSubscription();
57
+ const { isLoading, error } = chunkA6MOPB7D_cjs.useFFIDContext();
58
+ const { effectiveStatus, isBlocked, isGrace } = chunkA6MOPB7D_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 } = chunkFXIDKFXQ_cjs.useFFIDContext();
79
+ const { isLoading, isAuthenticated, login } = chunkA6MOPB7D_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 chunkFXIDKFXQ_cjs.ACCESS_GRANTING_EFFECTIVE_STATUSES; }
108
+ get: function () { return chunkA6MOPB7D_cjs.ACCESS_GRANTING_EFFECTIVE_STATUSES; }
109
109
  });
110
110
  Object.defineProperty(exports, "BLOCKING_EFFECTIVE_STATUSES", {
111
111
  enumerable: true,
112
- get: function () { return chunkFXIDKFXQ_cjs.BLOCKING_EFFECTIVE_STATUSES; }
112
+ get: function () { return chunkA6MOPB7D_cjs.BLOCKING_EFFECTIVE_STATUSES; }
113
113
  });
114
114
  Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
115
115
  enumerable: true,
116
- get: function () { return chunkFXIDKFXQ_cjs.DEFAULT_API_BASE_URL; }
116
+ get: function () { return chunkA6MOPB7D_cjs.DEFAULT_API_BASE_URL; }
117
117
  });
118
118
  Object.defineProperty(exports, "DEFAULT_OAUTH_SCOPES", {
119
119
  enumerable: true,
120
- get: function () { return chunkFXIDKFXQ_cjs.DEFAULT_OAUTH_SCOPES; }
120
+ get: function () { return chunkA6MOPB7D_cjs.DEFAULT_OAUTH_SCOPES; }
121
121
  });
122
122
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
123
123
  enumerable: true,
124
- get: function () { return chunkFXIDKFXQ_cjs.FFIDAnnouncementBadge; }
124
+ get: function () { return chunkA6MOPB7D_cjs.FFIDAnnouncementBadge; }
125
125
  });
126
126
  Object.defineProperty(exports, "FFIDAnnouncementList", {
127
127
  enumerable: true,
128
- get: function () { return chunkFXIDKFXQ_cjs.FFIDAnnouncementList; }
128
+ get: function () { return chunkA6MOPB7D_cjs.FFIDAnnouncementList; }
129
129
  });
130
130
  Object.defineProperty(exports, "FFIDInquiryForm", {
131
131
  enumerable: true,
132
- get: function () { return chunkFXIDKFXQ_cjs.FFIDInquiryForm; }
132
+ get: function () { return chunkA6MOPB7D_cjs.FFIDInquiryForm; }
133
133
  });
134
134
  Object.defineProperty(exports, "FFIDLoginButton", {
135
135
  enumerable: true,
136
- get: function () { return chunkFXIDKFXQ_cjs.FFIDLoginButton; }
136
+ get: function () { return chunkA6MOPB7D_cjs.FFIDLoginButton; }
137
137
  });
138
138
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
139
139
  enumerable: true,
140
- get: function () { return chunkFXIDKFXQ_cjs.FFIDOrganizationSwitcher; }
140
+ get: function () { return chunkA6MOPB7D_cjs.FFIDOrganizationSwitcher; }
141
141
  });
142
142
  Object.defineProperty(exports, "FFIDProvider", {
143
143
  enumerable: true,
144
- get: function () { return chunkFXIDKFXQ_cjs.FFIDProvider; }
144
+ get: function () { return chunkA6MOPB7D_cjs.FFIDProvider; }
145
145
  });
146
146
  Object.defineProperty(exports, "FFIDSDKError", {
147
147
  enumerable: true,
148
- get: function () { return chunkFXIDKFXQ_cjs.FFIDSDKError; }
148
+ get: function () { return chunkA6MOPB7D_cjs.FFIDSDKError; }
149
149
  });
150
150
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
151
151
  enumerable: true,
152
- get: function () { return chunkFXIDKFXQ_cjs.FFIDSubscriptionBadge; }
152
+ get: function () { return chunkA6MOPB7D_cjs.FFIDSubscriptionBadge; }
153
153
  });
154
154
  Object.defineProperty(exports, "FFIDUserMenu", {
155
155
  enumerable: true,
156
- get: function () { return chunkFXIDKFXQ_cjs.FFIDUserMenu; }
156
+ get: function () { return chunkA6MOPB7D_cjs.FFIDUserMenu; }
157
157
  });
158
158
  Object.defineProperty(exports, "FFID_ANNOUNCEMENTS_ERROR_CODES", {
159
159
  enumerable: true,
160
- get: function () { return chunkFXIDKFXQ_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
160
+ get: function () { return chunkA6MOPB7D_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
161
161
  });
162
162
  Object.defineProperty(exports, "FFID_INQUIRY_CATEGORIES", {
163
163
  enumerable: true,
164
- get: function () { return chunkFXIDKFXQ_cjs.FFID_INQUIRY_CATEGORIES; }
164
+ get: function () { return chunkA6MOPB7D_cjs.FFID_INQUIRY_CATEGORIES; }
165
165
  });
166
166
  Object.defineProperty(exports, "FFID_INQUIRY_CATEGORIES_SITE_2026", {
167
167
  enumerable: true,
168
- get: function () { return chunkFXIDKFXQ_cjs.FFID_INQUIRY_CATEGORIES_SITE_2026; }
168
+ get: function () { return chunkA6MOPB7D_cjs.FFID_INQUIRY_CATEGORIES_SITE_2026; }
169
169
  });
170
170
  Object.defineProperty(exports, "computeEffectiveStatusFromSession", {
171
171
  enumerable: true,
172
- get: function () { return chunkFXIDKFXQ_cjs.computeEffectiveStatusFromSession; }
172
+ get: function () { return chunkA6MOPB7D_cjs.computeEffectiveStatusFromSession; }
173
173
  });
174
174
  Object.defineProperty(exports, "createFFIDAnnouncementsClient", {
175
175
  enumerable: true,
176
- get: function () { return chunkFXIDKFXQ_cjs.createFFIDAnnouncementsClient; }
176
+ get: function () { return chunkA6MOPB7D_cjs.createFFIDAnnouncementsClient; }
177
177
  });
178
178
  Object.defineProperty(exports, "createFFIDClient", {
179
179
  enumerable: true,
180
- get: function () { return chunkFXIDKFXQ_cjs.createFFIDClient; }
180
+ get: function () { return chunkA6MOPB7D_cjs.createFFIDClient; }
181
181
  });
182
182
  Object.defineProperty(exports, "createTokenStore", {
183
183
  enumerable: true,
184
- get: function () { return chunkFXIDKFXQ_cjs.createTokenStore; }
184
+ get: function () { return chunkA6MOPB7D_cjs.createTokenStore; }
185
185
  });
186
186
  Object.defineProperty(exports, "generateCodeChallenge", {
187
187
  enumerable: true,
188
- get: function () { return chunkFXIDKFXQ_cjs.generateCodeChallenge; }
188
+ get: function () { return chunkA6MOPB7D_cjs.generateCodeChallenge; }
189
189
  });
190
190
  Object.defineProperty(exports, "generateCodeVerifier", {
191
191
  enumerable: true,
192
- get: function () { return chunkFXIDKFXQ_cjs.generateCodeVerifier; }
192
+ get: function () { return chunkA6MOPB7D_cjs.generateCodeVerifier; }
193
193
  });
194
194
  Object.defineProperty(exports, "hasAccessFromUserinfo", {
195
195
  enumerable: true,
196
- get: function () { return chunkFXIDKFXQ_cjs.hasAccessFromUserinfo; }
196
+ get: function () { return chunkA6MOPB7D_cjs.hasAccessFromUserinfo; }
197
197
  });
198
198
  Object.defineProperty(exports, "isBlockedFromUserinfo", {
199
199
  enumerable: true,
200
- get: function () { return chunkFXIDKFXQ_cjs.isBlockedFromUserinfo; }
200
+ get: function () { return chunkA6MOPB7D_cjs.isBlockedFromUserinfo; }
201
201
  });
202
202
  Object.defineProperty(exports, "isFFIDInquiryCategorySite2026", {
203
203
  enumerable: true,
204
- get: function () { return chunkFXIDKFXQ_cjs.isFFIDInquiryCategorySite2026; }
204
+ get: function () { return chunkA6MOPB7D_cjs.isFFIDInquiryCategorySite2026; }
205
205
  });
206
206
  Object.defineProperty(exports, "normalizeRedirectUri", {
207
207
  enumerable: true,
208
- get: function () { return chunkFXIDKFXQ_cjs.normalizeRedirectUri; }
208
+ get: function () { return chunkA6MOPB7D_cjs.normalizeRedirectUri; }
209
209
  });
210
210
  Object.defineProperty(exports, "retrieveCodeVerifier", {
211
211
  enumerable: true,
212
- get: function () { return chunkFXIDKFXQ_cjs.retrieveCodeVerifier; }
212
+ get: function () { return chunkA6MOPB7D_cjs.retrieveCodeVerifier; }
213
213
  });
214
214
  Object.defineProperty(exports, "storeCodeVerifier", {
215
215
  enumerable: true,
216
- get: function () { return chunkFXIDKFXQ_cjs.storeCodeVerifier; }
216
+ get: function () { return chunkA6MOPB7D_cjs.storeCodeVerifier; }
217
217
  });
218
218
  Object.defineProperty(exports, "useFFID", {
219
219
  enumerable: true,
220
- get: function () { return chunkFXIDKFXQ_cjs.useFFID; }
220
+ get: function () { return chunkA6MOPB7D_cjs.useFFID; }
221
221
  });
222
222
  Object.defineProperty(exports, "useFFIDAnnouncements", {
223
223
  enumerable: true,
224
- get: function () { return chunkFXIDKFXQ_cjs.useFFIDAnnouncements; }
224
+ get: function () { return chunkA6MOPB7D_cjs.useFFIDAnnouncements; }
225
225
  });
226
226
  Object.defineProperty(exports, "useSubscription", {
227
227
  enumerable: true,
228
- get: function () { return chunkFXIDKFXQ_cjs.useSubscription; }
228
+ get: function () { return chunkA6MOPB7D_cjs.useSubscription; }
229
229
  });
230
230
  Object.defineProperty(exports, "withSubscription", {
231
231
  enumerable: true,
232
- get: function () { return chunkFXIDKFXQ_cjs.withSubscription; }
232
+ get: function () { return chunkA6MOPB7D_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-EFp_ZgK9.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-EFp_ZgK9.cjs';
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-DSvX4q8E.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-DSvX4q8E.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';
@@ -1094,13 +1094,14 @@ interface ComputeEffectiveStatusInput {
1094
1094
  * current billing period (`cancel_at_period_end=true` in Stripe).
1095
1095
  *
1096
1096
  * Optional / defaults to `false` for backward compatibility — pre-#3460
1097
- * callers do not pass this field and MUST keep observing `'active'` for
1098
- * the same inputs. When `true` and the period has not yet ended, the
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
1099
1100
  * `'active'` branch returns `'active_canceling'` so consumers can render
1100
1101
  * a "cancellation scheduled" badge + reactivation CTA without losing
1101
- * access. Has no effect on any other DB status branch — runtime
1102
- * `expired` still wins inside `'active'`, and Stripe does not set
1103
- * `cancel_at_period_end` on terminal states.
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.
1104
1105
  */
1105
1106
  cancelAtPeriodEnd?: boolean | undefined;
1106
1107
  }
@@ -1146,12 +1147,13 @@ declare function computeEffectiveStatusFromSession(input: ComputeEffectiveStatus
1146
1147
  * backend constants in `src/app/api/v1/subscriptions/ext/check/route.ts`
1147
1148
  * (route-local) — change there forces a sync here in the same PR.
1148
1149
  *
1149
- * `active_canceling` (post-#3460) is included for forward compatibility:
1150
- * the FFID backend currently collapses cancellation-scheduled subscriptions
1151
- * back to `active` on `/ext/check`, but if a future change promotes
1152
- * `cancel_at_period_end` into the server's `EffectiveSubscriptionStatus`
1153
- * mapping the userinfo path will already treat it as access-granting
1154
- * without an additional SDK release.
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.
1155
1157
  */
1156
1158
  declare const ACCESS_GRANTING_EFFECTIVE_STATUSES: readonly EffectiveSubscriptionStatus[];
1157
1159
  /**
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-EFp_ZgK9.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-EFp_ZgK9.js';
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-DSvX4q8E.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-DSvX4q8E.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';
@@ -1094,13 +1094,14 @@ interface ComputeEffectiveStatusInput {
1094
1094
  * current billing period (`cancel_at_period_end=true` in Stripe).
1095
1095
  *
1096
1096
  * Optional / defaults to `false` for backward compatibility — pre-#3460
1097
- * callers do not pass this field and MUST keep observing `'active'` for
1098
- * the same inputs. When `true` and the period has not yet ended, the
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
1099
1100
  * `'active'` branch returns `'active_canceling'` so consumers can render
1100
1101
  * a "cancellation scheduled" badge + reactivation CTA without losing
1101
- * access. Has no effect on any other DB status branch — runtime
1102
- * `expired` still wins inside `'active'`, and Stripe does not set
1103
- * `cancel_at_period_end` on terminal states.
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.
1104
1105
  */
1105
1106
  cancelAtPeriodEnd?: boolean | undefined;
1106
1107
  }
@@ -1146,12 +1147,13 @@ declare function computeEffectiveStatusFromSession(input: ComputeEffectiveStatus
1146
1147
  * backend constants in `src/app/api/v1/subscriptions/ext/check/route.ts`
1147
1148
  * (route-local) — change there forces a sync here in the same PR.
1148
1149
  *
1149
- * `active_canceling` (post-#3460) is included for forward compatibility:
1150
- * the FFID backend currently collapses cancellation-scheduled subscriptions
1151
- * back to `active` on `/ext/check`, but if a future change promotes
1152
- * `cancel_at_period_end` into the server's `EffectiveSubscriptionStatus`
1153
- * mapping the userinfo path will already treat it as access-granting
1154
- * without an additional SDK release.
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.
1155
1157
  */
1156
1158
  declare const ACCESS_GRANTING_EFFECTIVE_STATUSES: readonly EffectiveSubscriptionStatus[];
1157
1159
  /**
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useFFIDContext, useSubscription } from './chunk-YAJN36SD.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-YAJN36SD.js';
1
+ import { useFFIDContext, useSubscription } from './chunk-KENJXMSG.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-KENJXMSG.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';
@@ -106,7 +106,16 @@ var SESSION_ELIGIBLE_SUBSCRIPTION_STATUSES = [
106
106
  function isSessionEligibleSubscriptionStatus(value) {
107
107
  return typeof value === "string" && SESSION_ELIGIBLE_SUBSCRIPTION_STATUSES.includes(value);
108
108
  }
109
+ function hasOwnKey(value, key) {
110
+ return Object.prototype.hasOwnProperty.call(value, key);
111
+ }
109
112
  function normalizeUserinfo(raw) {
113
+ const hasOrganizationId = hasOwnKey(raw, "organization_id");
114
+ const hasOrganizationName = hasOwnKey(raw, "organization_name");
115
+ const organizationFields = hasOrganizationId ? {
116
+ organizationId: raw.organization_id ?? null,
117
+ organizationName: hasOrganizationName ? raw.organization_name ?? null : null
118
+ } : hasOrganizationName ? { organizationName: raw.organization_name ?? null } : {};
110
119
  return {
111
120
  sub: raw.sub,
112
121
  email: raw.email,
@@ -116,7 +125,7 @@ function normalizeUserinfo(raw) {
116
125
  department: raw.department ?? null,
117
126
  position: raw.position ?? null,
118
127
  phoneNumber: raw.phone_number ?? null,
119
- organizationId: raw.organization_id ?? null,
128
+ ...organizationFields,
120
129
  subscription: raw.subscription ? {
121
130
  subscriptionId: raw.subscription.subscription_id ?? null,
122
131
  status: raw.subscription.status ?? null,
@@ -125,7 +134,16 @@ function normalizeUserinfo(raw) {
125
134
  seatModel: raw.subscription.seat_model ?? null,
126
135
  memberRole: raw.subscription.member_role ?? null,
127
136
  organizationId: raw.subscription.organization_id ?? null,
128
- hasSeatAssignment: raw.subscription.has_seat_assignment ?? false
137
+ organizationName: hasOwnKey(raw.subscription, "organization_name") ? raw.subscription.organization_name ?? null : null,
138
+ hasSeatAssignment: raw.subscription.has_seat_assignment ?? false,
139
+ // #3464: legacy FFID (< this issue) omits the field on the wire.
140
+ // The "unknown" axis is unused — no consumer differentiates "server
141
+ // didn't tell us" from "definitely not scheduled" because the
142
+ // companion `effectiveStatus` already returns `'active'` (not
143
+ // `'active_canceling'`) for legacy backends. Defaulting to `false`
144
+ // here keeps the downstream contract a plain boolean.
145
+ cancelAtPeriodEnd: raw.subscription.cancel_at_period_end ?? false,
146
+ currentPeriodEnd: raw.subscription.current_period_end ?? null
129
147
  } : void 0
130
148
  };
131
149
  }
@@ -142,11 +160,18 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
142
160
  planCode: subscription.planCode,
143
161
  planName: subscription.planCode,
144
162
  status: subscription.status,
145
- currentPeriodEnd: null,
163
+ // #3464: userinfo now carries `current_period_end` and
164
+ // `cancel_at_period_end`. Pre-#3464 FFID backends still omit them on
165
+ // the wire (`currentPeriodEnd === null` / `cancelAtPeriodEnd === false`
166
+ // after `normalizeUserinfo` defaults), so the session helper sees
167
+ // plain `'active'` — identical to pre-#3464 behaviour.
168
+ currentPeriodEnd: subscription.currentPeriodEnd,
146
169
  trialEnd: null,
170
+ cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
147
171
  seatModel: subscription.seatModel ?? void 0,
148
172
  memberRole: subscription.memberRole ?? void 0,
149
- organizationId: subscription.organizationId
173
+ organizationId: subscription.organizationId,
174
+ organizationName: subscription.organizationName ?? void 0
150
175
  }
151
176
  ];
152
177
  }
@@ -355,7 +380,8 @@ function createVerifyAccessToken(deps) {
355
380
  department: introspectResponse.department ?? null,
356
381
  position: introspectResponse.position ?? null,
357
382
  phone_number: introspectResponse.phone_number ?? null,
358
- organization_id: introspectResponse.organization_id ?? null
383
+ organization_id: introspectResponse.organization_id ?? null,
384
+ organization_name: introspectResponse.organization_name ?? null
359
385
  };
360
386
  const raw = introspectResponse.subscription ? {
361
387
  ...base,
@@ -367,6 +393,7 @@ function createVerifyAccessToken(deps) {
367
393
  seat_model: introspectResponse.subscription.seat_model,
368
394
  member_role: introspectResponse.subscription.member_role,
369
395
  organization_id: introspectResponse.subscription.organization_id,
396
+ organization_name: introspectResponse.subscription.organization_name ?? null,
370
397
  has_seat_assignment: introspectResponse.subscription.has_seat_assignment ?? false
371
398
  }
372
399
  } : base;
@@ -837,7 +864,7 @@ function createProfileMethods(deps) {
837
864
  }
838
865
 
839
866
  // src/client/version-check.ts
840
- var SDK_VERSION = "5.7.0";
867
+ var SDK_VERSION = "5.9.0";
841
868
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
842
869
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
843
870
  function sdkHeaders() {
@@ -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-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';
1
+ import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-DRjzfAaS.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-DRjzfAaS.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-s3y11uT6.cjs';
5
+ import '../types-BYdtyO_2.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-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';
1
+ import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-gboJROw0.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-gboJROw0.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-s3y11uT6.js';
5
+ import '../types-BYdtyO_2.js';
6
6
 
7
7
  /** Token verification - verifyAccessToken() implementation */
8
8
 
@@ -105,7 +105,16 @@ var SESSION_ELIGIBLE_SUBSCRIPTION_STATUSES = [
105
105
  function isSessionEligibleSubscriptionStatus(value) {
106
106
  return typeof value === "string" && SESSION_ELIGIBLE_SUBSCRIPTION_STATUSES.includes(value);
107
107
  }
108
+ function hasOwnKey(value, key) {
109
+ return Object.prototype.hasOwnProperty.call(value, key);
110
+ }
108
111
  function normalizeUserinfo(raw) {
112
+ const hasOrganizationId = hasOwnKey(raw, "organization_id");
113
+ const hasOrganizationName = hasOwnKey(raw, "organization_name");
114
+ const organizationFields = hasOrganizationId ? {
115
+ organizationId: raw.organization_id ?? null,
116
+ organizationName: hasOrganizationName ? raw.organization_name ?? null : null
117
+ } : hasOrganizationName ? { organizationName: raw.organization_name ?? null } : {};
109
118
  return {
110
119
  sub: raw.sub,
111
120
  email: raw.email,
@@ -115,7 +124,7 @@ function normalizeUserinfo(raw) {
115
124
  department: raw.department ?? null,
116
125
  position: raw.position ?? null,
117
126
  phoneNumber: raw.phone_number ?? null,
118
- organizationId: raw.organization_id ?? null,
127
+ ...organizationFields,
119
128
  subscription: raw.subscription ? {
120
129
  subscriptionId: raw.subscription.subscription_id ?? null,
121
130
  status: raw.subscription.status ?? null,
@@ -124,7 +133,16 @@ function normalizeUserinfo(raw) {
124
133
  seatModel: raw.subscription.seat_model ?? null,
125
134
  memberRole: raw.subscription.member_role ?? null,
126
135
  organizationId: raw.subscription.organization_id ?? null,
127
- hasSeatAssignment: raw.subscription.has_seat_assignment ?? false
136
+ organizationName: hasOwnKey(raw.subscription, "organization_name") ? raw.subscription.organization_name ?? null : null,
137
+ hasSeatAssignment: raw.subscription.has_seat_assignment ?? false,
138
+ // #3464: legacy FFID (< this issue) omits the field on the wire.
139
+ // The "unknown" axis is unused — no consumer differentiates "server
140
+ // didn't tell us" from "definitely not scheduled" because the
141
+ // companion `effectiveStatus` already returns `'active'` (not
142
+ // `'active_canceling'`) for legacy backends. Defaulting to `false`
143
+ // here keeps the downstream contract a plain boolean.
144
+ cancelAtPeriodEnd: raw.subscription.cancel_at_period_end ?? false,
145
+ currentPeriodEnd: raw.subscription.current_period_end ?? null
128
146
  } : void 0
129
147
  };
130
148
  }
@@ -141,11 +159,18 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
141
159
  planCode: subscription.planCode,
142
160
  planName: subscription.planCode,
143
161
  status: subscription.status,
144
- currentPeriodEnd: null,
162
+ // #3464: userinfo now carries `current_period_end` and
163
+ // `cancel_at_period_end`. Pre-#3464 FFID backends still omit them on
164
+ // the wire (`currentPeriodEnd === null` / `cancelAtPeriodEnd === false`
165
+ // after `normalizeUserinfo` defaults), so the session helper sees
166
+ // plain `'active'` — identical to pre-#3464 behaviour.
167
+ currentPeriodEnd: subscription.currentPeriodEnd,
145
168
  trialEnd: null,
169
+ cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
146
170
  seatModel: subscription.seatModel ?? void 0,
147
171
  memberRole: subscription.memberRole ?? void 0,
148
- organizationId: subscription.organizationId
172
+ organizationId: subscription.organizationId,
173
+ organizationName: subscription.organizationName ?? void 0
149
174
  }
150
175
  ];
151
176
  }
@@ -354,7 +379,8 @@ function createVerifyAccessToken(deps) {
354
379
  department: introspectResponse.department ?? null,
355
380
  position: introspectResponse.position ?? null,
356
381
  phone_number: introspectResponse.phone_number ?? null,
357
- organization_id: introspectResponse.organization_id ?? null
382
+ organization_id: introspectResponse.organization_id ?? null,
383
+ organization_name: introspectResponse.organization_name ?? null
358
384
  };
359
385
  const raw = introspectResponse.subscription ? {
360
386
  ...base,
@@ -366,6 +392,7 @@ function createVerifyAccessToken(deps) {
366
392
  seat_model: introspectResponse.subscription.seat_model,
367
393
  member_role: introspectResponse.subscription.member_role,
368
394
  organization_id: introspectResponse.subscription.organization_id,
395
+ organization_name: introspectResponse.subscription.organization_name ?? null,
369
396
  has_seat_assignment: introspectResponse.subscription.has_seat_assignment ?? false
370
397
  }
371
398
  } : base;
@@ -836,7 +863,7 @@ function createProfileMethods(deps) {
836
863
  }
837
864
 
838
865
  // src/client/version-check.ts
839
- var SDK_VERSION = "5.7.0";
866
+ var SDK_VERSION = "5.9.0";
840
867
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
841
868
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
842
869
  function sdkHeaders() {
@@ -1,5 +1,5 @@
1
- import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-CknwTgly.cjs';
2
- import '../../types-s3y11uT6.cjs';
1
+ import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-DRjzfAaS.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-C0k2PTbO.js';
2
- import '../../types-s3y11uT6.js';
1
+ import { k as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-gboJROw0.js';
2
+ import '../../types-BYdtyO_2.js';
3
3
 
4
4
  /**
5
5
  * FFID SDK - Test mode client (E2E / integration test bypass)
@@ -33,22 +33,18 @@
33
33
  * This is the FFID-internal runtime-expired case (see
34
34
  * `getEffectiveSubscriptionStatus` on the server). Deny access.
35
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.
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.
52
48
  *
53
49
  * @see /api/v1/subscriptions/ext/check
54
50
  * @see docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md