@feelflow/ffid-sdk 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -0
- package/dist/{chunk-P7HSNT4U.js → chunk-35UOD62N.js} +156 -3
- package/dist/{chunk-OYCNHBMG.cjs → chunk-5MO7G2JW.cjs} +156 -3
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-ZcJhRbD6.d.cts → ffid-client-BaStAONh.d.ts} +110 -11
- package/dist/{ffid-client-ZcJhRbD6.d.ts → ffid-client-DgprK2ec.d.cts} +110 -11
- package/dist/{index-Cn8-3hgb.d.cts → index-CInGR4I9.d.cts} +102 -11
- package/dist/{index-Cn8-3hgb.d.ts → index-CInGR4I9.d.ts} +102 -11
- package/dist/index.cjs +32 -32
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +156 -3
- package/dist/server/index.d.cts +3 -2
- package/dist/server/index.d.ts +3 -2
- package/dist/server/index.js +156 -3
- package/dist/server/test/index.d.cts +2 -1
- package/dist/server/test/index.d.ts +2 -1
- package/dist/types-5g_Bg6Ey.d.cts +37 -0
- package/dist/types-5g_Bg6Ey.d.ts +37 -0
- package/dist/webhooks/index.d.cts +18 -0
- package/dist/webhooks/index.d.ts +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -291,6 +291,72 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|
|
291
291
|
|
|
292
292
|
**詳細な実装レシピ**(middleware、Express、UI 分岐、Webhook 受信、fixture API を使ったテスト、`EffectiveSubscriptionStatus` 別の UI 推奨動作まで) → [docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md](https://github.com/feel-flow/feelflow-id-platform/blob/develop/docs/03-implementation/EXPIRED_CONTRACT_HANDLING.md)
|
|
293
293
|
|
|
294
|
+
### Server-side service access decision
|
|
295
|
+
|
|
296
|
+
API route / middleware では `checkServiceAccess()` を使う。FFID の `/api/v1/subscriptions/ext/check` が返す canonical decision をそのまま受け取り、外部サービス側で `past_due_since + 7d`、`current_period_end + 7d`、`payment_failed_at + 7d` のような lifecycle date math を再実装しない。
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
import { createFFIDClient } from '@feelflow/ffid-sdk'
|
|
300
|
+
|
|
301
|
+
const ffid = createFFIDClient({
|
|
302
|
+
serviceCode: 'flow-board-ai',
|
|
303
|
+
scope: '',
|
|
304
|
+
authMode: 'service-key',
|
|
305
|
+
serviceApiKey: process.env.FFID_SERVICE_API_KEY!,
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const { data: access, error } = await ffid.checkServiceAccess({
|
|
309
|
+
userId,
|
|
310
|
+
organizationId,
|
|
311
|
+
allowGrace: true,
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
if (error || !access?.hasAccess) {
|
|
315
|
+
return Response.redirect('/contract-required')
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
- `checkServiceAccess()` は **`data.hasAccess` が唯一の gate**。`result.error` は入力 validation など SDK が decision を作れない場合にだけ返る。
|
|
320
|
+
- `hasAccess`: FFID が決めた canonical access decision。`allowGrace=false` のときだけ SDK 側で `past_due_grace` を deny に変換する。
|
|
321
|
+
- `effectiveStatus`: `active` / `past_due_grace` / `blocked` / `canceled` / `trial_expired` / `expired`。
|
|
322
|
+
- `gracePeriodEndsAt`: `past_due_grace` が `blocked` に変わる時刻。表示・警告用であり、アクセス判定の source of truth にしない。
|
|
323
|
+
- `failPolicy`: 現在は `failClosed` 固定。FFID に到達できない、または canonical decision を取得できない場合は `result.error` ではなく `data.hasAccess=false` / `denialReason='ffid_unreachable'` / `data.error` を返す。呼び出し側は `result.error` だけで通過判定しない。
|
|
324
|
+
|
|
325
|
+
### Organization member management
|
|
326
|
+
|
|
327
|
+
`organization:read` / `organization:write` scope を持つ service-key または token で、組織メンバーの参照・追加・ロール変更・削除ができます。
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
import { createFFIDClient } from '@feelflow/ffid-sdk/server'
|
|
331
|
+
|
|
332
|
+
const ffid = createFFIDClient({
|
|
333
|
+
serviceCode: 'flow-board-ai',
|
|
334
|
+
scope: '',
|
|
335
|
+
authMode: 'service-key',
|
|
336
|
+
serviceApiKey: process.env.FFID_SERVICE_API_KEY!,
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
const addResult = await ffid.addMember({
|
|
340
|
+
organizationId,
|
|
341
|
+
email: 'new-member@example.com',
|
|
342
|
+
role: 'member',
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
if (addResult.error) {
|
|
346
|
+
throw new Error(addResult.error.message)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
await ffid.updateMemberRole({
|
|
350
|
+
organizationId,
|
|
351
|
+
userId: addResult.data.member.userId,
|
|
352
|
+
role: 'admin',
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
- `addMember` は既存 FFID ユーザーを active member として追加します。招待メール送信や token 発行は行いません。
|
|
357
|
+
- `role` は `admin` / `member` / `viewer` のみ指定可能です。`owner` は追加・昇格 API では扱いません。
|
|
358
|
+
- agency client と同じ呼び味が必要な場合は `ffid.addMember(organizationId, { email, role })` も使えます。
|
|
359
|
+
|
|
294
360
|
### getProfile() / updateProfile()
|
|
295
361
|
|
|
296
362
|
ログイン中ユーザー自身のプロフィールを取得・更新するメソッド(`createFFIDClient` から呼び出し)。
|
|
@@ -708,6 +708,7 @@ function createSubscriptionMethods(deps) {
|
|
|
708
708
|
var EXT_MEMBERS_ENDPOINT = "/api/v1/organizations/ext/members";
|
|
709
709
|
function createMembersMethods(deps) {
|
|
710
710
|
const { fetchWithAuth, createError, serviceCode } = deps;
|
|
711
|
+
const assignableRoles = /* @__PURE__ */ new Set(["admin", "member", "viewer"]);
|
|
711
712
|
function buildQuery(organizationId) {
|
|
712
713
|
return new URLSearchParams({ organizationId, serviceCode }).toString();
|
|
713
714
|
}
|
|
@@ -721,6 +722,37 @@ function createMembersMethods(deps) {
|
|
|
721
722
|
`${EXT_MEMBERS_ENDPOINT}?${buildQuery(params.organizationId)}`
|
|
722
723
|
);
|
|
723
724
|
}
|
|
725
|
+
function normalizeAddMemberArgs(paramsOrOrganizationId, data) {
|
|
726
|
+
if (typeof paramsOrOrganizationId === "string") {
|
|
727
|
+
const params = {
|
|
728
|
+
organizationId: paramsOrOrganizationId,
|
|
729
|
+
email: data?.email ?? ""
|
|
730
|
+
};
|
|
731
|
+
if (data?.role !== void 0) params.role = data.role;
|
|
732
|
+
return params;
|
|
733
|
+
}
|
|
734
|
+
return paramsOrOrganizationId;
|
|
735
|
+
}
|
|
736
|
+
async function addMember(paramsOrOrganizationId, data) {
|
|
737
|
+
const params = normalizeAddMemberArgs(paramsOrOrganizationId, data);
|
|
738
|
+
if (!params.organizationId || !params.email) {
|
|
739
|
+
return {
|
|
740
|
+
error: createError("VALIDATION_ERROR", "organizationId \u3068 email \u306F\u5FC5\u9808\u3067\u3059")
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
if (params.role !== void 0 && !assignableRoles.has(params.role)) {
|
|
744
|
+
return {
|
|
745
|
+
error: createError("VALIDATION_ERROR", "role \u306F admin\u3001member\u3001viewer \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044")
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
return fetchWithAuth(
|
|
749
|
+
`${EXT_MEMBERS_ENDPOINT}?${buildQuery(params.organizationId)}`,
|
|
750
|
+
{
|
|
751
|
+
method: "POST",
|
|
752
|
+
body: JSON.stringify({ email: params.email, role: params.role })
|
|
753
|
+
}
|
|
754
|
+
);
|
|
755
|
+
}
|
|
724
756
|
async function updateMemberRole(params) {
|
|
725
757
|
if (!params.organizationId || !params.userId) {
|
|
726
758
|
return {
|
|
@@ -753,7 +785,7 @@ function createMembersMethods(deps) {
|
|
|
753
785
|
}
|
|
754
786
|
);
|
|
755
787
|
}
|
|
756
|
-
return { listMembers, updateMemberRole, removeMember };
|
|
788
|
+
return { listMembers, addMember, updateMemberRole, removeMember };
|
|
757
789
|
}
|
|
758
790
|
|
|
759
791
|
// src/client/profile-methods.ts
|
|
@@ -806,7 +838,7 @@ function createProfileMethods(deps) {
|
|
|
806
838
|
}
|
|
807
839
|
|
|
808
840
|
// src/client/version-check.ts
|
|
809
|
-
var SDK_VERSION = "4.
|
|
841
|
+
var SDK_VERSION = "4.3.0";
|
|
810
842
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
811
843
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
812
844
|
function sdkHeaders() {
|
|
@@ -2222,6 +2254,73 @@ var FFID_ERROR_CODES = {
|
|
|
2222
2254
|
TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
|
|
2223
2255
|
};
|
|
2224
2256
|
var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
2257
|
+
var DEFAULT_ALLOW_GRACE = true;
|
|
2258
|
+
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2259
|
+
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2260
|
+
var ACCESS_GRANTING_EFFECTIVE_STATUSES = ["active", "past_due_grace"];
|
|
2261
|
+
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
2262
|
+
"blocked",
|
|
2263
|
+
"canceled",
|
|
2264
|
+
"expired",
|
|
2265
|
+
"trial_expired"
|
|
2266
|
+
];
|
|
2267
|
+
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2268
|
+
if (params.hasAccess) {
|
|
2269
|
+
return null;
|
|
2270
|
+
}
|
|
2271
|
+
if (params.effectiveStatus === null) {
|
|
2272
|
+
return "no_subscription";
|
|
2273
|
+
}
|
|
2274
|
+
if (params.isGrace && !allowGrace) {
|
|
2275
|
+
return "grace_disallowed";
|
|
2276
|
+
}
|
|
2277
|
+
if (params.effectiveStatus === "active" || params.effectiveStatus === "past_due_grace") {
|
|
2278
|
+
return "blocked";
|
|
2279
|
+
}
|
|
2280
|
+
return params.effectiveStatus;
|
|
2281
|
+
}
|
|
2282
|
+
function toServiceAccessDecision(response, allowGrace) {
|
|
2283
|
+
const effectiveStatus = response.effectiveStatus ?? null;
|
|
2284
|
+
const serverHasAccess = response.hasAccess ?? (effectiveStatus !== null && ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
2285
|
+
const isGrace = response.isGrace ?? effectiveStatus === "past_due_grace";
|
|
2286
|
+
const hasAccess = serverHasAccess && (allowGrace || !isGrace);
|
|
2287
|
+
const isBlocked = response.isBlocked ?? (effectiveStatus === null || effectiveStatus !== null && BLOCKING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
2288
|
+
return {
|
|
2289
|
+
hasAccess,
|
|
2290
|
+
effectiveStatus,
|
|
2291
|
+
isGrace,
|
|
2292
|
+
isBlocked: isBlocked || !hasAccess,
|
|
2293
|
+
allowGrace,
|
|
2294
|
+
failPolicy: DEFAULT_SERVICE_ACCESS_FAIL_POLICY,
|
|
2295
|
+
denialReason: resolveServiceAccessDenialReason({ effectiveStatus, hasAccess, isGrace }, allowGrace),
|
|
2296
|
+
organizationId: response.organizationId,
|
|
2297
|
+
subscriptionId: response.subscriptionId,
|
|
2298
|
+
status: response.status,
|
|
2299
|
+
planCode: response.planCode,
|
|
2300
|
+
currentPeriodEnd: response.currentPeriodEnd,
|
|
2301
|
+
gracePeriodEndsAt: response.gracePeriodEndsAt ?? null,
|
|
2302
|
+
reactivatable: response.reactivatable ?? false
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
function failClosedServiceAccessDecision(params, error) {
|
|
2306
|
+
return {
|
|
2307
|
+
hasAccess: false,
|
|
2308
|
+
effectiveStatus: null,
|
|
2309
|
+
isGrace: false,
|
|
2310
|
+
isBlocked: true,
|
|
2311
|
+
allowGrace: params.allowGrace ?? DEFAULT_ALLOW_GRACE,
|
|
2312
|
+
failPolicy: DEFAULT_SERVICE_ACCESS_FAIL_POLICY,
|
|
2313
|
+
denialReason: "ffid_unreachable",
|
|
2314
|
+
organizationId: params.organizationId || null,
|
|
2315
|
+
subscriptionId: null,
|
|
2316
|
+
status: null,
|
|
2317
|
+
planCode: null,
|
|
2318
|
+
currentPeriodEnd: null,
|
|
2319
|
+
gracePeriodEndsAt: null,
|
|
2320
|
+
reactivatable: false,
|
|
2321
|
+
error
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2225
2324
|
function resolveRedirectUri(raw, logger) {
|
|
2226
2325
|
if (raw === null) return null;
|
|
2227
2326
|
try {
|
|
@@ -2460,6 +2559,57 @@ function createFFIDClient(config) {
|
|
|
2460
2559
|
`${EXT_CHECK_ENDPOINT}?${query.toString()}`
|
|
2461
2560
|
);
|
|
2462
2561
|
}
|
|
2562
|
+
async function checkServiceAccess(params) {
|
|
2563
|
+
const failPolicy = params.failPolicy ?? DEFAULT_SERVICE_ACCESS_FAIL_POLICY;
|
|
2564
|
+
if (failPolicy !== DEFAULT_SERVICE_ACCESS_FAIL_POLICY) {
|
|
2565
|
+
return {
|
|
2566
|
+
error: createError(
|
|
2567
|
+
"VALIDATION_ERROR",
|
|
2568
|
+
`failPolicy \u306F ${DEFAULT_SERVICE_ACCESS_FAIL_POLICY} \u306E\u307F\u6307\u5B9A\u3067\u304D\u307E\u3059`
|
|
2569
|
+
)
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2572
|
+
const subscriptionParams = {
|
|
2573
|
+
organizationId: params.organizationId
|
|
2574
|
+
};
|
|
2575
|
+
if (params.userId !== void 0) {
|
|
2576
|
+
subscriptionParams.userId = params.userId;
|
|
2577
|
+
}
|
|
2578
|
+
const subscriptionResult = await checkSubscription(subscriptionParams);
|
|
2579
|
+
if (subscriptionResult.error) {
|
|
2580
|
+
if (subscriptionResult.error.code === "VALIDATION_ERROR") {
|
|
2581
|
+
return { error: subscriptionResult.error };
|
|
2582
|
+
}
|
|
2583
|
+
return {
|
|
2584
|
+
data: failClosedServiceAccessDecision(params, subscriptionResult.error)
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
return {
|
|
2588
|
+
data: toServiceAccessDecision(
|
|
2589
|
+
subscriptionResult.data,
|
|
2590
|
+
params.allowGrace ?? DEFAULT_ALLOW_GRACE
|
|
2591
|
+
)
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
async function requireServiceAccess(params) {
|
|
2595
|
+
const result = await checkServiceAccess(params);
|
|
2596
|
+
if (result.error) {
|
|
2597
|
+
return result;
|
|
2598
|
+
}
|
|
2599
|
+
if (!result.data.hasAccess) {
|
|
2600
|
+
const error = createError(
|
|
2601
|
+
SERVICE_ACCESS_DENIED_CODE,
|
|
2602
|
+
`FFID service access denied: ${result.data.denialReason ?? "unknown"}`
|
|
2603
|
+
);
|
|
2604
|
+
if (result.data.error) {
|
|
2605
|
+
error.details = { cause: result.data.error };
|
|
2606
|
+
}
|
|
2607
|
+
return {
|
|
2608
|
+
error
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
return result;
|
|
2612
|
+
}
|
|
2463
2613
|
const { createCheckoutSession, createPortalSession } = createBillingMethods({
|
|
2464
2614
|
fetchWithAuth,
|
|
2465
2615
|
createError
|
|
@@ -2477,7 +2627,7 @@ function createFFIDClient(config) {
|
|
|
2477
2627
|
fetchWithAuth,
|
|
2478
2628
|
createError
|
|
2479
2629
|
});
|
|
2480
|
-
const { listMembers, updateMemberRole, removeMember } = createMembersMethods({
|
|
2630
|
+
const { listMembers, addMember, updateMemberRole, removeMember } = createMembersMethods({
|
|
2481
2631
|
fetchWithAuth,
|
|
2482
2632
|
createError,
|
|
2483
2633
|
serviceCode: config.serviceCode
|
|
@@ -2558,7 +2708,10 @@ function createFFIDClient(config) {
|
|
|
2558
2708
|
exchangeCodeForTokens,
|
|
2559
2709
|
refreshAccessToken,
|
|
2560
2710
|
checkSubscription,
|
|
2711
|
+
checkServiceAccess,
|
|
2712
|
+
requireServiceAccess,
|
|
2561
2713
|
listMembers,
|
|
2714
|
+
addMember,
|
|
2562
2715
|
updateMemberRole,
|
|
2563
2716
|
removeMember,
|
|
2564
2717
|
getProfile,
|
|
@@ -710,6 +710,7 @@ function createSubscriptionMethods(deps) {
|
|
|
710
710
|
var EXT_MEMBERS_ENDPOINT = "/api/v1/organizations/ext/members";
|
|
711
711
|
function createMembersMethods(deps) {
|
|
712
712
|
const { fetchWithAuth, createError, serviceCode } = deps;
|
|
713
|
+
const assignableRoles = /* @__PURE__ */ new Set(["admin", "member", "viewer"]);
|
|
713
714
|
function buildQuery(organizationId) {
|
|
714
715
|
return new URLSearchParams({ organizationId, serviceCode }).toString();
|
|
715
716
|
}
|
|
@@ -723,6 +724,37 @@ function createMembersMethods(deps) {
|
|
|
723
724
|
`${EXT_MEMBERS_ENDPOINT}?${buildQuery(params.organizationId)}`
|
|
724
725
|
);
|
|
725
726
|
}
|
|
727
|
+
function normalizeAddMemberArgs(paramsOrOrganizationId, data) {
|
|
728
|
+
if (typeof paramsOrOrganizationId === "string") {
|
|
729
|
+
const params = {
|
|
730
|
+
organizationId: paramsOrOrganizationId,
|
|
731
|
+
email: data?.email ?? ""
|
|
732
|
+
};
|
|
733
|
+
if (data?.role !== void 0) params.role = data.role;
|
|
734
|
+
return params;
|
|
735
|
+
}
|
|
736
|
+
return paramsOrOrganizationId;
|
|
737
|
+
}
|
|
738
|
+
async function addMember(paramsOrOrganizationId, data) {
|
|
739
|
+
const params = normalizeAddMemberArgs(paramsOrOrganizationId, data);
|
|
740
|
+
if (!params.organizationId || !params.email) {
|
|
741
|
+
return {
|
|
742
|
+
error: createError("VALIDATION_ERROR", "organizationId \u3068 email \u306F\u5FC5\u9808\u3067\u3059")
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
if (params.role !== void 0 && !assignableRoles.has(params.role)) {
|
|
746
|
+
return {
|
|
747
|
+
error: createError("VALIDATION_ERROR", "role \u306F admin\u3001member\u3001viewer \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044")
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
return fetchWithAuth(
|
|
751
|
+
`${EXT_MEMBERS_ENDPOINT}?${buildQuery(params.organizationId)}`,
|
|
752
|
+
{
|
|
753
|
+
method: "POST",
|
|
754
|
+
body: JSON.stringify({ email: params.email, role: params.role })
|
|
755
|
+
}
|
|
756
|
+
);
|
|
757
|
+
}
|
|
726
758
|
async function updateMemberRole(params) {
|
|
727
759
|
if (!params.organizationId || !params.userId) {
|
|
728
760
|
return {
|
|
@@ -755,7 +787,7 @@ function createMembersMethods(deps) {
|
|
|
755
787
|
}
|
|
756
788
|
);
|
|
757
789
|
}
|
|
758
|
-
return { listMembers, updateMemberRole, removeMember };
|
|
790
|
+
return { listMembers, addMember, updateMemberRole, removeMember };
|
|
759
791
|
}
|
|
760
792
|
|
|
761
793
|
// src/client/profile-methods.ts
|
|
@@ -808,7 +840,7 @@ function createProfileMethods(deps) {
|
|
|
808
840
|
}
|
|
809
841
|
|
|
810
842
|
// src/client/version-check.ts
|
|
811
|
-
var SDK_VERSION = "4.
|
|
843
|
+
var SDK_VERSION = "4.3.0";
|
|
812
844
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
813
845
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
814
846
|
function sdkHeaders() {
|
|
@@ -2224,6 +2256,73 @@ var FFID_ERROR_CODES = {
|
|
|
2224
2256
|
TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
|
|
2225
2257
|
};
|
|
2226
2258
|
var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
|
|
2259
|
+
var DEFAULT_ALLOW_GRACE = true;
|
|
2260
|
+
var DEFAULT_SERVICE_ACCESS_FAIL_POLICY = "failClosed";
|
|
2261
|
+
var SERVICE_ACCESS_DENIED_CODE = "SERVICE_ACCESS_DENIED";
|
|
2262
|
+
var ACCESS_GRANTING_EFFECTIVE_STATUSES = ["active", "past_due_grace"];
|
|
2263
|
+
var BLOCKING_EFFECTIVE_STATUSES = [
|
|
2264
|
+
"blocked",
|
|
2265
|
+
"canceled",
|
|
2266
|
+
"expired",
|
|
2267
|
+
"trial_expired"
|
|
2268
|
+
];
|
|
2269
|
+
function resolveServiceAccessDenialReason(params, allowGrace) {
|
|
2270
|
+
if (params.hasAccess) {
|
|
2271
|
+
return null;
|
|
2272
|
+
}
|
|
2273
|
+
if (params.effectiveStatus === null) {
|
|
2274
|
+
return "no_subscription";
|
|
2275
|
+
}
|
|
2276
|
+
if (params.isGrace && !allowGrace) {
|
|
2277
|
+
return "grace_disallowed";
|
|
2278
|
+
}
|
|
2279
|
+
if (params.effectiveStatus === "active" || params.effectiveStatus === "past_due_grace") {
|
|
2280
|
+
return "blocked";
|
|
2281
|
+
}
|
|
2282
|
+
return params.effectiveStatus;
|
|
2283
|
+
}
|
|
2284
|
+
function toServiceAccessDecision(response, allowGrace) {
|
|
2285
|
+
const effectiveStatus = response.effectiveStatus ?? null;
|
|
2286
|
+
const serverHasAccess = response.hasAccess ?? (effectiveStatus !== null && ACCESS_GRANTING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
2287
|
+
const isGrace = response.isGrace ?? effectiveStatus === "past_due_grace";
|
|
2288
|
+
const hasAccess = serverHasAccess && (allowGrace || !isGrace);
|
|
2289
|
+
const isBlocked = response.isBlocked ?? (effectiveStatus === null || effectiveStatus !== null && BLOCKING_EFFECTIVE_STATUSES.includes(effectiveStatus));
|
|
2290
|
+
return {
|
|
2291
|
+
hasAccess,
|
|
2292
|
+
effectiveStatus,
|
|
2293
|
+
isGrace,
|
|
2294
|
+
isBlocked: isBlocked || !hasAccess,
|
|
2295
|
+
allowGrace,
|
|
2296
|
+
failPolicy: DEFAULT_SERVICE_ACCESS_FAIL_POLICY,
|
|
2297
|
+
denialReason: resolveServiceAccessDenialReason({ effectiveStatus, hasAccess, isGrace }, allowGrace),
|
|
2298
|
+
organizationId: response.organizationId,
|
|
2299
|
+
subscriptionId: response.subscriptionId,
|
|
2300
|
+
status: response.status,
|
|
2301
|
+
planCode: response.planCode,
|
|
2302
|
+
currentPeriodEnd: response.currentPeriodEnd,
|
|
2303
|
+
gracePeriodEndsAt: response.gracePeriodEndsAt ?? null,
|
|
2304
|
+
reactivatable: response.reactivatable ?? false
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
function failClosedServiceAccessDecision(params, error) {
|
|
2308
|
+
return {
|
|
2309
|
+
hasAccess: false,
|
|
2310
|
+
effectiveStatus: null,
|
|
2311
|
+
isGrace: false,
|
|
2312
|
+
isBlocked: true,
|
|
2313
|
+
allowGrace: params.allowGrace ?? DEFAULT_ALLOW_GRACE,
|
|
2314
|
+
failPolicy: DEFAULT_SERVICE_ACCESS_FAIL_POLICY,
|
|
2315
|
+
denialReason: "ffid_unreachable",
|
|
2316
|
+
organizationId: params.organizationId || null,
|
|
2317
|
+
subscriptionId: null,
|
|
2318
|
+
status: null,
|
|
2319
|
+
planCode: null,
|
|
2320
|
+
currentPeriodEnd: null,
|
|
2321
|
+
gracePeriodEndsAt: null,
|
|
2322
|
+
reactivatable: false,
|
|
2323
|
+
error
|
|
2324
|
+
};
|
|
2325
|
+
}
|
|
2227
2326
|
function resolveRedirectUri(raw, logger) {
|
|
2228
2327
|
if (raw === null) return null;
|
|
2229
2328
|
try {
|
|
@@ -2462,6 +2561,57 @@ function createFFIDClient(config) {
|
|
|
2462
2561
|
`${EXT_CHECK_ENDPOINT}?${query.toString()}`
|
|
2463
2562
|
);
|
|
2464
2563
|
}
|
|
2564
|
+
async function checkServiceAccess(params) {
|
|
2565
|
+
const failPolicy = params.failPolicy ?? DEFAULT_SERVICE_ACCESS_FAIL_POLICY;
|
|
2566
|
+
if (failPolicy !== DEFAULT_SERVICE_ACCESS_FAIL_POLICY) {
|
|
2567
|
+
return {
|
|
2568
|
+
error: createError(
|
|
2569
|
+
"VALIDATION_ERROR",
|
|
2570
|
+
`failPolicy \u306F ${DEFAULT_SERVICE_ACCESS_FAIL_POLICY} \u306E\u307F\u6307\u5B9A\u3067\u304D\u307E\u3059`
|
|
2571
|
+
)
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
const subscriptionParams = {
|
|
2575
|
+
organizationId: params.organizationId
|
|
2576
|
+
};
|
|
2577
|
+
if (params.userId !== void 0) {
|
|
2578
|
+
subscriptionParams.userId = params.userId;
|
|
2579
|
+
}
|
|
2580
|
+
const subscriptionResult = await checkSubscription(subscriptionParams);
|
|
2581
|
+
if (subscriptionResult.error) {
|
|
2582
|
+
if (subscriptionResult.error.code === "VALIDATION_ERROR") {
|
|
2583
|
+
return { error: subscriptionResult.error };
|
|
2584
|
+
}
|
|
2585
|
+
return {
|
|
2586
|
+
data: failClosedServiceAccessDecision(params, subscriptionResult.error)
|
|
2587
|
+
};
|
|
2588
|
+
}
|
|
2589
|
+
return {
|
|
2590
|
+
data: toServiceAccessDecision(
|
|
2591
|
+
subscriptionResult.data,
|
|
2592
|
+
params.allowGrace ?? DEFAULT_ALLOW_GRACE
|
|
2593
|
+
)
|
|
2594
|
+
};
|
|
2595
|
+
}
|
|
2596
|
+
async function requireServiceAccess(params) {
|
|
2597
|
+
const result = await checkServiceAccess(params);
|
|
2598
|
+
if (result.error) {
|
|
2599
|
+
return result;
|
|
2600
|
+
}
|
|
2601
|
+
if (!result.data.hasAccess) {
|
|
2602
|
+
const error = createError(
|
|
2603
|
+
SERVICE_ACCESS_DENIED_CODE,
|
|
2604
|
+
`FFID service access denied: ${result.data.denialReason ?? "unknown"}`
|
|
2605
|
+
);
|
|
2606
|
+
if (result.data.error) {
|
|
2607
|
+
error.details = { cause: result.data.error };
|
|
2608
|
+
}
|
|
2609
|
+
return {
|
|
2610
|
+
error
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2613
|
+
return result;
|
|
2614
|
+
}
|
|
2465
2615
|
const { createCheckoutSession, createPortalSession } = createBillingMethods({
|
|
2466
2616
|
fetchWithAuth,
|
|
2467
2617
|
createError
|
|
@@ -2479,7 +2629,7 @@ function createFFIDClient(config) {
|
|
|
2479
2629
|
fetchWithAuth,
|
|
2480
2630
|
createError
|
|
2481
2631
|
});
|
|
2482
|
-
const { listMembers, updateMemberRole, removeMember } = createMembersMethods({
|
|
2632
|
+
const { listMembers, addMember, updateMemberRole, removeMember } = createMembersMethods({
|
|
2483
2633
|
fetchWithAuth,
|
|
2484
2634
|
createError,
|
|
2485
2635
|
serviceCode: config.serviceCode
|
|
@@ -2560,7 +2710,10 @@ function createFFIDClient(config) {
|
|
|
2560
2710
|
exchangeCodeForTokens,
|
|
2561
2711
|
refreshAccessToken,
|
|
2562
2712
|
checkSubscription,
|
|
2713
|
+
checkServiceAccess,
|
|
2714
|
+
requireServiceAccess,
|
|
2563
2715
|
listMembers,
|
|
2716
|
+
addMember,
|
|
2564
2717
|
updateMemberRole,
|
|
2565
2718
|
removeMember,
|
|
2566
2719
|
getProfile,
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk5MO7G2JW_cjs = require('../chunk-5MO7G2JW.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 chunk5MO7G2JW_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunk5MO7G2JW_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunk5MO7G2JW_cjs.FFIDInquiryForm; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunk5MO7G2JW_cjs.FFIDLoginButton; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunk5MO7G2JW_cjs.FFIDOrganizationSwitcher; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunk5MO7G2JW_cjs.FFIDSubscriptionBadge; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunk5MO7G2JW_cjs.FFIDUserMenu; }
|
|
34
34
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { S as FFIDAnnouncementBadge, av as FFIDAnnouncementBadgeClassNames, aw as FFIDAnnouncementBadgeProps, T as FFIDAnnouncementList, ax as FFIDAnnouncementListClassNames, ay as FFIDAnnouncementListProps, a0 as FFIDInquiryForm, a1 as FFIDInquiryFormCategoryItem, a2 as FFIDInquiryFormClassNames, a3 as FFIDInquiryFormLegalLayout, a4 as FFIDInquiryFormOrganization, a5 as FFIDInquiryFormPlaceholderContext, a6 as FFIDInquiryFormPrefill, a7 as FFIDInquiryFormProps, a8 as FFIDInquiryFormSubmitData, a9 as FFIDInquiryFormSubmitResult, ab as FFIDLoginButton, az as FFIDLoginButtonProps, ah as FFIDOrganizationSwitcher, aA as FFIDOrganizationSwitcherClassNames, aB as FFIDOrganizationSwitcherProps, am as FFIDSubscriptionBadge, aC as FFIDSubscriptionBadgeClassNames, aD as FFIDSubscriptionBadgeProps, ao as FFIDUserMenu, aE as FFIDUserMenuClassNames, aF as FFIDUserMenuProps } from '../index-CInGR4I9.cjs';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import 'react';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { S as FFIDAnnouncementBadge, av as FFIDAnnouncementBadgeClassNames, aw as FFIDAnnouncementBadgeProps, T as FFIDAnnouncementList, ax as FFIDAnnouncementListClassNames, ay as FFIDAnnouncementListProps, a0 as FFIDInquiryForm, a1 as FFIDInquiryFormCategoryItem, a2 as FFIDInquiryFormClassNames, a3 as FFIDInquiryFormLegalLayout, a4 as FFIDInquiryFormOrganization, a5 as FFIDInquiryFormPlaceholderContext, a6 as FFIDInquiryFormPrefill, a7 as FFIDInquiryFormProps, a8 as FFIDInquiryFormSubmitData, a9 as FFIDInquiryFormSubmitResult, ab as FFIDLoginButton, az as FFIDLoginButtonProps, ah as FFIDOrganizationSwitcher, aA as FFIDOrganizationSwitcherClassNames, aB as FFIDOrganizationSwitcherProps, am as FFIDSubscriptionBadge, aC as FFIDSubscriptionBadgeClassNames, aD as FFIDSubscriptionBadgeProps, ao as FFIDUserMenu, aE as FFIDUserMenuClassNames, aF as FFIDUserMenuProps } from '../index-CInGR4I9.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-35UOD62N.js';
|