@rebasepro/server 0.23.0 → 0.24.1-canary.g19596ef

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 (287) hide show
  1. package/README.md +28 -3
  2. package/bin/rebase-server.js +4 -2
  3. package/dist/GCSStorageController-DEga1ULx.js +402 -0
  4. package/dist/GCSStorageController-DEga1ULx.js.map +1 -0
  5. package/dist/S3StorageController-Btx-6bJ5.js +480 -0
  6. package/dist/S3StorageController-Btx-6bJ5.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +92 -1
  8. package/dist/api/errors.d.ts +41 -0
  9. package/dist/api/live-schema-routes.d.ts +64 -10
  10. package/dist/api/logs-routes.d.ts +39 -1
  11. package/dist/api/mount-path.d.ts +30 -0
  12. package/dist/api/mount.d.ts +6 -13
  13. package/dist/api/openapi-generator.d.ts +17 -0
  14. package/dist/api/rest/api-generator.d.ts +97 -11
  15. package/dist/api/rest/auth-collection-writes.d.ts +28 -21
  16. package/dist/api/rest/field-access-query.d.ts +28 -8
  17. package/dist/api/rest/field-ops.d.ts +19 -7
  18. package/dist/api/rest/query-body.d.ts +10 -0
  19. package/dist/api/rest/write-validation.d.ts +9 -7
  20. package/dist/api/schema-editor-routes.d.ts +10 -1
  21. package/dist/api/sql-export-routes.d.ts +8 -0
  22. package/dist/api/types.d.ts +52 -1
  23. package/dist/{ast-schema-editor-Mvr50v_S.js → ast-schema-editor-mCeSC03x.js} +310 -12
  24. package/dist/ast-schema-editor-mCeSC03x.js.map +1 -0
  25. package/dist/auth/access.d.ts +156 -0
  26. package/dist/auth/adapter-middleware.d.ts +2 -1
  27. package/dist/auth/address-ownership.d.ts +16 -1
  28. package/dist/auth/admin-roles-route.d.ts +4 -2
  29. package/dist/auth/admin-roles.d.ts +17 -20
  30. package/dist/auth/admin-user-ops.d.ts +24 -2
  31. package/dist/auth/admin-users-route.d.ts +2 -0
  32. package/dist/auth/api-keys/api-key-middleware.d.ts +64 -56
  33. package/dist/auth/api-keys/api-key-routes.d.ts +44 -11
  34. package/dist/auth/api-keys/api-key-store.d.ts +31 -8
  35. package/dist/auth/api-keys/api-key-types.d.ts +14 -16
  36. package/dist/auth/api-keys/http-operation.d.ts +19 -0
  37. package/dist/auth/api-keys/index.d.ts +11 -11
  38. package/dist/auth/api-keys/key-grant.d.ts +41 -0
  39. package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
  40. package/dist/auth/auth-hooks.d.ts +46 -7
  41. package/dist/auth/builtin-auth-adapter.d.ts +21 -0
  42. package/dist/auth/cookie-utils.d.ts +7 -0
  43. package/dist/auth/deliverable-address.d.ts +6 -0
  44. package/dist/auth/email-change-routes.d.ts +44 -0
  45. package/dist/auth/expired-token-sweep.d.ts +71 -0
  46. package/dist/auth/impersonation.d.ts +110 -0
  47. package/dist/auth/index.d.ts +4 -2
  48. package/dist/auth/interfaces.d.ts +120 -59
  49. package/dist/auth/jwks-routes.d.ts +5 -1
  50. package/dist/auth/jwt-crypto.d.ts +7 -0
  51. package/dist/auth/jwt-keys.d.ts +4 -0
  52. package/dist/auth/jwt.d.ts +319 -157
  53. package/dist/auth/magic-link-routes.d.ts +5 -6
  54. package/dist/auth/mfa-crypto.d.ts +9 -3
  55. package/dist/auth/mfa-gate.d.ts +4 -2
  56. package/dist/auth/mfa-routes.d.ts +8 -9
  57. package/dist/auth/middleware.d.ts +26 -7
  58. package/dist/auth/otp-routes.d.ts +5 -6
  59. package/dist/auth/passwordless-signup.d.ts +27 -0
  60. package/dist/auth/platform-token.d.ts +122 -0
  61. package/dist/auth/rate-limiter.d.ts +99 -31
  62. package/dist/auth/registration-policy.d.ts +17 -0
  63. package/dist/auth/require-auth.d.ts +1 -1
  64. package/dist/auth/routes.d.ts +61 -0
  65. package/dist/auth/scope-routes.d.ts +22 -0
  66. package/dist/auth/session-routes.d.ts +17 -6
  67. package/dist/auth/token-revocation.d.ts +56 -1
  68. package/dist/auth/user-picking.d.ts +37 -0
  69. package/dist/auth/verify-credential.d.ts +49 -0
  70. package/dist/{auth-B-GIMpDG.js → auth-CSBky1mt.js} +4564 -1929
  71. package/dist/auth-CSBky1mt.js.map +1 -0
  72. package/dist/auth_adapter-CIItCTc8.js +21 -0
  73. package/dist/auth_adapter-CIItCTc8.js.map +1 -0
  74. package/dist/backend/create-backend.d.ts +281 -0
  75. package/dist/backend/default-backend.d.ts +35 -0
  76. package/dist/backend/no-collections.d.ts +19 -0
  77. package/dist/backend/options.d.ts +912 -0
  78. package/dist/backend/scope.d.ts +23 -0
  79. package/dist/backend/services.d.ts +54 -0
  80. package/dist/backend-DTAOsLQc.js.map +1 -1
  81. package/dist/backup/backup-common.d.ts +24 -3
  82. package/dist/backup/backup-routes.d.ts +46 -5
  83. package/dist/backup/backup-schedule.d.ts +33 -0
  84. package/dist/backup/backup-storage.d.ts +16 -0
  85. package/dist/backup/index.d.ts +5 -1
  86. package/dist/backup-DBGRUVTS.js +585 -0
  87. package/dist/backup-DBGRUVTS.js.map +1 -0
  88. package/dist/boot/boot.d.ts +2 -2
  89. package/dist/boot/bundle.d.ts +19 -0
  90. package/dist/boot/driver.d.ts +3 -0
  91. package/dist/boot/env.d.ts +58 -6
  92. package/dist/boot/http-server.d.ts +22 -0
  93. package/dist/boot/options.d.ts +16 -1
  94. package/dist/boot/provision.d.ts +4 -2
  95. package/dist/boot/resource-adapters.d.ts +11 -14
  96. package/dist/boot/runtime-cors.d.ts +17 -0
  97. package/dist/boot/security-headers.d.ts +26 -0
  98. package/dist/boot/sources.d.ts +9 -0
  99. package/dist/boot/static-routing.d.ts +65 -0
  100. package/dist/collection_patch-BRu-BvDv.js +472 -0
  101. package/dist/collection_patch-BRu-BvDv.js.map +1 -0
  102. package/dist/{contract-routes-CbFjuBwa.js → contract-routes-DiFwiLg2.js} +5 -8
  103. package/dist/contract-routes-DiFwiLg2.js.map +1 -0
  104. package/dist/cron/cron-loader.d.ts +77 -18
  105. package/dist/cron/cron-routes.d.ts +1 -1
  106. package/dist/cron/cron-scheduler.d.ts +94 -23
  107. package/dist/cron/cron-store.d.ts +37 -5
  108. package/dist/cron/define-cron.d.ts +6 -2
  109. package/dist/cron/index.d.ts +3 -3
  110. package/dist/cron-loader-NHqRfKF0.js +202 -0
  111. package/dist/cron-loader-NHqRfKF0.js.map +1 -0
  112. package/dist/{cron-routes-eE8nif_b.js → cron-routes-DsH8Jwn5.js} +34 -8
  113. package/dist/cron-routes-DsH8Jwn5.js.map +1 -0
  114. package/dist/{cron-scheduler-B0pLfAix.js → cron-scheduler-D1DT0nw5.js} +349 -65
  115. package/dist/cron-scheduler-D1DT0nw5.js.map +1 -0
  116. package/dist/cron-store-DEpVstUU.js +577 -0
  117. package/dist/cron-store-DEpVstUU.js.map +1 -0
  118. package/dist/{ddl-bootstrap-C6mo0Kmz.js → ddl-bootstrap-BNqi2NZe.js} +2 -2
  119. package/dist/{ddl-bootstrap-C6mo0Kmz.js.map → ddl-bootstrap-BNqi2NZe.js.map} +1 -1
  120. package/dist/email/index.d.ts +2 -2
  121. package/dist/email/smtp-email-service.d.ts +23 -0
  122. package/dist/email/templates.d.ts +22 -0
  123. package/dist/email/types.d.ts +44 -0
  124. package/dist/env.d.ts +1 -39
  125. package/dist/{errors-DWsX4yTd.js → errors-Cqp86KnA.js} +263 -10
  126. package/dist/errors-Cqp86KnA.js.map +1 -0
  127. package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
  128. package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
  129. package/dist/{function-loader-xnbDAPfa.js → function-loader-DbCSoNJj.js} +69 -39
  130. package/dist/function-loader-DbCSoNJj.js.map +1 -0
  131. package/dist/{function-routes-Chet4-lB.js → function-routes-BSTClQNa.js} +28 -15
  132. package/dist/function-routes-BSTClQNa.js.map +1 -0
  133. package/dist/functions/context.d.ts +26 -6
  134. package/dist/functions/define-function.d.ts +10 -6
  135. package/dist/functions/function-loader.d.ts +75 -18
  136. package/dist/functions/function-routes.d.ts +2 -1
  137. package/dist/functions/guards.d.ts +22 -5
  138. package/dist/functions/index.d.ts +6 -5
  139. package/dist/functions/index.js +148 -50
  140. package/dist/functions/index.js.map +1 -1
  141. package/dist/functions/internal.d.ts +2 -2
  142. package/dist/functions/proxy.d.ts +6 -2
  143. package/dist/functions/request-timeout.d.ts +7 -5
  144. package/dist/history/history-routes.d.ts +9 -0
  145. package/dist/history/retention-sweep.d.ts +81 -0
  146. package/dist/{history-recorder-B4MpJfJK.js → history-recorder-RZ1Ow4YY.js} +4 -4
  147. package/dist/{history-recorder-B4MpJfJK.js.map → history-recorder-RZ1Ow4YY.js.map} +1 -1
  148. package/dist/{history-store-BhxWOuz9.js → history-store-DPofGVDp.js} +2 -2
  149. package/dist/{history-store-BhxWOuz9.js.map → history-store-DPofGVDp.js.map} +1 -1
  150. package/dist/index.d.ts +32 -13
  151. package/dist/index.es.js +25329 -18393
  152. package/dist/index.es.js.map +1 -1
  153. package/dist/init/docs.d.ts +35 -10
  154. package/dist/init/health.d.ts +17 -2
  155. package/dist/init/process-safety.d.ts +7 -2
  156. package/dist/init/shutdown.d.ts +26 -1
  157. package/dist/init.d.ts +49 -811
  158. package/dist/internal-tables-L2t39RdT.js +136 -0
  159. package/dist/internal-tables-L2t39RdT.js.map +1 -0
  160. package/dist/jobs/job-queue.d.ts +8 -0
  161. package/dist/jobs/job-store.d.ts +24 -0
  162. package/dist/jobs/types.d.ts +25 -4
  163. package/dist/{jobs-CazMYhyy.js → jobs-8G-_agld.js} +235 -25
  164. package/dist/jobs-8G-_agld.js.map +1 -0
  165. package/dist/{jwt-DnQHNFCl.js → jwt-CBaFc34Y.js} +546 -447
  166. package/dist/jwt-CBaFc34Y.js.map +1 -0
  167. package/dist/{keys-CogCQpxG.js → keys-COzQ2aE8.js} +3 -17
  168. package/dist/{keys-CogCQpxG.js.map → keys-COzQ2aE8.js.map} +1 -1
  169. package/dist/load-failure-L5hvfDoG.js +80 -0
  170. package/dist/load-failure-L5hvfDoG.js.map +1 -0
  171. package/dist/{logger-DO2PZc4i.js → logger-Bt32sHFw.js} +41 -5
  172. package/dist/logger-Bt32sHFw.js.map +1 -0
  173. package/dist/{logs-routes-Bj4TYYUl.js → logs-routes-DQJhrf-b.js} +48 -8
  174. package/dist/logs-routes-DQJhrf-b.js.map +1 -0
  175. package/dist/mcp/consent-page.d.ts +1 -1
  176. package/dist/mcp/mcp-routes.d.ts +13 -0
  177. package/dist/mcp/mcp-tools.d.ts +23 -9
  178. package/dist/mcp/oauth-metadata.d.ts +21 -16
  179. package/dist/mcp/oauth-routes.d.ts +14 -1
  180. package/dist/metrics/index.d.ts +18 -0
  181. package/dist/metrics/pool-wait.d.ts +50 -0
  182. package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
  183. package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
  184. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
  185. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
  186. package/dist/{openapi-generator-O_O24MAT.js → openapi-generator-CeGW2dLC.js} +455 -80
  187. package/dist/openapi-generator-CeGW2dLC.js.map +1 -0
  188. package/dist/policy-PdzX-Opd.js +121 -0
  189. package/dist/policy-PdzX-Opd.js.map +1 -0
  190. package/dist/project_manifest-R6y_KHms.js +59 -0
  191. package/dist/project_manifest-R6y_KHms.js.map +1 -0
  192. package/dist/{proxy-Czngl3p9.js → proxy-BEKbsil6.js} +5 -4
  193. package/dist/proxy-BEKbsil6.js.map +1 -0
  194. package/dist/{query-parser-DGRVFNM3.js → query-parser-ECxP0nDw.js} +497 -52
  195. package/dist/query-parser-ECxP0nDw.js.map +1 -0
  196. package/dist/{request-timeout-C_4C2BeR.js → request-timeout-BiRelY-U.js} +17 -10
  197. package/dist/request-timeout-BiRelY-U.js.map +1 -0
  198. package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
  199. package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
  200. package/dist/schema-edit/apply-schema-change.d.ts +73 -3
  201. package/dist/schema-edit/local-source.d.ts +29 -0
  202. package/dist/schema-edit/project-root.d.ts +3 -2
  203. package/dist/schema-edit/remote-source.d.ts +20 -5
  204. package/dist/schema-edit/source-editor.d.ts +28 -0
  205. package/dist/schema-editor-routes-DRXBAbZy.js +136 -0
  206. package/dist/schema-editor-routes-DRXBAbZy.js.map +1 -0
  207. package/dist/serve-spa.d.ts +58 -0
  208. package/dist/services/outbound-post.d.ts +50 -0
  209. package/dist/services/outbound-url-guard.d.ts +34 -5
  210. package/dist/services/routed-realtime-service.d.ts +16 -0
  211. package/dist/services/webhook-service.d.ts +66 -14
  212. package/dist/singleton.d.ts +9 -5
  213. package/dist/soft-delete-params-CBryZXMq.js +668 -0
  214. package/dist/soft-delete-params-CBryZXMq.js.map +1 -0
  215. package/dist/sql-export-routes-D8ZaRvoR.js +240 -0
  216. package/dist/sql-export-routes-D8ZaRvoR.js.map +1 -0
  217. package/dist/{src-vkcwKXbT.js → src-D5Y3N-S4.js} +440 -20
  218. package/dist/src-D5Y3N-S4.js.map +1 -0
  219. package/dist/storage/GCSStorageController.d.ts +48 -2
  220. package/dist/storage/LocalStorageController.d.ts +69 -2
  221. package/dist/storage/S3StorageController.d.ts +39 -3
  222. package/dist/storage/image-transform.d.ts +15 -0
  223. package/dist/storage/index.d.ts +2 -2
  224. package/dist/storage/maintenance-routes.d.ts +23 -0
  225. package/dist/storage/maintenance.d.ts +126 -0
  226. package/dist/storage/property-limits.d.ts +41 -6
  227. package/dist/storage/rendition-cache.d.ts +9 -11
  228. package/dist/storage/request-keys.d.ts +15 -0
  229. package/dist/storage/request-principals.d.ts +30 -0
  230. package/dist/storage/requested-object.d.ts +74 -0
  231. package/dist/storage/routes.d.ts +52 -14
  232. package/dist/storage/source-variables.d.ts +10 -0
  233. package/dist/storage/streams.d.ts +42 -0
  234. package/dist/storage/tus-handler.d.ts +76 -7
  235. package/dist/storage/types.d.ts +101 -7
  236. package/dist/storage/upload-validation.d.ts +13 -0
  237. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
  238. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
  239. package/dist/strings.es-BeZWAodn.js +256 -0
  240. package/dist/strings.es-BeZWAodn.js.map +1 -0
  241. package/dist/upload-validation-CVobI5xO.js +172 -0
  242. package/dist/upload-validation-CVobI5xO.js.map +1 -0
  243. package/dist/utils/byte-size.d.ts +10 -0
  244. package/dist/utils/compression.d.ts +6 -0
  245. package/dist/utils/load-failure.d.ts +14 -0
  246. package/dist/utils/logger.d.ts +21 -0
  247. package/package.json +5 -5
  248. package/dist/GCSStorageController-CjrA4PMo.js +0 -242
  249. package/dist/GCSStorageController-CjrA4PMo.js.map +0 -1
  250. package/dist/S3StorageController-B6pKDNVj.js +0 -264
  251. package/dist/S3StorageController-B6pKDNVj.js.map +0 -1
  252. package/dist/admin-roles-vYdp_Pil.js +0 -36
  253. package/dist/admin-roles-vYdp_Pil.js.map +0 -1
  254. package/dist/admin_block-DxKLmdiv.js +0 -206
  255. package/dist/admin_block-DxKLmdiv.js.map +0 -1
  256. package/dist/ast-schema-editor-Mvr50v_S.js.map +0 -1
  257. package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
  258. package/dist/auth-B-GIMpDG.js.map +0 -1
  259. package/dist/backup-D7YR94N3.js +0 -253
  260. package/dist/backup-D7YR94N3.js.map +0 -1
  261. package/dist/contract-routes-CbFjuBwa.js.map +0 -1
  262. package/dist/cron-loader-DfTj2Hbi.js +0 -118
  263. package/dist/cron-loader-DfTj2Hbi.js.map +0 -1
  264. package/dist/cron-routes-eE8nif_b.js.map +0 -1
  265. package/dist/cron-scheduler-B0pLfAix.js.map +0 -1
  266. package/dist/cron-store-TcoGz-xS.js +0 -305
  267. package/dist/cron-store-TcoGz-xS.js.map +0 -1
  268. package/dist/dynamic-import-X40pTZUQ.js +0 -23
  269. package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
  270. package/dist/errors-DWsX4yTd.js.map +0 -1
  271. package/dist/function-loader-xnbDAPfa.js.map +0 -1
  272. package/dist/function-routes-Chet4-lB.js.map +0 -1
  273. package/dist/jobs-CazMYhyy.js.map +0 -1
  274. package/dist/jwt-DnQHNFCl.js.map +0 -1
  275. package/dist/logger-DO2PZc4i.js.map +0 -1
  276. package/dist/logs-routes-Bj4TYYUl.js.map +0 -1
  277. package/dist/openapi-generator-O_O24MAT.js.map +0 -1
  278. package/dist/proxy-Czngl3p9.js.map +0 -1
  279. package/dist/query-parser-DGRVFNM3.js.map +0 -1
  280. package/dist/request-timeout-C_4C2BeR.js.map +0 -1
  281. package/dist/schema-editor-routes-C5-lh_jO.js +0 -87
  282. package/dist/schema-editor-routes-C5-lh_jO.js.map +0 -1
  283. package/dist/src-pmvW7BFx.js +0 -6688
  284. package/dist/src-pmvW7BFx.js.map +0 -1
  285. package/dist/src-vkcwKXbT.js.map +0 -1
  286. package/dist/types-BfKcm9do.js +0 -39
  287. package/dist/types-BfKcm9do.js.map +0 -1
@@ -23,6 +23,38 @@ export declare function schemaDriftRemedy(): {
23
23
  short: string;
24
24
  lines: string[];
25
25
  };
26
+ /**
27
+ * Did the database refuse a value as unreadable for its column's type —
28
+ * SQLSTATE class 22, anywhere down the cause chain?
29
+ *
30
+ * For a lookup by an id the caller supplied, that is an answer rather than a
31
+ * failure: `abc` against a UUID key names no row, exactly as a well-formed id
32
+ * nobody has does.
33
+ */
34
+ export declare function isDataException(error: unknown): boolean;
35
+ /**
36
+ * Did the request fail because the database could not be reached at all — not
37
+ * because it refused the statement, and not because some other service is down?
38
+ *
39
+ * Read off the error the database driver raised, wherever it sits in the cause
40
+ * chain:
41
+ *
42
+ * - a SQLSTATE that means the connection was refused or dropped (class `08`,
43
+ * `57P01`–`57P03`). The database's own word, so it settles the question
44
+ * either way: a SQLSTATE of any other class is the database answering;
45
+ * - node-postgres's own sentence for a socket that closed under a query;
46
+ * - a socket failure (`ECONNREFUSED`, `ENOTFOUND`, …), but only where it can
47
+ * only be the database's: thrown as it is, which is how node-postgres hands
48
+ * back a pool connection it could not open, or as the cause of a failed
49
+ * Drizzle query (the wrapper that carries the statement). Under any other
50
+ * wrapper it belongs to another client: `fetch failed` is a `fetch()` to
51
+ * some other host, and an S3 call that cannot connect carries the AWS SDK's
52
+ * `$metadata`. Answering those "the database is unreachable" would send an
53
+ * operator to a database that is fine.
54
+ */
55
+ export declare function isDatabaseUnreachable(error: unknown): boolean;
56
+ /** What a caller is told when the database cannot be reached. Retryable, and not about them. */
57
+ export declare const DATABASE_UNAVAILABLE_MESSAGE: string;
26
58
  /**
27
59
  * Standardized API error class.
28
60
  * Throw this from any route handler — the errorHandler middleware
@@ -72,6 +104,15 @@ export declare class ApiError extends Error {
72
104
  static conflict(message: string, code?: string, details?: unknown): ApiError;
73
105
  static internal(message: string, code?: string): ApiError;
74
106
  static serviceUnavailable(message: string, code?: string): ApiError;
107
+ /**
108
+ * `503 DATABASE_UNAVAILABLE`: the database could not be reached. What
109
+ * every door answers then — the data API, sign-in, the admin routes and
110
+ * the realtime socket — so a client sees one retryable answer, sent with
111
+ * `Retry-After`, rather than a permission failure or a crash.
112
+ *
113
+ * @see isDatabaseUnreachable
114
+ */
115
+ static databaseUnavailable(message?: string): ApiError;
75
116
  }
76
117
  /**
77
118
  * Canonical error response shape:
@@ -29,7 +29,7 @@
29
29
  * — `applySchemaChange` re-checks rather than trusting the plan it is handed.
30
30
  */
31
31
  import { Hono } from "hono";
32
- import { type CollectionConfig, type DatabaseAdmin, type SchemaCommitPaths } from "@rebasepro/types";
32
+ import { type AuthAdapter, type CollectionPatch, type CollectionConfig, type DatabaseAdmin, type SchemaCommitPaths } from "@rebasepro/types";
33
33
  import { HonoEnv } from "./types.js";
34
34
  import { type SchemaEditRepository } from "../schema-edit/apply-schema-change.js";
35
35
  import { type SchemaEditPolicy } from "../schema-edit/schema-edit-permissions.js";
@@ -87,8 +87,8 @@ export interface LiveSchemaRoutesConfig {
87
87
  *
88
88
  * Absent for a project that *is* the repository, which is what the defaults
89
89
  * describe. Present for one in a subdirectory, where the defaults would
90
- * write `backend/` and `drizzle/` beside `.git` and leave the project's real
91
- * generated files untouched — committing a source change alongside a stale
90
+ * write `backend/` beside `.git` and leave the project's real generated
91
+ * file untouched — committing a source change alongside a stale
92
92
  * schema, which is the failure committing the whole change exists to avoid.
93
93
  */
94
94
  commitPaths?: Partial<SchemaCommitPaths>;
@@ -97,8 +97,8 @@ export interface LiveSchemaRoutesConfig {
97
97
  * environment.
98
98
  *
99
99
  * If it does, applying here is not the whole job: the DDL runs against
100
- * *this* database and `drizzle/schema.sql` is committed, but no migration
101
- * is written — a server cannot mint one, since that needs Atlas and a
100
+ * *this* database and the collection is committed, but no migration is
101
+ * written — a server cannot mint one, since that needs Atlas and a
102
102
  * throwaway database. The next environment built by replaying migrations
103
103
  * would not have this change, and nothing would have said so.
104
104
  */
@@ -110,12 +110,52 @@ export interface LiveSchemaRoutesConfig {
110
110
  * commit, a commit needs an author, and a credential is not an author.
111
111
  */
112
112
  policy?: SchemaEditPolicy;
113
+ /**
114
+ * The account behind a uid, for the commit's author line.
115
+ *
116
+ * The request's user is what its access token carries, and the built-in
117
+ * token carries a uid and roles — no name, no address — so without this a
118
+ * commit is authored by the uid. Absent, or answering nothing, the commit
119
+ * falls back to what the request carries.
120
+ */
121
+ resolveAuthorIdentity?: (uid: string) => Promise<AccountIdentity | null>;
122
+ }
123
+ /** What a commit's author line is made of. */
124
+ export interface AccountIdentity {
125
+ displayName?: string | null;
126
+ email?: string | null;
113
127
  }
114
- /** What the panel posts: one collection, in the shape it should end up. */
128
+ /**
129
+ * The account behind a uid, read through the auth in use: its user-management
130
+ * lookup when it has one — a plain read — else `resolveUser`. `null` when the
131
+ * auth has neither, or knows no such account.
132
+ */
133
+ export declare function readAccountIdentity(adapter: Pick<AuthAdapter, "userManagement" | "resolveUser"> | undefined, uid: string): Promise<AccountIdentity | null>;
134
+ /**
135
+ * What the panel posts about one collection.
136
+ *
137
+ * For a collection that exists, a `patch`: what the person changed, as the
138
+ * difference between the JSON the editor loaded and the JSON it is saving (see
139
+ * `collection_patch.ts` in `@rebasepro/types`). The whole collection travelled
140
+ * here once, and the write rewrote every key it carried and deleted whatever
141
+ * JSON had dropped — handlers, shared properties, imported enums, comments.
142
+ *
143
+ * For a collection that does not exist yet, the whole `collection`. A caller
144
+ * that sends a whole collection for one that exists has it turned into the
145
+ * patch of what differs (see {@link asPatch}).
146
+ */
115
147
  export interface ProposedChange {
116
148
  collectionId: string;
117
- /** The whole collection as it should be after the edit. */
118
- collection: Record<string, unknown>;
149
+ /** The whole collection — only for one that does not exist yet. */
150
+ collection?: Record<string, unknown>;
151
+ /** What changed about an existing collection. */
152
+ patch?: CollectionPatch;
153
+ /**
154
+ * Delete the collection's source: its file, and its entry in `index.ts`.
155
+ * Planned like any change — the table and its rows stay, and say so — and
156
+ * committed source-only.
157
+ */
158
+ remove?: true;
119
159
  }
120
160
  /**
121
161
  * The git identity for the caller.
@@ -123,11 +163,25 @@ export interface ProposedChange {
123
163
  * `undefined` when the request carries no user — a service key, say — which
124
164
  * lets the repository fall back to its own git config rather than inventing a
125
165
  * name for somebody.
166
+ *
167
+ * The name and address the request carries win; what it lacks is read from
168
+ * the account through `resolveAccount`. A lookup that fails costs the commit
169
+ * its name, never the commit: the author falls back to the uid.
126
170
  */
127
- export declare function commitAuthor(user: unknown): {
171
+ export declare function commitAuthor(user: unknown, resolveAccount?: (uid: string) => Promise<AccountIdentity | null>): Promise<{
128
172
  name: string;
129
173
  email: string;
130
- } | undefined;
174
+ } | undefined>;
175
+ /**
176
+ * The change as a patch against the collection as it is.
177
+ *
178
+ * A whole collection posted for one that exists is the difference from the
179
+ * current one: a caller that sends JSON cannot then delete what JSON could not
180
+ * carry. A key it left out is removed only when its value is pure data — a
181
+ * key holding code (`callbacks`, a handler, a component) is not something a
182
+ * JSON caller could have meant to drop.
183
+ */
184
+ export declare function asPatch(existing: CollectionConfig, change: ProposedChange): CollectionPatch;
131
185
  /**
132
186
  * The proposed collection set: everything as it is, with one collection
133
187
  * replaced or added.
@@ -44,6 +44,15 @@ declare class LogRingBuffer {
44
44
  getLatest(count?: number): LogEntry[];
45
45
  }
46
46
  export declare const logBuffer: LogRingBuffer;
47
+ /**
48
+ * Which process this log belongs to.
49
+ *
50
+ * The ring is this process's memory, and nothing gathers the rings of a
51
+ * deployment's other replicas or of its split runtime roles. So a reader is
52
+ * told whose log it is: `HOSTNAME` is the pod name on Kubernetes and the
53
+ * container id under Docker; the pid tells two local processes apart.
54
+ */
55
+ export declare function logInstanceName(): string;
47
56
  /** Add a log entry */
48
57
  export declare function addLog(level: LogEntry["level"], source: LogEntry["source"], message: string, metadata?: Record<string, unknown>): void;
49
58
  export interface LogMiddlewareOptions {
@@ -55,7 +64,25 @@ export interface LogMiddlewareOptions {
55
64
  * server it is also the thing evicting real entries out of the ring.
56
65
  */
57
66
  ignorePaths?: string[];
67
+ /**
68
+ * Where the API is mounted (`/api`). The segment after it names the
69
+ * subsystem a request is filed under — see {@link sourceForRequestPath}.
70
+ * Unset, the first segment of the path is read.
71
+ */
72
+ basePath?: string;
58
73
  }
74
+ /**
75
+ * The `source` of a request entry: the subsystem its path addresses.
76
+ *
77
+ * `/api/auth/*` and the MCP authorization server under `/api/oauth/*` are
78
+ * `auth`, `/api/storage/*` is `storage`, and everything else is `api`. The
79
+ * Logs Explorer's Source filter matches this field, so a sign-in filed as
80
+ * `api` was invisible under Auth. The realtime socket is not an HTTP request
81
+ * and is not recorded here.
82
+ *
83
+ * Exported for its test.
84
+ */
85
+ export declare function sourceForRequestPath(path: string, basePath?: string): LogEntry["source"];
59
86
  /** Hono middleware to log API requests */
60
87
  export declare function logMiddleware(options?: LogMiddlewareOptions): MiddlewareHandler<HonoEnv>;
61
88
  /**
@@ -79,6 +106,17 @@ export interface LogStreamTiming {
79
106
  heartbeatMs?: number;
80
107
  maxPending?: number;
81
108
  }
82
- export declare function createLogsRoutes(timing?: LogStreamTiming): Hono<HonoEnv>;
109
+ /** What ends the stream from the server's side. */
110
+ export interface LogsRoutesOptions {
111
+ /**
112
+ * Aborted when the backend shuts down. Every open stream ends then, rather
113
+ * than when its client happens to leave: `server.close()` waits on every
114
+ * open connection, so one Studio → Logs tab held a SIGTERM for the whole
115
+ * force timeout — longer than Cloud Run's or `docker stop`'s grace period,
116
+ * which killed the process before the pool was closed.
117
+ */
118
+ closeSignal?: AbortSignal;
119
+ }
120
+ export declare function createLogsRoutes(timing?: LogStreamTiming, options?: LogsRoutesOptions): Hono<HonoEnv>;
83
121
  declare const _default: Hono<HonoEnv, import("hono/types").BlankSchema, "/">;
84
122
  export default _default;
@@ -0,0 +1,30 @@
1
+ import type { Context, MiddlewareHandler } from "hono";
2
+ import type { HonoEnv } from "./types.js";
3
+ /**
4
+ * Where a route group is mounted, read from the request rather than configured.
5
+ *
6
+ * A group — the data API, the functions router — is a Hono sub-app a caller can
7
+ * mount anywhere: `/api/data`, `/v2/data`, `/:tenant/data`. A few of its
8
+ * decisions need that prefix (which collection a path names, which function a
9
+ * scoped key is calling, what URL the listing reports), and it used to be passed
10
+ * in as `${basePath}/data` when the group was built — which pinned the group to
11
+ * the one path its builder assumed.
12
+ *
13
+ * Hono already knows: a middleware registered at the root of a group with
14
+ * `use("/*")` is stored under the merged path `<mount>/*`, however deeply the
15
+ * group was nested, and `routePath(c)` returns the path of the handler running
16
+ * now. Must therefore be called from such a middleware — see
17
+ * {@link recordMountPath}, which is how a group does it.
18
+ *
19
+ * A mount path with parameters (`/:tenant/data`) is resolved against the request
20
+ * segment by segment, so the answer is the concrete prefix (`/acme/data`).
21
+ */
22
+ export declare function requestMountPath(c: Context): string;
23
+ /**
24
+ * A group's first middleware: record where the group is mounted as
25
+ * `c.var.mountPath`, for everything after it in the same request.
26
+ *
27
+ * Registered with `use("/*")` on the group's own router, before anything else —
28
+ * that registration is what makes {@link requestMountPath} see the mount.
29
+ */
30
+ export declare function recordMountPath(): MiddlewareHandler<HonoEnv>;
@@ -23,19 +23,12 @@
23
23
  */
24
24
  import { Hono } from "hono";
25
25
  import type { HonoEnv } from "./types.js";
26
- export interface MountOptions {
27
- /** Where the surface lives now. */
28
- canonical: string;
29
- /** Where it used to live, when it has moved. */
30
- legacy?: string;
31
- /** For the boot log — "Cron", "Logs". */
32
- surface: string;
33
- }
34
26
  /**
35
- * Mount `router` at its canonical path, and at its legacy path when it has one.
27
+ * `router`, served again at a path it has moved from.
36
28
  *
37
- * The same router instance serves both, so the two paths cannot drift: there is
38
- * one set of handlers and one gate, and an alias that forgot to apply the admin
39
- * gate is not a state this can reach.
29
+ * Mount the result at the old path, beside `router` at its canonical one. The
30
+ * same router instance serves both, so the two paths cannot drift: there is one
31
+ * set of handlers and one gate, and an alias that forgot to apply the admin gate
32
+ * is not a state this can reach.
40
33
  */
41
- export declare function mountWithLegacyAlias(app: Hono<HonoEnv>, router: Hono<HonoEnv>, options: MountOptions): void;
34
+ export declare function deprecatedAlias(router: Hono<HonoEnv>, canonical: string): Hono<HonoEnv>;
@@ -28,3 +28,20 @@ export interface OpenApiGeneratorOptions {
28
28
  };
29
29
  }
30
30
  export declare function generateOpenApiSpec(collections: CollectionConfig[], options?: OpenApiGeneratorOptions): Record<string, unknown>;
31
+ /**
32
+ * Build the component schema for a collection (output / read shape).
33
+ *
34
+ * Every declared property except the ones {@link isDocumentedProperty} rules
35
+ * out, plus the foreign keys and relations {@link emitRelationProperties} adds.
36
+ */
37
+ export declare function buildCollectionSchema(collection: CollectionConfig, registeredSchemas: ReadonlySet<string>): Record<string, unknown>;
38
+ /**
39
+ * Build an input schema (for POST/PUT) — excludes auto-generated fields.
40
+ *
41
+ * `excludeFromApi` columns are left out too, and the server now agrees: a write
42
+ * naming one is refused (`write-validation.ts`), which is what the flag's name
43
+ * and the generated SDK's own documentation always said. This comment used to
44
+ * record that such a write was "still accepted" — the document was right and
45
+ * the server was the thing that had not caught up.
46
+ */
47
+ export declare function buildCollectionInputSchema(collection: CollectionConfig): Record<string, unknown>;
@@ -1,7 +1,32 @@
1
1
  import { Hono } from "hono";
2
2
  import { AuthAdapter, DataDriver, CollectionConfig } from "@rebasepro/types";
3
- import { HonoEnv } from "../types.js";
3
+ import { QueryOptions, HonoEnv } from "../types.js";
4
4
  import { type ListLimitOptions } from "./query-parser.js";
5
+ /**
6
+ * The row a single-row write addresses, as its route found it.
7
+ *
8
+ * `/comments/7` and `/posts/1/comments/7` address the same kind of row — a row
9
+ * of `comments` — two ways, and a write to it is one operation whichever way
10
+ * it arrived: the same body checks, the same `If-Match`, the same
11
+ * `Idempotency-Key`, the same answer. It was two pipelines, and the nested one
12
+ * re-listed two of the root's checks by hand and skipped the rest.
13
+ */
14
+ export interface RowAddress {
15
+ /** The collection the row belongs to: what a body is checked against and an `ETag` computed for. */
16
+ collection: CollectionConfig;
17
+ /**
18
+ * The path the driver reads and writes at: the collection's own, or a
19
+ * nested one, which the driver resolves and scopes to its parent row.
20
+ */
21
+ path: string;
22
+ /**
23
+ * Handed to the driver beside `path`. Unset for a nested path, whose
24
+ * collection the driver resolves from the path itself.
25
+ */
26
+ driverCollection?: CollectionConfig;
27
+ /** What a 404 calls the address. */
28
+ name: string;
29
+ }
5
30
  /**
6
31
  * Lightweight REST API generator that leverages existing Rebase DataDriver.
7
32
  * Supports `include` query parameter for eager-loading relations via Drizzle.
@@ -113,13 +138,16 @@ export declare class RestApiGenerator {
113
138
  */
114
139
  private createUnmatchedRoute;
115
140
  /**
116
- * Check API key permissions for a collection operation.
117
- * Throws 403 if the key doesn't have the required permission.
118
- * No-ops if the request is not authenticated via an API key.
141
+ * Check a narrowed credential's data scope for a collection operation:
142
+ * `data:<operation>` on the collection, or unqualified.
143
+ *
144
+ * Throws 403 when it is missing. A person's own session holds the whole
145
+ * data plane — their rows are RLS's to decide — so this only ever refuses
146
+ * an API key or a token.
119
147
  */
120
148
  private enforceApiKeyPermission;
121
149
  /**
122
- * API key permission check for nested paths.
150
+ * Data-scope check for nested paths.
123
151
  *
124
152
  * The operation lands on the collection the path addresses — the target
125
153
  * of its last relation — so that is the collection the key must hold the
@@ -237,7 +265,9 @@ export declare class RestApiGenerator {
237
265
  *
238
266
  * `respond` is applied to the *stored* result rather than the stored result
239
267
  * being a response, so a replay honours the `Prefer` header of the request
240
- * replaying it rather than the one that first answered.
268
+ * replaying it rather than the one that first answered. `replayed` says
269
+ * the result is the stored one, so a route can restore what it put in a
270
+ * header rather than the body (the `PATCH`'s `ETag`).
241
271
  */
242
272
  private runIdempotent;
243
273
  /**
@@ -260,7 +290,7 @@ export declare class RestApiGenerator {
260
290
  * and a tag compared against a read that hides it compares against
261
291
  * nothing.
262
292
  */
263
- private rowForETag;
293
+ static rowForETag(driver: DataDriver, address: RowAddress, id: string, alreadyRead: Record<string, unknown> | undefined, withDeleted?: QueryOptions["withDeleted"]): Promise<Record<string, unknown> | undefined>;
264
294
  /**
265
295
  * `GET /:id`, at a row's own address or through a parent: the row as the
266
296
  * query asked for it, and the `ETag` naming its version.
@@ -272,7 +302,10 @@ export declare class RestApiGenerator {
272
302
  * relation was a 412. A narrowed read therefore takes its tag from
273
303
  * {@link rowForETag}, the read the write routes make.
274
304
  */
275
- private readRow;
305
+ static readRow(driver: DataDriver, address: RowAddress, id: string, queryOptions: QueryOptions): Promise<{
306
+ row: Record<string, unknown>;
307
+ etag: string | undefined;
308
+ } | undefined>;
276
309
  /**
277
310
  * Answer a bulk write, honouring `Prefer: return=minimal`.
278
311
  *
@@ -299,11 +332,61 @@ export declare class RestApiGenerator {
299
332
  * through a parent. Errors are not re-classified; see {@link createRow}.
300
333
  */
301
334
  private updateRow;
335
+ /**
336
+ * The 404 and the `If-Match` of an update or a delete, as a precondition
337
+ * the driver runs inside the write — or, for a driver that cannot, and for
338
+ * the auth collection, the same judgement made here on a read first.
339
+ *
340
+ * Inside the write is the point. The route used to read the row in a
341
+ * transaction of its own, through the admin's view-model walk, before
342
+ * writing it: every declared relation of the row was loaded — all 200,000
343
+ * comments of a post, for a PATCH of its title — and thrown away, and the
344
+ * write's own read of the row then repeated the lookup. And two writes
345
+ * carrying the same tag could both pass: each compared before either had
346
+ * written. Judged on the write's own read, after the row is locked when a
347
+ * tag is sent, the second one reads what the first wrote and is a 412.
348
+ *
349
+ * The auth collection is still read here first, without relations: the
350
+ * adapter's steps run before the write (`prepareUserUpdates`, and a
351
+ * deletion's `beforeUserDelete` veto, a hook of the application's), and an
352
+ * unknown uid must be the 404 before them, as it always was.
353
+ *
354
+ * @returns The precondition to hand the driver, or `undefined` for a driver
355
+ * that does not run one (the row was judged here).
356
+ */
357
+ private storedRowPrecondition;
302
358
  /**
303
359
  * Delete one row: `DELETE /<collection>/<id>`, and the same row reached
304
360
  * through a parent.
305
361
  */
306
362
  private deleteRow;
363
+ /**
364
+ * A listing — `GET /<collection>` and `POST /<collection>/query`, and the
365
+ * same two through a parent — from the parameters as the `GET` reads them
366
+ * off its URL.
367
+ *
368
+ * One method for both verbs is the whole contract of the POST route: the
369
+ * same parser, the same field-access refusals, the same page, count,
370
+ * cursor and include, the same errors. The caller has already checked the
371
+ * credential's scope for `collection`.
372
+ *
373
+ * @param collectionPath a nested listing's `parent/:id/child` path; unset
374
+ * for the collection's own.
375
+ */
376
+ private listRows;
377
+ /**
378
+ * A collection's count, from the query parameters in `queryDict`: the
379
+ * URL's for `GET …/count`, a body's for `POST …/count`. One method for
380
+ * both, as {@link listRows} is for the listing — the same parser, the same
381
+ * field-access refusals, the same count. The caller has already checked
382
+ * the credential's scope for `collection`.
383
+ *
384
+ * @param collectionPath a nested count's `parent/:id/child` path; unset
385
+ * for the collection's own.
386
+ */
387
+ private countRows;
388
+ /** A `POST …/query` or `POST …/count` body, as the dictionary {@link listRows} and {@link countRows} read. See `query-body.ts`. */
389
+ private queryDictFromRequest;
307
390
  /**
308
391
  * Create REST routes for a collection using existing Rebase patterns
309
392
  */
@@ -344,13 +427,16 @@ export declare class RestApiGenerator {
344
427
  * @param collectionPath the path to read — a nested listing passes its own
345
428
  * `parent/:id/child` path, which the driver resolves.
346
429
  */
347
- private readPage;
430
+ static readPage(driver: DataDriver, collection: CollectionConfig, queryOptions: QueryOptions, searchString?: string, searchExplain?: boolean, collectionPath?: string): Promise<{
431
+ rows: Record<string, unknown>[];
432
+ meta: Record<string, unknown>;
433
+ }>;
348
434
  /**
349
435
  * Fetch raw collection data without Entity wrapper (fallback for non-Postgres)
350
436
  */
351
- private fetchRawCollection;
437
+ static fetchRawCollection(driver: DataDriver, collection: CollectionConfig, queryOptions: QueryOptions, searchString?: string, searchExplain?: boolean, collectionPath?: string, startAfter?: Record<string, unknown>): Promise<Record<string, unknown>[]>;
352
438
  /**
353
439
  * Count raw entities for a collection
354
440
  */
355
- private countRawEntities;
441
+ static countRawEntities(driver: DataDriver, collection: CollectionConfig, queryOptions: QueryOptions, searchString?: string, collectionPath?: string): Promise<number>;
356
442
  }
@@ -1,19 +1,3 @@
1
- /**
2
- * A write to the auth collection is user administration.
3
- *
4
- * The auth collection's rows are the users. `/admin/users` holds a change to
5
- * one to the auth adapter's rules: a create goes through the adapter's user
6
- * creation (the password hashed, the email normalized, the collection's
7
- * `onCreateUser`, the invitation), an update may not leave the project without
8
- * an administrator and stores an email the way sign-in looks it up, and a
9
- * deletion runs `beforeUserDelete` (a veto), ends the sessions and runs
10
- * `afterUserDelete`. The data doors that write the same rows — the REST routes
11
- * and MCP's write tools — call these, so that no door writes a user by rules
12
- * of its own. (The Postgres socket calls the adapter's methods directly.)
13
- *
14
- * Every function here leaves any other collection, and an adapter without the
15
- * step, exactly as it was: the rows are then written as any table's.
16
- */
17
1
  import type { AuthAdapter, CollectionConfig, UserCreationFinalizeResult, UserCreationPrepareResult } from "@rebasepro/types";
18
2
  import type { FieldViewer } from "@rebasepro/common";
19
3
  /** Whether `collection` is the auth collection — its rows are the users. */
@@ -26,6 +10,21 @@ export type UserCreatingAdapter = AuthAdapter & Required<Pick<AuthAdapter, "prep
26
10
  * the door writes the row as any other.
27
11
  */
28
12
  export declare function createsUsers(adapter: AuthAdapter | undefined, collection: CollectionConfig): adapter is UserCreatingAdapter;
13
+ /**
14
+ * Refuse an upsert on the auth collection.
15
+ *
16
+ * An upsert is a create or an update, decided inside the write by whether the
17
+ * row is already there, and on the auth collection the two follow different
18
+ * rules: a create sets the password and sends the invitation
19
+ * ({@link createUserThroughAuthCollection}), an update may not demote the last
20
+ * administrator and normalizes the email ({@link prepareAuthCollectionUpdates}).
21
+ * Neither can be applied before the branch is known, so an upsert took
22
+ * neither — `{ id: <the last admin>, roles: ["viewer"] }` demoted them.
23
+ *
24
+ * Only where the adapter administers users; with no such step there is no
25
+ * rule for an upsert to miss. `where` prefixes the message (`Operation 3`).
26
+ */
27
+ export declare function assertNoUserUpsert(adapter: AuthAdapter | undefined, collection: CollectionConfig, where?: string): void;
29
28
  /**
30
29
  * Check a create body for the auth collection against what the adapter says a
31
30
  * create consumes (`describeUserCreationContract`).
@@ -43,8 +42,16 @@ export declare function assertUserCreationBodyValid(adapter: AuthAdapter | undef
43
42
  * through the adapter's `prepareUserCreation` (the password hashed or
44
43
  * generated, the email normalized, the collection's `onCreateUser`), in order.
45
44
  * The `values` of each result are what the door writes.
45
+ *
46
+ * `caller` is who the door is writing for: an administrator may waive the
47
+ * password policy for an import (`skipPasswordPolicy: true`), anyone else may
48
+ * not.
49
+ *
50
+ * `nameRows` is set by a bulk door: a refusal of one body (a `WEAK_PASSWORD`,
51
+ * a hook's 4xx) is then prefixed `Row <index>: `, as the bulk's other row
52
+ * errors are, so an import can say which line of its file failed.
46
53
  */
47
- export declare function prepareUserCreations(adapter: UserCreatingAdapter, collection: CollectionConfig, bodies: readonly Record<string, unknown>[]): Promise<UserCreationPrepareResult[]>;
54
+ export declare function prepareUserCreations(adapter: UserCreatingAdapter, collection: CollectionConfig, bodies: readonly Record<string, unknown>[], caller: FieldViewer, nameRows?: boolean): Promise<UserCreationPrepareResult[]>;
48
55
  /**
49
56
  * The second half, once the rows are written — and only then, so a write that
50
57
  * fails invites nobody: the credentials' delivery through
@@ -55,14 +62,14 @@ export declare function prepareUserCreations(adapter: UserCreatingAdapter, colle
55
62
  */
56
63
  export declare function completeUserCreations(adapter: UserCreatingAdapter, prepared: readonly UserCreationPrepareResult[], rows: readonly Record<string, unknown>[]): Promise<UserCreationFinalizeResult[]>;
57
64
  /**
58
- * Create one user through the auth collection: {@link prepareUserCreations},
59
- * then `save` (the door's own driver write), then
60
- * {@link completeUserCreations}.
65
+ * Create one user through the auth collection, for `caller`:
66
+ * {@link prepareUserCreations}, then `save` (the door's own driver write),
67
+ * then {@link completeUserCreations}.
61
68
  *
62
69
  * `undefined` when the create is not a user creation ({@link createsUsers}) —
63
70
  * the door then writes the row as any other.
64
71
  */
65
- export declare function createUserThroughAuthCollection(adapter: AuthAdapter | undefined, collection: CollectionConfig, body: Record<string, unknown>, save: (values: Record<string, unknown>) => Promise<Record<string, unknown>>): Promise<{
72
+ export declare function createUserThroughAuthCollection(adapter: AuthAdapter | undefined, collection: CollectionConfig, body: Record<string, unknown>, caller: FieldViewer, save: (values: Record<string, unknown>) => Promise<Record<string, unknown>>): Promise<{
66
73
  row: Record<string, unknown>;
67
74
  delivery: UserCreationFinalizeResult;
68
75
  } | undefined>;
@@ -1,5 +1,5 @@
1
1
  import type { CollectionConfig, IncludeSpec } from "@rebasepro/types";
2
- import type { LogicalCondition } from "@rebasepro/types";
2
+ import { type LogicalCondition } from "@rebasepro/types";
3
3
  import { type FieldViewer } from "@rebasepro/common";
4
4
  /**
5
5
  * A read may not name a field the caller cannot read.
@@ -10,13 +10,22 @@ import { type FieldViewer } from "@rebasepro/common";
10
10
  * `?orderBy=salary` returns them in order of it. A column no response can carry
11
11
  * has to be a column no query can interrogate, or the read rule is decoration.
12
12
  *
13
- * The refusal names the field. That is deliberate and it is not a leak: the
14
- * published OpenAPI lists every property of every collection, including the ones
15
- * a given caller cannot read, because the document is one document and is served
16
- * off the app rather than off the authenticated data router. Hiding the name
17
- * here would protect nothing and would answer a caller's genuine typo with
18
- * "unknown field", sending them to look for a spelling mistake that is not
19
- * there. Field *names* are public; field *values* are not.
13
+ * The refusal names a field restricted by role. That is deliberate and it is
14
+ * not a leak: the published OpenAPI lists every property of every collection,
15
+ * including the ones a given caller cannot read, because the document is one
16
+ * document and is served off the app rather than off the authenticated data
17
+ * router. Hiding the name here would protect nothing and would answer a
18
+ * caller's genuine typo with "unknown field", sending them to look for a
19
+ * spelling mistake that is not there. Those field *names* are public; their
20
+ * *values* are not.
21
+ *
22
+ * An `excludeFromApi` field is the exception, because its name is *not*
23
+ * public: OpenAPI, `list_collections` and the generated SDK all leave it out.
24
+ * "`email` is not readable on `authors`" would confirm the one thing those hide,
25
+ * so a filter, sort, projection, include, aggregate or vector search naming one
26
+ * is answered as one naming a field that does not exist — built by the functions the driver answers a
27
+ * typo with (`@rebasepro/common`'s `unknown-field`), so the two answers are the
28
+ * same bytes. See {@link assertNoHiddenNames}.
20
29
  *
21
30
  * @module
22
31
  */
@@ -67,4 +76,15 @@ export declare function assertQueryFieldsReadable(options: {
67
76
  property: string;
68
77
  };
69
78
  }, collection: CollectionConfig, viewer: FieldViewer | undefined): void;
79
+ /**
80
+ * The aggregate route's `select` and `groupBy`, which it parses itself: an
81
+ * `excludeFromApi` name there is answered exactly as the driver answers a
82
+ * column that does not exist. Walked in the driver's order — each aggregate's
83
+ * field, then each group key — and the first hidden *or* unknown name gets the
84
+ * answer, so a typo before a hidden name is still the one named.
85
+ */
86
+ export declare function assertNoHiddenAggregateNames(aggregates: readonly {
87
+ fn: string;
88
+ field?: string;
89
+ }[], groupBy: readonly string[], collection: CollectionConfig): void;
70
90
  export {};