@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
@@ -3,7 +3,7 @@ import __rebaseProcess from "process";
3
3
  globalThis.process ??= __rebaseProcess;
4
4
  __rebaseCreateRequire(import.meta.url);
5
5
  import { r as __require, t as __commonJSMin } from "./rolldown-runtime-dW7B1o5h.js";
6
- import { _ as REST_TO_CANONICAL, b as toCanonicalOp, d as isRelationalCollectionConfig, g as NULL_OPS, h as CANONICAL_TO_REST, l as getDeclaredSubcollections, m as ALL_WHERE_FILTER_OPS, p as getDataSourceCapabilities, u as isPostgresCollectionConfig, y as sortKeyToString } from "./src-CcOl05Oq.js";
6
+ import { A as REST_TO_CANONICAL, C as isPostgresCollectionConfig, D as ALL_WHERE_FILTER_OPS, E as getDataSourceCapabilities, N as sortKeyToString, O as CANONICAL_TO_REST, P as toCanonicalOp, S as getDeclaredSubcollections, j as isRelationAggregateSort, k as NULL_OPS, p as resolveResourceRefs, w as isRelationalCollectionConfig } from "./src-DHK4fHkw.js";
7
7
  //#region ../types/src/errors.ts
8
8
  /**
9
9
  * The single error type thrown across the entire Rebase client surface —
@@ -36,12 +36,18 @@ var RebaseApiError = class extends Error {
36
36
  code;
37
37
  /** Structured error payload from the server, when present. */
38
38
  details;
39
+ /** See {@link RebaseErrorInit.requestId}. Quote it in a bug report. */
40
+ requestId;
41
+ /** See {@link RebaseErrorInit.retryAfterSeconds}. */
42
+ retryAfterSeconds;
39
43
  constructor(message, init = {}) {
40
44
  super(message);
41
45
  this.name = "RebaseApiError";
42
46
  this.status = init.status;
43
47
  this.code = init.code;
44
48
  this.details = init.details;
49
+ this.requestId = init.requestId;
50
+ this.retryAfterSeconds = init.retryAfterSeconds;
45
51
  if (init.cause !== void 0) this.cause = init.cause;
46
52
  }
47
53
  };
@@ -55,11 +61,76 @@ var RebaseApiError = class extends Error {
55
61
  * @group Errors
56
62
  */
57
63
  var RebaseClientError = class extends RebaseApiError {
58
- constructor(message) {
59
- super(message);
64
+ /**
65
+ * `init` is the same one {@link RebaseApiError} takes, and it is what makes
66
+ * `code` reachable at all.
67
+ *
68
+ * The constructor used to accept a message and nothing else, so every
69
+ * client-side failure — an undefined filter value, an unknown accessor,
70
+ * `listen()` on a client built with `realtime: false`, a function name with
71
+ * a `/` in it, `refreshSession()` while signed out — arrived with `code ===
72
+ * undefined`. The documented `switch (e.code)` in this file's own example
73
+ * fell to `default: throw e` for all of them, and the only client-side error
74
+ * that *did* carry a code was `OFFLINE`, because that one path minted a
75
+ * `RebaseApiError` instead.
76
+ */
77
+ constructor(message, init = {}) {
78
+ super(message, init);
60
79
  this.name = "RebaseClientError";
61
80
  }
62
81
  };
82
+ /**
83
+ * Brand for a contract method a particular client cannot serve.
84
+ *
85
+ * `Symbol.for` rather than a fresh symbol: two copies of `@rebasepro/types` in
86
+ * one tree — which happens, see `docs/dependency-duplication-traps.md` — must
87
+ * agree about it, and a module-local symbol would not.
88
+ */
89
+ var UNSUPPORTED_METHOD = Symbol.for("rebase.unsupportedMethod");
90
+ /**
91
+ * Build the stub a client installs for a contract method it cannot serve.
92
+ *
93
+ * `listen`, `listenById` and `count` are part of `SDKCollectionClient`, not
94
+ * optional extras — a caller should be able to write
95
+ * `client.data.posts.count()` without asking first, and a transport that cannot
96
+ * serve it should answer with a sentence naming the configuration that would,
97
+ * rather than with `undefined is not a function` at the call site. Where the
98
+ * transport genuinely cannot (a client built with `realtime: false`, a driver
99
+ * with no `listenCollection`), it installs one of these instead of omitting the
100
+ * method.
101
+ *
102
+ * @param message What to tell the caller, naming the fix.
103
+ * @group Errors
104
+ */
105
+ function unsupportedMethod(message) {
106
+ const stub = () => {
107
+ throw new RebaseClientError(message, { code: "REALTIME_DISABLED" });
108
+ };
109
+ stub[UNSUPPORTED_METHOD] = true;
110
+ return stub;
111
+ }
112
+ /**
113
+ * Can this method actually do anything?
114
+ *
115
+ * `true` for a stub from {@link unsupportedMethod} **and** for a method that is
116
+ * simply not there — a partial client, a hand-built test double, an
117
+ * implementation written against an older shape of the interface. Both mean the
118
+ * same thing to a caller, so both answer the same way, and an adapter that
119
+ * checks this cannot be caught out by either.
120
+ *
121
+ * Ordinary code does not need it: calling the method and letting it throw is
122
+ * the normal path. Adapters do — the admin panel chooses between subscribing
123
+ * and a one-shot `find()` by asking whether the client can listen, and a UI
124
+ * that subscribes into a throw is worse than one that polls. This is the
125
+ * question `if (accessor.listen)` used to be asking, made explicit now that the
126
+ * method is always there to call.
127
+ *
128
+ * @group Errors
129
+ */
130
+ function isUnsupported(method) {
131
+ if (typeof method !== "function") return true;
132
+ return method[UNSUPPORTED_METHOD] === true;
133
+ }
63
134
  //#endregion
64
135
  //#region ../types/src/types/entities.ts
65
136
  /**
@@ -268,6 +339,7 @@ var policy = {
268
339
  roles
269
340
  }),
270
341
  authenticated: () => ({ kind: "authenticated" }),
342
+ registered: () => ({ kind: "registered" }),
271
343
  serverContext: () => ({ kind: "serverContext" }),
272
344
  existsIn: (args) => ({
273
345
  kind: "existsIn",
@@ -1282,6 +1354,51 @@ var toSnakeCase = (str) => {
1282
1354
  return regExpMatchArray.map((x) => x.toLowerCase()).join("_");
1283
1355
  };
1284
1356
  /**
1357
+ * Are these two identifiers one edit apart, ignoring case?
1358
+ *
1359
+ * Tight on purpose. A suggester that fires on two edits offers `columnWidth`
1360
+ * for `colWith` and `readOnly` for `required`, and a "did you mean" that is
1361
+ * usually wrong teaches people to stop reading them. One edit covers what
1362
+ * actually happens — a dropped letter (`multilne`), a doubled one, a transposed
1363
+ * pair (`validaton`), a wrong case — and nothing else.
1364
+ *
1365
+ * Lives here rather than beside either caller because both the CLI's manifest
1366
+ * reader and the server's collection validator answer the same question about
1367
+ * an unknown key, and two copies of a similarity rule is two rules the moment
1368
+ * one of them is tuned.
1369
+ */
1370
+ function isNearMiss(a, b) {
1371
+ const x = a.toLowerCase();
1372
+ const y = b.toLowerCase();
1373
+ if (x === y) return true;
1374
+ if (Math.abs(x.length - y.length) > 1) return false;
1375
+ const [shorter, longer] = x.length <= y.length ? [x, y] : [y, x];
1376
+ let i = 0;
1377
+ let j = 0;
1378
+ let edits = 0;
1379
+ while (i < shorter.length && j < longer.length) {
1380
+ if (shorter[i] === longer[j]) {
1381
+ i++;
1382
+ j++;
1383
+ continue;
1384
+ }
1385
+ if (++edits > 1) return false;
1386
+ if (shorter.length === longer.length) i++;
1387
+ j++;
1388
+ }
1389
+ return edits + (longer.length - j) + (shorter.length - i) <= 1;
1390
+ }
1391
+ /**
1392
+ * The key in `known` that `key` was probably meant to be, if any.
1393
+ *
1394
+ * `undefined` when nothing is close — which is the common case for a key that
1395
+ * is simply from a newer version, and the reason the caller must be able to say
1396
+ * "unknown" without saying "wrong".
1397
+ */
1398
+ function suggestNearMiss(known, key) {
1399
+ return known.find((candidate) => isNearMiss(candidate, key));
1400
+ }
1401
+ /**
1285
1402
  * Deep clone a value, preserving function references and class instances.
1286
1403
  * Unlike structuredClone, this handles objects that contain functions
1287
1404
  * (e.g. CollectionConfig with target(), childCollections(), callbacks).
@@ -1664,8 +1781,7 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
1664
1781
  targetSlug: targetCollection.slug,
1665
1782
  onUpdate: relation.onUpdate,
1666
1783
  onDelete: relation.onDelete,
1667
- overrides: relation.overrides,
1668
- validation: relation.validation
1784
+ overrides: relation.overrides
1669
1785
  };
1670
1786
  const sourceName = toSnakeCase(sourceCollection.slug ?? sourceCollection.name);
1671
1787
  switch (relation.kind) {
@@ -1842,9 +1958,60 @@ function resolveCollectionRelations(collection) {
1842
1958
  _resolvedRelationsCache.set(collection, relations);
1843
1959
  return relations;
1844
1960
  }
1961
+ /**
1962
+ * The `type: "relation"` property that declares a link, or `undefined` for one
1963
+ * that only exists in the collection's `relations` array.
1964
+ *
1965
+ * Both declaration sites end up in {@link resolveCollectionRelations}, and only
1966
+ * one of them has a property to carry field-level facts — `name`, `admin`, and
1967
+ * the one this exists for, `validation.required`.
1968
+ */
1969
+ function relationDeclaringProperty(collection, relation) {
1970
+ const resolved = resolveCollectionRelations(collection);
1971
+ for (const [key, raw] of Object.entries(collection.properties ?? {})) {
1972
+ const prop = raw;
1973
+ if (prop?.type !== "relation") continue;
1974
+ if (resolved[key] === relation) return prop;
1975
+ const addressed = prop.relation?.relationName;
1976
+ if (addressed && findRelation(resolved, addressed) === relation) return prop;
1977
+ }
1978
+ }
1979
+ /**
1980
+ * Must every row of this collection point at a target through this link?
1981
+ *
1982
+ * Read from the declaring property's `validation.required` — the same key every
1983
+ * other field uses, and the only place it lives.
1984
+ *
1985
+ * `RelationBase` carried its own `validation.required` until 0.18, which made
1986
+ * this two questions rather than one. They were answered by different readers:
1987
+ * the Postgres DDL generator asked the property (so the foreign-key column was
1988
+ * `NOT NULL`) and the SDK type generator asked the relation (so the generated
1989
+ * `Insert` type made the field optional). A `create()` that left the relation
1990
+ * out therefore typechecked and then failed at the database with a not-null
1991
+ * violation, and the two `required`s had to be written twice, identically, for
1992
+ * the pair to agree.
1993
+ *
1994
+ * A relation with no declaring property — an entry in `relations` nothing
1995
+ * points at — is not required. There is no field to fill in.
1996
+ */
1997
+ function isRelationRequired(collection, relation) {
1998
+ return Boolean(relationDeclaringProperty(collection, relation)?.validation?.required);
1999
+ }
2000
+ /**
2001
+ * The table a collection reads and writes.
2002
+ *
2003
+ * `table` when it is set, otherwise `toSnakeCase(slug)` — which is what made it
2004
+ * safe to drop `table` from the required fields on the config type: the runtime
2005
+ * had always derived it, and the type was demanding a value it did not need.
2006
+ *
2007
+ * The `||` chain is load-bearing. `toSnakeCase(undefined)` returns `""`, not
2008
+ * `undefined`, so the previous `??` chain short-circuited on the empty string
2009
+ * and the name fallback could never run — a safety net that read like one and
2010
+ * caught nothing. It was unreachable while `slug` was required; it stops being
2011
+ * unreachable the moment anything constructs a config without one.
2012
+ */
1845
2013
  function getTableName(collection) {
1846
- if (isRelationalCollectionConfig(collection)) return collection.table ?? toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);
1847
- return toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);
2014
+ return (isRelationalCollectionConfig(collection) ? collection.table : void 0) || toSnakeCase(collection.slug) || toSnakeCase(collection.name);
1848
2015
  }
1849
2016
  /**
1850
2017
  * The field key a database column is served and addressed under.
@@ -2012,6 +2179,17 @@ var FOREIGN_CONVENTION_UIDS = /* @__PURE__ */ new Map([
2012
2179
  ]);
2013
2180
  new RegExp(String.raw`rebase\.uid\(\)\s*=\s*'(${[...FOREIGN_CONVENTION_UIDS.keys()].join("|")})'`, "i");
2014
2181
  //#endregion
2182
+ //#region ../common/src/util/builders.ts
2183
+ /**
2184
+ * At runtime this is a plain identity function: a resource handle written where
2185
+ * a key belongs — `dataSource: analytics` — becomes its key, so past this point
2186
+ * a collection is plain data. The signature above is the rest of the point.
2187
+ * @group Builder
2188
+ */
2189
+ function defineCollection(collection) {
2190
+ return resolveResourceRefs(collection);
2191
+ }
2192
+ //#endregion
2015
2193
  //#region ../common/src/util/auth-default-policies.ts
2016
2194
  /**
2017
2195
  * Default RLS policies injected by the schema generator.
@@ -2880,7 +3058,7 @@ var CollectionRegistry = class {
2880
3058
  dataSources = {};
2881
3059
  /**
2882
3060
  * Global lifecycle callbacks applied to every collection.
2883
- * Runs on all data paths (REST, WebSocket, `rebase.data`).
3061
+ * Runs on all data paths (REST, WebSocket, `rebase.dataAsAdmin`).
2884
3062
  * Execution order: global → collection → property callbacks.
2885
3063
  */
2886
3064
  _globalCallbacks;
@@ -3018,7 +3196,7 @@ var CollectionRegistry = class {
3018
3196
  else {
3019
3197
  const declared = resolveCollectionRelations(collection)[key];
3020
3198
  if (declared) relationProperty.resolvedRelation = declared;
3021
- else console.warn(`Relation property '${key}' on '${collection.slug}' declares no \`relation\`, and the collection has no relation of that name.`);
3199
+ else console.warn(`Relation property '${key}' on '${collection.slug}' names no relation: it has no \`relation\` block, and the collection's \`relations\` array has no entry called '${key}'. The field will render no picker, generate no foreign key, and return nothing from \`include()\`.`);
3022
3200
  }
3023
3201
  }
3024
3202
  return newProperty;
@@ -3111,6 +3289,122 @@ var CollectionRegistry = class {
3111
3289
  }
3112
3290
  };
3113
3291
  //#endregion
3292
+ //#region ../common/src/collections/default-collections.ts
3293
+ /**
3294
+ * Default users collection.
3295
+ *
3296
+ * Prepended to the developer's collections array by the admin and server.
3297
+ * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers
3298
+ * override by defining their own collection with `slug: "users"`.
3299
+ *
3300
+ * Schema only — no `admin` block. This package is on the backend's dependency path,
3301
+ * where that field does not exist: `@rebasepro/cms-types` adds it by declaration
3302
+ * merging, and a BaaS install never installs that. The scaffolded
3303
+ * `config/collections/users.ts` carries the presentation for projects that want this
3304
+ * collection in their panel, which is also where it is editable.
3305
+ */
3306
+ var defaultUsersCollection = defineCollection({
3307
+ name: "Users",
3308
+ singularName: "User",
3309
+ slug: "users",
3310
+ auth: true,
3311
+ table: "users",
3312
+ schema: "rebase",
3313
+ securityRules: [{
3314
+ operation: "select",
3315
+ roles: ["admin"]
3316
+ }, {
3317
+ operations: [
3318
+ "insert",
3319
+ "update",
3320
+ "delete"
3321
+ ],
3322
+ roles: ["admin"]
3323
+ }],
3324
+ properties: {
3325
+ id: {
3326
+ name: "ID",
3327
+ type: "string",
3328
+ isId: "uuid"
3329
+ },
3330
+ email: {
3331
+ name: "Email",
3332
+ type: "string",
3333
+ validation: {
3334
+ required: true,
3335
+ unique: true
3336
+ }
3337
+ },
3338
+ displayName: {
3339
+ name: "Name",
3340
+ type: "string",
3341
+ columnName: "display_name",
3342
+ validation: { required: true }
3343
+ },
3344
+ photoURL: {
3345
+ name: "Photo URL",
3346
+ type: "string",
3347
+ columnName: "photo_url"
3348
+ },
3349
+ roles: {
3350
+ name: "Roles",
3351
+ type: "array",
3352
+ columnType: "text[]",
3353
+ of: {
3354
+ name: "Role",
3355
+ type: "string",
3356
+ enum: {
3357
+ admin: "Admin",
3358
+ editor: "Editor",
3359
+ viewer: "Viewer"
3360
+ }
3361
+ }
3362
+ },
3363
+ passwordHash: {
3364
+ name: "Password Hash",
3365
+ type: "string",
3366
+ columnName: "password_hash",
3367
+ excludeFromApi: true
3368
+ },
3369
+ emailVerified: {
3370
+ name: "Email Verified",
3371
+ type: "boolean",
3372
+ columnName: "email_verified",
3373
+ defaultValue: false
3374
+ },
3375
+ emailVerificationToken: {
3376
+ name: "Email Verification Token",
3377
+ type: "string",
3378
+ columnName: "email_verification_token",
3379
+ excludeFromApi: true
3380
+ },
3381
+ emailVerificationSentAt: {
3382
+ name: "Email Verification Sent At",
3383
+ type: "date",
3384
+ columnName: "email_verification_sent_at"
3385
+ },
3386
+ metadata: {
3387
+ name: "Metadata",
3388
+ type: "map",
3389
+ keyValue: true,
3390
+ properties: {},
3391
+ defaultValue: {}
3392
+ },
3393
+ createdAt: {
3394
+ name: "Created At",
3395
+ type: "date",
3396
+ columnName: "created_at",
3397
+ autoValue: "on_create"
3398
+ },
3399
+ updatedAt: {
3400
+ name: "Updated At",
3401
+ type: "date",
3402
+ columnName: "updated_at",
3403
+ autoValue: "on_update"
3404
+ }
3405
+ }
3406
+ });
3407
+ //#endregion
3114
3408
  //#region ../common/src/data/sort-dialect.ts
3115
3409
  /**
3116
3410
  * Sort-order wire codec.
@@ -3146,7 +3440,23 @@ function normalizeOrderBy(orderBy) {
3146
3440
  if (!orderBy || orderBy.length === 0) return void 0;
3147
3441
  const list = Array.isArray(orderBy[0]) ? orderBy : [orderBy];
3148
3442
  if (list.length === 0) return void 0;
3149
- return list.map(([key, direction]) => [sortKeyToString(key), direction]);
3443
+ return list.map((entry, index) => toStrictTuple(entry, index));
3444
+ }
3445
+ /** A sort whose *shape* is unusable, as opposed to one naming a field that does not exist. */
3446
+ var OrderBySpecError = class extends Error {
3447
+ code = "INVALID_ORDER_BY";
3448
+ constructor(detail) {
3449
+ super(`Invalid \`orderBy\`: ${detail}. Expected a field name, or a list of [field, direction] pairs like [["roles","asc"],["created_at","desc"]]`);
3450
+ this.name = "OrderBySpecError";
3451
+ }
3452
+ };
3453
+ function toStrictTuple(raw, index) {
3454
+ if (!Array.isArray(raw)) throw new OrderBySpecError(`entry ${index} has no field name`);
3455
+ const key = isRelationAggregateSort(raw[0]) ? sortKeyToString(raw[0]) : raw[0];
3456
+ if (typeof key !== "string" || key.trim() === "") throw new OrderBySpecError(`entry ${index} has no field name`);
3457
+ const direction = raw[1];
3458
+ if (direction !== void 0 && direction !== "asc" && direction !== "desc") throw new OrderBySpecError(`entry ${index} has direction '${String(direction)}'`);
3459
+ return [key, direction ?? "asc"];
3150
3460
  }
3151
3461
  /**
3152
3462
  * Serialize a sort to the wire.
@@ -3192,7 +3502,11 @@ var QueryBuilder = class {
3192
3502
  }
3193
3503
  where(columnOrCondition, operator, value) {
3194
3504
  if (typeof columnOrCondition === "object" && columnOrCondition !== null && "type" in columnOrCondition) {
3195
- this.params.logical = columnOrCondition;
3505
+ const next = columnOrCondition;
3506
+ this.params.logical = this.params.logical ? {
3507
+ type: "and",
3508
+ conditions: [this.params.logical, next]
3509
+ } : next;
3196
3510
  return this;
3197
3511
  }
3198
3512
  if (!this.params.where) this.params.where = {};
@@ -3777,6 +4091,36 @@ function readTuple(field, raw) {
3777
4091
  if (isOperatorShaped(op)) throw new UnknownFilterOperatorError(field, op);
3778
4092
  }
3779
4093
  /**
4094
+ * Encode the `<op>.<value>` half of a wire condition.
4095
+ *
4096
+ * This is the single leaf encoder. Both wire positions that carry a condition
4097
+ * — a top-level query parameter (`?status=eq.active`) and a leaf inside an
4098
+ * `and(...)`/`or(...)` group (`or(status.eq.active,…)`) — go through it, so a
4099
+ * rule expressed here holds in both. The group serializer used to carry its
4100
+ * own copy, and the copy had drifted on every rule that matters: `null` went
4101
+ * out as the four-character string, the empty list as `()`, and an operator
4102
+ * this dialect does not have was silently rewritten to `eq` — a filter that
4103
+ * ran, returned rows, and answered a different question than the one asked.
4104
+ *
4105
+ * `escapeScalar` is the one thing the two positions legitimately disagree
4106
+ * about. A scalar in a query parameter owns the whole value and needs no
4107
+ * escaping; a scalar inside a group sits between the same commas a list item
4108
+ * does, so a comma in it would end the condition early.
4109
+ */
4110
+ function serializeOperatorAndValue(op, value, { escapeScalar, where }) {
4111
+ if (typeof op !== "string") throw new TypeError(`${where}: operator must be a string, got ${typeof op}`);
4112
+ const restOp = CANONICAL_OP_LOOKUP.get(op);
4113
+ if (!restOp) throw new TypeError(`${where}: unknown operator "${op}". Valid operators: ${Object.keys(CANONICAL_TO_REST).join(", ")}`);
4114
+ if (value === null && (op === "==" || op === "!=")) return op === "==" ? "isnull.null" : "notnull.null";
4115
+ if (NULL_OPS.has(op)) return `${restOp}.null`;
4116
+ if (Array.isArray(value)) {
4117
+ if (value.length === 0) return `${restOp}.(${EMPTY_LIST_TOKEN})`;
4118
+ return `${restOp}.(${value.map((v) => escapeWireValue(stringifyValue(v))).join(",")})`;
4119
+ }
4120
+ const scalar = stringifyValue(value);
4121
+ return `${restOp}.${escapeScalar ? escapeWireValue(scalar) : scalar}`;
4122
+ }
4123
+ /**
3780
4124
  * Serialize a single canonical condition tuple to a PostgREST dot-string.
3781
4125
  *
3782
4126
  * Throws `TypeError` if the input is not a valid `[WhereFilterOp, unknown]` tuple.
@@ -3789,15 +4133,10 @@ function readTuple(field, raw) {
3789
4133
  function serializeTuple(tuple) {
3790
4134
  if (!Array.isArray(tuple) || tuple.length !== 2) throw new TypeError(`serializeTuple: expected a [WhereFilterOp, value] tuple, got ${JSON.stringify(tuple)}`);
3791
4135
  const [op, value] = tuple;
3792
- if (typeof op !== "string") throw new TypeError(`serializeTuple: operator must be a string, got ${typeof op}`);
3793
- const restOp = CANONICAL_OP_LOOKUP.get(op);
3794
- if (!restOp) throw new TypeError(`serializeTuple: unknown operator "${op}". Valid operators: ${Object.keys(CANONICAL_TO_REST).join(", ")}`);
3795
- if (value === null && (op === "==" || op === "!=")) return op === "==" ? "isnull.null" : "notnull.null";
3796
- if (Array.isArray(value)) {
3797
- if (value.length === 0) return `${restOp}.(${EMPTY_LIST_TOKEN})`;
3798
- return `${restOp}.(${value.map((v) => escapeWireValue(stringifyValue(v))).join(",")})`;
3799
- }
3800
- return `${restOp}.${stringifyValue(value)}`;
4136
+ return serializeOperatorAndValue(op, value, {
4137
+ escapeScalar: false,
4138
+ where: "serializeTuple"
4139
+ });
3801
4140
  }
3802
4141
  /**
3803
4142
  * Convert `FilterValues` (or `WireFilterValues`) to a PostgREST-style
@@ -3902,10 +4241,21 @@ function deserializeFilter(query) {
3902
4241
  /**
3903
4242
  * Serialize a `LogicalCondition` or `FilterCondition` to its wire-format string.
3904
4243
  *
4244
+ * Leaf encoding is {@link serializeOperatorAndValue}, the same function
4245
+ * `serializeTuple` uses, so `null`, the empty list and an unknown operator
4246
+ * behave identically inside a group and in a query parameter.
4247
+ *
4248
+ * @throws {TypeError} when a leaf names an operator this dialect does not have.
4249
+ * It used to fall back to `eq`, which turned `age >= 18` into `age = 18` with
4250
+ * no diagnostic anywhere.
4251
+ *
3905
4252
  * @example
3906
4253
  * serializeLogicalCondition({ column: "status", operator: "==", value: "active" })
3907
4254
  * // → "status.eq.active"
3908
4255
  *
4256
+ * serializeLogicalCondition({ column: "deleted_at", operator: "==", value: null })
4257
+ * // → "deleted_at.isnull.null"
4258
+ *
3909
4259
  * serializeLogicalCondition({ type: "or", conditions: [...] })
3910
4260
  * // → "or(status.eq.active,status.eq.pending)"
3911
4261
  */
@@ -3914,12 +4264,60 @@ function serializeLogicalCondition(cond) {
3914
4264
  const inner = (cond.conditions ?? []).map(serializeLogicalCondition).join(",");
3915
4265
  return `${cond.type}(${inner})`;
3916
4266
  }
3917
- const restOp = CANONICAL_OP_LOOKUP.get(cond.operator) ?? "eq";
3918
- if (Array.isArray(cond.value)) {
3919
- const items = cond.value.map((v) => escapeWireValue(stringifyValue(v))).join(",");
3920
- return `${cond.column}.${restOp}.(${items})`;
4267
+ return `${escapeWireValue(cond.column)}.${serializeOperatorAndValue(cond.operator, cond.value, {
4268
+ escapeScalar: true,
4269
+ where: "serializeLogicalCondition"
4270
+ })}`;
4271
+ }
4272
+ /**
4273
+ * Split a leaf condition into `column`, operator token and value.
4274
+ *
4275
+ * The naive reading — column is everything before the first dot, operator is
4276
+ * everything up to the second — cannot express a relation path. A filter on
4277
+ * `author.name` serializes to `author.name.eq.bob` and came back as the column
4278
+ * `author` with the operator `name`, which resolves to nothing, so the
4279
+ * fallback made it `author == "eq.bob"`: a condition that runs and matches
4280
+ * nothing, on a column the caller never named.
4281
+ *
4282
+ * So the operator is found rather than assumed: it is the first dot-separated
4283
+ * segment after the column that resolves to a real operator. Everything before
4284
+ * it is the column, everything after is the value. `version.eq.1.2.3` reads as
4285
+ * `version == "1.2.3"` because the scan stops at the first match — the `eq` at
4286
+ * offset 1, not a later segment — and `metadata->>x.eq.5` never had dots in the
4287
+ * column to begin with.
4288
+ *
4289
+ * Returns `undefined` when no segment resolves — `status.active`, an equality
4290
+ * written without an operator, which the caller handles.
4291
+ */
4292
+ function splitLeafCondition(str) {
4293
+ let limit = str.length;
4294
+ for (let i = 0; i < str.length; i++) {
4295
+ if (str[i] === "\\") {
4296
+ i++;
4297
+ continue;
4298
+ }
4299
+ if (str[i] === "(") {
4300
+ limit = i;
4301
+ break;
4302
+ }
4303
+ }
4304
+ const dots = [];
4305
+ for (let i = 0; i < limit; i++) {
4306
+ if (str[i] === "\\") {
4307
+ i++;
4308
+ continue;
4309
+ }
4310
+ if (str[i] === ".") dots.push(i);
4311
+ }
4312
+ for (let i = 1; i < dots.length; i++) {
4313
+ const operator = toCanonicalOp(str.substring(dots[i - 1] + 1, dots[i]));
4314
+ if (!operator) continue;
4315
+ return {
4316
+ column: unescapeWireValue(str.substring(0, dots[i - 1])),
4317
+ operator,
4318
+ value: str.substring(dots[i] + 1)
4319
+ };
3921
4320
  }
3922
- return `${cond.column}.${restOp}.${escapeWireValue(stringifyValue(cond.value))}`;
3923
4321
  }
3924
4322
  function deserializeLogicalCondition(str, nesting = 0) {
3925
4323
  if (nesting > 32) throw new Error(`Filter groups nest more than 32 levels deep. Flatten the condition — \`or(a,or(b,c))\` is \`or(a,b,c)\`.`);
@@ -3932,28 +4330,34 @@ function deserializeLogicalCondition(str, nesting = 0) {
3932
4330
  conditions: splitGroupItems(innerStr).map((part) => deserializeLogicalCondition(part, nesting + 1))
3933
4331
  };
3934
4332
  }
3935
- const firstDot = str.indexOf(".");
3936
- if (firstDot === -1) return {
3937
- column: str,
3938
- operator: "==",
3939
- value: true
3940
- };
3941
- const column = str.substring(0, firstDot);
3942
- const rest = str.substring(firstDot + 1);
3943
- const secondDot = rest.indexOf(".");
3944
- if (secondDot === -1) return {
3945
- column,
3946
- operator: "==",
3947
- value: unescapeWireValue(rest)
3948
- };
3949
- const opStr = rest.substring(0, secondDot);
3950
- const valueStr = rest.substring(secondDot + 1);
3951
- const operator = toCanonicalOp(opStr) ?? "==";
3952
- if (valueStr.startsWith("(") && valueStr.endsWith(")")) return {
4333
+ const leaf = splitLeafCondition(str);
4334
+ if (!leaf) {
4335
+ const firstDot = str.indexOf(".");
4336
+ if (firstDot === -1) return {
4337
+ column: unescapeWireValue(str),
4338
+ operator: "==",
4339
+ value: true
4340
+ };
4341
+ return {
4342
+ column: unescapeWireValue(str.substring(0, firstDot)),
4343
+ operator: "==",
4344
+ value: unescapeWireValue(str.substring(firstDot + 1))
4345
+ };
4346
+ }
4347
+ const { column, operator, value: valueStr } = leaf;
4348
+ if (NULL_OPS.has(operator)) return {
3953
4349
  column,
3954
4350
  operator,
3955
- value: splitListItems(valueStr.slice(1, -1))
4351
+ value: null
3956
4352
  };
4353
+ if (valueStr.startsWith("(") && valueStr.endsWith(")")) {
4354
+ const inner = valueStr.slice(1, -1);
4355
+ return {
4356
+ column,
4357
+ operator,
4358
+ value: inner === EMPTY_LIST_TOKEN ? [] : splitListItems(inner)
4359
+ };
4360
+ }
3957
4361
  return {
3958
4362
  column,
3959
4363
  operator,
@@ -3962,6 +4366,15 @@ function deserializeLogicalCondition(str, nesting = 0) {
3962
4366
  }
3963
4367
  //#endregion
3964
4368
  //#region ../common/src/data/buildRebaseData.ts
4369
+ /**
4370
+ * What a client says when its data source cannot subscribe.
4371
+ *
4372
+ * Named rather than inlined so the sentence a caller sees does not depend on
4373
+ * which of the two adapters below happened to build the client.
4374
+ */
4375
+ var noRealtime = (slug) => `Realtime is not available for "${slug}": its data source does not support subscriptions.`;
4376
+ /** What a client says when its data source cannot count. */
4377
+ var noCount = (slug) => `Counting is not available for "${slug}": its data source does not support it.`;
3965
4378
  function createPrimaryKeyResolver(options) {
3966
4379
  const cache = /* @__PURE__ */ new Map();
3967
4380
  const warned = /* @__PURE__ */ new Set();
@@ -4256,7 +4669,11 @@ var SdkQueryBuilder = class {
4256
4669
  }
4257
4670
  where(columnOrCondition, operator, value) {
4258
4671
  if (typeof columnOrCondition === "object" && columnOrCondition !== null && "type" in columnOrCondition) {
4259
- this.params.logical = columnOrCondition;
4672
+ const next = columnOrCondition;
4673
+ this.params.logical = this.params.logical ? {
4674
+ type: "and",
4675
+ conditions: [this.params.logical, next]
4676
+ } : next;
4260
4677
  return this;
4261
4678
  }
4262
4679
  if (!this.params.where) this.params.where = {};
@@ -4276,7 +4693,7 @@ var SdkQueryBuilder = class {
4276
4693
  /** Called again, this adds a tie-breaker rather than replacing the sort. */
4277
4694
  orderBy(column, direction = "asc") {
4278
4695
  const existing = normalizeOrderBy(this.params.orderBy) ?? [];
4279
- this.params.orderBy = [...existing, [column, direction]];
4696
+ this.params.orderBy = [...existing, [sortKeyToString(column), direction]];
4280
4697
  return this;
4281
4698
  }
4282
4699
  limit(count) {
@@ -4308,11 +4725,39 @@ var SdkQueryBuilder = class {
4308
4725
  async find() {
4309
4726
  return this.client.find(this.params);
4310
4727
  }
4728
+ /**
4729
+ * Page through everything this query matches, one row at a time.
4730
+ *
4731
+ * `.limit()` on the builder becomes the page size, so the ceiling on a
4732
+ * single `find()` is not a ceiling on what the query can read.
4733
+ */
4734
+ iterate(options) {
4735
+ return this.client.iterate({
4736
+ ...this.params,
4737
+ ...this.params.limit !== void 0 && { pageSize: this.params.limit },
4738
+ ...options
4739
+ });
4740
+ }
4741
+ /** Collect everything this query matches into one array. */
4742
+ findAll(options) {
4743
+ return this.client.findAll({
4744
+ ...this.params,
4745
+ ...this.params.limit !== void 0 && { pageSize: this.params.limit },
4746
+ ...options
4747
+ });
4748
+ }
4749
+ /**
4750
+ * Count the records matching this query.
4751
+ *
4752
+ * This used to answer `0` when the client had no `count` — a number, from a
4753
+ * source that had not counted anything, indistinguishable from an empty
4754
+ * collection. It now does what the client does, which on a source that
4755
+ * cannot count is throw and say so.
4756
+ */
4311
4757
  async count() {
4312
- return this.client.count ? this.client.count(this.params) : 0;
4758
+ return this.client.count(this.params);
4313
4759
  }
4314
4760
  listen(onUpdate, onError) {
4315
- if (!this.client.listen) throw new Error("Listen is only available when the driver supports realtime.");
4316
4761
  return this.client.listen(this.params, onUpdate, onError);
4317
4762
  }
4318
4763
  };
@@ -4340,6 +4785,14 @@ function toSdkCollectionClient(snap, slug = "collection") {
4340
4785
  const s = await snap.findById(id);
4341
4786
  return s ? entityToRow(s) : void 0;
4342
4787
  },
4788
+ async get(id) {
4789
+ const s = await snap.findById(id);
4790
+ if (!s) throw new RebaseApiError(`No record with id ${JSON.stringify(String(id))} in "${slug}".`, {
4791
+ status: 404,
4792
+ code: "NOT_FOUND"
4793
+ });
4794
+ return entityToRow(s);
4795
+ },
4343
4796
  async create(data, id) {
4344
4797
  return entityToRow(await snap.create(data, id));
4345
4798
  },
@@ -4370,12 +4823,12 @@ function toSdkCollectionClient(snap, slug = "collection") {
4370
4823
  if (!snap.deleteMany) throw new Error("Bulk deletes are not supported by this collection's data source. Fall back to delete() per record.");
4371
4824
  await snap.deleteMany(ids);
4372
4825
  },
4373
- count: snap.count ? (params) => snap.count(params) : void 0,
4826
+ count: snap.count ? (params) => snap.count(params) : unsupportedMethod(noCount(slug)),
4374
4827
  listen: snap.listen ? (params, onUpdate, onError) => snap.listen(params, (res) => onUpdate({
4375
4828
  data: res.data.map(entityToRow),
4376
4829
  meta: res.meta
4377
- }), onError) : void 0,
4378
- listenById: snap.listenById ? (id, onUpdate, onError) => snap.listenById(id, (s) => onUpdate(s ? entityToRow(s) : void 0), onError) : void 0,
4830
+ }), onError) : unsupportedMethod(noRealtime(slug)),
4831
+ listenById: snap.listenById ? (id, onUpdate, onError) => snap.listenById(id, (s) => onUpdate(s ? entityToRow(s) : void 0), onError) : unsupportedMethod(noRealtime(slug)),
4379
4832
  where(columnOrCondition, operator, value) {
4380
4833
  const builder = new SdkQueryBuilder(client);
4381
4834
  if (typeof columnOrCondition === "object") return builder.where(columnOrCondition);
@@ -4419,7 +4872,7 @@ function wrapAsSdkData(entityData) {
4419
4872
  * Build a flat {@link RebaseSdkData} from a `DataDriver`.
4420
4873
  *
4421
4874
  * This is the developer-facing SDK data layer used by backend framework
4422
- * callbacks & scripts (`context.data` / `rebase.data`). It returns flat rows —
4875
+ * callbacks & scripts (`context.data` / `rebase.dataAsAdmin`). It returns flat rows —
4423
4876
  * identical in shape to the frontend SDK client, down to how a relation is
4424
4877
  * served: a foreign key stays a foreign key, and a relation named in `include`
4425
4878
  * arrives as the target's own columns. The `{ __type: "relation" }` envelope is
@@ -4474,6 +4927,6 @@ function buildRoutedRebaseData({ defaultData, sources, resolveKey }) {
4474
4927
  } });
4475
4928
  }
4476
4929
  //#endregion
4477
- export { GeoPoint as A, ListLimitError as C, isAnonymousUid as D, ANONYMOUS_USER_ID as E, RebaseApiError as M, RebaseClientError as N, EntityReference as O, toSnakeCase as S, resolveClientListLimit as T, fieldKeyForColumn as _, deserializeLogicalCondition as a, buildCompositeId as b, collectAllPages as c, normalizeOrderBy as d, serializeOrderBy as f, getEffectiveSecurityRules as g, resolveDataSource as h, deserializeFilter as i, Vector as j, EntityRelation as k, paginateFind as l, createDataSourceRegistry as m, buildSdkData as n, serializeFilter as o, CollectionRegistry as p, UnknownFilterOperatorError as r, serializeLogicalCondition as s, buildRoutedRebaseData as t, resolveFindWindow as u, findRelation as v, MAX_LIST_LIMIT as w, resolvePrimaryKeys as x, resolveCollectionRelations as y };
4930
+ export { ANONYMOUS_USER_ID as A, buildCompositeId as C, ListLimitError as D, toSnakeCase as E, Vector as F, RebaseApiError as I, RebaseClientError as L, EntityReference as M, EntityRelation as N, MAX_LIST_LIMIT as O, GeoPoint as P, isUnsupported as R, resolveCollectionRelations as S, suggestNearMiss as T, getEffectiveSecurityRules as _, deserializeLogicalCondition as a, getTableName as b, collectAllPages as c, normalizeOrderBy as d, serializeOrderBy as f, resolveDataSource as g, createDataSourceRegistry as h, deserializeFilter as i, isAnonymousUid as j, resolveClientListLimit as k, paginateFind as l, CollectionRegistry as m, buildSdkData as n, serializeFilter as o, defaultUsersCollection as p, UnknownFilterOperatorError as r, serializeLogicalCondition as s, buildRoutedRebaseData as t, resolveFindWindow as u, fieldKeyForColumn as v, resolvePrimaryKeys as w, isRelationRequired as x, findRelation as y, unsupportedMethod as z };
4478
4931
 
4479
- //# sourceMappingURL=src-C9gKj23J.js.map
4932
+ //# sourceMappingURL=src-Dq-I3Ybx.js.map