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