@feelflow/ffid-sdk 7.0.0 → 7.2.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 +47 -0
- package/dist/{chunk-32VOLLNV.js → chunk-E2AJAVX6.js} +352 -64
- package/dist/{chunk-BI6UM2EJ.cjs → chunk-SOZ2B2ZL.cjs} +357 -63
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-C8XV7lUt.d.cts → ffid-client-BFgoVPOZ.d.cts} +161 -1
- package/dist/{ffid-client-CpVixUM3.d.ts → ffid-client-QNEFA3mv.d.ts} +161 -1
- package/dist/index.cjs +82 -58
- package/dist/index.d.cts +161 -1
- package/dist/index.d.ts +161 -1
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +357 -63
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +352 -64
- 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
|
@@ -397,6 +397,53 @@ await ffid.updateMemberRole({
|
|
|
397
397
|
- `role` は `admin` / `member` / `viewer` のみ指定可能です。`owner` は追加・昇格 API では扱いません。
|
|
398
398
|
- agency client と同じ呼び味が必要な場合は `ffid.addMember(organizationId, { email, role })` も使えます。
|
|
399
399
|
|
|
400
|
+
### Organization profile / public logo wall
|
|
401
|
+
|
|
402
|
+
hub 等の外部サービスが企業プロフィールを登録・照会し、FeelFlow 全サービス共通のロゴウォールを表示するためのメソッド(#5485 / #5547)。
|
|
403
|
+
|
|
404
|
+
- **`getOrganizationProfile` / `upsertOrganizationProfile` / `uploadOrganizationLogo`** は **`authMode: 'service-key'` 専用**(scope: `organization:read` / `organization:write`)。`token` / `cookie` モードで呼ぶとサーバーへ往復せず `VALIDATION_ERROR`。
|
|
405
|
+
- **`getPublicLogoWall`** は認証不要。service-key を送らない。エンドポイントは `GET /api/v1/organizations/logo-wall`(公開 API なので SDK を使わず直接 GET してもよいが、型付きエラーが欲しければ SDK 経由を推奨)。
|
|
406
|
+
- `upsert` の `listingConsent.consented: true` では `consentVersion` と `consentedByUserId` が必須。同意操作者が対象 org の active メンバーでないとサーバーが `CONSENTED_BY_NOT_MEMBER` を返す。
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
import {
|
|
410
|
+
createFFIDClient,
|
|
411
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES,
|
|
412
|
+
} from '@feelflow/ffid-sdk/server'
|
|
413
|
+
|
|
414
|
+
const ffid = createFFIDClient({
|
|
415
|
+
serviceCode: 'feel-agent',
|
|
416
|
+
scope: '',
|
|
417
|
+
authMode: 'service-key',
|
|
418
|
+
serviceApiKey: process.env.FFID_SERVICE_API_KEY!,
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
const current = await ffid.getOrganizationProfile(organizationId)
|
|
422
|
+
if (current.error) throw new Error(current.error.message)
|
|
423
|
+
|
|
424
|
+
const upsert = await ffid.upsertOrganizationProfile(organizationId, {
|
|
425
|
+
displayName: '株式会社サンプル',
|
|
426
|
+
industry: 'it-software',
|
|
427
|
+
companySize: '11-50',
|
|
428
|
+
websiteUrl: 'https://example.co.jp',
|
|
429
|
+
listingConsent: {
|
|
430
|
+
consented: true,
|
|
431
|
+
consentVersion: 'v1.0',
|
|
432
|
+
consentedByUserId: userId,
|
|
433
|
+
},
|
|
434
|
+
})
|
|
435
|
+
if (upsert.error?.code === FFID_ORGANIZATION_PROFILE_ERROR_CODES.CONSENTED_BY_NOT_MEMBER) {
|
|
436
|
+
throw new Error(upsert.error.message)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
await ffid.uploadOrganizationLogo(organizationId, logoFile)
|
|
440
|
+
|
|
441
|
+
const wall = await ffid.getPublicLogoWall()
|
|
442
|
+
// wall.data.entries: { displayName, logoUrl, websiteUrl }[]
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
位置引数と params オブジェクトの両方を受け付ける(`addMember` と同じ)。
|
|
446
|
+
|
|
400
447
|
### Provisioning(users / organizations)
|
|
401
448
|
|
|
402
449
|
外部サービスからの一括移行向けに、**service-key 認証**でユーザー・組織を冪等にプロビジョニングするメソッド。REST を直叩きせず `createFFIDClient` 経由で呼べる(SDK-first、#3790 / #4127)。
|
|
@@ -226,13 +226,18 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
|
|
|
226
226
|
];
|
|
227
227
|
}
|
|
228
228
|
var JWKS_ENDPOINT = "/.well-known/jwks.json";
|
|
229
|
-
var
|
|
229
|
+
var LEGACY_JWT_ISSUER = "https://id.feelflow.net";
|
|
230
230
|
var JWT_ALGORITHM = "ES256";
|
|
231
231
|
var JWT_CLOCK_TOLERANCE_SECONDS = 30;
|
|
232
|
+
function resolveAcceptedIssuers(baseUrl) {
|
|
233
|
+
const deployedOrigin = new URL(baseUrl).origin;
|
|
234
|
+
return deployedOrigin === LEGACY_JWT_ISSUER ? [LEGACY_JWT_ISSUER] : [deployedOrigin, LEGACY_JWT_ISSUER];
|
|
235
|
+
}
|
|
232
236
|
function createJwtVerifier(deps) {
|
|
233
237
|
const { baseUrl, serviceCode, logger, createError, errorCodes } = deps;
|
|
234
238
|
const jwksUrl = new URL(JWKS_ENDPOINT, baseUrl);
|
|
235
239
|
const jwks = createRemoteJWKSet(jwksUrl);
|
|
240
|
+
const acceptedIssuers = resolveAcceptedIssuers(baseUrl);
|
|
236
241
|
async function verifyJwt(accessToken) {
|
|
237
242
|
if (!accessToken || !accessToken.trim()) {
|
|
238
243
|
return {
|
|
@@ -245,7 +250,7 @@ function createJwtVerifier(deps) {
|
|
|
245
250
|
try {
|
|
246
251
|
const { payload } = await jwtVerify(accessToken, jwks, {
|
|
247
252
|
algorithms: [JWT_ALGORITHM],
|
|
248
|
-
issuer:
|
|
253
|
+
issuer: acceptedIssuers,
|
|
249
254
|
audience: serviceCode,
|
|
250
255
|
clockTolerance: JWT_CLOCK_TOLERANCE_SECONDS
|
|
251
256
|
});
|
|
@@ -1301,6 +1306,310 @@ function createMembersMethods(deps) {
|
|
|
1301
1306
|
return { listMembers, addMember, updateMemberRole, removeMember };
|
|
1302
1307
|
}
|
|
1303
1308
|
|
|
1309
|
+
// src/types/organization-profile.ts
|
|
1310
|
+
var FFID_INDUSTRY_CODES = [
|
|
1311
|
+
"agriculture",
|
|
1312
|
+
"construction",
|
|
1313
|
+
"manufacturing",
|
|
1314
|
+
"it-software",
|
|
1315
|
+
"telecom",
|
|
1316
|
+
"media",
|
|
1317
|
+
"retail",
|
|
1318
|
+
"wholesale",
|
|
1319
|
+
"finance-insurance",
|
|
1320
|
+
"real-estate",
|
|
1321
|
+
"transport-logistics",
|
|
1322
|
+
"hospitality-food",
|
|
1323
|
+
"healthcare",
|
|
1324
|
+
"education",
|
|
1325
|
+
"professional-services",
|
|
1326
|
+
"marketing-advertising",
|
|
1327
|
+
"energy-utilities",
|
|
1328
|
+
"public-sector",
|
|
1329
|
+
"nonprofit",
|
|
1330
|
+
"other"
|
|
1331
|
+
];
|
|
1332
|
+
var FFID_COMPANY_SIZE_CODES = [
|
|
1333
|
+
"1-10",
|
|
1334
|
+
"11-50",
|
|
1335
|
+
"51-200",
|
|
1336
|
+
"201-500",
|
|
1337
|
+
"501-1000",
|
|
1338
|
+
"1001+"
|
|
1339
|
+
];
|
|
1340
|
+
var BYTES_PER_KB = 1024;
|
|
1341
|
+
var KB_PER_MB = 1024;
|
|
1342
|
+
var FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB = 2;
|
|
1343
|
+
var FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB * KB_PER_MB * BYTES_PER_KB;
|
|
1344
|
+
var FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES = [
|
|
1345
|
+
"image/png",
|
|
1346
|
+
"image/jpeg",
|
|
1347
|
+
"image/webp"
|
|
1348
|
+
];
|
|
1349
|
+
var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
|
|
1350
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
1351
|
+
ORGANIZATION_NOT_FOUND: "ORGANIZATION_NOT_FOUND",
|
|
1352
|
+
CONSENTED_BY_NOT_MEMBER: "CONSENTED_BY_NOT_MEMBER",
|
|
1353
|
+
MISSING_FILE: "MISSING_FILE",
|
|
1354
|
+
INVALID_FILE_TYPE: "INVALID_FILE_TYPE",
|
|
1355
|
+
FILE_TOO_LARGE: "FILE_TOO_LARGE",
|
|
1356
|
+
INVALID_IMAGE: "INVALID_IMAGE",
|
|
1357
|
+
LOGO_UPLOAD_FAILED: "LOGO_UPLOAD_FAILED"
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
// src/client/version-check.ts
|
|
1361
|
+
var SDK_VERSION = "7.2.0";
|
|
1362
|
+
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1363
|
+
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1364
|
+
function sdkHeaders() {
|
|
1365
|
+
if (typeof window !== "undefined") return {};
|
|
1366
|
+
return {
|
|
1367
|
+
"User-Agent": SDK_USER_AGENT,
|
|
1368
|
+
[SDK_VERSION_HEADER]: SDK_VERSION
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
var LATEST_VERSION_HEADER = "X-FFID-SDK-Latest-Version";
|
|
1372
|
+
var SEMVER_PATTERN = /^\d+(\.\d+)*$/;
|
|
1373
|
+
var _versionWarningShown = false;
|
|
1374
|
+
function compareSemver(a, b) {
|
|
1375
|
+
const cleanA = a.replace(/^v/, "");
|
|
1376
|
+
const cleanB = b.replace(/^v/, "");
|
|
1377
|
+
if (!SEMVER_PATTERN.test(cleanA) || !SEMVER_PATTERN.test(cleanB)) return 0;
|
|
1378
|
+
const partsA = cleanA.split(".").map(Number);
|
|
1379
|
+
const partsB = cleanB.split(".").map(Number);
|
|
1380
|
+
const maxLen = Math.max(partsA.length, partsB.length);
|
|
1381
|
+
for (let i = 0; i < maxLen; i++) {
|
|
1382
|
+
const numA = partsA[i] ?? 0;
|
|
1383
|
+
const numB = partsB[i] ?? 0;
|
|
1384
|
+
if (numA < numB) return -1;
|
|
1385
|
+
if (numA > numB) return 1;
|
|
1386
|
+
}
|
|
1387
|
+
return 0;
|
|
1388
|
+
}
|
|
1389
|
+
function checkVersionHeader(response, logger) {
|
|
1390
|
+
if (_versionWarningShown) return;
|
|
1391
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
|
|
1392
|
+
if (!response.headers?.get) return;
|
|
1393
|
+
const latestVersion = response.headers.get(LATEST_VERSION_HEADER);
|
|
1394
|
+
if (!latestVersion) return;
|
|
1395
|
+
if (compareSemver(SDK_VERSION, latestVersion) < 0) {
|
|
1396
|
+
_versionWarningShown = true;
|
|
1397
|
+
logger.warn(
|
|
1398
|
+
`\u65B0\u3057\u3044\u30D0\u30FC\u30B8\u30E7\u30F3\u304C\u5229\u7528\u53EF\u80FD\u3067\u3059: v${latestVersion} (\u73FE\u5728: v${SDK_VERSION})
|
|
1399
|
+
npm install @feelflow/ffid-sdk@latest \u3067\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3067\u304D\u307E\u3059`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// src/client/organization-profile-methods.ts
|
|
1405
|
+
var EXT_PROFILE_ENDPOINT = "/api/v1/organizations/ext/profile";
|
|
1406
|
+
var EXT_PROFILE_LOGO_ENDPOINT = "/api/v1/organizations/ext/profile/logo";
|
|
1407
|
+
var LOGO_WALL_ENDPOINT = "/api/v1/organizations/logo-wall";
|
|
1408
|
+
var DEFAULT_LOGO_UPLOAD_FILENAME = "logo";
|
|
1409
|
+
function isBlank(value) {
|
|
1410
|
+
return !value || !value.trim();
|
|
1411
|
+
}
|
|
1412
|
+
function resolveOrganizationId(organizationIdOrParams) {
|
|
1413
|
+
return typeof organizationIdOrParams === "string" ? organizationIdOrParams : organizationIdOrParams.organizationId;
|
|
1414
|
+
}
|
|
1415
|
+
function resolveUpsertParams(organizationIdOrParams, payload) {
|
|
1416
|
+
if (typeof organizationIdOrParams === "string") {
|
|
1417
|
+
return { ...payload, organizationId: organizationIdOrParams };
|
|
1418
|
+
}
|
|
1419
|
+
return organizationIdOrParams;
|
|
1420
|
+
}
|
|
1421
|
+
function resolveUploadParams(organizationIdOrParams, file) {
|
|
1422
|
+
if (typeof organizationIdOrParams === "string") {
|
|
1423
|
+
return { organizationId: organizationIdOrParams, file };
|
|
1424
|
+
}
|
|
1425
|
+
return organizationIdOrParams;
|
|
1426
|
+
}
|
|
1427
|
+
function buildUpsertBody(params) {
|
|
1428
|
+
const { organizationId, ...body } = params;
|
|
1429
|
+
return body;
|
|
1430
|
+
}
|
|
1431
|
+
function profileQuery(organizationId) {
|
|
1432
|
+
return new URLSearchParams({ organizationId }).toString();
|
|
1433
|
+
}
|
|
1434
|
+
function logoUploadFilename(file) {
|
|
1435
|
+
if (typeof File !== "undefined" && file instanceof File && file.name) {
|
|
1436
|
+
return file.name;
|
|
1437
|
+
}
|
|
1438
|
+
return DEFAULT_LOGO_UPLOAD_FILENAME;
|
|
1439
|
+
}
|
|
1440
|
+
function listingConsentValidationError(listingConsent, createError) {
|
|
1441
|
+
if (!listingConsent || listingConsent.consented !== true) return null;
|
|
1442
|
+
if (isBlank(listingConsent.consentVersion) || isBlank(listingConsent.consentedByUserId)) {
|
|
1443
|
+
return createError(
|
|
1444
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES.VALIDATION_ERROR,
|
|
1445
|
+
"\u63B2\u8F09\u540C\u610F\u3092\u8A18\u9332\u3059\u308B\u5834\u5408\u306F consentVersion \u3068 consentedByUserId \u304C\u5FC5\u9808\u3067\u3059"
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
function resolveLogoFile(file, createError) {
|
|
1451
|
+
if (!file) {
|
|
1452
|
+
return {
|
|
1453
|
+
ok: false,
|
|
1454
|
+
error: createError(
|
|
1455
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES.MISSING_FILE,
|
|
1456
|
+
"file \u30D5\u30A3\u30FC\u30EB\u30C9\u306B\u30ED\u30B4\u753B\u50CF\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
1457
|
+
)
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
if (file.size > FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES) {
|
|
1461
|
+
return {
|
|
1462
|
+
ok: false,
|
|
1463
|
+
error: createError(
|
|
1464
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES.FILE_TOO_LARGE,
|
|
1465
|
+
`\u30ED\u30B4\u753B\u50CF\u306F${FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB}MB\u4EE5\u4E0B\u306B\u3057\u3066\u304F\u3060\u3055\u3044`
|
|
1466
|
+
)
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
if (file.type !== "" && !FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES.includes(file.type)) {
|
|
1470
|
+
return {
|
|
1471
|
+
ok: false,
|
|
1472
|
+
error: createError(
|
|
1473
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES.INVALID_FILE_TYPE,
|
|
1474
|
+
"\u30ED\u30B4\u753B\u50CF\u306F PNG / JPEG / WebP \u5F62\u5F0F\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
1475
|
+
)
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
return { ok: true, file };
|
|
1479
|
+
}
|
|
1480
|
+
function createOrganizationProfileMethods(deps) {
|
|
1481
|
+
const { fetchWithAuth, createError, authMode, baseUrl, logger, errorCodes } = deps;
|
|
1482
|
+
function serviceKeyModeError() {
|
|
1483
|
+
if (authMode === "service-key") return null;
|
|
1484
|
+
return createError(
|
|
1485
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES.VALIDATION_ERROR,
|
|
1486
|
+
"getOrganizationProfile / upsertOrganizationProfile / uploadOrganizationLogo \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"
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
function requireOrganizationId(organizationId) {
|
|
1490
|
+
if (isBlank(organizationId)) {
|
|
1491
|
+
return createError(
|
|
1492
|
+
FFID_ORGANIZATION_PROFILE_ERROR_CODES.VALIDATION_ERROR,
|
|
1493
|
+
"organizationId \u306F\u5FC5\u9808\u3067\u3059"
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
return null;
|
|
1497
|
+
}
|
|
1498
|
+
async function fetchPublic(endpoint, options = {}) {
|
|
1499
|
+
const url = `${baseUrl}${endpoint}`;
|
|
1500
|
+
logger.debug("Fetching (public):", url);
|
|
1501
|
+
let response;
|
|
1502
|
+
try {
|
|
1503
|
+
response = await fetch(url, {
|
|
1504
|
+
...options,
|
|
1505
|
+
credentials: "omit",
|
|
1506
|
+
headers: {
|
|
1507
|
+
...sdkHeaders(),
|
|
1508
|
+
...options.headers
|
|
1509
|
+
}
|
|
1510
|
+
});
|
|
1511
|
+
} catch (error) {
|
|
1512
|
+
logger.error("Network error:", error);
|
|
1513
|
+
return {
|
|
1514
|
+
error: {
|
|
1515
|
+
code: errorCodes.NETWORK_ERROR,
|
|
1516
|
+
message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
let parsed;
|
|
1521
|
+
try {
|
|
1522
|
+
parsed = await response.json();
|
|
1523
|
+
} catch (parseError) {
|
|
1524
|
+
logger.error("Parse error:", parseError, "Status:", response.status);
|
|
1525
|
+
return {
|
|
1526
|
+
error: {
|
|
1527
|
+
code: errorCodes.PARSE_ERROR,
|
|
1528
|
+
message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
|
|
1529
|
+
}
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1533
|
+
return {
|
|
1534
|
+
error: {
|
|
1535
|
+
code: errorCodes.PARSE_ERROR,
|
|
1536
|
+
message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
const raw = parsed;
|
|
1541
|
+
logger.debug("Response (public):", response.status, raw);
|
|
1542
|
+
checkVersionHeader(response, logger);
|
|
1543
|
+
if (!response.ok) {
|
|
1544
|
+
return {
|
|
1545
|
+
error: raw.error ?? {
|
|
1546
|
+
code: errorCodes.UNKNOWN_ERROR,
|
|
1547
|
+
message: "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
1548
|
+
}
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
if (raw.data === void 0) {
|
|
1552
|
+
return {
|
|
1553
|
+
error: {
|
|
1554
|
+
code: errorCodes.UNKNOWN_ERROR,
|
|
1555
|
+
message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
return { data: raw.data };
|
|
1560
|
+
}
|
|
1561
|
+
async function getOrganizationProfile(organizationIdOrParams) {
|
|
1562
|
+
const modeError = serviceKeyModeError();
|
|
1563
|
+
if (modeError) return { error: modeError };
|
|
1564
|
+
const organizationId = resolveOrganizationId(organizationIdOrParams);
|
|
1565
|
+
const idError = requireOrganizationId(organizationId);
|
|
1566
|
+
if (idError) return { error: idError };
|
|
1567
|
+
return fetchWithAuth(
|
|
1568
|
+
`${EXT_PROFILE_ENDPOINT}?${profileQuery(organizationId)}`
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
async function upsertOrganizationProfile(organizationIdOrParams, payload) {
|
|
1572
|
+
const modeError = serviceKeyModeError();
|
|
1573
|
+
if (modeError) return { error: modeError };
|
|
1574
|
+
const params = resolveUpsertParams(organizationIdOrParams, payload);
|
|
1575
|
+
const idError = requireOrganizationId(params.organizationId);
|
|
1576
|
+
if (idError) return { error: idError };
|
|
1577
|
+
const consentError = listingConsentValidationError(params.listingConsent, createError);
|
|
1578
|
+
if (consentError) return { error: consentError };
|
|
1579
|
+
return fetchWithAuth(
|
|
1580
|
+
`${EXT_PROFILE_ENDPOINT}?${profileQuery(params.organizationId)}`,
|
|
1581
|
+
{
|
|
1582
|
+
method: "PUT",
|
|
1583
|
+
body: JSON.stringify(buildUpsertBody(params))
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
async function uploadOrganizationLogo(organizationIdOrParams, file) {
|
|
1588
|
+
const modeError = serviceKeyModeError();
|
|
1589
|
+
if (modeError) return { error: modeError };
|
|
1590
|
+
const params = resolveUploadParams(organizationIdOrParams, file);
|
|
1591
|
+
const idError = requireOrganizationId(params.organizationId);
|
|
1592
|
+
if (idError) return { error: idError };
|
|
1593
|
+
const logoFile = resolveLogoFile(params.file, createError);
|
|
1594
|
+
if (!logoFile.ok) return { error: logoFile.error };
|
|
1595
|
+
const form = new FormData();
|
|
1596
|
+
form.append("file", logoFile.file, logoUploadFilename(logoFile.file));
|
|
1597
|
+
return fetchWithAuth(
|
|
1598
|
+
`${EXT_PROFILE_LOGO_ENDPOINT}?${profileQuery(params.organizationId)}`,
|
|
1599
|
+
{ method: "POST", body: form }
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
async function getPublicLogoWall() {
|
|
1603
|
+
return fetchPublic(LOGO_WALL_ENDPOINT);
|
|
1604
|
+
}
|
|
1605
|
+
return {
|
|
1606
|
+
getOrganizationProfile,
|
|
1607
|
+
upsertOrganizationProfile,
|
|
1608
|
+
uploadOrganizationLogo,
|
|
1609
|
+
getPublicLogoWall
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1304
1613
|
// src/client/provisioning-methods.ts
|
|
1305
1614
|
var USER_PROVISION_ENDPOINT = "/api/v1/ext/users/provision";
|
|
1306
1615
|
var USER_WELCOME_EMAIL_ENDPOINT = "/api/v1/ext/users/welcome-email";
|
|
@@ -1444,7 +1753,7 @@ function createSeatMethods(deps) {
|
|
|
1444
1753
|
}
|
|
1445
1754
|
|
|
1446
1755
|
// src/client/profile-methods.ts
|
|
1447
|
-
var
|
|
1756
|
+
var EXT_PROFILE_ENDPOINT2 = "/api/v1/users/ext/me";
|
|
1448
1757
|
function resolveAuthOverride(options, createError) {
|
|
1449
1758
|
if (!options || options.accessToken === void 0) {
|
|
1450
1759
|
return {};
|
|
@@ -1465,7 +1774,7 @@ function createProfileMethods(deps) {
|
|
|
1465
1774
|
async function getProfile(options) {
|
|
1466
1775
|
const { override, error } = resolveAuthOverride(options, createError);
|
|
1467
1776
|
if (error) return { error };
|
|
1468
|
-
return fetchWithAuth(
|
|
1777
|
+
return fetchWithAuth(EXT_PROFILE_ENDPOINT2, void 0, override);
|
|
1469
1778
|
}
|
|
1470
1779
|
async function updateProfile(data, options) {
|
|
1471
1780
|
if (data === null || typeof data !== "object" || Array.isArray(data)) {
|
|
@@ -1481,7 +1790,7 @@ function createProfileMethods(deps) {
|
|
|
1481
1790
|
const { override, error } = resolveAuthOverride(options, createError);
|
|
1482
1791
|
if (error) return { error };
|
|
1483
1792
|
return fetchWithAuth(
|
|
1484
|
-
|
|
1793
|
+
EXT_PROFILE_ENDPOINT2,
|
|
1485
1794
|
{
|
|
1486
1795
|
method: "PUT",
|
|
1487
1796
|
body: JSON.stringify(data)
|
|
@@ -1674,50 +1983,6 @@ function validateTokenResponse(tokenResponse) {
|
|
|
1674
1983
|
};
|
|
1675
1984
|
}
|
|
1676
1985
|
|
|
1677
|
-
// src/client/version-check.ts
|
|
1678
|
-
var SDK_VERSION = "7.0.0";
|
|
1679
|
-
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1680
|
-
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1681
|
-
function sdkHeaders() {
|
|
1682
|
-
if (typeof window !== "undefined") return {};
|
|
1683
|
-
return {
|
|
1684
|
-
"User-Agent": SDK_USER_AGENT,
|
|
1685
|
-
[SDK_VERSION_HEADER]: SDK_VERSION
|
|
1686
|
-
};
|
|
1687
|
-
}
|
|
1688
|
-
var LATEST_VERSION_HEADER = "X-FFID-SDK-Latest-Version";
|
|
1689
|
-
var SEMVER_PATTERN = /^\d+(\.\d+)*$/;
|
|
1690
|
-
var _versionWarningShown = false;
|
|
1691
|
-
function compareSemver(a, b) {
|
|
1692
|
-
const cleanA = a.replace(/^v/, "");
|
|
1693
|
-
const cleanB = b.replace(/^v/, "");
|
|
1694
|
-
if (!SEMVER_PATTERN.test(cleanA) || !SEMVER_PATTERN.test(cleanB)) return 0;
|
|
1695
|
-
const partsA = cleanA.split(".").map(Number);
|
|
1696
|
-
const partsB = cleanB.split(".").map(Number);
|
|
1697
|
-
const maxLen = Math.max(partsA.length, partsB.length);
|
|
1698
|
-
for (let i = 0; i < maxLen; i++) {
|
|
1699
|
-
const numA = partsA[i] ?? 0;
|
|
1700
|
-
const numB = partsB[i] ?? 0;
|
|
1701
|
-
if (numA < numB) return -1;
|
|
1702
|
-
if (numA > numB) return 1;
|
|
1703
|
-
}
|
|
1704
|
-
return 0;
|
|
1705
|
-
}
|
|
1706
|
-
function checkVersionHeader(response, logger) {
|
|
1707
|
-
if (_versionWarningShown) return;
|
|
1708
|
-
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
|
|
1709
|
-
if (!response.headers?.get) return;
|
|
1710
|
-
const latestVersion = response.headers.get(LATEST_VERSION_HEADER);
|
|
1711
|
-
if (!latestVersion) return;
|
|
1712
|
-
if (compareSemver(SDK_VERSION, latestVersion) < 0) {
|
|
1713
|
-
_versionWarningShown = true;
|
|
1714
|
-
logger.warn(
|
|
1715
|
-
`\u65B0\u3057\u3044\u30D0\u30FC\u30B8\u30E7\u30F3\u304C\u5229\u7528\u53EF\u80FD\u3067\u3059: v${latestVersion} (\u73FE\u5728: v${SDK_VERSION})
|
|
1716
|
-
npm install @feelflow/ffid-sdk@latest \u3067\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3067\u304D\u307E\u3059`
|
|
1717
|
-
);
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
1986
|
// src/client/oauth-token.ts
|
|
1722
1987
|
var OAUTH_TOKEN_ENDPOINT = "/api/v1/oauth/token";
|
|
1723
1988
|
var OAUTH_REVOKE_ENDPOINT = "/api/v1/oauth/revoke";
|
|
@@ -2633,7 +2898,7 @@ function normalizeRedirectUri(input) {
|
|
|
2633
2898
|
|
|
2634
2899
|
// src/client/password-reset.ts
|
|
2635
2900
|
var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
|
|
2636
|
-
function
|
|
2901
|
+
function isBlank2(value) {
|
|
2637
2902
|
return !value || !value.trim();
|
|
2638
2903
|
}
|
|
2639
2904
|
function createPasswordResetMethods(deps) {
|
|
@@ -2694,7 +2959,7 @@ function createPasswordResetMethods(deps) {
|
|
|
2694
2959
|
return { data: raw.data };
|
|
2695
2960
|
}
|
|
2696
2961
|
async function requestPasswordReset(email) {
|
|
2697
|
-
if (
|
|
2962
|
+
if (isBlank2(email)) {
|
|
2698
2963
|
return {
|
|
2699
2964
|
error: createError("VALIDATION_ERROR", "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059")
|
|
2700
2965
|
};
|
|
@@ -2708,7 +2973,7 @@ function createPasswordResetMethods(deps) {
|
|
|
2708
2973
|
);
|
|
2709
2974
|
}
|
|
2710
2975
|
async function verifyPasswordResetToken(accessToken) {
|
|
2711
|
-
if (
|
|
2976
|
+
if (isBlank2(accessToken)) {
|
|
2712
2977
|
return {
|
|
2713
2978
|
error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
2714
2979
|
};
|
|
@@ -2722,12 +2987,12 @@ function createPasswordResetMethods(deps) {
|
|
|
2722
2987
|
);
|
|
2723
2988
|
}
|
|
2724
2989
|
async function establishResetSession(accessToken, refreshToken) {
|
|
2725
|
-
if (
|
|
2990
|
+
if (isBlank2(accessToken)) {
|
|
2726
2991
|
return {
|
|
2727
2992
|
error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
2728
2993
|
};
|
|
2729
2994
|
}
|
|
2730
|
-
if (
|
|
2995
|
+
if (isBlank2(refreshToken)) {
|
|
2731
2996
|
return {
|
|
2732
2997
|
error: createError("VALIDATION_ERROR", "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
2733
2998
|
};
|
|
@@ -2741,7 +3006,7 @@ function createPasswordResetMethods(deps) {
|
|
|
2741
3006
|
);
|
|
2742
3007
|
}
|
|
2743
3008
|
async function confirmPasswordReset(password) {
|
|
2744
|
-
if (
|
|
3009
|
+
if (isBlank2(password)) {
|
|
2745
3010
|
return {
|
|
2746
3011
|
error: createError("VALIDATION_ERROR", "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5FC5\u9808\u3067\u3059")
|
|
2747
3012
|
};
|
|
@@ -2764,7 +3029,7 @@ function createPasswordResetMethods(deps) {
|
|
|
2764
3029
|
|
|
2765
3030
|
// src/client/otp.ts
|
|
2766
3031
|
var OTP_BASE = "/api/v1/auth/otp";
|
|
2767
|
-
function
|
|
3032
|
+
function isBlank3(value) {
|
|
2768
3033
|
return !value || !value.trim();
|
|
2769
3034
|
}
|
|
2770
3035
|
function createOtpMethods(deps) {
|
|
@@ -2825,7 +3090,7 @@ function createOtpMethods(deps) {
|
|
|
2825
3090
|
return { data: raw.data };
|
|
2826
3091
|
}
|
|
2827
3092
|
async function sendOtp(email, options) {
|
|
2828
|
-
if (
|
|
3093
|
+
if (isBlank3(email)) {
|
|
2829
3094
|
return {
|
|
2830
3095
|
error: createError("VALIDATION_ERROR", "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059")
|
|
2831
3096
|
};
|
|
@@ -2842,12 +3107,12 @@ function createOtpMethods(deps) {
|
|
|
2842
3107
|
);
|
|
2843
3108
|
}
|
|
2844
3109
|
async function verifyOtp(params) {
|
|
2845
|
-
if (
|
|
3110
|
+
if (isBlank3(params.accessToken)) {
|
|
2846
3111
|
return {
|
|
2847
3112
|
error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
2848
3113
|
};
|
|
2849
3114
|
}
|
|
2850
|
-
if (
|
|
3115
|
+
if (isBlank3(params.refreshToken)) {
|
|
2851
3116
|
return {
|
|
2852
3117
|
error: createError("VALIDATION_ERROR", "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
2853
3118
|
};
|
|
@@ -3413,6 +3678,12 @@ function resolveRedirectUri(raw, logger) {
|
|
|
3413
3678
|
return raw;
|
|
3414
3679
|
}
|
|
3415
3680
|
}
|
|
3681
|
+
function jsonContentTypeHeader(body) {
|
|
3682
|
+
if (typeof FormData !== "undefined" && body instanceof FormData) {
|
|
3683
|
+
return {};
|
|
3684
|
+
}
|
|
3685
|
+
return { "Content-Type": "application/json" };
|
|
3686
|
+
}
|
|
3416
3687
|
function createFFIDClient(config) {
|
|
3417
3688
|
if (!config.serviceCode || !config.serviceCode.trim()) {
|
|
3418
3689
|
throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
|
|
@@ -3465,7 +3736,7 @@ function createFFIDClient(config) {
|
|
|
3465
3736
|
...options,
|
|
3466
3737
|
credentials: "omit",
|
|
3467
3738
|
headers: {
|
|
3468
|
-
|
|
3739
|
+
...jsonContentTypeHeader(options.body),
|
|
3469
3740
|
...sdkHeaders(),
|
|
3470
3741
|
...options.headers,
|
|
3471
3742
|
Authorization: `Bearer ${authOverride.accessToken}`
|
|
@@ -3477,7 +3748,7 @@ function createFFIDClient(config) {
|
|
|
3477
3748
|
...options,
|
|
3478
3749
|
credentials: "omit",
|
|
3479
3750
|
headers: {
|
|
3480
|
-
|
|
3751
|
+
...jsonContentTypeHeader(options.body),
|
|
3481
3752
|
...sdkHeaders(),
|
|
3482
3753
|
"X-Service-Api-Key": serviceApiKey,
|
|
3483
3754
|
...options.headers
|
|
@@ -3487,7 +3758,7 @@ function createFFIDClient(config) {
|
|
|
3487
3758
|
if (authMode === "token") {
|
|
3488
3759
|
const tokens = tokenStore.getTokens();
|
|
3489
3760
|
const headers = {
|
|
3490
|
-
|
|
3761
|
+
...jsonContentTypeHeader(options.body),
|
|
3491
3762
|
...sdkHeaders(),
|
|
3492
3763
|
...options.headers
|
|
3493
3764
|
};
|
|
@@ -3504,7 +3775,7 @@ function createFFIDClient(config) {
|
|
|
3504
3775
|
...options,
|
|
3505
3776
|
credentials: "include",
|
|
3506
3777
|
headers: {
|
|
3507
|
-
|
|
3778
|
+
...jsonContentTypeHeader(options.body),
|
|
3508
3779
|
...sdkHeaders(),
|
|
3509
3780
|
...options.headers
|
|
3510
3781
|
}
|
|
@@ -3721,6 +3992,19 @@ function createFFIDClient(config) {
|
|
|
3721
3992
|
createError,
|
|
3722
3993
|
serviceCode: config.serviceCode
|
|
3723
3994
|
});
|
|
3995
|
+
const {
|
|
3996
|
+
getOrganizationProfile,
|
|
3997
|
+
upsertOrganizationProfile,
|
|
3998
|
+
uploadOrganizationLogo,
|
|
3999
|
+
getPublicLogoWall
|
|
4000
|
+
} = createOrganizationProfileMethods({
|
|
4001
|
+
fetchWithAuth,
|
|
4002
|
+
createError,
|
|
4003
|
+
authMode,
|
|
4004
|
+
baseUrl,
|
|
4005
|
+
logger,
|
|
4006
|
+
errorCodes: FFID_ERROR_CODES
|
|
4007
|
+
});
|
|
3724
4008
|
const { provisionUser, sendProvisionWelcomeEmail, provisionOrganization } = createProvisioningMethods({
|
|
3725
4009
|
fetchWithAuth,
|
|
3726
4010
|
createError,
|
|
@@ -3821,6 +4105,10 @@ function createFFIDClient(config) {
|
|
|
3821
4105
|
addMember,
|
|
3822
4106
|
updateMemberRole,
|
|
3823
4107
|
removeMember,
|
|
4108
|
+
getOrganizationProfile,
|
|
4109
|
+
upsertOrganizationProfile,
|
|
4110
|
+
uploadOrganizationLogo,
|
|
4111
|
+
getPublicLogoWall,
|
|
3824
4112
|
provisionUser,
|
|
3825
4113
|
sendProvisionWelcomeEmail,
|
|
3826
4114
|
provisionOrganization,
|
|
@@ -6009,4 +6297,4 @@ function FFIDInquiryForm({
|
|
|
6009
6297
|
);
|
|
6010
6298
|
}
|
|
6011
6299
|
|
|
6012
|
-
export { ACCESS_GRANTING_EFFECTIVE_STATUSES, BLOCKING_EFFECTIVE_STATUSES, CATALOG_HASH_PATTERN, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDCatalogHashError, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_CATALOG_ENVIRONMENTS, FFID_CATALOG_PUBLICATION_STATUSES, FFID_ERROR_CODES, FFID_INQUIRY_ACQUISITION_SOURCES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, canonicalizeCatalogValue, cleanupStateStorage, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
|
|
6300
|
+
export { ACCESS_GRANTING_EFFECTIVE_STATUSES, BLOCKING_EFFECTIVE_STATUSES, CATALOG_HASH_PATTERN, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDCatalogHashError, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_CATALOG_ENVIRONMENTS, FFID_CATALOG_PUBLICATION_STATUSES, FFID_COMPANY_SIZE_CODES, FFID_ERROR_CODES, FFID_INDUSTRY_CODES, FFID_INQUIRY_ACQUISITION_SOURCES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB, FFID_ORGANIZATION_PROFILE_ERROR_CODES, canonicalizeCatalogValue, cleanupStateStorage, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
|