@rebasepro/server 0.22.0 → 0.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.
Files changed (211) hide show
  1. package/README.md +1 -1
  2. package/bin/rebase-server.js +4 -2
  3. package/dist/{GCSStorageController-CLIJXwGS.js → GCSStorageController-BSiP1c-f.js} +57 -29
  4. package/dist/GCSStorageController-BSiP1c-f.js.map +1 -0
  5. package/dist/{S3StorageController-Dcuf8lMA.js → S3StorageController-CAwFRgjV.js} +19 -7
  6. package/dist/S3StorageController-CAwFRgjV.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +127 -1
  8. package/dist/api/errors.d.ts +9 -0
  9. package/dist/api/live-schema-routes.d.ts +52 -8
  10. package/dist/api/logs-routes.d.ts +39 -1
  11. package/dist/api/openapi-generator.d.ts +17 -0
  12. package/dist/api/rest/api-generator.d.ts +158 -42
  13. package/dist/api/rest/auth-collection-writes.d.ts +85 -0
  14. package/dist/api/rest/field-access-query.d.ts +6 -2
  15. package/dist/api/rest/idempotency.d.ts +7 -1
  16. package/dist/api/rest/nested-write-access.d.ts +46 -0
  17. package/dist/api/rest/write-validation.d.ts +34 -2
  18. package/dist/api/types.d.ts +17 -1
  19. package/dist/{ast-schema-editor-CslO8Oje.js → ast-schema-editor-CWqS_sLJ.js} +411 -13
  20. package/dist/ast-schema-editor-CWqS_sLJ.js.map +1 -0
  21. package/dist/auth/access.d.ts +105 -0
  22. package/dist/auth/adapter-middleware.d.ts +2 -1
  23. package/dist/auth/address-ownership.d.ts +68 -0
  24. package/dist/auth/admin-roles-route.d.ts +4 -2
  25. package/dist/auth/admin-roles.d.ts +17 -20
  26. package/dist/auth/admin-user-ops.d.ts +35 -2
  27. package/dist/auth/admin-users-route.d.ts +1 -0
  28. package/dist/auth/api-keys/api-key-middleware.d.ts +56 -55
  29. package/dist/auth/api-keys/api-key-routes.d.ts +41 -11
  30. package/dist/auth/api-keys/api-key-store.d.ts +31 -8
  31. package/dist/auth/api-keys/api-key-types.d.ts +14 -16
  32. package/dist/auth/api-keys/http-operation.d.ts +19 -0
  33. package/dist/auth/api-keys/index.d.ts +11 -11
  34. package/dist/auth/api-keys/key-grant.d.ts +41 -0
  35. package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
  36. package/dist/auth/auth-hooks.d.ts +50 -7
  37. package/dist/auth/builtin-auth-adapter.d.ts +8 -0
  38. package/dist/auth/captcha.d.ts +5 -0
  39. package/dist/auth/cookie-utils.d.ts +7 -0
  40. package/dist/auth/deliverable-address.d.ts +6 -0
  41. package/dist/auth/email-change-routes.d.ts +41 -0
  42. package/dist/auth/expired-token-sweep.d.ts +67 -0
  43. package/dist/auth/impersonation.d.ts +110 -0
  44. package/dist/auth/index.d.ts +4 -2
  45. package/dist/auth/interfaces.d.ts +146 -65
  46. package/dist/auth/jwt.d.ts +66 -3
  47. package/dist/auth/magic-link-routes.d.ts +2 -6
  48. package/dist/auth/mfa-routes.d.ts +2 -9
  49. package/dist/auth/middleware.d.ts +17 -5
  50. package/dist/auth/oauth-signin-policy.d.ts +25 -8
  51. package/dist/auth/otp-routes.d.ts +2 -6
  52. package/dist/auth/passwordless-signup.d.ts +27 -0
  53. package/dist/auth/platform-token.d.ts +122 -0
  54. package/dist/auth/rate-limiter.d.ts +72 -1
  55. package/dist/auth/routes.d.ts +45 -0
  56. package/dist/auth/scope-routes.d.ts +22 -0
  57. package/dist/auth/session-routes.d.ts +18 -6
  58. package/dist/auth/token-revocation.d.ts +53 -1
  59. package/dist/auth/verify-credential.d.ts +28 -0
  60. package/dist/{auth-CCDpk2rn.js → auth-DMLngxn_.js} +2712 -711
  61. package/dist/auth-DMLngxn_.js.map +1 -0
  62. package/dist/backend-DTAOsLQc.js +30 -0
  63. package/dist/backend-DTAOsLQc.js.map +1 -0
  64. package/dist/backup/backup-common.d.ts +29 -0
  65. package/dist/backup/backup-routes.d.ts +24 -4
  66. package/dist/backup/backup-schedule.d.ts +33 -0
  67. package/dist/backup/backup-storage.d.ts +14 -0
  68. package/dist/backup/index.d.ts +2 -0
  69. package/dist/backup-CN0s50D2.js +444 -0
  70. package/dist/backup-CN0s50D2.js.map +1 -0
  71. package/dist/boot/bundle.d.ts +19 -0
  72. package/dist/boot/driver.d.ts +10 -0
  73. package/dist/boot/env.d.ts +51 -6
  74. package/dist/boot/fetch-bundle.d.ts +18 -1
  75. package/dist/boot/rls-audit-option.d.ts +26 -0
  76. package/dist/boot/security-headers.d.ts +26 -0
  77. package/dist/boot/sources.d.ts +1 -0
  78. package/dist/boot/static-routing.d.ts +56 -0
  79. package/dist/collection_patch-BRu-BvDv.js +472 -0
  80. package/dist/collection_patch-BRu-BvDv.js.map +1 -0
  81. package/dist/{contract-routes-eLxV0le1.js → contract-routes-fz8i4pxs.js} +17 -4
  82. package/dist/contract-routes-fz8i4pxs.js.map +1 -0
  83. package/dist/cron/cron-routes.d.ts +7 -2
  84. package/dist/cron/cron-scheduler.d.ts +146 -21
  85. package/dist/cron/cron-store.d.ts +76 -8
  86. package/dist/cron/index.d.ts +1 -1
  87. package/dist/{cron-loader-CQjvjpEw.js → cron-loader-CwaANlOG.js} +4 -4
  88. package/dist/cron-loader-CwaANlOG.js.map +1 -0
  89. package/dist/cron-routes-Bc-SB0Se.js +96 -0
  90. package/dist/cron-routes-Bc-SB0Se.js.map +1 -0
  91. package/dist/{cron-scheduler-COPQxlEq.js → cron-scheduler-CYQgco86.js} +427 -83
  92. package/dist/cron-scheduler-CYQgco86.js.map +1 -0
  93. package/dist/{cron-store-BYGZFNWk.js → cron-store-D2Q9-Aco.js} +139 -23
  94. package/dist/cron-store-D2Q9-Aco.js.map +1 -0
  95. package/dist/{ddl-bootstrap-CfNvxMuK.js → ddl-bootstrap-BaqMSa4Y.js} +3 -26
  96. package/dist/ddl-bootstrap-BaqMSa4Y.js.map +1 -0
  97. package/dist/email/index.d.ts +2 -2
  98. package/dist/email/link-base.d.ts +5 -4
  99. package/dist/email/smtp-email-service.d.ts +13 -1
  100. package/dist/email/templates.d.ts +31 -0
  101. package/dist/email/types.d.ts +29 -2
  102. package/dist/env.d.ts +25 -7
  103. package/dist/{errors-DWsX4yTd.js → errors-D6_y86c5.js} +102 -8
  104. package/dist/errors-D6_y86c5.js.map +1 -0
  105. package/dist/{function-loader-xnbDAPfa.js → function-loader-D7o5Epjj.js} +2 -2
  106. package/dist/{function-loader-xnbDAPfa.js.map → function-loader-D7o5Epjj.js.map} +1 -1
  107. package/dist/{function-routes-Chet4-lB.js → function-routes-CaNG4waN.js} +24 -12
  108. package/dist/function-routes-CaNG4waN.js.map +1 -0
  109. package/dist/functions/context.d.ts +17 -6
  110. package/dist/functions/guards.d.ts +22 -5
  111. package/dist/functions/index.d.ts +2 -2
  112. package/dist/functions/index.js +90 -36
  113. package/dist/functions/index.js.map +1 -1
  114. package/dist/{history-recorder-BQmB0P_j.js → history-recorder-Nr8zLvoU.js} +9 -7
  115. package/dist/history-recorder-Nr8zLvoU.js.map +1 -0
  116. package/dist/{history-store-CetkrBBD.js → history-store-rcAm_xFR.js} +2 -2
  117. package/dist/{history-store-CetkrBBD.js.map → history-store-rcAm_xFR.js.map} +1 -1
  118. package/dist/index.d.ts +14 -4
  119. package/dist/index.es.js +5733 -1551
  120. package/dist/index.es.js.map +1 -1
  121. package/dist/init/docs.d.ts +5 -2
  122. package/dist/init/health.d.ts +17 -2
  123. package/dist/init/shutdown.d.ts +18 -3
  124. package/dist/init.d.ts +54 -0
  125. package/dist/jobs/index.d.ts +2 -2
  126. package/dist/jobs/job-queue.d.ts +23 -2
  127. package/dist/jobs/job-store.d.ts +37 -5
  128. package/dist/jobs/types.d.ts +8 -6
  129. package/dist/{jobs-Bjr8DZAi.js → jobs-DqYNfquG.js} +306 -167
  130. package/dist/jobs-DqYNfquG.js.map +1 -0
  131. package/dist/{jwt-C4OW-DNq.js → jwt-R6bSPMjk.js} +114 -38
  132. package/dist/{jwt-C4OW-DNq.js.map → jwt-R6bSPMjk.js.map} +1 -1
  133. package/dist/{keys-Qfc4XieN.js → keys-GAVZqbqx.js} +18 -17
  134. package/dist/{keys-Qfc4XieN.js.map → keys-GAVZqbqx.js.map} +1 -1
  135. package/dist/{logger-DO2PZc4i.js → logger-D-S-hO5e.js} +26 -3
  136. package/dist/logger-D-S-hO5e.js.map +1 -0
  137. package/dist/{logs-routes-3EEzPjhl.js → logs-routes-DAdv37GI.js} +54 -11
  138. package/dist/logs-routes-DAdv37GI.js.map +1 -0
  139. package/dist/mcp/consent-page.d.ts +1 -1
  140. package/dist/mcp/mcp-routes.d.ts +45 -2
  141. package/dist/mcp/mcp-tools.d.ts +22 -10
  142. package/dist/mcp/oauth-metadata.d.ts +21 -16
  143. package/dist/mcp/oauth-routes.d.ts +34 -1
  144. package/dist/mcp/oauth-store.d.ts +29 -13
  145. package/dist/metrics/history-recorder.d.ts +1 -1
  146. package/dist/{openapi-generator-D8uFz-LW.js → openapi-generator-DAq_XVDu.js} +135 -22
  147. package/dist/openapi-generator-DAq_XVDu.js.map +1 -0
  148. package/dist/{proxy-Czngl3p9.js → proxy-qRlqeUmO.js} +2 -2
  149. package/dist/{proxy-Czngl3p9.js.map → proxy-qRlqeUmO.js.map} +1 -1
  150. package/dist/{query-parser-BleZmY18.js → query-parser-BgiKJKvc.js} +41 -82
  151. package/dist/query-parser-BgiKJKvc.js.map +1 -0
  152. package/dist/{request-timeout-C_4C2BeR.js → request-timeout-DgH7j8qO.js} +3 -3
  153. package/dist/{request-timeout-C_4C2BeR.js.map → request-timeout-DgH7j8qO.js.map} +1 -1
  154. package/dist/rls-audit/index.d.ts +4 -0
  155. package/dist/schema-edit/apply-schema-change.d.ts +63 -3
  156. package/dist/schema-edit/project-root.d.ts +3 -2
  157. package/dist/schema-edit/remote-source.d.ts +9 -4
  158. package/dist/{schema-editor-routes-DdLihzp0.js → schema-editor-routes-oIyuWl3L.js} +12 -7
  159. package/dist/schema-editor-routes-oIyuWl3L.js.map +1 -0
  160. package/dist/serve-spa.d.ts +58 -0
  161. package/dist/services/routed-realtime-service.d.ts +11 -0
  162. package/dist/soft-delete-params-BWPilMPF.js +59 -0
  163. package/dist/soft-delete-params-BWPilMPF.js.map +1 -0
  164. package/dist/{src-Br6ARbs6.js → src-CatHFUym.js} +439 -45
  165. package/dist/src-CatHFUym.js.map +1 -0
  166. package/dist/{src-1vL-I1Po.js → src-I3aG1PcY.js} +371 -81
  167. package/dist/src-I3aG1PcY.js.map +1 -0
  168. package/dist/storage/GCSStorageController.d.ts +13 -1
  169. package/dist/storage/LocalStorageController.d.ts +2 -0
  170. package/dist/storage/S3StorageController.d.ts +2 -0
  171. package/dist/storage/index.d.ts +2 -2
  172. package/dist/storage/keys.d.ts +12 -0
  173. package/dist/storage/property-limits.d.ts +41 -6
  174. package/dist/storage/rendition-cache.d.ts +11 -1
  175. package/dist/storage/request-keys.d.ts +82 -0
  176. package/dist/storage/requested-object.d.ts +74 -0
  177. package/dist/storage/routes.d.ts +36 -18
  178. package/dist/storage/tus-handler.d.ts +30 -5
  179. package/dist/storage/types.d.ts +36 -1
  180. package/dist/types-BfKcm9do.js.map +1 -1
  181. package/dist/utils/logger.d.ts +12 -0
  182. package/package.json +9 -9
  183. package/dist/GCSStorageController-CLIJXwGS.js.map +0 -1
  184. package/dist/S3StorageController-Dcuf8lMA.js.map +0 -1
  185. package/dist/admin-roles-vYdp_Pil.js +0 -36
  186. package/dist/admin-roles-vYdp_Pil.js.map +0 -1
  187. package/dist/admin_block-DxKLmdiv.js +0 -206
  188. package/dist/admin_block-DxKLmdiv.js.map +0 -1
  189. package/dist/ast-schema-editor-CslO8Oje.js.map +0 -1
  190. package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
  191. package/dist/auth-CCDpk2rn.js.map +0 -1
  192. package/dist/backup-DzI9jLwc.js +0 -192
  193. package/dist/backup-DzI9jLwc.js.map +0 -1
  194. package/dist/contract-routes-eLxV0le1.js.map +0 -1
  195. package/dist/cron-loader-CQjvjpEw.js.map +0 -1
  196. package/dist/cron-routes-B7CRGfiq.js +0 -72
  197. package/dist/cron-routes-B7CRGfiq.js.map +0 -1
  198. package/dist/cron-scheduler-COPQxlEq.js.map +0 -1
  199. package/dist/cron-store-BYGZFNWk.js.map +0 -1
  200. package/dist/ddl-bootstrap-CfNvxMuK.js.map +0 -1
  201. package/dist/errors-DWsX4yTd.js.map +0 -1
  202. package/dist/function-routes-Chet4-lB.js.map +0 -1
  203. package/dist/history-recorder-BQmB0P_j.js.map +0 -1
  204. package/dist/jobs-Bjr8DZAi.js.map +0 -1
  205. package/dist/logger-DO2PZc4i.js.map +0 -1
  206. package/dist/logs-routes-3EEzPjhl.js.map +0 -1
  207. package/dist/openapi-generator-D8uFz-LW.js.map +0 -1
  208. package/dist/query-parser-BleZmY18.js.map +0 -1
  209. package/dist/schema-editor-routes-DdLihzp0.js.map +0 -1
  210. package/dist/src-1vL-I1Po.js.map +0 -1
  211. package/dist/src-Br6ARbs6.js.map +0 -1
@@ -3,8 +3,8 @@ import __rebaseProcess from "process";
3
3
  globalThis.process ??= __rebaseProcess;
4
4
  __rebaseCreateRequire(import.meta.url);
5
5
  import { i as __toESM, n as __exportAll, r as __require, t as __commonJSMin } from "./rolldown-runtime-dW7B1o5h.js";
6
- import { r as logger } from "./logger-DO2PZc4i.js";
7
- import { i as canonicalStorageId } from "./keys-Qfc4XieN.js";
6
+ import { r as logger } from "./logger-D-S-hO5e.js";
7
+ import { a as canonicalStorageId } from "./keys-GAVZqbqx.js";
8
8
  import { createPrivateKey, createPublicKey } from "crypto";
9
9
  //#region src/utils/portable-crypto.ts
10
10
  /**
@@ -4423,6 +4423,8 @@ var jwt_exports = /* @__PURE__ */ __exportAll({
4423
4423
  MCP_ACCESS_PURPOSE: () => MCP_ACCESS_PURPOSE,
4424
4424
  MFA_PENDING_PURPOSE: () => MFA_PENDING_PURPOSE,
4425
4425
  configureJwt: () => configureJwt,
4426
+ configuredJwtSecret: () => configuredJwtSecret,
4427
+ customClaimsOf: () => customClaimsOf,
4426
4428
  generateAccessToken: () => generateAccessToken,
4427
4429
  generateDownloadToken: () => generateDownloadToken,
4428
4430
  generateMcpAccessToken: () => generateMcpAccessToken,
@@ -4436,6 +4438,7 @@ var jwt_exports = /* @__PURE__ */ __exportAll({
4436
4438
  hasAsymmetricSigningKey: () => hasAsymmetricSigningKey,
4437
4439
  hashRefreshToken: () => hashRefreshToken,
4438
4440
  isJwtConfigured: () => isJwtConfigured,
4441
+ parseDurationMs: () => parseDurationMs,
4439
4442
  signPurposeToken: () => signPurposeToken,
4440
4443
  verifyAccessToken: () => verifyAccessToken,
4441
4444
  verifyDownloadToken: () => verifyDownloadToken,
@@ -4458,6 +4461,7 @@ var RESERVED_TOKEN_CLAIMS = /* @__PURE__ */ new Set([
4458
4461
  "roles",
4459
4462
  "aal",
4460
4463
  "isAnonymous",
4464
+ "sid",
4461
4465
  "purpose",
4462
4466
  "iat",
4463
4467
  "exp",
@@ -4466,7 +4470,13 @@ var RESERVED_TOKEN_CLAIMS = /* @__PURE__ */ new Set([
4466
4470
  "aud",
4467
4471
  "jti"
4468
4472
  ]);
4469
- /** The custom half of a verified token, or nothing when there is none. */
4473
+ /**
4474
+ * The custom half of a verified token, or nothing when there is none.
4475
+ *
4476
+ * Exported for the one other place that builds a request identity's claims
4477
+ * without a token to verify — `resolveUser`, which reads what a token minted
4478
+ * now would carry — so both drop the same identity claims.
4479
+ */
4470
4480
  function customClaimsOf(decoded) {
4471
4481
  const claims = {};
4472
4482
  for (const [key, value] of Object.entries(decoded)) {
@@ -4523,9 +4533,18 @@ function configureJwt(config) {
4523
4533
  active = resolved.find((key) => key.kid === config.activeKid) ?? null;
4524
4534
  if (!active) throw new Error(`auth.activeKid is "${config.activeKid}", which is not among the configured signing keys (${resolved.map((k) => `"${k.kid}"`).join(", ")}). Signing with a key nobody published produces tokens no verifier can check.`);
4525
4535
  } else active = resolved[0];
4536
+ const lifetimes = {};
4537
+ for (const key of ["accessExpiresIn", "refreshExpiresIn"]) {
4538
+ const value = config[key];
4539
+ if (value === void 0) continue;
4540
+ if (parseDurationMs(value) === null) throw new Error(`auth.${key} is "${value}", which is not a lifetime. Give a positive number and a unit — "15m", "1h", "30d", "1w", "2 weeks" — in the grammar the token signer reads (vercel/ms). A bare number is refused: the signer reads it as milliseconds.`);
4541
+ lifetimes[key] = value;
4542
+ }
4526
4543
  jwtConfig = {
4527
4544
  ...jwtConfig,
4528
- ...config
4545
+ ...config,
4546
+ accessExpiresIn: lifetimes.accessExpiresIn ?? jwtConfig.accessExpiresIn,
4547
+ refreshExpiresIn: lifetimes.refreshExpiresIn ?? jwtConfig.refreshExpiresIn
4529
4548
  };
4530
4549
  signingKeys = resolved;
4531
4550
  activeSigningKey = active;
@@ -4541,6 +4560,14 @@ function configureJwt(config) {
4541
4560
  function getJwks() {
4542
4561
  return toJwks(signingKeys);
4543
4562
  }
4563
+ /**
4564
+ * The secret `configureJwt` was given, or undefined before it is called. For
4565
+ * `mfa-crypto.ts`, which falls back to it when no MFA key is set — the secret
4566
+ * passed in code, not only the one in `JWT_SECRET`.
4567
+ */
4568
+ function configuredJwtSecret() {
4569
+ return jwtConfig.secret || void 0;
4570
+ }
4544
4571
  /** Is this backend signing access tokens asymmetrically? */
4545
4572
  function hasAsymmetricSigningKey() {
4546
4573
  return activeSigningKey !== null;
@@ -4562,14 +4589,15 @@ function isJwtConfigured() {
4562
4589
  /**
4563
4590
  * Generate an access token (short-lived, 1 hour by default)
4564
4591
  */
4565
- async function generateAccessToken(uid, roles, aal = "aal1", customClaims, isAnonymous = false) {
4592
+ async function generateAccessToken(uid, roles, aal = "aal1", customClaims, isAnonymous = false, sessionId) {
4566
4593
  if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
4567
4594
  const payload = {
4568
4595
  ...customClaims,
4569
4596
  uid,
4570
4597
  roles,
4571
4598
  aal,
4572
- ...isAnonymous ? { isAnonymous: true } : {}
4599
+ ...isAnonymous ? { isAnonymous: true } : {},
4600
+ ...sessionId ? { sid: sessionId } : {}
4573
4601
  };
4574
4602
  if (activeSigningKey) return signJwt(payload, activeSigningKey.privateKey, {
4575
4603
  expiresIn: jwtConfig.accessExpiresIn,
@@ -4585,16 +4613,59 @@ async function generateAccessToken(uid, roles, aal = "aal1", customClaims, isAno
4585
4613
  * Get the expiration time of an access token in milliseconds from now
4586
4614
  */
4587
4615
  function getAccessTokenExpiryMs() {
4588
- const match = (jwtConfig.accessExpiresIn || "1h").match(/^(\d+)([dhms])$/);
4589
- if (!match) return 3600 * 1e3;
4590
- const value = parseInt(match[1], 10);
4591
- switch (match[2]) {
4592
- case "d": return value * 24 * 60 * 60 * 1e3;
4593
- case "h": return value * 60 * 60 * 1e3;
4594
- case "m": return value * 60 * 1e3;
4595
- case "s": return value * 1e3;
4596
- default: return 3600 * 1e3;
4597
- }
4616
+ return parseDurationMs(jwtConfig.accessExpiresIn || "1h") ?? 3600 * 1e3;
4617
+ }
4618
+ var DURATION_UNIT_MS = {
4619
+ ms: 1,
4620
+ msec: 1,
4621
+ msecs: 1,
4622
+ millisecond: 1,
4623
+ milliseconds: 1,
4624
+ s: 1e3,
4625
+ sec: 1e3,
4626
+ secs: 1e3,
4627
+ second: 1e3,
4628
+ seconds: 1e3,
4629
+ m: 6e4,
4630
+ min: 6e4,
4631
+ mins: 6e4,
4632
+ minute: 6e4,
4633
+ minutes: 6e4,
4634
+ h: 36e5,
4635
+ hr: 36e5,
4636
+ hrs: 36e5,
4637
+ hour: 36e5,
4638
+ hours: 36e5,
4639
+ d: 864e5,
4640
+ day: 864e5,
4641
+ days: 864e5,
4642
+ w: 6048e5,
4643
+ week: 6048e5,
4644
+ weeks: 6048e5,
4645
+ y: 315576e5,
4646
+ yr: 315576e5,
4647
+ yrs: 315576e5,
4648
+ year: 315576e5,
4649
+ years: 315576e5
4650
+ };
4651
+ /**
4652
+ * A lifetime setting in milliseconds, or null when it is not one.
4653
+ *
4654
+ * The grammar is vercel/ms, because that is what `jsonwebtoken` reads
4655
+ * `expiresIn` with: the token's `exp` and the expiry this module reports
4656
+ * have to come from one reading of the same string, and they used to come
4657
+ * from two — ours understood `<integer><d|h|m|s>` and nothing else.
4658
+ *
4659
+ * Stricter than ms in two ways, both about values nobody means: a bare number
4660
+ * (ms reads "3600" as 3.6 seconds) and a lifetime of zero or less.
4661
+ */
4662
+ function parseDurationMs(value) {
4663
+ const match = /^(\d+(?:\.\d+)?|\.\d+) *([a-z]+)$/i.exec(value);
4664
+ if (!match) return null;
4665
+ const unit = DURATION_UNIT_MS[match[2].toLowerCase()];
4666
+ if (unit === void 0) return null;
4667
+ const ms = parseFloat(match[1]) * unit;
4668
+ return ms > 0 && Number.isFinite(ms) ? ms : null;
4598
4669
  }
4599
4670
  /**
4600
4671
  * Get the expiration timestamp for an access token
@@ -4638,21 +4709,21 @@ async function verifyAccessToken(token) {
4638
4709
  aal,
4639
4710
  ...decoded.isAnonymous === true ? { isAnonymous: true } : {},
4640
4711
  iat: decoded.iat,
4712
+ ...typeof decoded.exp === "number" ? { exp: decoded.exp } : {},
4713
+ ...typeof decoded.sid === "string" && decoded.sid ? { sid: decoded.sid } : {},
4641
4714
  ...(() => {
4642
4715
  const claims = customClaimsOf(decoded);
4643
4716
  return claims ? { claims } : {};
4644
4717
  })()
4645
4718
  };
4646
4719
  } catch (error) {
4647
- logger.error("[JWT] Verification failed", {
4648
- error,
4649
- detail: token.substring(0, 15)
4650
- });
4720
+ logger.error("[JWT] Verification failed", { error });
4651
4721
  return null;
4652
4722
  }
4653
4723
  }
4654
4724
  /**
4655
- * Generate a random refresh token (long-lived, 30 days by default)
4725
+ * Generate a random refresh token. Long-lived: 400 days by default, sliding —
4726
+ * see {@link getRefreshTokenTtlMs}.
4656
4727
  */
4657
4728
  function generateRefreshToken() {
4658
4729
  return randomHex(40);
@@ -4670,7 +4741,7 @@ function hashRefreshToken(token) {
4670
4741
  * what is actually enforced, which is worse than knowing the ceiling.
4671
4742
  */
4672
4743
  var MAX_COOKIE_AGE_MS = 400 * 24 * 60 * 60 * 1e3;
4673
- /** Fallback when `refreshExpiresIn` is unset or unparseable. */
4744
+ /** Fallback when `refreshExpiresIn` is unset. {@link configureJwt} refuses an unparseable one. */
4674
4745
  var DEFAULT_REFRESH_TTL_MS = MAX_COOKIE_AGE_MS;
4675
4746
  /**
4676
4747
  * How long a refresh token is valid for, in milliseconds.
@@ -4682,16 +4753,8 @@ var DEFAULT_REFRESH_TTL_MS = MAX_COOKIE_AGE_MS;
4682
4753
  * when they say they expect to still be signed in.
4683
4754
  */
4684
4755
  function getRefreshTokenTtlMs() {
4685
- const match = jwtConfig.refreshExpiresIn?.match(/^(\d+)([dhms])$/);
4686
- if (!match) return DEFAULT_REFRESH_TTL_MS;
4687
- const value = parseInt(match[1], 10);
4688
- switch (match[2]) {
4689
- case "d": return value * 24 * 60 * 60 * 1e3;
4690
- case "h": return value * 60 * 60 * 1e3;
4691
- case "m": return value * 60 * 1e3;
4692
- case "s": return value * 1e3;
4693
- default: return DEFAULT_REFRESH_TTL_MS;
4694
- }
4756
+ const duration = jwtConfig.refreshExpiresIn;
4757
+ return (duration ? parseDurationMs(duration) : null) ?? DEFAULT_REFRESH_TTL_MS;
4695
4758
  }
4696
4759
  /**
4697
4760
  * Calculate refresh token expiration date
@@ -4732,13 +4795,20 @@ async function generateMfaPendingToken(uid, expiresInSeconds = 300) {
4732
4795
  *
4733
4796
  * Returns `null` for anything else — including a perfectly valid *access*
4734
4797
  * token, which must not be interchangeable with this one in either direction.
4798
+ *
4799
+ * `iat` comes back with the uid because this token is a first factor that was
4800
+ * accepted at that instant, and a sign-out everywhere after it has to void it
4801
+ * the way it voids an access token — see `isAccessTokenRevoked`.
4735
4802
  */
4736
4803
  async function verifyMfaPendingToken(token) {
4737
4804
  if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
4738
4805
  try {
4739
4806
  const decoded = await verifyJwt(token, jwtConfig.secret, { algorithms: ["HS256"] });
4740
4807
  if (decoded.purpose !== "mfa-pending" || !decoded.uid) return null;
4741
- return { uid: decoded.uid };
4808
+ return {
4809
+ uid: decoded.uid,
4810
+ iat: typeof decoded.iat === "number" ? decoded.iat : void 0
4811
+ };
4742
4812
  } catch {
4743
4813
  return null;
4744
4814
  }
@@ -4760,17 +4830,22 @@ async function verifyMfaPendingToken(token) {
4760
4830
  * site that forgets to pass a named source produces a default-scoped token,
4761
4831
  * which fails closed at `/file/*` rather than over-granting.
4762
4832
  */
4763
- async function generateDownloadToken(path, expiresInSeconds = 300, storageId) {
4833
+ async function generateDownloadToken(path, expiresInSeconds = 300, storageId, principal) {
4764
4834
  if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
4765
4835
  return signJwt({
4766
4836
  purpose: "file-read",
4767
4837
  path,
4768
- storageId: canonicalStorageId(storageId)
4838
+ storageId: canonicalStorageId(storageId),
4839
+ ...principal ? { rl: await downloadTokenRateLimitMark(principal) } : {}
4769
4840
  }, jwtConfig.secret, {
4770
4841
  expiresIn: expiresInSeconds,
4771
4842
  algorithm: "HS256"
4772
4843
  });
4773
4844
  }
4845
+ /** See {@link DownloadTokenPayload.rl}. */
4846
+ async function downloadTokenRateLimitMark(principal) {
4847
+ return (await sha256Hex(`download-token-rl:${principal}`)).slice(0, 32);
4848
+ }
4774
4849
  /**
4775
4850
  * Verify and decode a download token.
4776
4851
  *
@@ -4788,7 +4863,8 @@ async function verifyDownloadToken(token) {
4788
4863
  if (decoded && decoded.purpose === "file-read" && typeof decoded.path === "string") return {
4789
4864
  purpose: "file-read",
4790
4865
  path: decoded.path,
4791
- storageId: canonicalStorageId(typeof decoded.storageId === "string" ? decoded.storageId : null)
4866
+ storageId: canonicalStorageId(typeof decoded.storageId === "string" ? decoded.storageId : null),
4867
+ ...typeof decoded.rl === "string" ? { rl: decoded.rl } : {}
4792
4868
  };
4793
4869
  return null;
4794
4870
  } catch (error) {
@@ -4914,6 +4990,6 @@ async function verifyMcpAccessToken(token, expectedAudience) {
4914
4990
  }
4915
4991
  }
4916
4992
  //#endregion
4917
- export { require_jsonwebtoken as C, sha256Bytes as D, randomInt as E, sha256Hex as O, normalizePemFromEnv as S, randomHex as T, verifyAccessToken as _, generateMcpAccessToken as a, verifyMfaPendingToken as b, getAccessTokenExpiry as c, getRefreshTokenTtlMs as d, hasAsymmetricSigningKey as f, signPurposeToken as g, jwt_exports as h, generateDownloadToken as i, getJwks as l, isJwtConfigured as m, configureJwt as n, generateMfaPendingToken as o, hashRefreshToken as p, generateAccessToken as r, generateRefreshToken as s, MAX_COOKIE_AGE_MS as t, getRefreshTokenExpiry as u, verifyDownloadToken as v, constantTimeEqual as w, verifyPurposeToken as x, verifyMcpAccessToken as y };
4993
+ export { sha256Bytes as A, verifyPurposeToken as C, constantTimeEqual as D, require_jsonwebtoken as E, randomHex as O, verifyMfaPendingToken as S, verifyJwt as T, jwt_exports as _, generateAccessToken as a, verifyDownloadToken as b, generateMfaPendingToken as c, getJwks as d, getRefreshTokenExpiry as f, isJwtConfigured as g, hashRefreshToken as h, customClaimsOf as i, sha256Hex as j, randomInt as k, generateRefreshToken as l, hasAsymmetricSigningKey as m, configureJwt as n, generateDownloadToken as o, getRefreshTokenTtlMs as p, configuredJwtSecret as r, generateMcpAccessToken as s, MAX_COOKIE_AGE_MS as t, getAccessTokenExpiry as u, signPurposeToken as v, normalizePemFromEnv as w, verifyMcpAccessToken as x, verifyAccessToken as y };
4918
4994
 
4919
- //# sourceMappingURL=jwt-C4OW-DNq.js.map
4995
+ //# sourceMappingURL=jwt-R6bSPMjk.js.map