@feelflow/ffid-sdk 12.1.0 → 12.2.1
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 +29 -0
- package/dist/{chunk-3MYUVPLD.js → chunk-HPECOYG2.js} +75 -15
- package/dist/{chunk-62MINYOA.cjs → chunk-MSY5VF2K.cjs} +76 -14
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-aUNBn5SW.d.cts → ffid-client-DMwmK8mM.d.cts} +15 -2
- package/dist/{ffid-client-5dVFeHt8.d.ts → ffid-client-Dr2KVlIZ.d.ts} +15 -2
- package/dist/index.cjs +99 -97
- package/dist/index.d.cts +17 -4
- package/dist/index.d.ts +17 -4
- package/dist/index.js +3 -7
- package/dist/server/index.cjs +66 -9
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +66 -9
- 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
|
@@ -22,6 +22,35 @@ pnpm add @feelflow/ffid-sdk
|
|
|
22
22
|
|
|
23
23
|
## 統合ガイド
|
|
24
24
|
|
|
25
|
+
### ニュースレター登録・目的別停止(12.2.0)
|
|
26
|
+
|
|
27
|
+
登録はサーバー上の `service-key` クライアントで行います。Service API Key を
|
|
28
|
+
ブラウザへ渡さず、公開フォームのCAPTCHAと配信同意をBFFで検証してください。
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// 一つの登録操作に一つのUUID。応答が失われた再操作では同じキーを保持する。
|
|
32
|
+
const idempotencyKey = crypto.randomUUID()
|
|
33
|
+
const result = await client.newsletter.subscribe({
|
|
34
|
+
email: 'reader@example.com',
|
|
35
|
+
types: ['general'],
|
|
36
|
+
source: 'website-newsletter',
|
|
37
|
+
locale: 'ja',
|
|
38
|
+
}, { idempotencyKey })
|
|
39
|
+
|
|
40
|
+
// tokenはメール内の不透明な値。ログへ出さない。
|
|
41
|
+
await client.newsletter.unsubscribe({ token, type: 'general' })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`requiresConfirmation` は確認メール送信済み、`confirmationEmailPending` は未送信、
|
|
45
|
+
`requiresSignIn` は既存会員の設定案内です。後二つを「登録完了」にしないでください。
|
|
46
|
+
未送信フラグは自動再送の予約を意味しません。登録内容を変えるときと、確定した結果の
|
|
47
|
+
後で新しい登録を依頼するときは新しいキーを使います。SDKが自動再送することはありません。
|
|
48
|
+
独立ニュースレター側の処理中・結果不明なreceiptの回復は、運用上の確認が必要です。
|
|
49
|
+
配信停止の `type` を省略すると既存の全目的停止を維持します。
|
|
50
|
+
キー付き登録には、独立ownerへ転送する更新済みFFID互換APIが必要です。旧処理モードでは
|
|
51
|
+
書込み・メール送信前に拒否し、SDKは返却された `requestId` の一致を確認します。
|
|
52
|
+
互換APIの配備と独立化の切替を確認してから、BFFでキー付き登録を有効にしてください。
|
|
53
|
+
|
|
25
54
|
サービスを FFID Platform に統合する詳細なガイドは **[Integration Guide](./docs/INTEGRATION_GUIDE.md)** を参照してください。OAuth フロー、フロントエンド/バックエンド実装パターン、セキュリティチェックリスト、アンチパターン集を網羅しています。
|
|
26
55
|
|
|
27
56
|
### Cookie 同意管理基盤 (v5.0.0+)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createContext, useState, useRef, useEffect, useMemo, useCallback, useContext } from 'react';
|
|
2
2
|
import { createRemoteJWKSet, jwtVerify, errors } from 'jose';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
5
|
|
|
5
6
|
// src/constants.ts
|
|
@@ -1391,7 +1392,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
|
|
|
1391
1392
|
};
|
|
1392
1393
|
|
|
1393
1394
|
// src/client/version-check.ts
|
|
1394
|
-
var SDK_VERSION = "12.1
|
|
1395
|
+
var SDK_VERSION = "12.2.1";
|
|
1395
1396
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1396
1397
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1397
1398
|
function sdkHeaders() {
|
|
@@ -3478,24 +3479,45 @@ function createContractWizardMethods(deps) {
|
|
|
3478
3479
|
};
|
|
3479
3480
|
}
|
|
3480
3481
|
|
|
3482
|
+
// src/newsletter/types.ts
|
|
3483
|
+
var FFID_NEWSLETTER_TYPES = ["inquiry_followup", "general"];
|
|
3484
|
+
var FFID_NEWSLETTER_DISPATCH_MAX_RECIPIENTS = 1e3;
|
|
3485
|
+
|
|
3481
3486
|
// src/newsletter/ffid-newsletter-client.ts
|
|
3482
3487
|
var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
|
|
3483
3488
|
var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
|
|
3484
3489
|
var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
|
|
3485
3490
|
var DISPATCH_ENDPOINT = "/api/v1/newsletter/dispatch";
|
|
3491
|
+
var PUBLIC_TOKEN_TIMEOUT_MS = 3e4;
|
|
3492
|
+
var subscribeResponseSchema = z.object({
|
|
3493
|
+
ok: z.literal(true),
|
|
3494
|
+
requiresConfirmation: z.boolean(),
|
|
3495
|
+
requiresSignIn: z.boolean(),
|
|
3496
|
+
confirmationEmailPending: z.boolean(),
|
|
3497
|
+
requestId: z.uuid().optional()
|
|
3498
|
+
}).refine(
|
|
3499
|
+
(value) => [
|
|
3500
|
+
value.requiresConfirmation,
|
|
3501
|
+
value.requiresSignIn,
|
|
3502
|
+
value.confirmationEmailPending
|
|
3503
|
+
].filter(Boolean).length <= 1
|
|
3504
|
+
);
|
|
3486
3505
|
function trimOrEmpty(s) {
|
|
3487
3506
|
return typeof s === "string" ? s.trim() : "";
|
|
3488
3507
|
}
|
|
3489
3508
|
async function postPublic(url, init, opts) {
|
|
3490
3509
|
let response;
|
|
3491
3510
|
try {
|
|
3492
|
-
response = await fetch(url,
|
|
3493
|
-
|
|
3511
|
+
response = await fetch(url, {
|
|
3512
|
+
...init,
|
|
3513
|
+
credentials: "omit",
|
|
3514
|
+
redirect: "error",
|
|
3515
|
+
cache: "no-store",
|
|
3516
|
+
signal: AbortSignal.timeout(PUBLIC_TOKEN_TIMEOUT_MS)
|
|
3517
|
+
});
|
|
3518
|
+
} catch {
|
|
3494
3519
|
return {
|
|
3495
|
-
error: opts.createError(
|
|
3496
|
-
"NETWORK_ERROR",
|
|
3497
|
-
err instanceof Error ? err.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
3498
|
-
)
|
|
3520
|
+
error: opts.createError("NETWORK_ERROR", opts.fallbackMessage)
|
|
3499
3521
|
};
|
|
3500
3522
|
}
|
|
3501
3523
|
if (!response.ok) {
|
|
@@ -3522,7 +3544,7 @@ async function postPublic(url, init, opts) {
|
|
|
3522
3544
|
}
|
|
3523
3545
|
function createNewsletterMethods(deps) {
|
|
3524
3546
|
const { fetchWithAuth, baseUrl, createError } = deps;
|
|
3525
|
-
async function subscribe(params) {
|
|
3547
|
+
async function subscribe(params, options = {}) {
|
|
3526
3548
|
const email = trimOrEmpty(params.email);
|
|
3527
3549
|
const source = trimOrEmpty(params.source);
|
|
3528
3550
|
if (!email) {
|
|
@@ -3539,10 +3561,19 @@ function createNewsletterMethods(deps) {
|
|
|
3539
3561
|
)
|
|
3540
3562
|
};
|
|
3541
3563
|
}
|
|
3542
|
-
|
|
3564
|
+
if (options.idempotencyKey !== void 0 && !z.uuid().safeParse(options.idempotencyKey).success) {
|
|
3565
|
+
return {
|
|
3566
|
+
error: createError(
|
|
3567
|
+
"INVALID_IDEMPOTENCY_KEY",
|
|
3568
|
+
"idempotencyKey \u306B\u306F UUID \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
3569
|
+
)
|
|
3570
|
+
};
|
|
3571
|
+
}
|
|
3572
|
+
const response = await fetchWithAuth(
|
|
3543
3573
|
EXT_SUBSCRIBE_ENDPOINT2,
|
|
3544
3574
|
{
|
|
3545
3575
|
method: "POST",
|
|
3576
|
+
...options.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : {},
|
|
3546
3577
|
body: JSON.stringify({
|
|
3547
3578
|
email,
|
|
3548
3579
|
types: params.types,
|
|
@@ -3551,6 +3582,23 @@ function createNewsletterMethods(deps) {
|
|
|
3551
3582
|
})
|
|
3552
3583
|
}
|
|
3553
3584
|
);
|
|
3585
|
+
if (response.error) return response;
|
|
3586
|
+
const parsed = subscribeResponseSchema.safeParse(response.data);
|
|
3587
|
+
if (!parsed.success)
|
|
3588
|
+
return {
|
|
3589
|
+
error: createError(
|
|
3590
|
+
"PARSE_ERROR",
|
|
3591
|
+
"\u30CB\u30E5\u30FC\u30B9\u30EC\u30BF\u30FC\u767B\u9332\u306E\u5FDC\u7B54\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
3592
|
+
)
|
|
3593
|
+
};
|
|
3594
|
+
if (options.idempotencyKey && parsed.data.requestId !== options.idempotencyKey)
|
|
3595
|
+
return {
|
|
3596
|
+
error: createError(
|
|
3597
|
+
"PARSE_ERROR",
|
|
3598
|
+
"\u30CB\u30E5\u30FC\u30B9\u30EC\u30BF\u30FC\u767B\u9332\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u8B58\u5225\u5B50\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
3599
|
+
)
|
|
3600
|
+
};
|
|
3601
|
+
return { data: parsed.data };
|
|
3554
3602
|
}
|
|
3555
3603
|
async function confirm(params) {
|
|
3556
3604
|
const token = trimOrEmpty(params.token);
|
|
@@ -3578,6 +3626,16 @@ function createNewsletterMethods(deps) {
|
|
|
3578
3626
|
}
|
|
3579
3627
|
const url = new URL(`${baseUrl}${UNSUBSCRIBE_ENDPOINT}`);
|
|
3580
3628
|
url.searchParams.set("token", token);
|
|
3629
|
+
if (params.type !== void 0) {
|
|
3630
|
+
if (!FFID_NEWSLETTER_TYPES.includes(params.type))
|
|
3631
|
+
return {
|
|
3632
|
+
error: createError(
|
|
3633
|
+
"VALIDATION_ERROR",
|
|
3634
|
+
"\u30CB\u30E5\u30FC\u30B9\u30EC\u30BF\u30FC\u306E\u914D\u4FE1\u7A2E\u5225\u304C\u4E0D\u6B63\u3067\u3059"
|
|
3635
|
+
)
|
|
3636
|
+
};
|
|
3637
|
+
url.searchParams.set("type", params.type);
|
|
3638
|
+
}
|
|
3581
3639
|
return postPublic(
|
|
3582
3640
|
url.toString(),
|
|
3583
3641
|
{ method: "POST" },
|
|
@@ -5246,10 +5304,12 @@ function FFIDUserMenu({
|
|
|
5246
5304
|
}) {
|
|
5247
5305
|
const { user, currentOrganization, logout, isLoading, isAuthenticated } = useFFID();
|
|
5248
5306
|
const [isOpen, setIsOpen] = useState(false);
|
|
5249
|
-
const
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5307
|
+
const avatarUrl = user?.avatarUrl ?? null;
|
|
5308
|
+
const [avatarState, setAvatarState] = useState({ url: avatarUrl, failed: false });
|
|
5309
|
+
if (avatarState.url !== avatarUrl) {
|
|
5310
|
+
setAvatarState({ url: avatarUrl, failed: false });
|
|
5311
|
+
}
|
|
5312
|
+
const avatarError = avatarState.url === avatarUrl && avatarState.failed;
|
|
5253
5313
|
if (!isAuthenticated || !user) {
|
|
5254
5314
|
return null;
|
|
5255
5315
|
}
|
|
@@ -5292,7 +5352,7 @@ function FFIDUserMenu({
|
|
|
5292
5352
|
className: classNames.avatar,
|
|
5293
5353
|
src: user.avatarUrl,
|
|
5294
5354
|
alt: displayName,
|
|
5295
|
-
onError: () =>
|
|
5355
|
+
onError: () => setAvatarState({ url: avatarUrl, failed: true }),
|
|
5296
5356
|
style: { width: SIZE_AVATAR_MD, height: SIZE_AVATAR_MD, borderRadius: "50%" }
|
|
5297
5357
|
}
|
|
5298
5358
|
) : defaultAvatar;
|
|
@@ -6868,4 +6928,4 @@ function FFIDInquiryForm({
|
|
|
6868
6928
|
);
|
|
6869
6929
|
}
|
|
6870
6930
|
|
|
6871
|
-
export { ACCESS_GRANTING_EFFECTIVE_STATUSES, AGENCY_INVITE_COOKIE_MAX_AGE_SEC, AGENCY_INVITE_COOKIE_NAME, AGENCY_INVITE_TOKEN_PARAM, AGENCY_INVITE_TOKEN_REDACTION, 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_CREDITS_CONSUME_MAX_AMOUNT, FFID_CREDITS_CONSUME_MIN_AMOUNT, FFID_CREDITS_ERROR_CODES, FFID_CREDITS_FEATURE_PATTERN, FFID_CREDITS_HISTORY_DEFAULT_LIMIT, FFID_CREDITS_HISTORY_MAX_LIMIT, FFID_CREDITS_HISTORY_MIN_LIMIT, FFID_CREDITS_IDEMPOTENCY_KEY_PATTERN, FFID_CREDITS_LOW_THRESHOLD_PERCENT, FFID_CREDITS_METADATA_MAX_BYTES, FFID_CREDIT_GRANT_KINDS, FFID_CREDIT_HISTORY_TYPES, FFID_CREDIT_PACK_MAX_QUANTITY, FFID_CREDIT_PACK_MIN_QUANTITY, 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_OAUTH_DENIAL_REASONS, FFID_ORGANIZATION_PROFILE_ERROR_CODES, FFID_SUBSCRIPTION_ERROR_CODES, canonicalizeCatalogValue, captureAgencyInviteToken, cleanupStateStorage, clearAgencyInviteToken, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, getFFIDAuthorizationError, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, isFFIDOAuthDenialReason, normalizeRedirectUri, readAgencyInviteCookie, readAgencyInviteToken, redactAgencyInviteToken, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
|
|
6931
|
+
export { ACCESS_GRANTING_EFFECTIVE_STATUSES, AGENCY_INVITE_COOKIE_MAX_AGE_SEC, AGENCY_INVITE_COOKIE_NAME, AGENCY_INVITE_TOKEN_PARAM, AGENCY_INVITE_TOKEN_REDACTION, 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_CREDITS_CONSUME_MAX_AMOUNT, FFID_CREDITS_CONSUME_MIN_AMOUNT, FFID_CREDITS_ERROR_CODES, FFID_CREDITS_FEATURE_PATTERN, FFID_CREDITS_HISTORY_DEFAULT_LIMIT, FFID_CREDITS_HISTORY_MAX_LIMIT, FFID_CREDITS_HISTORY_MIN_LIMIT, FFID_CREDITS_IDEMPOTENCY_KEY_PATTERN, FFID_CREDITS_LOW_THRESHOLD_PERCENT, FFID_CREDITS_METADATA_MAX_BYTES, FFID_CREDIT_GRANT_KINDS, FFID_CREDIT_HISTORY_TYPES, FFID_CREDIT_PACK_MAX_QUANTITY, FFID_CREDIT_PACK_MIN_QUANTITY, 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_NEWSLETTER_DISPATCH_MAX_RECIPIENTS, FFID_NEWSLETTER_TYPES, FFID_OAUTH_DENIAL_REASONS, FFID_ORGANIZATION_PROFILE_ERROR_CODES, FFID_SUBSCRIPTION_ERROR_CODES, canonicalizeCatalogValue, captureAgencyInviteToken, cleanupStateStorage, clearAgencyInviteToken, computeEffectiveStatusFromSession, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, getFFIDAuthorizationError, handleRedirectCallback, hasAccessFromUserinfo, hashCanonicalJson, isBlockedFromUserinfo, isFFIDInquiryAcquisitionSource, isFFIDInquiryCategorySite2026, isFFIDOAuthDenialReason, normalizeRedirectUri, readAgencyInviteCookie, readAgencyInviteToken, redactAgencyInviteToken, retrieveCodeVerifier, retrieveState, sha256Hex, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, validatePublishedCatalog, withSubscription };
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
4
|
var jose = require('jose');
|
|
5
|
+
var zod = require('zod');
|
|
5
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
7
|
|
|
7
8
|
// src/constants.ts
|
|
@@ -1393,7 +1394,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
|
|
|
1393
1394
|
};
|
|
1394
1395
|
|
|
1395
1396
|
// src/client/version-check.ts
|
|
1396
|
-
var SDK_VERSION = "12.1
|
|
1397
|
+
var SDK_VERSION = "12.2.1";
|
|
1397
1398
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1398
1399
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1399
1400
|
function sdkHeaders() {
|
|
@@ -3480,24 +3481,45 @@ function createContractWizardMethods(deps) {
|
|
|
3480
3481
|
};
|
|
3481
3482
|
}
|
|
3482
3483
|
|
|
3484
|
+
// src/newsletter/types.ts
|
|
3485
|
+
var FFID_NEWSLETTER_TYPES = ["inquiry_followup", "general"];
|
|
3486
|
+
var FFID_NEWSLETTER_DISPATCH_MAX_RECIPIENTS = 1e3;
|
|
3487
|
+
|
|
3483
3488
|
// src/newsletter/ffid-newsletter-client.ts
|
|
3484
3489
|
var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
|
|
3485
3490
|
var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
|
|
3486
3491
|
var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
|
|
3487
3492
|
var DISPATCH_ENDPOINT = "/api/v1/newsletter/dispatch";
|
|
3493
|
+
var PUBLIC_TOKEN_TIMEOUT_MS = 3e4;
|
|
3494
|
+
var subscribeResponseSchema = zod.z.object({
|
|
3495
|
+
ok: zod.z.literal(true),
|
|
3496
|
+
requiresConfirmation: zod.z.boolean(),
|
|
3497
|
+
requiresSignIn: zod.z.boolean(),
|
|
3498
|
+
confirmationEmailPending: zod.z.boolean(),
|
|
3499
|
+
requestId: zod.z.uuid().optional()
|
|
3500
|
+
}).refine(
|
|
3501
|
+
(value) => [
|
|
3502
|
+
value.requiresConfirmation,
|
|
3503
|
+
value.requiresSignIn,
|
|
3504
|
+
value.confirmationEmailPending
|
|
3505
|
+
].filter(Boolean).length <= 1
|
|
3506
|
+
);
|
|
3488
3507
|
function trimOrEmpty(s) {
|
|
3489
3508
|
return typeof s === "string" ? s.trim() : "";
|
|
3490
3509
|
}
|
|
3491
3510
|
async function postPublic(url, init, opts) {
|
|
3492
3511
|
let response;
|
|
3493
3512
|
try {
|
|
3494
|
-
response = await fetch(url,
|
|
3495
|
-
|
|
3513
|
+
response = await fetch(url, {
|
|
3514
|
+
...init,
|
|
3515
|
+
credentials: "omit",
|
|
3516
|
+
redirect: "error",
|
|
3517
|
+
cache: "no-store",
|
|
3518
|
+
signal: AbortSignal.timeout(PUBLIC_TOKEN_TIMEOUT_MS)
|
|
3519
|
+
});
|
|
3520
|
+
} catch {
|
|
3496
3521
|
return {
|
|
3497
|
-
error: opts.createError(
|
|
3498
|
-
"NETWORK_ERROR",
|
|
3499
|
-
err instanceof Error ? err.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
3500
|
-
)
|
|
3522
|
+
error: opts.createError("NETWORK_ERROR", opts.fallbackMessage)
|
|
3501
3523
|
};
|
|
3502
3524
|
}
|
|
3503
3525
|
if (!response.ok) {
|
|
@@ -3524,7 +3546,7 @@ async function postPublic(url, init, opts) {
|
|
|
3524
3546
|
}
|
|
3525
3547
|
function createNewsletterMethods(deps) {
|
|
3526
3548
|
const { fetchWithAuth, baseUrl, createError } = deps;
|
|
3527
|
-
async function subscribe(params) {
|
|
3549
|
+
async function subscribe(params, options = {}) {
|
|
3528
3550
|
const email = trimOrEmpty(params.email);
|
|
3529
3551
|
const source = trimOrEmpty(params.source);
|
|
3530
3552
|
if (!email) {
|
|
@@ -3541,10 +3563,19 @@ function createNewsletterMethods(deps) {
|
|
|
3541
3563
|
)
|
|
3542
3564
|
};
|
|
3543
3565
|
}
|
|
3544
|
-
|
|
3566
|
+
if (options.idempotencyKey !== void 0 && !zod.z.uuid().safeParse(options.idempotencyKey).success) {
|
|
3567
|
+
return {
|
|
3568
|
+
error: createError(
|
|
3569
|
+
"INVALID_IDEMPOTENCY_KEY",
|
|
3570
|
+
"idempotencyKey \u306B\u306F UUID \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
3571
|
+
)
|
|
3572
|
+
};
|
|
3573
|
+
}
|
|
3574
|
+
const response = await fetchWithAuth(
|
|
3545
3575
|
EXT_SUBSCRIBE_ENDPOINT2,
|
|
3546
3576
|
{
|
|
3547
3577
|
method: "POST",
|
|
3578
|
+
...options.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : {},
|
|
3548
3579
|
body: JSON.stringify({
|
|
3549
3580
|
email,
|
|
3550
3581
|
types: params.types,
|
|
@@ -3553,6 +3584,23 @@ function createNewsletterMethods(deps) {
|
|
|
3553
3584
|
})
|
|
3554
3585
|
}
|
|
3555
3586
|
);
|
|
3587
|
+
if (response.error) return response;
|
|
3588
|
+
const parsed = subscribeResponseSchema.safeParse(response.data);
|
|
3589
|
+
if (!parsed.success)
|
|
3590
|
+
return {
|
|
3591
|
+
error: createError(
|
|
3592
|
+
"PARSE_ERROR",
|
|
3593
|
+
"\u30CB\u30E5\u30FC\u30B9\u30EC\u30BF\u30FC\u767B\u9332\u306E\u5FDC\u7B54\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
3594
|
+
)
|
|
3595
|
+
};
|
|
3596
|
+
if (options.idempotencyKey && parsed.data.requestId !== options.idempotencyKey)
|
|
3597
|
+
return {
|
|
3598
|
+
error: createError(
|
|
3599
|
+
"PARSE_ERROR",
|
|
3600
|
+
"\u30CB\u30E5\u30FC\u30B9\u30EC\u30BF\u30FC\u767B\u9332\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u8B58\u5225\u5B50\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
3601
|
+
)
|
|
3602
|
+
};
|
|
3603
|
+
return { data: parsed.data };
|
|
3556
3604
|
}
|
|
3557
3605
|
async function confirm(params) {
|
|
3558
3606
|
const token = trimOrEmpty(params.token);
|
|
@@ -3580,6 +3628,16 @@ function createNewsletterMethods(deps) {
|
|
|
3580
3628
|
}
|
|
3581
3629
|
const url = new URL(`${baseUrl}${UNSUBSCRIBE_ENDPOINT}`);
|
|
3582
3630
|
url.searchParams.set("token", token);
|
|
3631
|
+
if (params.type !== void 0) {
|
|
3632
|
+
if (!FFID_NEWSLETTER_TYPES.includes(params.type))
|
|
3633
|
+
return {
|
|
3634
|
+
error: createError(
|
|
3635
|
+
"VALIDATION_ERROR",
|
|
3636
|
+
"\u30CB\u30E5\u30FC\u30B9\u30EC\u30BF\u30FC\u306E\u914D\u4FE1\u7A2E\u5225\u304C\u4E0D\u6B63\u3067\u3059"
|
|
3637
|
+
)
|
|
3638
|
+
};
|
|
3639
|
+
url.searchParams.set("type", params.type);
|
|
3640
|
+
}
|
|
3583
3641
|
return postPublic(
|
|
3584
3642
|
url.toString(),
|
|
3585
3643
|
{ method: "POST" },
|
|
@@ -5248,10 +5306,12 @@ function FFIDUserMenu({
|
|
|
5248
5306
|
}) {
|
|
5249
5307
|
const { user, currentOrganization, logout, isLoading, isAuthenticated } = useFFID();
|
|
5250
5308
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
5251
|
-
const
|
|
5252
|
-
react.
|
|
5253
|
-
|
|
5254
|
-
|
|
5309
|
+
const avatarUrl = user?.avatarUrl ?? null;
|
|
5310
|
+
const [avatarState, setAvatarState] = react.useState({ url: avatarUrl, failed: false });
|
|
5311
|
+
if (avatarState.url !== avatarUrl) {
|
|
5312
|
+
setAvatarState({ url: avatarUrl, failed: false });
|
|
5313
|
+
}
|
|
5314
|
+
const avatarError = avatarState.url === avatarUrl && avatarState.failed;
|
|
5255
5315
|
if (!isAuthenticated || !user) {
|
|
5256
5316
|
return null;
|
|
5257
5317
|
}
|
|
@@ -5294,7 +5354,7 @@ function FFIDUserMenu({
|
|
|
5294
5354
|
className: classNames.avatar,
|
|
5295
5355
|
src: user.avatarUrl,
|
|
5296
5356
|
alt: displayName,
|
|
5297
|
-
onError: () =>
|
|
5357
|
+
onError: () => setAvatarState({ url: avatarUrl, failed: true }),
|
|
5298
5358
|
style: { width: SIZE_AVATAR_MD, height: SIZE_AVATAR_MD, borderRadius: "50%" }
|
|
5299
5359
|
}
|
|
5300
5360
|
) : defaultAvatar;
|
|
@@ -6916,6 +6976,8 @@ exports.FFID_INQUIRY_CATEGORIES = FFID_INQUIRY_CATEGORIES;
|
|
|
6916
6976
|
exports.FFID_INQUIRY_CATEGORIES_SITE_2026 = FFID_INQUIRY_CATEGORIES_SITE_2026;
|
|
6917
6977
|
exports.FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES;
|
|
6918
6978
|
exports.FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB = FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB;
|
|
6979
|
+
exports.FFID_NEWSLETTER_DISPATCH_MAX_RECIPIENTS = FFID_NEWSLETTER_DISPATCH_MAX_RECIPIENTS;
|
|
6980
|
+
exports.FFID_NEWSLETTER_TYPES = FFID_NEWSLETTER_TYPES;
|
|
6919
6981
|
exports.FFID_OAUTH_DENIAL_REASONS = FFID_OAUTH_DENIAL_REASONS;
|
|
6920
6982
|
exports.FFID_ORGANIZATION_PROFILE_ERROR_CODES = FFID_ORGANIZATION_PROFILE_ERROR_CODES;
|
|
6921
6983
|
exports.FFID_SUBSCRIPTION_ERROR_CODES = FFID_SUBSCRIPTION_ERROR_CODES;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkMSY5VF2K_cjs = require('../chunk-MSY5VF2K.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 chunkMSY5VF2K_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkMSY5VF2K_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDInquiryForm", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkMSY5VF2K_cjs.FFIDInquiryForm; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkMSY5VF2K_cjs.FFIDLoginButton; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkMSY5VF2K_cjs.FFIDOrganizationSwitcher; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkMSY5VF2K_cjs.FFIDSubscriptionBadge; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunkMSY5VF2K_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-HPECOYG2.js';
|
|
@@ -114,7 +114,7 @@ interface FFIDInquiryCreateResponse {
|
|
|
114
114
|
* Newsletter types exposed by the FFID SDK.
|
|
115
115
|
*
|
|
116
116
|
* 2-layer newsletter model (#2078):
|
|
117
|
-
* - `inquiry_followup`:
|
|
117
|
+
* - `inquiry_followup`: 資料請求・お問い合わせ後のご案内 (Type A)
|
|
118
118
|
* - `general`: 定期ニュースレター (Type B)
|
|
119
119
|
*
|
|
120
120
|
* FFID account holders' preferences live in `user_marketing_preferences`;
|
|
@@ -133,6 +133,12 @@ interface FFIDNewsletterSubscribeParams {
|
|
|
133
133
|
/** ISO 639-1 locale (e.g. 'ja', 'en') */
|
|
134
134
|
locale?: string;
|
|
135
135
|
}
|
|
136
|
+
interface FFIDNewsletterSubscribeOptions {
|
|
137
|
+
/** UUID for one intentional registration. Reuse unchanged across retries;
|
|
138
|
+
* create a new key when the registration changes or a new request is intended.
|
|
139
|
+
* Transport-only: sent as Idempotency-Key, never added to the consent body. */
|
|
140
|
+
idempotencyKey?: string | undefined;
|
|
141
|
+
}
|
|
136
142
|
interface FFIDNewsletterSubscribeResponse {
|
|
137
143
|
ok: true;
|
|
138
144
|
/** True when a double opt-in confirmation email was sent */
|
|
@@ -140,6 +146,11 @@ interface FFIDNewsletterSubscribeResponse {
|
|
|
140
146
|
/** True when the email matched an existing FFID account; the caller
|
|
141
147
|
* must sign in to update preferences. Preferences are NOT modified. */
|
|
142
148
|
requiresSignIn: boolean;
|
|
149
|
+
/** True when confirmation could not be sent; subscription is still pending.
|
|
150
|
+
* This flag does not promise an automatic resend. */
|
|
151
|
+
confirmationEmailPending: boolean;
|
|
152
|
+
/** Present only when the independent owner acknowledged a durable registration intent. */
|
|
153
|
+
requestId?: string | undefined;
|
|
143
154
|
}
|
|
144
155
|
interface FFIDNewsletterConfirmParams {
|
|
145
156
|
/** Confirmation token received in the double opt-in email */
|
|
@@ -151,6 +162,8 @@ interface FFIDNewsletterConfirmResponse {
|
|
|
151
162
|
interface FFIDNewsletterUnsubscribeParams {
|
|
152
163
|
/** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
|
|
153
164
|
token: string;
|
|
165
|
+
/** Stop only the selected purpose. Omission preserves legacy all-purpose links. */
|
|
166
|
+
type?: FFIDNewsletterType | undefined;
|
|
154
167
|
}
|
|
155
168
|
interface FFIDNewsletterUnsubscribeResponse {
|
|
156
169
|
ok: true;
|
|
@@ -2880,7 +2893,7 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
2880
2893
|
}) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
|
|
2881
2894
|
/** Newsletter methods (subscribe / confirm / unsubscribe) */
|
|
2882
2895
|
newsletter: {
|
|
2883
|
-
subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
|
|
2896
|
+
subscribe: (params: FFIDNewsletterSubscribeParams, options?: FFIDNewsletterSubscribeOptions) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
|
|
2884
2897
|
confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
|
|
2885
2898
|
unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
|
|
2886
2899
|
dispatch: (params: FFIDNewsletterDispatchParams) => Promise<FFIDApiResponse<FFIDNewsletterDispatchResponse>>;
|
|
@@ -114,7 +114,7 @@ interface FFIDInquiryCreateResponse {
|
|
|
114
114
|
* Newsletter types exposed by the FFID SDK.
|
|
115
115
|
*
|
|
116
116
|
* 2-layer newsletter model (#2078):
|
|
117
|
-
* - `inquiry_followup`:
|
|
117
|
+
* - `inquiry_followup`: 資料請求・お問い合わせ後のご案内 (Type A)
|
|
118
118
|
* - `general`: 定期ニュースレター (Type B)
|
|
119
119
|
*
|
|
120
120
|
* FFID account holders' preferences live in `user_marketing_preferences`;
|
|
@@ -133,6 +133,12 @@ interface FFIDNewsletterSubscribeParams {
|
|
|
133
133
|
/** ISO 639-1 locale (e.g. 'ja', 'en') */
|
|
134
134
|
locale?: string;
|
|
135
135
|
}
|
|
136
|
+
interface FFIDNewsletterSubscribeOptions {
|
|
137
|
+
/** UUID for one intentional registration. Reuse unchanged across retries;
|
|
138
|
+
* create a new key when the registration changes or a new request is intended.
|
|
139
|
+
* Transport-only: sent as Idempotency-Key, never added to the consent body. */
|
|
140
|
+
idempotencyKey?: string | undefined;
|
|
141
|
+
}
|
|
136
142
|
interface FFIDNewsletterSubscribeResponse {
|
|
137
143
|
ok: true;
|
|
138
144
|
/** True when a double opt-in confirmation email was sent */
|
|
@@ -140,6 +146,11 @@ interface FFIDNewsletterSubscribeResponse {
|
|
|
140
146
|
/** True when the email matched an existing FFID account; the caller
|
|
141
147
|
* must sign in to update preferences. Preferences are NOT modified. */
|
|
142
148
|
requiresSignIn: boolean;
|
|
149
|
+
/** True when confirmation could not be sent; subscription is still pending.
|
|
150
|
+
* This flag does not promise an automatic resend. */
|
|
151
|
+
confirmationEmailPending: boolean;
|
|
152
|
+
/** Present only when the independent owner acknowledged a durable registration intent. */
|
|
153
|
+
requestId?: string | undefined;
|
|
143
154
|
}
|
|
144
155
|
interface FFIDNewsletterConfirmParams {
|
|
145
156
|
/** Confirmation token received in the double opt-in email */
|
|
@@ -151,6 +162,8 @@ interface FFIDNewsletterConfirmResponse {
|
|
|
151
162
|
interface FFIDNewsletterUnsubscribeParams {
|
|
152
163
|
/** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
|
|
153
164
|
token: string;
|
|
165
|
+
/** Stop only the selected purpose. Omission preserves legacy all-purpose links. */
|
|
166
|
+
type?: FFIDNewsletterType | undefined;
|
|
154
167
|
}
|
|
155
168
|
interface FFIDNewsletterUnsubscribeResponse {
|
|
156
169
|
ok: true;
|
|
@@ -2880,7 +2893,7 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
2880
2893
|
}) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
|
|
2881
2894
|
/** Newsletter methods (subscribe / confirm / unsubscribe) */
|
|
2882
2895
|
newsletter: {
|
|
2883
|
-
subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
|
|
2896
|
+
subscribe: (params: FFIDNewsletterSubscribeParams, options?: FFIDNewsletterSubscribeOptions) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
|
|
2884
2897
|
confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
|
|
2885
2898
|
unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
|
|
2886
2899
|
dispatch: (params: FFIDNewsletterDispatchParams) => Promise<FFIDApiResponse<FFIDNewsletterDispatchResponse>>;
|