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

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.
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Vault, SealingKeyProvider, PublicEnvelope, Noydb } from '@noy-db/hub';
2
2
  export { CustodyApi, DeedMarker, GrantCustodianOptions, LiberateOptions, LiberateResult, createDeedOwner, isDeedVault, liberateVault, loadDeedMarker } from '@noy-db/hub';
3
- import { a as VaultTemplate, S as StateManagementVault, V as VaultGroup, b as SkippedVault, M as MergeCompartmentOptions, c as MergeReport, d as SurfaceDirection, e as SurfaceConflictPolicy, f as SurfaceRow, g as VaultGroupOptions } from './vault-group-BXjO5kHB.cjs';
4
- export { C as CapturedBlueprint, h as CrossVaultAggregation, i as CrossVaultDerivationContext, j as CrossVaultDerivationSpec, k as CrossVaultGroupedAggregation, G as CrossVaultGroupedRow, l as CrossVaultLiveAggregation, m as CrossVaultLiveQuery, D as DecryptedMergeOptions, n as DeploymentEvent, F as FanoutQueryOptions, o as FanoutResult, p as FieldAuthorityInputs, q as FieldAuthorityPolicy, r as FieldAuthorityPolicyMissingError, s as FieldAuthorityRule, t as FieldLevelDeferredError, L as LiveQueryOptions, u as MergeConflict, v as MergeStrategy, w as MigrationStatusRow, R as RefreshInsightsResult, x as SchemaManifestRow, y as SchemaRolloutResult, z as ShardedCollection, A as ShardedGroupedQuery, B as ShardedQuery, E as ShardingConfig, H as SurfaceStatus, I as VaultRegistryRow, J as mergeCompartment, K as mergeDecryptedRecords, N as resolveFieldAuthority, O as resolveRecordByFieldAuthority } from './vault-group-BXjO5kHB.cjs';
3
+ import { a as VaultTemplate, S as StateManagementVault, V as VaultGroup, b as SkippedVault, M as MergeCompartmentOptions, c as MergeReport, d as SurfaceDirection, e as SurfaceConflictPolicy, f as SurfaceRow, g as VaultGroupOptions } from './vault-group-DqEyXbN1.cjs';
4
+ export { C as CapturedBlueprint, h as CrossVaultAggregation, i as CrossVaultDerivationContext, j as CrossVaultDerivationSpec, k as CrossVaultGroupedAggregation, G as CrossVaultGroupedRow, l as CrossVaultLiveAggregation, m as CrossVaultLiveQuery, D as DecryptedMergeOptions, n as DeploymentEvent, F as FanoutQueryOptions, o as FanoutResult, p as FieldAuthorityInputs, q as FieldAuthorityPolicy, r as FieldAuthorityPolicyMissingError, s as FieldAuthorityRule, t as FieldLevelDeferredError, L as LiveQueryOptions, u as MergeConflict, v as MergeStrategy, w as MigrationStatusRow, R as RefreshInsightsResult, x as SchemaManifestRow, y as SchemaRolloutResult, z as ShardedCollection, A as ShardedGroupedQuery, B as ShardedQuery, E as ShardingConfig, H as SurfaceStatus, I as VaultRegistryRow, J as mergeCompartment, K as mergeDecryptedRecords, N as resolveFieldAuthority, O as resolveRecordByFieldAuthority } from './vault-group-DqEyXbN1.cjs';
5
5
  import { AsXlsxSheetOptions } from '@noy-db/as-xlsx';
6
6
  export { MultiVaultDenormColumn, MultiVaultXlsxEntry, MultiVaultXlsxOptions } from '@noy-db/as-xlsx';
7
7
  import { ExtractionPreview, WriteNoydbBundleOptions } from '@noy-db/hub/bundle';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Vault, SealingKeyProvider, PublicEnvelope, Noydb } from '@noy-db/hub';
2
2
  export { CustodyApi, DeedMarker, GrantCustodianOptions, LiberateOptions, LiberateResult, createDeedOwner, isDeedVault, liberateVault, loadDeedMarker } from '@noy-db/hub';
3
- import { a as VaultTemplate, S as StateManagementVault, V as VaultGroup, b as SkippedVault, M as MergeCompartmentOptions, c as MergeReport, d as SurfaceDirection, e as SurfaceConflictPolicy, f as SurfaceRow, g as VaultGroupOptions } from './vault-group-BXjO5kHB.js';
4
- export { C as CapturedBlueprint, h as CrossVaultAggregation, i as CrossVaultDerivationContext, j as CrossVaultDerivationSpec, k as CrossVaultGroupedAggregation, G as CrossVaultGroupedRow, l as CrossVaultLiveAggregation, m as CrossVaultLiveQuery, D as DecryptedMergeOptions, n as DeploymentEvent, F as FanoutQueryOptions, o as FanoutResult, p as FieldAuthorityInputs, q as FieldAuthorityPolicy, r as FieldAuthorityPolicyMissingError, s as FieldAuthorityRule, t as FieldLevelDeferredError, L as LiveQueryOptions, u as MergeConflict, v as MergeStrategy, w as MigrationStatusRow, R as RefreshInsightsResult, x as SchemaManifestRow, y as SchemaRolloutResult, z as ShardedCollection, A as ShardedGroupedQuery, B as ShardedQuery, E as ShardingConfig, H as SurfaceStatus, I as VaultRegistryRow, J as mergeCompartment, K as mergeDecryptedRecords, N as resolveFieldAuthority, O as resolveRecordByFieldAuthority } from './vault-group-BXjO5kHB.js';
3
+ import { a as VaultTemplate, S as StateManagementVault, V as VaultGroup, b as SkippedVault, M as MergeCompartmentOptions, c as MergeReport, d as SurfaceDirection, e as SurfaceConflictPolicy, f as SurfaceRow, g as VaultGroupOptions } from './vault-group-DqEyXbN1.js';
4
+ export { C as CapturedBlueprint, h as CrossVaultAggregation, i as CrossVaultDerivationContext, j as CrossVaultDerivationSpec, k as CrossVaultGroupedAggregation, G as CrossVaultGroupedRow, l as CrossVaultLiveAggregation, m as CrossVaultLiveQuery, D as DecryptedMergeOptions, n as DeploymentEvent, F as FanoutQueryOptions, o as FanoutResult, p as FieldAuthorityInputs, q as FieldAuthorityPolicy, r as FieldAuthorityPolicyMissingError, s as FieldAuthorityRule, t as FieldLevelDeferredError, L as LiveQueryOptions, u as MergeConflict, v as MergeStrategy, w as MigrationStatusRow, R as RefreshInsightsResult, x as SchemaManifestRow, y as SchemaRolloutResult, z as ShardedCollection, A as ShardedGroupedQuery, B as ShardedQuery, E as ShardingConfig, H as SurfaceStatus, I as VaultRegistryRow, J as mergeCompartment, K as mergeDecryptedRecords, N as resolveFieldAuthority, O as resolveRecordByFieldAuthority } from './vault-group-DqEyXbN1.js';
5
5
  import { AsXlsxSheetOptions } from '@noy-db/as-xlsx';
6
6
  export { MultiVaultDenormColumn, MultiVaultXlsxEntry, MultiVaultXlsxOptions } from '@noy-db/as-xlsx';
7
7
  import { ExtractionPreview, WriteNoydbBundleOptions } from '@noy-db/hub/bundle';
package/dist/index.js CHANGED
@@ -1254,6 +1254,43 @@ var init_insight_auto_push = __esm({
1254
1254
  }
1255
1255
  });
1256
1256
 
1257
+ // src/federation/partial-reduce.ts
1258
+ function canPartialReduce(spec) {
1259
+ return Object.values(spec).every((r) => typeof r.merge === "function");
1260
+ }
1261
+ function reduceToPartial(records, spec) {
1262
+ const out = {};
1263
+ for (const [key, reducer] of Object.entries(spec)) {
1264
+ const r = reducer;
1265
+ let state = r.init();
1266
+ for (const rec of records) state = r.step(state, rec);
1267
+ out[key] = state;
1268
+ }
1269
+ return out;
1270
+ }
1271
+ function mergePartials(spec, partials) {
1272
+ const out = {};
1273
+ for (const [key, reducer] of Object.entries(spec)) {
1274
+ const r = reducer;
1275
+ let acc = r.init();
1276
+ for (const p of partials) acc = r.merge(acc, p[key]);
1277
+ out[key] = acc;
1278
+ }
1279
+ return out;
1280
+ }
1281
+ function finalizePartial(spec, merged) {
1282
+ const out = {};
1283
+ for (const [key, reducer] of Object.entries(spec)) {
1284
+ out[key] = reducer.finalize(merged[key]);
1285
+ }
1286
+ return out;
1287
+ }
1288
+ var init_partial_reduce = __esm({
1289
+ "src/federation/partial-reduce.ts"() {
1290
+ "use strict";
1291
+ }
1292
+ });
1293
+
1257
1294
  // src/federation/aggregate-across.ts
1258
1295
  import { reduceRecords } from "@noy-db/hub/kernel";
1259
1296
  import { groupAndReduce } from "@noy-db/hub/kernel";
@@ -1262,6 +1299,7 @@ var init_aggregate_across = __esm({
1262
1299
  "src/federation/aggregate-across.ts"() {
1263
1300
  "use strict";
1264
1301
  init_cross_vault_live();
1302
+ init_partial_reduce();
1265
1303
  CrossVaultAggregation = class {
1266
1304
  constructor(src, spec, bind) {
1267
1305
  this.src = src;
@@ -1272,6 +1310,10 @@ var init_aggregate_across = __esm({
1272
1310
  spec;
1273
1311
  bind;
1274
1312
  async run(options = {}) {
1313
+ if (this.src.fanoutReduce && canPartialReduce(this.spec)) {
1314
+ const { partials, skippedVaults: skippedVaults2 } = await this.src.fanoutReduce(this.spec, options);
1315
+ return { result: finalizePartial(this.spec, mergePartials(this.spec, partials)), skippedVaults: skippedVaults2 };
1316
+ }
1275
1317
  const { records, skippedVaults } = await this.src.fanoutRecords(options);
1276
1318
  return { result: reduceRecords(records, this.spec), skippedVaults };
1277
1319
  }
@@ -1398,6 +1440,7 @@ var init_vault_group = __esm({
1398
1440
  init_cross_vault_live();
1399
1441
  init_insight_auto_push();
1400
1442
  init_aggregate_across();
1443
+ init_partial_reduce();
1401
1444
  SHARD_SEPARATOR = "--";
1402
1445
  SAFE_PARTITION_KEY = /^[A-Za-z0-9._-]+$/;
1403
1446
  VaultGroup = class {
@@ -1536,22 +1579,33 @@ var init_vault_group = __esm({
1536
1579
  collection(collectionName) {
1537
1580
  return new ShardedCollection(this, collectionName);
1538
1581
  }
1539
- /** @internal — eligible (openable-candidate) rows + drift/divergence skips. */
1582
+ /** @internal — eligible (openable-candidate) rows + drift/divergence/unreachable skips. */
1540
1583
  async resolveEligible(options = {}) {
1541
1584
  const rows = await this.allRows();
1585
+ const candidates = options.only ? rows.filter((r) => options.only.includes(r.partitionKey)) : rows;
1542
1586
  const skipped = [];
1543
1587
  const versionOk = [];
1544
- for (const row of rows) {
1588
+ for (const row of candidates) {
1545
1589
  if (options.minVersion !== void 0 && row.schemaVersion < options.minVersion) {
1546
1590
  skipped.push({ vaultId: row.vaultId, reason: "schema-drift" });
1547
1591
  } else versionOk.push(row);
1548
1592
  }
1549
- const provisioned = await Promise.all(versionOk.map((r) => this.db._shardVaultProvisioned(r.vaultId)));
1593
+ const probes = await Promise.all(
1594
+ versionOk.map(async (row) => {
1595
+ try {
1596
+ return { row, provisioned: await this.db._shardVaultProvisioned(row.vaultId) };
1597
+ } catch (err) {
1598
+ if (options.failFast) throw err;
1599
+ return { row, error: err };
1600
+ }
1601
+ })
1602
+ );
1550
1603
  const eligible = [];
1551
- versionOk.forEach((row, i) => {
1552
- if (provisioned[i]) eligible.push(row);
1553
- else skipped.push({ vaultId: row.vaultId, reason: "error", error: new ShardProvisioningError(row.vaultId, row.partitionKey) });
1554
- });
1604
+ for (const p of probes) {
1605
+ if ("error" in p) skipped.push({ vaultId: p.row.vaultId, reason: "error", error: p.error });
1606
+ else if (p.provisioned) eligible.push(p.row);
1607
+ else skipped.push({ vaultId: p.row.vaultId, reason: "error", error: new ShardProvisioningError(p.row.vaultId, p.row.partitionKey) });
1608
+ }
1555
1609
  return { eligible, skipped };
1556
1610
  }
1557
1611
  /** @internal — registered push-model cross-vault derivations (#271 Insight Vault). */
@@ -1611,12 +1665,19 @@ var init_vault_group = __esm({
1611
1665
  * Insight Vault keyed by partition key. Shards behind `minVersion`,
1612
1666
  * unprovisioned, or whose read errors are reported in `skippedVaults` and
1613
1667
  * are not written (a stale summary is never left behind for a failed shard).
1668
+ * A shard whose backend is unreachable (provisioning probe or read throws) is
1669
+ * **skipped** (`reason: 'error'`) and the pass continues for the others — its
1670
+ * prior summary is left intact. Pass `failFast: true` for the legacy
1671
+ * all-or-nothing throw. Reconcile a lagging shard later with
1672
+ * `refreshInsights({ only: [pk] })` or `refreshDerivation(pk)`.
1614
1673
  */
1615
1674
  async refreshInsights(options = {}) {
1616
1675
  if (this.crossVaultDerivations.length === 0) return { written: 0, skippedVaults: [] };
1617
- const { eligible, skipped } = await this.resolveEligible(
1618
- options.minVersion !== void 0 ? { minVersion: options.minVersion } : {}
1619
- );
1676
+ const { eligible, skipped } = await this.resolveEligible({
1677
+ ...options.minVersion !== void 0 ? { minVersion: options.minVersion } : {},
1678
+ ...options.only !== void 0 ? { only: options.only } : {},
1679
+ ...options.failFast !== void 0 ? { failFast: options.failFast } : {}
1680
+ });
1620
1681
  let written = 0;
1621
1682
  for (const spec of this.crossVaultDerivations) {
1622
1683
  const results = await this.db.queryAcross(
@@ -1633,6 +1694,7 @@ var init_vault_group = __esm({
1633
1694
  const row = eligible[i];
1634
1695
  const res = results[i];
1635
1696
  if (!res || res.result === void 0) {
1697
+ if (options.failFast && res?.error) throw res.error;
1636
1698
  skipped.push({ vaultId: row.vaultId, reason: "error", ...res?.error ? { error: res.error } : {} });
1637
1699
  continue;
1638
1700
  }
@@ -1648,6 +1710,14 @@ var init_vault_group = __esm({
1648
1710
  }
1649
1711
  return { written, skippedVaults: skipped };
1650
1712
  }
1713
+ /**
1714
+ * Reconcile one shard's Insight summaries after its backend was unreachable.
1715
+ * Equivalent to `refreshInsights({ only: [partitionKey] })` — runs every
1716
+ * registered derivation (autoPush or not) for just this shard.
1717
+ */
1718
+ async refreshDerivation(partitionKey) {
1719
+ return this.refreshInsights({ only: [partitionKey] });
1720
+ }
1651
1721
  /** @internal — re-derive + push every autoPush derivation's summary for one shard. */
1652
1722
  async _recomputeShardInsights(partitionKey) {
1653
1723
  const row = await this.registry.get(this.registryId(partitionKey));
@@ -1883,6 +1953,34 @@ var init_vault_group = __esm({
1883
1953
  }
1884
1954
  return { records: results, skippedVaults: skipped };
1885
1955
  }
1956
+ /**
1957
+ * @internal — distributed partial-reduce (#8). Fan out across eligible shards,
1958
+ * but fold each shard's where-filtered records to a partial reducer STATE
1959
+ * inside the per-shard callback (never returning the rows). Only the scalar
1960
+ * `.aggregate()` path calls this, and that path rejects join legs upstream.
1961
+ */
1962
+ async fanoutReduce(spec, options = {}) {
1963
+ const { eligible, skipped } = await this.group.resolveEligible(options);
1964
+ const across = await this.group.db.queryAcross(
1965
+ eligible.map((r) => r.vaultId),
1966
+ async (vault) => {
1967
+ this.group.template.configure(vault);
1968
+ const coll = vault.collection(this.collectionName);
1969
+ await coll.list();
1970
+ let q = coll.query();
1971
+ for (const c of this.clauses) q = q.where(c.field, c.op, c.value);
1972
+ const rows = q.toArray();
1973
+ return reduceToPartial(rows, spec);
1974
+ },
1975
+ { concurrency: options.concurrency ?? 1, create: false }
1976
+ );
1977
+ const partials = [];
1978
+ for (const r of across) {
1979
+ if (r.error) skipped.push({ vaultId: r.vault, reason: classifyShardSkip(r.error), error: r.error });
1980
+ else partials.push(r.result);
1981
+ }
1982
+ return { partials, skippedVaults: skipped };
1983
+ }
1886
1984
  /** Fan out across eligible shards, merge, then apply any broadcast dimension legs. */
1887
1985
  async toArray(options = {}) {
1888
1986
  const { records, skippedVaults } = await this.fanoutRecords(options);