@feelflow/ffid-sdk 5.18.0 → 5.19.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 +77 -0
- package/dist/{chunk-L2H56C4W.js → chunk-D3PZ6SZB.js} +95 -1
- package/dist/{chunk-55S5VUWR.cjs → chunk-TW2FXASO.cjs} +95 -1
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-Cwk6cG3b.d.cts → ffid-client-BuDM5tmq.d.cts} +214 -1
- package/dist/{ffid-client-w8Twi5lD.d.ts → ffid-client-D0x8TBS5.d.ts} +214 -1
- package/dist/index.cjs +42 -42
- package/dist/index.d.cts +214 -1
- package/dist/index.d.ts +214 -1
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +95 -1
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +95 -1
- package/dist/server/test/index.d.cts +1 -1
- package/dist/server/test/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -396,6 +396,83 @@ await ffid.updateMemberRole({
|
|
|
396
396
|
- `role` は `admin` / `member` / `viewer` のみ指定可能です。`owner` は追加・昇格 API では扱いません。
|
|
397
397
|
- agency client と同じ呼び味が必要な場合は `ffid.addMember(organizationId, { email, role })` も使えます。
|
|
398
398
|
|
|
399
|
+
### Provisioning(users / organizations)
|
|
400
|
+
|
|
401
|
+
外部サービスからの一括移行向けに、**service-key 認証**でユーザー・組織を冪等にプロビジョニングするメソッド。REST を直叩きせず `createFFIDClient` 経由で呼べる(SDK-first、#3790 / #4127)。
|
|
402
|
+
|
|
403
|
+
- **`authMode: 'service-key'`(`X-Service-Api-Key`)専用**。`token`(Bearer)/ `cookie` モードで呼ぶとサーバーへ往復せず即座に `VALIDATION_ERROR` を返す(サーバー側エンドポイントが service-key 認証のみを受け付けるため)。
|
|
404
|
+
- 必要 scope: `provisionUser` → `user:provision`、`provisionOrganization` → `organization:write`。
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
import { createFFIDClient } from '@feelflow/ffid-sdk/server'
|
|
408
|
+
|
|
409
|
+
const ffid = createFFIDClient({
|
|
410
|
+
serviceCode: 'praxis',
|
|
411
|
+
scope: '',
|
|
412
|
+
authMode: 'service-key',
|
|
413
|
+
serviceApiKey: process.env.FFID_SERVICE_API_KEY!,
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
// 1. ユーザーを冪等に作成(新規なら created:true / 既存なら created:false)
|
|
417
|
+
const userRes = await ffid.provisionUser({
|
|
418
|
+
email: 'owner@example.com',
|
|
419
|
+
profile: { displayName: '山田 太郎', companyName: 'Example Inc.' },
|
|
420
|
+
})
|
|
421
|
+
if (userRes.error) throw new Error(userRes.error.message)
|
|
422
|
+
if (!userRes.data.dryRun) {
|
|
423
|
+
console.log(userRes.data.created ? '新規作成' : '既存ユーザー', userRes.data.user.id)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// 2. その owner の組織を作成し、メンバーを冪等に追加
|
|
427
|
+
const orgRes = await ffid.provisionOrganization({
|
|
428
|
+
name: 'Example 組織',
|
|
429
|
+
ownerEmail: 'owner@example.com',
|
|
430
|
+
members: [
|
|
431
|
+
{ email: 'member1@example.com', role: 'member' },
|
|
432
|
+
{ email: 'member2@example.com', role: 'viewer' },
|
|
433
|
+
],
|
|
434
|
+
})
|
|
435
|
+
if (orgRes.error) {
|
|
436
|
+
// owner が未登録なら error.code === 'OWNER_NOT_FOUND'(先に provisionUser が必要)
|
|
437
|
+
throw new Error(orgRes.error.message)
|
|
438
|
+
}
|
|
439
|
+
if (!orgRes.data.dryRun) {
|
|
440
|
+
for (const m of orgRes.data.members) {
|
|
441
|
+
console.log(m.email, m.status) // 'added' | 'already_member' | 'user_not_found'
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### 冪等セマンティクス
|
|
447
|
+
|
|
448
|
+
- `provisionUser`: **既存メールは `created: false`**(HTTP 200、no-op)、新規メールは `created: true`(HTTP 201、パスワードレス・メール確認済み)。メールはサーバー側で normalize(trim + lowercase)されるため、大文字小文字違いの再送でも同一ユーザーに解決する。新規作成で `profile` を渡した場合のみ `profileWritten` が付き、`false` は「ユーザーは作成されたがプロフィール書き込みに失敗」→ 再送を推奨。
|
|
449
|
+
- `provisionOrganization`: owner が同名の組織を既に持つ場合は `created: false`(HTTP 200)。`members` は冪等に追加され、各要素の `status` が `added` / `already_member` / `user_not_found` を返す。
|
|
450
|
+
|
|
451
|
+
#### dryRun
|
|
452
|
+
|
|
453
|
+
`dryRun: true` を渡すと **一切書き込まず**、実行時に何が起きるかだけを返す。レスポンスは `dryRun` 判別のタグ付きユニオン。
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
const preview = await ffid.provisionUser({ email: 'owner@example.com', dryRun: true })
|
|
457
|
+
if (!preview.error && preview.data.dryRun) {
|
|
458
|
+
console.log(preview.data.wouldCreate) // true = 実行すれば新規作成される
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const orgPreview = await ffid.provisionOrganization({
|
|
462
|
+
name: 'Example 組織',
|
|
463
|
+
ownerEmail: 'owner@example.com',
|
|
464
|
+
members: [{ email: 'member1@example.com', role: 'member' }],
|
|
465
|
+
dryRun: true,
|
|
466
|
+
})
|
|
467
|
+
if (!orgPreview.error && orgPreview.data.dryRun) {
|
|
468
|
+
console.log(orgPreview.data.wouldCreate) // 組織を新規作成するか
|
|
469
|
+
// per-member plan status: 'would_add' | 'already_member' | 'user_not_found'
|
|
470
|
+
orgPreview.data.members.forEach((m) => console.log(m.email, m.status))
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
`if (res.data.dryRun)` で TypeScript が型を絞り込むため、dry-run 分岐では `wouldCreate`、実行分岐では `created` がそれぞれ型安全に参照できる。
|
|
475
|
+
|
|
399
476
|
### getProfile() / updateProfile()
|
|
400
477
|
|
|
401
478
|
ログイン中ユーザー自身のプロフィールを取得・更新するメソッド(`createFFIDClient` から呼び出し)。
|
|
@@ -873,6 +873,93 @@ function createMembersMethods(deps) {
|
|
|
873
873
|
return { listMembers, addMember, updateMemberRole, removeMember };
|
|
874
874
|
}
|
|
875
875
|
|
|
876
|
+
// src/client/provisioning-methods.ts
|
|
877
|
+
var USER_PROVISION_ENDPOINT = "/api/v1/ext/users/provision";
|
|
878
|
+
var ORGANIZATION_PROVISION_ENDPOINT = "/api/v1/ext/organizations/provision";
|
|
879
|
+
var MAX_PROVISION_MEMBERS = 100;
|
|
880
|
+
var ASSIGNABLE_MEMBER_ROLES = {
|
|
881
|
+
admin: true,
|
|
882
|
+
member: true,
|
|
883
|
+
viewer: true
|
|
884
|
+
};
|
|
885
|
+
function isAssignableMemberRole(role) {
|
|
886
|
+
return Object.hasOwn(ASSIGNABLE_MEMBER_ROLES, role);
|
|
887
|
+
}
|
|
888
|
+
function createProvisioningMethods(deps) {
|
|
889
|
+
const { fetchWithAuth, createError, authMode } = deps;
|
|
890
|
+
function serviceKeyModeError() {
|
|
891
|
+
if (authMode === "service-key") return null;
|
|
892
|
+
return createError(
|
|
893
|
+
"VALIDATION_ERROR",
|
|
894
|
+
"provisionUser / provisionOrganization \u306F service-key \u8A8D\u8A3C\uFF08X-Service-Api-Key\uFF09\u3067\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002Bearer / cookie \u30E2\u30FC\u30C9\u3067\u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093"
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
async function provisionUser(params) {
|
|
898
|
+
const modeError = serviceKeyModeError();
|
|
899
|
+
if (modeError) return { error: modeError };
|
|
900
|
+
if (!params.email || !params.email.trim()) {
|
|
901
|
+
return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
|
|
902
|
+
}
|
|
903
|
+
const body = { email: params.email.trim() };
|
|
904
|
+
if (params.profile !== void 0) body.profile = params.profile;
|
|
905
|
+
if (params.dryRun !== void 0) body.dryRun = params.dryRun;
|
|
906
|
+
return fetchWithAuth(USER_PROVISION_ENDPOINT, {
|
|
907
|
+
method: "POST",
|
|
908
|
+
body: JSON.stringify(body)
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
async function provisionOrganization(params) {
|
|
912
|
+
const modeError = serviceKeyModeError();
|
|
913
|
+
if (modeError) return { error: modeError };
|
|
914
|
+
if (!params.name || !params.name.trim()) {
|
|
915
|
+
return { error: createError("VALIDATION_ERROR", "name \u306F\u5FC5\u9808\u3067\u3059") };
|
|
916
|
+
}
|
|
917
|
+
if (!params.ownerEmail || !params.ownerEmail.trim()) {
|
|
918
|
+
return { error: createError("VALIDATION_ERROR", "ownerEmail \u306F\u5FC5\u9808\u3067\u3059") };
|
|
919
|
+
}
|
|
920
|
+
if (params.members) {
|
|
921
|
+
if (params.members.length > MAX_PROVISION_MEMBERS) {
|
|
922
|
+
return {
|
|
923
|
+
error: createError(
|
|
924
|
+
"VALIDATION_ERROR",
|
|
925
|
+
`members \u306F1\u30EA\u30AF\u30A8\u30B9\u30C8\u3042\u305F\u308A\u6700\u5927 ${MAX_PROVISION_MEMBERS} \u4EF6\u307E\u3067\u3067\u3059`
|
|
926
|
+
)
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
for (const member of params.members) {
|
|
930
|
+
if (!member.email || !member.email.trim()) {
|
|
931
|
+
return { error: createError("VALIDATION_ERROR", "members[].email \u306F\u5FC5\u9808\u3067\u3059") };
|
|
932
|
+
}
|
|
933
|
+
if (!isAssignableMemberRole(member.role)) {
|
|
934
|
+
return {
|
|
935
|
+
error: createError(
|
|
936
|
+
"VALIDATION_ERROR",
|
|
937
|
+
"members[].role \u306F admin\u3001member\u3001viewer \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
938
|
+
)
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
const body = {
|
|
944
|
+
name: params.name.trim(),
|
|
945
|
+
ownerEmail: params.ownerEmail.trim()
|
|
946
|
+
};
|
|
947
|
+
if (params.billingEmail !== void 0) body.billingEmail = params.billingEmail.trim();
|
|
948
|
+
if (params.members !== void 0) {
|
|
949
|
+
body.members = params.members.map((member) => ({
|
|
950
|
+
email: member.email.trim(),
|
|
951
|
+
role: member.role
|
|
952
|
+
}));
|
|
953
|
+
}
|
|
954
|
+
if (params.dryRun !== void 0) body.dryRun = params.dryRun;
|
|
955
|
+
return fetchWithAuth(ORGANIZATION_PROVISION_ENDPOINT, {
|
|
956
|
+
method: "POST",
|
|
957
|
+
body: JSON.stringify(body)
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
return { provisionUser, provisionOrganization };
|
|
961
|
+
}
|
|
962
|
+
|
|
876
963
|
// src/client/seat-methods.ts
|
|
877
964
|
function seatsEndpoint(subscriptionId) {
|
|
878
965
|
return `/api/v1/subscriptions/ext/${encodeURIComponent(subscriptionId)}/seats/assignments`;
|
|
@@ -1117,7 +1204,7 @@ function createNonContractMethods(deps) {
|
|
|
1117
1204
|
}
|
|
1118
1205
|
|
|
1119
1206
|
// src/client/version-check.ts
|
|
1120
|
-
var SDK_VERSION = "5.
|
|
1207
|
+
var SDK_VERSION = "5.19.0";
|
|
1121
1208
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1122
1209
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1123
1210
|
function sdkHeaders() {
|
|
@@ -3128,6 +3215,11 @@ function createFFIDClient(config) {
|
|
|
3128
3215
|
createError,
|
|
3129
3216
|
serviceCode: config.serviceCode
|
|
3130
3217
|
});
|
|
3218
|
+
const { provisionUser, provisionOrganization } = createProvisioningMethods({
|
|
3219
|
+
fetchWithAuth,
|
|
3220
|
+
createError,
|
|
3221
|
+
authMode
|
|
3222
|
+
});
|
|
3131
3223
|
const { getProfile, updateProfile } = createProfileMethods({
|
|
3132
3224
|
fetchWithAuth,
|
|
3133
3225
|
createError
|
|
@@ -3223,6 +3315,8 @@ function createFFIDClient(config) {
|
|
|
3223
3315
|
addMember,
|
|
3224
3316
|
updateMemberRole,
|
|
3225
3317
|
removeMember,
|
|
3318
|
+
provisionUser,
|
|
3319
|
+
provisionOrganization,
|
|
3226
3320
|
getProfile,
|
|
3227
3321
|
updateProfile,
|
|
3228
3322
|
// Non-contract ext API coverage (#3783)
|
|
@@ -875,6 +875,93 @@ function createMembersMethods(deps) {
|
|
|
875
875
|
return { listMembers, addMember, updateMemberRole, removeMember };
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
+
// src/client/provisioning-methods.ts
|
|
879
|
+
var USER_PROVISION_ENDPOINT = "/api/v1/ext/users/provision";
|
|
880
|
+
var ORGANIZATION_PROVISION_ENDPOINT = "/api/v1/ext/organizations/provision";
|
|
881
|
+
var MAX_PROVISION_MEMBERS = 100;
|
|
882
|
+
var ASSIGNABLE_MEMBER_ROLES = {
|
|
883
|
+
admin: true,
|
|
884
|
+
member: true,
|
|
885
|
+
viewer: true
|
|
886
|
+
};
|
|
887
|
+
function isAssignableMemberRole(role) {
|
|
888
|
+
return Object.hasOwn(ASSIGNABLE_MEMBER_ROLES, role);
|
|
889
|
+
}
|
|
890
|
+
function createProvisioningMethods(deps) {
|
|
891
|
+
const { fetchWithAuth, createError, authMode } = deps;
|
|
892
|
+
function serviceKeyModeError() {
|
|
893
|
+
if (authMode === "service-key") return null;
|
|
894
|
+
return createError(
|
|
895
|
+
"VALIDATION_ERROR",
|
|
896
|
+
"provisionUser / provisionOrganization \u306F service-key \u8A8D\u8A3C\uFF08X-Service-Api-Key\uFF09\u3067\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002Bearer / cookie \u30E2\u30FC\u30C9\u3067\u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093"
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
async function provisionUser(params) {
|
|
900
|
+
const modeError = serviceKeyModeError();
|
|
901
|
+
if (modeError) return { error: modeError };
|
|
902
|
+
if (!params.email || !params.email.trim()) {
|
|
903
|
+
return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
|
|
904
|
+
}
|
|
905
|
+
const body = { email: params.email.trim() };
|
|
906
|
+
if (params.profile !== void 0) body.profile = params.profile;
|
|
907
|
+
if (params.dryRun !== void 0) body.dryRun = params.dryRun;
|
|
908
|
+
return fetchWithAuth(USER_PROVISION_ENDPOINT, {
|
|
909
|
+
method: "POST",
|
|
910
|
+
body: JSON.stringify(body)
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
async function provisionOrganization(params) {
|
|
914
|
+
const modeError = serviceKeyModeError();
|
|
915
|
+
if (modeError) return { error: modeError };
|
|
916
|
+
if (!params.name || !params.name.trim()) {
|
|
917
|
+
return { error: createError("VALIDATION_ERROR", "name \u306F\u5FC5\u9808\u3067\u3059") };
|
|
918
|
+
}
|
|
919
|
+
if (!params.ownerEmail || !params.ownerEmail.trim()) {
|
|
920
|
+
return { error: createError("VALIDATION_ERROR", "ownerEmail \u306F\u5FC5\u9808\u3067\u3059") };
|
|
921
|
+
}
|
|
922
|
+
if (params.members) {
|
|
923
|
+
if (params.members.length > MAX_PROVISION_MEMBERS) {
|
|
924
|
+
return {
|
|
925
|
+
error: createError(
|
|
926
|
+
"VALIDATION_ERROR",
|
|
927
|
+
`members \u306F1\u30EA\u30AF\u30A8\u30B9\u30C8\u3042\u305F\u308A\u6700\u5927 ${MAX_PROVISION_MEMBERS} \u4EF6\u307E\u3067\u3067\u3059`
|
|
928
|
+
)
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
for (const member of params.members) {
|
|
932
|
+
if (!member.email || !member.email.trim()) {
|
|
933
|
+
return { error: createError("VALIDATION_ERROR", "members[].email \u306F\u5FC5\u9808\u3067\u3059") };
|
|
934
|
+
}
|
|
935
|
+
if (!isAssignableMemberRole(member.role)) {
|
|
936
|
+
return {
|
|
937
|
+
error: createError(
|
|
938
|
+
"VALIDATION_ERROR",
|
|
939
|
+
"members[].role \u306F admin\u3001member\u3001viewer \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
940
|
+
)
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
const body = {
|
|
946
|
+
name: params.name.trim(),
|
|
947
|
+
ownerEmail: params.ownerEmail.trim()
|
|
948
|
+
};
|
|
949
|
+
if (params.billingEmail !== void 0) body.billingEmail = params.billingEmail.trim();
|
|
950
|
+
if (params.members !== void 0) {
|
|
951
|
+
body.members = params.members.map((member) => ({
|
|
952
|
+
email: member.email.trim(),
|
|
953
|
+
role: member.role
|
|
954
|
+
}));
|
|
955
|
+
}
|
|
956
|
+
if (params.dryRun !== void 0) body.dryRun = params.dryRun;
|
|
957
|
+
return fetchWithAuth(ORGANIZATION_PROVISION_ENDPOINT, {
|
|
958
|
+
method: "POST",
|
|
959
|
+
body: JSON.stringify(body)
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
return { provisionUser, provisionOrganization };
|
|
963
|
+
}
|
|
964
|
+
|
|
878
965
|
// src/client/seat-methods.ts
|
|
879
966
|
function seatsEndpoint(subscriptionId) {
|
|
880
967
|
return `/api/v1/subscriptions/ext/${encodeURIComponent(subscriptionId)}/seats/assignments`;
|
|
@@ -1119,7 +1206,7 @@ function createNonContractMethods(deps) {
|
|
|
1119
1206
|
}
|
|
1120
1207
|
|
|
1121
1208
|
// src/client/version-check.ts
|
|
1122
|
-
var SDK_VERSION = "5.
|
|
1209
|
+
var SDK_VERSION = "5.19.0";
|
|
1123
1210
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1124
1211
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1125
1212
|
function sdkHeaders() {
|
|
@@ -3130,6 +3217,11 @@ function createFFIDClient(config) {
|
|
|
3130
3217
|
createError,
|
|
3131
3218
|
serviceCode: config.serviceCode
|
|
3132
3219
|
});
|
|
3220
|
+
const { provisionUser, provisionOrganization } = createProvisioningMethods({
|
|
3221
|
+
fetchWithAuth,
|
|
3222
|
+
createError,
|
|
3223
|
+
authMode
|
|
3224
|
+
});
|
|
3133
3225
|
const { getProfile, updateProfile } = createProfileMethods({
|
|
3134
3226
|
fetchWithAuth,
|
|
3135
3227
|
createError
|
|
@@ -3225,6 +3317,8 @@ function createFFIDClient(config) {
|
|
|
3225
3317
|
addMember,
|
|
3226
3318
|
updateMemberRole,
|
|
3227
3319
|
removeMember,
|
|
3320
|
+
provisionUser,
|
|
3321
|
+
provisionOrganization,
|
|
3228
3322
|
getProfile,
|
|
3229
3323
|
updateProfile,
|
|
3230
3324
|
// Non-contract ext API coverage (#3783)
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkTW2FXASO_cjs = require('../chunk-TW2FXASO.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 chunkTW2FXASO_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkTW2FXASO_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkTW2FXASO_cjs.FFIDInquiryForm; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkTW2FXASO_cjs.FFIDLoginButton; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkTW2FXASO_cjs.FFIDOrganizationSwitcher; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkTW2FXASO_cjs.FFIDSubscriptionBadge; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunkTW2FXASO_cjs.FFIDUserMenu; }
|
|
34
34
|
});
|
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-D3PZ6SZB.js';
|
|
@@ -683,6 +683,217 @@ interface FFIDRemoveMemberResponse {
|
|
|
683
683
|
message: string;
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
+
/**
|
|
687
|
+
* Provisioning types (ext API) — service-key-authenticated, idempotent user /
|
|
688
|
+
* organization provisioning for external batch migration (#3790 / #4127).
|
|
689
|
+
*
|
|
690
|
+
* Mirrors the server contract of `POST /api/v1/ext/users/provision` and
|
|
691
|
+
* `POST /api/v1/ext/organizations/provision`. Responses are modelled as
|
|
692
|
+
* discriminated unions on `dryRun` so consumers narrow with `if (res.dryRun)`
|
|
693
|
+
* and the compiler enforces which fields are present on each branch
|
|
694
|
+
* (`wouldCreate` on dry-run, `created` on a real call).
|
|
695
|
+
*/
|
|
696
|
+
|
|
697
|
+
/** Optional business-profile fields applied to a freshly provisioned user. */
|
|
698
|
+
interface FFIDProvisionUserProfileInput {
|
|
699
|
+
/** Display name (1–255 chars). */
|
|
700
|
+
displayName?: string;
|
|
701
|
+
/** Company name (≤255 chars). */
|
|
702
|
+
companyName?: string;
|
|
703
|
+
/** Department (≤255 chars). */
|
|
704
|
+
department?: string;
|
|
705
|
+
/** Job title (≤255 chars). */
|
|
706
|
+
jobTitle?: string;
|
|
707
|
+
/** Phone number (≤30 chars). */
|
|
708
|
+
phone?: string;
|
|
709
|
+
}
|
|
710
|
+
/** Parameters for `provisionUser`. */
|
|
711
|
+
interface FFIDProvisionUserParams {
|
|
712
|
+
/**
|
|
713
|
+
* Email of the user to provision. Normalized (trim + lowercase) server-side
|
|
714
|
+
* before the idempotency lookup, so re-runs with different casing resolve to
|
|
715
|
+
* the same user.
|
|
716
|
+
*/
|
|
717
|
+
email: string;
|
|
718
|
+
/** Optional business profile applied only when a new user is created. */
|
|
719
|
+
profile?: FFIDProvisionUserProfileInput;
|
|
720
|
+
/**
|
|
721
|
+
* When `true`, the server performs no writes and returns a
|
|
722
|
+
* {@link FFIDProvisionUserDryRun} describing what a real call would do.
|
|
723
|
+
* @default false
|
|
724
|
+
*/
|
|
725
|
+
dryRun?: boolean;
|
|
726
|
+
}
|
|
727
|
+
/** Minimal identity returned for a provisioned / resolved user. */
|
|
728
|
+
interface FFIDProvisionedUser {
|
|
729
|
+
/** User ID (UUID). */
|
|
730
|
+
id: string;
|
|
731
|
+
/** Email address (normalized). */
|
|
732
|
+
email: string;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Real (non-dry-run) user provisioning outcome.
|
|
736
|
+
*
|
|
737
|
+
* Idempotent: an existing email resolves to `created: false` (HTTP 200) instead
|
|
738
|
+
* of creating a duplicate; a new email yields `created: true` (HTTP 201) for a
|
|
739
|
+
* passwordless, email-confirmed user.
|
|
740
|
+
*/
|
|
741
|
+
interface FFIDProvisionUserOutcome {
|
|
742
|
+
/** Discriminant — absent/`false` for a real call. */
|
|
743
|
+
dryRun?: false;
|
|
744
|
+
/**
|
|
745
|
+
* `true` → a new passwordless, email-confirmed user was created (HTTP 201).
|
|
746
|
+
* `false` → a user with this email already existed; idempotent no-op (HTTP 200).
|
|
747
|
+
*/
|
|
748
|
+
created: boolean;
|
|
749
|
+
user: FFIDProvisionedUser;
|
|
750
|
+
/**
|
|
751
|
+
* Present only when a new user was created **and** a `profile` was supplied.
|
|
752
|
+
* `false` means the user row was created but the authoritative profile write
|
|
753
|
+
* did not complete — some profile fields may not be fully applied, so
|
|
754
|
+
* re-issue the profile to be sure. Absent on the idempotent-existing branch
|
|
755
|
+
* and when no profile was requested.
|
|
756
|
+
*/
|
|
757
|
+
profileWritten?: boolean;
|
|
758
|
+
}
|
|
759
|
+
/** Dry-run user provisioning outcome — no writes performed. */
|
|
760
|
+
interface FFIDProvisionUserDryRun {
|
|
761
|
+
/** Discriminant — always `true` for a dry-run. */
|
|
762
|
+
dryRun: true;
|
|
763
|
+
/** Whether a real call would create a new user. */
|
|
764
|
+
wouldCreate: boolean;
|
|
765
|
+
/** `id` is present only when the user already exists. */
|
|
766
|
+
user: {
|
|
767
|
+
id?: string;
|
|
768
|
+
email: string;
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Response from `provisionUser`. Narrow with the truthiness of `dryRun`:
|
|
773
|
+
*
|
|
774
|
+
* ```ts
|
|
775
|
+
* if (res.dryRun) {
|
|
776
|
+
* // FFIDProvisionUserDryRun — inspect res.wouldCreate
|
|
777
|
+
* } else {
|
|
778
|
+
* // FFIDProvisionUserOutcome — inspect res.created
|
|
779
|
+
* }
|
|
780
|
+
* ```
|
|
781
|
+
*
|
|
782
|
+
* A real (non-dry-run) response omits `dryRun` on the wire (it is `undefined`,
|
|
783
|
+
* not `false`), so narrow with `if (res.dryRun)` — do **not** use
|
|
784
|
+
* `res.dryRun === false` or `switch (res.dryRun)`, which would miss every real
|
|
785
|
+
* response. This mirrors how `FFIDApiResponse` is narrowed on `data` / `error`.
|
|
786
|
+
*/
|
|
787
|
+
type FFIDProvisionUserResponse = FFIDProvisionUserOutcome | FFIDProvisionUserDryRun;
|
|
788
|
+
/** A member to add to the provisioned organization. */
|
|
789
|
+
interface FFIDProvisionOrganizationMemberInput {
|
|
790
|
+
email: string;
|
|
791
|
+
/** `owner` is intentionally excluded — the owner is set via `ownerEmail`. */
|
|
792
|
+
role: FFIDAssignableMemberRole;
|
|
793
|
+
}
|
|
794
|
+
/** Parameters for `provisionOrganization`. */
|
|
795
|
+
interface FFIDProvisionOrganizationParams {
|
|
796
|
+
/** Organization display name (1–255 chars). */
|
|
797
|
+
name: string;
|
|
798
|
+
/**
|
|
799
|
+
* Email of the organization owner. The owner **must** already be an FFID user
|
|
800
|
+
* — provision them via `provisionUser` first, otherwise the call returns an
|
|
801
|
+
* `OWNER_NOT_FOUND` error (HTTP 422).
|
|
802
|
+
*/
|
|
803
|
+
ownerEmail: string;
|
|
804
|
+
/** Optional billing contact email. */
|
|
805
|
+
billingEmail?: string;
|
|
806
|
+
/** Members to add idempotently (≤100 per request; validated client-side). */
|
|
807
|
+
members?: FFIDProvisionOrganizationMemberInput[];
|
|
808
|
+
/**
|
|
809
|
+
* When `true`, the server performs no writes and returns a
|
|
810
|
+
* {@link FFIDProvisionOrganizationDryRun} describing what a real call would do.
|
|
811
|
+
* @default false
|
|
812
|
+
*/
|
|
813
|
+
dryRun?: boolean;
|
|
814
|
+
}
|
|
815
|
+
/** Minimal organization shape returned by the org provisioning helper. */
|
|
816
|
+
interface FFIDProvisionedOrganization {
|
|
817
|
+
/** Organization ID (UUID). */
|
|
818
|
+
id: string;
|
|
819
|
+
/** Organization display name. */
|
|
820
|
+
name: string;
|
|
821
|
+
/** URL-safe slug. */
|
|
822
|
+
slug: string;
|
|
823
|
+
}
|
|
824
|
+
/** Per-member outcome status of a real (non-dry-run) organization provision. */
|
|
825
|
+
type FFIDProvisionMemberStatus = 'added' | 'already_member' | 'user_not_found';
|
|
826
|
+
/** Per-member outcome status of a dry-run organization provision. */
|
|
827
|
+
type FFIDProvisionMemberPlanStatus = 'would_add' | 'already_member' | 'user_not_found';
|
|
828
|
+
/** Per-member outcome of a real (non-dry-run) organization provision. */
|
|
829
|
+
interface FFIDProvisionMemberResult {
|
|
830
|
+
email: string;
|
|
831
|
+
role: FFIDAssignableMemberRole;
|
|
832
|
+
/**
|
|
833
|
+
* - `added` — membership was inserted.
|
|
834
|
+
* - `already_member` — user was already a member (idempotent no-op).
|
|
835
|
+
* - `user_not_found` — no FFID user exists for this email (skipped).
|
|
836
|
+
*/
|
|
837
|
+
status: FFIDProvisionMemberStatus;
|
|
838
|
+
}
|
|
839
|
+
/** Per-member plan of a dry-run organization provision. */
|
|
840
|
+
interface FFIDProvisionMemberPlan {
|
|
841
|
+
email: string;
|
|
842
|
+
role: FFIDAssignableMemberRole;
|
|
843
|
+
/**
|
|
844
|
+
* - `would_add` — user exists and is not yet a member.
|
|
845
|
+
* - `already_member` — user is already a member of the existing org.
|
|
846
|
+
* - `user_not_found` — no FFID user exists for this email.
|
|
847
|
+
*/
|
|
848
|
+
status: FFIDProvisionMemberPlanStatus;
|
|
849
|
+
}
|
|
850
|
+
/** Real (non-dry-run) organization provisioning outcome. */
|
|
851
|
+
interface FFIDProvisionOrganizationOutcome {
|
|
852
|
+
/** Discriminant — absent/`false` for a real call. */
|
|
853
|
+
dryRun?: false;
|
|
854
|
+
/**
|
|
855
|
+
* `true` → a brand-new organization was created (HTTP 201).
|
|
856
|
+
* `false` → the owner already owned an org with this name; idempotent (HTTP 200).
|
|
857
|
+
*/
|
|
858
|
+
created: boolean;
|
|
859
|
+
organization: FFIDProvisionedOrganization;
|
|
860
|
+
/** Per-member results (added / already_member / user_not_found). */
|
|
861
|
+
members: FFIDProvisionMemberResult[];
|
|
862
|
+
}
|
|
863
|
+
/** Dry-run organization provisioning outcome — no writes performed. */
|
|
864
|
+
interface FFIDProvisionOrganizationDryRun {
|
|
865
|
+
/** Discriminant — always `true` for a dry-run. */
|
|
866
|
+
dryRun: true;
|
|
867
|
+
/**
|
|
868
|
+
* Whether a real call would create a new organization. Coupled to
|
|
869
|
+
* `organization`: `wouldCreate === (organization === null)` — the server
|
|
870
|
+
* returns `organization: null` exactly when it would create a new org.
|
|
871
|
+
*/
|
|
872
|
+
wouldCreate: boolean;
|
|
873
|
+
/** `null` when the org does not exist yet (would be created) — see `wouldCreate`. */
|
|
874
|
+
organization: FFIDProvisionedOrganization | null;
|
|
875
|
+
/** Per-member plans (would_add / already_member / user_not_found). */
|
|
876
|
+
members: FFIDProvisionMemberPlan[];
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Response from `provisionOrganization`. Narrow on `dryRun`:
|
|
880
|
+
*
|
|
881
|
+
* ```ts
|
|
882
|
+
* if (res.dryRun) {
|
|
883
|
+
* // FFIDProvisionOrganizationDryRun — inspect res.wouldCreate / res.organization (nullable)
|
|
884
|
+
* } else {
|
|
885
|
+
* // FFIDProvisionOrganizationOutcome — inspect res.created / res.members
|
|
886
|
+
* }
|
|
887
|
+
* ```
|
|
888
|
+
*
|
|
889
|
+
* As with `FFIDProvisionUserResponse`, a real response omits `dryRun` on the
|
|
890
|
+
* wire, so narrow with `if (res.dryRun)` — not `res.dryRun === false`.
|
|
891
|
+
*
|
|
892
|
+
* When `ownerEmail` has no FFID user, the call resolves to
|
|
893
|
+
* `{ error: { code: 'OWNER_NOT_FOUND' } }` (HTTP 422) rather than a data branch.
|
|
894
|
+
*/
|
|
895
|
+
type FFIDProvisionOrganizationResponse = FFIDProvisionOrganizationOutcome | FFIDProvisionOrganizationDryRun;
|
|
896
|
+
|
|
686
897
|
/**
|
|
687
898
|
* Contract resource types (#3787 Phase A)
|
|
688
899
|
*
|
|
@@ -1732,6 +1943,8 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
1732
1943
|
organizationId: string;
|
|
1733
1944
|
userId: string;
|
|
1734
1945
|
}) => Promise<FFIDApiResponse<FFIDRemoveMemberResponse>>;
|
|
1946
|
+
provisionUser: (params: FFIDProvisionUserParams) => Promise<FFIDApiResponse<FFIDProvisionUserResponse>>;
|
|
1947
|
+
provisionOrganization: (params: FFIDProvisionOrganizationParams) => Promise<FFIDApiResponse<FFIDProvisionOrganizationResponse>>;
|
|
1735
1948
|
getProfile: (options?: FFIDProfileCallOptions) => Promise<FFIDApiResponse<FFIDUserProfile>>;
|
|
1736
1949
|
updateProfile: (data: FFIDUpdateUserProfileRequest, options?: FFIDProfileCallOptions) => Promise<FFIDApiResponse<FFIDUserProfile>>;
|
|
1737
1950
|
getLoginHistory: (params?: FFIDGetLoginHistoryParams) => Promise<FFIDApiResponse<FFIDLoginHistoryResponse>>;
|
|
@@ -1815,4 +2028,4 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
1815
2028
|
/** Type of the FFID client */
|
|
1816
2029
|
type FFIDClient = ReturnType<typeof createFFIDClient>;
|
|
1817
2030
|
|
|
1818
|
-
export { type
|
|
2031
|
+
export { type FFIDProvisionOrganizationDryRun as A, type FFIDProvisionOrganizationMemberInput as B, type FFIDProvisionOrganizationOutcome as C, type FFIDProvisionOrganizationParams as D, type FFIDProvisionOrganizationResponse as E, type FFIDLogger as F, type FFIDProvisionUserDryRun as G, type FFIDProvisionUserOutcome as H, type FFIDProvisionUserParams as I, type FFIDProvisionUserProfileInput as J, type FFIDProvisionUserResponse as K, type FFIDProvisionedOrganization as L, type FFIDProvisionedUser as M, type FFIDRemoveMemberResponse as N, type FFIDResetSessionResponse as O, type FFIDSubscription as P, type FFIDUpdateMemberRoleResponse as Q, type FFIDUpdateUserProfileRequest as R, type FFIDUser as S, type FFIDUserProfile as T, type TokenData as U, type TokenStore as V, createFFIDClient as W, createTokenStore as X, type FFIDError as a, type FFIDCacheAdapter as b, type FFIDVerifyAccessTokenOptions as c, type FFIDApiResponse as d, type FFIDOAuthUserInfo as e, type FFIDAddMemberParams as f, type FFIDAddMemberRequest as g, type FFIDAddMemberResponse as h, type FFIDAssignableMemberRole as i, type FFIDCacheConfig as j, type FFIDClient as k, type FFIDConfig as l, type FFIDListMembersResponse as m, type FFIDMemberRole as n, type FFIDOrganization as o, type FFIDOrganizationMember as p, type FFIDOtpSendResponse as q, type FFIDOtpVerifyResponse as r, type FFIDPasswordResetConfirmResponse as s, type FFIDPasswordResetResponse as t, type FFIDPasswordResetVerifyResponse as u, type FFIDProfileCallOptions as v, type FFIDProvisionMemberPlan as w, type FFIDProvisionMemberPlanStatus as x, type FFIDProvisionMemberResult as y, type FFIDProvisionMemberStatus as z };
|