@feelflow/ffid-sdk 10.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1062 -1010
- package/dist/agency/index.d.cts +23 -1
- package/dist/agency/index.d.ts +23 -1
- package/dist/{chunk-OXW6QSTO.js → chunk-QORWLPWG.js} +174 -46
- package/dist/{chunk-2LU2F3F2.cjs → chunk-VR3QR64A.cjs} +176 -45
- 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-5uxXRgIO.d.ts → ffid-client-By_vcKYu.d.ts} +32 -10
- package/dist/{ffid-client-CumygXXz.d.cts → ffid-client-C3A8L9uW.d.cts} +32 -10
- package/dist/{index-KjewcNn1.d.cts → index-BknVfXhZ.d.cts} +21 -9
- package/dist/{index-KjewcNn1.d.ts → index-BknVfXhZ.d.ts} +21 -9
- package/dist/index.cjs +100 -88
- package/dist/index.d.cts +117 -7
- package/dist/index.d.ts +117 -7
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +101 -13
- package/dist/server/index.d.cts +74 -3
- package/dist/server/index.d.ts +74 -3
- package/dist/server/index.js +99 -14
- package/dist/server/test/index.d.cts +1 -1
- package/dist/server/test/index.d.ts +1 -1
- package/package.json +131 -131
|
@@ -310,6 +310,9 @@ var OAUTH_INTROSPECT_ENDPOINT = "/api/v1/oauth/introspect";
|
|
|
310
310
|
var CACHE_KEY_PREFIX = "ffid:introspect:";
|
|
311
311
|
var HEX_BASE = 16;
|
|
312
312
|
var HEX_BYTE_WIDTH = 2;
|
|
313
|
+
var HTTP_TOO_MANY_REQUESTS = 429;
|
|
314
|
+
var HTTP_SERVER_ERROR_MIN = 500;
|
|
315
|
+
var HTTP_SERVER_ERROR_LIMIT = 600;
|
|
313
316
|
function createVerifyAccessToken(deps) {
|
|
314
317
|
const { authMode, baseUrl, serviceCode, serviceApiKey, verifyStrategy, logger, createError, errorCodes, cache, timeout } = deps;
|
|
315
318
|
let jwtVerify2 = null;
|
|
@@ -364,6 +367,16 @@ function createVerifyAccessToken(deps) {
|
|
|
364
367
|
}
|
|
365
368
|
return verifyViaIntrospect(accessToken);
|
|
366
369
|
}
|
|
370
|
+
function introspectionUnavailable(status) {
|
|
371
|
+
logger.error("Token introspection unavailable", { status });
|
|
372
|
+
return {
|
|
373
|
+
error: {
|
|
374
|
+
code: errorCodes.NETWORK_ERROR,
|
|
375
|
+
message: `\u30C8\u30FC\u30AF\u30F3\u691C\u8A3C\u30B5\u30FC\u30D3\u30B9\u304C\u4E00\u6642\u7684\u306B\u5229\u7528\u3067\u304D\u307E\u305B\u3093 (status: ${status})`,
|
|
376
|
+
details: { status }
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
367
380
|
async function verifyViaIntrospect(accessToken, cacheKeySuffix) {
|
|
368
381
|
if (!serviceApiKey) {
|
|
369
382
|
return {
|
|
@@ -421,10 +434,12 @@ function createVerifyAccessToken(deps) {
|
|
|
421
434
|
}
|
|
422
435
|
};
|
|
423
436
|
}
|
|
437
|
+
const upstreamUnavailable = response.status === HTTP_TOO_MANY_REQUESTS || response.status >= HTTP_SERVER_ERROR_MIN && response.status < HTTP_SERVER_ERROR_LIMIT;
|
|
424
438
|
let introspectResponse;
|
|
425
439
|
try {
|
|
426
440
|
introspectResponse = await response.json();
|
|
427
441
|
} catch (parseError) {
|
|
442
|
+
if (upstreamUnavailable) return introspectionUnavailable(response.status);
|
|
428
443
|
logger.error("Parse error during token verification:", parseError);
|
|
429
444
|
return {
|
|
430
445
|
error: {
|
|
@@ -433,6 +448,7 @@ function createVerifyAccessToken(deps) {
|
|
|
433
448
|
}
|
|
434
449
|
};
|
|
435
450
|
}
|
|
451
|
+
if (upstreamUnavailable) return introspectionUnavailable(response.status);
|
|
436
452
|
if (!response.ok) {
|
|
437
453
|
const errorBody = introspectResponse;
|
|
438
454
|
return {
|
|
@@ -1376,7 +1392,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
|
|
|
1376
1392
|
};
|
|
1377
1393
|
|
|
1378
1394
|
// src/client/version-check.ts
|
|
1379
|
-
var SDK_VERSION = "
|
|
1395
|
+
var SDK_VERSION = "11.0.0";
|
|
1380
1396
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1381
1397
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1382
1398
|
function sdkHeaders() {
|
|
@@ -1944,7 +1960,7 @@ function createInviteMethods(deps) {
|
|
|
1944
1960
|
}).toString();
|
|
1945
1961
|
return fetchWithAuth(`${EXT_INVITE_ENDPOINT}?${query}`, {
|
|
1946
1962
|
method: "POST",
|
|
1947
|
-
body: JSON.stringify({ email: params.email, role: params.role })
|
|
1963
|
+
body: JSON.stringify({ email: params.email, role: params.role, inviterUserId: params.inviterUserId })
|
|
1948
1964
|
});
|
|
1949
1965
|
}
|
|
1950
1966
|
return { inviteMember };
|
|
@@ -2247,6 +2263,25 @@ function createOAuthTokenMethods(deps) {
|
|
|
2247
2263
|
return { exchangeCodeForTokens, refreshAccessToken, signOutToken };
|
|
2248
2264
|
}
|
|
2249
2265
|
|
|
2266
|
+
// src/client/request-timeout.ts
|
|
2267
|
+
function withRequestTimeout(options, timeout) {
|
|
2268
|
+
if (timeout === void 0 || options.signal?.aborted) return options;
|
|
2269
|
+
const deadline = AbortSignal.timeout(timeout);
|
|
2270
|
+
if (!options.signal) return { ...options, signal: deadline };
|
|
2271
|
+
const callerSignal = options.signal;
|
|
2272
|
+
const controller = new AbortController();
|
|
2273
|
+
const abortFromCaller = () => abort(callerSignal.reason);
|
|
2274
|
+
const abortFromDeadline = () => abort(deadline.reason);
|
|
2275
|
+
function abort(reason) {
|
|
2276
|
+
callerSignal.removeEventListener("abort", abortFromCaller);
|
|
2277
|
+
deadline.removeEventListener("abort", abortFromDeadline);
|
|
2278
|
+
controller.abort(reason);
|
|
2279
|
+
}
|
|
2280
|
+
callerSignal.addEventListener("abort", abortFromCaller, { once: true });
|
|
2281
|
+
deadline.addEventListener("abort", abortFromDeadline, { once: true });
|
|
2282
|
+
return { ...options, signal: controller.signal };
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2250
2285
|
// src/client/session.ts
|
|
2251
2286
|
var SESSION_ENDPOINT = "/api/v1/auth/session";
|
|
2252
2287
|
var LOGOUT_ENDPOINT = "/api/v1/auth/signout";
|
|
@@ -3981,6 +4016,7 @@ function toServiceAccessDecision(response, allowGrace) {
|
|
|
3981
4016
|
const isBlocked = response.isBlocked ?? (effectiveStatus === null || effectiveStatus !== null && BLOCKING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
3982
4017
|
return {
|
|
3983
4018
|
hasAccess,
|
|
4019
|
+
...response.seatAssigned !== void 0 ? { seatAssigned: response.seatAssigned } : {},
|
|
3984
4020
|
effectiveStatus,
|
|
3985
4021
|
isGrace,
|
|
3986
4022
|
isBlocked: isBlocked || !hasAccess,
|
|
@@ -4048,6 +4084,7 @@ var FFID_SUBSCRIPTION_ERROR_CODES = {
|
|
|
4048
4084
|
var FFID_CREDITS_ERROR_CODES = {
|
|
4049
4085
|
CREDITS_INSUFFICIENT: "CREDITS_INSUFFICIENT",
|
|
4050
4086
|
CREDITS_IDEMPOTENCY_CONFLICT: "CREDITS_IDEMPOTENCY_CONFLICT",
|
|
4087
|
+
CREDITS_TURN_CANCELLED: "CREDITS_TURN_CANCELLED",
|
|
4051
4088
|
CREDITS_NOT_APPLICABLE: "CREDITS_NOT_APPLICABLE",
|
|
4052
4089
|
CREDITS_BALANCE_CAP_EXCEEDED: "CREDITS_BALANCE_CAP_EXCEEDED",
|
|
4053
4090
|
SEAT_BILLING_NOT_APPLICABLE: "SEAT_BILLING_NOT_APPLICABLE",
|
|
@@ -4212,9 +4249,10 @@ function createFFIDClient(config) {
|
|
|
4212
4249
|
async function fetchWithAuth(endpoint, options = {}, authOverride) {
|
|
4213
4250
|
const url = `${baseUrl}${endpoint}`;
|
|
4214
4251
|
logger.debug("Fetching:", url);
|
|
4215
|
-
|
|
4252
|
+
let fetchOptions = buildFetchOptions(options, authOverride);
|
|
4216
4253
|
let response;
|
|
4217
4254
|
try {
|
|
4255
|
+
fetchOptions = withRequestTimeout(fetchOptions, timeout);
|
|
4218
4256
|
response = await fetch(url, fetchOptions);
|
|
4219
4257
|
} catch (error) {
|
|
4220
4258
|
logger.error("Network error:", error);
|
|
@@ -4229,9 +4267,9 @@ function createFFIDClient(config) {
|
|
|
4229
4267
|
const refreshResult = await refreshAccessToken();
|
|
4230
4268
|
if (!refreshResult.error) {
|
|
4231
4269
|
logger.debug("Token refreshed, retrying request");
|
|
4232
|
-
const retryOptions = buildFetchOptions(options);
|
|
4233
4270
|
try {
|
|
4234
|
-
|
|
4271
|
+
fetchOptions = withRequestTimeout(buildFetchOptions(options), timeout);
|
|
4272
|
+
response = await fetch(url, fetchOptions);
|
|
4235
4273
|
} catch (retryError) {
|
|
4236
4274
|
logger.error("Network error on retry:", retryError);
|
|
4237
4275
|
return {
|
|
@@ -4250,6 +4288,15 @@ function createFFIDClient(config) {
|
|
|
4250
4288
|
try {
|
|
4251
4289
|
raw = await response.json();
|
|
4252
4290
|
} catch (parseError) {
|
|
4291
|
+
if (fetchOptions.signal?.aborted) {
|
|
4292
|
+
logger.error("Response body aborted:", parseError);
|
|
4293
|
+
return {
|
|
4294
|
+
error: {
|
|
4295
|
+
code: FFID_ERROR_CODES.NETWORK_ERROR,
|
|
4296
|
+
message: "\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u53D7\u4FE1\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3057\u305F"
|
|
4297
|
+
}
|
|
4298
|
+
};
|
|
4299
|
+
}
|
|
4253
4300
|
logger.error("Parse error:", parseError, "Status:", response.status);
|
|
4254
4301
|
return {
|
|
4255
4302
|
error: {
|
|
@@ -4611,6 +4658,50 @@ function createFFIDClient(config) {
|
|
|
4611
4658
|
};
|
|
4612
4659
|
}
|
|
4613
4660
|
|
|
4661
|
+
// src/client/authorization-error.ts
|
|
4662
|
+
var FFID_OAUTH_DENIAL_REASONS = [
|
|
4663
|
+
/** The user is not a member of the organization */
|
|
4664
|
+
"no_membership",
|
|
4665
|
+
/** The organization has no usable subscription for the service */
|
|
4666
|
+
"no_active_subscription",
|
|
4667
|
+
/** The organization has a subscription, but the user has no seat in it */
|
|
4668
|
+
"no_seat_assignment",
|
|
4669
|
+
/** The subscription has expired (canceled / past due beyond grace) */
|
|
4670
|
+
"subscription_expired",
|
|
4671
|
+
/** The flat plan's member limit is full, so no seat could be given */
|
|
4672
|
+
"member_limit_reached"
|
|
4673
|
+
];
|
|
4674
|
+
function isFFIDOAuthDenialReason(value) {
|
|
4675
|
+
return typeof value === "string" && FFID_OAUTH_DENIAL_REASONS.includes(value);
|
|
4676
|
+
}
|
|
4677
|
+
var DEFAULT_AUTHORIZATION_ERROR_MESSAGE = "\u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F";
|
|
4678
|
+
function buildAuthorizationError(params) {
|
|
4679
|
+
const oauthError = params.get("error");
|
|
4680
|
+
if (!oauthError) return null;
|
|
4681
|
+
const rawReason = params.get("denial_reason");
|
|
4682
|
+
const errorDescription = params.get("error_description");
|
|
4683
|
+
const details = {
|
|
4684
|
+
source: "authorization",
|
|
4685
|
+
denialReason: isFFIDOAuthDenialReason(rawReason) ? rawReason : null,
|
|
4686
|
+
errorDescription
|
|
4687
|
+
};
|
|
4688
|
+
return {
|
|
4689
|
+
code: oauthError,
|
|
4690
|
+
message: errorDescription ?? DEFAULT_AUTHORIZATION_ERROR_MESSAGE,
|
|
4691
|
+
details: { ...details }
|
|
4692
|
+
};
|
|
4693
|
+
}
|
|
4694
|
+
function getFFIDAuthorizationError(error) {
|
|
4695
|
+
const details = error?.details;
|
|
4696
|
+
if (!error || !details || details.source !== "authorization") return null;
|
|
4697
|
+
const description = details.errorDescription;
|
|
4698
|
+
return {
|
|
4699
|
+
oauthError: error.code,
|
|
4700
|
+
denialReason: isFFIDOAuthDenialReason(details.denialReason) ? details.denialReason : null,
|
|
4701
|
+
errorDescription: typeof description === "string" ? description : null
|
|
4702
|
+
};
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4614
4705
|
// src/client/callback.ts
|
|
4615
4706
|
var CALLBACK_ERROR_CODES = {
|
|
4616
4707
|
/** Stored state missing or did not match the callback `state` (CSRF guard) */
|
|
@@ -4635,16 +4726,43 @@ function extractSearchParams(source) {
|
|
|
4635
4726
|
return new URLSearchParams(query);
|
|
4636
4727
|
}
|
|
4637
4728
|
}
|
|
4638
|
-
|
|
4729
|
+
var CODE_CALLBACK_PARAMS = ["code", "state"];
|
|
4730
|
+
var ERROR_CALLBACK_CONSUMED_PARAMS = ["state"];
|
|
4731
|
+
function cleanCallbackUrlParams(logger, names) {
|
|
4639
4732
|
try {
|
|
4640
4733
|
const cleanUrl = new URL(window.location.href);
|
|
4641
|
-
cleanUrl.searchParams.delete(
|
|
4642
|
-
cleanUrl.searchParams.delete("state");
|
|
4734
|
+
for (const name of names) cleanUrl.searchParams.delete(name);
|
|
4643
4735
|
window.history.replaceState({}, "", cleanUrl.toString());
|
|
4644
4736
|
} catch (error) {
|
|
4645
4737
|
logger.warn("handleRedirectCallback: URL \u306E\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
|
|
4646
4738
|
}
|
|
4647
4739
|
}
|
|
4740
|
+
function validateCallbackState(client, urlState) {
|
|
4741
|
+
const { logger } = client;
|
|
4742
|
+
const storedState = retrieveState(logger);
|
|
4743
|
+
if (storedState === null && urlState === null) return null;
|
|
4744
|
+
if (storedState !== null && storedState === urlState) return null;
|
|
4745
|
+
if (storedState === null && !isStateStorageAvailable()) {
|
|
4746
|
+
logger.error(
|
|
4747
|
+
"handleRedirectCallback: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 CSRF \u691C\u8A3C\u304C\u3067\u304D\u307E\u305B\u3093\uFF08iOS private mode \u7B49\uFF09"
|
|
4748
|
+
);
|
|
4749
|
+
return {
|
|
4750
|
+
error: client.createError(
|
|
4751
|
+
CALLBACK_ERROR_CODES.STATE_UNAVAILABLE,
|
|
4752
|
+
"OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30E2\u30FC\u30C9\u3084\u30B9\u30C8\u30EC\u30FC\u30B8\u8A2D\u5B9A\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044"
|
|
4753
|
+
)
|
|
4754
|
+
};
|
|
4755
|
+
}
|
|
4756
|
+
logger.error(
|
|
4757
|
+
"handleRedirectCallback: OAuth state mismatch or omitted (possible CSRF) \u2014 \u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002\u6D88\u8CBB\u6E08\u307F callback \u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u518D\u51E6\u7406\uFF08`cleanUrl: false` \u5229\u7528\u6642\u306E cleanup \u6F0F\u308C\u3084 reload \u7B49\uFF09\u3067\u3082\u767A\u751F\u3057\u307E\u3059"
|
|
4758
|
+
);
|
|
4759
|
+
return {
|
|
4760
|
+
error: client.createError(
|
|
4761
|
+
CALLBACK_ERROR_CODES.STATE_MISMATCH,
|
|
4762
|
+
"OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
|
|
4763
|
+
)
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4648
4766
|
async function handleRedirectCallback(client, options) {
|
|
4649
4767
|
const { logger } = client;
|
|
4650
4768
|
const hasWindow = typeof window !== "undefined";
|
|
@@ -4661,6 +4779,24 @@ async function handleRedirectCallback(client, options) {
|
|
|
4661
4779
|
const params = extractSearchParams(source);
|
|
4662
4780
|
const code = params.get("code");
|
|
4663
4781
|
const urlState = params.get("state");
|
|
4782
|
+
const authorizationError = buildAuthorizationError(params);
|
|
4783
|
+
if (authorizationError && urlState !== null) {
|
|
4784
|
+
const stateError2 = validateCallbackState(client, urlState);
|
|
4785
|
+
if (stateError2) return stateError2;
|
|
4786
|
+
retrieveCodeVerifier(logger);
|
|
4787
|
+
logger.warn("handleRedirectCallback: \u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F:", {
|
|
4788
|
+
error: authorizationError.code,
|
|
4789
|
+
denialReason: params.get("denial_reason")
|
|
4790
|
+
});
|
|
4791
|
+
if (hasWindow) {
|
|
4792
|
+
if (options?.cleanUrl !== false) {
|
|
4793
|
+
cleanCallbackUrlParams(logger, ERROR_CALLBACK_CONSUMED_PARAMS);
|
|
4794
|
+
} else {
|
|
4795
|
+
logger.debug("handleRedirectCallback: cleanUrl=false \u306E\u305F\u3081 URL cleanup \u3092 consumer \u306B\u59D4\u8B72\u3057\u307E\u3057\u305F");
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
return { error: authorizationError };
|
|
4799
|
+
}
|
|
4664
4800
|
if (!code) {
|
|
4665
4801
|
logger.warn("handleRedirectCallback: \u8A8D\u53EF\u30B3\u30FC\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
|
|
4666
4802
|
return {
|
|
@@ -4670,37 +4806,13 @@ async function handleRedirectCallback(client, options) {
|
|
|
4670
4806
|
)
|
|
4671
4807
|
};
|
|
4672
4808
|
}
|
|
4673
|
-
const
|
|
4674
|
-
if (
|
|
4675
|
-
const stateMatches = storedState !== null && storedState === urlState;
|
|
4676
|
-
if (!stateMatches) {
|
|
4677
|
-
if (storedState === null && !isStateStorageAvailable()) {
|
|
4678
|
-
logger.error(
|
|
4679
|
-
"handleRedirectCallback: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 CSRF \u691C\u8A3C\u304C\u3067\u304D\u307E\u305B\u3093\uFF08iOS private mode \u7B49\uFF09"
|
|
4680
|
-
);
|
|
4681
|
-
return {
|
|
4682
|
-
error: client.createError(
|
|
4683
|
-
CALLBACK_ERROR_CODES.STATE_UNAVAILABLE,
|
|
4684
|
-
"OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u308B storage \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30E2\u30FC\u30C9\u3084\u30B9\u30C8\u30EC\u30FC\u30B8\u8A2D\u5B9A\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044"
|
|
4685
|
-
)
|
|
4686
|
-
};
|
|
4687
|
-
}
|
|
4688
|
-
logger.error(
|
|
4689
|
-
"handleRedirectCallback: OAuth state mismatch or omitted (possible CSRF) \u2014 \u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002\u6D88\u8CBB\u6E08\u307F callback \u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u518D\u51E6\u7406\uFF08`cleanUrl: false` \u5229\u7528\u6642\u306E cleanup \u6F0F\u308C\u3084 reload \u7B49\uFF09\u3067\u3082\u767A\u751F\u3057\u307E\u3059"
|
|
4690
|
-
);
|
|
4691
|
-
return {
|
|
4692
|
-
error: client.createError(
|
|
4693
|
-
CALLBACK_ERROR_CODES.STATE_MISMATCH,
|
|
4694
|
-
"OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
|
|
4695
|
-
)
|
|
4696
|
-
};
|
|
4697
|
-
}
|
|
4698
|
-
}
|
|
4809
|
+
const stateError = validateCallbackState(client, urlState);
|
|
4810
|
+
if (stateError) return stateError;
|
|
4699
4811
|
const verifier = retrieveCodeVerifier(logger);
|
|
4700
4812
|
const result = await client.exchangeCodeForTokens(code, verifier ?? void 0);
|
|
4701
4813
|
if (!result.error && hasWindow) {
|
|
4702
4814
|
if (options?.cleanUrl !== false) {
|
|
4703
|
-
cleanCallbackUrlParams(logger);
|
|
4815
|
+
cleanCallbackUrlParams(logger, CODE_CALLBACK_PARAMS);
|
|
4704
4816
|
} else {
|
|
4705
4817
|
logger.debug("handleRedirectCallback: cleanUrl=false \u306E\u305F\u3081 URL cleanup \u3092 consumer \u306B\u59D4\u8B72\u3057\u307E\u3057\u305F");
|
|
4706
4818
|
}
|
|
@@ -4709,6 +4821,13 @@ async function handleRedirectCallback(client, options) {
|
|
|
4709
4821
|
}
|
|
4710
4822
|
var DEFAULT_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
|
|
4711
4823
|
var TOKEN_REFRESH_RATIO = 0.8;
|
|
4824
|
+
function resolveCallbackKey(params) {
|
|
4825
|
+
const code = params.get("code");
|
|
4826
|
+
if (code) return code;
|
|
4827
|
+
const error = params.get("error");
|
|
4828
|
+
const state = params.get("state");
|
|
4829
|
+
return error && state ? `error:${error}:${state}` : null;
|
|
4830
|
+
}
|
|
4712
4831
|
var FFIDContext = react.createContext(null);
|
|
4713
4832
|
var FFIDClientContext = react.createContext(null);
|
|
4714
4833
|
function FFIDProvider({
|
|
@@ -4888,19 +5007,26 @@ function FFIDProvider({
|
|
|
4888
5007
|
},
|
|
4889
5008
|
[organizations, client]
|
|
4890
5009
|
);
|
|
4891
|
-
const
|
|
5010
|
+
const handledCallbackRef = react.useRef(null);
|
|
5011
|
+
const callbackPendingRef = react.useRef(false);
|
|
5012
|
+
const authorizationDeniedRef = react.useRef(false);
|
|
4892
5013
|
react.useEffect(() => {
|
|
4893
5014
|
if (client.authMode !== "token") return;
|
|
4894
5015
|
if (typeof window === "undefined") return;
|
|
4895
|
-
const
|
|
4896
|
-
|
|
4897
|
-
if (
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
client.logger.debug("
|
|
5016
|
+
const callbackKey = resolveCallbackKey(new URLSearchParams(window.location.search));
|
|
5017
|
+
if (!callbackKey) return;
|
|
5018
|
+
if (handledCallbackRef.current === callbackKey) return;
|
|
5019
|
+
handledCallbackRef.current = callbackKey;
|
|
5020
|
+
callbackPendingRef.current = true;
|
|
5021
|
+
client.logger.debug("OAuth callback detected, handling it");
|
|
4901
5022
|
handleRedirectCallback(client, { cleanUrl: cleanCallbackUrl }).then((result) => {
|
|
4902
5023
|
if (result.error) {
|
|
4903
|
-
|
|
5024
|
+
if (getFFIDAuthorizationError(result.error)) {
|
|
5025
|
+
client.logger.warn("FFID \u304C\u30ED\u30B0\u30A4\u30F3\u3092\u62D2\u5426\u3057\u307E\u3057\u305F:", result.error);
|
|
5026
|
+
authorizationDeniedRef.current = true;
|
|
5027
|
+
} else {
|
|
5028
|
+
client.logger.error("Token exchange failed:", result.error);
|
|
5029
|
+
}
|
|
4904
5030
|
if (result.error.code === FFID_ERROR_CODES.STATE_MISMATCH_ERROR && client.tokenStore.getTokens()) {
|
|
4905
5031
|
client.logger.debug(
|
|
4906
5032
|
"Stale callback rejected but stored tokens present, restoring session via refresh"
|
|
@@ -4918,13 +5044,15 @@ function FFIDProvider({
|
|
|
4918
5044
|
}).catch((err) => {
|
|
4919
5045
|
client.logger.error("Token exchange error:", err);
|
|
4920
5046
|
setIsLoading(false);
|
|
5047
|
+
}).finally(() => {
|
|
5048
|
+
callbackPendingRef.current = false;
|
|
4921
5049
|
});
|
|
4922
5050
|
}, [client]);
|
|
4923
5051
|
react.useEffect(() => {
|
|
4924
5052
|
if (client.authMode === "token") {
|
|
5053
|
+
if (callbackPendingRef.current || authorizationDeniedRef.current) return;
|
|
4925
5054
|
if (typeof window !== "undefined") {
|
|
4926
|
-
|
|
4927
|
-
if (urlParams.has("code")) {
|
|
5055
|
+
if (resolveCallbackKey(new URLSearchParams(window.location.search))) {
|
|
4928
5056
|
return;
|
|
4929
5057
|
}
|
|
4930
5058
|
}
|
|
@@ -6785,6 +6913,7 @@ exports.FFID_INQUIRY_CATEGORIES = FFID_INQUIRY_CATEGORIES;
|
|
|
6785
6913
|
exports.FFID_INQUIRY_CATEGORIES_SITE_2026 = FFID_INQUIRY_CATEGORIES_SITE_2026;
|
|
6786
6914
|
exports.FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES;
|
|
6787
6915
|
exports.FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB;
|
|
6916
|
+
exports.FFID_OAUTH_DENIAL_REASONS = FFID_OAUTH_DENIAL_REASONS;
|
|
6788
6917
|
exports.FFID_ORGANIZATION_PROFILE_ERROR_CODES = FFID_ORGANIZATION_PROFILE_ERROR_CODES;
|
|
6789
6918
|
exports.FFID_SUBSCRIPTION_ERROR_CODES = FFID_SUBSCRIPTION_ERROR_CODES;
|
|
6790
6919
|
exports.canonicalizeCatalogValue = canonicalizeCatalogValue;
|
|
@@ -6803,12 +6932,14 @@ exports.createFFIDClient = createFFIDClient;
|
|
|
6803
6932
|
exports.createTokenStore = createTokenStore;
|
|
6804
6933
|
exports.generateCodeChallenge = generateCodeChallenge;
|
|
6805
6934
|
exports.generateCodeVerifier = generateCodeVerifier;
|
|
6935
|
+
exports.getFFIDAuthorizationError = getFFIDAuthorizationError;
|
|
6806
6936
|
exports.handleRedirectCallback = handleRedirectCallback;
|
|
6807
6937
|
exports.hasAccessFromUserinfo = hasAccessFromUserinfo;
|
|
6808
6938
|
exports.hashCanonicalJson = hashCanonicalJson;
|
|
6809
6939
|
exports.isBlockedFromUserinfo = isBlockedFromUserinfo;
|
|
6810
6940
|
exports.isFFIDInquiryAcquisitionSource = isFFIDInquiryAcquisitionSource;
|
|
6811
6941
|
exports.isFFIDInquiryCategorySite2026 = isFFIDInquiryCategorySite2026;
|
|
6942
|
+
exports.isFFIDOAuthDenialReason = isFFIDOAuthDenialReason;
|
|
6812
6943
|
exports.normalizeRedirectUri = normalizeRedirectUri;
|
|
6813
6944
|
exports.readAgencyInviteCookie = readAgencyInviteCookie;
|
|
6814
6945
|
exports.readAgencyInviteToken = readAgencyInviteToken;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkVR3QR64A_cjs = require('../chunk-VR3QR64A.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 chunkVR3QR64A_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkVR3QR64A_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkVR3QR64A_cjs.FFIDInquiryForm; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkVR3QR64A_cjs.FFIDLoginButton; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkVR3QR64A_cjs.FFIDOrganizationSwitcher; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkVR3QR64A_cjs.FFIDSubscriptionBadge; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunkVR3QR64A_cjs.FFIDUserMenu; }
|
|
34
34
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-
|
|
1
|
+
export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-BknVfXhZ.cjs';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import 'react';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-
|
|
1
|
+
export { a8 as FFIDAnnouncementBadge, bk as FFIDAnnouncementBadgeClassNames, bl as FFIDAnnouncementBadgeProps, a9 as FFIDAnnouncementList, bm as FFIDAnnouncementListClassNames, bn as FFIDAnnouncementListProps, ar as FFIDInquiryForm, as as FFIDInquiryFormCategoryItem, at as FFIDInquiryFormClassNames, au as FFIDInquiryFormLegalLayout, av as FFIDInquiryFormOrganization, aw as FFIDInquiryFormPlaceholderContext, ax as FFIDInquiryFormPrefill, ay as FFIDInquiryFormProps, az as FFIDInquiryFormSubmitData, aA as FFIDInquiryFormSubmitResult, aC as FFIDLoginButton, bo as FFIDLoginButtonProps, aE as FFIDOrganizationSwitcher, bp as FFIDOrganizationSwitcherClassNames, bq as FFIDOrganizationSwitcherProps, aS as FFIDSubscriptionBadge, br as FFIDSubscriptionBadgeClassNames, bs as FFIDSubscriptionBadgeProps, aW as FFIDUserMenu, bt as FFIDUserMenuClassNames, bu as FFIDUserMenuProps } from '../index-BknVfXhZ.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-QORWLPWG.js';
|
|
@@ -961,12 +961,19 @@ interface FFIDBuyCreditsUrlParams {
|
|
|
961
961
|
type FFIDSubscriptionStatus = 'trialing' | 'active' | 'past_due' | 'canceled' | 'pending_invoice' | 'paused' | 'incomplete' | 'incomplete_expired' | 'unpaid';
|
|
962
962
|
interface FFIDSubscriptionCheckResponse {
|
|
963
963
|
hasActiveSubscription: boolean;
|
|
964
|
+
/**
|
|
965
|
+
* Active seat for the requested user; null for organization-only checks.
|
|
966
|
+
* Older servers omit this field. User access requires hasAccess AND
|
|
967
|
+
* seatAssigned === true; an omitted/null value is not proof of a seat.
|
|
968
|
+
*/
|
|
969
|
+
seatAssigned?: boolean | null;
|
|
964
970
|
/**
|
|
965
971
|
* Canonical access decision returned by FFID's `/subscriptions/ext/check`.
|
|
966
972
|
*
|
|
967
973
|
* This is the server-side source of truth for service gates. Consumers
|
|
968
974
|
* should not recompute access from `currentPeriodEnd`, `past_due_since`, or
|
|
969
975
|
* local payment timestamps.
|
|
976
|
+
* This is contract access; user access also requires seatAssigned === true.
|
|
970
977
|
*/
|
|
971
978
|
hasAccess?: boolean;
|
|
972
979
|
/** True when `effectiveStatus === 'past_due_grace'`. */
|
|
@@ -996,9 +1003,11 @@ interface FFIDSubscriptionCheckResponse {
|
|
|
996
1003
|
*/
|
|
997
1004
|
pricingModel?: FFIDPricingModel | null;
|
|
998
1005
|
/**
|
|
999
|
-
* Credit balance summary — flat plans only (10.0.0). `null` for per_seat, for
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1006
|
+
* Credit balance summary — paid flat plans only (10.0.0). `null` for per_seat, for a
|
|
1007
|
+
* `free` plan (flat on the unified ladder since #6547, but outside credits — consume /
|
|
1008
|
+
* balance return 409 `CREDITS_NOT_APPLICABLE`), for no subscription, **and** when FFID
|
|
1009
|
+
* could not read the ledger, so `null` does not mean "not flat" (use `pricingModel`).
|
|
1010
|
+
* Never affects `hasAccess`.
|
|
1002
1011
|
*/
|
|
1003
1012
|
credits?: FFIDSubscriptionCheckCredits | null;
|
|
1004
1013
|
/**
|
|
@@ -1014,7 +1023,8 @@ type FFIDServiceAccessFailPolicy = 'failClosed';
|
|
|
1014
1023
|
*
|
|
1015
1024
|
* `member_limit_reached` (10.0.0) is FFID's denial reason when a flat plan's member
|
|
1016
1025
|
* limit is full and the user has no seat. It reaches you through OAuth
|
|
1017
|
-
* (`denial_reason` on authorize / userinfo
|
|
1026
|
+
* (`denial_reason` on the authorize redirect / userinfo 403; see
|
|
1027
|
+
* `FFIDOAuthDenialReason` for that vocabulary); `checkServiceAccess()`
|
|
1018
1028
|
* derives its decision from `effectiveStatus` and never returns it, because a full
|
|
1019
1029
|
* member limit does not change `hasAccess` (CREDITS_API §1-5). It is in this union so
|
|
1020
1030
|
* one exhaustive `switch` over denial reasons covers both paths.
|
|
@@ -1044,7 +1054,10 @@ interface FFIDServiceAccessError {
|
|
|
1044
1054
|
details?: unknown;
|
|
1045
1055
|
}
|
|
1046
1056
|
interface FFIDServiceAccessDecision {
|
|
1057
|
+
/** Contract access; user access also requires seatAssigned === true. */
|
|
1047
1058
|
hasAccess: boolean;
|
|
1059
|
+
/** User's active seat, passed through when returned. Gate user access with === true. */
|
|
1060
|
+
seatAssigned?: boolean | null;
|
|
1048
1061
|
effectiveStatus: EffectiveSubscriptionStatus | null;
|
|
1049
1062
|
isGrace: boolean;
|
|
1050
1063
|
isBlocked: boolean;
|
|
@@ -1209,9 +1222,18 @@ interface FFIDAddMemberRequest {
|
|
|
1209
1222
|
interface FFIDAddMemberParams extends FFIDAddMemberRequest {
|
|
1210
1223
|
organizationId: string;
|
|
1211
1224
|
}
|
|
1225
|
+
/** Seat assignment outcome after membership creation; membership exists in every case. */
|
|
1226
|
+
type FFIDMemberSeatAssignmentResult = 'assigned' | 'not_applicable' | 'member_limit_reached' | 'failed';
|
|
1212
1227
|
/** Response from addMember (ext) */
|
|
1213
1228
|
interface FFIDAddMemberResponse {
|
|
1214
1229
|
member: FFIDOrganizationMember;
|
|
1230
|
+
/**
|
|
1231
|
+
* Membership creation can succeed even when seat assignment fails.
|
|
1232
|
+
* Omitted by older servers. `not_applicable`/undefined do not prove an active seat.
|
|
1233
|
+
* Check the authenticated user's hasAccess and seatAssigned before granting access;
|
|
1234
|
+
* do not automatically restore a removed seat on a duplicate-member retry.
|
|
1235
|
+
*/
|
|
1236
|
+
seatAssignment?: FFIDMemberSeatAssignmentResult;
|
|
1215
1237
|
}
|
|
1216
1238
|
/** Response from updateMemberRole (ext) */
|
|
1217
1239
|
interface FFIDUpdateMemberRoleResponse {
|
|
@@ -2430,11 +2452,10 @@ interface FFIDConfig {
|
|
|
2430
2452
|
*/
|
|
2431
2453
|
cache?: FFIDCacheConfig | undefined;
|
|
2432
2454
|
/**
|
|
2433
|
-
*
|
|
2434
|
-
* token verification
|
|
2435
|
-
*
|
|
2436
|
-
*
|
|
2437
|
-
* surfaced through the normal error path (e.g. `NETWORK_ERROR`).
|
|
2455
|
+
* Per-HTTP timeout (ms): shared JSON APIs (e.g. checkSubscription/getProfile),
|
|
2456
|
+
* token verification/introspection, token OAuth exchange/refresh/revoke; also FFIDProvider.timeout.
|
|
2457
|
+
* Shared JSON includes body and preserves signals; refresh/retry have separate deadlines.
|
|
2458
|
+
* Excludes token getSession, cookie signOut, public/newsletter/inquiry; not a method deadline.
|
|
2438
2459
|
* @default undefined (no timeout, uses fetch default)
|
|
2439
2460
|
*/
|
|
2440
2461
|
timeout?: number | undefined;
|
|
@@ -2800,6 +2821,7 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
2800
2821
|
organizationId: string;
|
|
2801
2822
|
email: string;
|
|
2802
2823
|
role?: FFIDAssignableMemberRole;
|
|
2824
|
+
inviterUserId?: string;
|
|
2803
2825
|
}) => Promise<FFIDApiResponse<FFIDInviteMemberResponse>>;
|
|
2804
2826
|
leaveOrganization: (params: FFIDLeaveOrganizationParams) => Promise<FFIDApiResponse<FFIDLeaveOrganizationResponse>>;
|
|
2805
2827
|
getAnalyticsConfig: (serviceCode: string, options?: FFIDProfileCallOptions) => Promise<FFIDApiResponse<FFIDAnalyticsConfig>>;
|
|
@@ -2886,4 +2908,4 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
2886
2908
|
/** Type of the FFID client */
|
|
2887
2909
|
type FFIDClient = ReturnType<typeof createFFIDClient>;
|
|
2888
2910
|
|
|
2889
|
-
export { type
|
|
2911
|
+
export { type FFIDProvisionUserResponse as $, type FFIDMemberSeatAssignmentResult as A, type FFIDOrganization as B, type FFIDOrganizationLogoUploadResponse as C, type FFIDOrganizationMember as D, type FFIDOrganizationProfile as E, type FFIDError as F, type FFIDOrganizationProfileErrorCode as G, type FFIDOrganizationProfileResponse as H, type FFIDOtpSendResponse as I, type FFIDOtpVerifyResponse as J, type FFIDPasswordResetConfirmResponse as K, type FFIDPasswordResetResponse as L, type FFIDPasswordResetVerifyResponse as M, type FFIDProfileCallOptions as N, type FFIDProvisionMemberPlan as O, type FFIDProvisionMemberPlanStatus as P, type FFIDProvisionMemberResult as Q, type FFIDProvisionMemberStatus as R, type FFIDProvisionOrganizationDryRun as S, type FFIDProvisionOrganizationMemberInput as T, type FFIDProvisionOrganizationOutcome as U, type FFIDProvisionOrganizationParams as V, type FFIDProvisionOrganizationResponse as W, type FFIDProvisionUserDryRun as X, type FFIDProvisionUserOutcome as Y, type FFIDProvisionUserParams as Z, type FFIDProvisionUserProfileInput as _, type FFIDLogger as a, type FFIDProvisionedOrganization as a0, type FFIDProvisionedUser as a1, type FFIDPublishedPlan as a2, type FFIDRemoveMemberResponse as a3, type FFIDResetSessionResponse as a4, type FFIDSubscription as a5, type FFIDUpdateMemberRoleResponse as a6, type FFIDUpdateUserProfileRequest as a7, type FFIDUploadOrganizationLogoParams as a8, type FFIDUpsertOrganizationProfileParams as a9, type FFIDUpsertOrganizationProfileRequest as aa, type FFIDUser as ab, type FFIDUserProfile as ac, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES as ad, FFID_CATALOG_ENVIRONMENTS as ae, FFID_CATALOG_PUBLICATION_STATUSES as af, FFID_COMPANY_SIZE_CODES as ag, FFID_INDUSTRY_CODES as ah, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES as ai, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB as aj, FFID_ORGANIZATION_PROFILE_ERROR_CODES as ak, type TokenData as al, type TokenStore as am, createFFIDClient as an, createTokenStore as ao, type FFIDCacheAdapter as b, type FFIDVerifyAccessTokenOptions as c, type FFIDApiResponse as d, type FFIDOAuthUserInfo as e, type FFIDCatalogEnvironment as f, type FFIDBillingInterval as g, type FFIDTaxBehavior as h, type FFIDPublishedCatalog as i, type FFIDAddMemberParams as j, type FFIDAddMemberRequest as k, type FFIDAddMemberResponse as l, type FFIDAllowedLogoMimeType as m, type FFIDAssignableMemberRole as n, type FFIDCacheConfig as o, type FFIDCatalogPublication as p, type FFIDCatalogPublicationStatus as q, type FFIDClient as r, type FFIDCompanySizeCode as s, type FFIDConfig as t, type FFIDIndustryCode as u, type FFIDListMembersResponse as v, type FFIDListingConsentInput as w, type FFIDLogoWallEntry as x, type FFIDLogoWallResponse as y, type FFIDMemberRole as z };
|