@cimplify/sdk 0.65.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/advanced.d.mts +1 -1
  2. package/dist/advanced.d.ts +1 -1
  3. package/dist/advanced.js +20 -20
  4. package/dist/advanced.mjs +1 -1
  5. package/dist/{chunk-AVQL3TSJ.js → chunk-3QSW33RG.js} +389 -78
  6. package/dist/chunk-E6T5VJMG.mjs +156 -0
  7. package/dist/{chunk-WDTFIIY6.mjs → chunk-FNK6UZOE.mjs} +2 -2
  8. package/dist/{chunk-3G4QCENX.mjs → chunk-FVGVJ4TC.mjs} +12 -50
  9. package/dist/chunk-IQLJJW2H.js +168 -0
  10. package/dist/{chunk-PKYZBKZD.mjs → chunk-JAPCAZN4.mjs} +10 -29
  11. package/dist/{chunk-R6363CC7.mjs → chunk-QQMDEGAK.mjs} +382 -79
  12. package/dist/{chunk-VKID3QUE.js → chunk-SH6HJW4A.js} +4 -4
  13. package/dist/{chunk-VAMZPBA4.js → chunk-SSLFZPAI.js} +44 -63
  14. package/dist/{chunk-HCZTBWU4.js → chunk-SXGFJEME.js} +12 -50
  15. package/dist/{client-BS5lNWWH.d.mts → client-ByI_3jfL.d.mts} +33 -20
  16. package/dist/{client-p1Iofyc9.d.ts → client-CQlEWH5j.d.ts} +1 -1
  17. package/dist/{client-QTrsv6Gu.d.ts → client-DVFQoDtI.d.ts} +33 -20
  18. package/dist/{client-XoswXzib.d.mts → client-Dd82KQ_G.d.mts} +1 -1
  19. package/dist/index.d.mts +2 -2
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +80 -81
  22. package/dist/index.mjs +4 -5
  23. package/dist/mock/cli.mjs +12 -50
  24. package/dist/mock/library.js +12 -50
  25. package/dist/mock/library.mjs +12 -50
  26. package/dist/mock/msw.js +12 -50
  27. package/dist/mock/msw.mjs +12 -50
  28. package/dist/react.d.mts +4 -7
  29. package/dist/react.d.ts +4 -7
  30. package/dist/react.js +63 -71
  31. package/dist/react.mjs +5 -13
  32. package/dist/server.d.mts +18 -3
  33. package/dist/server.d.ts +18 -3
  34. package/dist/server.js +175 -29
  35. package/dist/server.mjs +167 -25
  36. package/dist/{sign-in-dr7m09nm.d.ts → sign-in-RFuWZOgF.d.mts} +6 -1
  37. package/dist/{sign-in-dr7m09nm.d.mts → sign-in-RFuWZOgF.d.ts} +6 -1
  38. package/dist/styles.css +1 -1
  39. package/dist/testing/msw.js +2 -2
  40. package/dist/testing/msw.mjs +1 -1
  41. package/dist/testing/suite.d.mts +2 -2
  42. package/dist/testing/suite.d.ts +2 -2
  43. package/dist/testing/suite.js +23 -23
  44. package/dist/testing/suite.mjs +4 -4
  45. package/dist/testing.d.mts +2 -2
  46. package/dist/testing.d.ts +2 -2
  47. package/dist/testing.js +79 -79
  48. package/dist/testing.mjs +5 -5
  49. package/package.json +1 -1
  50. package/dist/chunk-2AU263DK.mjs +0 -323
  51. package/dist/chunk-6DMHVQ42.js +0 -338
  52. package/dist/chunk-DKT62WQW.js +0 -53
  53. package/dist/chunk-XSOYJLMZ.mjs +0 -45
package/dist/server.js CHANGED
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkDKT62WQW_js = require('./chunk-DKT62WQW.js');
4
- var chunkVAMZPBA4_js = require('./chunk-VAMZPBA4.js');
5
- require('./chunk-AVQL3TSJ.js');
3
+ var chunkSSLFZPAI_js = require('./chunk-SSLFZPAI.js');
4
+ var chunk3QSW33RG_js = require('./chunk-3QSW33RG.js');
6
5
  require('./chunk-7Y2O3E4D.js');
7
6
  var chunkXA3ZNR75_js = require('./chunk-XA3ZNR75.js');
8
7
  require('./chunk-OWW5GUSB.js');
@@ -27,7 +26,7 @@ function readEnv(...keys) {
27
26
  var getServerClient = react.cache((opts = {}) => {
28
27
  const baseUrl = opts.apiUrl ?? readEnv("CIMPLIFY_API_URL", "NEXT_PUBLIC_CIMPLIFY_API_URL") ?? defaultBaseUrl();
29
28
  const publicKey = opts.secretKey ?? readEnv("CIMPLIFY_SECRET_KEY", "NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY") ?? "mock-dev";
30
- const client = chunkVAMZPBA4_js.createCimplifyClient({
29
+ const client = chunkSSLFZPAI_js.createCimplifyClient({
31
30
  baseUrl,
32
31
  publicKey,
33
32
  suppressPublicKeyWarning: true
@@ -240,6 +239,9 @@ async function refreshPage() {
240
239
  }
241
240
  var SESSION_COOKIE = "cimplify_session";
242
241
  var ACCESS_TOKEN_COOKIE = "cimplify_access";
242
+ var REFRESH_TOKEN_COOKIE = "cimplify_refresh";
243
+ var REFRESH_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
244
+ var ACCESS_REFRESH_SKEW_SECONDS = 30;
243
245
  var HEADER_LOCATION = "Location";
244
246
  var PARAM_CODE = "code";
245
247
  var PARAM_STATE = "state";
@@ -248,7 +250,7 @@ var QUERY_AUTH_ERROR = "cimplify_auth_error";
248
250
  var discoveryCache = /* @__PURE__ */ new Map();
249
251
  var jwksCache = /* @__PURE__ */ new Map();
250
252
  function issuerBase(cfg) {
251
- return (cfg.issuer ?? cfg.authUrl ?? chunkDKT62WQW_js.DEFAULT_ISSUER).replace(/\/$/, "");
253
+ return (cfg.issuer ?? cfg.authUrl ?? chunk3QSW33RG_js.DEFAULT_ISSUER).replace(/\/$/, "");
252
254
  }
253
255
  function cookieName(cfg) {
254
256
  return cfg.cookieName ?? SESSION_COOKIE;
@@ -256,6 +258,9 @@ function cookieName(cfg) {
256
258
  function accessTokenCookieName(cfg) {
257
259
  return cfg.accessTokenCookieName ?? ACCESS_TOKEN_COOKIE;
258
260
  }
261
+ function refreshTokenCookieName(cfg) {
262
+ return cfg.refreshTokenCookieName ?? REFRESH_TOKEN_COOKIE;
263
+ }
259
264
  async function discovery(cfg) {
260
265
  const base = issuerBase(cfg);
261
266
  let p = discoveryCache.get(base);
@@ -356,28 +361,38 @@ function buildAccessTokenCookie(cfg, accessToken, maxAgeSeconds) {
356
361
  if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
357
362
  return parts.join("; ");
358
363
  }
359
- function buildSignoutCookies(cfg) {
360
- const idTokenParts = [
361
- `${cookieName(cfg)}=`,
364
+ function buildRefreshTokenCookie(cfg, refreshToken, maxAgeSeconds) {
365
+ const parts = [
366
+ `${refreshTokenCookieName(cfg)}=${refreshToken}`,
362
367
  "Path=/",
363
368
  "HttpOnly",
364
369
  "Secure",
365
370
  "SameSite=Lax",
366
- "Max-Age=0"
371
+ `Max-Age=${maxAgeSeconds}`
367
372
  ];
368
- const accessParts = [
369
- `${accessTokenCookieName(cfg)}=`,
370
- "Path=/",
371
- "HttpOnly",
372
- "Secure",
373
- "SameSite=Lax",
374
- "Max-Age=0"
373
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
374
+ return parts.join("; ");
375
+ }
376
+ function buildSignoutCookies(cfg) {
377
+ const clear = (name) => {
378
+ const parts = [`${name}=`, "Path=/", "HttpOnly", "Secure", "SameSite=Lax", "Max-Age=0"];
379
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
380
+ return parts.join("; ");
381
+ };
382
+ return [
383
+ clear(cookieName(cfg)),
384
+ clear(accessTokenCookieName(cfg)),
385
+ clear(refreshTokenCookieName(cfg))
375
386
  ];
376
- if (cfg.cookieDomain) {
377
- idTokenParts.push(`Domain=${cfg.cookieDomain}`);
378
- accessParts.push(`Domain=${cfg.cookieDomain}`);
379
- }
380
- return [idTokenParts.join("; "), accessParts.join("; ")];
387
+ }
388
+ function readCookie(name, cookieHeader) {
389
+ if (!cookieHeader) return null;
390
+ const match = cookieHeader.split(/;\s*/).find((p) => p.startsWith(`${name}=`));
391
+ if (!match) return null;
392
+ return match.slice(name.length + 1) || null;
393
+ }
394
+ function getRefreshTokenFromCookieHeader(cfg, cookieHeader) {
395
+ return readCookie(refreshTokenCookieName(cfg), cookieHeader);
381
396
  }
382
397
  function getAccessTokenFromCookieHeader(cfg, cookieHeader) {
383
398
  if (!cookieHeader) return null;
@@ -387,7 +402,21 @@ function getAccessTokenFromCookieHeader(cfg, cookieHeader) {
387
402
  const token = match.slice(name.length + 1);
388
403
  return token || null;
389
404
  }
405
+ function isSameOriginCallback(req, redirectUri) {
406
+ const site = req.headers.get("sec-fetch-site");
407
+ if (site) return site === "same-origin";
408
+ const origin = req.headers.get("origin");
409
+ if (!origin) return false;
410
+ try {
411
+ return origin === new URL(redirectUri).origin;
412
+ } catch {
413
+ return false;
414
+ }
415
+ }
390
416
  async function handleOidcCallback(req, opts) {
417
+ if (!isSameOriginCallback(req, opts.redirectUri)) {
418
+ return Response.json({ error: "forbidden_origin" }, { status: 403 });
419
+ }
391
420
  let body;
392
421
  try {
393
422
  body = await req.json();
@@ -404,30 +433,44 @@ async function handleOidcCallback(req, opts) {
404
433
  code: body.code,
405
434
  codeVerifier: body.codeVerifier
406
435
  });
407
- } catch (e) {
408
- return Response.json({ error: "exchange_failed", detail: String(e) }, { status: 400 });
436
+ } catch {
437
+ return Response.json({ error: "exchange_failed" }, { status: 400 });
409
438
  }
410
439
  if (!tokens.idToken) {
411
440
  return Response.json({ error: "missing_id_token" }, { status: 400 });
412
441
  }
413
442
  try {
414
443
  await verifyIdToken(opts, tokens.idToken);
415
- } catch (e) {
416
- return Response.json({ error: "id_token_invalid", detail: String(e) }, { status: 401 });
444
+ } catch {
445
+ return Response.json({ error: "id_token_invalid" }, { status: 401 });
417
446
  }
418
447
  const headers = new Headers({ "Content-Type": "application/json" });
419
448
  headers.append("Set-Cookie", buildSessionCookie(opts, tokens.idToken, tokens.expiresIn));
420
449
  headers.append("Set-Cookie", buildAccessTokenCookie(opts, tokens.accessToken, tokens.expiresIn));
421
- return new Response(JSON.stringify({ ok: true }), { status: 200, headers });
450
+ if (tokens.refreshToken) {
451
+ headers.append(
452
+ "Set-Cookie",
453
+ buildRefreshTokenCookie(opts, tokens.refreshToken, REFRESH_COOKIE_MAX_AGE_SECONDS)
454
+ );
455
+ }
456
+ return new Response(
457
+ JSON.stringify({
458
+ ok: true,
459
+ accessToken: tokens.accessToken,
460
+ expiresIn: tokens.expiresIn,
461
+ scope: tokens.scope
462
+ }),
463
+ { status: 200, headers }
464
+ );
422
465
  }
423
466
  function readPkceCookie(cookieHeader) {
424
467
  if (!cookieHeader) return null;
425
- const match = cookieHeader.split(/;\s*/).find((p) => p.startsWith(`${chunkDKT62WQW_js.PKCE_COOKIE}=`));
468
+ const match = cookieHeader.split(/;\s*/).find((p) => p.startsWith(`${chunk3QSW33RG_js.PKCE_COOKIE}=`));
426
469
  if (!match) return null;
427
- return chunkDKT62WQW_js.decodePkceState(match.slice(chunkDKT62WQW_js.PKCE_COOKIE.length + 1));
470
+ return chunk3QSW33RG_js.decodePkceState(match.slice(chunk3QSW33RG_js.PKCE_COOKIE.length + 1));
428
471
  }
429
472
  function buildPkceClearCookie() {
430
- return `${chunkDKT62WQW_js.PKCE_COOKIE}=; Path=${chunkDKT62WQW_js.PKCE_COOKIE_PATH}; Max-Age=0; Secure; SameSite=Lax`;
473
+ return `${chunk3QSW33RG_js.PKCE_COOKIE}=; Path=${chunk3QSW33RG_js.PKCE_COOKIE_PATH}; Max-Age=0; Secure; SameSite=Lax`;
431
474
  }
432
475
  function safeReturnPath(returnTo, fallback) {
433
476
  if (returnTo && returnTo.startsWith("/") && !returnTo.startsWith("//")) return returnTo;
@@ -467,6 +510,12 @@ async function handleRedirectCallback(req, opts) {
467
510
  const headers = new Headers({ [HEADER_LOCATION]: returnTo });
468
511
  headers.append("Set-Cookie", buildSessionCookie(opts, tokens.idToken, tokens.expiresIn));
469
512
  headers.append("Set-Cookie", buildAccessTokenCookie(opts, tokens.accessToken, tokens.expiresIn));
513
+ if (tokens.refreshToken) {
514
+ headers.append(
515
+ "Set-Cookie",
516
+ buildRefreshTokenCookie(opts, tokens.refreshToken, REFRESH_COOKIE_MAX_AGE_SECONDS)
517
+ );
518
+ }
470
519
  headers.append("Set-Cookie", buildPkceClearCookie());
471
520
  return new Response(null, { status: 302, headers });
472
521
  }
@@ -497,6 +546,99 @@ async function getSessionFromCookieHeader(cfg, cookieHeader) {
497
546
  return null;
498
547
  }
499
548
  }
549
+ async function refreshTokens(cfg, refreshToken) {
550
+ const doc = await discovery(cfg);
551
+ const body = new URLSearchParams({
552
+ grant_type: "refresh_token",
553
+ refresh_token: refreshToken,
554
+ client_id: cfg.clientId
555
+ });
556
+ const res = await fetch(doc.token_endpoint, {
557
+ method: "POST",
558
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
559
+ body: body.toString()
560
+ });
561
+ if (!res.ok) {
562
+ const text = await res.text().catch(() => "");
563
+ throw new Error(`token refresh failed (${res.status}): ${text}`);
564
+ }
565
+ const payload = await res.json();
566
+ return {
567
+ accessToken: payload.access_token,
568
+ idToken: payload.id_token,
569
+ refreshToken: payload.refresh_token,
570
+ expiresIn: payload.expires_in,
571
+ scope: payload.scope
572
+ };
573
+ }
574
+ function decodeBase64Url(segment) {
575
+ const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
576
+ const pad = b64.length % 4 ? "=".repeat(4 - b64.length % 4) : "";
577
+ return atob(b64 + pad);
578
+ }
579
+ function accessTokenExpiry(token) {
580
+ if (!token) return null;
581
+ const parts = token.split(".");
582
+ if (parts.length < 2) return null;
583
+ try {
584
+ const payload = JSON.parse(decodeBase64Url(parts[1]));
585
+ return typeof payload.exp === "number" ? payload.exp : null;
586
+ } catch {
587
+ return null;
588
+ }
589
+ }
590
+ var refreshInflight = /* @__PURE__ */ new Map();
591
+ function dedupedRefresh(cfg, refreshToken) {
592
+ const existing = refreshInflight.get(refreshToken);
593
+ if (existing) return existing;
594
+ const p = refreshTokens(cfg, refreshToken).finally(() => refreshInflight.delete(refreshToken));
595
+ refreshInflight.set(refreshToken, p);
596
+ return p;
597
+ }
598
+ function clearedResult(cfg) {
599
+ return {
600
+ outcome: "cleared",
601
+ setCookies: buildSignoutCookies(cfg),
602
+ cookies: [
603
+ { name: cookieName(cfg), value: "" },
604
+ { name: accessTokenCookieName(cfg), value: "" },
605
+ { name: refreshTokenCookieName(cfg), value: "" }
606
+ ]
607
+ };
608
+ }
609
+ async function handleTokenRefresh(req, cfg) {
610
+ const cookieHeader = req.headers.get("cookie");
611
+ const refreshToken = getRefreshTokenFromCookieHeader(cfg, cookieHeader);
612
+ if (!refreshToken) return { outcome: "noop", setCookies: [], cookies: [] };
613
+ const access = getAccessTokenFromCookieHeader(cfg, cookieHeader);
614
+ const exp = accessTokenExpiry(access);
615
+ const now = Math.floor(Date.now() / 1e3);
616
+ if (access && exp !== null && exp - now > ACCESS_REFRESH_SKEW_SECONDS) {
617
+ return { outcome: "noop", setCookies: [], cookies: [] };
618
+ }
619
+ let tokens;
620
+ try {
621
+ tokens = await dedupedRefresh(cfg, refreshToken);
622
+ } catch {
623
+ return clearedResult(cfg);
624
+ }
625
+ if (!tokens.idToken) return clearedResult(cfg);
626
+ const setCookies = [
627
+ buildSessionCookie(cfg, tokens.idToken, tokens.expiresIn),
628
+ buildAccessTokenCookie(cfg, tokens.accessToken, tokens.expiresIn)
629
+ ];
630
+ const cookies = [
631
+ { name: cookieName(cfg), value: tokens.idToken },
632
+ { name: accessTokenCookieName(cfg), value: tokens.accessToken }
633
+ ];
634
+ if (tokens.refreshToken) {
635
+ setCookies.push(
636
+ buildRefreshTokenCookie(cfg, tokens.refreshToken, REFRESH_COOKIE_MAX_AGE_SECONDS)
637
+ );
638
+ cookies.push({ name: refreshTokenCookieName(cfg), value: tokens.refreshToken });
639
+ }
640
+ return { outcome: "refreshed", setCookies, cookies };
641
+ }
500
642
 
501
643
  Object.defineProperty(exports, "CimplifyError", {
502
644
  enumerable: true,
@@ -505,17 +647,21 @@ Object.defineProperty(exports, "CimplifyError", {
505
647
  exports.CACHE_LIFE_DEFAULT = CACHE_LIFE_DEFAULT;
506
648
  exports.CACHE_LIFE_PROBE = CACHE_LIFE_PROBE;
507
649
  exports.buildAccessTokenCookie = buildAccessTokenCookie;
650
+ exports.buildRefreshTokenCookie = buildRefreshTokenCookie;
508
651
  exports.buildSessionCookie = buildSessionCookie;
509
652
  exports.buildSignoutCookie = buildSignoutCookie;
510
653
  exports.buildSignoutCookies = buildSignoutCookies;
511
654
  exports.exchangeCode = exchangeCode;
512
655
  exports.getAccessTokenFromCookieHeader = getAccessTokenFromCookieHeader;
656
+ exports.getRefreshTokenFromCookieHeader = getRefreshTokenFromCookieHeader;
513
657
  exports.getServerClient = getServerClient;
514
658
  exports.getSessionFromCookieHeader = getSessionFromCookieHeader;
515
659
  exports.handleOidcCallback = handleOidcCallback;
516
660
  exports.handleRedirectCallback = handleRedirectCallback;
517
661
  exports.handleSessionRequest = handleSessionRequest;
662
+ exports.handleTokenRefresh = handleTokenRefresh;
518
663
  exports.refreshPage = refreshPage;
664
+ exports.refreshTokens = refreshTokens;
519
665
  exports.revalidateAddOn = revalidateAddOn;
520
666
  exports.revalidateAddOns = revalidateAddOns;
521
667
  exports.revalidateBrand = revalidateBrand;
package/dist/server.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import { PKCE_COOKIE, decodePkceState, PKCE_COOKIE_PATH, DEFAULT_ISSUER } from './chunk-XSOYJLMZ.mjs';
2
- import { createCimplifyClient } from './chunk-PKYZBKZD.mjs';
3
- import './chunk-R6363CC7.mjs';
1
+ import { createCimplifyClient } from './chunk-JAPCAZN4.mjs';
2
+ import { PKCE_COOKIE, decodePkceState, PKCE_COOKIE_PATH, DEFAULT_ISSUER } from './chunk-QQMDEGAK.mjs';
4
3
  import './chunk-TD3AY34U.mjs';
5
4
  export { CimplifyError } from './chunk-AMZXALF6.mjs';
6
5
  import './chunk-3G6RQLXK.mjs';
@@ -238,6 +237,9 @@ async function refreshPage() {
238
237
  }
239
238
  var SESSION_COOKIE = "cimplify_session";
240
239
  var ACCESS_TOKEN_COOKIE = "cimplify_access";
240
+ var REFRESH_TOKEN_COOKIE = "cimplify_refresh";
241
+ var REFRESH_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
242
+ var ACCESS_REFRESH_SKEW_SECONDS = 30;
241
243
  var HEADER_LOCATION = "Location";
242
244
  var PARAM_CODE = "code";
243
245
  var PARAM_STATE = "state";
@@ -254,6 +256,9 @@ function cookieName(cfg) {
254
256
  function accessTokenCookieName(cfg) {
255
257
  return cfg.accessTokenCookieName ?? ACCESS_TOKEN_COOKIE;
256
258
  }
259
+ function refreshTokenCookieName(cfg) {
260
+ return cfg.refreshTokenCookieName ?? REFRESH_TOKEN_COOKIE;
261
+ }
257
262
  async function discovery(cfg) {
258
263
  const base = issuerBase(cfg);
259
264
  let p = discoveryCache.get(base);
@@ -354,28 +359,38 @@ function buildAccessTokenCookie(cfg, accessToken, maxAgeSeconds) {
354
359
  if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
355
360
  return parts.join("; ");
356
361
  }
357
- function buildSignoutCookies(cfg) {
358
- const idTokenParts = [
359
- `${cookieName(cfg)}=`,
362
+ function buildRefreshTokenCookie(cfg, refreshToken, maxAgeSeconds) {
363
+ const parts = [
364
+ `${refreshTokenCookieName(cfg)}=${refreshToken}`,
360
365
  "Path=/",
361
366
  "HttpOnly",
362
367
  "Secure",
363
368
  "SameSite=Lax",
364
- "Max-Age=0"
369
+ `Max-Age=${maxAgeSeconds}`
365
370
  ];
366
- const accessParts = [
367
- `${accessTokenCookieName(cfg)}=`,
368
- "Path=/",
369
- "HttpOnly",
370
- "Secure",
371
- "SameSite=Lax",
372
- "Max-Age=0"
371
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
372
+ return parts.join("; ");
373
+ }
374
+ function buildSignoutCookies(cfg) {
375
+ const clear = (name) => {
376
+ const parts = [`${name}=`, "Path=/", "HttpOnly", "Secure", "SameSite=Lax", "Max-Age=0"];
377
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
378
+ return parts.join("; ");
379
+ };
380
+ return [
381
+ clear(cookieName(cfg)),
382
+ clear(accessTokenCookieName(cfg)),
383
+ clear(refreshTokenCookieName(cfg))
373
384
  ];
374
- if (cfg.cookieDomain) {
375
- idTokenParts.push(`Domain=${cfg.cookieDomain}`);
376
- accessParts.push(`Domain=${cfg.cookieDomain}`);
377
- }
378
- return [idTokenParts.join("; "), accessParts.join("; ")];
385
+ }
386
+ function readCookie(name, cookieHeader) {
387
+ if (!cookieHeader) return null;
388
+ const match = cookieHeader.split(/;\s*/).find((p) => p.startsWith(`${name}=`));
389
+ if (!match) return null;
390
+ return match.slice(name.length + 1) || null;
391
+ }
392
+ function getRefreshTokenFromCookieHeader(cfg, cookieHeader) {
393
+ return readCookie(refreshTokenCookieName(cfg), cookieHeader);
379
394
  }
380
395
  function getAccessTokenFromCookieHeader(cfg, cookieHeader) {
381
396
  if (!cookieHeader) return null;
@@ -385,7 +400,21 @@ function getAccessTokenFromCookieHeader(cfg, cookieHeader) {
385
400
  const token = match.slice(name.length + 1);
386
401
  return token || null;
387
402
  }
403
+ function isSameOriginCallback(req, redirectUri) {
404
+ const site = req.headers.get("sec-fetch-site");
405
+ if (site) return site === "same-origin";
406
+ const origin = req.headers.get("origin");
407
+ if (!origin) return false;
408
+ try {
409
+ return origin === new URL(redirectUri).origin;
410
+ } catch {
411
+ return false;
412
+ }
413
+ }
388
414
  async function handleOidcCallback(req, opts) {
415
+ if (!isSameOriginCallback(req, opts.redirectUri)) {
416
+ return Response.json({ error: "forbidden_origin" }, { status: 403 });
417
+ }
389
418
  let body;
390
419
  try {
391
420
  body = await req.json();
@@ -402,21 +431,35 @@ async function handleOidcCallback(req, opts) {
402
431
  code: body.code,
403
432
  codeVerifier: body.codeVerifier
404
433
  });
405
- } catch (e) {
406
- return Response.json({ error: "exchange_failed", detail: String(e) }, { status: 400 });
434
+ } catch {
435
+ return Response.json({ error: "exchange_failed" }, { status: 400 });
407
436
  }
408
437
  if (!tokens.idToken) {
409
438
  return Response.json({ error: "missing_id_token" }, { status: 400 });
410
439
  }
411
440
  try {
412
441
  await verifyIdToken(opts, tokens.idToken);
413
- } catch (e) {
414
- return Response.json({ error: "id_token_invalid", detail: String(e) }, { status: 401 });
442
+ } catch {
443
+ return Response.json({ error: "id_token_invalid" }, { status: 401 });
415
444
  }
416
445
  const headers = new Headers({ "Content-Type": "application/json" });
417
446
  headers.append("Set-Cookie", buildSessionCookie(opts, tokens.idToken, tokens.expiresIn));
418
447
  headers.append("Set-Cookie", buildAccessTokenCookie(opts, tokens.accessToken, tokens.expiresIn));
419
- return new Response(JSON.stringify({ ok: true }), { status: 200, headers });
448
+ if (tokens.refreshToken) {
449
+ headers.append(
450
+ "Set-Cookie",
451
+ buildRefreshTokenCookie(opts, tokens.refreshToken, REFRESH_COOKIE_MAX_AGE_SECONDS)
452
+ );
453
+ }
454
+ return new Response(
455
+ JSON.stringify({
456
+ ok: true,
457
+ accessToken: tokens.accessToken,
458
+ expiresIn: tokens.expiresIn,
459
+ scope: tokens.scope
460
+ }),
461
+ { status: 200, headers }
462
+ );
420
463
  }
421
464
  function readPkceCookie(cookieHeader) {
422
465
  if (!cookieHeader) return null;
@@ -465,6 +508,12 @@ async function handleRedirectCallback(req, opts) {
465
508
  const headers = new Headers({ [HEADER_LOCATION]: returnTo });
466
509
  headers.append("Set-Cookie", buildSessionCookie(opts, tokens.idToken, tokens.expiresIn));
467
510
  headers.append("Set-Cookie", buildAccessTokenCookie(opts, tokens.accessToken, tokens.expiresIn));
511
+ if (tokens.refreshToken) {
512
+ headers.append(
513
+ "Set-Cookie",
514
+ buildRefreshTokenCookie(opts, tokens.refreshToken, REFRESH_COOKIE_MAX_AGE_SECONDS)
515
+ );
516
+ }
468
517
  headers.append("Set-Cookie", buildPkceClearCookie());
469
518
  return new Response(null, { status: 302, headers });
470
519
  }
@@ -495,5 +544,98 @@ async function getSessionFromCookieHeader(cfg, cookieHeader) {
495
544
  return null;
496
545
  }
497
546
  }
547
+ async function refreshTokens(cfg, refreshToken) {
548
+ const doc = await discovery(cfg);
549
+ const body = new URLSearchParams({
550
+ grant_type: "refresh_token",
551
+ refresh_token: refreshToken,
552
+ client_id: cfg.clientId
553
+ });
554
+ const res = await fetch(doc.token_endpoint, {
555
+ method: "POST",
556
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
557
+ body: body.toString()
558
+ });
559
+ if (!res.ok) {
560
+ const text = await res.text().catch(() => "");
561
+ throw new Error(`token refresh failed (${res.status}): ${text}`);
562
+ }
563
+ const payload = await res.json();
564
+ return {
565
+ accessToken: payload.access_token,
566
+ idToken: payload.id_token,
567
+ refreshToken: payload.refresh_token,
568
+ expiresIn: payload.expires_in,
569
+ scope: payload.scope
570
+ };
571
+ }
572
+ function decodeBase64Url(segment) {
573
+ const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
574
+ const pad = b64.length % 4 ? "=".repeat(4 - b64.length % 4) : "";
575
+ return atob(b64 + pad);
576
+ }
577
+ function accessTokenExpiry(token) {
578
+ if (!token) return null;
579
+ const parts = token.split(".");
580
+ if (parts.length < 2) return null;
581
+ try {
582
+ const payload = JSON.parse(decodeBase64Url(parts[1]));
583
+ return typeof payload.exp === "number" ? payload.exp : null;
584
+ } catch {
585
+ return null;
586
+ }
587
+ }
588
+ var refreshInflight = /* @__PURE__ */ new Map();
589
+ function dedupedRefresh(cfg, refreshToken) {
590
+ const existing = refreshInflight.get(refreshToken);
591
+ if (existing) return existing;
592
+ const p = refreshTokens(cfg, refreshToken).finally(() => refreshInflight.delete(refreshToken));
593
+ refreshInflight.set(refreshToken, p);
594
+ return p;
595
+ }
596
+ function clearedResult(cfg) {
597
+ return {
598
+ outcome: "cleared",
599
+ setCookies: buildSignoutCookies(cfg),
600
+ cookies: [
601
+ { name: cookieName(cfg), value: "" },
602
+ { name: accessTokenCookieName(cfg), value: "" },
603
+ { name: refreshTokenCookieName(cfg), value: "" }
604
+ ]
605
+ };
606
+ }
607
+ async function handleTokenRefresh(req, cfg) {
608
+ const cookieHeader = req.headers.get("cookie");
609
+ const refreshToken = getRefreshTokenFromCookieHeader(cfg, cookieHeader);
610
+ if (!refreshToken) return { outcome: "noop", setCookies: [], cookies: [] };
611
+ const access = getAccessTokenFromCookieHeader(cfg, cookieHeader);
612
+ const exp = accessTokenExpiry(access);
613
+ const now = Math.floor(Date.now() / 1e3);
614
+ if (access && exp !== null && exp - now > ACCESS_REFRESH_SKEW_SECONDS) {
615
+ return { outcome: "noop", setCookies: [], cookies: [] };
616
+ }
617
+ let tokens;
618
+ try {
619
+ tokens = await dedupedRefresh(cfg, refreshToken);
620
+ } catch {
621
+ return clearedResult(cfg);
622
+ }
623
+ if (!tokens.idToken) return clearedResult(cfg);
624
+ const setCookies = [
625
+ buildSessionCookie(cfg, tokens.idToken, tokens.expiresIn),
626
+ buildAccessTokenCookie(cfg, tokens.accessToken, tokens.expiresIn)
627
+ ];
628
+ const cookies = [
629
+ { name: cookieName(cfg), value: tokens.idToken },
630
+ { name: accessTokenCookieName(cfg), value: tokens.accessToken }
631
+ ];
632
+ if (tokens.refreshToken) {
633
+ setCookies.push(
634
+ buildRefreshTokenCookie(cfg, tokens.refreshToken, REFRESH_COOKIE_MAX_AGE_SECONDS)
635
+ );
636
+ cookies.push({ name: refreshTokenCookieName(cfg), value: tokens.refreshToken });
637
+ }
638
+ return { outcome: "refreshed", setCookies, cookies };
639
+ }
498
640
 
499
- export { CACHE_LIFE_DEFAULT, CACHE_LIFE_PROBE, buildAccessTokenCookie, buildSessionCookie, buildSignoutCookie, buildSignoutCookies, exchangeCode, getAccessTokenFromCookieHeader, getServerClient, getSessionFromCookieHeader, handleOidcCallback, handleRedirectCallback, handleSessionRequest, refreshPage, revalidateAddOn, revalidateAddOns, revalidateBrand, revalidateBusiness, revalidateByTag, revalidateCategories, revalidateCategory, revalidateCollection, revalidateCollections, revalidateLocation, revalidateLocations, revalidatePricing, revalidateProduct, revalidateProducts, revalidateStock, revalidateSubscription, revalidateSubscriptions, tags, updateAddOn, updateAddOns, updateBrand, updateBusiness, updateByTag, updateCategories, updateCategory, updateCollection, updateCollections, updateLocation, updateLocations, updatePricing, updateProduct, updateProducts, updateStock, updateSubscription, updateSubscriptions, verifyIdToken };
641
+ export { CACHE_LIFE_DEFAULT, CACHE_LIFE_PROBE, buildAccessTokenCookie, buildRefreshTokenCookie, buildSessionCookie, buildSignoutCookie, buildSignoutCookies, exchangeCode, getAccessTokenFromCookieHeader, getRefreshTokenFromCookieHeader, getServerClient, getSessionFromCookieHeader, handleOidcCallback, handleRedirectCallback, handleSessionRequest, handleTokenRefresh, refreshPage, refreshTokens, revalidateAddOn, revalidateAddOns, revalidateBrand, revalidateBusiness, revalidateByTag, revalidateCategories, revalidateCategory, revalidateCollection, revalidateCollections, revalidateLocation, revalidateLocations, revalidatePricing, revalidateProduct, revalidateProducts, revalidateStock, revalidateSubscription, revalidateSubscriptions, tags, updateAddOn, updateAddOns, updateBrand, updateBusiness, updateByTag, updateCategories, updateCategory, updateCollection, updateCollections, updateLocation, updateLocations, updatePricing, updateProduct, updateProducts, updateStock, updateSubscription, updateSubscriptions, verifyIdToken };
@@ -50,7 +50,12 @@ interface SignInOptions {
50
50
  error: string;
51
51
  description?: string;
52
52
  }) => void;
53
- onSuccess?: () => void;
53
+ onSuccess?: (result: SignInSuccess) => void;
54
+ }
55
+ interface SignInSuccess {
56
+ accessToken?: string;
57
+ expiresIn?: number;
58
+ scope?: string;
54
59
  }
55
60
  declare function startSignIn(opts: SignInOptions): Promise<void>;
56
61
 
@@ -50,7 +50,12 @@ interface SignInOptions {
50
50
  error: string;
51
51
  description?: string;
52
52
  }) => void;
53
- onSuccess?: () => void;
53
+ onSuccess?: (result: SignInSuccess) => void;
54
+ }
55
+ interface SignInSuccess {
56
+ accessToken?: string;
57
+ expiresIn?: number;
58
+ scope?: string;
54
59
  }
55
60
  declare function startSignIn(opts: SignInOptions): Promise<void>;
56
61