@feelflow/ffid-sdk 2.12.1 → 2.15.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 CHANGED
@@ -228,6 +228,44 @@ const PremiumFeature = withSubscription(MyComponent, {
228
228
  })
229
229
  ```
230
230
 
231
+ ### getProfile() / updateProfile()
232
+
233
+ ログイン中ユーザー自身のプロフィールを取得・更新するメソッド(`createFFIDClient` から呼び出し)。
234
+
235
+ - エンドポイント: `GET /api/v1/users/ext/me` / `PUT /api/v1/users/ext/me`
236
+ - 対応 authMode: `token`(Bearer)のみが SDK 経由で成立する
237
+ - **cookie モードは非対応** — ext エンドポイントはクロスオリジン用途のため、Bearer token または `X-Service-Api-Key` のどちらかが必須。FFID 自身の UI(同一オリジン)は従来通り `/api/v1/users/me` を使う
238
+ - **service-key モードも SDK 経由では非対応** — API Key 認証時はバックエンドが `?userId=<uuid>` クエリを要求するが、`getProfile()` / `updateProfile()` は自分自身(ambient user)を前提とするため、`userId` を受け取らない。サーバー間で任意ユーザーのプロフィールを操作したい場合は `fetchWithAuth` で直接エンドポイントを叩いてください
239
+ - 外部サービス(hub 等)のフロントエンドから token モードで呼ぶのが想定される主要パターン
240
+
241
+ ```tsx
242
+ import { createFFIDClient } from '@feelflow/ffid-sdk'
243
+
244
+ const client = createFFIDClient({
245
+ serviceCode: 'hub',
246
+ authMode: 'token',
247
+ apiBaseUrl: 'https://id.feelflow.net',
248
+ })
249
+
250
+ // 取得
251
+ const { data: profile, error } = await client.getProfile()
252
+ if (error) {
253
+ console.error('プロフィール取得失敗:', error.message)
254
+ } else {
255
+ console.log(profile.email, profile.displayName, profile.timezone)
256
+ }
257
+
258
+ // 更新(部分更新 — 渡したフィールドだけ差し替え)
259
+ const { data: updated, error: updateError } = await client.updateProfile({
260
+ displayName: '山田 太郎',
261
+ timezone: 'Asia/Tokyo',
262
+ locale: 'ja',
263
+ preferences: { theme: 'dark' },
264
+ })
265
+ ```
266
+
267
+ `updateProfile` に空オブジェクト `{}` を渡すと `VALIDATION_ERROR` が返ります(無意味なラウンドトリップを防止)。
268
+
231
269
  ## 型定義
232
270
 
233
271
  ```typescript
@@ -760,8 +760,57 @@ function createMembersMethods(deps) {
760
760
  return { listMembers, updateMemberRole, removeMember };
761
761
  }
762
762
 
763
+ // src/client/profile-methods.ts
764
+ var EXT_PROFILE_ENDPOINT = "/api/v1/users/ext/me";
765
+ function resolveAuthOverride(options, createError) {
766
+ if (!options || options.accessToken === void 0) {
767
+ return {};
768
+ }
769
+ const token = options.accessToken;
770
+ if (typeof token !== "string" || token.trim() === "") {
771
+ return {
772
+ error: createError(
773
+ "VALIDATION_ERROR",
774
+ "accessToken \u3092\u6307\u5B9A\u3059\u308B\u5834\u5408\u3001\u7A7A\u6587\u5B57\u5217\u3084\u7A7A\u767D\u306E\u307F\u306E\u5024\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
775
+ )
776
+ };
777
+ }
778
+ return { override: { accessToken: token } };
779
+ }
780
+ function createProfileMethods(deps) {
781
+ const { fetchWithAuth, createError } = deps;
782
+ async function getProfile(options) {
783
+ const { override, error } = resolveAuthOverride(options, createError);
784
+ if (error) return { error };
785
+ return fetchWithAuth(EXT_PROFILE_ENDPOINT, void 0, override);
786
+ }
787
+ async function updateProfile(data, options) {
788
+ if (data === null || typeof data !== "object" || Array.isArray(data)) {
789
+ return {
790
+ error: createError("VALIDATION_ERROR", "data \u306F\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059")
791
+ };
792
+ }
793
+ if (Object.keys(data).length === 0) {
794
+ return {
795
+ error: createError("VALIDATION_ERROR", "\u66F4\u65B0\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u30921\u3064\u4EE5\u4E0A\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044")
796
+ };
797
+ }
798
+ const { override, error } = resolveAuthOverride(options, createError);
799
+ if (error) return { error };
800
+ return fetchWithAuth(
801
+ EXT_PROFILE_ENDPOINT,
802
+ {
803
+ method: "PUT",
804
+ body: JSON.stringify(data)
805
+ },
806
+ override
807
+ );
808
+ }
809
+ return { getProfile, updateProfile };
810
+ }
811
+
763
812
  // src/client/version-check.ts
764
- var SDK_VERSION = "2.12.1";
813
+ var SDK_VERSION = "2.15.0";
765
814
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
766
815
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
767
816
  function sdkHeaders() {
@@ -1956,7 +2005,19 @@ function createFFIDClient(config) {
1956
2005
  function createError(code, message) {
1957
2006
  return { code, message };
1958
2007
  }
1959
- function buildFetchOptions(options) {
2008
+ function buildFetchOptions(options, authOverride) {
2009
+ if (authOverride) {
2010
+ return {
2011
+ ...options,
2012
+ credentials: "omit",
2013
+ headers: {
2014
+ "Content-Type": "application/json",
2015
+ ...sdkHeaders(),
2016
+ ...options.headers,
2017
+ Authorization: `Bearer ${authOverride.accessToken}`
2018
+ }
2019
+ };
2020
+ }
1960
2021
  if (authMode === "service-key") {
1961
2022
  return {
1962
2023
  ...options,
@@ -2003,10 +2064,10 @@ function createFFIDClient(config) {
2003
2064
  logger,
2004
2065
  errorCodes: FFID_ERROR_CODES
2005
2066
  });
2006
- async function fetchWithAuth(endpoint, options = {}) {
2067
+ async function fetchWithAuth(endpoint, options = {}, authOverride) {
2007
2068
  const url = `${baseUrl}${endpoint}`;
2008
2069
  logger.debug("Fetching:", url);
2009
- const fetchOptions = buildFetchOptions(options);
2070
+ const fetchOptions = buildFetchOptions(options, authOverride);
2010
2071
  let response;
2011
2072
  try {
2012
2073
  response = await fetch(url, fetchOptions);
@@ -2019,7 +2080,7 @@ function createFFIDClient(config) {
2019
2080
  }
2020
2081
  };
2021
2082
  }
2022
- if (authMode === "token" && response.status === UNAUTHORIZED_STATUS2) {
2083
+ if (!authOverride && authMode === "token" && response.status === UNAUTHORIZED_STATUS2) {
2023
2084
  const refreshResult = await refreshAccessToken();
2024
2085
  if (!refreshResult.error) {
2025
2086
  logger.debug("Token refreshed, retrying request");
@@ -2145,6 +2206,10 @@ function createFFIDClient(config) {
2145
2206
  createError,
2146
2207
  serviceCode: config.serviceCode
2147
2208
  });
2209
+ const { getProfile, updateProfile } = createProfileMethods({
2210
+ fetchWithAuth,
2211
+ createError
2212
+ });
2148
2213
  const {
2149
2214
  requestPasswordReset,
2150
2215
  verifyPasswordResetToken,
@@ -2216,6 +2281,8 @@ function createFFIDClient(config) {
2216
2281
  listMembers,
2217
2282
  updateMemberRole,
2218
2283
  removeMember,
2284
+ getProfile,
2285
+ updateProfile,
2219
2286
  createCheckoutSession,
2220
2287
  createPortalSession,
2221
2288
  listPlans,
@@ -3600,8 +3667,34 @@ var FFID_INQUIRY_CATEGORIES = [
3600
3667
  "press",
3601
3668
  "other"
3602
3669
  ];
3670
+ var FFID_INQUIRY_CATEGORIES_SITE_2026 = [
3671
+ // サービス
3672
+ "consulting",
3673
+ "saas",
3674
+ "development",
3675
+ // プロダクト
3676
+ "agent-hub",
3677
+ "ai-feel-chatbot",
3678
+ "knowledge-db",
3679
+ "biz-simulator",
3680
+ "discussion-board",
3681
+ "realtime-ai",
3682
+ // その他
3683
+ "partnership",
3684
+ "media",
3685
+ "recruiting",
3686
+ "other"
3687
+ ];
3688
+ var isFFIDInquiryCategorySite2026 = (value) => FFID_INQUIRY_CATEGORIES_SITE_2026.includes(value);
3603
3689
  var CATEGORY_PLACEHOLDER_LABEL_JA = "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044";
3604
3690
  var CATEGORY_REQUIRED_ERROR_JA = "\u304A\u554F\u3044\u5408\u308F\u305B\u7A2E\u5225\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
3691
+ var TERMS_REQUIRED_ERROR_JA = "\u5229\u7528\u898F\u7D04\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002";
3692
+ var PRIVACY_REQUIRED_ERROR_JA = "\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002";
3693
+ var TURNSTILE_PENDING_ERROR_JA = "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30C1\u30A7\u30C3\u30AF\u306E\u5B8C\u4E86\u5F8C\u306B\u9001\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
3694
+ function hasSatisfiedTurnstile(turnstileSlot, turnstileToken) {
3695
+ if (turnstileSlot == null) return true;
3696
+ return (turnstileToken ?? "").trim().length > 0;
3697
+ }
3605
3698
  var SUBMIT_BUTTON_OPACITY_PENDING = 0.6;
3606
3699
  var labelStyle = {
3607
3700
  display: "block",
@@ -3671,6 +3764,23 @@ function defaultCategories() {
3671
3764
  label: DEFAULT_CATEGORY_LABELS_JA[value]
3672
3765
  }));
3673
3766
  }
3767
+ function warnOnGroupLabelConflicts(options) {
3768
+ if (process.env.NODE_ENV === "production") return;
3769
+ const firstExplicitLabel = /* @__PURE__ */ new Map();
3770
+ const warnedGroups = /* @__PURE__ */ new Set();
3771
+ for (const opt of options) {
3772
+ if (!opt.group || opt.groupLabel === void 0) continue;
3773
+ const firstLabel = firstExplicitLabel.get(opt.group);
3774
+ if (firstLabel === void 0) {
3775
+ firstExplicitLabel.set(opt.group, opt.groupLabel);
3776
+ } else if (firstLabel !== opt.groupLabel && !warnedGroups.has(opt.group)) {
3777
+ warnedGroups.add(opt.group);
3778
+ console.warn(
3779
+ `[FFIDInquiryForm] group "${opt.group}" has conflicting groupLabels: "${firstLabel}" (first-wins) vs "${opt.groupLabel}" (ignored). Pass the same groupLabel for every item in the group, or omit it on all but the first.`
3780
+ );
3781
+ }
3782
+ }
3783
+ }
3674
3784
  function renderCategoryOptions(options) {
3675
3785
  const hasAnyGroup = options.some((o) => !!o.group);
3676
3786
  if (!hasAnyGroup) {
@@ -3723,6 +3833,9 @@ function FFIDInquiryForm({
3723
3833
  () => categories && categories.length > 0 ? categories : defaultCategories(),
3724
3834
  [categories]
3725
3835
  );
3836
+ react.useEffect(() => {
3837
+ warnOnGroupLabelConflicts(categoryOptions);
3838
+ }, [categoryOptions]);
3726
3839
  const initialOrgId = react.useMemo(() => {
3727
3840
  if (!isAuth) return null;
3728
3841
  if (preselectedOrganizationId !== void 0) return preselectedOrganizationId;
@@ -3756,6 +3869,8 @@ function FFIDInquiryForm({
3756
3869
  const [agreedLegal, setAgreedLegal] = react.useState(false);
3757
3870
  const [agreedTerms, setAgreedTerms] = react.useState(false);
3758
3871
  const [agreedPrivacy, setAgreedPrivacy] = react.useState(false);
3872
+ const [agreedTermsError, setAgreedTermsError] = react.useState(false);
3873
+ const [agreedPrivacyError, setAgreedPrivacyError] = react.useState(false);
3759
3874
  const [submitting, setSubmitting] = react.useState(false);
3760
3875
  const [formError, setFormError] = react.useState(null);
3761
3876
  const [successMessage, setSuccessMessage] = react.useState(null);
@@ -3773,7 +3888,7 @@ function FFIDInquiryForm({
3773
3888
  onChangeRef.current = onChange;
3774
3889
  }, [onChange]);
3775
3890
  react.useEffect(() => {
3776
- if (category === "") return;
3891
+ if (category === "" || successMessage) return;
3777
3892
  onChangeRef.current?.({
3778
3893
  name: name.trim(),
3779
3894
  email: email.trim(),
@@ -3802,25 +3917,19 @@ function FFIDInquiryForm({
3802
3917
  termsVersion,
3803
3918
  privacyVersion,
3804
3919
  turnstileToken,
3805
- locale
3920
+ locale,
3921
+ successMessage
3806
3922
  ]);
3807
3923
  const s = (style) => styleOrUndefined(style, unstyled);
3808
3924
  async function handleSubmit(e) {
3809
3925
  e.preventDefault();
3810
3926
  setFormError(null);
3811
3927
  if (separateLegalCheckboxes) {
3812
- if (!agreedTerms && !agreedPrivacy) {
3813
- setFormError("\u5229\u7528\u898F\u7D04\u3068\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3814
- return;
3815
- }
3816
- if (!agreedTerms) {
3817
- setFormError("\u5229\u7528\u898F\u7D04\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3818
- return;
3819
- }
3820
- if (!agreedPrivacy) {
3821
- setFormError("\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3822
- return;
3823
- }
3928
+ const termsInvalid = !agreedTerms;
3929
+ const privacyInvalid = !agreedPrivacy;
3930
+ setAgreedTermsError(termsInvalid);
3931
+ setAgreedPrivacyError(privacyInvalid);
3932
+ if (termsInvalid || privacyInvalid) return;
3824
3933
  } else if (!agreedLegal) {
3825
3934
  setFormError("\u5229\u7528\u898F\u7D04\u3068\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3826
3935
  return;
@@ -3837,6 +3946,10 @@ function FFIDInquiryForm({
3837
3946
  setFormError("\u304A\u540D\u524D\u3068\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
3838
3947
  return;
3839
3948
  }
3949
+ if (!isAuth && !hasSatisfiedTurnstile(turnstileSlot, turnstileToken)) {
3950
+ setFormError(TURNSTILE_PENDING_ERROR_JA);
3951
+ return;
3952
+ }
3840
3953
  setSubmitting(true);
3841
3954
  try {
3842
3955
  const result = await onSubmit({
@@ -3914,7 +4027,7 @@ function FFIDInquiryForm({
3914
4027
  onSubmit: handleSubmit,
3915
4028
  className: cx(className, classNames?.form),
3916
4029
  noValidate: true,
3917
- "data-hydrated": hydrated ? "true" : void 0,
4030
+ "data-hydrated": hydrated ? "true" : "false",
3918
4031
  children: [
3919
4032
  showOrgBlock && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s(fieldsetStyle), className: cx(classNames?.field, classNames?.orgSelectWrapper), children: [
3920
4033
  /* @__PURE__ */ jsxRuntime.jsx("label", { style: s(labelStyle), className: classNames?.label, htmlFor: "ffid-inquiry-org", children: "\u554F\u3044\u5408\u308F\u305B\u308B\u7ACB\u5834" }),
@@ -4081,7 +4194,11 @@ function FFIDInquiryForm({
4081
4194
  type: "checkbox",
4082
4195
  className: classNames?.legalCheckbox,
4083
4196
  checked: agreedTerms,
4084
- onChange: (e) => setAgreedTerms(e.target.checked),
4197
+ onChange: (e) => {
4198
+ const checked = e.target.checked;
4199
+ setAgreedTerms(checked);
4200
+ if (checked) setAgreedTermsError(false);
4201
+ },
4085
4202
  required: true
4086
4203
  }
4087
4204
  ),
@@ -4090,6 +4207,7 @@ function FFIDInquiryForm({
4090
4207
  " \u306B\u540C\u610F\u3057\u307E\u3059\u3002"
4091
4208
  ] })
4092
4209
  ] }),
4210
+ agreedTermsError && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", style: s(errorTextStyle), className: classNames?.errorText, children: TERMS_REQUIRED_ERROR_JA }),
4093
4211
  /* @__PURE__ */ jsxRuntime.jsxs("label", { style: s(legalRowLast), className: classNames?.legalRow, children: [
4094
4212
  /* @__PURE__ */ jsxRuntime.jsx(
4095
4213
  "input",
@@ -4097,7 +4215,11 @@ function FFIDInquiryForm({
4097
4215
  type: "checkbox",
4098
4216
  className: classNames?.legalCheckbox,
4099
4217
  checked: agreedPrivacy,
4100
- onChange: (e) => setAgreedPrivacy(e.target.checked),
4218
+ onChange: (e) => {
4219
+ const checked = e.target.checked;
4220
+ setAgreedPrivacy(checked);
4221
+ if (checked) setAgreedPrivacyError(false);
4222
+ },
4101
4223
  required: true
4102
4224
  }
4103
4225
  ),
@@ -4105,7 +4227,8 @@ function FFIDInquiryForm({
4105
4227
  renderPrivacyLink(),
4106
4228
  " \u306B\u540C\u610F\u3057\u307E\u3059\u3002"
4107
4229
  ] })
4108
- ] })
4230
+ ] }),
4231
+ agreedPrivacyError && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", style: s(errorTextStyle), className: classNames?.errorText, children: PRIVACY_REQUIRED_ERROR_JA })
4109
4232
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: s(fieldsetStyle), className: classNames?.legalBlock, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { style: s(legalRowLast), className: classNames?.legalRow, children: [
4110
4233
  /* @__PURE__ */ jsxRuntime.jsx(
4111
4234
  "input",
@@ -4165,11 +4288,13 @@ exports.FFIDSubscriptionBadge = FFIDSubscriptionBadge;
4165
4288
  exports.FFIDUserMenu = FFIDUserMenu;
4166
4289
  exports.FFID_ANNOUNCEMENTS_ERROR_CODES = FFID_ANNOUNCEMENTS_ERROR_CODES;
4167
4290
  exports.FFID_INQUIRY_CATEGORIES = FFID_INQUIRY_CATEGORIES;
4291
+ exports.FFID_INQUIRY_CATEGORIES_SITE_2026 = FFID_INQUIRY_CATEGORIES_SITE_2026;
4168
4292
  exports.createFFIDAnnouncementsClient = createFFIDAnnouncementsClient;
4169
4293
  exports.createFFIDClient = createFFIDClient;
4170
4294
  exports.createTokenStore = createTokenStore;
4171
4295
  exports.generateCodeChallenge = generateCodeChallenge;
4172
4296
  exports.generateCodeVerifier = generateCodeVerifier;
4297
+ exports.isFFIDInquiryCategorySite2026 = isFFIDInquiryCategorySite2026;
4173
4298
  exports.normalizeRedirectUri = normalizeRedirectUri;
4174
4299
  exports.retrieveCodeVerifier = retrieveCodeVerifier;
4175
4300
  exports.storeCodeVerifier = storeCodeVerifier;
@@ -758,8 +758,57 @@ function createMembersMethods(deps) {
758
758
  return { listMembers, updateMemberRole, removeMember };
759
759
  }
760
760
 
761
+ // src/client/profile-methods.ts
762
+ var EXT_PROFILE_ENDPOINT = "/api/v1/users/ext/me";
763
+ function resolveAuthOverride(options, createError) {
764
+ if (!options || options.accessToken === void 0) {
765
+ return {};
766
+ }
767
+ const token = options.accessToken;
768
+ if (typeof token !== "string" || token.trim() === "") {
769
+ return {
770
+ error: createError(
771
+ "VALIDATION_ERROR",
772
+ "accessToken \u3092\u6307\u5B9A\u3059\u308B\u5834\u5408\u3001\u7A7A\u6587\u5B57\u5217\u3084\u7A7A\u767D\u306E\u307F\u306E\u5024\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
773
+ )
774
+ };
775
+ }
776
+ return { override: { accessToken: token } };
777
+ }
778
+ function createProfileMethods(deps) {
779
+ const { fetchWithAuth, createError } = deps;
780
+ async function getProfile(options) {
781
+ const { override, error } = resolveAuthOverride(options, createError);
782
+ if (error) return { error };
783
+ return fetchWithAuth(EXT_PROFILE_ENDPOINT, void 0, override);
784
+ }
785
+ async function updateProfile(data, options) {
786
+ if (data === null || typeof data !== "object" || Array.isArray(data)) {
787
+ return {
788
+ error: createError("VALIDATION_ERROR", "data \u306F\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059")
789
+ };
790
+ }
791
+ if (Object.keys(data).length === 0) {
792
+ return {
793
+ error: createError("VALIDATION_ERROR", "\u66F4\u65B0\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u30921\u3064\u4EE5\u4E0A\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044")
794
+ };
795
+ }
796
+ const { override, error } = resolveAuthOverride(options, createError);
797
+ if (error) return { error };
798
+ return fetchWithAuth(
799
+ EXT_PROFILE_ENDPOINT,
800
+ {
801
+ method: "PUT",
802
+ body: JSON.stringify(data)
803
+ },
804
+ override
805
+ );
806
+ }
807
+ return { getProfile, updateProfile };
808
+ }
809
+
761
810
  // src/client/version-check.ts
762
- var SDK_VERSION = "2.12.1";
811
+ var SDK_VERSION = "2.15.0";
763
812
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
764
813
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
765
814
  function sdkHeaders() {
@@ -1954,7 +2003,19 @@ function createFFIDClient(config) {
1954
2003
  function createError(code, message) {
1955
2004
  return { code, message };
1956
2005
  }
1957
- function buildFetchOptions(options) {
2006
+ function buildFetchOptions(options, authOverride) {
2007
+ if (authOverride) {
2008
+ return {
2009
+ ...options,
2010
+ credentials: "omit",
2011
+ headers: {
2012
+ "Content-Type": "application/json",
2013
+ ...sdkHeaders(),
2014
+ ...options.headers,
2015
+ Authorization: `Bearer ${authOverride.accessToken}`
2016
+ }
2017
+ };
2018
+ }
1958
2019
  if (authMode === "service-key") {
1959
2020
  return {
1960
2021
  ...options,
@@ -2001,10 +2062,10 @@ function createFFIDClient(config) {
2001
2062
  logger,
2002
2063
  errorCodes: FFID_ERROR_CODES
2003
2064
  });
2004
- async function fetchWithAuth(endpoint, options = {}) {
2065
+ async function fetchWithAuth(endpoint, options = {}, authOverride) {
2005
2066
  const url = `${baseUrl}${endpoint}`;
2006
2067
  logger.debug("Fetching:", url);
2007
- const fetchOptions = buildFetchOptions(options);
2068
+ const fetchOptions = buildFetchOptions(options, authOverride);
2008
2069
  let response;
2009
2070
  try {
2010
2071
  response = await fetch(url, fetchOptions);
@@ -2017,7 +2078,7 @@ function createFFIDClient(config) {
2017
2078
  }
2018
2079
  };
2019
2080
  }
2020
- if (authMode === "token" && response.status === UNAUTHORIZED_STATUS2) {
2081
+ if (!authOverride && authMode === "token" && response.status === UNAUTHORIZED_STATUS2) {
2021
2082
  const refreshResult = await refreshAccessToken();
2022
2083
  if (!refreshResult.error) {
2023
2084
  logger.debug("Token refreshed, retrying request");
@@ -2143,6 +2204,10 @@ function createFFIDClient(config) {
2143
2204
  createError,
2144
2205
  serviceCode: config.serviceCode
2145
2206
  });
2207
+ const { getProfile, updateProfile } = createProfileMethods({
2208
+ fetchWithAuth,
2209
+ createError
2210
+ });
2146
2211
  const {
2147
2212
  requestPasswordReset,
2148
2213
  verifyPasswordResetToken,
@@ -2214,6 +2279,8 @@ function createFFIDClient(config) {
2214
2279
  listMembers,
2215
2280
  updateMemberRole,
2216
2281
  removeMember,
2282
+ getProfile,
2283
+ updateProfile,
2217
2284
  createCheckoutSession,
2218
2285
  createPortalSession,
2219
2286
  listPlans,
@@ -3598,8 +3665,34 @@ var FFID_INQUIRY_CATEGORIES = [
3598
3665
  "press",
3599
3666
  "other"
3600
3667
  ];
3668
+ var FFID_INQUIRY_CATEGORIES_SITE_2026 = [
3669
+ // サービス
3670
+ "consulting",
3671
+ "saas",
3672
+ "development",
3673
+ // プロダクト
3674
+ "agent-hub",
3675
+ "ai-feel-chatbot",
3676
+ "knowledge-db",
3677
+ "biz-simulator",
3678
+ "discussion-board",
3679
+ "realtime-ai",
3680
+ // その他
3681
+ "partnership",
3682
+ "media",
3683
+ "recruiting",
3684
+ "other"
3685
+ ];
3686
+ var isFFIDInquiryCategorySite2026 = (value) => FFID_INQUIRY_CATEGORIES_SITE_2026.includes(value);
3601
3687
  var CATEGORY_PLACEHOLDER_LABEL_JA = "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044";
3602
3688
  var CATEGORY_REQUIRED_ERROR_JA = "\u304A\u554F\u3044\u5408\u308F\u305B\u7A2E\u5225\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
3689
+ var TERMS_REQUIRED_ERROR_JA = "\u5229\u7528\u898F\u7D04\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002";
3690
+ var PRIVACY_REQUIRED_ERROR_JA = "\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002";
3691
+ var TURNSTILE_PENDING_ERROR_JA = "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30C1\u30A7\u30C3\u30AF\u306E\u5B8C\u4E86\u5F8C\u306B\u9001\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
3692
+ function hasSatisfiedTurnstile(turnstileSlot, turnstileToken) {
3693
+ if (turnstileSlot == null) return true;
3694
+ return (turnstileToken ?? "").trim().length > 0;
3695
+ }
3603
3696
  var SUBMIT_BUTTON_OPACITY_PENDING = 0.6;
3604
3697
  var labelStyle = {
3605
3698
  display: "block",
@@ -3669,6 +3762,23 @@ function defaultCategories() {
3669
3762
  label: DEFAULT_CATEGORY_LABELS_JA[value]
3670
3763
  }));
3671
3764
  }
3765
+ function warnOnGroupLabelConflicts(options) {
3766
+ if (process.env.NODE_ENV === "production") return;
3767
+ const firstExplicitLabel = /* @__PURE__ */ new Map();
3768
+ const warnedGroups = /* @__PURE__ */ new Set();
3769
+ for (const opt of options) {
3770
+ if (!opt.group || opt.groupLabel === void 0) continue;
3771
+ const firstLabel = firstExplicitLabel.get(opt.group);
3772
+ if (firstLabel === void 0) {
3773
+ firstExplicitLabel.set(opt.group, opt.groupLabel);
3774
+ } else if (firstLabel !== opt.groupLabel && !warnedGroups.has(opt.group)) {
3775
+ warnedGroups.add(opt.group);
3776
+ console.warn(
3777
+ `[FFIDInquiryForm] group "${opt.group}" has conflicting groupLabels: "${firstLabel}" (first-wins) vs "${opt.groupLabel}" (ignored). Pass the same groupLabel for every item in the group, or omit it on all but the first.`
3778
+ );
3779
+ }
3780
+ }
3781
+ }
3672
3782
  function renderCategoryOptions(options) {
3673
3783
  const hasAnyGroup = options.some((o) => !!o.group);
3674
3784
  if (!hasAnyGroup) {
@@ -3721,6 +3831,9 @@ function FFIDInquiryForm({
3721
3831
  () => categories && categories.length > 0 ? categories : defaultCategories(),
3722
3832
  [categories]
3723
3833
  );
3834
+ useEffect(() => {
3835
+ warnOnGroupLabelConflicts(categoryOptions);
3836
+ }, [categoryOptions]);
3724
3837
  const initialOrgId = useMemo(() => {
3725
3838
  if (!isAuth) return null;
3726
3839
  if (preselectedOrganizationId !== void 0) return preselectedOrganizationId;
@@ -3754,6 +3867,8 @@ function FFIDInquiryForm({
3754
3867
  const [agreedLegal, setAgreedLegal] = useState(false);
3755
3868
  const [agreedTerms, setAgreedTerms] = useState(false);
3756
3869
  const [agreedPrivacy, setAgreedPrivacy] = useState(false);
3870
+ const [agreedTermsError, setAgreedTermsError] = useState(false);
3871
+ const [agreedPrivacyError, setAgreedPrivacyError] = useState(false);
3757
3872
  const [submitting, setSubmitting] = useState(false);
3758
3873
  const [formError, setFormError] = useState(null);
3759
3874
  const [successMessage, setSuccessMessage] = useState(null);
@@ -3771,7 +3886,7 @@ function FFIDInquiryForm({
3771
3886
  onChangeRef.current = onChange;
3772
3887
  }, [onChange]);
3773
3888
  useEffect(() => {
3774
- if (category === "") return;
3889
+ if (category === "" || successMessage) return;
3775
3890
  onChangeRef.current?.({
3776
3891
  name: name.trim(),
3777
3892
  email: email.trim(),
@@ -3800,25 +3915,19 @@ function FFIDInquiryForm({
3800
3915
  termsVersion,
3801
3916
  privacyVersion,
3802
3917
  turnstileToken,
3803
- locale
3918
+ locale,
3919
+ successMessage
3804
3920
  ]);
3805
3921
  const s = (style) => styleOrUndefined(style, unstyled);
3806
3922
  async function handleSubmit(e) {
3807
3923
  e.preventDefault();
3808
3924
  setFormError(null);
3809
3925
  if (separateLegalCheckboxes) {
3810
- if (!agreedTerms && !agreedPrivacy) {
3811
- setFormError("\u5229\u7528\u898F\u7D04\u3068\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3812
- return;
3813
- }
3814
- if (!agreedTerms) {
3815
- setFormError("\u5229\u7528\u898F\u7D04\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3816
- return;
3817
- }
3818
- if (!agreedPrivacy) {
3819
- setFormError("\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3820
- return;
3821
- }
3926
+ const termsInvalid = !agreedTerms;
3927
+ const privacyInvalid = !agreedPrivacy;
3928
+ setAgreedTermsError(termsInvalid);
3929
+ setAgreedPrivacyError(privacyInvalid);
3930
+ if (termsInvalid || privacyInvalid) return;
3822
3931
  } else if (!agreedLegal) {
3823
3932
  setFormError("\u5229\u7528\u898F\u7D04\u3068\u30D7\u30E9\u30A4\u30D0\u30B7\u30FC\u30DD\u30EA\u30B7\u30FC\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002");
3824
3933
  return;
@@ -3835,6 +3944,10 @@ function FFIDInquiryForm({
3835
3944
  setFormError("\u304A\u540D\u524D\u3068\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
3836
3945
  return;
3837
3946
  }
3947
+ if (!isAuth && !hasSatisfiedTurnstile(turnstileSlot, turnstileToken)) {
3948
+ setFormError(TURNSTILE_PENDING_ERROR_JA);
3949
+ return;
3950
+ }
3838
3951
  setSubmitting(true);
3839
3952
  try {
3840
3953
  const result = await onSubmit({
@@ -3912,7 +4025,7 @@ function FFIDInquiryForm({
3912
4025
  onSubmit: handleSubmit,
3913
4026
  className: cx(className, classNames?.form),
3914
4027
  noValidate: true,
3915
- "data-hydrated": hydrated ? "true" : void 0,
4028
+ "data-hydrated": hydrated ? "true" : "false",
3916
4029
  children: [
3917
4030
  showOrgBlock && /* @__PURE__ */ jsxs("div", { style: s(fieldsetStyle), className: cx(classNames?.field, classNames?.orgSelectWrapper), children: [
3918
4031
  /* @__PURE__ */ jsx("label", { style: s(labelStyle), className: classNames?.label, htmlFor: "ffid-inquiry-org", children: "\u554F\u3044\u5408\u308F\u305B\u308B\u7ACB\u5834" }),
@@ -4079,7 +4192,11 @@ function FFIDInquiryForm({
4079
4192
  type: "checkbox",
4080
4193
  className: classNames?.legalCheckbox,
4081
4194
  checked: agreedTerms,
4082
- onChange: (e) => setAgreedTerms(e.target.checked),
4195
+ onChange: (e) => {
4196
+ const checked = e.target.checked;
4197
+ setAgreedTerms(checked);
4198
+ if (checked) setAgreedTermsError(false);
4199
+ },
4083
4200
  required: true
4084
4201
  }
4085
4202
  ),
@@ -4088,6 +4205,7 @@ function FFIDInquiryForm({
4088
4205
  " \u306B\u540C\u610F\u3057\u307E\u3059\u3002"
4089
4206
  ] })
4090
4207
  ] }),
4208
+ agreedTermsError && /* @__PURE__ */ jsx("p", { role: "alert", style: s(errorTextStyle), className: classNames?.errorText, children: TERMS_REQUIRED_ERROR_JA }),
4091
4209
  /* @__PURE__ */ jsxs("label", { style: s(legalRowLast), className: classNames?.legalRow, children: [
4092
4210
  /* @__PURE__ */ jsx(
4093
4211
  "input",
@@ -4095,7 +4213,11 @@ function FFIDInquiryForm({
4095
4213
  type: "checkbox",
4096
4214
  className: classNames?.legalCheckbox,
4097
4215
  checked: agreedPrivacy,
4098
- onChange: (e) => setAgreedPrivacy(e.target.checked),
4216
+ onChange: (e) => {
4217
+ const checked = e.target.checked;
4218
+ setAgreedPrivacy(checked);
4219
+ if (checked) setAgreedPrivacyError(false);
4220
+ },
4099
4221
  required: true
4100
4222
  }
4101
4223
  ),
@@ -4103,7 +4225,8 @@ function FFIDInquiryForm({
4103
4225
  renderPrivacyLink(),
4104
4226
  " \u306B\u540C\u610F\u3057\u307E\u3059\u3002"
4105
4227
  ] })
4106
- ] })
4228
+ ] }),
4229
+ agreedPrivacyError && /* @__PURE__ */ jsx("p", { role: "alert", style: s(errorTextStyle), className: classNames?.errorText, children: PRIVACY_REQUIRED_ERROR_JA })
4107
4230
  ] }) : /* @__PURE__ */ jsx("div", { style: s(fieldsetStyle), className: classNames?.legalBlock, children: /* @__PURE__ */ jsxs("label", { style: s(legalRowLast), className: classNames?.legalRow, children: [
4108
4231
  /* @__PURE__ */ jsx(
4109
4232
  "input",
@@ -4151,4 +4274,4 @@ function FFIDInquiryForm({
4151
4274
  );
4152
4275
  }
4153
4276
 
4154
- export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
4277
+ export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };