@feelflow/ffid-sdk 2.21.0 → 3.0.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.
Files changed (38) hide show
  1. package/dist/agency/index.cjs +3 -3
  2. package/dist/agency/index.d.cts +1 -1
  3. package/dist/agency/index.d.ts +1 -1
  4. package/dist/agency/index.js +2 -2
  5. package/dist/announcements/index.cjs +2 -2
  6. package/dist/announcements/index.js +1 -1
  7. package/dist/chunk-JEVK2XUM.js +5 -0
  8. package/dist/{chunk-HUU4Q5VH.cjs → chunk-JNR4AKL5.cjs} +71 -3
  9. package/dist/{chunk-YUIITYBE.cjs → chunk-MDHKSVLP.cjs} +2 -0
  10. package/dist/{chunk-I7NEMG52.js → chunk-XWI4BFKW.js} +71 -4
  11. package/dist/components/index.cjs +8 -8
  12. package/dist/components/index.d.cts +1 -1
  13. package/dist/components/index.d.ts +1 -1
  14. package/dist/components/index.js +1 -1
  15. package/dist/constants-D61jqRIO.d.cts +35 -0
  16. package/dist/constants-D61jqRIO.d.ts +35 -0
  17. package/dist/{ffid-client-DgJRU-YZ.d.cts → ffid-client-B26jbUp5.d.cts} +48 -0
  18. package/dist/{ffid-client-DgJRU-YZ.d.ts → ffid-client-B26jbUp5.d.ts} +48 -0
  19. package/dist/{index-Dr5G9HQ4.d.cts → index-C3zyNa4j.d.cts} +13 -0
  20. package/dist/{index-Dr5G9HQ4.d.ts → index-C3zyNa4j.d.ts} +13 -0
  21. package/dist/index.cjs +37 -31
  22. package/dist/index.d.cts +67 -4
  23. package/dist/index.d.ts +67 -4
  24. package/dist/index.js +4 -3
  25. package/dist/legal/index.cjs +3 -3
  26. package/dist/legal/index.d.cts +1 -1
  27. package/dist/legal/index.d.ts +1 -1
  28. package/dist/legal/index.js +2 -2
  29. package/dist/server/index.cjs +73 -5
  30. package/dist/server/index.d.cts +3 -3
  31. package/dist/server/index.d.ts +3 -3
  32. package/dist/server/index.js +68 -4
  33. package/dist/server/test/index.d.cts +1 -1
  34. package/dist/server/test/index.d.ts +1 -1
  35. package/package.json +1 -1
  36. package/dist/chunk-QBRM2RRC.js +0 -4
  37. package/dist/constants-DvTGHPZn.d.cts +0 -10
  38. package/dist/constants-DvTGHPZn.d.ts +0 -10
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkYUIITYBE_cjs = require('../chunk-YUIITYBE.cjs');
3
+ var chunkMDHKSVLP_cjs = require('../chunk-MDHKSVLP.cjs');
4
4
 
5
5
  // src/agency/ffid-agency-client.ts
6
6
  var API_PREFIX = "/api/v1/agencies";
@@ -26,7 +26,7 @@ var consoleLogger = {
26
26
  error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
27
27
  };
28
28
  function createFFIDAgencyClient(config = {}) {
29
- const baseUrl = config.apiBaseUrl ?? chunkYUIITYBE_cjs.DEFAULT_API_BASE_URL;
29
+ const baseUrl = config.apiBaseUrl ?? chunkMDHKSVLP_cjs.DEFAULT_API_BASE_URL;
30
30
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
31
31
  function validateIds(...pairs) {
32
32
  for (const [value, name] of pairs) {
@@ -316,7 +316,7 @@ function createFFIDAgencyClient(config = {}) {
316
316
 
317
317
  Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
318
318
  enumerable: true,
319
- get: function () { return chunkYUIITYBE_cjs.DEFAULT_API_BASE_URL; }
319
+ get: function () { return chunkMDHKSVLP_cjs.DEFAULT_API_BASE_URL; }
320
320
  });
321
321
  exports.FFID_AGENCY_ERROR_CODES = FFID_AGENCY_ERROR_CODES;
322
322
  exports.createFFIDAgencyClient = createFFIDAgencyClient;
@@ -1,4 +1,4 @@
1
- export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.cjs';
1
+ export { D as DEFAULT_API_BASE_URL } from '../constants-D61jqRIO.cjs';
2
2
 
3
3
  /**
4
4
  * FFID Agency SDK Type Definitions
@@ -1,4 +1,4 @@
1
- export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.js';
1
+ export { D as DEFAULT_API_BASE_URL } from '../constants-D61jqRIO.js';
2
2
 
3
3
  /**
4
4
  * FFID Agency SDK Type Definitions
@@ -1,5 +1,5 @@
1
- import { DEFAULT_API_BASE_URL } from '../chunk-QBRM2RRC.js';
2
- export { DEFAULT_API_BASE_URL } from '../chunk-QBRM2RRC.js';
1
+ import { DEFAULT_API_BASE_URL } from '../chunk-JEVK2XUM.js';
2
+ export { DEFAULT_API_BASE_URL } from '../chunk-JEVK2XUM.js';
3
3
 
4
4
  // src/agency/ffid-agency-client.ts
5
5
  var API_PREFIX = "/api/v1/agencies";
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkYUIITYBE_cjs = require('../chunk-YUIITYBE.cjs');
3
+ var chunkMDHKSVLP_cjs = require('../chunk-MDHKSVLP.cjs');
4
4
 
5
5
  // src/announcements/ffid-announcements-client.ts
6
6
  var API_PATH = "/api/v1/announcements";
@@ -29,7 +29,7 @@ var consoleLogger = {
29
29
  error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
30
30
  };
31
31
  function createFFIDAnnouncementsClient(config = {}) {
32
- const baseUrl = config.apiBaseUrl ?? chunkYUIITYBE_cjs.DEFAULT_API_BASE_URL;
32
+ const baseUrl = config.apiBaseUrl ?? chunkMDHKSVLP_cjs.DEFAULT_API_BASE_URL;
33
33
  const logger = config.logger ?? (config.debug ? consoleLogger : quietLogger);
34
34
  async function fetchApi(endpoint) {
35
35
  const url = `${baseUrl}${endpoint}`;
@@ -1,4 +1,4 @@
1
- import { DEFAULT_API_BASE_URL } from '../chunk-QBRM2RRC.js';
1
+ import { DEFAULT_API_BASE_URL } from '../chunk-JEVK2XUM.js';
2
2
 
3
3
  // src/announcements/ffid-announcements-client.ts
4
4
  var API_PATH = "/api/v1/announcements";
@@ -0,0 +1,5 @@
1
+ // src/constants.ts
2
+ var DEFAULT_API_BASE_URL = "https://id.feelflow.net";
3
+ var DEFAULT_OAUTH_SCOPES = "openid email profile subscription:read legal:read";
4
+
5
+ export { DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES };
@@ -6,6 +6,7 @@ var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
7
  // src/constants.ts
8
8
  var DEFAULT_API_BASE_URL = "https://id.feelflow.net";
9
+ var DEFAULT_OAUTH_SCOPES = "openid email profile subscription:read legal:read";
9
10
 
10
11
  // src/auth/token-store.ts
11
12
  var STORAGE_KEY = "ffid_tokens";
@@ -807,7 +808,7 @@ function createProfileMethods(deps) {
807
808
  }
808
809
 
809
810
  // src/client/version-check.ts
810
- var SDK_VERSION = "2.21.0";
811
+ var SDK_VERSION = "3.0.0";
811
812
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
812
813
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
813
814
  function sdkHeaders() {
@@ -1462,6 +1463,7 @@ function createRedirectMethods(deps) {
1462
1463
  baseUrl,
1463
1464
  clientId,
1464
1465
  serviceCode,
1466
+ scope,
1465
1467
  resolvedRedirectUri,
1466
1468
  logger
1467
1469
  } = deps;
@@ -1470,6 +1472,24 @@ function createRedirectMethods(deps) {
1470
1472
  logger.warn("SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093");
1471
1473
  return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
1472
1474
  }
1475
+ if (authMode === "service-key") {
1476
+ logger.error(
1477
+ "[FFID SDK] service-key \u30E2\u30FC\u30C9\u3067\u306F redirectToAuthorize \u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093 \u2014 server-to-server \u7528\u9014\u306E\u305F\u3081 OAuth \u30D6\u30E9\u30A6\u30B6 flow \u3092\u6301\u3061\u307E\u305B\u3093"
1478
+ );
1479
+ return {
1480
+ success: false,
1481
+ error: "service-key \u30E2\u30FC\u30C9\u3067\u306F OAuth \u8A8D\u53EF\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093"
1482
+ };
1483
+ }
1484
+ if (!scope || !scope.trim()) {
1485
+ logger.error(
1486
+ "[FFID SDK] scope \u304C\u672A\u8A2D\u5B9A\u306E\u305F\u3081 /oauth/authorize \u3092\u547C\u3073\u51FA\u305B\u307E\u305B\u3093 (#2674) \u2014 FFIDConfig.scope \u306B DEFAULT_OAUTH_SCOPES \u307E\u305F\u306F\u660E\u793A\u7684\u306A scope \u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044"
1487
+ );
1488
+ return {
1489
+ success: false,
1490
+ error: "OAuth scope \u304C\u672A\u8A2D\u5B9A\u306E\u305F\u3081\u8A8D\u53EF\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3092\u5B9F\u884C\u3067\u304D\u307E\u305B\u3093"
1491
+ };
1492
+ }
1473
1493
  const authorizeKey = buildAuthorizeKey(baseUrl, clientId, options?.organizationId);
1474
1494
  const now = Date.now();
1475
1495
  const recentCount = getRecentRedirectCount(authorizeKey, now, logger);
@@ -1502,6 +1522,7 @@ function createRedirectMethods(deps) {
1502
1522
  const params = new URLSearchParams({
1503
1523
  response_type: "code",
1504
1524
  client_id: clientId,
1525
+ scope,
1505
1526
  redirect_uri: redirectUri,
1506
1527
  state,
1507
1528
  code_challenge: challenge,
@@ -1984,6 +2005,7 @@ function createContractWizardMethods(deps) {
1984
2005
  var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
1985
2006
  var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
1986
2007
  var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
2008
+ var DISPATCH_ENDPOINT = "/api/v1/newsletter/dispatch";
1987
2009
  function trimOrEmpty(s) {
1988
2010
  return typeof s === "string" ? s.trim() : "";
1989
2011
  }
@@ -2089,7 +2111,36 @@ function createNewsletterMethods(deps) {
2089
2111
  }
2090
2112
  );
2091
2113
  }
2092
- return { subscribe, confirm, unsubscribe };
2114
+ async function dispatch(params) {
2115
+ const subject = trimOrEmpty(params.subject);
2116
+ if (!subject) {
2117
+ return { error: createError("VALIDATION_ERROR", "subject \u306F\u5FC5\u9808\u3067\u3059") };
2118
+ }
2119
+ if (!params.body || typeof params.body !== "object") {
2120
+ return { error: createError("VALIDATION_ERROR", "body \u306F\u5FC5\u9808\u3067\u3059") };
2121
+ }
2122
+ const bodySource = params.body;
2123
+ const hasHtmlBody = typeof bodySource.htmlBody === "string" && bodySource.htmlBody.length > 0;
2124
+ const hasTemplateId = typeof bodySource.templateId === "string" && bodySource.templateId.length > 0;
2125
+ if (hasHtmlBody === hasTemplateId) {
2126
+ return {
2127
+ error: createError(
2128
+ "BODY_SOURCE_REQUIRED",
2129
+ "body \u306F htmlBody \u307E\u305F\u306F templateId \u306E\u3044\u305A\u308C\u304B\u4E00\u65B9\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
2130
+ )
2131
+ };
2132
+ }
2133
+ return fetchWithAuth(DISPATCH_ENDPOINT, {
2134
+ method: "POST",
2135
+ body: JSON.stringify({
2136
+ subject,
2137
+ articleUrl: params.articleUrl,
2138
+ body: params.body,
2139
+ segment: params.segment
2140
+ })
2141
+ });
2142
+ }
2143
+ return { subscribe, confirm, unsubscribe, dispatch };
2093
2144
  }
2094
2145
 
2095
2146
  // src/inquiry/ffid-inquiry-client.ts
@@ -2191,8 +2242,21 @@ function createFFIDClient(config) {
2191
2242
  if (!config.serviceCode || !config.serviceCode.trim()) {
2192
2243
  throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
2193
2244
  }
2245
+ const scope = config.scope?.trim() ?? "";
2194
2246
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
2195
2247
  const authMode = config.authMode ?? "cookie";
2248
+ const VALID_AUTH_MODES = ["cookie", "token", "service-key"];
2249
+ if (!VALID_AUTH_MODES.includes(authMode)) {
2250
+ throw new Error(
2251
+ `FFID Client: authMode \u304C\u4E0D\u6B63\u3067\u3059 (\u53D7\u4FE1: ${JSON.stringify(authMode)}, \u6709\u52B9\u5024: ${VALID_AUTH_MODES.join(" | ")})`
2252
+ );
2253
+ }
2254
+ if (authMode !== "service-key" && !scope) {
2255
+ const received = config.scope === void 0 ? "undefined" : JSON.stringify(config.scope);
2256
+ throw new Error(
2257
+ `FFID Client: scope \u304C\u672A\u8A2D\u5B9A\u3067\u3059 (\u53D7\u4FE1: ${received})\u3002\`DEFAULT_OAUTH_SCOPES\` \u3092 import \u3059\u308B\u304B\u3001\u660E\u793A\u7684\u306B scope \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 (#2674)`
2258
+ );
2259
+ }
2196
2260
  const clientId = config.clientId ?? config.serviceCode;
2197
2261
  const rawRedirectUri = config.redirectUri ?? null;
2198
2262
  const serviceApiKey = config.serviceApiKey?.trim();
@@ -2363,6 +2427,7 @@ function createFFIDClient(config) {
2363
2427
  baseUrl,
2364
2428
  clientId,
2365
2429
  serviceCode: config.serviceCode,
2430
+ scope,
2366
2431
  resolvedRedirectUri,
2367
2432
  logger
2368
2433
  });
@@ -2547,6 +2612,7 @@ var FFIDClientContext = react.createContext(null);
2547
2612
  function FFIDProvider({
2548
2613
  children,
2549
2614
  serviceCode,
2615
+ scope,
2550
2616
  apiBaseUrl,
2551
2617
  debug = false,
2552
2618
  logger,
@@ -2573,13 +2639,14 @@ function FFIDProvider({
2573
2639
  const client = react.useMemo(
2574
2640
  () => createFFIDClient({
2575
2641
  serviceCode,
2642
+ scope,
2576
2643
  apiBaseUrl,
2577
2644
  debug,
2578
2645
  logger,
2579
2646
  authMode,
2580
2647
  clientId
2581
2648
  }),
2582
- [serviceCode, apiBaseUrl, debug, logger, authMode, clientId]
2649
+ [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId]
2583
2650
  );
2584
2651
  const refresh = react.useCallback(async () => {
2585
2652
  client.logger.debug("Refreshing session...");
@@ -4571,6 +4638,7 @@ function FFIDInquiryForm({
4571
4638
  }
4572
4639
 
4573
4640
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
4641
+ exports.DEFAULT_OAUTH_SCOPES = DEFAULT_OAUTH_SCOPES;
4574
4642
  exports.FFIDAnnouncementBadge = FFIDAnnouncementBadge;
4575
4643
  exports.FFIDAnnouncementList = FFIDAnnouncementList;
4576
4644
  exports.FFIDInquiryForm = FFIDInquiryForm;
@@ -2,5 +2,7 @@
2
2
 
3
3
  // src/constants.ts
4
4
  var DEFAULT_API_BASE_URL = "https://id.feelflow.net";
5
+ var DEFAULT_OAUTH_SCOPES = "openid email profile subscription:read legal:read";
5
6
 
6
7
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
8
+ exports.DEFAULT_OAUTH_SCOPES = DEFAULT_OAUTH_SCOPES;
@@ -4,6 +4,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  // src/constants.ts
6
6
  var DEFAULT_API_BASE_URL = "https://id.feelflow.net";
7
+ var DEFAULT_OAUTH_SCOPES = "openid email profile subscription:read legal:read";
7
8
 
8
9
  // src/auth/token-store.ts
9
10
  var STORAGE_KEY = "ffid_tokens";
@@ -805,7 +806,7 @@ function createProfileMethods(deps) {
805
806
  }
806
807
 
807
808
  // src/client/version-check.ts
808
- var SDK_VERSION = "2.21.0";
809
+ var SDK_VERSION = "3.0.0";
809
810
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
810
811
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
811
812
  function sdkHeaders() {
@@ -1460,6 +1461,7 @@ function createRedirectMethods(deps) {
1460
1461
  baseUrl,
1461
1462
  clientId,
1462
1463
  serviceCode,
1464
+ scope,
1463
1465
  resolvedRedirectUri,
1464
1466
  logger
1465
1467
  } = deps;
@@ -1468,6 +1470,24 @@ function createRedirectMethods(deps) {
1468
1470
  logger.warn("SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093");
1469
1471
  return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
1470
1472
  }
1473
+ if (authMode === "service-key") {
1474
+ logger.error(
1475
+ "[FFID SDK] service-key \u30E2\u30FC\u30C9\u3067\u306F redirectToAuthorize \u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093 \u2014 server-to-server \u7528\u9014\u306E\u305F\u3081 OAuth \u30D6\u30E9\u30A6\u30B6 flow \u3092\u6301\u3061\u307E\u305B\u3093"
1476
+ );
1477
+ return {
1478
+ success: false,
1479
+ error: "service-key \u30E2\u30FC\u30C9\u3067\u306F OAuth \u8A8D\u53EF\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093"
1480
+ };
1481
+ }
1482
+ if (!scope || !scope.trim()) {
1483
+ logger.error(
1484
+ "[FFID SDK] scope \u304C\u672A\u8A2D\u5B9A\u306E\u305F\u3081 /oauth/authorize \u3092\u547C\u3073\u51FA\u305B\u307E\u305B\u3093 (#2674) \u2014 FFIDConfig.scope \u306B DEFAULT_OAUTH_SCOPES \u307E\u305F\u306F\u660E\u793A\u7684\u306A scope \u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044"
1485
+ );
1486
+ return {
1487
+ success: false,
1488
+ error: "OAuth scope \u304C\u672A\u8A2D\u5B9A\u306E\u305F\u3081\u8A8D\u53EF\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3092\u5B9F\u884C\u3067\u304D\u307E\u305B\u3093"
1489
+ };
1490
+ }
1471
1491
  const authorizeKey = buildAuthorizeKey(baseUrl, clientId, options?.organizationId);
1472
1492
  const now = Date.now();
1473
1493
  const recentCount = getRecentRedirectCount(authorizeKey, now, logger);
@@ -1500,6 +1520,7 @@ function createRedirectMethods(deps) {
1500
1520
  const params = new URLSearchParams({
1501
1521
  response_type: "code",
1502
1522
  client_id: clientId,
1523
+ scope,
1503
1524
  redirect_uri: redirectUri,
1504
1525
  state,
1505
1526
  code_challenge: challenge,
@@ -1982,6 +2003,7 @@ function createContractWizardMethods(deps) {
1982
2003
  var EXT_SUBSCRIBE_ENDPOINT2 = "/api/v1/ext/newsletter/subscribe";
1983
2004
  var CONFIRM_ENDPOINT = "/api/newsletter/confirm";
1984
2005
  var UNSUBSCRIBE_ENDPOINT = "/api/newsletter/unsubscribe";
2006
+ var DISPATCH_ENDPOINT = "/api/v1/newsletter/dispatch";
1985
2007
  function trimOrEmpty(s) {
1986
2008
  return typeof s === "string" ? s.trim() : "";
1987
2009
  }
@@ -2087,7 +2109,36 @@ function createNewsletterMethods(deps) {
2087
2109
  }
2088
2110
  );
2089
2111
  }
2090
- return { subscribe, confirm, unsubscribe };
2112
+ async function dispatch(params) {
2113
+ const subject = trimOrEmpty(params.subject);
2114
+ if (!subject) {
2115
+ return { error: createError("VALIDATION_ERROR", "subject \u306F\u5FC5\u9808\u3067\u3059") };
2116
+ }
2117
+ if (!params.body || typeof params.body !== "object") {
2118
+ return { error: createError("VALIDATION_ERROR", "body \u306F\u5FC5\u9808\u3067\u3059") };
2119
+ }
2120
+ const bodySource = params.body;
2121
+ const hasHtmlBody = typeof bodySource.htmlBody === "string" && bodySource.htmlBody.length > 0;
2122
+ const hasTemplateId = typeof bodySource.templateId === "string" && bodySource.templateId.length > 0;
2123
+ if (hasHtmlBody === hasTemplateId) {
2124
+ return {
2125
+ error: createError(
2126
+ "BODY_SOURCE_REQUIRED",
2127
+ "body \u306F htmlBody \u307E\u305F\u306F templateId \u306E\u3044\u305A\u308C\u304B\u4E00\u65B9\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
2128
+ )
2129
+ };
2130
+ }
2131
+ return fetchWithAuth(DISPATCH_ENDPOINT, {
2132
+ method: "POST",
2133
+ body: JSON.stringify({
2134
+ subject,
2135
+ articleUrl: params.articleUrl,
2136
+ body: params.body,
2137
+ segment: params.segment
2138
+ })
2139
+ });
2140
+ }
2141
+ return { subscribe, confirm, unsubscribe, dispatch };
2091
2142
  }
2092
2143
 
2093
2144
  // src/inquiry/ffid-inquiry-client.ts
@@ -2189,8 +2240,21 @@ function createFFIDClient(config) {
2189
2240
  if (!config.serviceCode || !config.serviceCode.trim()) {
2190
2241
  throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
2191
2242
  }
2243
+ const scope = config.scope?.trim() ?? "";
2192
2244
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
2193
2245
  const authMode = config.authMode ?? "cookie";
2246
+ const VALID_AUTH_MODES = ["cookie", "token", "service-key"];
2247
+ if (!VALID_AUTH_MODES.includes(authMode)) {
2248
+ throw new Error(
2249
+ `FFID Client: authMode \u304C\u4E0D\u6B63\u3067\u3059 (\u53D7\u4FE1: ${JSON.stringify(authMode)}, \u6709\u52B9\u5024: ${VALID_AUTH_MODES.join(" | ")})`
2250
+ );
2251
+ }
2252
+ if (authMode !== "service-key" && !scope) {
2253
+ const received = config.scope === void 0 ? "undefined" : JSON.stringify(config.scope);
2254
+ throw new Error(
2255
+ `FFID Client: scope \u304C\u672A\u8A2D\u5B9A\u3067\u3059 (\u53D7\u4FE1: ${received})\u3002\`DEFAULT_OAUTH_SCOPES\` \u3092 import \u3059\u308B\u304B\u3001\u660E\u793A\u7684\u306B scope \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 (#2674)`
2256
+ );
2257
+ }
2194
2258
  const clientId = config.clientId ?? config.serviceCode;
2195
2259
  const rawRedirectUri = config.redirectUri ?? null;
2196
2260
  const serviceApiKey = config.serviceApiKey?.trim();
@@ -2361,6 +2425,7 @@ function createFFIDClient(config) {
2361
2425
  baseUrl,
2362
2426
  clientId,
2363
2427
  serviceCode: config.serviceCode,
2428
+ scope,
2364
2429
  resolvedRedirectUri,
2365
2430
  logger
2366
2431
  });
@@ -2545,6 +2610,7 @@ var FFIDClientContext = createContext(null);
2545
2610
  function FFIDProvider({
2546
2611
  children,
2547
2612
  serviceCode,
2613
+ scope,
2548
2614
  apiBaseUrl,
2549
2615
  debug = false,
2550
2616
  logger,
@@ -2571,13 +2637,14 @@ function FFIDProvider({
2571
2637
  const client = useMemo(
2572
2638
  () => createFFIDClient({
2573
2639
  serviceCode,
2640
+ scope,
2574
2641
  apiBaseUrl,
2575
2642
  debug,
2576
2643
  logger,
2577
2644
  authMode,
2578
2645
  clientId
2579
2646
  }),
2580
- [serviceCode, apiBaseUrl, debug, logger, authMode, clientId]
2647
+ [serviceCode, scope, apiBaseUrl, debug, logger, authMode, clientId]
2581
2648
  );
2582
2649
  const refresh = useCallback(async () => {
2583
2650
  client.logger.debug("Refreshing session...");
@@ -4568,4 +4635,4 @@ function FFIDInquiryForm({
4568
4635
  );
4569
4636
  }
4570
4637
 
4571
- 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, computeEffectiveStatusFromSession, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
4638
+ export { DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, computeEffectiveStatusFromSession, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
@@ -1,34 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var chunkHUU4Q5VH_cjs = require('../chunk-HUU4Q5VH.cjs');
3
+ var chunkJNR4AKL5_cjs = require('../chunk-JNR4AKL5.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunkHUU4Q5VH_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkJNR4AKL5_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunkHUU4Q5VH_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkJNR4AKL5_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDInquiryForm", {
16
16
  enumerable: true,
17
- get: function () { return chunkHUU4Q5VH_cjs.FFIDInquiryForm; }
17
+ get: function () { return chunkJNR4AKL5_cjs.FFIDInquiryForm; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDLoginButton", {
20
20
  enumerable: true,
21
- get: function () { return chunkHUU4Q5VH_cjs.FFIDLoginButton; }
21
+ get: function () { return chunkJNR4AKL5_cjs.FFIDLoginButton; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
24
24
  enumerable: true,
25
- get: function () { return chunkHUU4Q5VH_cjs.FFIDOrganizationSwitcher; }
25
+ get: function () { return chunkJNR4AKL5_cjs.FFIDOrganizationSwitcher; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
28
28
  enumerable: true,
29
- get: function () { return chunkHUU4Q5VH_cjs.FFIDSubscriptionBadge; }
29
+ get: function () { return chunkJNR4AKL5_cjs.FFIDSubscriptionBadge; }
30
30
  });
31
31
  Object.defineProperty(exports, "FFIDUserMenu", {
32
32
  enumerable: true,
33
- get: function () { return chunkHUU4Q5VH_cjs.FFIDUserMenu; }
33
+ get: function () { return chunkJNR4AKL5_cjs.FFIDUserMenu; }
34
34
  });
@@ -1,3 +1,3 @@
1
- export { N as FFIDAnnouncementBadge, am as FFIDAnnouncementBadgeClassNames, an as FFIDAnnouncementBadgeProps, O as FFIDAnnouncementList, ao as FFIDAnnouncementListClassNames, ap as FFIDAnnouncementListProps, W as FFIDInquiryForm, X as FFIDInquiryFormCategoryItem, Y as FFIDInquiryFormClassNames, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, aq as FFIDLoginButtonProps, aa as FFIDOrganizationSwitcher, ar as FFIDOrganizationSwitcherClassNames, as as FFIDOrganizationSwitcherProps, ad as FFIDSubscriptionBadge, at as FFIDSubscriptionBadgeClassNames, au as FFIDSubscriptionBadgeProps, af as FFIDUserMenu, av as FFIDUserMenuClassNames, aw as FFIDUserMenuProps } from '../index-Dr5G9HQ4.cjs';
1
+ export { N as FFIDAnnouncementBadge, am as FFIDAnnouncementBadgeClassNames, an as FFIDAnnouncementBadgeProps, O as FFIDAnnouncementList, ao as FFIDAnnouncementListClassNames, ap as FFIDAnnouncementListProps, W as FFIDInquiryForm, X as FFIDInquiryFormCategoryItem, Y as FFIDInquiryFormClassNames, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, aq as FFIDLoginButtonProps, aa as FFIDOrganizationSwitcher, ar as FFIDOrganizationSwitcherClassNames, as as FFIDOrganizationSwitcherProps, ad as FFIDSubscriptionBadge, at as FFIDSubscriptionBadgeClassNames, au as FFIDSubscriptionBadgeProps, af as FFIDUserMenu, av as FFIDUserMenuClassNames, aw as FFIDUserMenuProps } from '../index-C3zyNa4j.cjs';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1,3 +1,3 @@
1
- export { N as FFIDAnnouncementBadge, am as FFIDAnnouncementBadgeClassNames, an as FFIDAnnouncementBadgeProps, O as FFIDAnnouncementList, ao as FFIDAnnouncementListClassNames, ap as FFIDAnnouncementListProps, W as FFIDInquiryForm, X as FFIDInquiryFormCategoryItem, Y as FFIDInquiryFormClassNames, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, aq as FFIDLoginButtonProps, aa as FFIDOrganizationSwitcher, ar as FFIDOrganizationSwitcherClassNames, as as FFIDOrganizationSwitcherProps, ad as FFIDSubscriptionBadge, at as FFIDSubscriptionBadgeClassNames, au as FFIDSubscriptionBadgeProps, af as FFIDUserMenu, av as FFIDUserMenuClassNames, aw as FFIDUserMenuProps } from '../index-Dr5G9HQ4.js';
1
+ export { N as FFIDAnnouncementBadge, am as FFIDAnnouncementBadgeClassNames, an as FFIDAnnouncementBadgeProps, O as FFIDAnnouncementList, ao as FFIDAnnouncementListClassNames, ap as FFIDAnnouncementListProps, W as FFIDInquiryForm, X as FFIDInquiryFormCategoryItem, Y as FFIDInquiryFormClassNames, Z as FFIDInquiryFormOrganization, _ as FFIDInquiryFormPlaceholderContext, $ as FFIDInquiryFormPrefill, a0 as FFIDInquiryFormProps, a1 as FFIDInquiryFormSubmitData, a2 as FFIDInquiryFormSubmitResult, a4 as FFIDLoginButton, aq as FFIDLoginButtonProps, aa as FFIDOrganizationSwitcher, ar as FFIDOrganizationSwitcherClassNames, as as FFIDOrganizationSwitcherProps, ad as FFIDSubscriptionBadge, at as FFIDSubscriptionBadgeClassNames, au as FFIDSubscriptionBadgeProps, af as FFIDUserMenu, av as FFIDUserMenuClassNames, aw as FFIDUserMenuProps } from '../index-C3zyNa4j.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-I7NEMG52.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-XWI4BFKW.js';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * FFID SDK Shared Constants
3
+ *
4
+ * Constants shared across all SDK entry points.
5
+ * Centralizing these prevents drift during domain/URL changes.
6
+ */
7
+ /** Default FFID API base URL (production) */
8
+ declare const DEFAULT_API_BASE_URL = "https://id.feelflow.net";
9
+ /**
10
+ * Recommended default OAuth scope set for FFID-connected services (v3.0.0+).
11
+ *
12
+ * Coverage:
13
+ * - `openid email profile` — OIDC standard claims (always required)
14
+ * - `subscription:read` — `/api/v1/subscriptions/ext/*` 系(プラン / 課金 gate)
15
+ * - `legal:read` — `/api/v1/legal/ext` 系(利用規約・同意状態)
16
+ *
17
+ * Add feature-specific scopes on top of this when needed (browser SDK):
18
+ * - `analytics:read` for `/api/v1/ext/analytics/config`
19
+ * - `organization:read` / `organization:write` for `/api/v1/organizations/ext/members`
20
+ * - `subscription:write` for self-serve plan changes
21
+ * - `legal:write` for recording user consent
22
+ * - `profile:read` / `profile:write` for profile UI
23
+ * - `organization:api-key` for org-level API key issuance
24
+ *
25
+ * **Note**: kept as a widened `string` (not `as const`) so consumers can
26
+ * concatenate additional scopes (e.g. `\`${DEFAULT_OAUTH_SCOPES} analytics:read\``)
27
+ * and so it remains assignable to `FFIDConfig.scope: string`. `widget:verify`
28
+ * is intentionally excluded — it is a service-key-only scope (`/api/v1/widget/*`),
29
+ * not used by the browser OAuth flow.
30
+ *
31
+ * Survey: feel-flow/feelflow-id-platform#2656 issuecomment-4324082742
32
+ */
33
+ declare const DEFAULT_OAUTH_SCOPES = "openid email profile subscription:read legal:read";
34
+
35
+ export { DEFAULT_API_BASE_URL as D, DEFAULT_OAUTH_SCOPES as a };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * FFID SDK Shared Constants
3
+ *
4
+ * Constants shared across all SDK entry points.
5
+ * Centralizing these prevents drift during domain/URL changes.
6
+ */
7
+ /** Default FFID API base URL (production) */
8
+ declare const DEFAULT_API_BASE_URL = "https://id.feelflow.net";
9
+ /**
10
+ * Recommended default OAuth scope set for FFID-connected services (v3.0.0+).
11
+ *
12
+ * Coverage:
13
+ * - `openid email profile` — OIDC standard claims (always required)
14
+ * - `subscription:read` — `/api/v1/subscriptions/ext/*` 系(プラン / 課金 gate)
15
+ * - `legal:read` — `/api/v1/legal/ext` 系(利用規約・同意状態)
16
+ *
17
+ * Add feature-specific scopes on top of this when needed (browser SDK):
18
+ * - `analytics:read` for `/api/v1/ext/analytics/config`
19
+ * - `organization:read` / `organization:write` for `/api/v1/organizations/ext/members`
20
+ * - `subscription:write` for self-serve plan changes
21
+ * - `legal:write` for recording user consent
22
+ * - `profile:read` / `profile:write` for profile UI
23
+ * - `organization:api-key` for org-level API key issuance
24
+ *
25
+ * **Note**: kept as a widened `string` (not `as const`) so consumers can
26
+ * concatenate additional scopes (e.g. `\`${DEFAULT_OAUTH_SCOPES} analytics:read\``)
27
+ * and so it remains assignable to `FFIDConfig.scope: string`. `widget:verify`
28
+ * is intentionally excluded — it is a service-key-only scope (`/api/v1/widget/*`),
29
+ * not used by the browser OAuth flow.
30
+ *
31
+ * Survey: feel-flow/feelflow-id-platform#2656 issuecomment-4324082742
32
+ */
33
+ declare const DEFAULT_OAUTH_SCOPES = "openid email profile subscription:read legal:read";
34
+
35
+ export { DEFAULT_API_BASE_URL as D, DEFAULT_OAUTH_SCOPES as a };
@@ -127,6 +127,40 @@ interface FFIDNewsletterUnsubscribeParams {
127
127
  interface FFIDNewsletterUnsubscribeResponse {
128
128
  ok: true;
129
129
  }
130
+ type FFIDNewsletterCampaignStatus = 'draft' | 'queued' | 'sending' | 'sent' | 'failed' | 'cancelled';
131
+ type FFIDNewsletterSegment = {
132
+ type: 'all';
133
+ } | {
134
+ type: 'filter';
135
+ conditions: Record<string, unknown>;
136
+ };
137
+ /**
138
+ * Body source XOR — exactly one of `htmlBody` / `templateId` must be set.
139
+ * V1 only ships `htmlBody`; `templateId` is reserved for SendGrid dynamic
140
+ * templates and is rejected server-side until that work lands.
141
+ */
142
+ type FFIDNewsletterBodySource = {
143
+ htmlBody: string;
144
+ templateId?: never;
145
+ } | {
146
+ templateId: string;
147
+ htmlBody?: never;
148
+ };
149
+ interface FFIDNewsletterDispatchParams {
150
+ subject: string;
151
+ /** Optional landing-page URL persisted on `newsletter_campaigns.article_url`. */
152
+ articleUrl?: string;
153
+ body: FFIDNewsletterBodySource;
154
+ /** Defaults to `{ type: 'all' }` server-side when omitted. */
155
+ segment?: FFIDNewsletterSegment;
156
+ }
157
+ interface FFIDNewsletterDispatchResponse {
158
+ campaignId: string;
159
+ totalRecipients: number;
160
+ status: FFIDNewsletterCampaignStatus;
161
+ sentCount: number;
162
+ failedCount: number;
163
+ }
130
164
 
131
165
  /** Cache adapter interface for FFID SDK token verification */
132
166
  /**
@@ -589,6 +623,19 @@ interface FFIDVerifyAccessTokenOptions {
589
623
  interface FFIDConfig {
590
624
  /** Service code to identify your application */
591
625
  serviceCode: string;
626
+ /**
627
+ * OAuth 2.0 scope (space-separated). Required since v3.0.0 (#2674).
628
+ *
629
+ * Use `DEFAULT_OAUTH_SCOPES` from `@feelflow/ffid-sdk` for the recommended
630
+ * baseline, or specify a least-privilege subset for your use case. Phase 3
631
+ * of `feelflow-id-platform#2656` will reject `/oauth/authorize` requests
632
+ * without this parameter, so passing an empty string here is also rejected
633
+ * — **except** in `service-key` mode (server-to-server, never calls
634
+ * `/oauth/authorize`), where `''` is permitted at runtime.
635
+ *
636
+ * @example 'openid email profile subscription:read legal:read'
637
+ */
638
+ scope: string;
592
639
  /** FFID API base URL (defaults to production) */
593
640
  apiBaseUrl?: string | undefined;
594
641
  /**
@@ -1125,6 +1172,7 @@ declare function createFFIDClient(config: FFIDConfig): {
1125
1172
  subscribe: (params: FFIDNewsletterSubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterSubscribeResponse>>;
1126
1173
  confirm: (params: FFIDNewsletterConfirmParams) => Promise<FFIDApiResponse<FFIDNewsletterConfirmResponse>>;
1127
1174
  unsubscribe: (params: FFIDNewsletterUnsubscribeParams) => Promise<FFIDApiResponse<FFIDNewsletterUnsubscribeResponse>>;
1175
+ dispatch: (params: FFIDNewsletterDispatchParams) => Promise<FFIDApiResponse<FFIDNewsletterDispatchResponse>>;
1128
1176
  };
1129
1177
  /** Inquiry methods (create) */
1130
1178
  inquiry: {