@klum-db/lobby 0.2.0-pre.31 → 0.2.0-pre.33

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.
@@ -1,4 +1,4 @@
1
- import { V as VaultGroup } from '../vault-group-DqEyXbN1.cjs';
1
+ import { V as VaultGroup } from '../vault-group-SfkQJ3CM.cjs';
2
2
  import '@noy-db/hub/kernel';
3
3
  import '@noy-db/hub';
4
4
  import '@noy-db/hub/bundle';
@@ -1,4 +1,4 @@
1
- import { V as VaultGroup } from '../vault-group-DqEyXbN1.js';
1
+ import { V as VaultGroup } from '../vault-group-SfkQJ3CM.js';
2
2
  import '@noy-db/hub/kernel';
3
3
  import '@noy-db/hub';
4
4
  import '@noy-db/hub/bundle';
package/dist/index.cjs CHANGED
@@ -1223,28 +1223,33 @@ var init_insight_auto_push = __esm({
1223
1223
  "src/federation/insight-auto-push.ts"() {
1224
1224
  "use strict";
1225
1225
  InsightAutoPush = class {
1226
- constructor(recompute, isSource, onError = (err, pk) => console.warn(`[klum-db] insight auto-push failed for shard "${pk}":`, err)) {
1226
+ constructor(recompute, isSource, onError = (err, pk) => console.warn(`[klum-db] insight auto-push failed for shard "${pk}":`, err), debounceMs) {
1227
1227
  this.recompute = recompute;
1228
1228
  this.isSource = isSource;
1229
1229
  this.onError = onError;
1230
+ this.debounceMs = debounceMs;
1230
1231
  }
1231
1232
  recompute;
1232
1233
  isSource;
1233
1234
  onError;
1234
- /** Partition keys awaiting recompute. */
1235
+ debounceMs;
1235
1236
  dirty = /* @__PURE__ */ new Set();
1236
- /** The in-flight flush, or null when idle. */
1237
1237
  pending = null;
1238
+ timer = null;
1239
+ resolvePending = null;
1240
+ flushing = false;
1238
1241
  /** Called from a shard's onAfterWrite hook. Marks the shard dirty + schedules a flush. */
1239
1242
  noteWrite(partitionKey, collection) {
1240
1243
  if (!this.isSource(collection)) return;
1241
1244
  this.dirty.add(partitionKey);
1242
- this.schedule();
1245
+ if (this.debounceMs !== void 0) this.scheduleDebounced();
1246
+ else this.schedule();
1243
1247
  }
1244
1248
  /** Resolve once no flush is pending (drains rescheduled flushes too). */
1245
1249
  async whenSettled() {
1246
1250
  while (this.pending) await this.pending;
1247
1251
  }
1252
+ // ── microtask path (unchanged default) ──
1248
1253
  schedule() {
1249
1254
  if (this.pending) return;
1250
1255
  this.pending = this.runFlush().finally(() => {
@@ -1252,6 +1257,29 @@ var init_insight_auto_push = __esm({
1252
1257
  if (this.dirty.size > 0) this.schedule();
1253
1258
  });
1254
1259
  }
1260
+ // ── debounce path (#13) ──
1261
+ scheduleDebounced() {
1262
+ if (!this.pending) this.pending = new Promise((r) => {
1263
+ this.resolvePending = r;
1264
+ });
1265
+ if (this.timer) clearTimeout(this.timer);
1266
+ this.timer = setTimeout(() => {
1267
+ this.timer = null;
1268
+ if (this.flushing) return;
1269
+ this.flushing = true;
1270
+ void this.runFlush().finally(() => {
1271
+ this.flushing = false;
1272
+ if (this.dirty.size > 0) {
1273
+ this.scheduleDebounced();
1274
+ } else {
1275
+ const resolve = this.resolvePending;
1276
+ this.resolvePending = null;
1277
+ this.pending = null;
1278
+ resolve?.();
1279
+ }
1280
+ });
1281
+ }, this.debounceMs);
1282
+ }
1255
1283
  async runFlush() {
1256
1284
  await Promise.resolve();
1257
1285
  const pks = [...this.dirty];
@@ -1416,6 +1444,73 @@ var init_aggregate_across = __esm({
1416
1444
  }
1417
1445
  });
1418
1446
 
1447
+ // src/federation/retrieve-across.ts
1448
+ async function retrieveAcross(group, collectionName, query, opts = {}) {
1449
+ const { eligible, skipped } = await group.resolveEligible({
1450
+ ...opts.minVersion !== void 0 ? { minVersion: opts.minVersion } : {},
1451
+ ...opts.failFast !== void 0 ? { failFast: opts.failFast } : {}
1452
+ });
1453
+ const across = await group.db.queryAcross(
1454
+ eligible.map((r) => r.vaultId),
1455
+ async (vault) => {
1456
+ group.template.configure(vault);
1457
+ const coll = vault.collection(collectionName);
1458
+ let within;
1459
+ if (opts.where?.length) {
1460
+ let q = coll.query();
1461
+ for (const [f, op, v] of opts.where) q = q.where(f, op, v);
1462
+ within = q;
1463
+ }
1464
+ return coll.retrieve(query, {
1465
+ ...opts.mode ? { mode: opts.mode } : {},
1466
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {},
1467
+ ...opts.minScore !== void 0 ? { minScore: opts.minScore } : {},
1468
+ ...opts.fields ? { fields: opts.fields } : {},
1469
+ ...opts.match ? { match: opts.match } : {},
1470
+ ...opts.prefix ? { prefix: opts.prefix } : {},
1471
+ ...opts.snippetWindow !== void 0 ? { snippetWindow: opts.snippetWindow } : {},
1472
+ ...opts.includeRecord ? { includeRecord: true } : {},
1473
+ ...within ? { within } : {}
1474
+ });
1475
+ },
1476
+ { concurrency: opts.concurrency ?? 1, create: false }
1477
+ );
1478
+ const skippedVaults = [...skipped];
1479
+ const perVault = [];
1480
+ for (const r of across) {
1481
+ if (r.error) {
1482
+ if (opts.failFast) throw r.error;
1483
+ skippedVaults.push({ vaultId: r.vault, reason: classifyShardSkip(r.error), error: r.error });
1484
+ } else {
1485
+ perVault.push({ vault: r.vault, hits: r.result });
1486
+ }
1487
+ }
1488
+ const lists = perVault.map((pv) => {
1489
+ if (pv.vault.includes(SEP)) {
1490
+ throw new Error(`retrieveAcross: vault id "${pv.vault}" contains the reserved NUL separator`);
1491
+ }
1492
+ return pv.hits.map((h) => ({ ...h, id: pv.vault + SEP + h.id }));
1493
+ });
1494
+ const fused = (0, import_kernel10.fuseRetrieval)(lists, {
1495
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {},
1496
+ ...opts.rrfK !== void 0 ? { k: opts.rrfK } : {}
1497
+ });
1498
+ const hits = fused.map((h) => {
1499
+ const i = h.id.indexOf(SEP);
1500
+ return { ...h, vault: h.id.slice(0, i), id: h.id.slice(i + 1) };
1501
+ });
1502
+ return { hits, skippedVaults };
1503
+ }
1504
+ var import_kernel10, SEP;
1505
+ var init_retrieve_across = __esm({
1506
+ "src/federation/retrieve-across.ts"() {
1507
+ "use strict";
1508
+ import_kernel10 = require("@noy-db/hub/kernel");
1509
+ init_classify_skip();
1510
+ SEP = "\0";
1511
+ }
1512
+ });
1513
+
1419
1514
  // src/federation/vault-group.ts
1420
1515
  var vault_group_exports = {};
1421
1516
  __export(vault_group_exports, {
@@ -1424,49 +1519,55 @@ __export(vault_group_exports, {
1424
1519
  ShardedQuery: () => ShardedQuery,
1425
1520
  VaultGroup: () => VaultGroup
1426
1521
  });
1522
+ function autoPushConfig(spec) {
1523
+ if (!spec.autoPush) return null;
1524
+ return spec.autoPush === true ? {} : spec.autoPush;
1525
+ }
1427
1526
  function assertSafePartitionKey(partitionKey) {
1428
1527
  if (partitionKey.length === 0) {
1429
- throw new import_kernel10.ValidationError("partitionKey must be a non-empty string");
1528
+ throw new import_kernel11.ValidationError("partitionKey must be a non-empty string");
1430
1529
  }
1431
1530
  if (partitionKey === import_hub4.STATE_VAULT_NAME) {
1432
- throw new import_kernel10.ReservedVaultNameError(partitionKey);
1531
+ throw new import_kernel11.ReservedVaultNameError(partitionKey);
1433
1532
  }
1434
1533
  if (!SAFE_PARTITION_KEY.test(partitionKey)) {
1435
- throw new import_kernel10.ValidationError(
1534
+ throw new import_kernel11.ValidationError(
1436
1535
  `partitionKey "${partitionKey}" contains characters outside [A-Za-z0-9._-]. Map your records to a store-safe key in sharding.keyOf.`
1437
1536
  );
1438
1537
  }
1439
1538
  if (partitionKey.includes(SHARD_SEPARATOR)) {
1440
- throw new import_kernel10.ValidationError(
1539
+ throw new import_kernel11.ValidationError(
1441
1540
  `partitionKey "${partitionKey}" must not contain "--" \u2014 it is reserved as the shard vault-id separator and would risk shard-id collisions.`
1442
1541
  );
1443
1542
  }
1444
1543
  }
1445
- var import_kernel10, SHARD_SEPARATOR, SAFE_PARTITION_KEY, VaultGroup, ShardedCollection, ShardedQuery, ShardedGroupedQuery;
1544
+ var import_kernel11, SHARD_SEPARATOR, SAFE_PARTITION_KEY, VaultGroup, ShardedCollection, ShardedQuery, ShardedGroupedQuery;
1446
1545
  var init_vault_group = __esm({
1447
1546
  "src/federation/vault-group.ts"() {
1448
1547
  "use strict";
1449
1548
  init_state_vault();
1450
- import_kernel10 = require("@noy-db/hub/kernel");
1549
+ import_kernel11 = require("@noy-db/hub/kernel");
1451
1550
  init_constants();
1452
1551
  init_classify_skip();
1453
1552
  init_cross_shard_join();
1454
1553
  init_cross_vault_live();
1455
1554
  init_insight_auto_push();
1456
1555
  init_aggregate_across();
1556
+ init_retrieve_across();
1457
1557
  init_partial_reduce();
1458
1558
  SHARD_SEPARATOR = "--";
1459
1559
  SAFE_PARTITION_KEY = /^[A-Za-z0-9._-]+$/;
1460
1560
  VaultGroup = class {
1461
- constructor(db, name, registry, sharding, template, cutoverOnOpen = false) {
1561
+ constructor(db, name, registry, sharding, template, cutoverOnOpen = false, meta) {
1462
1562
  this.db = db;
1463
1563
  this.name = name;
1464
1564
  this.registry = registry;
1465
1565
  this.sharding = sharding;
1466
1566
  this.template = template;
1467
1567
  this.cutoverOnOpen = cutoverOnOpen;
1568
+ this.meta = meta;
1468
1569
  if (name.includes(SHARD_SEPARATOR)) {
1469
- throw new import_kernel10.ValidationError(
1570
+ throw new import_kernel11.ValidationError(
1470
1571
  `VaultGroup name "${name}" must not contain "--" (reserved shard vault-id separator).`
1471
1572
  );
1472
1573
  }
@@ -1477,6 +1578,7 @@ var init_vault_group = __esm({
1477
1578
  sharding;
1478
1579
  template;
1479
1580
  cutoverOnOpen;
1581
+ meta;
1480
1582
  /** @internal — set when the group is managed (no explicit registry). */
1481
1583
  stateVault;
1482
1584
  /** @internal */
@@ -1510,6 +1612,30 @@ var init_vault_group = __esm({
1510
1612
  const rows = this.registry.query().toArray();
1511
1613
  return rows.filter((r) => r.group === this.name);
1512
1614
  }
1615
+ /**
1616
+ * Federation-level descriptive metadata (#27): this group's `meta` plus each
1617
+ * member vault's `vaultMeta` (read via `getMeta()`). Best-effort per shard — a
1618
+ * shard that fails to open yields `meta: undefined` for that entry, never
1619
+ * throwing. Member meta is transient per-open (noy-db sets it at `openVault`,
1620
+ * does not persist it); this surfaces whatever each vault was opened with.
1621
+ */
1622
+ async federationMeta() {
1623
+ const rows = await this.allRows();
1624
+ const vaults = await Promise.all(
1625
+ rows.map(async (row) => {
1626
+ let meta;
1627
+ try {
1628
+ const vault = await this.db.openVault(row.vaultId);
1629
+ this.template.configure(vault);
1630
+ meta = vault.getMeta();
1631
+ } catch {
1632
+ meta = void 0;
1633
+ }
1634
+ return { vaultId: row.vaultId, partitionKey: row.partitionKey, meta };
1635
+ })
1636
+ );
1637
+ return { meta: this.meta, vaults };
1638
+ }
1513
1639
  /**
1514
1640
  * Open an existing shard and apply the template. When `cutoverOnOpen` is set
1515
1641
  * (#271) and the shard's registry version is behind the template, its cutover
@@ -1546,11 +1672,11 @@ var init_vault_group = __esm({
1546
1672
  const vaultId = this.shardVaultId(partitionKey);
1547
1673
  const row = await this.registry.get(this.registryId(partitionKey));
1548
1674
  const provisioned = await this.db._shardVaultProvisioned(vaultId);
1549
- if (row && !provisioned) throw new import_kernel10.ShardProvisioningError(vaultId, partitionKey);
1675
+ if (row && !provisioned) throw new import_kernel11.ShardProvisioningError(vaultId, partitionKey);
1550
1676
  if (row && provisioned) return this.openShard(partitionKey);
1551
1677
  if (region !== void 0) {
1552
1678
  const backendRegion = this.db._resolveBackend(vaultId).capabilities?.region;
1553
- if (backendRegion !== region) throw new import_kernel10.DataResidencyError(vaultId, region, backendRegion);
1679
+ if (backendRegion !== region) throw new import_kernel11.DataResidencyError(vaultId, region, backendRegion);
1554
1680
  }
1555
1681
  const vault = await this.db.openVault(vaultId);
1556
1682
  this.template.configure(vault);
@@ -1584,9 +1710,9 @@ var init_vault_group = __esm({
1584
1710
  async shard(partitionKey) {
1585
1711
  const vaultId = this.shardVaultId(partitionKey);
1586
1712
  const row = await this.registry.get(this.registryId(partitionKey));
1587
- if (!row) throw new import_kernel10.UnknownShardError(partitionKey, this.name);
1713
+ if (!row) throw new import_kernel11.UnknownShardError(partitionKey, this.name);
1588
1714
  const provisioned = await this.db._shardVaultProvisioned(vaultId);
1589
- if (!provisioned) throw new import_kernel10.ShardProvisioningError(vaultId, partitionKey);
1715
+ if (!provisioned) throw new import_kernel11.ShardProvisioningError(vaultId, partitionKey);
1590
1716
  return this.openShard(partitionKey);
1591
1717
  }
1592
1718
  /** A sharded view over one logical collection across all shards. */
@@ -1618,7 +1744,7 @@ var init_vault_group = __esm({
1618
1744
  for (const p of probes) {
1619
1745
  if ("error" in p) skipped.push({ vaultId: p.row.vaultId, reason: "error", error: p.error });
1620
1746
  else if (p.provisioned) eligible.push(p.row);
1621
- else skipped.push({ vaultId: p.row.vaultId, reason: "error", error: new import_kernel10.ShardProvisioningError(p.row.vaultId, p.row.partitionKey) });
1747
+ else skipped.push({ vaultId: p.row.vaultId, reason: "error", error: new import_kernel11.ShardProvisioningError(p.row.vaultId, p.row.partitionKey) });
1622
1748
  }
1623
1749
  return { eligible, skipped };
1624
1750
  }
@@ -1655,15 +1781,18 @@ var init_vault_group = __esm({
1655
1781
  withCrossVaultDerivation(spec) {
1656
1782
  const target = spec.target.vault;
1657
1783
  if (target === this.name || target.startsWith(`${this.name}${SHARD_SEPARATOR}`)) {
1658
- throw new import_kernel10.ValidationError(
1784
+ throw new import_kernel11.ValidationError(
1659
1785
  `withCrossVaultDerivation: target.vault "${target}" is the "${this.name}" group itself or one of its shards \u2014 an Insight summary must target a SEPARATE analytics vault, never write back into client-shard data (it would breach the per-shard DEK boundary). Use a distinct vault name.`
1660
1786
  );
1661
1787
  }
1662
1788
  this.crossVaultDerivations.push(spec);
1663
1789
  if (spec.autoPush && !this.insightAutoPush) {
1790
+ const cfg = autoPushConfig(spec);
1664
1791
  const controller = new InsightAutoPush(
1665
1792
  (pk) => this._recomputeShardInsights(pk),
1666
- (collection) => this.crossVaultDerivations.some((s) => s.autoPush && s.source === collection)
1793
+ (collection) => this.crossVaultDerivations.some((s) => s.autoPush && s.source === collection),
1794
+ void 0,
1795
+ cfg?.debounceMs
1667
1796
  );
1668
1797
  this.insightAutoPush = controller;
1669
1798
  const prefix = `${this.name}${SHARD_SEPARATOR}`;
@@ -1744,6 +1873,8 @@ var init_vault_group = __esm({
1744
1873
  };
1745
1874
  for (const spec of this.crossVaultDerivations) {
1746
1875
  if (!spec.autoPush) continue;
1876
+ const min = autoPushConfig(spec)?.minVersion;
1877
+ if (min !== void 0 && row.schemaVersion < min) continue;
1747
1878
  const records = await shard.collection(spec.source).list();
1748
1879
  const summary = spec.derive(records, ctx);
1749
1880
  const insight = await this.db.openVault(spec.target.vault);
@@ -1776,7 +1907,7 @@ var init_vault_group = __esm({
1776
1907
  async cutoverShard(partitionKey) {
1777
1908
  const vaultId = this.shardVaultId(partitionKey);
1778
1909
  const row = await this.registry.get(this.registryId(partitionKey));
1779
- if (!row) throw new import_kernel10.UnknownShardError(partitionKey, this.name);
1910
+ if (!row) throw new import_kernel11.UnknownShardError(partitionKey, this.name);
1780
1911
  const target = this.template.version;
1781
1912
  const sv = await this.ensureStateVault();
1782
1913
  const base = { vaultId, group: this.name, currentVersion: row.schemaVersion, targetVersion: target };
@@ -1859,7 +1990,7 @@ var init_vault_group = __esm({
1859
1990
  let vault;
1860
1991
  if (!row) {
1861
1992
  if (this.group.sharding.autoCreate === false) {
1862
- throw new import_kernel10.UnknownShardError(key, this.group.name);
1993
+ throw new import_kernel11.UnknownShardError(key, this.group.name);
1863
1994
  }
1864
1995
  vault = await this.group.createShard(key, this.group.sharding.regionOf?.(record));
1865
1996
  } else {
@@ -1871,6 +2002,17 @@ var init_vault_group = __esm({
1871
2002
  query() {
1872
2003
  return new ShardedQuery(this.group, this.collectionName, []);
1873
2004
  }
2005
+ /**
2006
+ * Cross-vault federated retrieval (#26): scatter-gather across all eligible
2007
+ * shards — each shard runs its own trusted-tier `retrieve()`, then results are
2008
+ * RRF-fused by rank only (no cross-vault statistics cross the DEK boundary).
2009
+ * Every hit carries its originating `vault`. An unreachable, schema-drifted, or
2010
+ * un-indexed shard is skipped (`skippedVaults`); pass `failFast` to re-throw
2011
+ * the first per-shard error instead.
2012
+ */
2013
+ async retrieve(query, opts = {}) {
2014
+ return retrieveAcross(this.group, this.collectionName, query, opts);
2015
+ }
1874
2016
  };
1875
2017
  ShardedQuery = class _ShardedQuery {
1876
2018
  constructor(group, collectionName, clauses, coPartitionedLegs = [], broadcastLegs = []) {
@@ -1931,7 +2073,7 @@ var init_vault_group = __esm({
1931
2073
  this.group.template.configure(probe);
1932
2074
  for (const leg of this.coPartitionedLegs) {
1933
2075
  if (!probe.resolveRef(this.collectionName, leg.field)) {
1934
- throw new import_kernel10.CrossShardJoinError(
2076
+ throw new import_kernel11.CrossShardJoinError(
1935
2077
  `crossShardJoin("${leg.field}"): no ref() declared for "${leg.field}" on collection "${this.collectionName}" in template "${this.group.sharding.vaultTemplate}". Add refs: { ${leg.field}: ref('<target>') } to the template's collection options.`
1936
2078
  );
1937
2079
  }
@@ -2013,23 +2155,23 @@ var init_vault_group = __esm({
2013
2155
  isRelevant: (e) => e.collection === collectionName && e.vault.startsWith(`${group.name}--`)
2014
2156
  };
2015
2157
  }
2016
- /** @internal — joined queries don't support reactive/aggregate surfaces in v1. */
2017
- assertNoJoinLegs(surface) {
2018
- if (this.coPartitionedLegs.length || this.broadcastLegs.length) {
2019
- throw new import_kernel10.CrossShardJoinError(
2020
- `${surface}() is not supported on a ShardedQuery with crossShardJoin/broadcastJoin legs in v1. Use toArray() for joined cross-shard queries.`
2021
- );
2022
- }
2023
- }
2024
- /** Returns a reactive cross-shard live query — a facade over CrossVaultLive. */
2158
+ /**
2159
+ * Returns a reactive cross-shard live query — a facade over CrossVaultLive.
2160
+ *
2161
+ * Joined queries (crossShardJoin / broadcastJoin) are supported (#14): the live
2162
+ * value reflects the fully-joined rows. **v1 limitation:** recomputes only on
2163
+ * writes to the primary (left) collection; writes to a co-partitioned right
2164
+ * collection or a broadcast-dimension collection do NOT trigger a recompute —
2165
+ * re-run the query to pick those up.
2166
+ */
2025
2167
  live(options = {}) {
2026
- this.assertNoJoinLegs("live");
2027
2168
  const bind = this.liveBinding();
2028
2169
  const core = new CrossVaultLive({
2029
2170
  ...bind,
2030
2171
  compute: async () => {
2031
2172
  const { records, skippedVaults } = await this.fanoutRecords(options);
2032
- return { records, skipped: skippedVaults };
2173
+ const joined = await applyBroadcastLegs(records, this.broadcastLegs);
2174
+ return { records: joined, skipped: skippedVaults };
2033
2175
  },
2034
2176
  initialSnapshot: { records: [], skipped: [] },
2035
2177
  ...options.debounceMs !== void 0 ? { debounceMs: options.debounceMs } : {}
@@ -2049,14 +2191,28 @@ var init_vault_group = __esm({
2049
2191
  stop: () => core.stop()
2050
2192
  };
2051
2193
  }
2194
+ /**
2195
+ * @internal — the FanoutRecordSource for aggregate surfaces. With no join legs,
2196
+ * returns `this` (partial-reduce-eligible, #8). With join legs, returns a
2197
+ * toArray-backed source (fully-joined rows) and NO fanoutReduce, forcing
2198
+ * central-reduce over the joined rows (partial-reduce can't span the central
2199
+ * broadcast join). Used by scalar `aggregate()` and `ShardedGroupedQuery`.
2200
+ */
2201
+ aggregateSource() {
2202
+ if (!this.coPartitionedLegs.length && !this.broadcastLegs.length) return this;
2203
+ return {
2204
+ fanoutRecords: async (o) => {
2205
+ const { results, skippedVaults } = await this.toArray(o);
2206
+ return { records: results, skippedVaults };
2207
+ }
2208
+ };
2209
+ }
2052
2210
  /** One-shot distributed aggregate — central reduce over all shard records. */
2053
2211
  aggregate(spec) {
2054
- this.assertNoJoinLegs("aggregate");
2055
- return new CrossVaultAggregation(this, spec, this.liveBinding());
2212
+ return new CrossVaultAggregation(this.aggregateSource(), spec, this.liveBinding());
2056
2213
  }
2057
2214
  /** Begin a grouped cross-shard aggregate. */
2058
2215
  groupBy(field) {
2059
- this.assertNoJoinLegs("groupBy");
2060
2216
  return new ShardedGroupedQuery(this, field);
2061
2217
  }
2062
2218
  };
@@ -2069,7 +2225,7 @@ var init_vault_group = __esm({
2069
2225
  field;
2070
2226
  aggregate(spec) {
2071
2227
  return new CrossVaultGroupedAggregation(
2072
- { fanoutRecords: (o) => this.query.fanoutRecords(o) },
2228
+ this.query.aggregateSource(),
2073
2229
  this.field,
2074
2230
  spec,
2075
2231
  this.query.liveBinding()
@@ -2082,10 +2238,10 @@ var init_vault_group = __esm({
2082
2238
  // src/index.ts
2083
2239
  var index_exports = {};
2084
2240
  __export(index_exports, {
2085
- CrossShardJoinError: () => import_kernel12.CrossShardJoinError,
2241
+ CrossShardJoinError: () => import_kernel13.CrossShardJoinError,
2086
2242
  CrossVaultDanglingRefError: () => CrossVaultDanglingRefError,
2087
2243
  CustodyApi: () => import_hub6.CustodyApi,
2088
- DataResidencyError: () => import_kernel12.DataResidencyError,
2244
+ DataResidencyError: () => import_kernel13.DataResidencyError,
2089
2245
  DockedUnit: () => DockedUnit,
2090
2246
  FieldAuthorityPolicyMissingError: () => FieldAuthorityPolicyMissingError,
2091
2247
  FieldLevelDeferredError: () => FieldLevelDeferredError,
@@ -2096,14 +2252,14 @@ __export(index_exports, {
2096
2252
  NOYDB_MULTI_BUNDLE_MAGIC: () => NOYDB_MULTI_BUNDLE_MAGIC,
2097
2253
  NOYDB_MULTI_BUNDLE_PREFIX_BYTES: () => NOYDB_MULTI_BUNDLE_PREFIX_BYTES,
2098
2254
  NOYDB_MULTI_BUNDLE_VERSION: () => NOYDB_MULTI_BUNDLE_VERSION,
2099
- ReservedVaultNameError: () => import_kernel12.ReservedVaultNameError,
2100
- ShardProvisioningError: () => import_kernel12.ShardProvisioningError,
2255
+ ReservedVaultNameError: () => import_kernel13.ReservedVaultNameError,
2256
+ ShardProvisioningError: () => import_kernel13.ShardProvisioningError,
2101
2257
  SurfaceCadenceScheduler: () => SurfaceCadenceScheduler,
2102
2258
  SurfaceNotFoundError: () => SurfaceNotFoundError,
2103
2259
  SurfaceStateError: () => SurfaceStateError,
2104
2260
  UnitGraduationError: () => UnitGraduationError,
2105
- UnknownShardError: () => import_kernel12.UnknownShardError,
2106
- VaultTemplateNotFoundError: () => import_kernel12.VaultTemplateNotFoundError,
2261
+ UnknownShardError: () => import_kernel13.UnknownShardError,
2262
+ VaultTemplateNotFoundError: () => import_kernel13.VaultTemplateNotFoundError,
2107
2263
  agreeSurface: () => agreeSurface,
2108
2264
  applySurface: () => applySurface,
2109
2265
  createDeedOwner: () => import_hub6.createDeedOwner,
@@ -2133,7 +2289,7 @@ __export(index_exports, {
2133
2289
  writeMultiVaultBundle: () => writeMultiVaultBundle
2134
2290
  });
2135
2291
  module.exports = __toCommonJS(index_exports);
2136
- var import_kernel11 = require("@noy-db/hub/kernel");
2292
+ var import_kernel12 = require("@noy-db/hub/kernel");
2137
2293
  var import_hub5 = require("@noy-db/hub");
2138
2294
 
2139
2295
  // src/dock/docked-unit.ts
@@ -2216,7 +2372,7 @@ async function meterGroup(group, opts = {}) {
2216
2372
  }
2217
2373
 
2218
2374
  // src/index.ts
2219
- var import_kernel12 = require("@noy-db/hub/kernel");
2375
+ var import_kernel13 = require("@noy-db/hub/kernel");
2220
2376
  init_multi_bundle();
2221
2377
  init_extract_cross_vault();
2222
2378
  init_merge_compartment();
@@ -2304,15 +2460,15 @@ var Lobby = class {
2304
2460
  }
2305
2461
  async openVaultGroup(name, opts) {
2306
2462
  const db = this.noydb;
2307
- if (db.isClosed) throw new import_kernel11.ValidationError("Instance is closed");
2308
- if (name === import_hub5.STATE_VAULT_NAME) throw new import_kernel11.ReservedVaultNameError(name);
2463
+ if (db.isClosed) throw new import_kernel12.ValidationError("Instance is closed");
2464
+ if (name === import_hub5.STATE_VAULT_NAME) throw new import_kernel12.ReservedVaultNameError(name);
2309
2465
  const template = this.vaultTemplates.get(opts.sharding.vaultTemplate);
2310
- if (!template) throw new import_kernel11.VaultTemplateNotFoundError(opts.sharding.vaultTemplate);
2466
+ if (!template) throw new import_kernel12.VaultTemplateNotFoundError(opts.sharding.vaultTemplate);
2311
2467
  const { VaultGroup: VaultGroup2 } = await Promise.resolve().then(() => (init_vault_group(), vault_group_exports));
2312
2468
  const { StateManagementVault: StateManagementVault2 } = await Promise.resolve().then(() => (init_state_vault(), state_vault_exports));
2313
2469
  const stateVault = opts.registry ? void 0 : await StateManagementVault2.open(db);
2314
2470
  const registry = opts.registry ?? stateVault.registry;
2315
- const group = new VaultGroup2(db, name, registry, opts.sharding, template, opts.cutoverOnOpen ?? false);
2471
+ const group = new VaultGroup2(db, name, registry, opts.sharding, template, opts.cutoverOnOpen ?? false, opts.meta);
2316
2472
  if (stateVault) {
2317
2473
  group._attachStateVault(stateVault);
2318
2474
  await stateVault.recordManifest(opts.sharding.vaultTemplate, template);
@@ -2326,7 +2482,7 @@ var Lobby = class {
2326
2482
  }
2327
2483
  async openStateManagementVault() {
2328
2484
  const db = this.noydb;
2329
- if (db.isClosed) throw new import_kernel11.ValidationError("Instance is closed");
2485
+ if (db.isClosed) throw new import_kernel12.ValidationError("Instance is closed");
2330
2486
  const { StateManagementVault: StateManagementVault2 } = await Promise.resolve().then(() => (init_state_vault(), state_vault_exports));
2331
2487
  return StateManagementVault2.open(db);
2332
2488
  }