@rebasepro/server 0.17.3 → 0.18.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 (147) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +5 -1
  3. package/bin/rebase-server.js +16 -1
  4. package/dist/{GCSStorageController-Bl7nmhdv.js → GCSStorageController-ZXPoNqW3.js} +21 -10
  5. package/dist/GCSStorageController-ZXPoNqW3.js.map +1 -0
  6. package/dist/{S3StorageController-CWvvrRpF.js → S3StorageController-5pAXyv31.js} +24 -10
  7. package/dist/S3StorageController-5pAXyv31.js.map +1 -0
  8. package/dist/admin-roles-vYdp_Pil.js +36 -0
  9. package/dist/admin-roles-vYdp_Pil.js.map +1 -0
  10. package/dist/{admin_block-BX6YULvJ.js → admin_block-0Xu0r6eZ.js} +4 -1
  11. package/dist/admin_block-0Xu0r6eZ.js.map +1 -0
  12. package/dist/api/errors.d.ts +37 -0
  13. package/dist/api/live-schema-routes.d.ts +14 -0
  14. package/dist/api/logs-routes.d.ts +8 -0
  15. package/dist/api/rest/api-generator.d.ts +33 -0
  16. package/dist/api/root-error-handler.d.ts +62 -0
  17. package/dist/api/schema-drift.d.ts +39 -0
  18. package/dist/api/types.d.ts +55 -0
  19. package/dist/{ast-schema-editor-CvkYOvri.js → ast-schema-editor-CNgFJ3NF.js} +23 -7
  20. package/dist/ast-schema-editor-CNgFJ3NF.js.map +1 -0
  21. package/dist/auth/api-keys/api-key-routes.d.ts +12 -0
  22. package/dist/auth/auth-hooks.d.ts +13 -2
  23. package/dist/auth/exclude-auth-secrets.d.ts +14 -0
  24. package/dist/auth/jwt.d.ts +22 -1
  25. package/dist/auth/mfa-routes.d.ts +10 -1
  26. package/dist/auth/middleware.d.ts +22 -0
  27. package/dist/auth/rate-limiter.d.ts +50 -0
  28. package/dist/auth/registration-policy.d.ts +27 -0
  29. package/dist/auth/rls-scope.d.ts +9 -1
  30. package/dist/auth/routes.d.ts +8 -1
  31. package/dist/auth/seed-admin.d.ts +73 -0
  32. package/dist/auth/session-routes.d.ts +10 -0
  33. package/dist/{auth-DkbzMZUS.js → auth-BRiOuyq8.js} +283 -198
  34. package/dist/auth-BRiOuyq8.js.map +1 -0
  35. package/dist/{backup-CRdZkA6c.js → backup-C8P6Cl3G.js} +2 -2
  36. package/dist/{backup-CRdZkA6c.js.map → backup-C8P6Cl3G.js.map} +1 -1
  37. package/dist/boot/boot.d.ts +18 -0
  38. package/dist/boot/bundle.d.ts +29 -6
  39. package/dist/boot/ddl-bootstrap.d.ts +2 -0
  40. package/dist/boot/env.d.ts +30 -1
  41. package/dist/boot/fetch-bundle.d.ts +24 -1
  42. package/dist/boot/options.d.ts +0 -8
  43. package/dist/boot/provision.d.ts +58 -18
  44. package/dist/boot/resource-adapters.d.ts +11 -1
  45. package/dist/boot/resource-resolvers.d.ts +96 -0
  46. package/dist/boot/sources.d.ts +27 -20
  47. package/dist/collections/validate-config.d.ts +29 -0
  48. package/dist/{contract-routes-CHPVKTZW.js → contract-routes-CusnEB5h.js} +24 -9
  49. package/dist/{contract-routes-CHPVKTZW.js.map → contract-routes-CusnEB5h.js.map} +1 -1
  50. package/dist/cron/cron-loader.d.ts +7 -1
  51. package/dist/cron/cron-scheduler.d.ts +48 -2
  52. package/dist/{cron-loader-d9WMFENB.js → cron-loader-DnmIePn_.js} +23 -4
  53. package/dist/cron-loader-DnmIePn_.js.map +1 -0
  54. package/dist/{cron-routes-DSC-kZXI.js → cron-routes-D3x2ydMa.js} +9 -6
  55. package/dist/cron-routes-D3x2ydMa.js.map +1 -0
  56. package/dist/{cron-scheduler-BB82dWuU.js → cron-scheduler-BpPKpl4i.js} +148 -28
  57. package/dist/cron-scheduler-BpPKpl4i.js.map +1 -0
  58. package/dist/{cron-store-KeN8rN63.js → cron-store-CCQXwgVL.js} +5 -5
  59. package/dist/{cron-store-KeN8rN63.js.map → cron-store-CCQXwgVL.js.map} +1 -1
  60. package/dist/{ddl-bootstrap-5YZCZ8qk.js → ddl-bootstrap-CfNvxMuK.js} +26 -2
  61. package/dist/{ddl-bootstrap-5YZCZ8qk.js.map → ddl-bootstrap-CfNvxMuK.js.map} +1 -1
  62. package/dist/email/index.d.ts +1 -0
  63. package/dist/email/unconfigured.d.ts +20 -0
  64. package/dist/env.d.ts +25 -0
  65. package/dist/errors-HjfaPlvY.js +385 -0
  66. package/dist/errors-HjfaPlvY.js.map +1 -0
  67. package/dist/{function-loader-LLdmBFoL.js → function-loader-xnbDAPfa.js} +9 -3
  68. package/dist/{function-loader-LLdmBFoL.js.map → function-loader-xnbDAPfa.js.map} +1 -1
  69. package/dist/function-routes-gQ0EShVG.js +267 -0
  70. package/dist/function-routes-gQ0EShVG.js.map +1 -0
  71. package/dist/functions/define-function.d.ts +6 -3
  72. package/dist/functions/function-routes.d.ts +8 -4
  73. package/dist/functions/index.js +128 -23
  74. package/dist/functions/index.js.map +1 -1
  75. package/dist/{history-recorder-B2pL3X8b.js → history-recorder-B1FwXx9J.js} +3 -3
  76. package/dist/{history-recorder-B2pL3X8b.js.map → history-recorder-B1FwXx9J.js.map} +1 -1
  77. package/dist/{history-store-BUJ-37Sm.js → history-store-LHXaQywp.js} +2 -2
  78. package/dist/{history-store-BUJ-37Sm.js.map → history-store-LHXaQywp.js.map} +1 -1
  79. package/dist/index.d.ts +16 -4
  80. package/dist/index.es.js +16229 -7676
  81. package/dist/index.es.js.map +1 -1
  82. package/dist/init.d.ts +33 -13
  83. package/dist/{jobs-XXXcZrmj.js → jobs-DkkD9mPV.js} +5 -5
  84. package/dist/{jobs-XXXcZrmj.js.map → jobs-DkkD9mPV.js.map} +1 -1
  85. package/dist/{jwt-DNeOn39r.js → jwt-DkhXwMzR.js} +9 -314
  86. package/dist/jwt-DkhXwMzR.js.map +1 -0
  87. package/dist/keys-g8lbVC_o.js +230 -0
  88. package/dist/keys-g8lbVC_o.js.map +1 -0
  89. package/dist/{logger-DS03e908.js → logger-DO2PZc4i.js} +197 -18
  90. package/dist/logger-DO2PZc4i.js.map +1 -0
  91. package/dist/{logs-routes-DB72iQSr.js → logs-routes-CbsTpozn.js} +74 -6
  92. package/dist/logs-routes-CbsTpozn.js.map +1 -0
  93. package/dist/{openapi-generator-CpZp2Fai.js → openapi-generator-BIBbO1Tq.js} +221 -38
  94. package/dist/openapi-generator-BIBbO1Tq.js.map +1 -0
  95. package/dist/{proxy-CMymhnwG.js → proxy-Czngl3p9.js} +2 -2
  96. package/dist/{proxy-CMymhnwG.js.map → proxy-Czngl3p9.js.map} +1 -1
  97. package/dist/{query-parser-DqXNaBIH.js → query-parser-C68Q9EX4.js} +35 -6
  98. package/dist/{query-parser-DqXNaBIH.js.map → query-parser-C68Q9EX4.js.map} +1 -1
  99. package/dist/queues/runtime.d.ts +56 -0
  100. package/dist/{request-timeout-C8gkc-j7.js → request-timeout-DESvlfrS.js} +4 -6
  101. package/dist/request-timeout-DESvlfrS.js.map +1 -0
  102. package/dist/schema-edit/project-root.d.ts +4 -4
  103. package/dist/{schema-editor-routes-DNV_nBhW.js → schema-editor-routes-CcZKh50q.js} +4 -4
  104. package/dist/{schema-editor-routes-DNV_nBhW.js.map → schema-editor-routes-CcZKh50q.js.map} +1 -1
  105. package/dist/{schemas-DBxgjM9A.js → schemas-C3234HWE.js} +2746 -72
  106. package/dist/schemas-C3234HWE.js.map +1 -0
  107. package/dist/singleton.d.ts +6 -4
  108. package/dist/src-DHK4fHkw.js +1002 -0
  109. package/dist/src-DHK4fHkw.js.map +1 -0
  110. package/dist/{src-C9gKj23J.js → src-Dq-I3Ybx.js} +507 -54
  111. package/dist/src-Dq-I3Ybx.js.map +1 -0
  112. package/dist/storage/GCSStorageController.d.ts +5 -0
  113. package/dist/storage/LocalStorageController.d.ts +14 -0
  114. package/dist/storage/S3StorageController.d.ts +8 -0
  115. package/dist/storage/image-transform.d.ts +35 -0
  116. package/dist/storage/keys.d.ts +23 -0
  117. package/dist/storage/policies.d.ts +22 -0
  118. package/dist/storage/routes.d.ts +9 -0
  119. package/dist/storage/tus-handler.d.ts +43 -1
  120. package/dist/storage/types.d.ts +28 -0
  121. package/dist/types-BfKcm9do.js.map +1 -1
  122. package/dist/utils/dev-port.d.ts +18 -0
  123. package/dist/utils/logger.d.ts +60 -0
  124. package/dist/utils/request-logger.d.ts +2 -1
  125. package/package.json +30 -24
  126. package/dist/GCSStorageController-Bl7nmhdv.js.map +0 -1
  127. package/dist/S3StorageController-CWvvrRpF.js.map +0 -1
  128. package/dist/admin_block-BX6YULvJ.js.map +0 -1
  129. package/dist/ast-schema-editor-CvkYOvri.js.map +0 -1
  130. package/dist/auth-DkbzMZUS.js.map +0 -1
  131. package/dist/cron-loader-d9WMFENB.js.map +0 -1
  132. package/dist/cron-routes-DSC-kZXI.js.map +0 -1
  133. package/dist/cron-scheduler-BB82dWuU.js.map +0 -1
  134. package/dist/errors-DBwpj9N8.js +0 -231
  135. package/dist/errors-DBwpj9N8.js.map +0 -1
  136. package/dist/function-routes-ClT6UQpD.js +0 -41
  137. package/dist/function-routes-ClT6UQpD.js.map +0 -1
  138. package/dist/jwt-DNeOn39r.js.map +0 -1
  139. package/dist/logger-DS03e908.js.map +0 -1
  140. package/dist/logs-routes-DB72iQSr.js.map +0 -1
  141. package/dist/openapi-generator-CpZp2Fai.js.map +0 -1
  142. package/dist/request-timeout-C8gkc-j7.js.map +0 -1
  143. package/dist/schemas-DBxgjM9A.js.map +0 -1
  144. package/dist/src-C9gKj23J.js.map +0 -1
  145. package/dist/src-CcOl05Oq.js +0 -552
  146. package/dist/src-CcOl05Oq.js.map +0 -1
  147. package/dist/utils/logging.d.ts +0 -5
@@ -0,0 +1,1002 @@
1
+ import { createRequire as __rebaseCreateRequire } from "module";
2
+ import __rebaseProcess from "process";
3
+ globalThis.process ??= __rebaseProcess;
4
+ __rebaseCreateRequire(import.meta.url);
5
+ //#region ../types/src/types/filter-operators.ts
6
+ /** The wire spelling of a {@link RelationAggregateSort}: `min(applications.created_at)`. */
7
+ var RELATION_AGGREGATE_SORT_PATTERN = /^(min|max|count|sum|avg)\(([^().]+)(?:\.([^()]+))?\)$/;
8
+ /**
9
+ * A {@link RelationAggregateSort} as a single string — `min(applications.created_at)`,
10
+ * `count(applications)`.
11
+ *
12
+ * The wire form is a string because every layer below the call site already is
13
+ * one: `OrderByTuple` is `[string, direction]`, the REST parameter is
14
+ * `?orderBy=key:direction`, the driver contract takes `orderBy?: string |
15
+ * OrderByTuple[]`, and a cursor names its keys by string. `_score` established
16
+ * the same pattern — a sort key that is not a column, spelled as one — and this
17
+ * reuses it rather than widening five signatures to carry an object that would
18
+ * be flattened at the end anyway.
19
+ *
20
+ * SQL's own spelling, so the key reads as what it compiles to. Neither `:` nor
21
+ * `,` appears in it, which is what keeps it safe in the colon-delimited wire
22
+ * shorthand.
23
+ *
24
+ * @group Models
25
+ */
26
+ function encodeRelationAggregateSort(sort) {
27
+ return `${sort.agg}(${sort.relation}${sort.field ? `.${sort.field}` : ""})`;
28
+ }
29
+ /**
30
+ * Read the string spelling back, or `undefined` if it is not one.
31
+ *
32
+ * `undefined` rather than a throw: this is asked of *every* sort key to find
33
+ * out which kind it is, and an ordinary column name is not an error.
34
+ *
35
+ * @group Models
36
+ */
37
+ function parseRelationAggregateSort(key) {
38
+ const match = RELATION_AGGREGATE_SORT_PATTERN.exec(key);
39
+ if (!match) return void 0;
40
+ const [, agg, relation, field] = match;
41
+ if (!field && agg !== "count") return void 0;
42
+ return {
43
+ agg,
44
+ relation,
45
+ ...field && { field }
46
+ };
47
+ }
48
+ /** Is this sort key the object form rather than a field name? */
49
+ function isRelationAggregateSort(key) {
50
+ return typeof key === "object" && key !== null && typeof key.relation === "string" && typeof key.agg === "string";
51
+ }
52
+ /** A sort key in the single-string form every layer below the call site speaks. */
53
+ function sortKeyToString(key) {
54
+ return isRelationAggregateSort(key) ? encodeRelationAggregateSort(key) : key;
55
+ }
56
+ /** Maps canonical operators to their REST short-code equivalents. */
57
+ var CANONICAL_TO_REST = {
58
+ "==": "eq",
59
+ "!=": "neq",
60
+ ">": "gt",
61
+ ">=": "gte",
62
+ "<": "lt",
63
+ "<=": "lte",
64
+ "in": "in",
65
+ "not-in": "nin",
66
+ "array-contains": "cs",
67
+ "array-contains-any": "csa",
68
+ "like": "like",
69
+ "ilike": "ilike",
70
+ "not-like": "nlike",
71
+ "not-ilike": "nilike",
72
+ "is-null": "isnull",
73
+ "is-not-null": "notnull"
74
+ };
75
+ /** Maps REST short-code operators to their canonical equivalents. */
76
+ var REST_TO_CANONICAL = {
77
+ "eq": "==",
78
+ "neq": "!=",
79
+ "gt": ">",
80
+ "gte": ">=",
81
+ "lt": "<",
82
+ "lte": "<=",
83
+ "in": "in",
84
+ "nin": "not-in",
85
+ "cs": "array-contains",
86
+ "csa": "array-contains-any",
87
+ "like": "like",
88
+ "ilike": "ilike",
89
+ "nlike": "not-like",
90
+ "nilike": "not-ilike",
91
+ "isnull": "is-null",
92
+ "notnull": "is-not-null"
93
+ };
94
+ /**
95
+ * Operators that test for null/not-null and therefore ignore their value.
96
+ * Codecs normalize the value of these conditions to `null`.
97
+ */
98
+ var NULL_OPS = /* @__PURE__ */ new Set(["is-null", "is-not-null"]);
99
+ /**
100
+ * Every canonical operator, in a stable order. Useful for engine capability
101
+ * declarations ({@link DataSourceCapabilities.filterOperators}) and for
102
+ * building operator subsets.
103
+ * @group Models
104
+ */
105
+ var ALL_WHERE_FILTER_OPS = [
106
+ "<",
107
+ "<=",
108
+ "==",
109
+ "!=",
110
+ ">=",
111
+ ">",
112
+ "in",
113
+ "not-in",
114
+ "array-contains",
115
+ "array-contains-any",
116
+ "like",
117
+ "ilike",
118
+ "not-like",
119
+ "not-ilike",
120
+ "is-null",
121
+ "is-not-null"
122
+ ];
123
+ /** All canonical operator strings for runtime validation. */
124
+ var CANONICAL_OPS = new Set(ALL_WHERE_FILTER_OPS);
125
+ /**
126
+ * The REST table as a `Map`, because the key `toCanonicalOp` is handed comes
127
+ * off the wire.
128
+ *
129
+ * Indexed as a plain object, every `Object.prototype` member answered:
130
+ * `toCanonicalOp("valueOf")` returned the inherited *function* as though it
131
+ * were a `WhereFilterOp`, and every caller here treats a defined result as
132
+ * "known operator". Same defect the REST codec's own lookup tables were
133
+ * converted away from in `filter-dialect.ts`; this is the copy that survived
134
+ * one package over, and it now sits under the operator validation the REST
135
+ * parser does, which would otherwise have admitted `["constructor", x]`.
136
+ */
137
+ var REST_OP_LOOKUP = new Map(Object.entries(REST_TO_CANONICAL));
138
+ /**
139
+ * Resolve any operator string (canonical or REST short-code) to its
140
+ * canonical `WhereFilterOp` form. Returns `undefined` for unknown operators.
141
+ *
142
+ * @example
143
+ * toCanonicalOp("==") // "=="
144
+ * toCanonicalOp("eq") // "=="
145
+ * toCanonicalOp("cs") // "array-contains"
146
+ * toCanonicalOp("xyz") // undefined
147
+ */
148
+ function toCanonicalOp(op) {
149
+ if (CANONICAL_OPS.has(op)) return op;
150
+ return REST_OP_LOOKUP.get(op);
151
+ }
152
+ //#endregion
153
+ //#region ../types/src/types/data_source.ts
154
+ /**
155
+ * The default data-source key, used when a collection does not name a
156
+ * `dataSource`. Shared by the frontend router and the backend driver
157
+ * registry so both agree on "the default database".
158
+ * @group Models
159
+ */
160
+ var DEFAULT_DATA_SOURCE_KEY = "(default)";
161
+ /**
162
+ * Relation kinds assumed filterable when a driver does not say.
163
+ *
164
+ * `belongsTo` alone: its filter is a comparison on a column of the row being
165
+ * filtered, the one shape that needs no query construction a driver might not
166
+ * have. Everything else is a correlated subquery over another table.
167
+ *
168
+ * @group Models
169
+ */
170
+ var DEFAULT_FILTERABLE_RELATION_KINDS = ["belongsTo"];
171
+ /** @group Models */
172
+ var POSTGRES_CAPABILITIES = {
173
+ key: "postgres",
174
+ label: "PostgreSQL",
175
+ supportsRelations: true,
176
+ supportsSubcollections: false,
177
+ supportsRLS: true,
178
+ supportsReferences: false,
179
+ supportsColumnTypes: true,
180
+ supportsRealtime: true,
181
+ supportsVectors: true,
182
+ filterOperators: ALL_WHERE_FILTER_OPS,
183
+ filterableRelationKinds: [
184
+ "belongsTo",
185
+ "manyToMany",
186
+ "hasMany",
187
+ "hasOne"
188
+ ],
189
+ supportsRelationFieldFilters: true,
190
+ relationAggregateSorts: true,
191
+ supportsSQLAdmin: true,
192
+ supportsDocumentAdmin: false,
193
+ supportsSchemaAdmin: true
194
+ };
195
+ /** @group Models */
196
+ var FIREBASE_CAPABILITIES = {
197
+ key: "firestore",
198
+ label: "Firebase / Firestore",
199
+ supportsRelations: false,
200
+ supportsSubcollections: true,
201
+ supportsRLS: false,
202
+ supportsReferences: true,
203
+ supportsColumnTypes: false,
204
+ supportsRealtime: true,
205
+ supportsVectors: false,
206
+ filterOperators: ALL_WHERE_FILTER_OPS.filter((op) => op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
207
+ filterableRelationKinds: [],
208
+ supportsRelationFieldFilters: false,
209
+ relationAggregateSorts: false,
210
+ supportsSQLAdmin: false,
211
+ supportsDocumentAdmin: false,
212
+ supportsSchemaAdmin: false
213
+ };
214
+ /** @group Models */
215
+ var MONGODB_CAPABILITIES = {
216
+ key: "mongodb",
217
+ label: "MongoDB",
218
+ supportsRelations: false,
219
+ supportsSubcollections: true,
220
+ supportsRLS: false,
221
+ supportsReferences: true,
222
+ supportsColumnTypes: false,
223
+ supportsRealtime: false,
224
+ supportsVectors: false,
225
+ filterOperators: ALL_WHERE_FILTER_OPS,
226
+ filterableRelationKinds: [],
227
+ supportsRelationFieldFilters: false,
228
+ relationAggregateSorts: false,
229
+ supportsSQLAdmin: false,
230
+ supportsDocumentAdmin: true,
231
+ supportsSchemaAdmin: true
232
+ };
233
+ /**
234
+ * Fallback capabilities when the driver is unknown.
235
+ * Enables everything so nothing is hidden unexpectedly.
236
+ * @group Models
237
+ */
238
+ var DEFAULT_CAPABILITIES = {
239
+ key: "(default)",
240
+ label: "Default",
241
+ supportsRelations: true,
242
+ supportsSubcollections: true,
243
+ supportsRLS: true,
244
+ supportsReferences: true,
245
+ supportsColumnTypes: true,
246
+ supportsRealtime: true,
247
+ supportsVectors: true,
248
+ filterOperators: ALL_WHERE_FILTER_OPS,
249
+ filterableRelationKinds: DEFAULT_FILTERABLE_RELATION_KINDS,
250
+ supportsRelationFieldFilters: false,
251
+ relationAggregateSorts: false,
252
+ supportsSQLAdmin: true,
253
+ supportsDocumentAdmin: true,
254
+ supportsSchemaAdmin: true
255
+ };
256
+ var CAPABILITIES_REGISTRY = {
257
+ postgres: POSTGRES_CAPABILITIES,
258
+ firestore: FIREBASE_CAPABILITIES,
259
+ mongodb: MONGODB_CAPABILITIES,
260
+ "(default)": DEFAULT_CAPABILITIES
261
+ };
262
+ /**
263
+ * Look up capabilities for a given engine key.
264
+ * If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
265
+ * @group Models
266
+ */
267
+ function getDataSourceCapabilities(engine) {
268
+ if (!engine) return POSTGRES_CAPABILITIES;
269
+ return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
270
+ }
271
+ //#endregion
272
+ //#region ../types/src/types/collections.ts
273
+ /**
274
+ * Type guard for PostgreSQL collections.
275
+ * Returns true if the collection uses the Postgres engine (or the default engine).
276
+ *
277
+ * Generic over the *input* type, and narrows by intersection rather than
278
+ * replacement. Narrowing to a bare `PostgresCollectionConfig` discarded whatever
279
+ * the caller actually had — most visibly the admin panel's view model, whose
280
+ * flattened presentation fields vanished the moment a collection passed through
281
+ * one of these guards.
282
+ *
283
+ * @group Models
284
+ */
285
+ function isPostgresCollectionConfig(collection) {
286
+ return !collection.engine || collection.engine === "postgres";
287
+ }
288
+ /**
289
+ * Narrows to the SQL collection fields — `table`, `relations`,
290
+ * `disableDefaultPolicies` — by asking the engine's declared capabilities
291
+ * rather than by naming Postgres.
292
+ *
293
+ * The two halves of this already existed and were never joined. The engine
294
+ * split (`PostgresCollectionConfig` / `FirebaseCollectionConfig` /
295
+ * `MongoDBCollectionConfig`) said which fields belong to which engine at the
296
+ * type level; {@link DataSourceCapabilities} said the same thing at runtime,
297
+ * down to a `supportsRelations` flag. So call sites guarded on the capability
298
+ * and then read a field the base type had to declare for them — which is why
299
+ * those fields were on the base, and why a MongoDB collection could be written
300
+ * with a `table`.
301
+ *
302
+ * Prefer this over {@link isPostgresCollectionConfig} wherever the question is
303
+ * "does this collection live in a SQL table", so a custom SQL engine
304
+ * registered through `registerDataSourceCapabilities` is included.
305
+ *
306
+ * @group Models
307
+ */
308
+ function isRelationalCollectionConfig(collection) {
309
+ return getDataSourceCapabilities(collection.engine).supportsRelations;
310
+ }
311
+ /**
312
+ * Type guard for Firebase / Firestore collections.
313
+ * @group Models
314
+ */
315
+ function isFirebaseCollectionConfig(collection) {
316
+ return collection.engine === "firestore";
317
+ }
318
+ /**
319
+ * Type guard for MongoDB collections.
320
+ * @group Models
321
+ */
322
+ function isMongoDBCollectionConfig(collection) {
323
+ return collection.engine === "mongodb";
324
+ }
325
+ /**
326
+ * Returns the data path for a collection.
327
+ * For Firestore or MongoDB collections with a `path`, returns that value;
328
+ * otherwise falls back to `slug`.
329
+ */
330
+ function getCollectionDataPath(collection) {
331
+ if (isFirebaseCollectionConfig(collection) && collection.path) return collection.path;
332
+ if (isMongoDBCollectionConfig(collection) && collection.path) return collection.path;
333
+ return collection.slug;
334
+ }
335
+ /**
336
+ * Reads a collection's driver-declared subcollections thunk (the `subcollections`
337
+ * field) independent of engine identity, so engine-agnostic code doesn't have to
338
+ * type-guard against a specific driver. Returns `undefined` when the collection
339
+ * declares none.
340
+ *
341
+ * Pair with `getDataSourceCapabilities(engine).supportsSubcollections` to decide
342
+ * whether the engine honours subcollections at all before reading them.
343
+ * @group Models
344
+ */
345
+ function getDeclaredSubcollections(collection) {
346
+ return collection.subcollections;
347
+ }
348
+ //#endregion
349
+ //#region ../types/src/types/rls-functions.ts
350
+ /**
351
+ * The SQL helper functions RLS policies call, and the schema they live in.
352
+ *
353
+ * ## One schema, and it is ours
354
+ *
355
+ * Rebase creates exactly one schema in a project's database: `rebase`. These
356
+ * three functions live in it alongside the framework's own tables, and that is
357
+ * the whole contract — a reader can look at a database and know precisely which
358
+ * namespace belongs to the framework and that nothing else was touched.
359
+ *
360
+ * It used to be two. `uid()`, `jwt()` and `roles()` sat in a schema called
361
+ * `auth`, which is Supabase's name, chosen so that a developer who had written
362
+ * Supabase RLS would recognise `auth.uid()`. The familiarity was real but the
363
+ * name was not Rebase's to take, and taking it had a concrete cost: pointing
364
+ * Rebase at a database that already had a Supabase `auth` schema meant
365
+ * `CREATE OR REPLACE FUNCTION auth.uid() RETURNS text` against Supabase's
366
+ * `RETURNS uuid`, which Postgres rejects outright —
367
+ *
368
+ * ERROR: cannot change return type of existing function
369
+ * HINT: Use DROP FUNCTION auth.uid() first.
370
+ *
371
+ * — and the failure landed inside a catch-all that logged a warning and carried
372
+ * on, leaving a database with auth tables, no helper functions, and policies
373
+ * calling functions that did not exist. Under `rebase db migrate` the same
374
+ * statements aborted the migration instead.
375
+ *
376
+ * `rebase.uid()` collides with nobody. A Supabase database keeps its `auth`
377
+ * schema untouched and gains a `rebase` one, which is what a gradual migration
378
+ * needs.
379
+ *
380
+ * ## Why functions at all, rather than inlining `current_setting`
381
+ *
382
+ * Because the indirection has already been spent once. `uid()` resolves
383
+ * `app.uid` and falls back to the pre-rename `app.user_id`, so that during a
384
+ * rolling deploy — old and new pods serving one database — both eras resolve
385
+ * the principal. That was a single `CREATE OR REPLACE`. Inlined into policy
386
+ * bodies it would have been a rewrite of every policy on every table.
387
+ *
388
+ * ## Why the name is not configurable
389
+ *
390
+ * A policy body is stored SQL: Postgres parses `USING (…)` once and keeps it, so
391
+ * these strings are written into every policy in every database Rebase has
392
+ * provisioned. Everything that reads policies back — the SQL-to-policy parser
393
+ * behind the admin UI, the drift checker, `rls-check` — would have to know the
394
+ * configured value to recognise its own output. One frozen name is the feature.
395
+ */
396
+ /** The schema Rebase owns. The only schema Rebase creates. */
397
+ var REBASE_SCHEMA = "rebase";
398
+ /**
399
+ * The principal of the current request, as text, or NULL in the server context.
400
+ *
401
+ * Never NULL for a user request — an anonymous one carries
402
+ * {@link ANONYMOUS_USER_ID} — which is what makes `IS NULL` a reliable test for
403
+ * the trusted server plane and `IS NOT NULL` a tautology.
404
+ */
405
+ var RLS_UID_SQL = `${REBASE_SCHEMA}.uid()`;
406
+ /** The request's roles as a comma-separated string, for `string_to_array`. */
407
+ var RLS_ROLES_SQL = `${REBASE_SCHEMA}.roles()`;
408
+ `${REBASE_SCHEMA}`;
409
+ /** The request's JWT claims as `jsonb`, or `{}`. */
410
+ var RLS_JWT_SQL = `${REBASE_SCHEMA}.jwt()`;
411
+ /**
412
+ * The pre-1.0 spellings, for recognising policies and hand-written SQL that
413
+ * predate the move.
414
+ *
415
+ * Kept because policies outlive the server that wrote them: a database migrated
416
+ * by an older release still holds `auth.uid()` in its policy bodies until the
417
+ * next push or boot recompiles them, and anything that reads policies back has
418
+ * to recognise both eras or report the framework's own output as foreign drift.
419
+ * Also used to give a project whose `securityRules` contain raw `auth.uid()` a
420
+ * message naming the replacement, instead of a parse failure.
421
+ */
422
+ var LEGACY_RLS_SCHEMA = "auth";
423
+ `${LEGACY_RLS_SCHEMA}`;
424
+ `${LEGACY_RLS_SCHEMA}`;
425
+ `${LEGACY_RLS_SCHEMA}`;
426
+ //#endregion
427
+ //#region ../types/src/types/resources.ts
428
+ /** The key a resource takes when a project declares only one of its kind. */
429
+ var DEFAULT_RESOURCE_KEY = "(default)";
430
+ var BRAND = Symbol.for("@rebasepro/types.resource");
431
+ /** Whether a value is a resource handle rather than a plain string key. */
432
+ function isResourceHandle(value) {
433
+ return typeof value === "object" && value !== null && BRAND in value;
434
+ }
435
+ /** The key a resource reference names, whether it is a handle or already a key. */
436
+ function resourceKeyOf(ref) {
437
+ return isResourceHandle(ref) ? ref.key : ref;
438
+ }
439
+ /**
440
+ * Replace every resource handle inside a value with its key, deeply.
441
+ *
442
+ * Applied where authored config becomes data: `defineCollection`, the
443
+ * collection loaders, the derive step. Past that point a collection is plain
444
+ * data that serialises, compares with `===` and reaches the admin UI over the
445
+ * wire, so a handle must not survive into it. Plain objects and arrays are
446
+ * walked; anything else — a function, a Date, a class instance — is a leaf and
447
+ * is returned as it is, which is what keeps callbacks and validators intact.
448
+ */
449
+ function resolveResourceRefs(value) {
450
+ if (isResourceHandle(value)) return value.key;
451
+ if (Array.isArray(value)) {
452
+ let changed = false;
453
+ const out = value.map((item) => {
454
+ const next = resolveResourceRefs(item);
455
+ if (next !== item) changed = true;
456
+ return next;
457
+ });
458
+ return changed ? out : value;
459
+ }
460
+ if (value !== null && typeof value === "object") {
461
+ const proto = Object.getPrototypeOf(value);
462
+ if (proto === Object.prototype || proto === null) {
463
+ let changed = false;
464
+ const out = {};
465
+ for (const [k, v] of Object.entries(value)) {
466
+ const next = resolveResourceRefs(v);
467
+ if (next !== v) changed = true;
468
+ out[k] = next;
469
+ }
470
+ return changed ? out : value;
471
+ }
472
+ }
473
+ return value;
474
+ }
475
+ var GLOBAL_KEY = Symbol.for("@rebasepro/types.resourceRegistry");
476
+ /**
477
+ * Where kinds live, versioned — and why the version is in the symbol.
478
+ *
479
+ * Sharing one kinds map across copies means the copy that registers SECOND is
480
+ * the one that runs the comparison. That copy is whatever the bundle happens to
481
+ * carry, which for a driver is a build of this package frozen at its release —
482
+ * so the rule enforced is the rule that shipped THEN, not the one written here.
483
+ *
484
+ * `revision` (390bb03cd, applied to `database` in 346df48e2) was supposed to
485
+ * settle a disagreement between two copies, and it settles it only when the
486
+ * copy doing the arithmetic knows what `revision` is. 0.17.0–0.17.3 do not:
487
+ * they deep-equal the spec and throw. The runtime registers at import and a
488
+ * driver is imported after it, so the old copy is always second, always the
489
+ * judge, and always throws — verified by the bundle corpus on 2026-09-07,
490
+ * which reported v0.17.3's message verbatim ("Two packages cannot define the
491
+ * same kind.", no revision clause) while the runtime it ran on was 0.18.
492
+ *
493
+ * So copies that understand `revision` keep their kinds here, under a symbol
494
+ * no released copy looks at, and the legacy map is left to whoever still wants
495
+ * it. An old copy then registers into a map nobody contests, finds no existing
496
+ * entry, and cannot throw — in any load order, which is what the previous fix
497
+ * only claimed. Bumping this suffix again is how a future change to the
498
+ * REGISTRATION PROTOCOL is made; a change to a kind's own definition is still
499
+ * `revision`, among peers that share this map.
500
+ */
501
+ var KINDS_KEY = Symbol.for("@rebasepro/types.resourceKinds.v2");
502
+ function registry() {
503
+ const g = globalThis;
504
+ let shared = g[GLOBAL_KEY];
505
+ if (!shared) {
506
+ shared = {
507
+ kinds: /* @__PURE__ */ new Map(),
508
+ declarations: /* @__PURE__ */ new Map()
509
+ };
510
+ g[GLOBAL_KEY] = shared;
511
+ }
512
+ let kinds = g[KINDS_KEY];
513
+ if (!kinds) {
514
+ kinds = /* @__PURE__ */ new Map();
515
+ g[KINDS_KEY] = kinds;
516
+ }
517
+ return {
518
+ kinds,
519
+ legacyKinds: shared.kinds,
520
+ declarations: shared.declarations
521
+ };
522
+ }
523
+ /**
524
+ * Every kind visible to this copy: the versioned map, plus anything only a
525
+ * legacy copy registered.
526
+ *
527
+ * The fallback is not for Rebase's own kinds — this copy defines all of those —
528
+ * but for a third-party driver built against an older `@rebasepro/types` that
529
+ * registers a kind of its own. Dropping it would make that kind invisible and
530
+ * turn `declareResource` into "unknown resource kind" for something genuinely
531
+ * registered.
532
+ */
533
+ function visibleKinds() {
534
+ const { kinds, legacyKinds } = registry();
535
+ if (legacyKinds.size === 0) return kinds;
536
+ const merged = new Map(legacyKinds);
537
+ for (const [k, v] of kinds) merged.set(k, v);
538
+ return merged;
539
+ }
540
+ var amendments = /* @__PURE__ */ new Map();
541
+ /**
542
+ * Correct a registered kind without touching its registered literal.
543
+ *
544
+ * Use this, never an edit to the literal, for a kind that has shipped in a
545
+ * published package. The amendment applies to reads through this copy only.
546
+ */
547
+ function amendResourceKind(kind, amendment) {
548
+ amendments.set(kind, {
549
+ ...amendments.get(kind),
550
+ ...amendment
551
+ });
552
+ }
553
+ /** A registered kind as this copy sees it: the shared literal plus this copy's amendments. */
554
+ function effectiveKind(spec) {
555
+ const amendment = amendments.get(spec.kind);
556
+ return amendment ? {
557
+ ...spec,
558
+ ...amendment
559
+ } : spec;
560
+ }
561
+ /** `kind:key`, the graph's primary key. */
562
+ function declarationId(kind, key) {
563
+ return `${kind}:${key}`;
564
+ }
565
+ /**
566
+ * Register a resource kind.
567
+ *
568
+ * Idempotent for an identical spec. When a spec for the same kind is already
569
+ * registered and differs, the `revision` decides: the higher one is kept and
570
+ * the other copy is warned about, in either load order. Two different specs at
571
+ * the SAME revision are a genuine conflict — two packages defining one kind, or
572
+ * a change that forgot to bump — and still throw.
573
+ *
574
+ * Both copies in that comparison are peers on `KINDS_KEY`, which is what makes
575
+ * the rule enforceable: a copy old enough not to know `revision` writes to the
576
+ * legacy map instead and never reaches this function's arithmetic. Registering
577
+ * a kind an older copy already put in the legacy map is therefore not a
578
+ * conflict — it is the ordinary case, and `visibleKinds` prefers this one.
579
+ */
580
+ function registerResourceKind(spec) {
581
+ const kinds = registry().kinds;
582
+ const existing = kinds.get(spec.kind);
583
+ if (!existing) {
584
+ kinds.set(spec.kind, spec);
585
+ return;
586
+ }
587
+ if (JSON.stringify(existing) === JSON.stringify(spec)) return;
588
+ const have = existing.revision ?? 0;
589
+ const incoming = spec.revision ?? 0;
590
+ if (have === incoming) throw new Error(`Resource kind "${spec.kind}" is already registered with a different definition at revision ${have}. Two packages cannot define the same kind; a newer definition of the same kind must carry a higher \`revision\`.`);
591
+ const [kept, dropped] = incoming > have ? [spec, existing] : [existing, spec];
592
+ if (kept === spec) kinds.set(spec.kind, spec);
593
+ console.warn(`[resources] Resource kind "${spec.kind}" is registered twice, at revisions ${dropped.revision ?? 0} and ${kept.revision ?? 0}; keeping revision ${kept.revision ?? 0}. The older copy is usually @rebasepro/types inlined in a driver built before the kind changed — rebuild the project with a current driver to remove it.`);
594
+ }
595
+ /** Every registered kind, for validators and for `rebase doctor`. */
596
+ function resourceKinds() {
597
+ return [...visibleKinds().values()].map(effectiveKind);
598
+ }
599
+ /** One registered kind, or undefined. */
600
+ function resourceKind(kind) {
601
+ const spec = visibleKinds().get(kind);
602
+ return spec && effectiveKind(spec);
603
+ }
604
+ var COMMON_OPTION_KEYS = [
605
+ "engine",
606
+ "transport",
607
+ "label"
608
+ ];
609
+ /** Whether an engine is one the kind knows, or an explicit `custom:` opt-out. */
610
+ function isValidEngine(spec, engine) {
611
+ return engine.startsWith("custom:") || spec.engines.includes(engine);
612
+ }
613
+ /**
614
+ * Declare a resource. The primitive every kind's constructor is built from.
615
+ *
616
+ * Redeclaring the same `kind:key` with a *different* shape throws rather than
617
+ * merging. Merging is what the old storage path did, and it silently discarded
618
+ * one of the two engines — a declaration accepted and then ignored, which is
619
+ * the failure this whole model exists to remove. Redeclaring it identically is
620
+ * fine: a config module evaluated twice must not be an error.
621
+ */
622
+ function declareResource(kind, key = DEFAULT_RESOURCE_KEY, options = {}) {
623
+ const spec = resourceKind(kind);
624
+ if (!spec) {
625
+ const known = [...visibleKinds().keys()].sort().join(", ") || "none";
626
+ throw new Error(`Unknown resource kind "${kind}". Registered kinds: ${known}. Call registerResourceKind() before declaring one.`);
627
+ }
628
+ if (!key || typeof key !== "string" || key.trim() === "") throw new Error(`A ${kind} needs a non-empty key.`);
629
+ const engine = options.engine ?? spec.defaultEngine;
630
+ if (!isValidEngine(spec, engine)) throw new Error(`Unknown ${kind} engine "${engine}" for "${key}". Known engines: ${spec.engines.join(", ")}. An engine this build does not ship is spelled "custom:${engine}", which says so at the call site rather than failing later.`);
631
+ const allowed = /* @__PURE__ */ new Set([...COMMON_OPTION_KEYS, ...spec.optionKeys ?? []]);
632
+ const unknown = Object.keys(options).filter((k) => !allowed.has(k));
633
+ if (unknown.length > 0) throw new Error(`Unknown option(s) on ${kind} "${key}": ${unknown.join(", ")}. A ${kind} accepts: ${[...allowed].sort().join(", ")}.`);
634
+ const extra = {};
635
+ for (const k of spec.optionKeys ?? []) if (options[k] !== void 0) extra[k] = options[k];
636
+ const declaration = {
637
+ kind,
638
+ key,
639
+ engine,
640
+ transport: options.transport ?? "server",
641
+ ...options.label !== void 0 ? { label: options.label } : {},
642
+ options: Object.freeze(extra)
643
+ };
644
+ const id = declarationId(kind, key);
645
+ const previous = registry().declarations.get(id);
646
+ if (previous) {
647
+ if (JSON.stringify(previous) !== JSON.stringify(declaration)) throw new Error(`${kind} "${key}" is declared twice with different configuration. Declare it once and export it — two declarations of one resource is the ambiguity this model exists to remove, so it is refused rather than merged.`);
648
+ } else registry().declarations.set(id, declaration);
649
+ return {
650
+ ...declaration,
651
+ toString() {
652
+ return key;
653
+ },
654
+ [BRAND]: true
655
+ };
656
+ }
657
+ /** Every declared resource, in declaration order, optionally filtered by kind. */
658
+ function declaredResources(kind) {
659
+ const all = [...registry().declarations.values()];
660
+ return kind ? all.filter((r) => r.kind === kind) : all;
661
+ }
662
+ /**
663
+ * The env-var suffix a resource's bindings use: `__ANALYTICS` for `analytics`,
664
+ * and nothing at all for the default-keyed one.
665
+ *
666
+ * The default takes no suffix so that a project with one database configured
667
+ * through plain `DATABASE_URL` keeps working having declared nothing — the
668
+ * overwhelmingly common project must not have to say so.
669
+ */
670
+ function resourceEnvSuffix(key) {
671
+ if (key === "(default)") return "";
672
+ return `__${key.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "")}`;
673
+ }
674
+ /**
675
+ * Build a graph from the current declarations, sorted for a stable diff.
676
+ *
677
+ * `usedBy` maps a `kind:key` id to the things that reach it. The derive step
678
+ * supplies it after evaluating collections; a runtime building the graph at
679
+ * boot passes nothing and gets declarations alone, which is all it binds from.
680
+ */
681
+ function buildResourceGraph(usedBy) {
682
+ return {
683
+ version: 1,
684
+ resources: declaredResources().slice().sort((a, b) => a.kind.localeCompare(b.kind) || a.key.localeCompare(b.key)).map((r) => {
685
+ const users = usedBy?.get(declarationId(r.kind, r.key));
686
+ return users && users.length > 0 ? {
687
+ ...r,
688
+ usedBy: [...users].sort()
689
+ } : r;
690
+ })
691
+ };
692
+ }
693
+ //#endregion
694
+ //#region ../types/src/types/storage_source.ts
695
+ /**
696
+ * Describes a named storage backend — a place files live.
697
+ *
698
+ * Declared once and shared front + back: the frontend uses it to decide
699
+ * transport (HTTP proxy vs direct SDK), the backend uses the same `key`
700
+ * to resolve a StorageController, and collection properties reference
701
+ * a definition by its `key` via `StorageConfig.storageSource`.
702
+ *
703
+ * This mirrors the {@link DataSourceDefinition} pattern used for databases.
704
+ *
705
+ * @group Models
706
+ */
707
+ /**
708
+ * The default storage source key, used when a property does not specify
709
+ * a `storageSource`. Shared by the frontend and backend registries so
710
+ * both agree on "the default storage backend".
711
+ * @group Models
712
+ */
713
+ var DEFAULT_STORAGE_SOURCE_KEY = "(default)";
714
+ /**
715
+ * The environment-variable suffix for a storage or data source key.
716
+ *
717
+ * `""` for the default source — so a single-bucket project keeps configuring
718
+ * plain `S3_BUCKET` — and `__<KEY>` for every named one, uppercased with
719
+ * non-alphanumerics collapsed to underscores: `media-cdn` → `S3_BUCKET__MEDIA_CDN`.
720
+ *
721
+ * The rule derives the variable name from the declared key rather than
722
+ * discovering keys by scanning the environment. Scanning would have to guess how
723
+ * `S3_BUCKET__MEDIA_CDN` splits into a key; deriving cannot be ambiguous, and a
724
+ * typo surfaces as a missing source at boot instead of a silently ignored
725
+ * variable.
726
+ *
727
+ * It lives in this package, with no dependencies, because four things must agree
728
+ * on it exactly: the CLI (validating a build), the runtime (reading its own
729
+ * environment), the control plane (writing a tenant's Secret), and the docs. A
730
+ * second implementation of a naming convention is a second chance to disagree.
731
+ *
732
+ * @group Models
733
+ */
734
+ function storageEnvSuffix(key, defaultKey = DEFAULT_STORAGE_SOURCE_KEY) {
735
+ if (!key || key === defaultKey) return "";
736
+ const normalized = key.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
737
+ if (!normalized) throw new Error(`Source key "${key}" cannot be turned into an environment variable name. Use a key containing at least one letter or digit.`);
738
+ return `__${normalized}`;
739
+ }
740
+ /**
741
+ * Two distinct keys that collapse onto the same variable name, or `null`.
742
+ *
743
+ * `media-cdn` and `media_cdn` are different source keys but the same suffix, so
744
+ * without this one of them silently reads the other's configuration. Returns the
745
+ * offending pair rather than throwing, so each caller can raise it in its own
746
+ * idiom — a `BundleError` at boot, a build failure in the CLI, a rejected deploy
747
+ * in a control plane.
748
+ *
749
+ * @group Models
750
+ */
751
+ function findStorageSuffixCollision(keys, defaultKey = DEFAULT_STORAGE_SOURCE_KEY) {
752
+ const seen = /* @__PURE__ */ new Map();
753
+ for (const key of keys) {
754
+ const suffix = storageEnvSuffix(key, defaultKey);
755
+ const existing = seen.get(suffix);
756
+ if (existing !== void 0 && existing !== key) return {
757
+ a: existing,
758
+ b: key,
759
+ suffix
760
+ };
761
+ seen.set(suffix, key);
762
+ }
763
+ return null;
764
+ }
765
+ //#endregion
766
+ //#region ../types/src/types/resource_kinds.ts
767
+ /**
768
+ * The kinds Rebase ships, and the constructors a project declares them with.
769
+ *
770
+ * Each kind is registered rather than hardcoded, so a fourth one arrives
771
+ * without editing a manifest schema, a validator and a switch statement. That
772
+ * cost is precisely why databases and buckets ended up declared in different
773
+ * files with different rules — the cheapest thing to do was always to bolt the
774
+ * new kind onto whichever home was nearest.
775
+ *
776
+ * A kind owns its engine list. `custom:<id>` is always accepted, so a build
777
+ * that ships an engine this package has never heard of says so at the call site
778
+ * instead of looking like a typo of one that exists.
779
+ */
780
+ registerResourceKind({
781
+ revision: 1,
782
+ kind: "database",
783
+ engines: [
784
+ "postgres",
785
+ "mongodb",
786
+ "firestore",
787
+ "sqlite"
788
+ ],
789
+ defaultEngine: "postgres",
790
+ envBases: [
791
+ "DATABASE_URL",
792
+ "REBASE_DRIVER",
793
+ "REBASE_DB_POOL_MAX"
794
+ ],
795
+ optionKeys: [
796
+ "databaseId",
797
+ "migrations",
798
+ "extensions"
799
+ ],
800
+ implicitDefault: true
801
+ });
802
+ amendResourceKind("database", { envBases: [
803
+ "DATABASE_URL",
804
+ "DATABASE_READ_URL",
805
+ "ADMIN_CONNECTION_STRING",
806
+ "REBASE_DRIVER",
807
+ "DB_POOL_MAX",
808
+ "DB_POOL_IDLE_TIMEOUT",
809
+ "DB_POOL_CONNECT_TIMEOUT"
810
+ ] });
811
+ registerResourceKind({
812
+ kind: "bucket",
813
+ engines: [
814
+ "local",
815
+ "s3",
816
+ "gcs",
817
+ "azure",
818
+ "firebase"
819
+ ],
820
+ defaultEngine: "local",
821
+ envBases: [
822
+ "S3_BUCKET",
823
+ "GCS_BUCKET",
824
+ "STORAGE_BUCKET",
825
+ "STORAGE_PUBLIC_URL"
826
+ ],
827
+ envBasesByEngine: {
828
+ local: ["STORAGE_BUCKET"],
829
+ s3: [
830
+ "S3_BUCKET",
831
+ "STORAGE_ENDPOINT",
832
+ "STORAGE_REGION",
833
+ "STORAGE_PUBLIC_URL"
834
+ ],
835
+ gcs: ["GCS_BUCKET", "STORAGE_PUBLIC_URL"],
836
+ azure: ["STORAGE_BUCKET", "STORAGE_PUBLIC_URL"],
837
+ firebase: ["STORAGE_BUCKET", "STORAGE_PUBLIC_URL"]
838
+ },
839
+ optionKeys: [
840
+ "publicRead",
841
+ "prefix",
842
+ "account"
843
+ ],
844
+ implicitDefault: false
845
+ });
846
+ amendResourceKind("bucket", {
847
+ optionKeys: [
848
+ "publicRead",
849
+ "prefix",
850
+ "account",
851
+ "default"
852
+ ],
853
+ envBases: [
854
+ "STORAGE_TYPE",
855
+ "STORAGE_PATH",
856
+ "S3_BUCKET",
857
+ "S3_REGION",
858
+ "S3_ACCESS_KEY_ID",
859
+ "S3_SECRET_ACCESS_KEY",
860
+ "S3_ENDPOINT",
861
+ "S3_FORCE_PATH_STYLE",
862
+ "GCS_BUCKET",
863
+ "GCS_PROJECT_ID",
864
+ "GCS_KEY_FILENAME"
865
+ ],
866
+ envBasesByEngine: {
867
+ local: ["STORAGE_TYPE", "STORAGE_PATH"],
868
+ s3: [
869
+ "STORAGE_TYPE",
870
+ "S3_BUCKET",
871
+ "S3_REGION",
872
+ "S3_ACCESS_KEY_ID",
873
+ "S3_SECRET_ACCESS_KEY",
874
+ "S3_ENDPOINT",
875
+ "S3_FORCE_PATH_STYLE"
876
+ ],
877
+ gcs: [
878
+ "STORAGE_TYPE",
879
+ "GCS_BUCKET",
880
+ "GCS_PROJECT_ID",
881
+ "GCS_KEY_FILENAME"
882
+ ],
883
+ azure: [],
884
+ firebase: []
885
+ }
886
+ });
887
+ registerResourceKind({
888
+ kind: "topic",
889
+ engines: ["jobs"],
890
+ defaultEngine: "jobs",
891
+ envBases: ["REBASE_TOPIC_URL"],
892
+ optionKeys: ["delivery", "maxAttempts"],
893
+ implicitDefault: false
894
+ });
895
+ amendResourceKind("topic", { envBases: [] });
896
+ var runtimeHolder = { current: null };
897
+ /** Install the transport topics publish through. Called by the server at boot. */
898
+ function setTopicRuntime(runtime) {
899
+ runtimeHolder.current = runtime;
900
+ }
901
+ var subscriptions = [];
902
+ /** Every declared subscription, for the worker to wire and the graph to record. */
903
+ function declaredSubscriptions(topic) {
904
+ return topic ? subscriptions.filter((s) => s.topic === topic) : subscriptions.slice();
905
+ }
906
+ registerResourceKind({
907
+ kind: "cron",
908
+ engines: ["scheduler"],
909
+ defaultEngine: "scheduler",
910
+ envBases: [],
911
+ optionKeys: [
912
+ "schedule",
913
+ "timezone",
914
+ "description",
915
+ "enabled",
916
+ "timeoutSeconds",
917
+ "catchUpWindowSeconds"
918
+ ],
919
+ implicitDefault: false
920
+ });
921
+ /**
922
+ * Declare a cron, as the scheduler's `defineCron` does on its way through.
923
+ *
924
+ * Projects do not call this: `defineCron` in `@rebasepro/server` does, so a
925
+ * cron file is both the handler and the declaration — one file, one name, and
926
+ * the graph derived from it says what a host needs to know without evaluating
927
+ * the handler. Exported so the derive step and the scheduler spell the
928
+ * declaration identically.
929
+ */
930
+ function declareCron(name, options) {
931
+ if (typeof options.schedule !== "string" || options.schedule.trim() === "") throw new Error(`Cron "${name}" needs a schedule — a five-field cron expression such as "0 3 * * *".`);
932
+ return declareResource("cron", name, options);
933
+ }
934
+ registerResourceKind({
935
+ kind: "function",
936
+ engines: ["http"],
937
+ defaultEngine: "http",
938
+ envBases: [],
939
+ optionKeys: [
940
+ "portable",
941
+ "requires",
942
+ "file"
943
+ ],
944
+ implicitDefault: false
945
+ });
946
+ registerResourceKind({
947
+ kind: "queue",
948
+ engines: ["jobs"],
949
+ defaultEngine: "jobs",
950
+ envBases: [],
951
+ optionKeys: ["maxAttempts"],
952
+ implicitDefault: false
953
+ });
954
+ var queueRuntimeHolder = { current: null };
955
+ /** Install the transport queues enqueue through. Called by the server at boot. */
956
+ function setQueueRuntime(runtime) {
957
+ queueRuntimeHolder.current = runtime;
958
+ }
959
+ var queueConsumers = /* @__PURE__ */ new Map();
960
+ /** Every declared queue handler, for the worker to wire. */
961
+ function declaredQueueConsumers() {
962
+ return [...queueConsumers.values()];
963
+ }
964
+ /**
965
+ * One declaration, as the data layer's definition.
966
+ *
967
+ * There is exactly one of these per kind, and everything that needs a
968
+ * definition goes through it — the frontend, the managed runtime's boot path,
969
+ * and an ejected project's own entrypoint. That is not tidiness: the mapping
970
+ * used to exist twice, once here and once in `@rebasepro/server`'s
971
+ * `graphToStorageSources`, and the two disagreed. The server's copy carried a
972
+ * bucket's `account`; this one dropped it, so a bucket declared with shared
973
+ * credentials resolved them on the managed runtime and resolved *nothing* in an
974
+ * ejected backend — the source was skipped and every upload to it answered 501.
975
+ *
976
+ * A field-by-field map is one line away from that failure at all times, so
977
+ * there is now one line to keep right instead of two to keep equal.
978
+ */
979
+ function resourceToDataSource(declaration) {
980
+ return {
981
+ key: declaration.key === "(default)" ? DEFAULT_DATA_SOURCE_KEY : declaration.key,
982
+ engine: declaration.engine,
983
+ transport: declaration.transport,
984
+ ...typeof declaration.options.databaseId === "string" ? { databaseId: declaration.options.databaseId } : {},
985
+ ...declaration.label !== void 0 ? { label: declaration.label } : {}
986
+ };
987
+ }
988
+ /** One declaration, as the storage layer's definition. See {@link resourceToDataSource}. */
989
+ function resourceToStorageSource(declaration) {
990
+ return {
991
+ key: declaration.key === "(default)" ? DEFAULT_STORAGE_SOURCE_KEY : declaration.key,
992
+ engine: declaration.engine,
993
+ transport: declaration.transport,
994
+ ...typeof declaration.options.account === "string" ? { account: declaration.options.account } : {},
995
+ ...declaration.options.default === true ? { default: true } : {},
996
+ ...declaration.label !== void 0 ? { label: declaration.label } : {}
997
+ };
998
+ }
999
+ //#endregion
1000
+ export { REST_TO_CANONICAL as A, isPostgresCollectionConfig as C, ALL_WHERE_FILTER_OPS as D, getDataSourceCapabilities as E, parseRelationAggregateSort as M, sortKeyToString as N, CANONICAL_TO_REST as O, toCanonicalOp as P, getDeclaredSubcollections as S, DEFAULT_DATA_SOURCE_KEY as T, resourceKinds as _, resourceToStorageSource as a, RLS_UID_SQL as b, DEFAULT_STORAGE_SOURCE_KEY as c, DEFAULT_RESOURCE_KEY as d, buildResourceGraph as f, resourceKind as g, resourceKeyOf as h, resourceToDataSource as i, isRelationAggregateSort as j, NULL_OPS as k, findStorageSuffixCollision as l, resourceEnvSuffix as m, declaredQueueConsumers as n, setQueueRuntime as o, resolveResourceRefs as p, declaredSubscriptions as r, setTopicRuntime as s, declareCron as t, storageEnvSuffix as u, RLS_JWT_SQL as v, isRelationalCollectionConfig as w, getCollectionDataPath as x, RLS_ROLES_SQL as y };
1001
+
1002
+ //# sourceMappingURL=src-DHK4fHkw.js.map