@feelflow/ffid-sdk 2.6.0 → 2.7.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.
@@ -621,7 +621,7 @@ function createMembersMethods(deps) {
621
621
  }
622
622
 
623
623
  // src/client/version-check.ts
624
- var SDK_VERSION = "2.6.0";
624
+ var SDK_VERSION = "2.7.0";
625
625
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
626
626
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
627
627
  function sdkHeaders() {
@@ -1565,6 +1565,118 @@ function createContractWizardMethods(deps) {
1565
1565
  };
1566
1566
  }
1567
1567
 
1568
+ // src/newsletter/ffid-newsletter-client.ts
1569
+ var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
1570
+ var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
1571
+ var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
1572
+ function trimOrEmpty(s) {
1573
+ return typeof s === "string" ? s.trim() : "";
1574
+ }
1575
+ async function postPublic(url, init, opts) {
1576
+ let response;
1577
+ try {
1578
+ response = await fetch(url, init);
1579
+ } catch (err) {
1580
+ return {
1581
+ error: opts.createError(
1582
+ "NETWORK_ERROR",
1583
+ err instanceof Error ? err.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1584
+ )
1585
+ };
1586
+ }
1587
+ if (!response.ok) {
1588
+ try {
1589
+ const body = await response.json();
1590
+ if (body?.error?.code || body?.error?.message) {
1591
+ return {
1592
+ error: opts.createError(
1593
+ body.error.code ?? "UNKNOWN_ERROR",
1594
+ body.error.message ?? `${opts.fallbackMessage} (status: ${response.status})`
1595
+ )
1596
+ };
1597
+ }
1598
+ } catch {
1599
+ }
1600
+ return {
1601
+ error: opts.createError(
1602
+ "NETWORK_ERROR",
1603
+ `${opts.fallbackMessage} (status: ${response.status})`
1604
+ )
1605
+ };
1606
+ }
1607
+ return { data: opts.success };
1608
+ }
1609
+ function createNewsletterMethods(deps) {
1610
+ const { fetchWithAuth, baseUrl, createError } = deps;
1611
+ async function subscribe(params) {
1612
+ const email = trimOrEmpty(params.email);
1613
+ const source = trimOrEmpty(params.source);
1614
+ if (!email) {
1615
+ return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
1616
+ }
1617
+ if (!source) {
1618
+ return { error: createError("VALIDATION_ERROR", "source \u306F\u5FC5\u9808\u3067\u3059") };
1619
+ }
1620
+ if (!Array.isArray(params.types) || params.types.length === 0) {
1621
+ return {
1622
+ error: createError(
1623
+ "VALIDATION_ERROR",
1624
+ "types \u306B\u306F1\u3064\u4EE5\u4E0A\u306E newsletter \u7A2E\u5225\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
1625
+ )
1626
+ };
1627
+ }
1628
+ return fetchWithAuth(
1629
+ EXT_SUBSCRIBE_ENDPOINT2,
1630
+ {
1631
+ method: "POST",
1632
+ body: JSON.stringify({
1633
+ email,
1634
+ types: params.types,
1635
+ source,
1636
+ locale: params.locale
1637
+ })
1638
+ }
1639
+ );
1640
+ }
1641
+ async function confirm(params) {
1642
+ const token = trimOrEmpty(params.token);
1643
+ if (!token) {
1644
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1645
+ }
1646
+ return postPublic(
1647
+ `${baseUrl}${CONFIRM_ENDPOINT}`,
1648
+ {
1649
+ method: "POST",
1650
+ headers: { "Content-Type": "application/json" },
1651
+ body: JSON.stringify({ token })
1652
+ },
1653
+ {
1654
+ success: { ok: true },
1655
+ createError,
1656
+ fallbackMessage: "\u78BA\u8A8D\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1657
+ }
1658
+ );
1659
+ }
1660
+ async function unsubscribe(params) {
1661
+ const token = trimOrEmpty(params.token);
1662
+ if (!token) {
1663
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1664
+ }
1665
+ const url = new URL(`${baseUrl}${UNSUBSCRIBE_ENDPOINT}`);
1666
+ url.searchParams.set("token", token);
1667
+ return postPublic(
1668
+ url.toString(),
1669
+ { method: "POST" },
1670
+ {
1671
+ success: { ok: true },
1672
+ createError,
1673
+ fallbackMessage: "\u89E3\u9664\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1674
+ }
1675
+ );
1676
+ }
1677
+ return { subscribe, confirm, unsubscribe };
1678
+ }
1679
+
1568
1680
  // src/client/ffid-client.ts
1569
1681
  var UNAUTHORIZED_STATUS2 = 401;
1570
1682
  var SDK_LOG_PREFIX = "[FFID SDK]";
@@ -1840,6 +1952,11 @@ function createFFIDClient(config) {
1840
1952
  createError,
1841
1953
  errorCodes: FFID_ERROR_CODES
1842
1954
  });
1955
+ const newsletter = createNewsletterMethods({
1956
+ fetchWithAuth,
1957
+ baseUrl,
1958
+ createError
1959
+ });
1843
1960
  const verifyAccessToken = createVerifyAccessToken({
1844
1961
  authMode,
1845
1962
  baseUrl,
@@ -1894,6 +2011,8 @@ function createFFIDClient(config) {
1894
2011
  confirmPasswordReset,
1895
2012
  sendOtp,
1896
2013
  verifyOtp,
2014
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
2015
+ newsletter,
1897
2016
  /** Token store (token mode only) */
1898
2017
  tokenStore,
1899
2018
  /** Resolved auth mode */
@@ -619,7 +619,7 @@ function createMembersMethods(deps) {
619
619
  }
620
620
 
621
621
  // src/client/version-check.ts
622
- var SDK_VERSION = "2.6.0";
622
+ var SDK_VERSION = "2.7.0";
623
623
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
624
624
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
625
625
  function sdkHeaders() {
@@ -1563,6 +1563,118 @@ function createContractWizardMethods(deps) {
1563
1563
  };
1564
1564
  }
1565
1565
 
1566
+ // src/newsletter/ffid-newsletter-client.ts
1567
+ var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
1568
+ var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
1569
+ var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
1570
+ function trimOrEmpty(s) {
1571
+ return typeof s === "string" ? s.trim() : "";
1572
+ }
1573
+ async function postPublic(url, init, opts) {
1574
+ let response;
1575
+ try {
1576
+ response = await fetch(url, init);
1577
+ } catch (err) {
1578
+ return {
1579
+ error: opts.createError(
1580
+ "NETWORK_ERROR",
1581
+ err instanceof Error ? err.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1582
+ )
1583
+ };
1584
+ }
1585
+ if (!response.ok) {
1586
+ try {
1587
+ const body = await response.json();
1588
+ if (body?.error?.code || body?.error?.message) {
1589
+ return {
1590
+ error: opts.createError(
1591
+ body.error.code ?? "UNKNOWN_ERROR",
1592
+ body.error.message ?? `${opts.fallbackMessage} (status: ${response.status})`
1593
+ )
1594
+ };
1595
+ }
1596
+ } catch {
1597
+ }
1598
+ return {
1599
+ error: opts.createError(
1600
+ "NETWORK_ERROR",
1601
+ `${opts.fallbackMessage} (status: ${response.status})`
1602
+ )
1603
+ };
1604
+ }
1605
+ return { data: opts.success };
1606
+ }
1607
+ function createNewsletterMethods(deps) {
1608
+ const { fetchWithAuth, baseUrl, createError } = deps;
1609
+ async function subscribe(params) {
1610
+ const email = trimOrEmpty(params.email);
1611
+ const source = trimOrEmpty(params.source);
1612
+ if (!email) {
1613
+ return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
1614
+ }
1615
+ if (!source) {
1616
+ return { error: createError("VALIDATION_ERROR", "source \u306F\u5FC5\u9808\u3067\u3059") };
1617
+ }
1618
+ if (!Array.isArray(params.types) || params.types.length === 0) {
1619
+ return {
1620
+ error: createError(
1621
+ "VALIDATION_ERROR",
1622
+ "types \u306B\u306F1\u3064\u4EE5\u4E0A\u306E newsletter \u7A2E\u5225\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
1623
+ )
1624
+ };
1625
+ }
1626
+ return fetchWithAuth(
1627
+ EXT_SUBSCRIBE_ENDPOINT2,
1628
+ {
1629
+ method: "POST",
1630
+ body: JSON.stringify({
1631
+ email,
1632
+ types: params.types,
1633
+ source,
1634
+ locale: params.locale
1635
+ })
1636
+ }
1637
+ );
1638
+ }
1639
+ async function confirm(params) {
1640
+ const token = trimOrEmpty(params.token);
1641
+ if (!token) {
1642
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1643
+ }
1644
+ return postPublic(
1645
+ `${baseUrl}${CONFIRM_ENDPOINT}`,
1646
+ {
1647
+ method: "POST",
1648
+ headers: { "Content-Type": "application/json" },
1649
+ body: JSON.stringify({ token })
1650
+ },
1651
+ {
1652
+ success: { ok: true },
1653
+ createError,
1654
+ fallbackMessage: "\u78BA\u8A8D\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1655
+ }
1656
+ );
1657
+ }
1658
+ async function unsubscribe(params) {
1659
+ const token = trimOrEmpty(params.token);
1660
+ if (!token) {
1661
+ return { error: createError("VALIDATION_ERROR", "token \u306F\u5FC5\u9808\u3067\u3059") };
1662
+ }
1663
+ const url = new URL(`${baseUrl}${UNSUBSCRIBE_ENDPOINT}`);
1664
+ url.searchParams.set("token", token);
1665
+ return postPublic(
1666
+ url.toString(),
1667
+ { method: "POST" },
1668
+ {
1669
+ success: { ok: true },
1670
+ createError,
1671
+ fallbackMessage: "\u89E3\u9664\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5931\u6557\u3057\u307E\u3057\u305F"
1672
+ }
1673
+ );
1674
+ }
1675
+ return { subscribe, confirm, unsubscribe };
1676
+ }
1677
+
1566
1678
  // src/client/ffid-client.ts
1567
1679
  var UNAUTHORIZED_STATUS2 = 401;
1568
1680
  var SDK_LOG_PREFIX = "[FFID SDK]";
@@ -1838,6 +1950,11 @@ function createFFIDClient(config) {
1838
1950
  createError,
1839
1951
  errorCodes: FFID_ERROR_CODES
1840
1952
  });
1953
+ const newsletter = createNewsletterMethods({
1954
+ fetchWithAuth,
1955
+ baseUrl,
1956
+ createError
1957
+ });
1841
1958
  const verifyAccessToken = createVerifyAccessToken({
1842
1959
  authMode,
1843
1960
  baseUrl,
@@ -1892,6 +2009,8 @@ function createFFIDClient(config) {
1892
2009
  confirmPasswordReset,
1893
2010
  sendOtp,
1894
2011
  verifyOtp,
2012
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
2013
+ newsletter,
1895
2014
  /** Token store (token mode only) */
1896
2015
  tokenStore,
1897
2016
  /** Resolved auth mode */
@@ -1,30 +1,30 @@
1
1
  'use strict';
2
2
 
3
- var chunkZORI5YFR_cjs = require('../chunk-ZORI5YFR.cjs');
3
+ var chunkI6MKRVUB_cjs = require('../chunk-I6MKRVUB.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunkZORI5YFR_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkI6MKRVUB_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunkZORI5YFR_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkI6MKRVUB_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDLoginButton", {
16
16
  enumerable: true,
17
- get: function () { return chunkZORI5YFR_cjs.FFIDLoginButton; }
17
+ get: function () { return chunkI6MKRVUB_cjs.FFIDLoginButton; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
20
20
  enumerable: true,
21
- get: function () { return chunkZORI5YFR_cjs.FFIDOrganizationSwitcher; }
21
+ get: function () { return chunkI6MKRVUB_cjs.FFIDOrganizationSwitcher; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
24
24
  enumerable: true,
25
- get: function () { return chunkZORI5YFR_cjs.FFIDSubscriptionBadge; }
25
+ get: function () { return chunkI6MKRVUB_cjs.FFIDSubscriptionBadge; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDUserMenu", {
28
28
  enumerable: true,
29
- get: function () { return chunkZORI5YFR_cjs.FFIDUserMenu; }
29
+ get: function () { return chunkI6MKRVUB_cjs.FFIDUserMenu; }
30
30
  });
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-7FEWA2P2.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-YQPG6Z7W.js';
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkZORI5YFR_cjs = require('./chunk-ZORI5YFR.cjs');
3
+ var chunkI6MKRVUB_cjs = require('./chunk-I6MKRVUB.cjs');
4
4
  var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
@@ -46,7 +46,7 @@ function createKVCacheAdapter(kv) {
46
46
  }
47
47
  function withFFIDAuth(Component, options = {}) {
48
48
  const WrappedComponent = (props) => {
49
- const { isLoading, isAuthenticated, login } = chunkZORI5YFR_cjs.useFFIDContext();
49
+ const { isLoading, isAuthenticated, login } = chunkI6MKRVUB_cjs.useFFIDContext();
50
50
  const hasRedirected = react.useRef(false);
51
51
  react.useEffect(() => {
52
52
  if (!isLoading && !isAuthenticated && options.redirectToLogin && !hasRedirected.current) {
@@ -69,86 +69,90 @@ function withFFIDAuth(Component, options = {}) {
69
69
  return WrappedComponent;
70
70
  }
71
71
 
72
+ // src/newsletter/types.ts
73
+ var FFID_NEWSLETTER_TYPES = ["inquiry_followup", "general"];
74
+
72
75
  Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
73
76
  enumerable: true,
74
- get: function () { return chunkZORI5YFR_cjs.DEFAULT_API_BASE_URL; }
77
+ get: function () { return chunkI6MKRVUB_cjs.DEFAULT_API_BASE_URL; }
75
78
  });
76
79
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
77
80
  enumerable: true,
78
- get: function () { return chunkZORI5YFR_cjs.FFIDAnnouncementBadge; }
81
+ get: function () { return chunkI6MKRVUB_cjs.FFIDAnnouncementBadge; }
79
82
  });
80
83
  Object.defineProperty(exports, "FFIDAnnouncementList", {
81
84
  enumerable: true,
82
- get: function () { return chunkZORI5YFR_cjs.FFIDAnnouncementList; }
85
+ get: function () { return chunkI6MKRVUB_cjs.FFIDAnnouncementList; }
83
86
  });
84
87
  Object.defineProperty(exports, "FFIDLoginButton", {
85
88
  enumerable: true,
86
- get: function () { return chunkZORI5YFR_cjs.FFIDLoginButton; }
89
+ get: function () { return chunkI6MKRVUB_cjs.FFIDLoginButton; }
87
90
  });
88
91
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
89
92
  enumerable: true,
90
- get: function () { return chunkZORI5YFR_cjs.FFIDOrganizationSwitcher; }
93
+ get: function () { return chunkI6MKRVUB_cjs.FFIDOrganizationSwitcher; }
91
94
  });
92
95
  Object.defineProperty(exports, "FFIDProvider", {
93
96
  enumerable: true,
94
- get: function () { return chunkZORI5YFR_cjs.FFIDProvider; }
97
+ get: function () { return chunkI6MKRVUB_cjs.FFIDProvider; }
95
98
  });
96
99
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
97
100
  enumerable: true,
98
- get: function () { return chunkZORI5YFR_cjs.FFIDSubscriptionBadge; }
101
+ get: function () { return chunkI6MKRVUB_cjs.FFIDSubscriptionBadge; }
99
102
  });
100
103
  Object.defineProperty(exports, "FFIDUserMenu", {
101
104
  enumerable: true,
102
- get: function () { return chunkZORI5YFR_cjs.FFIDUserMenu; }
105
+ get: function () { return chunkI6MKRVUB_cjs.FFIDUserMenu; }
103
106
  });
104
107
  Object.defineProperty(exports, "FFID_ANNOUNCEMENTS_ERROR_CODES", {
105
108
  enumerable: true,
106
- get: function () { return chunkZORI5YFR_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
109
+ get: function () { return chunkI6MKRVUB_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
107
110
  });
108
111
  Object.defineProperty(exports, "createFFIDAnnouncementsClient", {
109
112
  enumerable: true,
110
- get: function () { return chunkZORI5YFR_cjs.createFFIDAnnouncementsClient; }
113
+ get: function () { return chunkI6MKRVUB_cjs.createFFIDAnnouncementsClient; }
111
114
  });
112
115
  Object.defineProperty(exports, "createFFIDClient", {
113
116
  enumerable: true,
114
- get: function () { return chunkZORI5YFR_cjs.createFFIDClient; }
117
+ get: function () { return chunkI6MKRVUB_cjs.createFFIDClient; }
115
118
  });
116
119
  Object.defineProperty(exports, "createTokenStore", {
117
120
  enumerable: true,
118
- get: function () { return chunkZORI5YFR_cjs.createTokenStore; }
121
+ get: function () { return chunkI6MKRVUB_cjs.createTokenStore; }
119
122
  });
120
123
  Object.defineProperty(exports, "generateCodeChallenge", {
121
124
  enumerable: true,
122
- get: function () { return chunkZORI5YFR_cjs.generateCodeChallenge; }
125
+ get: function () { return chunkI6MKRVUB_cjs.generateCodeChallenge; }
123
126
  });
124
127
  Object.defineProperty(exports, "generateCodeVerifier", {
125
128
  enumerable: true,
126
- get: function () { return chunkZORI5YFR_cjs.generateCodeVerifier; }
129
+ get: function () { return chunkI6MKRVUB_cjs.generateCodeVerifier; }
127
130
  });
128
131
  Object.defineProperty(exports, "retrieveCodeVerifier", {
129
132
  enumerable: true,
130
- get: function () { return chunkZORI5YFR_cjs.retrieveCodeVerifier; }
133
+ get: function () { return chunkI6MKRVUB_cjs.retrieveCodeVerifier; }
131
134
  });
132
135
  Object.defineProperty(exports, "storeCodeVerifier", {
133
136
  enumerable: true,
134
- get: function () { return chunkZORI5YFR_cjs.storeCodeVerifier; }
137
+ get: function () { return chunkI6MKRVUB_cjs.storeCodeVerifier; }
135
138
  });
136
139
  Object.defineProperty(exports, "useFFID", {
137
140
  enumerable: true,
138
- get: function () { return chunkZORI5YFR_cjs.useFFID; }
141
+ get: function () { return chunkI6MKRVUB_cjs.useFFID; }
139
142
  });
140
143
  Object.defineProperty(exports, "useFFIDAnnouncements", {
141
144
  enumerable: true,
142
- get: function () { return chunkZORI5YFR_cjs.useFFIDAnnouncements; }
145
+ get: function () { return chunkI6MKRVUB_cjs.useFFIDAnnouncements; }
143
146
  });
144
147
  Object.defineProperty(exports, "useSubscription", {
145
148
  enumerable: true,
146
- get: function () { return chunkZORI5YFR_cjs.useSubscription; }
149
+ get: function () { return chunkI6MKRVUB_cjs.useSubscription; }
147
150
  });
148
151
  Object.defineProperty(exports, "withSubscription", {
149
152
  enumerable: true,
150
- get: function () { return chunkZORI5YFR_cjs.withSubscription; }
153
+ get: function () { return chunkI6MKRVUB_cjs.withSubscription; }
151
154
  });
155
+ exports.FFID_NEWSLETTER_TYPES = FFID_NEWSLETTER_TYPES;
152
156
  exports.createKVCacheAdapter = createKVCacheAdapter;
153
157
  exports.createMemoryCacheAdapter = createMemoryCacheAdapter;
154
158
  exports.withFFIDAuth = withFFIDAuth;
package/dist/index.d.cts CHANGED
@@ -475,6 +475,12 @@ declare function createFFIDClient(config: FFIDConfig): {
475
475
  accessToken: string;
476
476
  refreshToken: string;
477
477
  }) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
478
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
479
+ newsletter: {
480
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
481
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
482
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
483
+ };
478
484
  /** Token store (token mode only) */
479
485
  tokenStore: TokenStore;
480
486
  /** Resolved auth mode */
@@ -763,4 +769,64 @@ declare function createFFIDAnnouncementsClient(config?: FFIDAnnouncementsClientC
763
769
  /** Type of the FFID Announcements client */
764
770
  type FFIDAnnouncementsClient = ReturnType<typeof createFFIDAnnouncementsClient>;
765
771
 
766
- export { AnnouncementListResponse, type ContractWizardFlowType, type ContractWizardResubscribeOptions, type ContractWizardSubscribeOptions, type ContractWizardSubscriptionOptions, DEFAULT_API_BASE_URL, FFIDAnnouncementsApiResponse, type FFIDAnnouncementsClient, FFIDAnnouncementsClientConfig, FFIDAnnouncementsLogger, FFIDApiResponse, type FFIDBillingInterval, FFIDCacheAdapter, type FFIDCancelPendingDowngradeResponse, type FFIDCancelSubscriptionParams, type FFIDCancelSubscriptionResponse, type FFIDChangePlanParams, type FFIDChangePlanResponse, FFIDCheckoutSessionResponse, type FFIDClient, FFIDConfig, FFIDCreateCheckoutParams, FFIDCreatePortalParams, FFIDError, FFIDListMembersResponse, type FFIDListPlansResponse, FFIDLogger, FFIDMemberRole, FFIDOAuthUserInfo, FFIDOrganization, type FFIDOtpSendResponse, type FFIDOtpVerifyResponse, type FFIDPasswordResetConfirmResponse, type FFIDPasswordResetResponse, type FFIDPasswordResetVerifyResponse, type FFIDPlanChangeLineItem, type FFIDPlanChangePreview, type FFIDPlanChangePreviewResponse, type FFIDPlanInfo, FFIDPortalSessionResponse, type FFIDPreviewPlanChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, type FFIDServiceInfo, FFIDSessionResponse, type FFIDSubscribeParams, type FFIDSubscribeResponse, FFIDSubscription, FFIDSubscriptionCheckResponse, FFIDSubscriptionContextValue, type FFIDSubscriptionDetail, FFIDSubscriptionStatus, type FFIDSubscriptionSummary, type FFIDSupportedCurrency, FFIDUpdateMemberRoleResponse, FFIDUser, FFIDVerifyAccessTokenOptions, FFID_ANNOUNCEMENTS_ERROR_CODES, type KVNamespaceLike, ListAnnouncementsOptions, type RedirectToAuthorizeOptions, type TokenData, type TokenStore, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, createFFIDAnnouncementsClient, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useSubscription, withFFIDAuth, withSubscription };
772
+ /**
773
+ * Newsletter types exposed by the FFID SDK.
774
+ *
775
+ * 2-layer newsletter model (#2078):
776
+ * - `inquiry_followup`: 問い合わせフォローアップ (Type A)
777
+ * - `general`: 定期ニュースレター (Type B)
778
+ *
779
+ * FFID account holders' preferences live in `user_marketing_preferences`;
780
+ * anonymous subscribers live in `newsletter_subscribers` with double
781
+ * opt-in required.
782
+ */
783
+ declare const FFID_NEWSLETTER_TYPES: readonly ["inquiry_followup", "general"];
784
+ type FFIDNewsletterType = (typeof FFID_NEWSLETTER_TYPES)[number];
785
+ interface FFIDNewsletterSubscribeParams {
786
+ /** Subscriber email address */
787
+ email: string;
788
+ /** One or more newsletter types to opt in to */
789
+ types: FFIDNewsletterType[];
790
+ /** Origin string recorded on the subscriber row (e.g. your service code) */
791
+ source: string;
792
+ /** ISO 639-1 locale (e.g. 'ja', 'en') */
793
+ locale?: string;
794
+ }
795
+ interface FFIDNewsletterSubscribeResponse {
796
+ ok: true;
797
+ /** True when a double opt-in confirmation email was sent */
798
+ requiresConfirmation: boolean;
799
+ /** True when the email matched an existing FFID account; the caller
800
+ * must sign in to update preferences. Preferences are NOT modified. */
801
+ requiresSignIn: boolean;
802
+ }
803
+ interface FFIDNewsletterConfirmParams {
804
+ /** Confirmation token received in the double opt-in email */
805
+ token: string;
806
+ }
807
+ interface FFIDNewsletterConfirmResponse {
808
+ ok: true;
809
+ }
810
+ interface FFIDNewsletterUnsubscribeParams {
811
+ /** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
812
+ token: string;
813
+ }
814
+ interface FFIDNewsletterUnsubscribeResponse {
815
+ ok: true;
816
+ }
817
+
818
+ /** Newsletter methods - subscribe / confirm / unsubscribe */
819
+
820
+ interface NewsletterMethodsDeps {
821
+ fetchWithAuth: <T>(endpoint: string, options?: RequestInit) => Promise<FFIDApiResponse<T>>;
822
+ baseUrl: string;
823
+ createError: (code: string, message: string) => FFIDError;
824
+ }
825
+ declare function createNewsletterMethods(deps: NewsletterMethodsDeps): {
826
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
827
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
828
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
829
+ };
830
+ type FFIDNewsletterClient = ReturnType<typeof createNewsletterMethods>;
831
+
832
+ export { AnnouncementListResponse, type ContractWizardFlowType, type ContractWizardResubscribeOptions, type ContractWizardSubscribeOptions, type ContractWizardSubscriptionOptions, DEFAULT_API_BASE_URL, FFIDAnnouncementsApiResponse, type FFIDAnnouncementsClient, FFIDAnnouncementsClientConfig, FFIDAnnouncementsLogger, FFIDApiResponse, type FFIDBillingInterval, FFIDCacheAdapter, type FFIDCancelPendingDowngradeResponse, type FFIDCancelSubscriptionParams, type FFIDCancelSubscriptionResponse, type FFIDChangePlanParams, type FFIDChangePlanResponse, FFIDCheckoutSessionResponse, type FFIDClient, FFIDConfig, FFIDCreateCheckoutParams, FFIDCreatePortalParams, FFIDError, FFIDListMembersResponse, type FFIDListPlansResponse, FFIDLogger, FFIDMemberRole, type FFIDNewsletterClient, type FFIDNewsletterConfirmParams, type FFIDNewsletterConfirmResponse, type FFIDNewsletterSubscribeParams, type FFIDNewsletterSubscribeResponse, type FFIDNewsletterType, type FFIDNewsletterUnsubscribeParams, type FFIDNewsletterUnsubscribeResponse, FFIDOAuthUserInfo, FFIDOrganization, type FFIDOtpSendResponse, type FFIDOtpVerifyResponse, type FFIDPasswordResetConfirmResponse, type FFIDPasswordResetResponse, type FFIDPasswordResetVerifyResponse, type FFIDPlanChangeLineItem, type FFIDPlanChangePreview, type FFIDPlanChangePreviewResponse, type FFIDPlanInfo, FFIDPortalSessionResponse, type FFIDPreviewPlanChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, type FFIDServiceInfo, FFIDSessionResponse, type FFIDSubscribeParams, type FFIDSubscribeResponse, FFIDSubscription, FFIDSubscriptionCheckResponse, FFIDSubscriptionContextValue, type FFIDSubscriptionDetail, FFIDSubscriptionStatus, type FFIDSubscriptionSummary, type FFIDSupportedCurrency, FFIDUpdateMemberRoleResponse, FFIDUser, FFIDVerifyAccessTokenOptions, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_NEWSLETTER_TYPES, type KVNamespaceLike, ListAnnouncementsOptions, type RedirectToAuthorizeOptions, type TokenData, type TokenStore, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, createFFIDAnnouncementsClient, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useSubscription, withFFIDAuth, withSubscription };
package/dist/index.d.ts CHANGED
@@ -475,6 +475,12 @@ declare function createFFIDClient(config: FFIDConfig): {
475
475
  accessToken: string;
476
476
  refreshToken: string;
477
477
  }) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
478
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
479
+ newsletter: {
480
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
481
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
482
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
483
+ };
478
484
  /** Token store (token mode only) */
479
485
  tokenStore: TokenStore;
480
486
  /** Resolved auth mode */
@@ -763,4 +769,64 @@ declare function createFFIDAnnouncementsClient(config?: FFIDAnnouncementsClientC
763
769
  /** Type of the FFID Announcements client */
764
770
  type FFIDAnnouncementsClient = ReturnType<typeof createFFIDAnnouncementsClient>;
765
771
 
766
- export { AnnouncementListResponse, type ContractWizardFlowType, type ContractWizardResubscribeOptions, type ContractWizardSubscribeOptions, type ContractWizardSubscriptionOptions, DEFAULT_API_BASE_URL, FFIDAnnouncementsApiResponse, type FFIDAnnouncementsClient, FFIDAnnouncementsClientConfig, FFIDAnnouncementsLogger, FFIDApiResponse, type FFIDBillingInterval, FFIDCacheAdapter, type FFIDCancelPendingDowngradeResponse, type FFIDCancelSubscriptionParams, type FFIDCancelSubscriptionResponse, type FFIDChangePlanParams, type FFIDChangePlanResponse, FFIDCheckoutSessionResponse, type FFIDClient, FFIDConfig, FFIDCreateCheckoutParams, FFIDCreatePortalParams, FFIDError, FFIDListMembersResponse, type FFIDListPlansResponse, FFIDLogger, FFIDMemberRole, FFIDOAuthUserInfo, FFIDOrganization, type FFIDOtpSendResponse, type FFIDOtpVerifyResponse, type FFIDPasswordResetConfirmResponse, type FFIDPasswordResetResponse, type FFIDPasswordResetVerifyResponse, type FFIDPlanChangeLineItem, type FFIDPlanChangePreview, type FFIDPlanChangePreviewResponse, type FFIDPlanInfo, FFIDPortalSessionResponse, type FFIDPreviewPlanChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, type FFIDServiceInfo, FFIDSessionResponse, type FFIDSubscribeParams, type FFIDSubscribeResponse, FFIDSubscription, FFIDSubscriptionCheckResponse, FFIDSubscriptionContextValue, type FFIDSubscriptionDetail, FFIDSubscriptionStatus, type FFIDSubscriptionSummary, type FFIDSupportedCurrency, FFIDUpdateMemberRoleResponse, FFIDUser, FFIDVerifyAccessTokenOptions, FFID_ANNOUNCEMENTS_ERROR_CODES, type KVNamespaceLike, ListAnnouncementsOptions, type RedirectToAuthorizeOptions, type TokenData, type TokenStore, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, createFFIDAnnouncementsClient, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useSubscription, withFFIDAuth, withSubscription };
772
+ /**
773
+ * Newsletter types exposed by the FFID SDK.
774
+ *
775
+ * 2-layer newsletter model (#2078):
776
+ * - `inquiry_followup`: 問い合わせフォローアップ (Type A)
777
+ * - `general`: 定期ニュースレター (Type B)
778
+ *
779
+ * FFID account holders' preferences live in `user_marketing_preferences`;
780
+ * anonymous subscribers live in `newsletter_subscribers` with double
781
+ * opt-in required.
782
+ */
783
+ declare const FFID_NEWSLETTER_TYPES: readonly ["inquiry_followup", "general"];
784
+ type FFIDNewsletterType = (typeof FFID_NEWSLETTER_TYPES)[number];
785
+ interface FFIDNewsletterSubscribeParams {
786
+ /** Subscriber email address */
787
+ email: string;
788
+ /** One or more newsletter types to opt in to */
789
+ types: FFIDNewsletterType[];
790
+ /** Origin string recorded on the subscriber row (e.g. your service code) */
791
+ source: string;
792
+ /** ISO 639-1 locale (e.g. 'ja', 'en') */
793
+ locale?: string;
794
+ }
795
+ interface FFIDNewsletterSubscribeResponse {
796
+ ok: true;
797
+ /** True when a double opt-in confirmation email was sent */
798
+ requiresConfirmation: boolean;
799
+ /** True when the email matched an existing FFID account; the caller
800
+ * must sign in to update preferences. Preferences are NOT modified. */
801
+ requiresSignIn: boolean;
802
+ }
803
+ interface FFIDNewsletterConfirmParams {
804
+ /** Confirmation token received in the double opt-in email */
805
+ token: string;
806
+ }
807
+ interface FFIDNewsletterConfirmResponse {
808
+ ok: true;
809
+ }
810
+ interface FFIDNewsletterUnsubscribeParams {
811
+ /** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
812
+ token: string;
813
+ }
814
+ interface FFIDNewsletterUnsubscribeResponse {
815
+ ok: true;
816
+ }
817
+
818
+ /** Newsletter methods - subscribe / confirm / unsubscribe */
819
+
820
+ interface NewsletterMethodsDeps {
821
+ fetchWithAuth: <T>(endpoint: string, options?: RequestInit) => Promise<FFIDApiResponse<T>>;
822
+ baseUrl: string;
823
+ createError: (code: string, message: string) => FFIDError;
824
+ }
825
+ declare function createNewsletterMethods(deps: NewsletterMethodsDeps): {
826
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
827
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
828
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
829
+ };
830
+ type FFIDNewsletterClient = ReturnType<typeof createNewsletterMethods>;
831
+
832
+ export { AnnouncementListResponse, type ContractWizardFlowType, type ContractWizardResubscribeOptions, type ContractWizardSubscribeOptions, type ContractWizardSubscriptionOptions, DEFAULT_API_BASE_URL, FFIDAnnouncementsApiResponse, type FFIDAnnouncementsClient, FFIDAnnouncementsClientConfig, FFIDAnnouncementsLogger, FFIDApiResponse, type FFIDBillingInterval, FFIDCacheAdapter, type FFIDCancelPendingDowngradeResponse, type FFIDCancelSubscriptionParams, type FFIDCancelSubscriptionResponse, type FFIDChangePlanParams, type FFIDChangePlanResponse, FFIDCheckoutSessionResponse, type FFIDClient, FFIDConfig, FFIDCreateCheckoutParams, FFIDCreatePortalParams, FFIDError, FFIDListMembersResponse, type FFIDListPlansResponse, FFIDLogger, FFIDMemberRole, type FFIDNewsletterClient, type FFIDNewsletterConfirmParams, type FFIDNewsletterConfirmResponse, type FFIDNewsletterSubscribeParams, type FFIDNewsletterSubscribeResponse, type FFIDNewsletterType, type FFIDNewsletterUnsubscribeParams, type FFIDNewsletterUnsubscribeResponse, FFIDOAuthUserInfo, FFIDOrganization, type FFIDOtpSendResponse, type FFIDOtpVerifyResponse, type FFIDPasswordResetConfirmResponse, type FFIDPasswordResetResponse, type FFIDPasswordResetVerifyResponse, type FFIDPlanChangeLineItem, type FFIDPlanChangePreview, type FFIDPlanChangePreviewResponse, type FFIDPlanInfo, FFIDPortalSessionResponse, type FFIDPreviewPlanChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, type FFIDServiceInfo, FFIDSessionResponse, type FFIDSubscribeParams, type FFIDSubscribeResponse, FFIDSubscription, FFIDSubscriptionCheckResponse, FFIDSubscriptionContextValue, type FFIDSubscriptionDetail, FFIDSubscriptionStatus, type FFIDSubscriptionSummary, type FFIDSupportedCurrency, FFIDUpdateMemberRoleResponse, FFIDUser, FFIDVerifyAccessTokenOptions, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_NEWSLETTER_TYPES, type KVNamespaceLike, ListAnnouncementsOptions, type RedirectToAuthorizeOptions, type TokenData, type TokenStore, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, createFFIDAnnouncementsClient, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useSubscription, withFFIDAuth, withSubscription };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useFFIDContext } from './chunk-7FEWA2P2.js';
2
- export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-7FEWA2P2.js';
1
+ import { useFFIDContext } from './chunk-YQPG6Z7W.js';
2
+ export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-YQPG6Z7W.js';
3
3
  import { useRef, useEffect } from 'react';
4
4
  import { jsx, Fragment } from 'react/jsx-runtime';
5
5
 
@@ -68,4 +68,7 @@ function withFFIDAuth(Component, options = {}) {
68
68
  return WrappedComponent;
69
69
  }
70
70
 
71
- export { createKVCacheAdapter, createMemoryCacheAdapter, withFFIDAuth };
71
+ // src/newsletter/types.ts
72
+ var FFID_NEWSLETTER_TYPES = ["inquiry_followup", "general"];
73
+
74
+ export { FFID_NEWSLETTER_TYPES, createKVCacheAdapter, createMemoryCacheAdapter, withFFIDAuth };
@@ -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.7.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,118 @@ 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
+
1551
1663
  // src/client/ffid-client.ts
1552
1664
  var UNAUTHORIZED_STATUS2 = 401;
1553
1665
  var SDK_LOG_PREFIX = "[FFID SDK]";
@@ -1823,6 +1935,11 @@ function createFFIDClient(config) {
1823
1935
  createError,
1824
1936
  errorCodes: FFID_ERROR_CODES
1825
1937
  });
1938
+ const newsletter = createNewsletterMethods({
1939
+ fetchWithAuth,
1940
+ baseUrl,
1941
+ createError
1942
+ });
1826
1943
  const verifyAccessToken = createVerifyAccessToken({
1827
1944
  authMode,
1828
1945
  baseUrl,
@@ -1877,6 +1994,8 @@ function createFFIDClient(config) {
1877
1994
  confirmPasswordReset,
1878
1995
  sendOtp,
1879
1996
  verifyOtp,
1997
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
1998
+ newsletter,
1880
1999
  /** Token store (token mode only) */
1881
2000
  tokenStore,
1882
2001
  /** Resolved auth mode */
@@ -1,5 +1,51 @@
1
1
  export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.cjs';
2
2
 
3
+ /**
4
+ * Newsletter types exposed by the FFID SDK.
5
+ *
6
+ * 2-layer newsletter model (#2078):
7
+ * - `inquiry_followup`: 問い合わせフォローアップ (Type A)
8
+ * - `general`: 定期ニュースレター (Type B)
9
+ *
10
+ * FFID account holders' preferences live in `user_marketing_preferences`;
11
+ * anonymous subscribers live in `newsletter_subscribers` with double
12
+ * opt-in required.
13
+ */
14
+ declare const FFID_NEWSLETTER_TYPES: readonly ["inquiry_followup", "general"];
15
+ type FFIDNewsletterType = (typeof FFID_NEWSLETTER_TYPES)[number];
16
+ interface FFIDNewsletterSubscribeParams {
17
+ /** Subscriber email address */
18
+ email: string;
19
+ /** One or more newsletter types to opt in to */
20
+ types: FFIDNewsletterType[];
21
+ /** Origin string recorded on the subscriber row (e.g. your service code) */
22
+ source: string;
23
+ /** ISO 639-1 locale (e.g. 'ja', 'en') */
24
+ locale?: string;
25
+ }
26
+ interface FFIDNewsletterSubscribeResponse {
27
+ ok: true;
28
+ /** True when a double opt-in confirmation email was sent */
29
+ requiresConfirmation: boolean;
30
+ /** True when the email matched an existing FFID account; the caller
31
+ * must sign in to update preferences. Preferences are NOT modified. */
32
+ requiresSignIn: boolean;
33
+ }
34
+ interface FFIDNewsletterConfirmParams {
35
+ /** Confirmation token received in the double opt-in email */
36
+ token: string;
37
+ }
38
+ interface FFIDNewsletterConfirmResponse {
39
+ ok: true;
40
+ }
41
+ interface FFIDNewsletterUnsubscribeParams {
42
+ /** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
43
+ token: string;
44
+ }
45
+ interface FFIDNewsletterUnsubscribeResponse {
46
+ ok: true;
47
+ }
48
+
3
49
  /** Cache adapter interface for FFID SDK token verification */
4
50
  /**
5
51
  * Pluggable cache adapter interface.
@@ -779,6 +825,12 @@ declare function createFFIDClient(config: FFIDConfig): {
779
825
  accessToken: string;
780
826
  refreshToken: string;
781
827
  }) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
828
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
829
+ newsletter: {
830
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
831
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
832
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
833
+ };
782
834
  /** Token store (token mode only) */
783
835
  tokenStore: TokenStore;
784
836
  /** Resolved auth mode */
@@ -1,5 +1,51 @@
1
1
  export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.js';
2
2
 
3
+ /**
4
+ * Newsletter types exposed by the FFID SDK.
5
+ *
6
+ * 2-layer newsletter model (#2078):
7
+ * - `inquiry_followup`: 問い合わせフォローアップ (Type A)
8
+ * - `general`: 定期ニュースレター (Type B)
9
+ *
10
+ * FFID account holders' preferences live in `user_marketing_preferences`;
11
+ * anonymous subscribers live in `newsletter_subscribers` with double
12
+ * opt-in required.
13
+ */
14
+ declare const FFID_NEWSLETTER_TYPES: readonly ["inquiry_followup", "general"];
15
+ type FFIDNewsletterType = (typeof FFID_NEWSLETTER_TYPES)[number];
16
+ interface FFIDNewsletterSubscribeParams {
17
+ /** Subscriber email address */
18
+ email: string;
19
+ /** One or more newsletter types to opt in to */
20
+ types: FFIDNewsletterType[];
21
+ /** Origin string recorded on the subscriber row (e.g. your service code) */
22
+ source: string;
23
+ /** ISO 639-1 locale (e.g. 'ja', 'en') */
24
+ locale?: string;
25
+ }
26
+ interface FFIDNewsletterSubscribeResponse {
27
+ ok: true;
28
+ /** True when a double opt-in confirmation email was sent */
29
+ requiresConfirmation: boolean;
30
+ /** True when the email matched an existing FFID account; the caller
31
+ * must sign in to update preferences. Preferences are NOT modified. */
32
+ requiresSignIn: boolean;
33
+ }
34
+ interface FFIDNewsletterConfirmParams {
35
+ /** Confirmation token received in the double opt-in email */
36
+ token: string;
37
+ }
38
+ interface FFIDNewsletterConfirmResponse {
39
+ ok: true;
40
+ }
41
+ interface FFIDNewsletterUnsubscribeParams {
42
+ /** Unsubscribe token received in the newsletter footer / List-Unsubscribe header */
43
+ token: string;
44
+ }
45
+ interface FFIDNewsletterUnsubscribeResponse {
46
+ ok: true;
47
+ }
48
+
3
49
  /** Cache adapter interface for FFID SDK token verification */
4
50
  /**
5
51
  * Pluggable cache adapter interface.
@@ -779,6 +825,12 @@ declare function createFFIDClient(config: FFIDConfig): {
779
825
  accessToken: string;
780
826
  refreshToken: string;
781
827
  }) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
828
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
829
+ newsletter: {
830
+ subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
831
+ confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
832
+ unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
833
+ };
782
834
  /** Token store (token mode only) */
783
835
  tokenStore: TokenStore;
784
836
  /** 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.7.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,118 @@ 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
+
1550
1662
  // src/client/ffid-client.ts
1551
1663
  var UNAUTHORIZED_STATUS2 = 401;
1552
1664
  var SDK_LOG_PREFIX = "[FFID SDK]";
@@ -1822,6 +1934,11 @@ function createFFIDClient(config) {
1822
1934
  createError,
1823
1935
  errorCodes: FFID_ERROR_CODES
1824
1936
  });
1937
+ const newsletter = createNewsletterMethods({
1938
+ fetchWithAuth,
1939
+ baseUrl,
1940
+ createError
1941
+ });
1825
1942
  const verifyAccessToken = createVerifyAccessToken({
1826
1943
  authMode,
1827
1944
  baseUrl,
@@ -1876,6 +1993,8 @@ function createFFIDClient(config) {
1876
1993
  confirmPasswordReset,
1877
1994
  sendOtp,
1878
1995
  verifyOtp,
1996
+ /** Newsletter methods (subscribe / confirm / unsubscribe) */
1997
+ newsletter,
1879
1998
  /** Token store (token mode only) */
1880
1999
  tokenStore,
1881
2000
  /** 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.7.0",
4
4
  "description": "FeelFlow ID Platform SDK for React/Next.js applications",
5
5
  "keywords": [
6
6
  "feelflow",