@feelflow/ffid-sdk 2.12.0 → 2.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -761,7 +761,7 @@ function createMembersMethods(deps) {
761
761
  }
762
762
 
763
763
  // src/client/version-check.ts
764
- var SDK_VERSION = "2.12.0";
764
+ var SDK_VERSION = "2.12.1";
765
765
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
766
766
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
767
767
  function sdkHeaders() {
@@ -1384,6 +1384,23 @@ function createRedirectMethods(deps) {
1384
1384
  return { redirectToLogin, redirectToAuthorize, getLoginUrl, getSignupUrl, getLogoutUrl, redirectToLogout };
1385
1385
  }
1386
1386
 
1387
+ // src/client/redirect-uri.ts
1388
+ var AUTHORITY_BOUNDARY = /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^/?#]+)([/?#]?)/;
1389
+ function normalizeRedirectUri(input) {
1390
+ const url = new URL(input);
1391
+ const isRootPath = url.pathname === "" || url.pathname === "/";
1392
+ if (!isRootPath) {
1393
+ return { normalized: input, changed: false };
1394
+ }
1395
+ const match = input.match(AUTHORITY_BOUNDARY);
1396
+ if (match === null || match[2] === "/") {
1397
+ return { normalized: input, changed: false };
1398
+ }
1399
+ const authority = match[1];
1400
+ const rest = input.slice(authority.length);
1401
+ return { normalized: `${authority}/${rest}`, changed: true };
1402
+ }
1403
+
1387
1404
  // src/client/password-reset.ts
1388
1405
  var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
1389
1406
  function isBlank(value) {
@@ -1894,6 +1911,24 @@ var FFID_ERROR_CODES = {
1894
1911
  TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
1895
1912
  };
1896
1913
  var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
1914
+ function resolveRedirectUri(raw, logger) {
1915
+ if (raw === null) return null;
1916
+ try {
1917
+ const { normalized, changed } = normalizeRedirectUri(raw);
1918
+ if (changed) {
1919
+ logger.warn(
1920
+ `FFID Client: redirect_uri \u3092\u6B63\u898F\u5316\u3057\u307E\u3057\u305F (${raw} \u2192 ${normalized})\u3002FFID \u7BA1\u7406\u753B\u9762\u3067\u306E\u767B\u9332\u5024\u3068\u4E00\u81F4\u3055\u305B\u3066\u304F\u3060\u3055\u3044\u3002`
1921
+ );
1922
+ }
1923
+ return normalized;
1924
+ } catch (error) {
1925
+ logger.warn(
1926
+ `FFID Client: redirectUri \u306E\u30D1\u30FC\u30B9\u306B\u5931\u6557\u3057\u305F\u305F\u3081\u6B63\u898F\u5316\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F (${raw})`,
1927
+ error
1928
+ );
1929
+ return raw;
1930
+ }
1931
+ }
1897
1932
  function createFFIDClient(config) {
1898
1933
  if (!config.serviceCode || !config.serviceCode.trim()) {
1899
1934
  throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
@@ -1901,7 +1936,7 @@ function createFFIDClient(config) {
1901
1936
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
1902
1937
  const authMode = config.authMode ?? "cookie";
1903
1938
  const clientId = config.clientId ?? config.serviceCode;
1904
- const resolvedRedirectUri = config.redirectUri ?? null;
1939
+ const rawRedirectUri = config.redirectUri ?? null;
1905
1940
  const serviceApiKey = config.serviceApiKey?.trim();
1906
1941
  const verifyStrategy = config.verifyStrategy ?? "jwt";
1907
1942
  const cache = config.cache;
@@ -1916,6 +1951,7 @@ function createFFIDClient(config) {
1916
1951
  throw new Error("FFID Client: timeout \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
1917
1952
  }
1918
1953
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
1954
+ const resolvedRedirectUri = resolveRedirectUri(rawRedirectUri, logger);
1919
1955
  const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
1920
1956
  function createError(code, message) {
1921
1957
  return { code, message };
@@ -4134,6 +4170,7 @@ exports.createFFIDClient = createFFIDClient;
4134
4170
  exports.createTokenStore = createTokenStore;
4135
4171
  exports.generateCodeChallenge = generateCodeChallenge;
4136
4172
  exports.generateCodeVerifier = generateCodeVerifier;
4173
+ exports.normalizeRedirectUri = normalizeRedirectUri;
4137
4174
  exports.retrieveCodeVerifier = retrieveCodeVerifier;
4138
4175
  exports.storeCodeVerifier = storeCodeVerifier;
4139
4176
  exports.useFFID = useFFID;
@@ -759,7 +759,7 @@ function createMembersMethods(deps) {
759
759
  }
760
760
 
761
761
  // src/client/version-check.ts
762
- var SDK_VERSION = "2.12.0";
762
+ var SDK_VERSION = "2.12.1";
763
763
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
764
764
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
765
765
  function sdkHeaders() {
@@ -1382,6 +1382,23 @@ function createRedirectMethods(deps) {
1382
1382
  return { redirectToLogin, redirectToAuthorize, getLoginUrl, getSignupUrl, getLogoutUrl, redirectToLogout };
1383
1383
  }
1384
1384
 
1385
+ // src/client/redirect-uri.ts
1386
+ var AUTHORITY_BOUNDARY = /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^/?#]+)([/?#]?)/;
1387
+ function normalizeRedirectUri(input) {
1388
+ const url = new URL(input);
1389
+ const isRootPath = url.pathname === "" || url.pathname === "/";
1390
+ if (!isRootPath) {
1391
+ return { normalized: input, changed: false };
1392
+ }
1393
+ const match = input.match(AUTHORITY_BOUNDARY);
1394
+ if (match === null || match[2] === "/") {
1395
+ return { normalized: input, changed: false };
1396
+ }
1397
+ const authority = match[1];
1398
+ const rest = input.slice(authority.length);
1399
+ return { normalized: `${authority}/${rest}`, changed: true };
1400
+ }
1401
+
1385
1402
  // src/client/password-reset.ts
1386
1403
  var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
1387
1404
  function isBlank(value) {
@@ -1892,6 +1909,24 @@ var FFID_ERROR_CODES = {
1892
1909
  TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
1893
1910
  };
1894
1911
  var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
1912
+ function resolveRedirectUri(raw, logger) {
1913
+ if (raw === null) return null;
1914
+ try {
1915
+ const { normalized, changed } = normalizeRedirectUri(raw);
1916
+ if (changed) {
1917
+ logger.warn(
1918
+ `FFID Client: redirect_uri \u3092\u6B63\u898F\u5316\u3057\u307E\u3057\u305F (${raw} \u2192 ${normalized})\u3002FFID \u7BA1\u7406\u753B\u9762\u3067\u306E\u767B\u9332\u5024\u3068\u4E00\u81F4\u3055\u305B\u3066\u304F\u3060\u3055\u3044\u3002`
1919
+ );
1920
+ }
1921
+ return normalized;
1922
+ } catch (error) {
1923
+ logger.warn(
1924
+ `FFID Client: redirectUri \u306E\u30D1\u30FC\u30B9\u306B\u5931\u6557\u3057\u305F\u305F\u3081\u6B63\u898F\u5316\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F (${raw})`,
1925
+ error
1926
+ );
1927
+ return raw;
1928
+ }
1929
+ }
1895
1930
  function createFFIDClient(config) {
1896
1931
  if (!config.serviceCode || !config.serviceCode.trim()) {
1897
1932
  throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
@@ -1899,7 +1934,7 @@ function createFFIDClient(config) {
1899
1934
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
1900
1935
  const authMode = config.authMode ?? "cookie";
1901
1936
  const clientId = config.clientId ?? config.serviceCode;
1902
- const resolvedRedirectUri = config.redirectUri ?? null;
1937
+ const rawRedirectUri = config.redirectUri ?? null;
1903
1938
  const serviceApiKey = config.serviceApiKey?.trim();
1904
1939
  const verifyStrategy = config.verifyStrategy ?? "jwt";
1905
1940
  const cache = config.cache;
@@ -1914,6 +1949,7 @@ function createFFIDClient(config) {
1914
1949
  throw new Error("FFID Client: timeout \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
1915
1950
  }
1916
1951
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
1952
+ const resolvedRedirectUri = resolveRedirectUri(rawRedirectUri, logger);
1917
1953
  const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
1918
1954
  function createError(code, message) {
1919
1955
  return { code, message };
@@ -4115,4 +4151,4 @@ function FFIDInquiryForm({
4115
4151
  );
4116
4152
  }
4117
4153
 
4118
- export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
4154
+ export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useFFIDContext, useSubscription, withSubscription };
@@ -1,34 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var chunk5ZMR3NNO_cjs = require('../chunk-5ZMR3NNO.cjs');
3
+ var chunkDJPOGNAO_cjs = require('../chunk-DJPOGNAO.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunk5ZMR3NNO_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkDJPOGNAO_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunk5ZMR3NNO_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkDJPOGNAO_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDInquiryForm", {
16
16
  enumerable: true,
17
- get: function () { return chunk5ZMR3NNO_cjs.FFIDInquiryForm; }
17
+ get: function () { return chunkDJPOGNAO_cjs.FFIDInquiryForm; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDLoginButton", {
20
20
  enumerable: true,
21
- get: function () { return chunk5ZMR3NNO_cjs.FFIDLoginButton; }
21
+ get: function () { return chunkDJPOGNAO_cjs.FFIDLoginButton; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
24
24
  enumerable: true,
25
- get: function () { return chunk5ZMR3NNO_cjs.FFIDOrganizationSwitcher; }
25
+ get: function () { return chunkDJPOGNAO_cjs.FFIDOrganizationSwitcher; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
28
28
  enumerable: true,
29
- get: function () { return chunk5ZMR3NNO_cjs.FFIDSubscriptionBadge; }
29
+ get: function () { return chunkDJPOGNAO_cjs.FFIDSubscriptionBadge; }
30
30
  });
31
31
  Object.defineProperty(exports, "FFIDUserMenu", {
32
32
  enumerable: true,
33
- get: function () { return chunk5ZMR3NNO_cjs.FFIDUserMenu; }
33
+ get: function () { return chunkDJPOGNAO_cjs.FFIDUserMenu; }
34
34
  });
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-KJUA77BM.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-MDBV4WY3.js';
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk5ZMR3NNO_cjs = require('./chunk-5ZMR3NNO.cjs');
3
+ var chunkDJPOGNAO_cjs = require('./chunk-DJPOGNAO.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 } = chunk5ZMR3NNO_cjs.useFFIDContext();
49
+ const { isLoading, isAuthenticated, login } = chunkDJPOGNAO_cjs.useFFIDContext();
50
50
  const hasRedirected = react.useRef(false);
51
51
  react.useEffect(() => {
52
52
  if (!isLoading && !isAuthenticated && options.redirectToLogin && !hasRedirected.current) {
@@ -74,95 +74,99 @@ var FFID_NEWSLETTER_TYPES = ["inquiry_followup", "general"];
74
74
 
75
75
  Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
76
76
  enumerable: true,
77
- get: function () { return chunk5ZMR3NNO_cjs.DEFAULT_API_BASE_URL; }
77
+ get: function () { return chunkDJPOGNAO_cjs.DEFAULT_API_BASE_URL; }
78
78
  });
79
79
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
80
80
  enumerable: true,
81
- get: function () { return chunk5ZMR3NNO_cjs.FFIDAnnouncementBadge; }
81
+ get: function () { return chunkDJPOGNAO_cjs.FFIDAnnouncementBadge; }
82
82
  });
83
83
  Object.defineProperty(exports, "FFIDAnnouncementList", {
84
84
  enumerable: true,
85
- get: function () { return chunk5ZMR3NNO_cjs.FFIDAnnouncementList; }
85
+ get: function () { return chunkDJPOGNAO_cjs.FFIDAnnouncementList; }
86
86
  });
87
87
  Object.defineProperty(exports, "FFIDInquiryForm", {
88
88
  enumerable: true,
89
- get: function () { return chunk5ZMR3NNO_cjs.FFIDInquiryForm; }
89
+ get: function () { return chunkDJPOGNAO_cjs.FFIDInquiryForm; }
90
90
  });
91
91
  Object.defineProperty(exports, "FFIDLoginButton", {
92
92
  enumerable: true,
93
- get: function () { return chunk5ZMR3NNO_cjs.FFIDLoginButton; }
93
+ get: function () { return chunkDJPOGNAO_cjs.FFIDLoginButton; }
94
94
  });
95
95
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
96
96
  enumerable: true,
97
- get: function () { return chunk5ZMR3NNO_cjs.FFIDOrganizationSwitcher; }
97
+ get: function () { return chunkDJPOGNAO_cjs.FFIDOrganizationSwitcher; }
98
98
  });
99
99
  Object.defineProperty(exports, "FFIDProvider", {
100
100
  enumerable: true,
101
- get: function () { return chunk5ZMR3NNO_cjs.FFIDProvider; }
101
+ get: function () { return chunkDJPOGNAO_cjs.FFIDProvider; }
102
102
  });
103
103
  Object.defineProperty(exports, "FFIDSDKError", {
104
104
  enumerable: true,
105
- get: function () { return chunk5ZMR3NNO_cjs.FFIDSDKError; }
105
+ get: function () { return chunkDJPOGNAO_cjs.FFIDSDKError; }
106
106
  });
107
107
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
108
108
  enumerable: true,
109
- get: function () { return chunk5ZMR3NNO_cjs.FFIDSubscriptionBadge; }
109
+ get: function () { return chunkDJPOGNAO_cjs.FFIDSubscriptionBadge; }
110
110
  });
111
111
  Object.defineProperty(exports, "FFIDUserMenu", {
112
112
  enumerable: true,
113
- get: function () { return chunk5ZMR3NNO_cjs.FFIDUserMenu; }
113
+ get: function () { return chunkDJPOGNAO_cjs.FFIDUserMenu; }
114
114
  });
115
115
  Object.defineProperty(exports, "FFID_ANNOUNCEMENTS_ERROR_CODES", {
116
116
  enumerable: true,
117
- get: function () { return chunk5ZMR3NNO_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
117
+ get: function () { return chunkDJPOGNAO_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
118
118
  });
119
119
  Object.defineProperty(exports, "FFID_INQUIRY_CATEGORIES", {
120
120
  enumerable: true,
121
- get: function () { return chunk5ZMR3NNO_cjs.FFID_INQUIRY_CATEGORIES; }
121
+ get: function () { return chunkDJPOGNAO_cjs.FFID_INQUIRY_CATEGORIES; }
122
122
  });
123
123
  Object.defineProperty(exports, "createFFIDAnnouncementsClient", {
124
124
  enumerable: true,
125
- get: function () { return chunk5ZMR3NNO_cjs.createFFIDAnnouncementsClient; }
125
+ get: function () { return chunkDJPOGNAO_cjs.createFFIDAnnouncementsClient; }
126
126
  });
127
127
  Object.defineProperty(exports, "createFFIDClient", {
128
128
  enumerable: true,
129
- get: function () { return chunk5ZMR3NNO_cjs.createFFIDClient; }
129
+ get: function () { return chunkDJPOGNAO_cjs.createFFIDClient; }
130
130
  });
131
131
  Object.defineProperty(exports, "createTokenStore", {
132
132
  enumerable: true,
133
- get: function () { return chunk5ZMR3NNO_cjs.createTokenStore; }
133
+ get: function () { return chunkDJPOGNAO_cjs.createTokenStore; }
134
134
  });
135
135
  Object.defineProperty(exports, "generateCodeChallenge", {
136
136
  enumerable: true,
137
- get: function () { return chunk5ZMR3NNO_cjs.generateCodeChallenge; }
137
+ get: function () { return chunkDJPOGNAO_cjs.generateCodeChallenge; }
138
138
  });
139
139
  Object.defineProperty(exports, "generateCodeVerifier", {
140
140
  enumerable: true,
141
- get: function () { return chunk5ZMR3NNO_cjs.generateCodeVerifier; }
141
+ get: function () { return chunkDJPOGNAO_cjs.generateCodeVerifier; }
142
+ });
143
+ Object.defineProperty(exports, "normalizeRedirectUri", {
144
+ enumerable: true,
145
+ get: function () { return chunkDJPOGNAO_cjs.normalizeRedirectUri; }
142
146
  });
143
147
  Object.defineProperty(exports, "retrieveCodeVerifier", {
144
148
  enumerable: true,
145
- get: function () { return chunk5ZMR3NNO_cjs.retrieveCodeVerifier; }
149
+ get: function () { return chunkDJPOGNAO_cjs.retrieveCodeVerifier; }
146
150
  });
147
151
  Object.defineProperty(exports, "storeCodeVerifier", {
148
152
  enumerable: true,
149
- get: function () { return chunk5ZMR3NNO_cjs.storeCodeVerifier; }
153
+ get: function () { return chunkDJPOGNAO_cjs.storeCodeVerifier; }
150
154
  });
151
155
  Object.defineProperty(exports, "useFFID", {
152
156
  enumerable: true,
153
- get: function () { return chunk5ZMR3NNO_cjs.useFFID; }
157
+ get: function () { return chunkDJPOGNAO_cjs.useFFID; }
154
158
  });
155
159
  Object.defineProperty(exports, "useFFIDAnnouncements", {
156
160
  enumerable: true,
157
- get: function () { return chunk5ZMR3NNO_cjs.useFFIDAnnouncements; }
161
+ get: function () { return chunkDJPOGNAO_cjs.useFFIDAnnouncements; }
158
162
  });
159
163
  Object.defineProperty(exports, "useSubscription", {
160
164
  enumerable: true,
161
- get: function () { return chunk5ZMR3NNO_cjs.useSubscription; }
165
+ get: function () { return chunkDJPOGNAO_cjs.useSubscription; }
162
166
  });
163
167
  Object.defineProperty(exports, "withSubscription", {
164
168
  enumerable: true,
165
- get: function () { return chunk5ZMR3NNO_cjs.withSubscription; }
169
+ get: function () { return chunkDJPOGNAO_cjs.withSubscription; }
166
170
  });
167
171
  exports.FFID_NEWSLETTER_TYPES = FFID_NEWSLETTER_TYPES;
168
172
  exports.createKVCacheAdapter = createKVCacheAdapter;
package/dist/index.d.cts CHANGED
@@ -568,6 +568,25 @@ declare class FFIDSDKError extends Error {
568
568
  constructor(code: string, message: string);
569
569
  }
570
570
 
571
+ /**
572
+ * Redirect URI normalization (SDK copy)
573
+ *
574
+ * Kept in sync with `src/lib/common/redirect-uri.ts` in the FFID server
575
+ * repository. OAuth 2.1 exact-match comparison requires that both the
576
+ * registered redirect_uri (managed via the FFID admin UI) and the value
577
+ * sent by OAuth clients converge on the same canonical form — otherwise
578
+ * root-path URLs like `https://example.com` vs `https://example.com/`
579
+ * silently fail to match.
580
+ */
581
+ /** Result of a normalization attempt. */
582
+ interface NormalizeRedirectUriResult {
583
+ /** The normalized URL. `input` plus a trailing `/` if a root-path slash was appended; otherwise exactly `input`. */
584
+ readonly normalized: string;
585
+ /** True only when a trailing slash was appended to a root-path URL. */
586
+ readonly changed: boolean;
587
+ }
588
+ declare function normalizeRedirectUri(input: string): NormalizeRedirectUriResult;
589
+
571
590
  /**
572
591
  * Create an in-memory cache adapter using a Map.
573
592
  * Suitable for single-process environments (e.g., development, testing).
@@ -913,4 +932,4 @@ declare function createInquiryMethods(deps: InquiryMethodsDeps): {
913
932
  };
914
933
  type FFIDInquiryClient = ReturnType<typeof createInquiryMethods>;
915
934
 
916
- 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, type FFIDInquiryClient, FFIDInquiryCreateParams, FFIDInquiryCreateResponse, 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, type FFIDPreviewSeatChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, FFIDSDKError, type FFIDSeatChangeLineItem, type FFIDSeatChangePreview, type FFIDSeatChangePreviewResponse, 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 };
935
+ 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, type FFIDInquiryClient, FFIDInquiryCreateParams, FFIDInquiryCreateResponse, 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, type FFIDPreviewSeatChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, FFIDSDKError, type FFIDSeatChangeLineItem, type FFIDSeatChangePreview, type FFIDSeatChangePreviewResponse, 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 NormalizeRedirectUriResult, type RedirectToAuthorizeOptions, type TokenData, type TokenStore, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, createFFIDAnnouncementsClient, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, generateCodeChallenge, generateCodeVerifier, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useSubscription, withFFIDAuth, withSubscription };
package/dist/index.d.ts CHANGED
@@ -568,6 +568,25 @@ declare class FFIDSDKError extends Error {
568
568
  constructor(code: string, message: string);
569
569
  }
570
570
 
571
+ /**
572
+ * Redirect URI normalization (SDK copy)
573
+ *
574
+ * Kept in sync with `src/lib/common/redirect-uri.ts` in the FFID server
575
+ * repository. OAuth 2.1 exact-match comparison requires that both the
576
+ * registered redirect_uri (managed via the FFID admin UI) and the value
577
+ * sent by OAuth clients converge on the same canonical form — otherwise
578
+ * root-path URLs like `https://example.com` vs `https://example.com/`
579
+ * silently fail to match.
580
+ */
581
+ /** Result of a normalization attempt. */
582
+ interface NormalizeRedirectUriResult {
583
+ /** The normalized URL. `input` plus a trailing `/` if a root-path slash was appended; otherwise exactly `input`. */
584
+ readonly normalized: string;
585
+ /** True only when a trailing slash was appended to a root-path URL. */
586
+ readonly changed: boolean;
587
+ }
588
+ declare function normalizeRedirectUri(input: string): NormalizeRedirectUriResult;
589
+
571
590
  /**
572
591
  * Create an in-memory cache adapter using a Map.
573
592
  * Suitable for single-process environments (e.g., development, testing).
@@ -913,4 +932,4 @@ declare function createInquiryMethods(deps: InquiryMethodsDeps): {
913
932
  };
914
933
  type FFIDInquiryClient = ReturnType<typeof createInquiryMethods>;
915
934
 
916
- 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, type FFIDInquiryClient, FFIDInquiryCreateParams, FFIDInquiryCreateResponse, 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, type FFIDPreviewSeatChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, FFIDSDKError, type FFIDSeatChangeLineItem, type FFIDSeatChangePreview, type FFIDSeatChangePreviewResponse, 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 };
935
+ 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, type FFIDInquiryClient, FFIDInquiryCreateParams, FFIDInquiryCreateResponse, 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, type FFIDPreviewSeatChangeParams, FFIDProvider, type FFIDProviderProps, FFIDRedirectResult, FFIDRemoveMemberResponse, type FFIDResetSessionResponse, FFIDSDKError, type FFIDSeatChangeLineItem, type FFIDSeatChangePreview, type FFIDSeatChangePreviewResponse, 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 NormalizeRedirectUriResult, type RedirectToAuthorizeOptions, type TokenData, type TokenStore, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, createFFIDAnnouncementsClient, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, generateCodeChallenge, generateCodeVerifier, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useSubscription, withFFIDAuth, withSubscription };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useFFIDContext } from './chunk-KJUA77BM.js';
2
- export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-KJUA77BM.js';
1
+ import { useFFIDContext } from './chunk-MDBV4WY3.js';
2
+ export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_INQUIRY_CATEGORIES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, normalizeRedirectUri, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-MDBV4WY3.js';
3
3
  import { useRef, useEffect } from 'react';
4
4
  import { jsx, Fragment } from 'react/jsx-runtime';
5
5
 
@@ -757,7 +757,7 @@ function createMembersMethods(deps) {
757
757
  }
758
758
 
759
759
  // src/client/version-check.ts
760
- var SDK_VERSION = "2.12.0";
760
+ var SDK_VERSION = "2.12.1";
761
761
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
762
762
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
763
763
  function sdkHeaders() {
@@ -1367,6 +1367,23 @@ function createRedirectMethods(deps) {
1367
1367
  return { redirectToLogin, redirectToAuthorize, getLoginUrl, getSignupUrl, getLogoutUrl, redirectToLogout };
1368
1368
  }
1369
1369
 
1370
+ // src/client/redirect-uri.ts
1371
+ var AUTHORITY_BOUNDARY = /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^/?#]+)([/?#]?)/;
1372
+ function normalizeRedirectUri(input) {
1373
+ const url = new URL(input);
1374
+ const isRootPath = url.pathname === "" || url.pathname === "/";
1375
+ if (!isRootPath) {
1376
+ return { normalized: input, changed: false };
1377
+ }
1378
+ const match = input.match(AUTHORITY_BOUNDARY);
1379
+ if (match === null || match[2] === "/") {
1380
+ return { normalized: input, changed: false };
1381
+ }
1382
+ const authority = match[1];
1383
+ const rest = input.slice(authority.length);
1384
+ return { normalized: `${authority}/${rest}`, changed: true };
1385
+ }
1386
+
1370
1387
  // src/client/password-reset.ts
1371
1388
  var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
1372
1389
  function isBlank(value) {
@@ -1877,6 +1894,24 @@ var FFID_ERROR_CODES = {
1877
1894
  TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
1878
1895
  };
1879
1896
  var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
1897
+ function resolveRedirectUri(raw, logger) {
1898
+ if (raw === null) return null;
1899
+ try {
1900
+ const { normalized, changed } = normalizeRedirectUri(raw);
1901
+ if (changed) {
1902
+ logger.warn(
1903
+ `FFID Client: redirect_uri \u3092\u6B63\u898F\u5316\u3057\u307E\u3057\u305F (${raw} \u2192 ${normalized})\u3002FFID \u7BA1\u7406\u753B\u9762\u3067\u306E\u767B\u9332\u5024\u3068\u4E00\u81F4\u3055\u305B\u3066\u304F\u3060\u3055\u3044\u3002`
1904
+ );
1905
+ }
1906
+ return normalized;
1907
+ } catch (error) {
1908
+ logger.warn(
1909
+ `FFID Client: redirectUri \u306E\u30D1\u30FC\u30B9\u306B\u5931\u6557\u3057\u305F\u305F\u3081\u6B63\u898F\u5316\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F (${raw})`,
1910
+ error
1911
+ );
1912
+ return raw;
1913
+ }
1914
+ }
1880
1915
  function createFFIDClient(config) {
1881
1916
  if (!config.serviceCode || !config.serviceCode.trim()) {
1882
1917
  throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
@@ -1884,7 +1919,7 @@ function createFFIDClient(config) {
1884
1919
  const baseUrl = config.apiBaseUrl ?? chunkYUIITYBE_cjs.DEFAULT_API_BASE_URL;
1885
1920
  const authMode = config.authMode ?? "cookie";
1886
1921
  const clientId = config.clientId ?? config.serviceCode;
1887
- const resolvedRedirectUri = config.redirectUri ?? null;
1922
+ const rawRedirectUri = config.redirectUri ?? null;
1888
1923
  const serviceApiKey = config.serviceApiKey?.trim();
1889
1924
  const verifyStrategy = config.verifyStrategy ?? "jwt";
1890
1925
  const cache = config.cache;
@@ -1899,6 +1934,7 @@ function createFFIDClient(config) {
1899
1934
  throw new Error("FFID Client: timeout \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
1900
1935
  }
1901
1936
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
1937
+ const resolvedRedirectUri = resolveRedirectUri(rawRedirectUri, logger);
1902
1938
  const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
1903
1939
  function createError(code, message) {
1904
1940
  return { code, message };
@@ -756,7 +756,7 @@ function createMembersMethods(deps) {
756
756
  }
757
757
 
758
758
  // src/client/version-check.ts
759
- var SDK_VERSION = "2.12.0";
759
+ var SDK_VERSION = "2.12.1";
760
760
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
761
761
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
762
762
  function sdkHeaders() {
@@ -1366,6 +1366,23 @@ function createRedirectMethods(deps) {
1366
1366
  return { redirectToLogin, redirectToAuthorize, getLoginUrl, getSignupUrl, getLogoutUrl, redirectToLogout };
1367
1367
  }
1368
1368
 
1369
+ // src/client/redirect-uri.ts
1370
+ var AUTHORITY_BOUNDARY = /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^/?#]+)([/?#]?)/;
1371
+ function normalizeRedirectUri(input) {
1372
+ const url = new URL(input);
1373
+ const isRootPath = url.pathname === "" || url.pathname === "/";
1374
+ if (!isRootPath) {
1375
+ return { normalized: input, changed: false };
1376
+ }
1377
+ const match = input.match(AUTHORITY_BOUNDARY);
1378
+ if (match === null || match[2] === "/") {
1379
+ return { normalized: input, changed: false };
1380
+ }
1381
+ const authority = match[1];
1382
+ const rest = input.slice(authority.length);
1383
+ return { normalized: `${authority}/${rest}`, changed: true };
1384
+ }
1385
+
1369
1386
  // src/client/password-reset.ts
1370
1387
  var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
1371
1388
  function isBlank(value) {
@@ -1876,6 +1893,24 @@ var FFID_ERROR_CODES = {
1876
1893
  TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
1877
1894
  };
1878
1895
  var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
1896
+ function resolveRedirectUri(raw, logger) {
1897
+ if (raw === null) return null;
1898
+ try {
1899
+ const { normalized, changed } = normalizeRedirectUri(raw);
1900
+ if (changed) {
1901
+ logger.warn(
1902
+ `FFID Client: redirect_uri \u3092\u6B63\u898F\u5316\u3057\u307E\u3057\u305F (${raw} \u2192 ${normalized})\u3002FFID \u7BA1\u7406\u753B\u9762\u3067\u306E\u767B\u9332\u5024\u3068\u4E00\u81F4\u3055\u305B\u3066\u304F\u3060\u3055\u3044\u3002`
1903
+ );
1904
+ }
1905
+ return normalized;
1906
+ } catch (error) {
1907
+ logger.warn(
1908
+ `FFID Client: redirectUri \u306E\u30D1\u30FC\u30B9\u306B\u5931\u6557\u3057\u305F\u305F\u3081\u6B63\u898F\u5316\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F (${raw})`,
1909
+ error
1910
+ );
1911
+ return raw;
1912
+ }
1913
+ }
1879
1914
  function createFFIDClient(config) {
1880
1915
  if (!config.serviceCode || !config.serviceCode.trim()) {
1881
1916
  throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
@@ -1883,7 +1918,7 @@ function createFFIDClient(config) {
1883
1918
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
1884
1919
  const authMode = config.authMode ?? "cookie";
1885
1920
  const clientId = config.clientId ?? config.serviceCode;
1886
- const resolvedRedirectUri = config.redirectUri ?? null;
1921
+ const rawRedirectUri = config.redirectUri ?? null;
1887
1922
  const serviceApiKey = config.serviceApiKey?.trim();
1888
1923
  const verifyStrategy = config.verifyStrategy ?? "jwt";
1889
1924
  const cache = config.cache;
@@ -1898,6 +1933,7 @@ function createFFIDClient(config) {
1898
1933
  throw new Error("FFID Client: timeout \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
1899
1934
  }
1900
1935
  const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
1936
+ const resolvedRedirectUri = resolveRedirectUri(rawRedirectUri, logger);
1901
1937
  const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
1902
1938
  function createError(code, message) {
1903
1939
  return { code, message };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feelflow/ffid-sdk",
3
- "version": "2.12.0",
3
+ "version": "2.12.1",
4
4
  "description": "FeelFlow ID Platform SDK for React/Next.js applications",
5
5
  "keywords": [
6
6
  "feelflow",