@feelflow/ffid-sdk 1.10.0 → 1.13.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.
@@ -5,6 +5,7 @@ var jose = require('jose');
5
5
 
6
6
  // src/auth/token-store.ts
7
7
  var STORAGE_KEY = "ffid_tokens";
8
+ var TOKEN_STORE_LOG_PREFIX = "[FFID SDK] TokenStore:";
8
9
  var EXPIRY_BUFFER_SECONDS = 30;
9
10
  var EXPIRY_BUFFER_MS = EXPIRY_BUFFER_SECONDS * 1e3;
10
11
  function isLocalStorageAvailable() {
@@ -28,22 +29,33 @@ function createLocalStorageStore() {
28
29
  const raw = storage.getItem(STORAGE_KEY);
29
30
  if (!raw) return null;
30
31
  const parsed = JSON.parse(raw);
31
- if (!isTokenData(parsed)) return null;
32
+ if (!isTokenData(parsed)) {
33
+ console.warn(TOKEN_STORE_LOG_PREFIX, "\u30C8\u30FC\u30AF\u30F3\u30C7\u30FC\u30BF\u304C\u4E0D\u6B63\u306A\u5F62\u5F0F\u3067\u3059\u3002\u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u30AF\u30EA\u30A2\u3057\u307E\u3059");
34
+ storage.removeItem(STORAGE_KEY);
35
+ return null;
36
+ }
32
37
  return parsed;
33
- } catch {
38
+ } catch (error) {
39
+ console.warn(TOKEN_STORE_LOG_PREFIX, "\u30C8\u30FC\u30AF\u30F3\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u7834\u640D\u30C7\u30FC\u30BF\u3092\u30AF\u30EA\u30A2\u3057\u307E\u3059", error);
40
+ try {
41
+ storage.removeItem(STORAGE_KEY);
42
+ } catch {
43
+ }
34
44
  return null;
35
45
  }
36
46
  },
37
47
  setTokens(tokens) {
38
48
  try {
39
49
  storage.setItem(STORAGE_KEY, JSON.stringify(tokens));
40
- } catch {
50
+ } catch (error) {
51
+ console.warn(TOKEN_STORE_LOG_PREFIX, "\u30C8\u30FC\u30AF\u30F3\u4FDD\u5B58\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF08\u30B9\u30C8\u30EC\u30FC\u30B8\u5BB9\u91CF\u8D85\u904E\u306E\u53EF\u80FD\u6027\uFF09", error);
41
52
  }
42
53
  },
43
54
  clearTokens() {
44
55
  try {
45
56
  storage.removeItem(STORAGE_KEY);
46
- } catch {
57
+ } catch (error) {
58
+ console.warn(TOKEN_STORE_LOG_PREFIX, "\u30C8\u30FC\u30AF\u30F3\u524A\u9664\u306B\u5931\u6557\u3057\u307E\u3057\u305F", error);
47
59
  }
48
60
  },
49
61
  isAccessTokenExpired() {
@@ -86,42 +98,6 @@ function createTokenStore(storageType) {
86
98
  return createMemoryStore();
87
99
  }
88
100
 
89
- // src/auth/pkce.ts
90
- var VERIFIER_STORAGE_KEY = "ffid_code_verifier";
91
- var CODE_VERIFIER_MIN_LENGTH = 43;
92
- var UNRESERVED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
93
- function generateCodeVerifier() {
94
- const length = CODE_VERIFIER_MIN_LENGTH;
95
- const randomValues = new Uint8Array(length);
96
- crypto.getRandomValues(randomValues);
97
- let verifier = "";
98
- for (let i = 0; i < length; i++) {
99
- verifier += UNRESERVED_CHARS[randomValues[i] % UNRESERVED_CHARS.length];
100
- }
101
- return verifier;
102
- }
103
- async function generateCodeChallenge(verifier) {
104
- const encoder = new TextEncoder();
105
- const data = encoder.encode(verifier);
106
- const digest = await crypto.subtle.digest("SHA-256", data);
107
- return base64UrlEncode(digest);
108
- }
109
- function storeCodeVerifier(verifier) {
110
- try {
111
- if (typeof window === "undefined") return;
112
- window.sessionStorage.setItem(VERIFIER_STORAGE_KEY, verifier);
113
- } catch {
114
- }
115
- }
116
- function base64UrlEncode(buffer) {
117
- const bytes = new Uint8Array(buffer);
118
- let binary = "";
119
- for (let i = 0; i < bytes.length; i++) {
120
- binary += String.fromCharCode(bytes[i]);
121
- }
122
- return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
123
- }
124
-
125
101
  // src/client/oauth-userinfo.ts
126
102
  var VALID_SUBSCRIPTION_STATUSES = ["trialing", "active", "past_due", "canceled", "paused"];
127
103
  function isValidSubscriptionStatus(value) {
@@ -225,6 +201,7 @@ var OAUTH_INTROSPECT_ENDPOINT = "/api/v1/oauth/introspect";
225
201
  var CACHE_KEY_PREFIX = "ffid:introspect:";
226
202
  var HEX_BASE = 16;
227
203
  var HEX_BYTE_WIDTH = 2;
204
+ var TOKEN_LOG_PREFIX_LENGTH = 8;
228
205
  function createVerifyAccessToken(deps) {
229
206
  const { authMode, baseUrl, serviceCode, serviceApiKey, verifyStrategy, logger, createError, errorCodes, cache, timeout } = deps;
230
207
  let jwtVerify2 = null;
@@ -240,7 +217,7 @@ function createVerifyAccessToken(deps) {
240
217
  }
241
218
  return jwtVerify2;
242
219
  }
243
- async function verifyAccessToken(accessToken) {
220
+ async function verifyAccessToken(accessToken, options) {
244
221
  if (authMode !== "service-key") {
245
222
  return {
246
223
  error: createError(
@@ -257,12 +234,24 @@ function createVerifyAccessToken(deps) {
257
234
  )
258
235
  };
259
236
  }
237
+ if (options?.includeProfile && verifyStrategy === "jwt" && !serviceApiKey) {
238
+ return {
239
+ error: createError(
240
+ errorCodes.TOKEN_VERIFICATION_ERROR,
241
+ "includeProfile: true \u3092\u4F7F\u7528\u3059\u308B\u306B\u306F serviceApiKey \u306E\u8A2D\u5B9A\u304C\u5FC5\u8981\u3067\u3059"
242
+ )
243
+ };
244
+ }
260
245
  if (verifyStrategy === "jwt") {
261
- return getJwtVerifier()(accessToken);
246
+ const jwtResult = await getJwtVerifier()(accessToken);
247
+ if (!options?.includeProfile || jwtResult.error) {
248
+ return jwtResult;
249
+ }
250
+ return verifyViaIntrospect(accessToken, "profile");
262
251
  }
263
252
  return verifyViaIntrospect(accessToken);
264
253
  }
265
- async function verifyViaIntrospect(accessToken) {
254
+ async function verifyViaIntrospect(accessToken, cacheKeySuffix) {
266
255
  if (!serviceApiKey) {
267
256
  return {
268
257
  error: createError(
@@ -273,7 +262,7 @@ function createVerifyAccessToken(deps) {
273
262
  }
274
263
  const url = `${baseUrl}${OAUTH_INTROSPECT_ENDPOINT}`;
275
264
  logger.debug("Verifying access token:", url);
276
- const cacheKey = await buildCacheKey(accessToken);
265
+ const cacheKey = cache ? await buildCacheKey(accessToken, cacheKeySuffix) : "";
277
266
  if (cache) {
278
267
  try {
279
268
  const cached = await cache.adapter.get(cacheKey);
@@ -375,16 +364,23 @@ function createVerifyAccessToken(deps) {
375
364
  }
376
365
  return { data: userinfo };
377
366
  }
378
- async function buildCacheKey(token) {
367
+ async function buildCacheKey(token, suffix) {
368
+ let key;
379
369
  if (typeof globalThis.crypto?.subtle?.digest === "function") {
380
370
  const encoder = new TextEncoder();
381
371
  const data = encoder.encode(token);
382
372
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
383
373
  const hashArray = Array.from(new Uint8Array(hashBuffer));
384
374
  const hashHex = hashArray.map((b) => b.toString(HEX_BASE).padStart(HEX_BYTE_WIDTH, "0")).join("");
385
- return CACHE_KEY_PREFIX + hashHex;
375
+ key = CACHE_KEY_PREFIX + hashHex;
376
+ } else {
377
+ const tokenPrefix = token.length > TOKEN_LOG_PREFIX_LENGTH ? token.substring(0, TOKEN_LOG_PREFIX_LENGTH) + "..." : "***";
378
+ logger.warn(
379
+ `crypto.subtle \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u3001\u30AD\u30E3\u30C3\u30B7\u30E5\u30AD\u30FC\u306B\u30CF\u30C3\u30B7\u30E5\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u30C8\u30FC\u30AF\u30F3\u3092\u4F7F\u7528\u3057\u307E\u3059 (token prefix: ${tokenPrefix})`
380
+ );
381
+ key = CACHE_KEY_PREFIX + token;
386
382
  }
387
- return CACHE_KEY_PREFIX + token;
383
+ return suffix ? `${key}:${suffix}` : key;
388
384
  }
389
385
  return verifyAccessToken;
390
386
  }
@@ -437,9 +433,15 @@ function createBillingMethods(deps) {
437
433
  }
438
434
 
439
435
  // src/client/version-check.ts
440
- var SDK_VERSION = "1.10.0";
436
+ var SDK_VERSION = "1.13.0";
441
437
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
442
438
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
439
+ function sdkHeaders() {
440
+ return {
441
+ "User-Agent": SDK_USER_AGENT,
442
+ [SDK_VERSION_HEADER]: SDK_VERSION
443
+ };
444
+ }
443
445
  var LATEST_VERSION_HEADER = "X-FFID-SDK-Latest-Version";
444
446
  var SEMVER_PATTERN = /^\d+(\.\d+)*$/;
445
447
  var _versionWarningShown = false;
@@ -473,213 +475,277 @@ npm install @feelflow/ffid-sdk@latest \u3067\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8
473
475
  }
474
476
  }
475
477
 
476
- // src/client/ffid-client.ts
477
- var NO_CONTENT_STATUS = 204;
478
- var SESSION_ENDPOINT = "/api/v1/auth/session";
479
- var LOGOUT_ENDPOINT = "/api/v1/auth/signout";
478
+ // src/client/oauth-token.ts
480
479
  var OAUTH_TOKEN_ENDPOINT = "/api/v1/oauth/token";
481
- var OAUTH_USERINFO_ENDPOINT = "/api/v1/oauth/userinfo";
482
- var OAUTH_AUTHORIZE_ENDPOINT = "/api/v1/oauth/authorize";
483
480
  var OAUTH_REVOKE_ENDPOINT = "/api/v1/oauth/revoke";
484
- var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
485
- var SDK_LOG_PREFIX = "[FFID SDK]";
486
481
  var MS_PER_SECOND = 1e3;
487
- var UNAUTHORIZED_STATUS = 401;
488
- var STATE_RANDOM_BYTES = 16;
489
- var HEX_BASE2 = 16;
490
- var noopLogger = {
491
- debug: () => {
492
- },
493
- info: () => {
494
- },
495
- warn: () => {
496
- },
497
- error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
498
- };
499
- var consoleLogger = {
500
- debug: (...args) => console.debug(SDK_LOG_PREFIX, ...args),
501
- info: (...args) => console.info(SDK_LOG_PREFIX, ...args),
502
- warn: (...args) => console.warn(SDK_LOG_PREFIX, ...args),
503
- error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
504
- };
505
- var FFID_ERROR_CODES = {
506
- NETWORK_ERROR: "NETWORK_ERROR",
507
- PARSE_ERROR: "PARSE_ERROR",
508
- UNKNOWN_ERROR: "UNKNOWN_ERROR",
509
- TOKEN_EXCHANGE_ERROR: "TOKEN_EXCHANGE_ERROR",
510
- TOKEN_REFRESH_ERROR: "TOKEN_REFRESH_ERROR",
511
- NO_TOKENS: "NO_TOKENS",
512
- TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
513
- };
514
- function createFFIDClient(config) {
515
- if (!config.serviceCode || !config.serviceCode.trim()) {
516
- throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
482
+ function validateTokenResponse(tokenResponse) {
483
+ const invalid = [];
484
+ if (!tokenResponse.access_token) {
485
+ invalid.push("access_token");
517
486
  }
518
- const baseUrl = config.apiBaseUrl ?? chunkYUIITYBE_cjs.DEFAULT_API_BASE_URL;
519
- const authMode = config.authMode ?? "cookie";
520
- const clientId = config.clientId ?? config.serviceCode;
521
- const resolvedRedirectUri = config.redirectUri ?? null;
522
- const serviceApiKey = config.serviceApiKey?.trim();
523
- const verifyStrategy = config.verifyStrategy ?? "jwt";
524
- const cache = config.cache;
525
- const timeout = config.timeout;
526
- if (authMode === "service-key" && !serviceApiKey) {
527
- throw new Error("FFID Client: service-key \u30E2\u30FC\u30C9\u3067\u306F serviceApiKey \u304C\u5FC5\u9808\u3067\u3059");
487
+ if (!tokenResponse.refresh_token) {
488
+ invalid.push("refresh_token");
528
489
  }
529
- if (cache && cache.ttl <= 0) {
530
- throw new Error("FFID Client: cache.ttl \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
490
+ if (typeof tokenResponse.expires_in !== "number" || tokenResponse.expires_in <= 0) {
491
+ invalid.push("expires_in");
531
492
  }
532
- if (timeout !== void 0 && timeout <= 0) {
533
- throw new Error("FFID Client: timeout \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
493
+ if (invalid.length > 0) {
494
+ return `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u4E0D\u6B63\u306A\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u3059: ${invalid.join(", ")}`;
534
495
  }
535
- const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
536
- const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
537
- async function fetchWithAuth(endpoint, options = {}) {
538
- const url = `${baseUrl}${endpoint}`;
539
- logger.debug("Fetching:", url);
540
- const fetchOptions = buildFetchOptions(options);
496
+ return null;
497
+ }
498
+ function createOAuthTokenMethods(deps) {
499
+ const {
500
+ baseUrl,
501
+ clientId,
502
+ resolvedRedirectUri,
503
+ tokenStore,
504
+ logger,
505
+ errorCodes
506
+ } = deps;
507
+ async function exchangeCodeForTokens(code, codeVerifier) {
508
+ const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
509
+ logger.debug("Exchanging code for tokens:", url);
510
+ const effectiveRedirectUri = resolvedRedirectUri ?? (typeof window !== "undefined" ? window.location.origin + window.location.pathname : null);
511
+ if (!effectiveRedirectUri) {
512
+ logger.error("redirectUri is required for token exchange in SSR environments. Set config.redirectUri explicitly.");
513
+ return {
514
+ error: {
515
+ code: errorCodes.TOKEN_EXCHANGE_ERROR,
516
+ message: "redirectUri \u304C\u672A\u8A2D\u5B9A\u3067\u3059\u3002SSR\u74B0\u5883\u3067\u306F config.redirectUri \u3092\u660E\u793A\u7684\u306B\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
517
+ }
518
+ };
519
+ }
520
+ const body = {
521
+ grant_type: "authorization_code",
522
+ code,
523
+ client_id: clientId,
524
+ redirect_uri: effectiveRedirectUri
525
+ };
526
+ if (codeVerifier) {
527
+ body.code_verifier = codeVerifier;
528
+ }
541
529
  let response;
542
530
  try {
543
- response = await fetch(url, fetchOptions);
531
+ response = await fetch(url, {
532
+ method: "POST",
533
+ credentials: "omit",
534
+ headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
535
+ body: new URLSearchParams(body).toString()
536
+ });
544
537
  } catch (error) {
545
- logger.error("Network error:", error);
538
+ logger.error("Network error during token exchange:", error);
546
539
  return {
547
540
  error: {
548
- code: FFID_ERROR_CODES.NETWORK_ERROR,
541
+ code: errorCodes.NETWORK_ERROR,
549
542
  message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
550
543
  }
551
544
  };
552
545
  }
553
- if (authMode === "token" && response.status === UNAUTHORIZED_STATUS) {
554
- const refreshResult = await refreshAccessToken();
555
- if (!refreshResult.error) {
556
- logger.debug("Token refreshed, retrying request");
557
- const retryOptions = buildFetchOptions(options);
558
- try {
559
- response = await fetch(url, retryOptions);
560
- } catch (retryError) {
561
- logger.error("Network error on retry:", retryError);
562
- return {
563
- error: {
564
- code: FFID_ERROR_CODES.NETWORK_ERROR,
565
- message: retryError instanceof Error ? retryError.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
566
- }
567
- };
568
- }
569
- }
570
- }
571
- let raw;
546
+ let tokenResponse;
572
547
  try {
573
- raw = await response.json();
548
+ tokenResponse = await response.json();
574
549
  } catch (parseError) {
575
- logger.error("Parse error:", parseError, "Status:", response.status);
550
+ logger.error("Parse error during token exchange:", parseError);
576
551
  return {
577
552
  error: {
578
- code: FFID_ERROR_CODES.PARSE_ERROR,
579
- message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
553
+ code: errorCodes.PARSE_ERROR,
554
+ message: `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F (status: ${response.status})`
580
555
  }
581
556
  };
582
557
  }
583
- logger.debug("Response:", response.status, raw);
584
- checkVersionHeader(response, logger);
585
558
  if (!response.ok) {
586
- return {
587
- error: raw.error ?? {
588
- code: FFID_ERROR_CODES.UNKNOWN_ERROR,
589
- message: "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
590
- }
591
- };
592
- }
593
- if (raw.data === void 0) {
559
+ const errorBody = tokenResponse;
594
560
  return {
595
561
  error: {
596
- code: FFID_ERROR_CODES.UNKNOWN_ERROR,
597
- message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
598
- }
599
- };
600
- }
601
- return { data: raw.data };
602
- }
603
- function sdkHeaders() {
604
- return {
605
- "User-Agent": SDK_USER_AGENT,
606
- [SDK_VERSION_HEADER]: SDK_VERSION
607
- };
608
- }
609
- function buildFetchOptions(options) {
610
- if (authMode === "service-key") {
611
- return {
612
- ...options,
613
- credentials: "omit",
614
- headers: {
615
- "Content-Type": "application/json",
616
- ...sdkHeaders(),
617
- "X-Service-Api-Key": serviceApiKey,
618
- ...options.headers
562
+ code: errorBody.error ?? errorCodes.TOKEN_EXCHANGE_ERROR,
563
+ message: errorBody.error_description ?? "\u30C8\u30FC\u30AF\u30F3\u4EA4\u63DB\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
619
564
  }
620
565
  };
621
566
  }
622
- if (authMode === "token") {
623
- const tokens = tokenStore.getTokens();
624
- const headers = {
625
- "Content-Type": "application/json",
626
- ...sdkHeaders(),
627
- ...options.headers
628
- };
629
- if (tokens) {
630
- headers["Authorization"] = `Bearer ${tokens.accessToken}`;
631
- }
632
- return {
633
- ...options,
634
- credentials: "omit",
635
- headers
636
- };
637
- }
638
- return {
639
- ...options,
640
- credentials: "include",
641
- headers: {
642
- "Content-Type": "application/json",
643
- ...sdkHeaders(),
644
- ...options.headers
645
- }
646
- };
647
- }
648
- async function getSession() {
649
- if (authMode === "token") {
650
- return getSessionFromUserinfo();
651
- }
652
- const result = await fetchWithAuth(SESSION_ENDPOINT);
653
- if (result.data?.user) {
567
+ const validationError = validateTokenResponse(tokenResponse);
568
+ if (validationError) {
569
+ logger.error("Token exchange validation failed:", validationError);
654
570
  return {
655
- ...result,
656
- data: {
657
- ...result.data,
658
- user: normalizeFFIDUser(result.data.user)
571
+ error: {
572
+ code: errorCodes.TOKEN_EXCHANGE_ERROR,
573
+ message: validationError
659
574
  }
660
575
  };
661
576
  }
662
- return result;
663
- }
664
- function normalizeFFIDUser(user) {
665
- return {
666
- ...user,
667
- locale: user.locale ?? null,
668
- timezone: user.timezone ?? null
669
- };
577
+ tokenStore.setTokens({
578
+ accessToken: tokenResponse.access_token,
579
+ refreshToken: tokenResponse.refresh_token,
580
+ expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
581
+ });
582
+ logger.debug("Token exchange successful");
583
+ return { data: void 0 };
670
584
  }
671
- async function getSessionFromUserinfo() {
585
+ async function refreshAccessToken() {
672
586
  const tokens = tokenStore.getTokens();
673
587
  if (!tokens) {
674
588
  return {
675
589
  error: {
676
- code: FFID_ERROR_CODES.NO_TOKENS,
677
- message: "\u30C8\u30FC\u30AF\u30F3\u304C\u4FDD\u5B58\u3055\u308C\u3066\u3044\u307E\u305B\u3093"
590
+ code: errorCodes.NO_TOKENS,
591
+ message: "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u304C\u3042\u308A\u307E\u305B\u3093"
678
592
  }
679
593
  };
680
594
  }
681
- const url = `${baseUrl}${OAUTH_USERINFO_ENDPOINT}`;
682
- logger.debug("Fetching userinfo:", url);
595
+ const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
596
+ logger.debug("Refreshing access token:", url);
597
+ let response;
598
+ try {
599
+ response = await fetch(url, {
600
+ method: "POST",
601
+ credentials: "omit",
602
+ headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
603
+ body: new URLSearchParams({
604
+ grant_type: "refresh_token",
605
+ refresh_token: tokens.refreshToken,
606
+ client_id: clientId
607
+ }).toString()
608
+ });
609
+ } catch (error) {
610
+ logger.error("Network error during token refresh:", error);
611
+ return {
612
+ error: {
613
+ code: errorCodes.NETWORK_ERROR,
614
+ message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
615
+ }
616
+ };
617
+ }
618
+ let tokenResponse;
619
+ try {
620
+ tokenResponse = await response.json();
621
+ } catch (parseError) {
622
+ logger.error("Parse error during token refresh:", parseError);
623
+ return {
624
+ error: {
625
+ code: errorCodes.PARSE_ERROR,
626
+ message: `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F (status: ${response.status})`
627
+ }
628
+ };
629
+ }
630
+ if (!response.ok) {
631
+ const errorBody = tokenResponse;
632
+ logger.error("Token refresh failed:", errorBody);
633
+ const irrecoverableErrors = ["token_revoked", "invalid_grant"];
634
+ if (errorBody.error && irrecoverableErrors.includes(errorBody.error)) {
635
+ tokenStore.clearTokens();
636
+ logger.debug("Cleared tokens due to irrecoverable refresh error:", errorBody.error);
637
+ }
638
+ return {
639
+ error: {
640
+ code: errorBody.error ?? errorCodes.TOKEN_REFRESH_ERROR,
641
+ message: errorBody.error_description ?? "\u30C8\u30FC\u30AF\u30F3\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
642
+ }
643
+ };
644
+ }
645
+ const validationError = validateTokenResponse(tokenResponse);
646
+ if (validationError) {
647
+ logger.error("Token refresh validation failed:", validationError);
648
+ return {
649
+ error: {
650
+ code: errorCodes.TOKEN_REFRESH_ERROR,
651
+ message: validationError
652
+ }
653
+ };
654
+ }
655
+ tokenStore.setTokens({
656
+ accessToken: tokenResponse.access_token,
657
+ refreshToken: tokenResponse.refresh_token,
658
+ expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
659
+ });
660
+ logger.debug("Token refresh successful");
661
+ return { data: void 0 };
662
+ }
663
+ async function signOutToken() {
664
+ const tokens = tokenStore.getTokens();
665
+ tokenStore.clearTokens();
666
+ if (!tokens) {
667
+ logger.debug("No tokens to revoke");
668
+ return { data: void 0 };
669
+ }
670
+ const url = `${baseUrl}${OAUTH_REVOKE_ENDPOINT}`;
671
+ logger.debug("Revoking token:", url);
672
+ try {
673
+ const response = await fetch(url, {
674
+ method: "POST",
675
+ credentials: "omit",
676
+ headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
677
+ body: new URLSearchParams({
678
+ token: tokens.accessToken,
679
+ client_id: clientId
680
+ }).toString()
681
+ });
682
+ if (!response.ok) {
683
+ logger.warn(
684
+ "\u30C8\u30FC\u30AF\u30F3\u7121\u52B9\u5316\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u30B5\u30FC\u30D0\u30FC\u3067\u5931\u6557\u3057\u307E\u3057\u305F:",
685
+ `status=${response.status}`
686
+ );
687
+ }
688
+ } catch (error) {
689
+ logger.warn("\u30C8\u30FC\u30AF\u30F3\u7121\u52B9\u5316\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30EA\u30AF\u30A8\u30B9\u30C8\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
690
+ }
691
+ logger.debug("Token sign-out completed");
692
+ return { data: void 0 };
693
+ }
694
+ return { exchangeCodeForTokens, refreshAccessToken, signOutToken };
695
+ }
696
+
697
+ // src/client/session.ts
698
+ var SESSION_ENDPOINT = "/api/v1/auth/session";
699
+ var LOGOUT_ENDPOINT = "/api/v1/auth/signout";
700
+ var OAUTH_USERINFO_ENDPOINT = "/api/v1/oauth/userinfo";
701
+ var NO_CONTENT_STATUS = 204;
702
+ var UNAUTHORIZED_STATUS = 401;
703
+ function normalizeFFIDUser(user) {
704
+ return {
705
+ ...user,
706
+ locale: user.locale ?? null,
707
+ timezone: user.timezone ?? null
708
+ };
709
+ }
710
+ function createSessionMethods(deps) {
711
+ const {
712
+ authMode,
713
+ baseUrl,
714
+ serviceCode,
715
+ tokenStore,
716
+ logger,
717
+ fetchWithAuth,
718
+ refreshAccessToken,
719
+ errorCodes
720
+ } = deps;
721
+ async function getSession() {
722
+ if (authMode === "token") {
723
+ return getSessionFromUserinfo();
724
+ }
725
+ const result = await fetchWithAuth(SESSION_ENDPOINT);
726
+ if (result.data?.user) {
727
+ return {
728
+ ...result,
729
+ data: {
730
+ ...result.data,
731
+ user: normalizeFFIDUser(result.data.user)
732
+ }
733
+ };
734
+ }
735
+ return result;
736
+ }
737
+ async function getSessionFromUserinfo() {
738
+ const tokens = tokenStore.getTokens();
739
+ if (!tokens) {
740
+ return {
741
+ error: {
742
+ code: errorCodes.NO_TOKENS,
743
+ message: "\u30C8\u30FC\u30AF\u30F3\u304C\u4FDD\u5B58\u3055\u308C\u3066\u3044\u307E\u305B\u3093"
744
+ }
745
+ };
746
+ }
747
+ const url = `${baseUrl}${OAUTH_USERINFO_ENDPOINT}`;
748
+ logger.debug("Fetching userinfo:", url);
683
749
  let response;
684
750
  try {
685
751
  response = await fetch(url, {
@@ -694,7 +760,7 @@ function createFFIDClient(config) {
694
760
  logger.error("Network error:", error);
695
761
  return {
696
762
  error: {
697
- code: FFID_ERROR_CODES.NETWORK_ERROR,
763
+ code: errorCodes.NETWORK_ERROR,
698
764
  message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
699
765
  }
700
766
  };
@@ -717,7 +783,7 @@ function createFFIDClient(config) {
717
783
  logger.error("Network error on retry:", retryError);
718
784
  return {
719
785
  error: {
720
- code: FFID_ERROR_CODES.NETWORK_ERROR,
786
+ code: errorCodes.NETWORK_ERROR,
721
787
  message: retryError instanceof Error ? retryError.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
722
788
  }
723
789
  };
@@ -734,7 +800,7 @@ function createFFIDClient(config) {
734
800
  logger.error("Parse error:", parseError, "Status:", response.status);
735
801
  return {
736
802
  error: {
737
- code: FFID_ERROR_CODES.PARSE_ERROR,
803
+ code: errorCodes.PARSE_ERROR,
738
804
  message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
739
805
  }
740
806
  };
@@ -743,7 +809,7 @@ function createFFIDClient(config) {
743
809
  const errorBody = rawUserinfo;
744
810
  return {
745
811
  error: {
746
- code: errorBody.code ?? FFID_ERROR_CODES.UNKNOWN_ERROR,
812
+ code: errorBody.code ?? errorCodes.UNKNOWN_ERROR,
747
813
  message: errorBody.message ?? "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
748
814
  }
749
815
  };
@@ -762,16 +828,10 @@ function createFFIDClient(config) {
762
828
  data: {
763
829
  user,
764
830
  organizations: [],
765
- subscriptions: mapUserinfoSubscriptionToSession(userinfo, config.serviceCode)
831
+ subscriptions: mapUserinfoSubscriptionToSession(userinfo, serviceCode)
766
832
  }
767
833
  };
768
834
  }
769
- async function signOut() {
770
- if (authMode === "token") {
771
- return signOutToken();
772
- }
773
- return signOutCookie();
774
- }
775
835
  async function signOutCookie() {
776
836
  const url = `${baseUrl}${LOGOUT_ENDPOINT}`;
777
837
  logger.debug("Fetching:", url);
@@ -786,7 +846,7 @@ function createFFIDClient(config) {
786
846
  logger.error("Network error:", error);
787
847
  return {
788
848
  error: {
789
- code: FFID_ERROR_CODES.NETWORK_ERROR,
849
+ code: errorCodes.NETWORK_ERROR,
790
850
  message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
791
851
  }
792
852
  };
@@ -800,14 +860,20 @@ function createFFIDClient(config) {
800
860
  const raw = await response.json();
801
861
  return {
802
862
  error: raw.error ?? {
803
- code: FFID_ERROR_CODES.UNKNOWN_ERROR,
863
+ code: errorCodes.UNKNOWN_ERROR,
804
864
  message: "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
805
865
  }
806
866
  };
807
- } catch {
867
+ } catch (parseError) {
868
+ logger.error(
869
+ "\u30B5\u30A4\u30F3\u30A2\u30A6\u30C8\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F:",
870
+ parseError,
871
+ "Status:",
872
+ response.status
873
+ );
808
874
  return {
809
875
  error: {
810
- code: FFID_ERROR_CODES.PARSE_ERROR,
876
+ code: errorCodes.PARSE_ERROR,
811
877
  message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
812
878
  }
813
879
  };
@@ -816,214 +882,567 @@ function createFFIDClient(config) {
816
882
  logger.debug("Response:", response.status);
817
883
  return { data: void 0 };
818
884
  }
819
- async function signOutToken() {
820
- const tokens = tokenStore.getTokens();
821
- tokenStore.clearTokens();
822
- if (!tokens) {
823
- logger.debug("No tokens to revoke");
824
- return { data: void 0 };
885
+ return { getSession, signOutCookie };
886
+ }
887
+
888
+ // src/auth/pkce.ts
889
+ var VERIFIER_STORAGE_KEY = "ffid_code_verifier";
890
+ var CODE_VERIFIER_MIN_LENGTH = 43;
891
+ var UNRESERVED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
892
+ function generateCodeVerifier() {
893
+ const length = CODE_VERIFIER_MIN_LENGTH;
894
+ const randomValues = new Uint8Array(length);
895
+ crypto.getRandomValues(randomValues);
896
+ let verifier = "";
897
+ for (let i = 0; i < length; i++) {
898
+ verifier += UNRESERVED_CHARS[randomValues[i] % UNRESERVED_CHARS.length];
899
+ }
900
+ return verifier;
901
+ }
902
+ async function generateCodeChallenge(verifier) {
903
+ const encoder = new TextEncoder();
904
+ const data = encoder.encode(verifier);
905
+ const digest = await crypto.subtle.digest("SHA-256", data);
906
+ return base64UrlEncode(digest);
907
+ }
908
+ function storeCodeVerifier(verifier, logger) {
909
+ try {
910
+ if (typeof window === "undefined") {
911
+ logger?.warn("storeCodeVerifier: sessionStorage is not available in SSR context");
912
+ return false;
825
913
  }
826
- const url = `${baseUrl}${OAUTH_REVOKE_ENDPOINT}`;
827
- logger.debug("Revoking token:", url);
914
+ window.sessionStorage.setItem(VERIFIER_STORAGE_KEY, verifier);
915
+ return true;
916
+ } catch (error) {
917
+ logger?.warn("storeCodeVerifier: sessionStorage \u3078\u306E\u4FDD\u5B58\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
918
+ return false;
919
+ }
920
+ }
921
+ function base64UrlEncode(buffer) {
922
+ const bytes = new Uint8Array(buffer);
923
+ let binary = "";
924
+ for (let i = 0; i < bytes.length; i++) {
925
+ binary += String.fromCharCode(bytes[i]);
926
+ }
927
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
928
+ }
929
+
930
+ // src/client/redirect.ts
931
+ var OAUTH_AUTHORIZE_ENDPOINT = "/api/v1/oauth/authorize";
932
+ var STATE_RANDOM_BYTES = 16;
933
+ var HEX_BASE2 = 16;
934
+ function generateRandomState() {
935
+ const array = new Uint8Array(STATE_RANDOM_BYTES);
936
+ crypto.getRandomValues(array);
937
+ return Array.from(array, (byte) => byte.toString(HEX_BASE2).padStart(2, "0")).join("");
938
+ }
939
+ function createRedirectMethods(deps) {
940
+ const {
941
+ authMode,
942
+ baseUrl,
943
+ clientId,
944
+ serviceCode,
945
+ resolvedRedirectUri,
946
+ logger
947
+ } = deps;
948
+ async function redirectToAuthorize() {
949
+ const verifier = generateCodeVerifier();
950
+ storeCodeVerifier(verifier, logger);
951
+ let challenge;
828
952
  try {
829
- await fetch(url, {
830
- method: "POST",
831
- credentials: "omit",
832
- headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
833
- body: new URLSearchParams({
834
- token: tokens.accessToken,
835
- client_id: clientId
836
- }).toString()
837
- });
953
+ challenge = await generateCodeChallenge(verifier);
838
954
  } catch (error) {
839
- logger.warn("Token revocation failed:", error);
955
+ const errorMessage = error instanceof Error ? error.message : "PKCE \u30B3\u30FC\u30C9\u30C1\u30E3\u30EC\u30F3\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F";
956
+ logger.error("PKCE \u30B3\u30FC\u30C9\u30C1\u30E3\u30EC\u30F3\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
957
+ return { success: false, error: errorMessage };
840
958
  }
841
- logger.debug("Token sign-out completed");
842
- return { data: void 0 };
959
+ const state = generateRandomState();
960
+ const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
961
+ const params = new URLSearchParams({
962
+ response_type: "code",
963
+ client_id: clientId,
964
+ redirect_uri: redirectUri,
965
+ state,
966
+ code_challenge: challenge,
967
+ code_challenge_method: "S256"
968
+ });
969
+ const authorizeUrl = `${baseUrl}${OAUTH_AUTHORIZE_ENDPOINT}?${params.toString()}`;
970
+ logger.debug("Redirecting to authorize:", authorizeUrl);
971
+ window.location.href = authorizeUrl;
972
+ return { success: true };
843
973
  }
844
- async function exchangeCodeForTokens(code, codeVerifier) {
845
- const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
846
- logger.debug("Exchanging code for tokens:", url);
847
- const effectiveRedirectUri = resolvedRedirectUri ?? (typeof window !== "undefined" ? window.location.origin + window.location.pathname : null);
848
- if (!effectiveRedirectUri) {
849
- logger.error("redirectUri is required for token exchange in SSR environments. Set config.redirectUri explicitly.");
850
- return {
851
- error: {
852
- code: FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR,
853
- message: "redirectUri \u304C\u672A\u8A2D\u5B9A\u3067\u3059\u3002SSR\u74B0\u5883\u3067\u306F config.redirectUri \u3092\u660E\u793A\u7684\u306B\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
854
- }
855
- };
974
+ async function redirectToLogin() {
975
+ if (typeof window === "undefined") {
976
+ logger.warn("SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093");
977
+ return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
856
978
  }
857
- const body = {
858
- grant_type: "authorization_code",
859
- code,
860
- client_id: clientId,
861
- redirect_uri: effectiveRedirectUri
862
- };
863
- if (codeVerifier) {
864
- body.code_verifier = codeVerifier;
979
+ if (authMode === "token") {
980
+ return redirectToAuthorize();
981
+ }
982
+ const currentUrl = window.location.href;
983
+ const loginUrl = `${baseUrl}/login?redirect=${encodeURIComponent(currentUrl)}&service=${encodeURIComponent(serviceCode)}`;
984
+ logger.debug("Redirecting to login:", loginUrl);
985
+ window.location.href = loginUrl;
986
+ return { success: true };
987
+ }
988
+ function getLoginUrl(redirectUrl) {
989
+ let redirect;
990
+ if (redirectUrl != null) {
991
+ redirect = redirectUrl;
992
+ } else if (typeof window !== "undefined") {
993
+ redirect = window.location.href;
994
+ } else {
995
+ logger.warn("getLoginUrl: SSR \u74B0\u5883\u3067 redirectUrl \u304C\u672A\u6307\u5B9A\u306E\u305F\u3081\u7A7A\u6587\u5B57\u306B\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059");
996
+ redirect = "";
997
+ }
998
+ return `${baseUrl}/login?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}`;
999
+ }
1000
+ function getSignupUrl(redirectUrl) {
1001
+ let redirect;
1002
+ if (redirectUrl != null) {
1003
+ redirect = redirectUrl;
1004
+ } else if (typeof window !== "undefined") {
1005
+ redirect = window.location.href;
1006
+ } else {
1007
+ logger.warn("getSignupUrl: SSR \u74B0\u5883\u3067 redirectUrl \u304C\u672A\u6307\u5B9A\u306E\u305F\u3081\u7A7A\u6587\u5B57\u306B\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059");
1008
+ redirect = "";
865
1009
  }
1010
+ return `${baseUrl}/signup?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}`;
1011
+ }
1012
+ return { redirectToLogin, redirectToAuthorize, getLoginUrl, getSignupUrl };
1013
+ }
1014
+
1015
+ // src/client/password-reset.ts
1016
+ var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
1017
+ function isBlank(value) {
1018
+ return !value || !value.trim();
1019
+ }
1020
+ function createPasswordResetMethods(deps) {
1021
+ const { baseUrl, logger, createError, fetchWithAuth, errorCodes } = deps;
1022
+ async function fetchPublic(endpoint, options = {}) {
1023
+ const url = `${baseUrl}${endpoint}`;
1024
+ logger.debug("Fetching (public):", url);
866
1025
  let response;
867
1026
  try {
868
1027
  response = await fetch(url, {
869
- method: "POST",
870
- credentials: "omit",
871
- headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
872
- body: new URLSearchParams(body).toString()
873
- });
874
- } catch (error) {
875
- logger.error("Network error during token exchange:", error);
876
- return {
877
- error: {
878
- code: FFID_ERROR_CODES.NETWORK_ERROR,
1028
+ ...options,
1029
+ credentials: "include",
1030
+ headers: {
1031
+ "Content-Type": "application/json",
1032
+ ...sdkHeaders(),
1033
+ ...options.headers
1034
+ }
1035
+ });
1036
+ } catch (error) {
1037
+ logger.error("Network error:", error);
1038
+ return {
1039
+ error: {
1040
+ code: errorCodes.NETWORK_ERROR,
879
1041
  message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
880
1042
  }
881
1043
  };
882
1044
  }
883
- let tokenResponse;
1045
+ let raw;
884
1046
  try {
885
- tokenResponse = await response.json();
1047
+ raw = await response.json();
886
1048
  } catch (parseError) {
887
- logger.error("Parse error during token exchange:", parseError);
1049
+ logger.error("Parse error:", parseError, "Status:", response.status);
888
1050
  return {
889
1051
  error: {
890
- code: FFID_ERROR_CODES.PARSE_ERROR,
891
- message: `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F (status: ${response.status})`
1052
+ code: errorCodes.PARSE_ERROR,
1053
+ message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
892
1054
  }
893
1055
  };
894
1056
  }
1057
+ logger.debug("Response (public):", response.status, raw);
1058
+ checkVersionHeader(response, logger);
895
1059
  if (!response.ok) {
896
- const errorBody = tokenResponse;
1060
+ return {
1061
+ error: raw.error ?? {
1062
+ code: errorCodes.UNKNOWN_ERROR,
1063
+ message: "\u30D1\u30B9\u30EF\u30FC\u30C9\u30EA\u30BB\u30C3\u30C8\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
1064
+ }
1065
+ };
1066
+ }
1067
+ if (raw.data === void 0) {
897
1068
  return {
898
1069
  error: {
899
- code: errorBody.error ?? FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR,
900
- message: errorBody.error_description ?? "\u30C8\u30FC\u30AF\u30F3\u4EA4\u63DB\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
1070
+ code: errorCodes.UNKNOWN_ERROR,
1071
+ message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
901
1072
  }
902
1073
  };
903
1074
  }
904
- tokenStore.setTokens({
905
- accessToken: tokenResponse.access_token,
906
- refreshToken: tokenResponse.refresh_token,
907
- expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
1075
+ return { data: raw.data };
1076
+ }
1077
+ async function requestPasswordReset(email) {
1078
+ if (isBlank(email)) {
1079
+ return {
1080
+ error: createError("VALIDATION_ERROR", "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059")
1081
+ };
1082
+ }
1083
+ return fetchPublic(
1084
+ RESET_PASSWORD_BASE,
1085
+ {
1086
+ method: "POST",
1087
+ body: JSON.stringify({ email })
1088
+ }
1089
+ );
1090
+ }
1091
+ async function verifyPasswordResetToken(accessToken) {
1092
+ if (isBlank(accessToken)) {
1093
+ return {
1094
+ error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
1095
+ };
1096
+ }
1097
+ const query = new URLSearchParams({
1098
+ access_token: accessToken,
1099
+ type: "recovery"
908
1100
  });
909
- logger.debug("Token exchange successful");
910
- return { data: void 0 };
1101
+ return fetchPublic(
1102
+ `${RESET_PASSWORD_BASE}/verify?${query.toString()}`
1103
+ );
911
1104
  }
912
- async function refreshAccessToken() {
913
- const tokens = tokenStore.getTokens();
914
- if (!tokens) {
1105
+ async function establishResetSession(accessToken, refreshToken) {
1106
+ if (isBlank(accessToken)) {
915
1107
  return {
916
- error: {
917
- code: FFID_ERROR_CODES.NO_TOKENS,
918
- message: "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u304C\u3042\u308A\u307E\u305B\u3093"
919
- }
1108
+ error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
920
1109
  };
921
1110
  }
922
- const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
923
- logger.debug("Refreshing access token:", url);
1111
+ if (isBlank(refreshToken)) {
1112
+ return {
1113
+ error: createError("VALIDATION_ERROR", "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
1114
+ };
1115
+ }
1116
+ return fetchPublic(
1117
+ `${RESET_PASSWORD_BASE}/session`,
1118
+ {
1119
+ method: "POST",
1120
+ body: JSON.stringify({ accessToken, refreshToken })
1121
+ }
1122
+ );
1123
+ }
1124
+ async function confirmPasswordReset(password) {
1125
+ if (isBlank(password)) {
1126
+ return {
1127
+ error: createError("VALIDATION_ERROR", "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5FC5\u9808\u3067\u3059")
1128
+ };
1129
+ }
1130
+ return fetchWithAuth(
1131
+ `${RESET_PASSWORD_BASE}/confirm`,
1132
+ {
1133
+ method: "POST",
1134
+ body: JSON.stringify({ password })
1135
+ }
1136
+ );
1137
+ }
1138
+ return {
1139
+ requestPasswordReset,
1140
+ verifyPasswordResetToken,
1141
+ establishResetSession,
1142
+ confirmPasswordReset
1143
+ };
1144
+ }
1145
+
1146
+ // src/client/otp.ts
1147
+ var OTP_BASE = "/api/v1/auth/otp";
1148
+ function isBlank2(value) {
1149
+ return !value || !value.trim();
1150
+ }
1151
+ function createOtpMethods(deps) {
1152
+ const { baseUrl, logger, createError, errorCodes } = deps;
1153
+ async function fetchPublic(endpoint, options = {}) {
1154
+ const url = `${baseUrl}${endpoint}`;
1155
+ logger.debug("Fetching (public):", url);
924
1156
  let response;
925
1157
  try {
926
1158
  response = await fetch(url, {
927
- method: "POST",
928
- credentials: "omit",
929
- headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
930
- body: new URLSearchParams({
931
- grant_type: "refresh_token",
932
- refresh_token: tokens.refreshToken,
933
- client_id: clientId
934
- }).toString()
1159
+ ...options,
1160
+ credentials: "include",
1161
+ headers: {
1162
+ "Content-Type": "application/json",
1163
+ ...sdkHeaders(),
1164
+ ...options.headers
1165
+ }
935
1166
  });
936
1167
  } catch (error) {
937
- logger.error("Network error during token refresh:", error);
1168
+ logger.error("Network error:", error);
938
1169
  return {
939
1170
  error: {
940
- code: FFID_ERROR_CODES.NETWORK_ERROR,
1171
+ code: errorCodes.NETWORK_ERROR,
941
1172
  message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
942
1173
  }
943
1174
  };
944
1175
  }
945
- let tokenResponse;
1176
+ let raw;
946
1177
  try {
947
- tokenResponse = await response.json();
1178
+ raw = await response.json();
948
1179
  } catch (parseError) {
949
- logger.error("Parse error during token refresh:", parseError);
1180
+ logger.error("Parse error:", parseError, "Status:", response.status);
950
1181
  return {
951
1182
  error: {
952
- code: FFID_ERROR_CODES.PARSE_ERROR,
953
- message: `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F (status: ${response.status})`
1183
+ code: errorCodes.PARSE_ERROR,
1184
+ message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
954
1185
  }
955
1186
  };
956
1187
  }
1188
+ logger.debug("Response (public):", response.status, raw);
1189
+ checkVersionHeader(response, logger);
957
1190
  if (!response.ok) {
958
- const errorBody = tokenResponse;
959
- logger.error("Token refresh failed:", errorBody);
960
- const irrecoverableErrors = ["token_revoked", "invalid_grant"];
961
- if (errorBody.error && irrecoverableErrors.includes(errorBody.error)) {
962
- tokenStore.clearTokens();
963
- logger.debug("Cleared tokens due to irrecoverable refresh error:", errorBody.error);
964
- }
1191
+ return {
1192
+ error: raw.error ?? {
1193
+ code: errorCodes.UNKNOWN_ERROR,
1194
+ message: "OTP\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
1195
+ }
1196
+ };
1197
+ }
1198
+ if (raw.data === void 0) {
965
1199
  return {
966
1200
  error: {
967
- code: errorBody.error ?? FFID_ERROR_CODES.TOKEN_REFRESH_ERROR,
968
- message: errorBody.error_description ?? "\u30C8\u30FC\u30AF\u30F3\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
1201
+ code: errorCodes.UNKNOWN_ERROR,
1202
+ message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
969
1203
  }
970
1204
  };
971
1205
  }
972
- tokenStore.setTokens({
973
- accessToken: tokenResponse.access_token,
974
- refreshToken: tokenResponse.refresh_token,
975
- expiresAt: Date.now() + tokenResponse.expires_in * MS_PER_SECOND
976
- });
977
- logger.debug("Token refresh successful");
978
- return { data: void 0 };
1206
+ return { data: raw.data };
979
1207
  }
980
- function redirectToLogin() {
981
- if (typeof window === "undefined") {
982
- logger.debug("Cannot redirect in SSR context");
983
- return false;
1208
+ async function sendOtp(email, options) {
1209
+ if (isBlank2(email)) {
1210
+ return {
1211
+ error: createError("VALIDATION_ERROR", "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059")
1212
+ };
984
1213
  }
985
- if (authMode === "token") {
986
- return redirectToAuthorize();
1214
+ return fetchPublic(
1215
+ `${OTP_BASE}/send`,
1216
+ {
1217
+ method: "POST",
1218
+ body: JSON.stringify({
1219
+ email,
1220
+ ...options?.redirectUrl ? { redirectUrl: options.redirectUrl } : {}
1221
+ })
1222
+ }
1223
+ );
1224
+ }
1225
+ async function verifyOtp(params) {
1226
+ if (isBlank2(params.accessToken)) {
1227
+ return {
1228
+ error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
1229
+ };
987
1230
  }
988
- const currentUrl = window.location.href;
989
- const loginUrl = `${baseUrl}/login?redirect=${encodeURIComponent(currentUrl)}&service=${encodeURIComponent(config.serviceCode)}`;
990
- logger.debug("Redirecting to login:", loginUrl);
991
- window.location.href = loginUrl;
992
- return true;
1231
+ if (isBlank2(params.refreshToken)) {
1232
+ return {
1233
+ error: createError("VALIDATION_ERROR", "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
1234
+ };
1235
+ }
1236
+ return fetchPublic(
1237
+ `${OTP_BASE}/verify`,
1238
+ {
1239
+ method: "POST",
1240
+ body: JSON.stringify({
1241
+ accessToken: params.accessToken,
1242
+ refreshToken: params.refreshToken
1243
+ })
1244
+ }
1245
+ );
993
1246
  }
994
- function redirectToAuthorize() {
995
- const verifier = generateCodeVerifier();
996
- storeCodeVerifier(verifier);
997
- generateCodeChallenge(verifier).then((challenge) => {
998
- const state = generateRandomState();
999
- const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
1000
- const params = new URLSearchParams({
1001
- response_type: "code",
1002
- client_id: clientId,
1003
- redirect_uri: redirectUri,
1004
- state,
1005
- code_challenge: challenge,
1006
- code_challenge_method: "S256"
1007
- });
1008
- const authorizeUrl = `${baseUrl}${OAUTH_AUTHORIZE_ENDPOINT}?${params.toString()}`;
1009
- logger.debug("Redirecting to authorize:", authorizeUrl);
1010
- window.location.href = authorizeUrl;
1011
- }).catch((error) => {
1012
- logger.error("Failed to generate code challenge:", error);
1013
- });
1014
- return true;
1247
+ return {
1248
+ sendOtp,
1249
+ verifyOtp
1250
+ };
1251
+ }
1252
+
1253
+ // src/client/ffid-client.ts
1254
+ var UNAUTHORIZED_STATUS2 = 401;
1255
+ var SDK_LOG_PREFIX = "[FFID SDK]";
1256
+ var noopLogger = {
1257
+ debug: () => {
1258
+ },
1259
+ info: () => {
1260
+ },
1261
+ warn: (...args) => console.warn(SDK_LOG_PREFIX, ...args),
1262
+ error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
1263
+ };
1264
+ var consoleLogger = {
1265
+ debug: (...args) => console.debug(SDK_LOG_PREFIX, ...args),
1266
+ info: (...args) => console.info(SDK_LOG_PREFIX, ...args),
1267
+ warn: (...args) => console.warn(SDK_LOG_PREFIX, ...args),
1268
+ error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
1269
+ };
1270
+ var FFID_ERROR_CODES = {
1271
+ NETWORK_ERROR: "NETWORK_ERROR",
1272
+ PARSE_ERROR: "PARSE_ERROR",
1273
+ UNKNOWN_ERROR: "UNKNOWN_ERROR",
1274
+ TOKEN_EXCHANGE_ERROR: "TOKEN_EXCHANGE_ERROR",
1275
+ TOKEN_REFRESH_ERROR: "TOKEN_REFRESH_ERROR",
1276
+ NO_TOKENS: "NO_TOKENS",
1277
+ TOKEN_VERIFICATION_ERROR: "TOKEN_VERIFICATION_ERROR"
1278
+ };
1279
+ var EXT_CHECK_ENDPOINT = "/api/v1/subscriptions/ext/check";
1280
+ function createFFIDClient(config) {
1281
+ if (!config.serviceCode || !config.serviceCode.trim()) {
1282
+ throw new Error("FFID Client: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
1015
1283
  }
1016
- function getLoginUrl(redirectUrl) {
1017
- const redirect = redirectUrl ?? (typeof window !== "undefined" ? window.location.href : "");
1018
- return `${baseUrl}/login?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(config.serviceCode)}`;
1284
+ const baseUrl = config.apiBaseUrl ?? chunkYUIITYBE_cjs.DEFAULT_API_BASE_URL;
1285
+ const authMode = config.authMode ?? "cookie";
1286
+ const clientId = config.clientId ?? config.serviceCode;
1287
+ const resolvedRedirectUri = config.redirectUri ?? null;
1288
+ const serviceApiKey = config.serviceApiKey?.trim();
1289
+ const verifyStrategy = config.verifyStrategy ?? "jwt";
1290
+ const cache = config.cache;
1291
+ const timeout = config.timeout;
1292
+ if (authMode === "service-key" && !serviceApiKey) {
1293
+ throw new Error("FFID Client: service-key \u30E2\u30FC\u30C9\u3067\u306F serviceApiKey \u304C\u5FC5\u9808\u3067\u3059");
1019
1294
  }
1020
- function getSignupUrl(redirectUrl) {
1021
- const redirect = redirectUrl ?? (typeof window !== "undefined" ? window.location.href : "");
1022
- return `${baseUrl}/signup?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(config.serviceCode)}`;
1295
+ if (cache && cache.ttl <= 0) {
1296
+ throw new Error("FFID Client: cache.ttl \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
1023
1297
  }
1298
+ if (timeout !== void 0 && timeout <= 0) {
1299
+ throw new Error("FFID Client: timeout \u306F\u6B63\u306E\u6570\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044");
1300
+ }
1301
+ const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
1302
+ const tokenStore = authMode === "token" ? createTokenStore() : createTokenStore("memory");
1024
1303
  function createError(code, message) {
1025
1304
  return { code, message };
1026
1305
  }
1306
+ function buildFetchOptions(options) {
1307
+ if (authMode === "service-key") {
1308
+ return {
1309
+ ...options,
1310
+ credentials: "omit",
1311
+ headers: {
1312
+ "Content-Type": "application/json",
1313
+ ...sdkHeaders(),
1314
+ "X-Service-Api-Key": serviceApiKey,
1315
+ ...options.headers
1316
+ }
1317
+ };
1318
+ }
1319
+ if (authMode === "token") {
1320
+ const tokens = tokenStore.getTokens();
1321
+ const headers = {
1322
+ "Content-Type": "application/json",
1323
+ ...sdkHeaders(),
1324
+ ...options.headers
1325
+ };
1326
+ if (tokens) {
1327
+ headers["Authorization"] = `Bearer ${tokens.accessToken}`;
1328
+ }
1329
+ return {
1330
+ ...options,
1331
+ credentials: "omit",
1332
+ headers
1333
+ };
1334
+ }
1335
+ return {
1336
+ ...options,
1337
+ credentials: "include",
1338
+ headers: {
1339
+ "Content-Type": "application/json",
1340
+ ...sdkHeaders(),
1341
+ ...options.headers
1342
+ }
1343
+ };
1344
+ }
1345
+ const { exchangeCodeForTokens, refreshAccessToken, signOutToken } = createOAuthTokenMethods({
1346
+ baseUrl,
1347
+ clientId,
1348
+ resolvedRedirectUri,
1349
+ tokenStore,
1350
+ logger,
1351
+ errorCodes: FFID_ERROR_CODES
1352
+ });
1353
+ async function fetchWithAuth(endpoint, options = {}) {
1354
+ const url = `${baseUrl}${endpoint}`;
1355
+ logger.debug("Fetching:", url);
1356
+ const fetchOptions = buildFetchOptions(options);
1357
+ let response;
1358
+ try {
1359
+ response = await fetch(url, fetchOptions);
1360
+ } catch (error) {
1361
+ logger.error("Network error:", error);
1362
+ return {
1363
+ error: {
1364
+ code: FFID_ERROR_CODES.NETWORK_ERROR,
1365
+ message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1366
+ }
1367
+ };
1368
+ }
1369
+ if (authMode === "token" && response.status === UNAUTHORIZED_STATUS2) {
1370
+ const refreshResult = await refreshAccessToken();
1371
+ if (!refreshResult.error) {
1372
+ logger.debug("Token refreshed, retrying request");
1373
+ const retryOptions = buildFetchOptions(options);
1374
+ try {
1375
+ response = await fetch(url, retryOptions);
1376
+ } catch (retryError) {
1377
+ logger.error("Network error on retry:", retryError);
1378
+ return {
1379
+ error: {
1380
+ code: FFID_ERROR_CODES.NETWORK_ERROR,
1381
+ message: retryError instanceof Error ? retryError.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1382
+ }
1383
+ };
1384
+ }
1385
+ } else {
1386
+ logger.warn("Token refresh failed, returning refresh error:", refreshResult.error);
1387
+ return { error: refreshResult.error };
1388
+ }
1389
+ }
1390
+ let raw;
1391
+ try {
1392
+ raw = await response.json();
1393
+ } catch (parseError) {
1394
+ logger.error("Parse error:", parseError, "Status:", response.status);
1395
+ return {
1396
+ error: {
1397
+ code: FFID_ERROR_CODES.PARSE_ERROR,
1398
+ message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
1399
+ }
1400
+ };
1401
+ }
1402
+ logger.debug("Response:", response.status, raw);
1403
+ checkVersionHeader(response, logger);
1404
+ if (!response.ok) {
1405
+ return {
1406
+ error: raw.error ?? {
1407
+ code: FFID_ERROR_CODES.UNKNOWN_ERROR,
1408
+ message: "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
1409
+ }
1410
+ };
1411
+ }
1412
+ if (raw.data === void 0) {
1413
+ return {
1414
+ error: {
1415
+ code: FFID_ERROR_CODES.UNKNOWN_ERROR,
1416
+ message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
1417
+ }
1418
+ };
1419
+ }
1420
+ return { data: raw.data };
1421
+ }
1422
+ const { getSession, signOutCookie } = createSessionMethods({
1423
+ authMode,
1424
+ baseUrl,
1425
+ serviceCode: config.serviceCode,
1426
+ tokenStore,
1427
+ logger,
1428
+ fetchWithAuth,
1429
+ refreshAccessToken,
1430
+ errorCodes: FFID_ERROR_CODES
1431
+ });
1432
+ async function signOut() {
1433
+ if (authMode === "token") {
1434
+ return signOutToken();
1435
+ }
1436
+ return signOutCookie();
1437
+ }
1438
+ const { redirectToLogin, getLoginUrl, getSignupUrl } = createRedirectMethods({
1439
+ authMode,
1440
+ baseUrl,
1441
+ clientId,
1442
+ serviceCode: config.serviceCode,
1443
+ resolvedRedirectUri,
1444
+ logger
1445
+ });
1027
1446
  async function checkSubscription(params) {
1028
1447
  if (!params.userId || !params.organizationId) {
1029
1448
  return {
@@ -1043,6 +1462,24 @@ function createFFIDClient(config) {
1043
1462
  fetchWithAuth,
1044
1463
  createError
1045
1464
  });
1465
+ const {
1466
+ requestPasswordReset,
1467
+ verifyPasswordResetToken,
1468
+ establishResetSession,
1469
+ confirmPasswordReset
1470
+ } = createPasswordResetMethods({
1471
+ baseUrl,
1472
+ logger,
1473
+ createError,
1474
+ fetchWithAuth,
1475
+ errorCodes: FFID_ERROR_CODES
1476
+ });
1477
+ const { sendOtp, verifyOtp } = createOtpMethods({
1478
+ baseUrl,
1479
+ logger,
1480
+ createError,
1481
+ errorCodes: FFID_ERROR_CODES
1482
+ });
1046
1483
  const verifyAccessToken = createVerifyAccessToken({
1047
1484
  authMode,
1048
1485
  baseUrl,
@@ -1068,6 +1505,12 @@ function createFFIDClient(config) {
1068
1505
  createCheckoutSession,
1069
1506
  createPortalSession,
1070
1507
  verifyAccessToken,
1508
+ requestPasswordReset,
1509
+ verifyPasswordResetToken,
1510
+ establishResetSession,
1511
+ confirmPasswordReset,
1512
+ sendOtp,
1513
+ verifyOtp,
1071
1514
  /** Token store (token mode only) */
1072
1515
  tokenStore,
1073
1516
  /** Resolved auth mode */
@@ -1080,11 +1523,6 @@ function createFFIDClient(config) {
1080
1523
  redirectUri: resolvedRedirectUri
1081
1524
  };
1082
1525
  }
1083
- function generateRandomState() {
1084
- const array = new Uint8Array(STATE_RANDOM_BYTES);
1085
- crypto.getRandomValues(array);
1086
- return Array.from(array, (byte) => byte.toString(HEX_BASE2).padStart(2, "0")).join("");
1087
- }
1088
1526
 
1089
1527
  // src/client/cache/memory-cache-adapter.ts
1090
1528
  var MS_PER_SECOND2 = 1e3;