@rebasepro/server 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +1 -1
  2. package/bin/rebase-server.js +4 -2
  3. package/dist/{GCSStorageController-CjrA4PMo.js → GCSStorageController-BSiP1c-f.js} +22 -8
  4. package/dist/GCSStorageController-BSiP1c-f.js.map +1 -0
  5. package/dist/{S3StorageController-B6pKDNVj.js → S3StorageController-CAwFRgjV.js} +19 -7
  6. package/dist/S3StorageController-CAwFRgjV.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +92 -1
  8. package/dist/api/errors.d.ts +9 -0
  9. package/dist/api/live-schema-routes.d.ts +38 -8
  10. package/dist/api/logs-routes.d.ts +39 -1
  11. package/dist/api/openapi-generator.d.ts +17 -0
  12. package/dist/api/rest/api-generator.d.ts +44 -10
  13. package/dist/api/rest/write-validation.d.ts +2 -2
  14. package/dist/api/types.d.ts +17 -1
  15. package/dist/{ast-schema-editor-Mvr50v_S.js → ast-schema-editor-CWqS_sLJ.js} +309 -11
  16. package/dist/ast-schema-editor-CWqS_sLJ.js.map +1 -0
  17. package/dist/auth/access.d.ts +105 -0
  18. package/dist/auth/adapter-middleware.d.ts +2 -1
  19. package/dist/auth/address-ownership.d.ts +16 -1
  20. package/dist/auth/admin-roles-route.d.ts +4 -2
  21. package/dist/auth/admin-roles.d.ts +17 -20
  22. package/dist/auth/admin-users-route.d.ts +1 -0
  23. package/dist/auth/api-keys/api-key-middleware.d.ts +56 -55
  24. package/dist/auth/api-keys/api-key-routes.d.ts +41 -11
  25. package/dist/auth/api-keys/api-key-store.d.ts +31 -8
  26. package/dist/auth/api-keys/api-key-types.d.ts +14 -16
  27. package/dist/auth/api-keys/http-operation.d.ts +19 -0
  28. package/dist/auth/api-keys/index.d.ts +11 -11
  29. package/dist/auth/api-keys/key-grant.d.ts +41 -0
  30. package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
  31. package/dist/auth/auth-hooks.d.ts +46 -7
  32. package/dist/auth/builtin-auth-adapter.d.ts +8 -0
  33. package/dist/auth/cookie-utils.d.ts +7 -0
  34. package/dist/auth/deliverable-address.d.ts +6 -0
  35. package/dist/auth/email-change-routes.d.ts +41 -0
  36. package/dist/auth/expired-token-sweep.d.ts +67 -0
  37. package/dist/auth/impersonation.d.ts +110 -0
  38. package/dist/auth/index.d.ts +4 -2
  39. package/dist/auth/interfaces.d.ts +110 -59
  40. package/dist/auth/jwt.d.ts +49 -3
  41. package/dist/auth/magic-link-routes.d.ts +2 -6
  42. package/dist/auth/mfa-routes.d.ts +2 -9
  43. package/dist/auth/middleware.d.ts +17 -5
  44. package/dist/auth/otp-routes.d.ts +2 -6
  45. package/dist/auth/passwordless-signup.d.ts +27 -0
  46. package/dist/auth/platform-token.d.ts +122 -0
  47. package/dist/auth/rate-limiter.d.ts +41 -0
  48. package/dist/auth/routes.d.ts +45 -0
  49. package/dist/auth/scope-routes.d.ts +22 -0
  50. package/dist/auth/session-routes.d.ts +11 -6
  51. package/dist/auth/token-revocation.d.ts +50 -1
  52. package/dist/auth/verify-credential.d.ts +28 -0
  53. package/dist/{auth-B-GIMpDG.js → auth-DMLngxn_.js} +2159 -569
  54. package/dist/auth-DMLngxn_.js.map +1 -0
  55. package/dist/backend-DTAOsLQc.js.map +1 -1
  56. package/dist/backup/backup-common.d.ts +10 -0
  57. package/dist/backup/backup-routes.d.ts +24 -4
  58. package/dist/backup/backup-schedule.d.ts +33 -0
  59. package/dist/backup/backup-storage.d.ts +14 -0
  60. package/dist/backup/index.d.ts +2 -0
  61. package/dist/backup-CN0s50D2.js +444 -0
  62. package/dist/backup-CN0s50D2.js.map +1 -0
  63. package/dist/boot/bundle.d.ts +19 -0
  64. package/dist/boot/env.d.ts +49 -4
  65. package/dist/boot/security-headers.d.ts +26 -0
  66. package/dist/boot/static-routing.d.ts +56 -0
  67. package/dist/collection_patch-BRu-BvDv.js +472 -0
  68. package/dist/collection_patch-BRu-BvDv.js.map +1 -0
  69. package/dist/{contract-routes-CbFjuBwa.js → contract-routes-fz8i4pxs.js} +17 -4
  70. package/dist/contract-routes-fz8i4pxs.js.map +1 -0
  71. package/dist/cron/cron-scheduler.d.ts +25 -20
  72. package/dist/cron/cron-store.d.ts +6 -2
  73. package/dist/{cron-loader-DfTj2Hbi.js → cron-loader-CwaANlOG.js} +4 -4
  74. package/dist/cron-loader-CwaANlOG.js.map +1 -0
  75. package/dist/{cron-routes-eE8nif_b.js → cron-routes-Bc-SB0Se.js} +10 -7
  76. package/dist/cron-routes-Bc-SB0Se.js.map +1 -0
  77. package/dist/{cron-scheduler-B0pLfAix.js → cron-scheduler-CYQgco86.js} +52 -34
  78. package/dist/cron-scheduler-CYQgco86.js.map +1 -0
  79. package/dist/{cron-store-TcoGz-xS.js → cron-store-D2Q9-Aco.js} +10 -15
  80. package/dist/cron-store-D2Q9-Aco.js.map +1 -0
  81. package/dist/{ddl-bootstrap-C6mo0Kmz.js → ddl-bootstrap-BaqMSa4Y.js} +2 -2
  82. package/dist/{ddl-bootstrap-C6mo0Kmz.js.map → ddl-bootstrap-BaqMSa4Y.js.map} +1 -1
  83. package/dist/email/index.d.ts +2 -2
  84. package/dist/email/templates.d.ts +22 -0
  85. package/dist/email/types.d.ts +26 -0
  86. package/dist/env.d.ts +1 -2
  87. package/dist/{errors-DWsX4yTd.js → errors-D6_y86c5.js} +102 -8
  88. package/dist/errors-D6_y86c5.js.map +1 -0
  89. package/dist/{function-loader-xnbDAPfa.js → function-loader-D7o5Epjj.js} +2 -2
  90. package/dist/{function-loader-xnbDAPfa.js.map → function-loader-D7o5Epjj.js.map} +1 -1
  91. package/dist/{function-routes-Chet4-lB.js → function-routes-CaNG4waN.js} +24 -12
  92. package/dist/function-routes-CaNG4waN.js.map +1 -0
  93. package/dist/functions/context.d.ts +17 -6
  94. package/dist/functions/guards.d.ts +22 -5
  95. package/dist/functions/index.d.ts +2 -2
  96. package/dist/functions/index.js +90 -36
  97. package/dist/functions/index.js.map +1 -1
  98. package/dist/{history-recorder-B4MpJfJK.js → history-recorder-Nr8zLvoU.js} +4 -4
  99. package/dist/{history-recorder-B4MpJfJK.js.map → history-recorder-Nr8zLvoU.js.map} +1 -1
  100. package/dist/{history-store-BhxWOuz9.js → history-store-rcAm_xFR.js} +2 -2
  101. package/dist/{history-store-BhxWOuz9.js.map → history-store-rcAm_xFR.js.map} +1 -1
  102. package/dist/index.d.ts +8 -2
  103. package/dist/index.es.js +3084 -753
  104. package/dist/index.es.js.map +1 -1
  105. package/dist/init/health.d.ts +17 -2
  106. package/dist/init/shutdown.d.ts +10 -0
  107. package/dist/init.d.ts +54 -0
  108. package/dist/{jobs-CazMYhyy.js → jobs-DqYNfquG.js} +5 -5
  109. package/dist/{jobs-CazMYhyy.js.map → jobs-DqYNfquG.js.map} +1 -1
  110. package/dist/{jwt-DnQHNFCl.js → jwt-R6bSPMjk.js} +39 -15
  111. package/dist/{jwt-DnQHNFCl.js.map → jwt-R6bSPMjk.js.map} +1 -1
  112. package/dist/{keys-CogCQpxG.js → keys-GAVZqbqx.js} +3 -17
  113. package/dist/{keys-CogCQpxG.js.map → keys-GAVZqbqx.js.map} +1 -1
  114. package/dist/{logger-DO2PZc4i.js → logger-D-S-hO5e.js} +26 -3
  115. package/dist/logger-D-S-hO5e.js.map +1 -0
  116. package/dist/{logs-routes-Bj4TYYUl.js → logs-routes-DAdv37GI.js} +48 -8
  117. package/dist/logs-routes-DAdv37GI.js.map +1 -0
  118. package/dist/mcp/consent-page.d.ts +1 -1
  119. package/dist/mcp/mcp-routes.d.ts +7 -0
  120. package/dist/mcp/mcp-tools.d.ts +15 -9
  121. package/dist/mcp/oauth-metadata.d.ts +21 -16
  122. package/dist/mcp/oauth-routes.d.ts +7 -1
  123. package/dist/{openapi-generator-O_O24MAT.js → openapi-generator-DAq_XVDu.js} +104 -13
  124. package/dist/openapi-generator-DAq_XVDu.js.map +1 -0
  125. package/dist/{proxy-Czngl3p9.js → proxy-qRlqeUmO.js} +2 -2
  126. package/dist/{proxy-Czngl3p9.js.map → proxy-qRlqeUmO.js.map} +1 -1
  127. package/dist/{query-parser-DGRVFNM3.js → query-parser-BgiKJKvc.js} +6 -56
  128. package/dist/query-parser-BgiKJKvc.js.map +1 -0
  129. package/dist/{request-timeout-C_4C2BeR.js → request-timeout-DgH7j8qO.js} +3 -3
  130. package/dist/{request-timeout-C_4C2BeR.js.map → request-timeout-DgH7j8qO.js.map} +1 -1
  131. package/dist/schema-edit/apply-schema-change.d.ts +63 -3
  132. package/dist/schema-edit/project-root.d.ts +3 -2
  133. package/dist/schema-edit/remote-source.d.ts +9 -4
  134. package/dist/{schema-editor-routes-C5-lh_jO.js → schema-editor-routes-oIyuWl3L.js} +12 -7
  135. package/dist/schema-editor-routes-oIyuWl3L.js.map +1 -0
  136. package/dist/serve-spa.d.ts +58 -0
  137. package/dist/services/routed-realtime-service.d.ts +11 -0
  138. package/dist/soft-delete-params-BWPilMPF.js +59 -0
  139. package/dist/soft-delete-params-BWPilMPF.js.map +1 -0
  140. package/dist/{src-vkcwKXbT.js → src-CatHFUym.js} +439 -20
  141. package/dist/src-CatHFUym.js.map +1 -0
  142. package/dist/{src-pmvW7BFx.js → src-I3aG1PcY.js} +252 -70
  143. package/dist/src-I3aG1PcY.js.map +1 -0
  144. package/dist/storage/GCSStorageController.d.ts +2 -0
  145. package/dist/storage/LocalStorageController.d.ts +2 -0
  146. package/dist/storage/S3StorageController.d.ts +2 -0
  147. package/dist/storage/index.d.ts +2 -2
  148. package/dist/storage/property-limits.d.ts +41 -6
  149. package/dist/storage/request-keys.d.ts +15 -0
  150. package/dist/storage/requested-object.d.ts +74 -0
  151. package/dist/storage/routes.d.ts +36 -18
  152. package/dist/storage/tus-handler.d.ts +30 -5
  153. package/dist/storage/types.d.ts +19 -0
  154. package/dist/types-BfKcm9do.js.map +1 -1
  155. package/dist/utils/logger.d.ts +12 -0
  156. package/package.json +5 -5
  157. package/dist/GCSStorageController-CjrA4PMo.js.map +0 -1
  158. package/dist/S3StorageController-B6pKDNVj.js.map +0 -1
  159. package/dist/admin-roles-vYdp_Pil.js +0 -36
  160. package/dist/admin-roles-vYdp_Pil.js.map +0 -1
  161. package/dist/admin_block-DxKLmdiv.js +0 -206
  162. package/dist/admin_block-DxKLmdiv.js.map +0 -1
  163. package/dist/ast-schema-editor-Mvr50v_S.js.map +0 -1
  164. package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
  165. package/dist/auth-B-GIMpDG.js.map +0 -1
  166. package/dist/backup-D7YR94N3.js +0 -253
  167. package/dist/backup-D7YR94N3.js.map +0 -1
  168. package/dist/contract-routes-CbFjuBwa.js.map +0 -1
  169. package/dist/cron-loader-DfTj2Hbi.js.map +0 -1
  170. package/dist/cron-routes-eE8nif_b.js.map +0 -1
  171. package/dist/cron-scheduler-B0pLfAix.js.map +0 -1
  172. package/dist/cron-store-TcoGz-xS.js.map +0 -1
  173. package/dist/errors-DWsX4yTd.js.map +0 -1
  174. package/dist/function-routes-Chet4-lB.js.map +0 -1
  175. package/dist/logger-DO2PZc4i.js.map +0 -1
  176. package/dist/logs-routes-Bj4TYYUl.js.map +0 -1
  177. package/dist/openapi-generator-O_O24MAT.js.map +0 -1
  178. package/dist/query-parser-DGRVFNM3.js.map +0 -1
  179. package/dist/schema-editor-routes-C5-lh_jO.js.map +0 -1
  180. package/dist/src-pmvW7BFx.js.map +0 -1
  181. package/dist/src-vkcwKXbT.js.map +0 -1
@@ -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 { A as NULL_OPS, C as isPostgresCollectionConfig, D as ALL_WHERE_FILTER_OPS, E as getDataSourceCapabilities, F as toCanonicalOp, M as isRelationAggregateSort, O as CANONICAL_TO_REST, P as sortKeyToString, S as getDeclaredSubcollections, b as rewriteLegacyRlsFunctions, f as resolveResourceRefs, j as REST_TO_CANONICAL, k as LIST_OPS, w as isRelationalCollectionConfig } from "./src-vkcwKXbT.js";
6
+ import { B as rewriteLegacyRlsFunctions, H as getDeclaredSubcollections, J as CANONICAL_TO_REST, K as getDataSourceCapabilities, M as resolveResourceRefs, Q as isRelationAggregateSort, U as isPostgresCollectionConfig, V as getCollectionDataPath, W as isRelationalCollectionConfig, X as NULL_OPS, Y as LIST_OPS, Z as REST_TO_CANONICAL, et as sortKeyToString, q as ALL_WHERE_FILTER_OPS, tt as toCanonicalOp } from "./src-CatHFUym.js";
7
7
  //#region ../types/src/errors.ts
8
8
  /**
9
9
  * The single error type thrown across the entire Rebase client surface —
@@ -4018,6 +4018,13 @@ var CollectionRegistry = class {
4018
4018
  }
4019
4019
  collectionsByTableName = /* @__PURE__ */ new Map();
4020
4020
  collectionsBySlug = /* @__PURE__ */ new Map();
4021
+ /**
4022
+ * Root collections whose driver stores them under a `path` other than
4023
+ * their slug, by that path. A list, because the path is only unique within
4024
+ * a data source: two collections in different databases may both be stored
4025
+ * at `customer`.
4026
+ */
4027
+ collectionsByDataPath = /* @__PURE__ */ new Map();
4021
4028
  rootCollections = [];
4022
4029
  cachedCollectionsList = null;
4023
4030
  rawCollectionsByTableName = /* @__PURE__ */ new Map();
@@ -4042,6 +4049,7 @@ var CollectionRegistry = class {
4042
4049
  reset() {
4043
4050
  this.collectionsByTableName.clear();
4044
4051
  this.collectionsBySlug.clear();
4052
+ this.collectionsByDataPath.clear();
4045
4053
  this.rootCollections = [];
4046
4054
  this.cachedCollectionsList = null;
4047
4055
  this.rawCollectionsByTableName.clear();
@@ -4074,6 +4082,7 @@ var CollectionRegistry = class {
4074
4082
  this.collectionsByTableName.set(getTableName(normalized), normalized);
4075
4083
  this.rawCollectionsByTableName.set(getTableName(raw), raw);
4076
4084
  if (normalized.slug) this.collectionsBySlug.set(normalized.slug, normalized);
4085
+ this.indexDataPath(normalized);
4077
4086
  if (raw.slug) this.rawCollectionsBySlug.set(raw.slug, raw);
4078
4087
  });
4079
4088
  normalizedCollections.forEach((c) => {
@@ -4091,6 +4100,19 @@ var CollectionRegistry = class {
4091
4100
  this.rootCollections.push(collection);
4092
4101
  this.rawRootCollections.push(raw);
4093
4102
  this._registerRecursively(collection, raw);
4103
+ const registered = this.collectionsByTableName.get(getTableName(collection));
4104
+ if (registered) this.indexDataPath(registered);
4105
+ }
4106
+ /**
4107
+ * Index a root collection by the path its driver stores it under, when
4108
+ * that is not its slug. Only roots: a subcollection's `path` is relative to
4109
+ * the record it hangs off, so it names nothing on its own.
4110
+ */
4111
+ indexDataPath(collection) {
4112
+ const dataPath = getCollectionDataPath(collection);
4113
+ if (!dataPath || dataPath === collection.slug) return;
4114
+ const indexed = this.collectionsByDataPath.get(dataPath) ?? [];
4115
+ if (!indexed.includes(collection)) this.collectionsByDataPath.set(dataPath, [...indexed, collection]);
4094
4116
  }
4095
4117
  _registerRecursively(collection, rawCollection) {
4096
4118
  if (this.collectionsByTableName.has(getTableName(collection))) return;
@@ -4144,7 +4166,24 @@ var CollectionRegistry = class {
4144
4166
  }
4145
4167
  return newProperty;
4146
4168
  }
4147
- get(path) {
4169
+ /**
4170
+ * The collection registered under `path`: by slug, by slug with hyphens
4171
+ * for underscores, by table name, and last by the `path` a root Firestore
4172
+ * or MongoDB collection declares for its driver.
4173
+ *
4174
+ * One string can name two collections. Declaring `slug: "fs_diagnosis",
4175
+ * path: "diagnosis"` is how a Firestore collection sits beside a Postgres
4176
+ * collection whose slug is `diagnosis` — and a reference read back from
4177
+ * Firestore carries `diagnosis`. The order above settles it in favour of the
4178
+ * slug unless `preferredDriver` is given: then the first collection whose
4179
+ * data source or engine is `preferredDriver` wins. Pass a reference's
4180
+ * `driver`, or the data source of the record the path was read from.
4181
+ */
4182
+ get(path, preferredDriver) {
4183
+ if (preferredDriver) {
4184
+ const preferred = this.candidatesFor(path).find((collection) => collection.dataSource === preferredDriver || collection.engine === preferredDriver);
4185
+ if (preferred) return preferred;
4186
+ }
4148
4187
  const bySlug = this.collectionsBySlug.get(path);
4149
4188
  if (bySlug) return bySlug;
4150
4189
  if (path.includes("-")) {
@@ -4152,7 +4191,84 @@ var CollectionRegistry = class {
4152
4191
  const byNormalized = this.collectionsBySlug.get(normalized);
4153
4192
  if (byNormalized) return byNormalized;
4154
4193
  }
4155
- return this.collectionsByTableName.get(path);
4194
+ const byTableName = this.collectionsByTableName.get(path);
4195
+ if (byTableName) return byTableName;
4196
+ return this.collectionsByDataPath.get(path)?.[0];
4197
+ }
4198
+ /** Every collection {@link get} could answer `path` with, in its order. */
4199
+ candidatesFor(path) {
4200
+ const candidates = [
4201
+ this.collectionsBySlug.get(path),
4202
+ path.includes("-") ? this.collectionsBySlug.get(path.replace(/-/g, "_")) : void 0,
4203
+ this.collectionsByTableName.get(path),
4204
+ ...this.collectionsByDataPath.get(path) ?? []
4205
+ ];
4206
+ return candidates.filter((collection, index) => collection !== void 0 && candidates.indexOf(collection) === index);
4207
+ }
4208
+ /**
4209
+ * The path a collection's rows are stored under, for the path the admin
4210
+ * addresses it by.
4211
+ *
4212
+ * The admin addresses a collection by its slug — in routes, in
4213
+ * `data.collection(...)`, in the `path` of every entity it lists — because
4214
+ * the slug is what is unique. A Firestore or MongoDB collection may declare
4215
+ * a `path` of its own ({@link getCollectionDataPath}), and its driver has to
4216
+ * be handed that one, under every record and subcollection too:
4217
+ * `fs_diagnosis/abc/locales` is stored at `diagnosis/abc/locales`.
4218
+ *
4219
+ * A path that names no registered collection, or runs only through
4220
+ * collections stored under their slugs, comes back unchanged.
4221
+ */
4222
+ resolveDataPath(path) {
4223
+ let resolved;
4224
+ const exact = this.get(path);
4225
+ if (exact) resolved = {
4226
+ collections: [exact],
4227
+ entityIds: []
4228
+ };
4229
+ else try {
4230
+ resolved = this.resolvePathToCollections(path);
4231
+ } catch {
4232
+ return path;
4233
+ }
4234
+ const { collections, entityIds } = resolved;
4235
+ if (collections.every((collection) => getCollectionDataPath(collection) === collection.slug)) return path;
4236
+ return collections.map((collection, index) => index < entityIds.length ? `${getCollectionDataPath(collection)}/${entityIds[index]}` : getCollectionDataPath(collection)).join("/");
4237
+ }
4238
+ /**
4239
+ * The path the admin addresses a collection by, for a path its rows are
4240
+ * stored under: the inverse of {@link resolveDataPath}, for a reference
4241
+ * read back from its driver.
4242
+ *
4243
+ * The root is the longest leading run of segments naming a collection, and
4244
+ * becomes its slug when the run is where that collection is stored. Each
4245
+ * subcollection after a record id is matched by where it is stored too. A
4246
+ * path that already names its collections by slug comes back unchanged.
4247
+ *
4248
+ * `preferredDriver` decides between a collection stored at the path and one
4249
+ * whose slug it is, as in {@link get}.
4250
+ */
4251
+ resolveCollectionPath(path, preferredDriver) {
4252
+ const segments = path.split("/").filter(Boolean);
4253
+ for (let length = segments.length; length > 0; length--) {
4254
+ const prefix = segments.slice(0, length).join("/");
4255
+ const root = this.get(prefix, preferredDriver);
4256
+ if (!root) continue;
4257
+ const translated = [getCollectionDataPath(root) === prefix ? root.slug : prefix];
4258
+ let current = root;
4259
+ let rest = segments.slice(length);
4260
+ while (rest.length >= 2) {
4261
+ const [entityId, storedAt, ...after] = rest;
4262
+ const child = getSubcollections(current).find((subcollection) => getCollectionDataPath(subcollection) === storedAt);
4263
+ if (!child) break;
4264
+ translated.push(entityId, child.slug);
4265
+ current = child;
4266
+ rest = after;
4267
+ }
4268
+ const collectionPath = [...translated, ...rest].join("/");
4269
+ return collectionPath === segments.join("/") ? path : collectionPath;
4270
+ }
4271
+ return path;
4156
4272
  }
4157
4273
  /**
4158
4274
  * Gets the pristine, un-normalized collection exactly as it was provided.
@@ -4200,29 +4316,41 @@ var CollectionRegistry = class {
4200
4316
  }
4201
4317
  /**
4202
4318
  * Resolves a multi-segment path like "products/123/locales" and returns
4203
- * information about the collections and entity IDs along the path
4319
+ * information about the collections and entity IDs along the path.
4320
+ *
4321
+ * A slug may contain slashes (`content/de-DE/podcasts`), so the root is
4322
+ * the longest leading run of segments naming a registered collection, and
4323
+ * each subcollection is matched the same way among its parent's.
4324
+ *
4325
+ * @param options.allowRecordPath accept a path that ends at a record
4326
+ * (`…/{id}`) and resolve it to the collection holding that record, with the
4327
+ * id last in `entityIds`. Without it such a path is an error. Only the
4328
+ * registry can tell the two shapes apart, because only it knows where each
4329
+ * slug ends.
4204
4330
  */
4205
- resolvePathToCollections(path) {
4331
+ resolvePathToCollections(path, options) {
4206
4332
  const pathSegments = path.split("/").filter((p) => p);
4207
4333
  if (pathSegments.length === 0) throw new Error(`Invalid path: ${path}`);
4208
- if (pathSegments.length % 2 !== 1) throw new Error(`Invalid collection path: ${path}. It must have an odd number of segments.`);
4209
- const collections = [];
4334
+ const root = splitAtLeadingCollection(pathSegments, (candidate) => this.get(candidate));
4335
+ if (!root) throw new Error(`Unknown collection path or slug: ${path}`);
4336
+ let currentCollection = root.collection;
4337
+ const collections = [currentCollection];
4210
4338
  const entityIds = [];
4211
- let currentCollection = this.get(pathSegments[0]);
4212
- if (!currentCollection) throw new Error(`Unknown collection path or slug: ${pathSegments[0]}`);
4213
- collections.push(currentCollection);
4214
- for (let i = 1; i < pathSegments.length; i += 2) {
4215
- const entityId = pathSegments[i];
4339
+ let rest = root.rest;
4340
+ while (rest.length > 0) {
4341
+ const [entityId, ...afterEntity] = rest;
4216
4342
  entityIds.push(entityId);
4217
- if (i + 1 < pathSegments.length) {
4218
- const subcollectionSlug = pathSegments[i + 1];
4219
- const subcollections = getSubcollections(currentCollection);
4220
- if (!subcollections || subcollections.length === 0) throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);
4221
- const subcollection = subcollections.find((c) => c.slug === subcollectionSlug);
4222
- if (!subcollection) throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
4223
- currentCollection = this.normalizeCollection(subcollection);
4224
- collections.push(currentCollection);
4343
+ if (afterEntity.length === 0) {
4344
+ if (options?.allowRecordPath) break;
4345
+ throw new Error(`Invalid collection path: ${path}. It ends at the record '${entityId}' of '${currentCollection.slug}', not at a collection.`);
4225
4346
  }
4347
+ const subcollections = getSubcollections(currentCollection);
4348
+ if (!subcollections || subcollections.length === 0) throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);
4349
+ const child = splitAtLeadingCollection(afterEntity, (candidate) => subcollections.find((c) => c.slug === candidate));
4350
+ if (!child) throw new Error(`Subcollection '${afterEntity[0]}' not found in ${currentCollection.slug}`);
4351
+ currentCollection = this.normalizeCollection(child.collection);
4352
+ collections.push(currentCollection);
4353
+ rest = child.rest;
4226
4354
  }
4227
4355
  return {
4228
4356
  collections,
@@ -4231,6 +4359,26 @@ var CollectionRegistry = class {
4231
4359
  };
4232
4360
  }
4233
4361
  };
4362
+ /**
4363
+ * Split path segments at the collection they start with.
4364
+ *
4365
+ * A slug may contain slashes, and several drivers need it to: a Firestore
4366
+ * collection partitioned by locale is declared as `content/de-DE/podcasts`,
4367
+ * and that string is its *name*. So the collection a path starts with is not
4368
+ * its first segment but the longest run of whole leading segments that names
4369
+ * one, and what follows it is `entityId/subcollection/…`.
4370
+ *
4371
+ * Whole segments only, so `content` never matches the start of `contents/1`.
4372
+ */
4373
+ function splitAtLeadingCollection(segments, find) {
4374
+ for (let length = segments.length; length > 0; length--) {
4375
+ const collection = find(segments.slice(0, length).join("/"));
4376
+ if (collection) return {
4377
+ collection,
4378
+ rest: segments.slice(length)
4379
+ };
4380
+ }
4381
+ }
4234
4382
  //#endregion
4235
4383
  //#region ../common/src/collections/engine-support.ts
4236
4384
  /**
@@ -4785,23 +4933,6 @@ function includePaths(tree, prefix = "") {
4785
4933
  }
4786
4934
  return out;
4787
4935
  }
4788
- /**
4789
- * The relation names an `include` asks for at the top level.
4790
- *
4791
- * `["author", "comments.author"]` and `{author: true, comments: {...}}` both
4792
- * answer `["author", "comments"]` — a *hop*, not a path, because the only
4793
- * consumer is `?fields=`, which names keys on the row being returned and a
4794
- * nested relation is not one of those.
4795
- *
4796
- * Derived rather than passed: `include` has four spellings and three of them
4797
- * are not a `string[]`, so every consumer that wants the plain names either
4798
- * calls this or reimplements the flattening.
4799
- */
4800
- function topLevelIncludeNames(spec) {
4801
- const normalized = normalizeInclude(spec);
4802
- if (!normalized) return [];
4803
- return Object.keys(normalized.tree);
4804
- }
4805
4936
  /** Whether any node in the tree carries per-relation options. */
4806
4937
  function hasOptions(tree) {
4807
4938
  return Object.values(tree).some((node) => node.limit !== void 0 || node.where !== void 0 || node.logical !== void 0 || node.orderBy !== void 0 || node.fields !== void 0 || hasOptions(node.children));
@@ -6110,7 +6241,7 @@ function inlineRelationRefs(row) {
6110
6241
  }
6111
6242
  return out ?? row;
6112
6243
  }
6113
- function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6244
+ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel, storedPath = () => slug) {
6114
6245
  const accessor = {
6115
6246
  async find(params) {
6116
6247
  const filter = params?.where ? deserializeFilter(params.where) : void 0;
@@ -6120,7 +6251,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6120
6251
  const startAfter = cursor ? cursorToStartAfter(cursor) : void 0;
6121
6252
  const probeLimit = startAfter ? limit + 1 : limit;
6122
6253
  const fetchService = driver.restFetchService;
6123
- const fetched = fetchService ? await fetchService.fetchCollectionForRest(slug, {
6254
+ const fetched = fetchService ? await fetchService.fetchCollectionForRest(storedPath(), {
6124
6255
  filter,
6125
6256
  logical: params?.logical,
6126
6257
  limit: probeLimit,
@@ -6131,7 +6262,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6131
6262
  fields: params?.fields,
6132
6263
  distinct: params?.distinct
6133
6264
  }, params?.include) : await driver.fetchCollection({
6134
- path: slug,
6265
+ path: storedPath(),
6135
6266
  limit: probeLimit,
6136
6267
  offset: startAfter ? void 0 : driverOffset,
6137
6268
  startAfter,
@@ -6149,7 +6280,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6149
6280
  let hasMore = seeking ? fetched.length > limit : rows.length >= limit;
6150
6281
  if (driver.count) {
6151
6282
  total = await driver.count({
6152
- path: slug,
6283
+ path: storedPath(),
6153
6284
  filter,
6154
6285
  logical: params?.logical,
6155
6286
  searchString: params?.searchString
@@ -6157,7 +6288,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6157
6288
  if (!seeking) hasMore = offset + rows.length < total;
6158
6289
  }
6159
6290
  const last = rows[rows.length - 1];
6160
- const nextCursor = hasMore && last && driver.restFetchService?.cursorFor ? driver.restFetchService.cursorFor(slug, last, orderBy) : void 0;
6291
+ const nextCursor = hasMore && last && driver.restFetchService?.cursorFor ? driver.restFetchService.cursorFor(storedPath(), last, orderBy) : void 0;
6161
6292
  return {
6162
6293
  data: rows.map((row) => rowToEntity(row, slug, getPks(), toViewModel)),
6163
6294
  meta: {
@@ -6171,23 +6302,39 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6171
6302
  },
6172
6303
  async findById(id) {
6173
6304
  const fetchService = driver.restFetchService;
6174
- const row = fetchService ? await fetchService.fetchOneForRest(slug, id) : await driver.fetchOne({
6175
- path: slug,
6305
+ const row = fetchService ? await fetchService.fetchOneForRest(storedPath(), id) : await driver.fetchOne({
6306
+ path: storedPath(),
6176
6307
  id
6177
6308
  });
6178
6309
  return row ? rowToEntity(row, slug, getPks(), toViewModel) : void 0;
6179
6310
  },
6180
- aggregate: driver.restFetchService?.aggregate ? async (params) => driver.restFetchService.aggregate(slug, {
6181
- aggregates: params.select.map(toDriverAggregate),
6182
- groupBy: params.groupBy,
6183
- filter: params.where ? deserializeFilter(params.where) : void 0,
6184
- logical: params.logical,
6185
- searchString: params.searchString,
6186
- limit: params.limit
6187
- }) : void 0,
6311
+ aggregate: driver.restFetchService?.aggregate ? async (params) => {
6312
+ const limit = (params.groupBy?.length ?? 0) > 0 ? params.limit : void 0;
6313
+ const rows = await driver.restFetchService.aggregate(storedPath(), {
6314
+ aggregates: params.select.map(toDriverAggregate),
6315
+ groupBy: params.groupBy,
6316
+ filter: params.where ? deserializeFilter(params.where) : void 0,
6317
+ logical: params.logical,
6318
+ searchString: params.searchString,
6319
+ limit: limit !== void 0 ? limit + 1 : params.limit,
6320
+ offset: params.offset
6321
+ });
6322
+ if (limit === void 0) return rows;
6323
+ const page = rows.slice(0, limit);
6324
+ const meta = {
6325
+ limit,
6326
+ offset: params.offset ?? 0,
6327
+ hasMore: rows.length > limit
6328
+ };
6329
+ Object.defineProperty(page, "meta", {
6330
+ value: meta,
6331
+ enumerable: false
6332
+ });
6333
+ return page;
6334
+ } : void 0,
6188
6335
  async create(data, id) {
6189
6336
  return rowToEntity(await driver.save({
6190
- path: slug,
6337
+ path: storedPath(),
6191
6338
  values: data,
6192
6339
  id,
6193
6340
  status: "new"
@@ -6195,7 +6342,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6195
6342
  },
6196
6343
  createMany: driver.saveMany ? async (data, options) => {
6197
6344
  return (await driver.saveMany({
6198
- path: slug,
6345
+ path: storedPath(),
6199
6346
  rows: data,
6200
6347
  upsert: options?.upsert,
6201
6348
  onConflict: options?.onConflict
@@ -6203,7 +6350,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6203
6350
  } : void 0,
6204
6351
  async update(id, data) {
6205
6352
  return rowToEntity(await driver.save({
6206
- path: slug,
6353
+ path: storedPath(),
6207
6354
  values: data,
6208
6355
  id,
6209
6356
  status: "existing"
@@ -6212,12 +6359,12 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6212
6359
  async delete(id) {
6213
6360
  return driver.delete({ row: {
6214
6361
  id,
6215
- path: slug
6362
+ path: storedPath()
6216
6363
  } });
6217
6364
  },
6218
6365
  updateMany: driver.updateMany ? async (updates) => {
6219
6366
  return (await driver.updateMany({
6220
- path: slug,
6367
+ path: storedPath(),
6221
6368
  updates: updates.map((u) => ({
6222
6369
  id: u.id,
6223
6370
  values: u.data
@@ -6226,14 +6373,14 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6226
6373
  } : void 0,
6227
6374
  deleteMany: driver.deleteMany ? async (ids) => {
6228
6375
  await driver.deleteMany({
6229
- path: slug,
6376
+ path: storedPath(),
6230
6377
  ids
6231
6378
  });
6232
6379
  } : void 0,
6233
6380
  count: driver.count ? async (params) => {
6234
6381
  const filter = params?.where ? deserializeFilter(params.where) : void 0;
6235
6382
  return driver.count({
6236
- path: slug,
6383
+ path: storedPath(),
6237
6384
  filter,
6238
6385
  logical: params?.logical,
6239
6386
  searchString: params?.searchString
@@ -6243,7 +6390,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6243
6390
  const { limit, offset, driverOffset } = resolveFindWindow(params);
6244
6391
  const normalize = driver.restFetchService ? inlineRelationRefs : (row) => row;
6245
6392
  return driver.listenCollection({
6246
- path: slug,
6393
+ path: storedPath(),
6247
6394
  limit,
6248
6395
  offset: driverOffset,
6249
6396
  filter: params?.where,
@@ -6269,7 +6416,7 @@ function createDriverAccessor(driver, slug, getPks = () => [], toViewModel) {
6269
6416
  listenById: driver.listenOne ? (id, onUpdate, onError) => {
6270
6417
  const normalize = driver.restFetchService ? inlineRelationRefs : (row) => row;
6271
6418
  return driver.listenOne({
6272
- path: slug,
6419
+ path: storedPath(),
6273
6420
  id,
6274
6421
  onUpdate: (entity) => onUpdate(entity ? rowToEntity(normalize(entity), slug, getPks(), toViewModel) : void 0),
6275
6422
  onError
@@ -6338,7 +6485,7 @@ function buildRebaseData(driver, options) {
6338
6485
  function getAccessor(slug) {
6339
6486
  let accessor = cache.get(slug);
6340
6487
  if (!accessor) {
6341
- accessor = createDriverAccessor(driver, slug, () => primaryKeysFor(slug), viewModelFor(slug));
6488
+ accessor = createDriverAccessor(driver, slug, () => primaryKeysFor(slug), viewModelFor(slug), () => options?.resolveDataPath?.(slug) ?? slug);
6342
6489
  cache.set(slug, accessor);
6343
6490
  }
6344
6491
  return accessor;
@@ -6495,6 +6642,31 @@ var SdkQueryBuilder = class {
6495
6642
  }
6496
6643
  };
6497
6644
  /**
6645
+ * Refuse a write option this door cannot honour, by name, before anything is
6646
+ * written.
6647
+ *
6648
+ * The in-process accessor implements the same `SDKCollectionClient` as the HTTP
6649
+ * client, whose `ifMatch` is "Honoured on `update` and `delete`" — and its
6650
+ * writes took no options at all, so `rebase.data.posts.update(id, data, {
6651
+ * ifMatch: staleEtag })` overwrote the row and resolved. A precondition the
6652
+ * caller wrote, dropped without a word, is the worst thing a door can do with
6653
+ * it. The driver's `save` has no precondition and no idempotency store to hand
6654
+ * these to, so they are refused rather than ignored. An `undefined` value is no
6655
+ * option, as it is over HTTP: `etagOf(row)` is `undefined` for a row that
6656
+ * carries no version, and that means "write unconditionally".
6657
+ */
6658
+ function refuseUnhonouredWriteOptions(method, slug, options) {
6659
+ const unsupported = ["ifMatch", "idempotencyKey"].filter((key) => options?.[key]);
6660
+ if (unsupported.length === 0) return;
6661
+ throw new RebaseClientError(`${method}() on "${slug}" in-process (context.data, rebase.data) cannot honour ${unsupported.join(" or ")}: this door has no ${unsupported.includes("ifMatch") ? "precondition check" : "idempotency store"}, and ignoring the option would write as though it had been checked. Drop it here, or send the write through the HTTP client, which honours it.`, {
6662
+ code: "UNSUPPORTED_OPTION",
6663
+ details: {
6664
+ method,
6665
+ options: unsupported
6666
+ }
6667
+ });
6668
+ }
6669
+ /**
6498
6670
  * Wrap a Entity-shaped {@link CollectionAccessor} into a flat
6499
6671
  * {@link SDKCollectionClient}. Every returned record is unwrapped to a flat row
6500
6672
  * so the backend SDK is byte-for-byte the same shape as the frontend client.
@@ -6526,14 +6698,19 @@ function toSdkCollectionClient(snap, slug = "collection") {
6526
6698
  });
6527
6699
  return entityToRow(s);
6528
6700
  },
6529
- async create(data, id) {
6701
+ async create(data, id, options) {
6702
+ refuseUnhonouredWriteOptions("create", slug, options);
6530
6703
  return entityToRow(await snap.create(data, id));
6531
6704
  },
6532
6705
  async createMany(data, options) {
6706
+ refuseUnhonouredWriteOptions("createMany", slug, options);
6533
6707
  if (!Array.isArray(data)) throw new TypeError("createMany expects an array of records.");
6534
6708
  if (data.length === 0) return [];
6535
6709
  if (!snap.createMany) throw new Error("Bulk writes are not supported by this collection's data source. Fall back to create() per record.");
6536
- return (await snap.createMany(data, options)).map(entityToRow);
6710
+ return (await snap.createMany(data, {
6711
+ upsert: options?.upsert,
6712
+ onConflict: options?.onConflict
6713
+ })).map(entityToRow);
6537
6714
  },
6538
6715
  /**
6539
6716
  * One row through the bulk path, because the bulk path is where the
@@ -6545,6 +6722,7 @@ function toSdkCollectionClient(snap, slug = "collection") {
6545
6722
  * one is exactly an upsert of one.
6546
6723
  */
6547
6724
  async upsert(data, options) {
6725
+ refuseUnhonouredWriteOptions("upsert", slug, options);
6548
6726
  if (!snap.createMany) throw new Error("Upsert is not supported by this collection's data source: it needs a bulk write, which this driver does not implement. Fall back to create() or update().");
6549
6727
  const row = (await snap.createMany([data], {
6550
6728
  upsert: true,
@@ -6553,10 +6731,12 @@ function toSdkCollectionClient(snap, slug = "collection") {
6553
6731
  if (!row) throw new Error(`Upsert into "${slug}" returned no row.`);
6554
6732
  return entityToRow(row);
6555
6733
  },
6556
- async update(id, data) {
6734
+ async update(id, data, options) {
6735
+ refuseUnhonouredWriteOptions("update", slug, options);
6557
6736
  return entityToRow(await snap.update(id, data));
6558
6737
  },
6559
- async updateMany(updates) {
6738
+ async updateMany(updates, options) {
6739
+ refuseUnhonouredWriteOptions("updateMany", slug, options);
6560
6740
  if (!Array.isArray(updates)) throw new TypeError("updateMany expects an array of { id, data } entries.");
6561
6741
  if (updates.length === 0) return [];
6562
6742
  if (!snap.updateMany) throw new Error("Bulk updates are not supported by this collection's data source. Fall back to update() per record.");
@@ -6565,10 +6745,12 @@ function toSdkCollectionClient(snap, slug = "collection") {
6565
6745
  data: u.data
6566
6746
  })))).map(entityToRow);
6567
6747
  },
6568
- delete(id) {
6748
+ async delete(id, options) {
6749
+ refuseUnhonouredWriteOptions("delete", slug, options);
6569
6750
  return snap.delete(id);
6570
6751
  },
6571
- async deleteMany(ids) {
6752
+ async deleteMany(ids, options) {
6753
+ refuseUnhonouredWriteOptions("deleteMany", slug, options);
6572
6754
  if (!Array.isArray(ids)) throw new TypeError("deleteMany expects an array of ids.");
6573
6755
  if (ids.length === 0) return;
6574
6756
  if (!snap.deleteMany) throw new Error("Bulk deletes are not supported by this collection's data source. Fall back to delete() per record.");
@@ -6683,6 +6865,6 @@ function buildRoutedRebaseData({ defaultData, sources, resolveKey }) {
6683
6865
  }
6684
6866
  new Set(REBASE_INTERNAL_TABLES);
6685
6867
  //#endregion
6686
- export { toSnakeCase as $, createDataSourceRegistry as A, fieldKeyForColumn as B, cursorToStartAfter as C, restrictedFieldNames as D, effectiveAccess as E, revokeInternalTableSql as F, resolveCollectionRelations as G, getTableName as H, getJunctionConfigForRelation as I, resolvePrimaryKeys as J, enumToObjectEntries as K, getEffectiveSecurityRules as L, resolveDataSource as M, authSecretsMissingExclusion as N, assertBeforeQueryIsPostgresOnly as O, REBASE_USER_ROLE as P, suggestNearMiss as Q, getTenantConfig as R, CursorMismatchError as S, reconcileCursorOrder as T, isRelationRequired as U, findRelation as V, relationDeclaringProperty as W, isObject as X, hydrateRegExp as Y, splitSearchTerms as Z, topLevelIncludeNames as _, Vector as _t, deserializeFilter as a, FIELD_OPERATORS as at, serializeOrderBy as b, isUnsupported as bt, serializeLogicalCondition as c, ANONYMOUS_USER_ID as ct, resolveFindWindow as d, hasForeignKeyOnTarget as dt, unref as et, IncludeSpecError as f, isManyToMany as ft, serializeInclude as g, GeoPoint as gt, normalizeInclude as h, EntityRelation as ht, UnknownFilterOperatorError as i, BATCH_REF_KEY as it, isRelationalCollection as j, CollectionRegistry as k, collectAllPages as l, isAnonymousUid as lt, mergeIncludeSpecs as m, EntityReference as mt, buildSdkData as n, MAX_LIST_LIMIT as nt, deserializeLogicalCondition as o, hasFieldOperation as ot, deserializeInclude as p, isToMany as pt, buildCompositeId as q, RESERVED_QUERY_KEYS as r, resolveClientListLimit as rt, serializeFilter as s, isFieldOperation as st, buildRoutedRebaseData as t, ListLimitError as tt, paginateFind as u, JUNCTION_PIVOT_KEY as ut, OrderBySpecError as v, RebaseApiError as vt, decodeCursor as w, CursorError as x, unsupportedMethod as xt, normalizeOrderBy as y, RebaseClientError as yt, securityRuleToConditions as z };
6868
+ export { unref as $, isRelationalCollection as A, findRelation as B, decodeCursor as C, assertBeforeQueryIsPostgresOnly as D, restrictedFieldNames as E, getJunctionConfigForRelation as F, enumToObjectEntries as G, isRelationRequired as H, getEffectiveSecurityRules as I, hydrateRegExp as J, buildCompositeId as K, getTenantConfig as L, authSecretsMissingExclusion as M, REBASE_USER_ROLE as N, CollectionRegistry as O, revokeInternalTableSql as P, toSnakeCase as Q, securityRuleToConditions as R, cursorToStartAfter as S, effectiveAccess as T, relationDeclaringProperty as U, getTableName as V, resolveCollectionRelations as W, splitSearchTerms as X, isObject as Y, suggestNearMiss as Z, OrderBySpecError as _, RebaseApiError as _t, deserializeFilter as a, hasFieldOperation as at, CursorError as b, unsupportedMethod as bt, serializeLogicalCondition as c, isAnonymousUid as ct, resolveFindWindow as d, isManyToMany as dt, ListLimitError as et, IncludeSpecError as f, isToMany as ft, serializeInclude as g, Vector as gt, normalizeInclude as h, GeoPoint as ht, UnknownFilterOperatorError as i, FIELD_OPERATORS as it, resolveDataSource as j, createDataSourceRegistry as k, collectAllPages as l, JUNCTION_PIVOT_KEY as lt, mergeIncludeSpecs as m, EntityRelation as mt, buildSdkData as n, resolveClientListLimit as nt, deserializeLogicalCondition as o, isFieldOperation as ot, deserializeInclude as p, EntityReference as pt, resolvePrimaryKeys as q, RESERVED_QUERY_KEYS as r, BATCH_REF_KEY as rt, serializeFilter as s, ANONYMOUS_USER_ID as st, buildRoutedRebaseData as t, MAX_LIST_LIMIT as tt, paginateFind as u, hasForeignKeyOnTarget as ut, normalizeOrderBy as v, RebaseClientError as vt, reconcileCursorOrder as w, CursorMismatchError as x, serializeOrderBy as y, isUnsupported as yt, fieldKeyForColumn as z };
6687
6869
 
6688
- //# sourceMappingURL=src-pmvW7BFx.js.map
6870
+ //# sourceMappingURL=src-I3aG1PcY.js.map