@feelflow/ffid-sdk 2.6.0 → 2.8.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.
@@ -617,7 +617,7 @@ function createMembersMethods(deps) {
617
617
  }
618
618
 
619
619
  // src/client/version-check.ts
620
- var SDK_VERSION = "2.6.0";
620
+ var SDK_VERSION = "2.8.0";
621
621
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
622
622
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
623
623
  function sdkHeaders() {
@@ -1548,6 +1548,168 @@ function createContractWizardMethods(deps) {
1548
1548
  };
1549
1549
  }
1550
1550
 
1551
+ // src/newsletter/ffid-newsletter-client.ts
1552
+ var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
1553
+ var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
1554
+ var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
1555
+ function trimOrEmpty(s) {
1556
+ return typeof s === "string" ? s.trim() : "";
1557
+ }
1558
+ async function postPublic(url, init, opts) {
1559
+ let response;
1560
+ try {
1561
+ response = await fetch(url, init);
1562
+ } catch (err) {
1563
+ return {
1564
+ error: opts.createError(
1565
+ "NETWORK_ERROR",
1566
+ err instanceof Error ? err.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1567
+ )
1568
+ };
1569
+ }
1570
+ if (!response.ok) {
1571
+ try {
1572
+ const body = await response.json();
1573
+ if (body?.error?.code || body?.error?.message) {
1574
+ return {
1575
+ error: opts.createError(
1576
+ body.error.code ?? "UNKNOWN_ERROR",
1577
+ body.error.message ?? `${opts.fallbackMessage} (status: ${response.status})`
1578
+ )
1579
+ };
1580
+ }
1581
+ } catch {
1582
+ }
1583
+ return {
1584
+ error: opts.createError(
1585
+ "NETWORK_ERROR",
1586
+ `${opts.fallbackMessage} (status: ${response.status})`
1587
+ )
1588
+ };
1589
+ }
1590
+ return { data: opts.success };
1591
+ }
1592
+ function createNewsletterMethods(deps) {
1593
+ const { fetchWithAuth, baseUrl, createError } = deps;
1594
+ async function subscribe(params) {
1595
+ const email = trimOrEmpty(params.email);
1596
+ const source = trimOrEmpty(params.source);
1597
+ if (!email) {
1598
+ return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
1599
+ }
1600
+ if (!source) {
1601
+ return { error: createError("VALIDATION_ERROR", "source \u306F\u5FC5\u9808\u3067\u3059") };
1602
+ }
1603
+ if (!Array.isArray(params.types) || params.types.length === 0) {
1604
+ return {
1605
+ error: createError(
1606
+ "VALIDATION_ERROR",
1607
+ "types \u306B\u306F1\u3064\u4EE5\u4E0A\u306E newsletter \u7A2E\u5225\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
1608
+ )
1609
+ };
1610
+ }
1611
+ return fetchWithAuth(
1612
+ EXT_SUBSCRIBE_ENDPOINT2,
1613
+ {
1614
+ method: "POST",
1615
+ body: JSON.stringify({
1616
+ email,
1617
+ types: params.types,
1618
+ source,
1619
+ locale: params.locale
1620
+ })
1621
+ }
1622
+ );
1623
+ }
1624
+ async function confirm(params) {
1625
+ const token = trimOrEmpty(params.token);
1626
+ if (!token) {
1627
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1628
+ }
1629
+ return postPublic(
1630
+ `${baseUrl}${CONFIRM_ENDPOINT}`,
1631
+ {
1632
+ method: "POST",
1633
+ headers: { "Content-Type": "application/json" },
1634
+ body: JSON.stringify({ token })
1635
+ },
1636
+ {
1637
+ success: { ok: true },
1638
+ createError,
1639
+ fallbackMessage: "\u78BA\u8A8D\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1640
+ }
1641
+ );
1642
+ }
1643
+ async function unsubscribe(params) {
1644
+ const token = trimOrEmpty(params.token);
1645
+ if (!token) {
1646
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1647
+ }
1648
+ const url = new URL(`${baseUrl}${UNSUBSCRIBE_ENDPOINT}`);
1649
+ url.searchParams.set("token", token);
1650
+ return postPublic(
1651
+ url.toString(),
1652
+ { method: "POST" },
1653
+ {
1654
+ success: { ok: true },
1655
+ createError,
1656
+ fallbackMessage: "\u89E3\u9664\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1657
+ }
1658
+ );
1659
+ }
1660
+ return { subscribe, confirm, unsubscribe };
1661
+ }
1662
+
1663
+ // src/inquiry/ffid-inquiry-client.ts
1664
+ var EXT_INQUIRY_ENDPOINT = "/api/v1/ext/inquiry";
1665
+ function trimOrEmpty2(s) {
1666
+ return typeof s === "string" ? s.trim() : "";
1667
+ }
1668
+ function createInquiryMethods(deps) {
1669
+ const { fetchWithAuth, createError } = deps;
1670
+ async function create(params) {
1671
+ const email = trimOrEmpty2(params.email);
1672
+ const name = trimOrEmpty2(params.name);
1673
+ const message = trimOrEmpty2(params.message);
1674
+ const termsVersion = trimOrEmpty2(params.termsVersion);
1675
+ const privacyVersion = trimOrEmpty2(params.privacyVersion);
1676
+ if (!email) return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
1677
+ if (!name) return { error: createError("VALIDATION_ERROR", "name \u306F\u5FC5\u9808\u3067\u3059") };
1678
+ if (!message) return { error: createError("VALIDATION_ERROR", "message \u306F\u5FC5\u9808\u3067\u3059") };
1679
+ if (!termsVersion) {
1680
+ return { error: createError("VALIDATION_ERROR", "termsVersion \u306F\u5FC5\u9808\u3067\u3059") };
1681
+ }
1682
+ if (!privacyVersion) {
1683
+ return { error: createError("VALIDATION_ERROR", "privacyVersion \u306F\u5FC5\u9808\u3067\u3059") };
1684
+ }
1685
+ const inquiryFollowupOptIn = params.inquiryFollowupOptIn === true;
1686
+ const generalNewsletterOptIn = params.generalNewsletterOptIn === true;
1687
+ return fetchWithAuth(EXT_INQUIRY_ENDPOINT, {
1688
+ method: "POST",
1689
+ body: JSON.stringify({
1690
+ email,
1691
+ name,
1692
+ message,
1693
+ category: params.category,
1694
+ company: params.company,
1695
+ phone: params.phone,
1696
+ locale: params.locale,
1697
+ termsVersion,
1698
+ privacyVersion,
1699
+ // The ext endpoint still accepts the legacy single-flag field, but
1700
+ // the SDK always submits the 2-layer model. `newsletterOptIn` is
1701
+ // passed as the union of the two new flags only to satisfy the
1702
+ // current schema's required bool — the server preferentially
1703
+ // reads `inquiryFollowupOptIn` / `generalNewsletterOptIn`.
1704
+ newsletterOptIn: inquiryFollowupOptIn || generalNewsletterOptIn,
1705
+ inquiryFollowupOptIn,
1706
+ generalNewsletterOptIn
1707
+ })
1708
+ });
1709
+ }
1710
+ return { create };
1711
+ }
1712
+
1551
1713
  // src/client/ffid-client.ts
1552
1714
  var UNAUTHORIZED_STATUS2 = 401;
1553
1715
  var SDK_LOG_PREFIX = "[FFID SDK]";
@@ -1823,6 +1985,15 @@ function createFFIDClient(config) {
1823
1985
  createError,
1824
1986
  errorCodes: FFID_ERROR_CODES
1825
1987
  });
1988
+ const newsletter = createNewsletterMethods({
1989
+ fetchWithAuth,
1990
+ baseUrl,
1991
+ createError
1992
+ });
1993
+ const inquiry = createInquiryMethods({
1994
+ fetchWithAuth,
1995
+ createError
1996
+ });
1826
1997
  const verifyAccessToken = createVerifyAccessToken({
1827
1998
  authMode,
1828
1999
  baseUrl,
@@ -1877,6 +2048,10 @@ function createFFIDClient(config) {
1877
2048
  confirmPasswordReset,
1878
2049
  sendOtp,
1879
2050
  verifyOtp,
2051
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
2052
+ newsletter,
2053
+ /** Inquiry methods (create) */
2054
+ inquiry,
1880
2055
  /** Token store (token mode only) */
1881
2056
  tokenStore,
1882
2057
  /** Resolved auth mode */
@@ -1,5 +1,93 @@
1
1
  export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.cjs';
2
2
 
3
+ /**
4
+ * Inquiry types exposed by the FFID SDK.
5
+ *
6
+ * Mirrors the `/api/v1/ext/inquiry` and `/api/contact` endpoints
7
+ * with a single shared shape so that consumers can render one
8
+ * `<FFIDInquiryForm />` and submit through either endpoint.
9
+ */
10
+ /**
11
+ * Categories surfaced by the default form. Consumers are free to
12
+ * pass their own list via `<FFIDInquiryForm categories={...} />`.
13
+ */
14
+ declare const FFID_INQUIRY_CATEGORIES: readonly ["general", "sales", "support", "partnership", "press", "other"];
15
+ type FFIDInquiryCategory = (typeof FFID_INQUIRY_CATEGORIES)[number];
16
+ /**
17
+ * Parameters for `client.inquiry.create()`. When submitting from a
18
+ * server-side SDK (Service API Key), set `source` to a stable
19
+ * origin string so admins can trace the submission back.
20
+ */
21
+ interface FFIDInquiryCreateParams {
22
+ email: string;
23
+ name: string;
24
+ message: string;
25
+ category?: FFIDInquiryCategory | (string & {});
26
+ company?: string;
27
+ phone?: string;
28
+ locale?: 'ja' | 'en';
29
+ /** Current terms-of-service version the submitter agreed to. */
30
+ termsVersion: string;
31
+ /** Current privacy-policy version the submitter agreed to. */
32
+ privacyVersion: string;
33
+ /** Opt-in to the post-inquiry follow-up newsletter (Type A). */
34
+ inquiryFollowupOptIn?: boolean;
35
+ /** Opt-in to the general marketing newsletter (Type B). */
36
+ generalNewsletterOptIn?: boolean;
37
+ }
38
+ interface FFIDInquiryCreateResponse {
39
+ ok: true;
40
+ inquiryId: string;
41
+ /** True only when the submitter is already a confirmed newsletter subscriber. */
42
+ newsletterSubscribed: boolean;
43
+ }
44
+
45
+ /**
46
+ * Newsletter types exposed by the FFID SDK.
47
+ *
48
+ * 2-layer newsletter model (#2078):
49
+ * - `inquiry_followup`: 問い合わせフォローアップ (Type A)
50
+ * - `general`: 定期ニュースレター (Type B)
51
+ *
52
+ * FFID account holders' preferences live in `user_marketing_preferences`;
53
+ * anonymous subscribers live in `newsletter_subscribers` with double
54
+ * opt-in required.
55
+ */
56
+ declare const FFID_NEWSLETTER_TYPES: readonly ["inquiry_followup", "general"];
57
+ type FFIDNewsletterType = (typeof FFID_NEWSLETTER_TYPES)[number];
58
+ interface FFIDNewsletterSubscribeParams {
59
+ /** Subscriber email address */
60
+ email: string;
61
+ /** One or more newsletter types to opt in to */
62
+ types: FFIDNewsletterType[];
63
+ /** Origin string recorded on the subscriber row (e.g. your service code) */
64
+ source: string;
65
+ /** ISO 639-1 locale (e.g. 'ja', 'en') */
66
+ locale?: string;
67
+ }
68
+ interface FFIDNewsletterSubscribeResponse {
69
+ ok: true;
70
+ /** True when a double opt-in confirmation email was sent */
71
+ requiresConfirmation: boolean;
72
+ /** True when the email matched an existing FFID account; the caller
73
+ * must sign in to update preferences. Preferences are NOT modified. */
74
+ requiresSignIn: boolean;
75
+ }
76
+ interface FFIDNewsletterConfirmParams {
77
+ /** Confirmation token received in the double opt-in email */
78
+ token: string;
79
+ }
80
+ interface FFIDNewsletterConfirmResponse {
81
+ ok: true;
82
+ }
83
+ interface FFIDNewsletterUnsubscribeParams {
84
+ /** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
85
+ token: string;
86
+ }
87
+ interface FFIDNewsletterUnsubscribeResponse {
88
+ ok: true;
89
+ }
90
+
3
91
  /** Cache adapter interface for FFID SDK token verification */
4
92
  /**
5
93
  * Pluggable cache adapter interface.
@@ -779,6 +867,16 @@ declare function createFFIDClient(config: FFIDConfig): {
779
867
  accessToken: string;
780
868
  refreshToken: string;
781
869
  }) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
870
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
871
+ newsletter: {
872
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
873
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
874
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
875
+ };
876
+ /** Inquiry methods (create) */
877
+ inquiry: {
878
+ create: (params: FFIDInquiryCreateParams) => Promise<FFIDApiResponse<FFIDInquiryCreateResponse>>;
879
+ };
782
880
  /** Token store (token mode only) */
783
881
  tokenStore: TokenStore;
784
882
  /** Resolved auth mode */
@@ -1,5 +1,93 @@
1
1
  export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.js';
2
2
 
3
+ /**
4
+ * Inquiry types exposed by the FFID SDK.
5
+ *
6
+ * Mirrors the `/api/v1/ext/inquiry` and `/api/contact` endpoints
7
+ * with a single shared shape so that consumers can render one
8
+ * `<FFIDInquiryForm />` and submit through either endpoint.
9
+ */
10
+ /**
11
+ * Categories surfaced by the default form. Consumers are free to
12
+ * pass their own list via `<FFIDInquiryForm categories={...} />`.
13
+ */
14
+ declare const FFID_INQUIRY_CATEGORIES: readonly ["general", "sales", "support", "partnership", "press", "other"];
15
+ type FFIDInquiryCategory = (typeof FFID_INQUIRY_CATEGORIES)[number];
16
+ /**
17
+ * Parameters for `client.inquiry.create()`. When submitting from a
18
+ * server-side SDK (Service API Key), set `source` to a stable
19
+ * origin string so admins can trace the submission back.
20
+ */
21
+ interface FFIDInquiryCreateParams {
22
+ email: string;
23
+ name: string;
24
+ message: string;
25
+ category?: FFIDInquiryCategory | (string & {});
26
+ company?: string;
27
+ phone?: string;
28
+ locale?: 'ja' | 'en';
29
+ /** Current terms-of-service version the submitter agreed to. */
30
+ termsVersion: string;
31
+ /** Current privacy-policy version the submitter agreed to. */
32
+ privacyVersion: string;
33
+ /** Opt-in to the post-inquiry follow-up newsletter (Type A). */
34
+ inquiryFollowupOptIn?: boolean;
35
+ /** Opt-in to the general marketing newsletter (Type B). */
36
+ generalNewsletterOptIn?: boolean;
37
+ }
38
+ interface FFIDInquiryCreateResponse {
39
+ ok: true;
40
+ inquiryId: string;
41
+ /** True only when the submitter is already a confirmed newsletter subscriber. */
42
+ newsletterSubscribed: boolean;
43
+ }
44
+
45
+ /**
46
+ * Newsletter types exposed by the FFID SDK.
47
+ *
48
+ * 2-layer newsletter model (#2078):
49
+ * - `inquiry_followup`: 問い合わせフォローアップ (Type A)
50
+ * - `general`: 定期ニュースレター (Type B)
51
+ *
52
+ * FFID account holders' preferences live in `user_marketing_preferences`;
53
+ * anonymous subscribers live in `newsletter_subscribers` with double
54
+ * opt-in required.
55
+ */
56
+ declare const FFID_NEWSLETTER_TYPES: readonly ["inquiry_followup", "general"];
57
+ type FFIDNewsletterType = (typeof FFID_NEWSLETTER_TYPES)[number];
58
+ interface FFIDNewsletterSubscribeParams {
59
+ /** Subscriber email address */
60
+ email: string;
61
+ /** One or more newsletter types to opt in to */
62
+ types: FFIDNewsletterType[];
63
+ /** Origin string recorded on the subscriber row (e.g. your service code) */
64
+ source: string;
65
+ /** ISO 639-1 locale (e.g. 'ja', 'en') */
66
+ locale?: string;
67
+ }
68
+ interface FFIDNewsletterSubscribeResponse {
69
+ ok: true;
70
+ /** True when a double opt-in confirmation email was sent */
71
+ requiresConfirmation: boolean;
72
+ /** True when the email matched an existing FFID account; the caller
73
+ * must sign in to update preferences. Preferences are NOT modified. */
74
+ requiresSignIn: boolean;
75
+ }
76
+ interface FFIDNewsletterConfirmParams {
77
+ /** Confirmation token received in the double opt-in email */
78
+ token: string;
79
+ }
80
+ interface FFIDNewsletterConfirmResponse {
81
+ ok: true;
82
+ }
83
+ interface FFIDNewsletterUnsubscribeParams {
84
+ /** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
85
+ token: string;
86
+ }
87
+ interface FFIDNewsletterUnsubscribeResponse {
88
+ ok: true;
89
+ }
90
+
3
91
  /** Cache adapter interface for FFID SDK token verification */
4
92
  /**
5
93
  * Pluggable cache adapter interface.
@@ -779,6 +867,16 @@ declare function createFFIDClient(config: FFIDConfig): {
779
867
  accessToken: string;
780
868
  refreshToken: string;
781
869
  }) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
870
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
871
+ newsletter: {
872
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
873
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
874
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
875
+ };
876
+ /** Inquiry methods (create) */
877
+ inquiry: {
878
+ create: (params: FFIDInquiryCreateParams) => Promise<FFIDApiResponse<FFIDInquiryCreateResponse>>;
879
+ };
782
880
  /** Token store (token mode only) */
783
881
  tokenStore: TokenStore;
784
882
  /** Resolved auth mode */
@@ -616,7 +616,7 @@ function createMembersMethods(deps) {
616
616
  }
617
617
 
618
618
  // src/client/version-check.ts
619
- var SDK_VERSION = "2.6.0";
619
+ var SDK_VERSION = "2.8.0";
620
620
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
621
621
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
622
622
  function sdkHeaders() {
@@ -1547,6 +1547,168 @@ function createContractWizardMethods(deps) {
1547
1547
  };
1548
1548
  }
1549
1549
 
1550
+ // src/newsletter/ffid-newsletter-client.ts
1551
+ var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
1552
+ var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
1553
+ var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
1554
+ function trimOrEmpty(s) {
1555
+ return typeof s === "string" ? s.trim() : "";
1556
+ }
1557
+ async function postPublic(url, init, opts) {
1558
+ let response;
1559
+ try {
1560
+ response = await fetch(url, init);
1561
+ } catch (err) {
1562
+ return {
1563
+ error: opts.createError(
1564
+ "NETWORK_ERROR",
1565
+ err instanceof Error ? err.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1566
+ )
1567
+ };
1568
+ }
1569
+ if (!response.ok) {
1570
+ try {
1571
+ const body = await response.json();
1572
+ if (body?.error?.code || body?.error?.message) {
1573
+ return {
1574
+ error: opts.createError(
1575
+ body.error.code ?? "UNKNOWN_ERROR",
1576
+ body.error.message ?? `${opts.fallbackMessage} (status: ${response.status})`
1577
+ )
1578
+ };
1579
+ }
1580
+ } catch {
1581
+ }
1582
+ return {
1583
+ error: opts.createError(
1584
+ "NETWORK_ERROR",
1585
+ `${opts.fallbackMessage} (status: ${response.status})`
1586
+ )
1587
+ };
1588
+ }
1589
+ return { data: opts.success };
1590
+ }
1591
+ function createNewsletterMethods(deps) {
1592
+ const { fetchWithAuth, baseUrl, createError } = deps;
1593
+ async function subscribe(params) {
1594
+ const email = trimOrEmpty(params.email);
1595
+ const source = trimOrEmpty(params.source);
1596
+ if (!email) {
1597
+ return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
1598
+ }
1599
+ if (!source) {
1600
+ return { error: createError("VALIDATION_ERROR", "source \u306F\u5FC5\u9808\u3067\u3059") };
1601
+ }
1602
+ if (!Array.isArray(params.types) || params.types.length === 0) {
1603
+ return {
1604
+ error: createError(
1605
+ "VALIDATION_ERROR",
1606
+ "types \u306B\u306F1\u3064\u4EE5\u4E0A\u306E newsletter \u7A2E\u5225\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
1607
+ )
1608
+ };
1609
+ }
1610
+ return fetchWithAuth(
1611
+ EXT_SUBSCRIBE_ENDPOINT2,
1612
+ {
1613
+ method: "POST",
1614
+ body: JSON.stringify({
1615
+ email,
1616
+ types: params.types,
1617
+ source,
1618
+ locale: params.locale
1619
+ })
1620
+ }
1621
+ );
1622
+ }
1623
+ async function confirm(params) {
1624
+ const token = trimOrEmpty(params.token);
1625
+ if (!token) {
1626
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1627
+ }
1628
+ return postPublic(
1629
+ `${baseUrl}${CONFIRM_ENDPOINT}`,
1630
+ {
1631
+ method: "POST",
1632
+ headers: { "Content-Type": "application/json" },
1633
+ body: JSON.stringify({ token })
1634
+ },
1635
+ {
1636
+ success: { ok: true },
1637
+ createError,
1638
+ fallbackMessage: "\u78BA\u8A8D\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1639
+ }
1640
+ );
1641
+ }
1642
+ async function unsubscribe(params) {
1643
+ const token = trimOrEmpty(params.token);
1644
+ if (!token) {
1645
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1646
+ }
1647
+ const url = new URL(`${baseUrl}${UNSUBSCRIBE_ENDPOINT}`);
1648
+ url.searchParams.set("token", token);
1649
+ return postPublic(
1650
+ url.toString(),
1651
+ { method: "POST" },
1652
+ {
1653
+ success: { ok: true },
1654
+ createError,
1655
+ fallbackMessage: "\u89E3\u9664\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1656
+ }
1657
+ );
1658
+ }
1659
+ return { subscribe, confirm, unsubscribe };
1660
+ }
1661
+
1662
+ // src/inquiry/ffid-inquiry-client.ts
1663
+ var EXT_INQUIRY_ENDPOINT = "/api/v1/ext/inquiry";
1664
+ function trimOrEmpty2(s) {
1665
+ return typeof s === "string" ? s.trim() : "";
1666
+ }
1667
+ function createInquiryMethods(deps) {
1668
+ const { fetchWithAuth, createError } = deps;
1669
+ async function create(params) {
1670
+ const email = trimOrEmpty2(params.email);
1671
+ const name = trimOrEmpty2(params.name);
1672
+ const message = trimOrEmpty2(params.message);
1673
+ const termsVersion = trimOrEmpty2(params.termsVersion);
1674
+ const privacyVersion = trimOrEmpty2(params.privacyVersion);
1675
+ if (!email) return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
1676
+ if (!name) return { error: createError("VALIDATION_ERROR", "name \u306F\u5FC5\u9808\u3067\u3059") };
1677
+ if (!message) return { error: createError("VALIDATION_ERROR", "message \u306F\u5FC5\u9808\u3067\u3059") };
1678
+ if (!termsVersion) {
1679
+ return { error: createError("VALIDATION_ERROR", "termsVersion \u306F\u5FC5\u9808\u3067\u3059") };
1680
+ }
1681
+ if (!privacyVersion) {
1682
+ return { error: createError("VALIDATION_ERROR", "privacyVersion \u306F\u5FC5\u9808\u3067\u3059") };
1683
+ }
1684
+ const inquiryFollowupOptIn = params.inquiryFollowupOptIn === true;
1685
+ const generalNewsletterOptIn = params.generalNewsletterOptIn === true;
1686
+ return fetchWithAuth(EXT_INQUIRY_ENDPOINT, {
1687
+ method: "POST",
1688
+ body: JSON.stringify({
1689
+ email,
1690
+ name,
1691
+ message,
1692
+ category: params.category,
1693
+ company: params.company,
1694
+ phone: params.phone,
1695
+ locale: params.locale,
1696
+ termsVersion,
1697
+ privacyVersion,
1698
+ // The ext endpoint still accepts the legacy single-flag field, but
1699
+ // the SDK always submits the 2-layer model. `newsletterOptIn` is
1700
+ // passed as the union of the two new flags only to satisfy the
1701
+ // current schema's required bool — the server preferentially
1702
+ // reads `inquiryFollowupOptIn` / `generalNewsletterOptIn`.
1703
+ newsletterOptIn: inquiryFollowupOptIn || generalNewsletterOptIn,
1704
+ inquiryFollowupOptIn,
1705
+ generalNewsletterOptIn
1706
+ })
1707
+ });
1708
+ }
1709
+ return { create };
1710
+ }
1711
+
1550
1712
  // src/client/ffid-client.ts
1551
1713
  var UNAUTHORIZED_STATUS2 = 401;
1552
1714
  var SDK_LOG_PREFIX = "[FFID SDK]";
@@ -1822,6 +1984,15 @@ function createFFIDClient(config) {
1822
1984
  createError,
1823
1985
  errorCodes: FFID_ERROR_CODES
1824
1986
  });
1987
+ const newsletter = createNewsletterMethods({
1988
+ fetchWithAuth,
1989
+ baseUrl,
1990
+ createError
1991
+ });
1992
+ const inquiry = createInquiryMethods({
1993
+ fetchWithAuth,
1994
+ createError
1995
+ });
1825
1996
  const verifyAccessToken = createVerifyAccessToken({
1826
1997
  authMode,
1827
1998
  baseUrl,
@@ -1876,6 +2047,10 @@ function createFFIDClient(config) {
1876
2047
  confirmPasswordReset,
1877
2048
  sendOtp,
1878
2049
  verifyOtp,
2050
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
2051
+ newsletter,
2052
+ /** Inquiry methods (create) */
2053
+ inquiry,
1879
2054
  /** Token store (token mode only) */
1880
2055
  tokenStore,
1881
2056
  /** Resolved auth mode */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feelflow/ffid-sdk",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "FeelFlow ID Platform SDK for React/Next.js applications",
5
5
  "keywords": [
6
6
  "feelflow",