@rebasepro/server 0.23.0 → 0.24.1-canary.g56af4a4

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 (261) hide show
  1. package/README.md +1 -1
  2. package/bin/rebase-server.js +4 -2
  3. package/dist/GCSStorageController-DivE9bAx.js +402 -0
  4. package/dist/GCSStorageController-DivE9bAx.js.map +1 -0
  5. package/dist/S3StorageController-D_vKs4kP.js +480 -0
  6. package/dist/S3StorageController-D_vKs4kP.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +92 -1
  8. package/dist/api/errors.d.ts +9 -0
  9. package/dist/api/live-schema-routes.d.ts +38 -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 +97 -11
  13. package/dist/api/rest/auth-collection-writes.d.ts +28 -21
  14. package/dist/api/rest/field-access-query.d.ts +28 -8
  15. package/dist/api/rest/field-ops.d.ts +19 -7
  16. package/dist/api/rest/query-body.d.ts +10 -0
  17. package/dist/api/rest/write-validation.d.ts +9 -7
  18. package/dist/api/schema-editor-routes.d.ts +10 -1
  19. package/dist/api/sql-export-routes.d.ts +8 -0
  20. package/dist/api/types.d.ts +28 -1
  21. package/dist/{ast-schema-editor-Mvr50v_S.js → ast-schema-editor-CSdL0iCk.js} +310 -12
  22. package/dist/ast-schema-editor-CSdL0iCk.js.map +1 -0
  23. package/dist/auth/access.d.ts +121 -0
  24. package/dist/auth/adapter-middleware.d.ts +2 -1
  25. package/dist/auth/address-ownership.d.ts +16 -1
  26. package/dist/auth/admin-roles-route.d.ts +4 -2
  27. package/dist/auth/admin-roles.d.ts +17 -20
  28. package/dist/auth/admin-user-ops.d.ts +24 -2
  29. package/dist/auth/admin-users-route.d.ts +2 -0
  30. package/dist/auth/api-keys/api-key-middleware.d.ts +56 -55
  31. package/dist/auth/api-keys/api-key-routes.d.ts +41 -11
  32. package/dist/auth/api-keys/api-key-store.d.ts +31 -8
  33. package/dist/auth/api-keys/api-key-types.d.ts +14 -16
  34. package/dist/auth/api-keys/http-operation.d.ts +19 -0
  35. package/dist/auth/api-keys/index.d.ts +11 -11
  36. package/dist/auth/api-keys/key-grant.d.ts +41 -0
  37. package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
  38. package/dist/auth/auth-hooks.d.ts +46 -7
  39. package/dist/auth/builtin-auth-adapter.d.ts +8 -0
  40. package/dist/auth/cookie-utils.d.ts +7 -0
  41. package/dist/auth/deliverable-address.d.ts +6 -0
  42. package/dist/auth/email-change-routes.d.ts +41 -0
  43. package/dist/auth/expired-token-sweep.d.ts +71 -0
  44. package/dist/auth/impersonation.d.ts +110 -0
  45. package/dist/auth/index.d.ts +4 -2
  46. package/dist/auth/interfaces.d.ts +120 -59
  47. package/dist/auth/jwt-crypto.d.ts +7 -0
  48. package/dist/auth/jwt-keys.d.ts +4 -0
  49. package/dist/auth/jwt.d.ts +54 -3
  50. package/dist/auth/magic-link-routes.d.ts +2 -6
  51. package/dist/auth/mfa-routes.d.ts +2 -9
  52. package/dist/auth/middleware.d.ts +17 -5
  53. package/dist/auth/otp-routes.d.ts +2 -6
  54. package/dist/auth/passwordless-signup.d.ts +27 -0
  55. package/dist/auth/platform-token.d.ts +122 -0
  56. package/dist/auth/rate-limiter.d.ts +54 -1
  57. package/dist/auth/registration-policy.d.ts +17 -0
  58. package/dist/auth/routes.d.ts +45 -0
  59. package/dist/auth/scope-routes.d.ts +22 -0
  60. package/dist/auth/session-routes.d.ts +11 -6
  61. package/dist/auth/token-revocation.d.ts +50 -1
  62. package/dist/auth/user-picking.d.ts +35 -0
  63. package/dist/auth/verify-credential.d.ts +28 -0
  64. package/dist/{auth-B-GIMpDG.js → auth-OPq_FeMs.js} +3115 -638
  65. package/dist/auth-OPq_FeMs.js.map +1 -0
  66. package/dist/auth_adapter-CIItCTc8.js +21 -0
  67. package/dist/auth_adapter-CIItCTc8.js.map +1 -0
  68. package/dist/backend-DTAOsLQc.js.map +1 -1
  69. package/dist/backup/backup-common.d.ts +24 -3
  70. package/dist/backup/backup-routes.d.ts +46 -5
  71. package/dist/backup/backup-schedule.d.ts +33 -0
  72. package/dist/backup/backup-storage.d.ts +16 -0
  73. package/dist/backup/index.d.ts +5 -1
  74. package/dist/backup-5d7XhLX3.js +581 -0
  75. package/dist/backup-5d7XhLX3.js.map +1 -0
  76. package/dist/boot/bundle.d.ts +19 -0
  77. package/dist/boot/driver.d.ts +3 -0
  78. package/dist/boot/env.d.ts +56 -4
  79. package/dist/boot/http-server.d.ts +22 -0
  80. package/dist/boot/options.d.ts +16 -1
  81. package/dist/boot/runtime-cors.d.ts +17 -0
  82. package/dist/boot/security-headers.d.ts +26 -0
  83. package/dist/boot/static-routing.d.ts +65 -0
  84. package/dist/collection_patch-BRu-BvDv.js +472 -0
  85. package/dist/collection_patch-BRu-BvDv.js.map +1 -0
  86. package/dist/{contract-routes-CbFjuBwa.js → contract-routes-02lASyJI.js} +5 -8
  87. package/dist/contract-routes-02lASyJI.js.map +1 -0
  88. package/dist/cron/cron-routes.d.ts +1 -1
  89. package/dist/cron/cron-scheduler.d.ts +94 -23
  90. package/dist/cron/cron-store.d.ts +31 -4
  91. package/dist/cron/define-cron.d.ts +6 -2
  92. package/dist/cron/index.d.ts +1 -1
  93. package/dist/{cron-loader-DfTj2Hbi.js → cron-loader-D7OmleAb.js} +11 -7
  94. package/dist/cron-loader-D7OmleAb.js.map +1 -0
  95. package/dist/{cron-routes-eE8nif_b.js → cron-routes-CBfiaqEL.js} +34 -8
  96. package/dist/cron-routes-CBfiaqEL.js.map +1 -0
  97. package/dist/{cron-scheduler-B0pLfAix.js → cron-scheduler-C2vbETMo.js} +349 -65
  98. package/dist/cron-scheduler-C2vbETMo.js.map +1 -0
  99. package/dist/cron-store-B2Ih0gCN.js +540 -0
  100. package/dist/cron-store-B2Ih0gCN.js.map +1 -0
  101. package/dist/{ddl-bootstrap-C6mo0Kmz.js → ddl-bootstrap-BaqMSa4Y.js} +2 -2
  102. package/dist/{ddl-bootstrap-C6mo0Kmz.js.map → ddl-bootstrap-BaqMSa4Y.js.map} +1 -1
  103. package/dist/email/index.d.ts +2 -2
  104. package/dist/email/smtp-email-service.d.ts +23 -0
  105. package/dist/email/templates.d.ts +22 -0
  106. package/dist/email/types.d.ts +44 -0
  107. package/dist/env.d.ts +1 -39
  108. package/dist/{errors-DWsX4yTd.js → errors-D6_y86c5.js} +102 -8
  109. package/dist/errors-D6_y86c5.js.map +1 -0
  110. package/dist/filter-dialect-REl-TjZr.js +1628 -0
  111. package/dist/filter-dialect-REl-TjZr.js.map +1 -0
  112. package/dist/{function-loader-xnbDAPfa.js → function-loader-BDKKiBmy.js} +5 -4
  113. package/dist/function-loader-BDKKiBmy.js.map +1 -0
  114. package/dist/{function-routes-Chet4-lB.js → function-routes-DWB7BBsi.js} +25 -13
  115. package/dist/function-routes-DWB7BBsi.js.map +1 -0
  116. package/dist/functions/context.d.ts +26 -6
  117. package/dist/functions/define-function.d.ts +7 -4
  118. package/dist/functions/guards.d.ts +22 -5
  119. package/dist/functions/index.d.ts +2 -2
  120. package/dist/functions/index.js +114 -37
  121. package/dist/functions/index.js.map +1 -1
  122. package/dist/functions/request-timeout.d.ts +7 -5
  123. package/dist/history/history-routes.d.ts +9 -0
  124. package/dist/history/retention-sweep.d.ts +81 -0
  125. package/dist/{history-recorder-B4MpJfJK.js → history-recorder-DHenr3lm.js} +4 -4
  126. package/dist/{history-recorder-B4MpJfJK.js.map → history-recorder-DHenr3lm.js.map} +1 -1
  127. package/dist/{history-store-BhxWOuz9.js → history-store-DPofGVDp.js} +2 -2
  128. package/dist/{history-store-BhxWOuz9.js.map → history-store-DPofGVDp.js.map} +1 -1
  129. package/dist/index.d.ts +14 -7
  130. package/dist/index.es.js +23363 -17552
  131. package/dist/index.es.js.map +1 -1
  132. package/dist/init/health.d.ts +17 -2
  133. package/dist/init/shutdown.d.ts +20 -0
  134. package/dist/init.d.ts +70 -6
  135. package/dist/internal-tables-L2t39RdT.js +136 -0
  136. package/dist/internal-tables-L2t39RdT.js.map +1 -0
  137. package/dist/jobs/job-queue.d.ts +8 -0
  138. package/dist/jobs/job-store.d.ts +24 -0
  139. package/dist/jobs/types.d.ts +25 -4
  140. package/dist/{jobs-CazMYhyy.js → jobs-BpD4Q0qR.js} +235 -25
  141. package/dist/jobs-BpD4Q0qR.js.map +1 -0
  142. package/dist/{jwt-DnQHNFCl.js → jwt-Bqcu7cGt.js} +207 -77
  143. package/dist/jwt-Bqcu7cGt.js.map +1 -0
  144. package/dist/{keys-CogCQpxG.js → keys-GAVZqbqx.js} +3 -17
  145. package/dist/{keys-CogCQpxG.js.map → keys-GAVZqbqx.js.map} +1 -1
  146. package/dist/load-failure-UvzZgGXT.js +48 -0
  147. package/dist/load-failure-UvzZgGXT.js.map +1 -0
  148. package/dist/{logger-DO2PZc4i.js → logger-D-S-hO5e.js} +26 -3
  149. package/dist/logger-D-S-hO5e.js.map +1 -0
  150. package/dist/{logs-routes-Bj4TYYUl.js → logs-routes-DAdv37GI.js} +48 -8
  151. package/dist/logs-routes-DAdv37GI.js.map +1 -0
  152. package/dist/mcp/consent-page.d.ts +1 -1
  153. package/dist/mcp/mcp-routes.d.ts +7 -0
  154. package/dist/mcp/mcp-tools.d.ts +23 -9
  155. package/dist/mcp/oauth-metadata.d.ts +21 -16
  156. package/dist/mcp/oauth-routes.d.ts +7 -1
  157. package/dist/metrics/index.d.ts +18 -0
  158. package/dist/metrics/pool-wait.d.ts +50 -0
  159. package/dist/offline-8Ks3yp9n-CadBKm2D.js +3305 -0
  160. package/dist/offline-8Ks3yp9n-CadBKm2D.js.map +1 -0
  161. package/dist/offline-store-D9ytNNaa-BCr2vsFB.js +1903 -0
  162. package/dist/offline-store-D9ytNNaa-BCr2vsFB.js.map +1 -0
  163. package/dist/{openapi-generator-O_O24MAT.js → openapi-generator-BqoUh4Ij.js} +455 -80
  164. package/dist/openapi-generator-BqoUh4Ij.js.map +1 -0
  165. package/dist/policy-PdzX-Opd.js +121 -0
  166. package/dist/policy-PdzX-Opd.js.map +1 -0
  167. package/dist/project_manifest-R6y_KHms.js +59 -0
  168. package/dist/project_manifest-R6y_KHms.js.map +1 -0
  169. package/dist/{proxy-Czngl3p9.js → proxy-qRlqeUmO.js} +2 -2
  170. package/dist/{proxy-Czngl3p9.js.map → proxy-qRlqeUmO.js.map} +1 -1
  171. package/dist/{query-parser-DGRVFNM3.js → query-parser-DK9eMkb9.js} +497 -52
  172. package/dist/query-parser-DK9eMkb9.js.map +1 -0
  173. package/dist/{request-timeout-C_4C2BeR.js → request-timeout-Dnl2_OBc.js} +17 -10
  174. package/dist/request-timeout-Dnl2_OBc.js.map +1 -0
  175. package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
  176. package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
  177. package/dist/schema-edit/apply-schema-change.d.ts +73 -3
  178. package/dist/schema-edit/local-source.d.ts +29 -0
  179. package/dist/schema-edit/project-root.d.ts +3 -2
  180. package/dist/schema-edit/remote-source.d.ts +20 -5
  181. package/dist/schema-edit/source-editor.d.ts +28 -0
  182. package/dist/schema-editor-routes-BFf3i8jm.js +136 -0
  183. package/dist/schema-editor-routes-BFf3i8jm.js.map +1 -0
  184. package/dist/serve-spa.d.ts +58 -0
  185. package/dist/services/outbound-post.d.ts +50 -0
  186. package/dist/services/outbound-url-guard.d.ts +34 -5
  187. package/dist/services/routed-realtime-service.d.ts +16 -0
  188. package/dist/services/webhook-service.d.ts +66 -14
  189. package/dist/soft-delete-params-47yBGs3_.js +668 -0
  190. package/dist/soft-delete-params-47yBGs3_.js.map +1 -0
  191. package/dist/sql-export-routes-BNNuGGLP.js +240 -0
  192. package/dist/sql-export-routes-BNNuGGLP.js.map +1 -0
  193. package/dist/{src-vkcwKXbT.js → src-CatHFUym.js} +439 -20
  194. package/dist/src-CatHFUym.js.map +1 -0
  195. package/dist/storage/GCSStorageController.d.ts +48 -2
  196. package/dist/storage/LocalStorageController.d.ts +69 -2
  197. package/dist/storage/S3StorageController.d.ts +39 -3
  198. package/dist/storage/image-transform.d.ts +5 -0
  199. package/dist/storage/index.d.ts +2 -2
  200. package/dist/storage/maintenance-routes.d.ts +23 -0
  201. package/dist/storage/maintenance.d.ts +126 -0
  202. package/dist/storage/property-limits.d.ts +41 -6
  203. package/dist/storage/rendition-cache.d.ts +9 -11
  204. package/dist/storage/request-keys.d.ts +15 -0
  205. package/dist/storage/request-principals.d.ts +30 -0
  206. package/dist/storage/requested-object.d.ts +74 -0
  207. package/dist/storage/routes.d.ts +52 -14
  208. package/dist/storage/source-variables.d.ts +10 -0
  209. package/dist/storage/streams.d.ts +42 -0
  210. package/dist/storage/tus-handler.d.ts +76 -7
  211. package/dist/storage/types.d.ts +101 -7
  212. package/dist/storage/upload-validation.d.ts +13 -0
  213. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
  214. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
  215. package/dist/strings.es-BeZWAodn.js +256 -0
  216. package/dist/strings.es-BeZWAodn.js.map +1 -0
  217. package/dist/upload-validation-Dd-fnsbA.js +172 -0
  218. package/dist/upload-validation-Dd-fnsbA.js.map +1 -0
  219. package/dist/utils/byte-size.d.ts +10 -0
  220. package/dist/utils/compression.d.ts +6 -0
  221. package/dist/utils/load-failure.d.ts +14 -0
  222. package/dist/utils/logger.d.ts +12 -0
  223. package/package.json +5 -5
  224. package/dist/GCSStorageController-CjrA4PMo.js +0 -242
  225. package/dist/GCSStorageController-CjrA4PMo.js.map +0 -1
  226. package/dist/S3StorageController-B6pKDNVj.js +0 -264
  227. package/dist/S3StorageController-B6pKDNVj.js.map +0 -1
  228. package/dist/admin-roles-vYdp_Pil.js +0 -36
  229. package/dist/admin-roles-vYdp_Pil.js.map +0 -1
  230. package/dist/admin_block-DxKLmdiv.js +0 -206
  231. package/dist/admin_block-DxKLmdiv.js.map +0 -1
  232. package/dist/ast-schema-editor-Mvr50v_S.js.map +0 -1
  233. package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
  234. package/dist/auth-B-GIMpDG.js.map +0 -1
  235. package/dist/backup-D7YR94N3.js +0 -253
  236. package/dist/backup-D7YR94N3.js.map +0 -1
  237. package/dist/contract-routes-CbFjuBwa.js.map +0 -1
  238. package/dist/cron-loader-DfTj2Hbi.js.map +0 -1
  239. package/dist/cron-routes-eE8nif_b.js.map +0 -1
  240. package/dist/cron-scheduler-B0pLfAix.js.map +0 -1
  241. package/dist/cron-store-TcoGz-xS.js +0 -305
  242. package/dist/cron-store-TcoGz-xS.js.map +0 -1
  243. package/dist/dynamic-import-X40pTZUQ.js +0 -23
  244. package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
  245. package/dist/errors-DWsX4yTd.js.map +0 -1
  246. package/dist/function-loader-xnbDAPfa.js.map +0 -1
  247. package/dist/function-routes-Chet4-lB.js.map +0 -1
  248. package/dist/jobs-CazMYhyy.js.map +0 -1
  249. package/dist/jwt-DnQHNFCl.js.map +0 -1
  250. package/dist/logger-DO2PZc4i.js.map +0 -1
  251. package/dist/logs-routes-Bj4TYYUl.js.map +0 -1
  252. package/dist/openapi-generator-O_O24MAT.js.map +0 -1
  253. package/dist/query-parser-DGRVFNM3.js.map +0 -1
  254. package/dist/request-timeout-C_4C2BeR.js.map +0 -1
  255. package/dist/schema-editor-routes-C5-lh_jO.js +0 -87
  256. package/dist/schema-editor-routes-C5-lh_jO.js.map +0 -1
  257. package/dist/src-pmvW7BFx.js +0 -6688
  258. package/dist/src-pmvW7BFx.js.map +0 -1
  259. package/dist/src-vkcwKXbT.js.map +0 -1
  260. package/dist/types-BfKcm9do.js +0 -39
  261. package/dist/types-BfKcm9do.js.map +0 -1
@@ -44,6 +44,14 @@ interface RateLimiterOptions {
44
44
  * `limit`; returning `null` skips the limiter for this request.
45
45
  */
46
46
  resolveLimit?: (c: Parameters<MiddlewareHandler<HonoEnv>>[0]) => number | null | undefined | Promise<number | null | undefined>;
47
+ /**
48
+ * How many requests this one counts as. Default 1. For a request that
49
+ * does the work of several — a batch — so batching is cheaper than the
50
+ * requests it replaces without being free. Charged one hit at a time, and
51
+ * refused at the first that does not fit; the hits before it stay charged,
52
+ * as the requests a batch replaces would have been.
53
+ */
54
+ cost?: (c: Parameters<MiddlewareHandler<HonoEnv>>[0]) => number | Promise<number>;
47
55
  /**
48
56
  * Number of trusted reverse-proxy hops in front of this server. Each hop
49
57
  * appends the address it saw to `X-Forwarded-For`, so the real client IP is
@@ -83,6 +91,41 @@ export declare function setSharedRateLimitStore(store: RateLimitStore | undefine
83
91
  * Uses a sliding window: only hits within the last `windowMs` are counted.
84
92
  */
85
93
  export declare function createRateLimiter(options?: RateLimiterOptions): MiddlewareHandler<HonoEnv>;
94
+ /**
95
+ * Default key generator: the client's address, from the most trustworthy source
96
+ * this deployment has.
97
+ *
98
+ * `X-Forwarded-For` is a client-writable header; only the entries appended by
99
+ * trusted reverse proxies can be believed. With `trustedProxyHops` proxies in
100
+ * front, each appends the address it saw, so the real client IP is the
101
+ * `trustedProxyHops`-th entry from the right — everything further left is
102
+ * client-supplied and must be ignored. This is what prevents a caller from
103
+ * spoofing `X-Forwarded-For` to spread its requests across many rate-limit keys.
104
+ *
105
+ * `X-Real-IP` is the *same* kind of header and needs the same rule, which it
106
+ * did not have: it was read unconditionally, including under
107
+ * `trustedProxyHops === 0` — the mode whose entire meaning is "no proxy is in
108
+ * front of me". With no proxy there, nothing writes `X-Real-IP` except the
109
+ * caller, so the key was theirs to choose: one header per request bought an
110
+ * unlimited number of buckets, and the limiters on login, registration and
111
+ * password reset counted to one. The reasoning had been done carefully for one
112
+ * spelling of a proxy header and not carried to its twin.
113
+ *
114
+ * So `X-Real-IP` is now believed only where a proxy is declared to exist. With
115
+ * none, the connection's own address is used — unforgeable, and available
116
+ * because the server runs on `@hono/node-server`. `"unknown"` is the last
117
+ * resort only, and it is a single shared bucket by design: better that
118
+ * anonymous callers throttle each other than that any of them throttles nobody.
119
+ */
120
+ /**
121
+ * Where a request comes from, as the rate limiters judge it: the socket's own
122
+ * address, or — only behind as many proxies as `TRUSTED_PROXY_HOPS` declares —
123
+ * the address they report. What a session row records as its IP, so the
124
+ * sessions list shows the same address the limiter counted, rather than the
125
+ * raw `X-Forwarded-For` (whose leftmost entry the caller chooses) or
126
+ * `"unknown"` for every direct connection.
127
+ */
128
+ export declare function requestClientAddress(c: Parameters<MiddlewareHandler<HonoEnv>>[0]): string;
86
129
  /**
87
130
  * Pre-configured rate limiter for general auth endpoints (login, register).
88
131
  * 200 requests per 15 minutes per IP.
@@ -209,6 +252,12 @@ export interface DataRateLimitConfig {
209
252
  anonymousFunctions?: number | null;
210
253
  /** Share counts across replicas. Defaults to this process's memory. */
211
254
  store?: RateLimitStore;
255
+ /**
256
+ * The deployment's service key, recognised as a Bearer before any auth
257
+ * middleware has run — the storage router's limiter runs ahead of its
258
+ * routes' auth — and never limited. See {@link dataRateLimitBuckets}.
259
+ */
260
+ serviceKey?: string;
212
261
  }
213
262
  /** @see DataRateLimitConfig.anonymousFunctions */
214
263
  export declare const DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT = 3000;
@@ -229,7 +278,11 @@ export declare const DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT = 3000;
229
278
  * set them, and one that already has a proxy doing this should pass
230
279
  * `enabled: false` rather than pay for it twice.
231
280
  */
232
- export declare function createDataRateLimiter(config?: DataRateLimitConfig): MiddlewareHandler<HonoEnv>;
281
+ export declare function createDataRateLimiter(config?: DataRateLimitConfig,
282
+ /** See {@link RateLimiterOptions.cost}: what one request on this router counts as. */
283
+ options?: {
284
+ cost?: RateLimiterOptions["cost"];
285
+ }): MiddlewareHandler<HonoEnv>;
233
286
  /**
234
287
  * The data API's per-caller limit, as a check rather than a middleware — for
235
288
  * the door into the same data that is not an HTTP request.
@@ -1,3 +1,4 @@
1
+ import type { AuthRepository } from "./interfaces.js";
1
2
  /**
2
3
  * Whether a registration may proceed — computed in exactly one place.
3
4
  *
@@ -66,6 +67,21 @@ export interface RegistrationPolicy {
66
67
  export declare function isBootstrapWindowOpen(env?: {
67
68
  NODE_ENV?: string;
68
69
  }): boolean;
70
+ type UserPresenceRepository = Pick<AuthRepository, "firstUserIds" | "listUsersPaginated">;
71
+ /**
72
+ * Whether the users table is empty — the question behind the bootstrap window.
73
+ *
74
+ * Through `AuthRepository.firstUserIds` when the repository has it: one
75
+ * unordered `LIMIT 1` read. Otherwise through `listUsersPaginated`, which also
76
+ * counts and sorts the whole table, so it is only the fallback.
77
+ */
78
+ export declare function isUserTableEmpty(repo: UserPresenceRepository): Promise<boolean>;
79
+ /**
80
+ * Whether the account just created is the only one there is. Two ids at most:
81
+ * whether anyone else exists, and, when nobody does, whether it is this one.
82
+ * Same fallback as {@link isUserTableEmpty}.
83
+ */
84
+ export declare function isOnlyUser(repo: UserPresenceRepository, uid: string): Promise<boolean>;
69
85
  /**
70
86
  * What to tell a caller who hit an empty production database with the window
71
87
  * shut. Named here so the register route and the bootstrap route say the same
@@ -113,3 +129,4 @@ export declare function isAnonymousAuthOpen(policy: {
113
129
  allowAnonymous?: boolean;
114
130
  disableSelfRegistration?: boolean;
115
131
  }): boolean;
132
+ export {};
@@ -4,6 +4,8 @@ import type { AuthHooks } from "./auth-hooks.js";
4
4
  import { EmailService, EmailConfig } from "../email/index.js";
5
5
  import { HonoEnv } from "../api/types.js";
6
6
  import { type CaptchaConfig } from "./captcha.js";
7
+ import { isDeliverableAddress } from "./deliverable-address.js";
8
+ export { isDeliverableAddress };
7
9
  /**
8
10
  * Shared configuration for auth and admin route factories.
9
11
  */
@@ -86,7 +88,30 @@ export interface AuthModuleConfig {
86
88
  * how long a captured token stays useful to someone who copied it.
87
89
  */
88
90
  refreshTokenReuseIntervalSeconds?: number;
91
+ /**
92
+ * Let a magic-link or email-code request for an address with no account
93
+ * create one (no password, unverified until the link or code is used),
94
+ * while registration is open. Off by default. See `passwordless-signup.ts`.
95
+ */
96
+ magicLinkCreatesUsers?: boolean;
97
+ /**
98
+ * What a refresh token presented after its reuse window does to its
99
+ * session. See `RebaseAuthConfig.refreshTokenReuse`. Default `"reject"`.
100
+ */
101
+ refreshTokenReuse?: RefreshTokenReusePolicy;
102
+ /**
103
+ * Refuse password sign-in until the account's address is verified, and
104
+ * register confirm-first: `POST /auth/register` answers the same "check
105
+ * your inbox" whether or not the address already has an account, and
106
+ * signs nobody in. Off by default. Needs email; the boot refuses it
107
+ * without. See `RebaseAuthConfig.requireEmailVerification`.
108
+ */
109
+ requireEmailVerification?: boolean;
89
110
  }
111
+ /** What a refresh token replayed after its reuse window does to its session. */
112
+ export type RefreshTokenReusePolicy = "reject" | "revoke-session";
113
+ /** How long an email-verification link stays usable. */
114
+ export declare const EMAIL_VERIFICATION_TTL_MS: number;
90
115
  /**
91
116
  * Configuration for httpOnly refresh-token cookies.
92
117
  */
@@ -109,4 +134,24 @@ export interface CookieAuthConfig {
109
134
  */
110
135
  secure?: boolean;
111
136
  }
137
+ /**
138
+ * What {@link CreateSessionAndTokens} is told about the sign-in it opens.
139
+ *
140
+ * `method` is what `providerId` says for the session from now on — stored on
141
+ * its refresh token and carried across every rotation — so each door names
142
+ * its own rather than leaving it to a default.
143
+ */
144
+ export interface SessionOptions {
145
+ /** `"password"`, `"anonymous"`, `"magic-link"`, `"otp"`, `"mfa"` or a provider id. */
146
+ method: string;
147
+ /** Only for the route that has just seen the second factor. */
148
+ skipMfaGate?: boolean;
149
+ aal?: "aal1" | "aal2";
150
+ }
151
+ /** Mint a session, as every sign-in door does. See `createSessionAndTokens`. */
152
+ export type CreateSessionAndTokens = (uid: string, userAgent: string, ipAddress: string, options: SessionOptions) => Promise<{
153
+ roleIds: string[];
154
+ accessToken: string;
155
+ refreshToken: string;
156
+ }>;
112
157
  export declare function createAuthRoutes(config: AuthModuleConfig): Hono<HonoEnv>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `GET /auth/scopes` — every scope this backend knows, described, and the
3
+ * ones the caller holds.
4
+ *
5
+ * What a screen needs to offer scopes for a key or a role: the built-in ones,
6
+ * the app's own `auth.scopes`, their wording and what their targets name. Any
7
+ * authenticated caller may read it; it describes the backend's vocabulary,
8
+ * not anybody's data.
9
+ *
10
+ * @module
11
+ */
12
+ import { Hono, type MiddlewareHandler } from "hono";
13
+ import type { AccessJudgeRepository } from "./token-revocation.js";
14
+ import type { HonoEnv } from "../api/types.js";
15
+ export interface ScopeRouteOptions {
16
+ serviceKey?: string;
17
+ resolveRoles?: (uid: string) => Promise<string[]>;
18
+ revocationRepo?: AccessJudgeRepository;
19
+ /** Authenticates `rk_` keys first, so a key can read what it holds. */
20
+ apiKeyPreAuth?: MiddlewareHandler<HonoEnv>;
21
+ }
22
+ export declare function createScopeRoutes(options: ScopeRouteOptions): Hono<HonoEnv>;
@@ -2,7 +2,7 @@ import { Hono } from "hono";
2
2
  import { z } from "zod";
3
3
  import { HonoEnv } from "../api/types.js";
4
4
  import type { MiddlewareHandler } from "hono";
5
- import type { AuthModuleConfig } from "./routes.js";
5
+ import type { AuthModuleConfig, CreateSessionAndTokens } from "./routes.js";
6
6
  import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
7
7
  import type { resolveAuthHooks } from "./auth-hooks.js";
8
8
  interface SessionRoutesConfig {
@@ -28,11 +28,7 @@ interface SessionRoutesConfig {
28
28
  isAnonymous?: boolean;
29
29
  metadata?: Record<string, unknown> | null;
30
30
  }, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
31
- createSessionAndTokens: (uid: string, userAgent: string, ipAddress: string) => Promise<{
32
- roleIds: string[];
33
- accessToken: string;
34
- refreshToken: string;
35
- }>;
31
+ createSessionAndTokens: CreateSessionAndTokens;
36
32
  applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>;
37
33
  /**
38
34
  * The `register` captcha, built by the caller so a misconfiguration fails
@@ -41,6 +37,15 @@ interface SessionRoutesConfig {
41
37
  * `/register`. Absent when captcha is off or `register` is not protected.
42
38
  */
43
39
  registerCaptcha?: MiddlewareHandler<HonoEnv>;
40
+ /**
41
+ * Mail the account a verification link, in the background. Upgrading a
42
+ * guest is registration, and registration starts the address proof.
43
+ */
44
+ sendVerificationMail?: (user: {
45
+ id: string;
46
+ email: string;
47
+ displayName?: string | null;
48
+ }) => void;
44
49
  }
45
50
  export declare function mountSessionRoutes(opts: SessionRoutesConfig): void;
46
51
  export {};
@@ -37,6 +37,55 @@ import type { AccessTokenPayload } from "./jwt.js";
37
37
  * failure is logged at warn so it is visible rather than silent.
38
38
  */
39
39
  export declare function isAccessTokenRevoked(authRepo: Pick<AuthRepository, "getTokensValidAfter">, payload: Pick<AccessTokenPayload, "uid" | "iat">): Promise<boolean>;
40
+ /**
41
+ * The repository reads {@link judgeAccessToken} may make. All optional: a
42
+ * repository answers what it can, and the judge says what it could not ask.
43
+ */
44
+ export type AccessJudgeRepository = Partial<Pick<AuthRepository, "getAccountAccessState" | "getUserWithRoles" | "getTokensValidAfter">>;
45
+ /**
46
+ * Why an access token that verifies is not honoured.
47
+ *
48
+ * - `revoked`: issued before the account's revocation watermark — a sign-out
49
+ * everywhere, a password change or reset.
50
+ * - `session-revoked`: its own sign-in was ended — `POST /auth/logout`, or
51
+ * `DELETE /auth/sessions/:id` from another device. Needs the token's `sid`.
52
+ * - `account-deleted`: the account it names no longer exists.
53
+ * - `account-disabled`: an administrator switched the account off.
54
+ */
55
+ export type AccessTokenRefusal = "revoked" | "session-revoked" | "account-deleted" | "account-disabled";
56
+ export type AccessTokenVerdict = {
57
+ live: true;
58
+ /**
59
+ * The account's roles now, or `undefined` when the repository could
60
+ * not say (it reads neither the account nor its roles).
61
+ */
62
+ roles?: string[];
63
+ } | {
64
+ live: false;
65
+ refusal: AccessTokenRefusal;
66
+ };
67
+ /**
68
+ * Is the account behind this verified access token still the one that may use
69
+ * it — and with which roles?
70
+ *
71
+ * A verified signature says who the token was minted for, an hour ago at
72
+ * most. This asks the database what has happened to that account since. Every
73
+ * door that honours an access token — the data plane, the admin gates, the
74
+ * realtime socket — asks it here, so they cannot disagree about it.
75
+ *
76
+ * They did. A deleted account read as "not revoked": the watermark lives on
77
+ * the user row, so once the row was gone there was no watermark, and the
78
+ * roles lookup answered `[]` rather than "nobody". A token its owner had
79
+ * revoked came back to life when an administrator deleted the account, as an
80
+ * authenticated principal with that uid, for the rest of its lifetime. MCP
81
+ * refresh and personal API keys already treated a missing account as revoked;
82
+ * the main door did not.
83
+ *
84
+ * Throws when the repository does. Unlike the watermark read on its own, this
85
+ * one decides the roles a request runs with, so a failure is a refusal (the
86
+ * callers answer 503) rather than a guess.
87
+ */
88
+ export declare function judgeAccessToken(authRepo: AccessJudgeRepository, payload: Pick<AccessTokenPayload, "uid" | "iat" | "sid">): Promise<AccessTokenVerdict>;
40
89
  /**
41
90
  * End every session this user holds, on every device.
42
91
  *
@@ -72,4 +121,4 @@ export declare function revokeAllSessions(authRepo: Pick<AuthRepository, "delete
72
121
  * `null` removes the password instead, for the same reason and with the same
73
122
  * revocation: see `confirmAddressOwnership`.
74
123
  */
75
- export declare function replaceUserPassword(authRepo: Pick<AuthRepository, "updatePassword" | "deleteAllRefreshTokensForUser" | "setTokensValidAfter">, uid: string, passwordHash: string | null): Promise<void>;
124
+ export declare function replaceUserPassword(authRepo: Pick<AuthRepository, "updatePassword" | "deleteAllRefreshTokensForUser" | "setTokensValidAfter"> & Partial<Pick<AuthRepository, "deleteAllPasswordResetTokensForUser">>, uid: string, passwordHash: string | null): Promise<void>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Who may read the user picker (`GET /api/admin/users/pick`).
3
+ *
4
+ * A `userSelect` field stores a user's id, and the person filling it in picks
5
+ * that user from a list. Listing the users is an admin-plane read
6
+ * (`users:read`), which an editor does not hold — so the picker answers a
7
+ * narrower question for a wider audience: id, name, email and avatar, to
8
+ * anyone who may write a collection that has such a field.
9
+ *
10
+ * "May write" is the collection's `securityRules` for an insert or an update,
11
+ * evaluated the way the admin panel decides whether to offer the form, with
12
+ * one difference. A rule that depends only on the row (an owner field) counts
13
+ * as allowing, since the person may write some row. A rule written as SQL the
14
+ * policy model cannot read cannot be judged ahead, and here it counts as
15
+ * refusing: read optimistically, it would let any signed-in person list every
16
+ * user's name and email. A key or token narrowed by scopes must also hold
17
+ * `data:write` on that collection.
18
+ *
19
+ * The collections are read through a getter configured at boot, so a schema
20
+ * edited live is what is judged.
21
+ *
22
+ * @module
23
+ */
24
+ import type { Context } from "hono";
25
+ import { type CollectionConfig, type Properties } from "@rebasepro/types";
26
+ import type { HonoEnv } from "../api/types.js";
27
+ /** Tell the picker which collections this backend serves. Called once at boot. */
28
+ export declare function configureUserPicking(collections: () => readonly CollectionConfig[]): void;
29
+ /** Whether any property, at any depth, is a `userSelect` field. */
30
+ export declare function propertiesReferenceUsers(properties: Properties | undefined): boolean;
31
+ /**
32
+ * Whether this request's caller may read the user picker: they hold
33
+ * `users:read`, or they may write a collection with a `userSelect` field.
34
+ */
35
+ export declare function mayPickUsers(c: Context<HonoEnv>): boolean;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Verify a bearer credential outside the HTTP middlewares — for a custom
3
+ * socket, a tunnel, anything an app authenticates from a frame or a header it
4
+ * read itself.
5
+ *
6
+ * One answer for the two kinds of credential a person can hold: a session
7
+ * token, and an API key (`rk_`). Both come back as who the caller acts as and
8
+ * what it may do, so the endpoint checks a scope the same way either way.
9
+ *
10
+ * @module
11
+ */
12
+ import type { ApiKeyStore } from "./api-keys/api-key-store.js";
13
+ /** Who a verified credential acts as, and what it may do. */
14
+ export interface VerifiedCredential {
15
+ uid: string;
16
+ roles: string[];
17
+ scopes: string[];
18
+ /** `"api-key"` when an `rk_` key was presented, otherwise `"session"`. */
19
+ kind: "session" | "api-key";
20
+ }
21
+ /** Install the key store `verifyCredential` checks `rk_` keys against. Called once at boot. */
22
+ export declare function configureCredentialStore(store: ApiKeyStore | undefined): void;
23
+ /**
24
+ * The identity and scopes behind a bearer credential, or null when it does
25
+ * not verify — expired, revoked, unknown, or a key on a backend with no key
26
+ * store.
27
+ */
28
+ export declare function verifyCredential(token: string): Promise<VerifiedCredential | null>;