@feelflow/ffid-sdk 5.22.0 → 5.24.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useFFIDContext, useSubscription } from './chunk-7NRO2TBG.js';
2
- export { ACCESS_GRANTING_EFFECTIVE_STATUSES, BLOCKING_EFFECTIVE_STATUSES, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_ERROR_CODES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, cleanupStateStorage as clearState, computeEffectiveStatusFromSession, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, handleRedirectCallback, hasAccessFromUserinfo, isBlockedFromUserinfo, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, retrieveState, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-7NRO2TBG.js';
1
+ import { useFFIDContext, useSubscription } from './chunk-7A2P3NII.js';
2
+ export { ACCESS_GRANTING_EFFECTIVE_STATUSES, BLOCKING_EFFECTIVE_STATUSES, DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES, EFFECTIVE_SUBSCRIPTION_STATUSES, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDInquiryForm, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSDKError, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, FFID_ERROR_CODES, FFID_INQUIRY_CATEGORIES, FFID_INQUIRY_CATEGORIES_SITE_2026, cleanupStateStorage as clearState, computeEffectiveStatusFromSession, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, handleRedirectCallback, hasAccessFromUserinfo, isBlockedFromUserinfo, isFFIDInquiryCategorySite2026, normalizeRedirectUri, retrieveCodeVerifier, retrieveState, storeCodeVerifier, storeState, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-7A2P3NII.js';
3
3
  export { ALL_DENIED_EXCEPT_NECESSARY, CONSENT_COOKIE_NAME, CONSENT_DISMISSAL_TIMESTAMP_KEY, COOKIE_VERSION, DEFAULT_CONSENT_ERROR_MESSAGES, FFIDAnalyticsProvider, FFIDConsentError, FFIDCookieBanner, FFIDCookieLink, FFIDCookieSettings, FFID_CONSENT_ERROR_CODES, clearConsentDismissalTimestamp, decodeConsentCookie, encodeConsentCookie, readConsentCookie, readConsentDismissalTimestamp, useFFIDConsent, useFFIDConsentPreferences, writeConsentCookie, writeConsentDismissalTimestamp } from './chunk-G7VOX64X.js';
4
4
  import { useEffect, useRef } from 'react';
5
5
  import { jsx, Fragment } from 'react/jsx-runtime';
@@ -1222,7 +1222,7 @@ function createNonContractMethods(deps) {
1222
1222
  }
1223
1223
 
1224
1224
  // src/client/version-check.ts
1225
- var SDK_VERSION = "5.22.0";
1225
+ var SDK_VERSION = "5.24.0";
1226
1226
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1227
1227
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1228
1228
  function sdkHeaders() {
@@ -1292,8 +1292,15 @@ function createOAuthTokenMethods(deps) {
1292
1292
  resolvedRedirectUri,
1293
1293
  tokenStore,
1294
1294
  logger,
1295
+ timeout,
1295
1296
  errorCodes
1296
1297
  } = deps;
1298
+ function withTimeout2(init) {
1299
+ if (timeout !== void 0) {
1300
+ return { ...init, signal: AbortSignal.timeout(timeout) };
1301
+ }
1302
+ return init;
1303
+ }
1297
1304
  async function exchangeCodeForTokens(code, codeVerifier, opts) {
1298
1305
  const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
1299
1306
  logger.debug("Exchanging code for tokens:", url);
@@ -1329,12 +1336,12 @@ function createOAuthTokenMethods(deps) {
1329
1336
  }
1330
1337
  let response;
1331
1338
  try {
1332
- response = await fetch(url, {
1339
+ response = await fetch(url, withTimeout2({
1333
1340
  method: "POST",
1334
1341
  credentials: "omit",
1335
1342
  headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
1336
1343
  body: new URLSearchParams(body).toString()
1337
- });
1344
+ }));
1338
1345
  } catch (error) {
1339
1346
  logger.error("Network error during token exchange:", error);
1340
1347
  return {
@@ -1397,7 +1404,7 @@ function createOAuthTokenMethods(deps) {
1397
1404
  logger.debug("Refreshing access token:", url);
1398
1405
  let response;
1399
1406
  try {
1400
- response = await fetch(url, {
1407
+ response = await fetch(url, withTimeout2({
1401
1408
  method: "POST",
1402
1409
  credentials: "omit",
1403
1410
  headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
@@ -1406,7 +1413,7 @@ function createOAuthTokenMethods(deps) {
1406
1413
  refresh_token: tokens.refreshToken,
1407
1414
  client_id: clientId
1408
1415
  }).toString()
1409
- });
1416
+ }));
1410
1417
  } catch (error) {
1411
1418
  logger.error("Network error during token refresh:", error);
1412
1419
  return {
@@ -1476,7 +1483,7 @@ function createOAuthTokenMethods(deps) {
1476
1483
  async function revokeOAuthToken(token, tokenTypeHint) {
1477
1484
  const url = `${baseUrl}${OAUTH_REVOKE_ENDPOINT}`;
1478
1485
  try {
1479
- const response = await fetch(url, {
1486
+ const response = await fetch(url, withTimeout2({
1480
1487
  method: "POST",
1481
1488
  credentials: "omit",
1482
1489
  headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
@@ -1485,9 +1492,10 @@ function createOAuthTokenMethods(deps) {
1485
1492
  client_id: clientId,
1486
1493
  token_type_hint: tokenTypeHint
1487
1494
  }).toString()
1488
- });
1495
+ }));
1489
1496
  return response.ok;
1490
- } catch {
1497
+ } catch (err) {
1498
+ logger.debug("Token revoke request failed (client-side; e.g. timeout/network):", err);
1491
1499
  return false;
1492
1500
  }
1493
1501
  }
@@ -2888,6 +2896,7 @@ function createFFIDClient(config) {
2888
2896
  resolvedRedirectUri,
2889
2897
  tokenStore,
2890
2898
  logger,
2899
+ timeout,
2891
2900
  errorCodes: FFID_ERROR_CODES
2892
2901
  });
2893
2902
  async function fetchWithAuth(endpoint, options = {}, authOverride) {
@@ -3382,6 +3391,271 @@ function getFFIDConsentFromCookieHeader(cookieHeader) {
3382
3391
  return decodeConsentCookie(decodeURIComponent(value));
3383
3392
  }
3384
3393
 
3394
+ // src/server/auth/server-state.ts
3395
+ var STATE_RANDOM_BYTES2 = 16;
3396
+ var HEX_RADIX = 16;
3397
+ function generateServerState() {
3398
+ const bytes = new Uint8Array(STATE_RANDOM_BYTES2);
3399
+ globalThis.crypto.getRandomValues(bytes);
3400
+ return Array.from(bytes, (b) => b.toString(HEX_RADIX).padStart(2, "0")).join("");
3401
+ }
3402
+
3403
+ // src/server/auth/server-oauth-token.ts
3404
+ var OAUTH_TOKEN_ENDPOINT2 = "/api/v1/oauth/token";
3405
+ var MS_PER_SECOND3 = 1e3;
3406
+ function withTimeout(init, timeout) {
3407
+ if (timeout !== void 0) {
3408
+ return { ...init, signal: AbortSignal.timeout(timeout) };
3409
+ }
3410
+ return init;
3411
+ }
3412
+ function validateTokenResponse2(r) {
3413
+ const invalid = [];
3414
+ if (!r.access_token) invalid.push("access_token");
3415
+ if (!r.refresh_token) invalid.push("refresh_token");
3416
+ if (typeof r.expires_in !== "number" || !Number.isFinite(r.expires_in) || r.expires_in <= 0) {
3417
+ invalid.push("expires_in");
3418
+ }
3419
+ return invalid.length > 0 ? `\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(", ")}` : null;
3420
+ }
3421
+ function toTokens(r) {
3422
+ return {
3423
+ accessToken: r.access_token,
3424
+ refreshToken: r.refresh_token,
3425
+ expiresAt: Date.now() + r.expires_in * MS_PER_SECOND3
3426
+ };
3427
+ }
3428
+ function fail(code, message) {
3429
+ return { error: { code, message } };
3430
+ }
3431
+ async function postToken(deps, body, fallbackErrorCode) {
3432
+ const url = `${deps.apiBaseUrl}${OAUTH_TOKEN_ENDPOINT2}`;
3433
+ let response;
3434
+ try {
3435
+ response = await fetch(
3436
+ url,
3437
+ withTimeout(
3438
+ {
3439
+ method: "POST",
3440
+ credentials: "omit",
3441
+ headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
3442
+ body: new URLSearchParams(body).toString()
3443
+ },
3444
+ deps.timeout
3445
+ )
3446
+ );
3447
+ } catch (error) {
3448
+ return fail(
3449
+ FFID_ERROR_CODES.NETWORK_ERROR,
3450
+ error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
3451
+ );
3452
+ }
3453
+ let json;
3454
+ try {
3455
+ json = await response.json();
3456
+ } catch {
3457
+ return fail(
3458
+ FFID_ERROR_CODES.PARSE_ERROR,
3459
+ `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F (status: ${response.status})`
3460
+ );
3461
+ }
3462
+ if (!response.ok) {
3463
+ const errorBody = json;
3464
+ return fail(errorBody.error ?? fallbackErrorCode, errorBody.error_description ?? "\u30C8\u30FC\u30AF\u30F3\u51E6\u7406\u306B\u5931\u6557\u3057\u307E\u3057\u305F");
3465
+ }
3466
+ const validationError = validateTokenResponse2(json);
3467
+ if (validationError) {
3468
+ return fail(fallbackErrorCode, validationError);
3469
+ }
3470
+ return { tokens: toTokens(json) };
3471
+ }
3472
+ function exchangeAuthorizationCodeServer(deps, code) {
3473
+ return postToken(
3474
+ deps,
3475
+ {
3476
+ grant_type: "authorization_code",
3477
+ code,
3478
+ client_id: deps.clientId,
3479
+ client_secret: deps.clientSecret,
3480
+ redirect_uri: deps.redirectUri
3481
+ },
3482
+ FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR
3483
+ );
3484
+ }
3485
+ function refreshTokensServer(deps, refreshToken) {
3486
+ return postToken(
3487
+ deps,
3488
+ {
3489
+ grant_type: "refresh_token",
3490
+ refresh_token: refreshToken,
3491
+ client_id: deps.clientId,
3492
+ client_secret: deps.clientSecret
3493
+ },
3494
+ FFID_ERROR_CODES.TOKEN_REFRESH_ERROR
3495
+ );
3496
+ }
3497
+
3498
+ // src/server/auth/server-auth-client.ts
3499
+ var OAUTH_AUTHORIZE_ENDPOINT2 = "/api/v1/oauth/authorize";
3500
+ var SCREEN_HINT_SIGNUP2 = "signup";
3501
+ function createServerAuthClient(config) {
3502
+ if (!config.serviceCode?.trim()) {
3503
+ throw new Error("FFID Server Auth: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
3504
+ }
3505
+ if (!config.clientSecret?.trim()) {
3506
+ throw new Error("FFID Server Auth: clientSecret \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
3507
+ }
3508
+ if (!config.redirectUri?.trim()) {
3509
+ throw new Error("FFID Server Auth: redirectUri \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
3510
+ }
3511
+ if (!config.scope?.trim()) {
3512
+ throw new Error(
3513
+ "FFID Server Auth: scope \u304C\u672A\u8A2D\u5B9A\u3067\u3059\u3002`DEFAULT_OAUTH_SCOPES` \u3092 import \u3059\u308B\u304B\u660E\u793A\u7684\u306B\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
3514
+ );
3515
+ }
3516
+ const apiBaseUrl = config.apiBaseUrl ?? chunkMDHKSVLP_cjs.DEFAULT_API_BASE_URL;
3517
+ const clientId = config.clientId ?? config.serviceCode;
3518
+ const deps = {
3519
+ apiBaseUrl,
3520
+ clientId,
3521
+ clientSecret: config.clientSecret,
3522
+ redirectUri: config.redirectUri,
3523
+ timeout: config.timeout
3524
+ };
3525
+ function buildAuthorizeUrl(opts) {
3526
+ const state = generateServerState();
3527
+ const params = new URLSearchParams({
3528
+ response_type: "code",
3529
+ client_id: clientId,
3530
+ scope: config.scope,
3531
+ redirect_uri: config.redirectUri,
3532
+ state
3533
+ });
3534
+ const organizationId = opts?.organizationId?.trim();
3535
+ if (organizationId) params.set("organization_id", organizationId);
3536
+ if (opts?.screenHint === SCREEN_HINT_SIGNUP2) params.set("screen_hint", SCREEN_HINT_SIGNUP2);
3537
+ if (opts?.prompt) params.set("prompt", opts.prompt);
3538
+ return { url: `${apiBaseUrl}${OAUTH_AUTHORIZE_ENDPOINT2}?${params.toString()}`, state };
3539
+ }
3540
+ async function handleCallback(input) {
3541
+ let url;
3542
+ try {
3543
+ url = typeof input.url === "string" ? new URL(input.url) : input.url;
3544
+ } catch {
3545
+ return {
3546
+ error: {
3547
+ code: FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR,
3548
+ message: "\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF URL \u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
3549
+ }
3550
+ };
3551
+ }
3552
+ const returnedState = url.searchParams.get("state") ?? void 0;
3553
+ if (!input.storedState || !returnedState || input.storedState !== returnedState) {
3554
+ return {
3555
+ error: {
3556
+ code: FFID_ERROR_CODES.STATE_MISMATCH_ERROR,
3557
+ message: "OAuth state \u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002CSRF \u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u8A8D\u8A3C\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
3558
+ }
3559
+ };
3560
+ }
3561
+ const errorParam = url.searchParams.get("error");
3562
+ if (errorParam) {
3563
+ return {
3564
+ error: {
3565
+ code: errorParam,
3566
+ message: url.searchParams.get("error_description") ?? "\u8A8D\u53EF\u30B5\u30FC\u30D0\u30FC\u304C\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F"
3567
+ }
3568
+ };
3569
+ }
3570
+ const code = url.searchParams.get("code");
3571
+ if (!code) {
3572
+ return {
3573
+ error: {
3574
+ code: FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR,
3575
+ message: "authorization code \u304C\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u306B\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093"
3576
+ }
3577
+ };
3578
+ }
3579
+ return exchangeAuthorizationCodeServer(deps, code);
3580
+ }
3581
+ function refresh(refreshToken) {
3582
+ return refreshTokensServer(deps, refreshToken);
3583
+ }
3584
+ return { buildAuthorizeUrl, handleCallback, refresh };
3585
+ }
3586
+
3587
+ // src/server/auth/session-cookies.ts
3588
+ var FFID_SESSION_COOKIE_NAME = "ffid_session";
3589
+ var DEFAULT_PATH = "/";
3590
+ var DEFAULT_SAME_SITE = "lax";
3591
+ var HOURS_PER_DAY2 = 24;
3592
+ var DEFAULT_MAX_AGE_DAYS = 30;
3593
+ var DEFAULT_MAX_AGE_SECONDS = 60 * 60 * HOURS_PER_DAY2 * DEFAULT_MAX_AGE_DAYS;
3594
+ var BASE64_GROUP = 4;
3595
+ function base64UrlEncode2(input) {
3596
+ const bytes = new TextEncoder().encode(input);
3597
+ const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join("");
3598
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
3599
+ }
3600
+ function base64UrlDecode(input) {
3601
+ const b64 = input.replace(/-/g, "+").replace(/_/g, "/");
3602
+ const remainder = b64.length % BASE64_GROUP;
3603
+ const padded = remainder === 0 ? b64 : b64 + "=".repeat(BASE64_GROUP - remainder);
3604
+ const bytes = Uint8Array.from(atob(padded), (char) => char.charCodeAt(0));
3605
+ return new TextDecoder().decode(bytes);
3606
+ }
3607
+ function sameSiteLabel(value) {
3608
+ return value.charAt(0).toUpperCase() + value.slice(1);
3609
+ }
3610
+ function buildSetCookie(nameValue, opts, maxAge) {
3611
+ const path = opts.path ?? DEFAULT_PATH;
3612
+ const sameSite = opts.sameSite ?? DEFAULT_SAME_SITE;
3613
+ const secure = opts.secure ?? true;
3614
+ const httpOnly = opts.httpOnly ?? true;
3615
+ const attrs = [nameValue, `Path=${path}`, `Max-Age=${maxAge}`, `SameSite=${sameSiteLabel(sameSite)}`];
3616
+ if (httpOnly) attrs.push("HttpOnly");
3617
+ if (secure) attrs.push("Secure");
3618
+ if (opts.domain) attrs.push(`Domain=${opts.domain}`);
3619
+ return attrs.join("; ");
3620
+ }
3621
+ function parseCookieHeader(header) {
3622
+ const out = {};
3623
+ for (const part of header.split(";")) {
3624
+ const eq = part.indexOf("=");
3625
+ if (eq === -1) continue;
3626
+ const key = part.slice(0, eq).trim();
3627
+ if (key) out[key] = part.slice(eq + 1).trim();
3628
+ }
3629
+ return out;
3630
+ }
3631
+ function serialize(tokens, opts = {}) {
3632
+ const value = base64UrlEncode2(JSON.stringify(tokens));
3633
+ const maxAge = opts.maxAge ?? DEFAULT_MAX_AGE_SECONDS;
3634
+ return [buildSetCookie(`${FFID_SESSION_COOKIE_NAME}=${value}`, opts, maxAge)];
3635
+ }
3636
+ function read(cookieHeader) {
3637
+ if (!cookieHeader) return null;
3638
+ const raw = parseCookieHeader(cookieHeader)[FFID_SESSION_COOKIE_NAME];
3639
+ if (!raw) return null;
3640
+ try {
3641
+ const parsed = JSON.parse(base64UrlDecode(raw));
3642
+ if (typeof parsed.accessToken !== "string" || typeof parsed.refreshToken !== "string" || typeof parsed.expiresAt !== "number") {
3643
+ return null;
3644
+ }
3645
+ return {
3646
+ accessToken: parsed.accessToken,
3647
+ refreshToken: parsed.refreshToken,
3648
+ expiresAt: parsed.expiresAt
3649
+ };
3650
+ } catch {
3651
+ return null;
3652
+ }
3653
+ }
3654
+ function clear(opts = {}) {
3655
+ return [buildSetCookie(`${FFID_SESSION_COOKIE_NAME}=`, opts, 0)];
3656
+ }
3657
+ var sessionCookies = { serialize, read, clear };
3658
+
3385
3659
  Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
3386
3660
  enumerable: true,
3387
3661
  get: function () { return chunkMDHKSVLP_cjs.DEFAULT_API_BASE_URL; }
@@ -3394,12 +3668,16 @@ exports.ALL_DENIED_EXCEPT_NECESSARY = ALL_DENIED_EXCEPT_NECESSARY;
3394
3668
  exports.CONSENT_COOKIE_NAME = CONSENT_COOKIE_NAME;
3395
3669
  exports.COOKIE_VERSION = COOKIE_VERSION;
3396
3670
  exports.FFID_ERROR_CODES = FFID_ERROR_CODES;
3671
+ exports.FFID_SESSION_COOKIE_NAME = FFID_SESSION_COOKIE_NAME;
3397
3672
  exports.createFFIDClient = createFFIDClient;
3398
3673
  exports.createKVCacheAdapter = createKVCacheAdapter;
3399
3674
  exports.createMemoryCacheAdapter = createMemoryCacheAdapter;
3675
+ exports.createServerAuthClient = createServerAuthClient;
3400
3676
  exports.createTokenStore = createTokenStore;
3401
3677
  exports.createVerifyAccessToken = createVerifyAccessToken;
3402
3678
  exports.decodeConsentCookie = decodeConsentCookie;
3403
3679
  exports.encodeConsentCookie = encodeConsentCookie;
3680
+ exports.generateServerState = generateServerState;
3404
3681
  exports.getFFIDConsentFromCookieHeader = getFFIDConsentFromCookieHeader;
3405
3682
  exports.getFFIDConsentFromCookies = getFFIDConsentFromCookies;
3683
+ exports.sessionCookies = sessionCookies;
@@ -1,5 +1,5 @@
1
- import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-CEJMpqRZ.cjs';
2
- export { f as FFIDAddMemberParams, g as FFIDAddMemberRequest, h as FFIDAddMemberResponse, i as FFIDAssignableMemberRole, j as FFIDCacheConfig, k as FFIDClient, l as FFIDConfig, m as FFIDListMembersResponse, n as FFIDMemberRole, o as FFIDOrganization, p as FFIDOrganizationMember, q as FFIDOtpSendResponse, r as FFIDOtpVerifyResponse, s as FFIDPasswordResetConfirmResponse, t as FFIDPasswordResetResponse, u as FFIDPasswordResetVerifyResponse, v as FFIDProfileCallOptions, w as FFIDProvisionMemberPlan, x as FFIDProvisionMemberPlanStatus, y as FFIDProvisionMemberResult, z as FFIDProvisionMemberStatus, A as FFIDProvisionOrganizationDryRun, B as FFIDProvisionOrganizationMemberInput, C as FFIDProvisionOrganizationOutcome, D as FFIDProvisionOrganizationParams, E as FFIDProvisionOrganizationResponse, G as FFIDProvisionUserDryRun, H as FFIDProvisionUserOutcome, I as FFIDProvisionUserParams, J as FFIDProvisionUserProfileInput, K as FFIDProvisionUserResponse, L as FFIDProvisionedOrganization, M as FFIDProvisionedUser, N as FFIDRemoveMemberResponse, O as FFIDResetSessionResponse, P as FFIDSubscription, Q as FFIDUpdateMemberRoleResponse, R as FFIDUpdateUserProfileRequest, S as FFIDUser, T as FFIDUserProfile, U as TokenData, V as TokenStore, W as createFFIDClient, X as createTokenStore } from '../ffid-client-CEJMpqRZ.cjs';
1
+ import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-D0Jh4bO7.cjs';
2
+ export { f as FFIDAddMemberParams, g as FFIDAddMemberRequest, h as FFIDAddMemberResponse, i as FFIDAssignableMemberRole, j as FFIDCacheConfig, k as FFIDClient, l as FFIDConfig, m as FFIDListMembersResponse, n as FFIDMemberRole, o as FFIDOrganization, p as FFIDOrganizationMember, q as FFIDOtpSendResponse, r as FFIDOtpVerifyResponse, s as FFIDPasswordResetConfirmResponse, t as FFIDPasswordResetResponse, u as FFIDPasswordResetVerifyResponse, v as FFIDProfileCallOptions, w as FFIDProvisionMemberPlan, x as FFIDProvisionMemberPlanStatus, y as FFIDProvisionMemberResult, z as FFIDProvisionMemberStatus, A as FFIDProvisionOrganizationDryRun, B as FFIDProvisionOrganizationMemberInput, C as FFIDProvisionOrganizationOutcome, D as FFIDProvisionOrganizationParams, E as FFIDProvisionOrganizationResponse, G as FFIDProvisionUserDryRun, H as FFIDProvisionUserOutcome, I as FFIDProvisionUserParams, J as FFIDProvisionUserProfileInput, K as FFIDProvisionUserResponse, L as FFIDProvisionedOrganization, M as FFIDProvisionedUser, N as FFIDRemoveMemberResponse, O as FFIDResetSessionResponse, P as FFIDSubscription, Q as FFIDUpdateMemberRoleResponse, R as FFIDUpdateUserProfileRequest, S as FFIDUser, T as FFIDUserProfile, U as TokenData, V as TokenStore, W as createFFIDClient, X as createTokenStore } from '../ffid-client-D0Jh4bO7.cjs';
3
3
  export { D as DEFAULT_API_BASE_URL, a as DEFAULT_OAUTH_SCOPES } from '../constants-D61jqRIO.cjs';
4
4
  import { z } from 'zod';
5
5
  import '../types-Cjb9J0rL.cjs';
@@ -233,4 +233,160 @@ declare function decodeConsentCookie(raw: string | null | undefined): FFIDConsen
233
233
 
234
234
  declare const CONSENT_COOKIE_NAME = "ffid_consent";
235
235
 
236
- export { ALL_DENIED_EXCEPT_NECESSARY, CONSENT_COOKIE_NAME, COOKIE_VERSION, FFIDCacheAdapter, type FFIDConsentCategories, type FFIDConsentCategoryCode, type FFIDCookieStoreLike, type FFIDErrorCode, FFIDOAuthUserInfo, FFIDVerifyAccessTokenOptions, FFID_ERROR_CODES, type KVNamespaceLike, createKVCacheAdapter, createMemoryCacheAdapter, createVerifyAccessToken, decodeConsentCookie, encodeConsentCookie, getFFIDConsentFromCookieHeader, getFFIDConsentFromCookies };
236
+ /**
237
+ * Public types for the confidential / BFF server auth helpers (#4261 / #4269).
238
+ * React/DOM-free — see `src/server/auth/server-auth-client.ts`.
239
+ */
240
+
241
+ /** Configuration for {@link createServerAuthClient}. */
242
+ interface ServerAuthConfig {
243
+ /** FFID service code (== OAuth `client_id` unless `clientId` is overridden). */
244
+ serviceCode: string;
245
+ /** OAuth `client_id`. Defaults to `serviceCode`. */
246
+ clientId?: string;
247
+ /**
248
+ * confidential-client secret — a `service_api_key` (`ffid_sk_live_…`) carrying
249
+ * the `oauth:client_auth` scope (PR-A1 #4267). Read from a server-only env var;
250
+ * never sent to the browser.
251
+ */
252
+ clientSecret: string;
253
+ /** FFID API base URL. Defaults to `DEFAULT_API_BASE_URL` (`https://id.feelflow.net`). */
254
+ apiBaseUrl?: string;
255
+ /** Server callback URL, registered in the service's `allowed_redirect_uris`. */
256
+ redirectUri: string;
257
+ /** OAuth scope (space-separated), forwarded to `/oauth/authorize?scope=…`. */
258
+ scope: string;
259
+ /**
260
+ * Optional request timeout (ms) applied to token fetches via
261
+ * `AbortSignal.timeout` (#4260). Unset → no timeout (fetch default).
262
+ */
263
+ timeout?: number | undefined;
264
+ }
265
+ /** Session tokens established by the BFF flow. Persist via {@link sessionCookies}. */
266
+ interface ServerSessionTokens {
267
+ accessToken: string;
268
+ refreshToken: string;
269
+ /** Access-token expiry as epoch milliseconds. */
270
+ expiresAt: number;
271
+ }
272
+ /** Options for {@link ServerAuthClient.buildAuthorizeUrl}. */
273
+ interface BuildAuthorizeUrlOptions {
274
+ /**
275
+ * `'signup'` は `?screen_hint=signup` を転送する(OIDC `prompt=create`
276
+ * 相当の意図の FFID 独自パラメータ)。
277
+ */
278
+ screenHint?: 'signup';
279
+ /** Forwards `?organization_id=…` (trimmed; empty is ignored). */
280
+ organizationId?: string;
281
+ /** Forwards OIDC `prompt` (`select_account` / `login`) to the upstream chooser (#4027). */
282
+ prompt?: 'login' | 'select_account';
283
+ }
284
+ /** Result of {@link ServerAuthClient.buildAuthorizeUrl}. */
285
+ interface BuildAuthorizeUrlResult {
286
+ /** Authorize URL to 302 the browser to. */
287
+ url: string;
288
+ /** Random `state` — persist in an httpOnly cookie and pass back as `storedState`. */
289
+ state: string;
290
+ }
291
+ /** Input to {@link ServerAuthClient.handleCallback}. */
292
+ interface HandleCallbackInput {
293
+ /** The callback request URL (absolute). `code` / `state` are read from its query. */
294
+ url: string | URL;
295
+ /** The `state` previously stored in the httpOnly cookie (undefined if absent). */
296
+ storedState: string | undefined;
297
+ }
298
+ /**
299
+ * Discriminated result of a server token operation. Mirrors {@link FFIDApiResponse}:
300
+ * exactly one of `tokens` / `error` is present.
301
+ */
302
+ type ServerTokenResult = {
303
+ tokens: ServerSessionTokens;
304
+ error?: undefined;
305
+ } | {
306
+ tokens?: undefined;
307
+ error: FFIDError;
308
+ };
309
+ /** Framework-agnostic confidential / BFF auth client. */
310
+ interface ServerAuthClient {
311
+ /**
312
+ * Build the authorize URL and a fresh `state`. The caller stores `state` in an
313
+ * httpOnly cookie, then 302s to `url`. No `code_challenge` is sent (v1 uses
314
+ * `client_secret`, not PKCE).
315
+ */
316
+ buildAuthorizeUrl(opts?: BuildAuthorizeUrlOptions): BuildAuthorizeUrlResult;
317
+ /**
318
+ * Validate `state` (CSRF, fail-closed) then exchange `code` for tokens using
319
+ * the `client_secret` (server→server, browser never sees the secret or tokens).
320
+ */
321
+ handleCallback(input: HandleCallbackInput): Promise<ServerTokenResult>;
322
+ /** Refresh tokens (`refresh_token` grant, `client_secret`-authenticated). */
323
+ refresh(refreshToken: string): Promise<ServerTokenResult>;
324
+ }
325
+ /** Attributes for the session `Set-Cookie` (name is fixed — see {@link FFID_SESSION_COOKIE_NAME}). */
326
+ interface CookieOptions {
327
+ /** `Path` attribute. Default `/`. */
328
+ path?: string;
329
+ /** `Domain` attribute. Omitted by default (host-only cookie). */
330
+ domain?: string;
331
+ /** `SameSite` attribute. Default `lax` (required for the cross-site callback redirect). */
332
+ sameSite?: 'lax' | 'strict' | 'none';
333
+ /**
334
+ * `Secure` attribute. Default `true`. ⚠️ `false` にすると cookie が平文 HTTP
335
+ * でも送信されるようになり、本番環境では非推奨(通常は変更しないこと)。
336
+ */
337
+ secure?: boolean;
338
+ /**
339
+ * `HttpOnly` attribute. Default `true`. ⚠️ `false` にするとトークンが
340
+ * ページ JS(`document.cookie`)から読めるようになり、本モジュールの
341
+ * 機密性モデルが破れる — 通常は変更しないこと。
342
+ */
343
+ httpOnly?: boolean;
344
+ /** `Max-Age` in seconds. Default 30 days. */
345
+ maxAge?: number;
346
+ }
347
+
348
+ /** Create a confidential / BFF auth client bound to one service's credentials. */
349
+ declare function createServerAuthClient(config: ServerAuthConfig): ServerAuthClient;
350
+
351
+ /**
352
+ * httpOnly session cookie codec for the confidential / BFF flow (#4261 / #4269).
353
+ *
354
+ * v1 stores the whole {@link ServerSessionTokens} in a single base64url-JSON
355
+ * cookie (`ffid_session`). httpOnly + Secure + SameSite=Lax by default so the
356
+ * browser can never read the tokens and the cookie survives the top-level
357
+ * callback redirect. The 4 KB per-cookie limit applies; access-token encryption
358
+ * and access/refresh split are documented future extensions (設計 spec
359
+ * (docs/02-design/2026-07-08-sdk-confidential-bff-design.md) §11).
360
+ *
361
+ * React/DOM-free: pure string I/O. The caller applies the returned `Set-Cookie`
362
+ * strings (e.g. `res.headers.append('Set-Cookie', c)`).
363
+ */
364
+
365
+ /** Fixed session cookie name (read/serialize must agree — not configurable). */
366
+ declare const FFID_SESSION_COOKIE_NAME = "ffid_session";
367
+ declare function serialize(tokens: ServerSessionTokens, opts?: CookieOptions): string[];
368
+ declare function read(cookieHeader: string | undefined): ServerSessionTokens | null;
369
+ declare function clear(opts?: Omit<CookieOptions, 'maxAge'>): string[];
370
+ /** httpOnly session cookie serialize / read / clear (returns `Set-Cookie` values). */
371
+ declare const sessionCookies: {
372
+ serialize: typeof serialize;
373
+ read: typeof read;
374
+ clear: typeof clear;
375
+ };
376
+
377
+ /**
378
+ * Server-side OAuth `state` generation for the confidential / BFF flow (#4261).
379
+ *
380
+ * React/DOM-free: uses Web Crypto (`globalThis.crypto.getRandomValues`), which
381
+ * is available in Node 18+ and Edge runtimes. Unlike `src/auth/state.ts` (the
382
+ * browser flow), this never touches `window` / web storage — the caller persists
383
+ * the returned `state` in an httpOnly cookie instead.
384
+ */
385
+ /**
386
+ * Generate a cryptographically-random, URL-safe OAuth `state` (32 hex chars).
387
+ * The caller stores this in an httpOnly `Secure` `SameSite=Lax` cookie and
388
+ * validates it on the callback (CSRF defense, RFC 6749 §10.12).
389
+ */
390
+ declare function generateServerState(): string;
391
+
392
+ export { ALL_DENIED_EXCEPT_NECESSARY, type BuildAuthorizeUrlOptions, type BuildAuthorizeUrlResult, CONSENT_COOKIE_NAME, COOKIE_VERSION, type CookieOptions, FFIDCacheAdapter, type FFIDConsentCategories, type FFIDConsentCategoryCode, type FFIDCookieStoreLike, type FFIDErrorCode, FFIDOAuthUserInfo, FFIDVerifyAccessTokenOptions, FFID_ERROR_CODES, FFID_SESSION_COOKIE_NAME, type HandleCallbackInput, type KVNamespaceLike, type ServerAuthClient, type ServerAuthConfig, type ServerSessionTokens, type ServerTokenResult, createKVCacheAdapter, createMemoryCacheAdapter, createServerAuthClient, createVerifyAccessToken, decodeConsentCookie, encodeConsentCookie, generateServerState, getFFIDConsentFromCookieHeader, getFFIDConsentFromCookies, sessionCookies };