@klum-db/lobby 0.2.0-pre.32 → 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.
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-BchRCDm5.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 FederatedRetrieveHit, q as FederatedRetrieveOptions, r as FederatedRetrieveResult, s as FederationMeta, t as FieldAuthorityInputs, u as FieldAuthorityPolicy, v as FieldAuthorityPolicyMissingError, w as FieldAuthorityRule, x as FieldLevelDeferredError, y as GroupMeta, L as LiveQueryOptions, z as MergeConflict, A as MergeStrategy, B as MigrationStatusRow, R as RefreshInsightsResult, E as SchemaManifestRow, H as SchemaRolloutResult, I as ShardedCollection, J as ShardedGroupedQuery, K as ShardedQuery, N as ShardingConfig, O as SurfaceStatus, P as VaultRegistryRow, Q as mergeCompartment, T as mergeDecryptedRecords, U as resolveFieldAuthority, W as resolveRecordByFieldAuthority } from './vault-group-BchRCDm5.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-SfkQJ3CM.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 FederatedRetrieveHit, q as FederatedRetrieveOptions, r as FederatedRetrieveResult, s as FederationMeta, t as FieldAuthorityInputs, u as FieldAuthorityPolicy, v as FieldAuthorityPolicyMissingError, w as FieldAuthorityRule, x as FieldLevelDeferredError, y as GroupMeta, I as InsightAutoPushConfig, L as LiveQueryOptions, z as MergeConflict, A as MergeStrategy, B as MigrationStatusRow, R as RefreshInsightsResult, E as SchemaManifestRow, H as SchemaRolloutResult, J as ShardedCollection, K as ShardedGroupedQuery, N as ShardedQuery, O as ShardingConfig, P as SurfaceStatus, Q as VaultRegistryRow, T as mergeCompartment, U as mergeDecryptedRecords, W as resolveFieldAuthority, X as resolveRecordByFieldAuthority } from './vault-group-SfkQJ3CM.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-BchRCDm5.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 FederatedRetrieveHit, q as FederatedRetrieveOptions, r as FederatedRetrieveResult, s as FederationMeta, t as FieldAuthorityInputs, u as FieldAuthorityPolicy, v as FieldAuthorityPolicyMissingError, w as FieldAuthorityRule, x as FieldLevelDeferredError, y as GroupMeta, L as LiveQueryOptions, z as MergeConflict, A as MergeStrategy, B as MigrationStatusRow, R as RefreshInsightsResult, E as SchemaManifestRow, H as SchemaRolloutResult, I as ShardedCollection, J as ShardedGroupedQuery, K as ShardedQuery, N as ShardingConfig, O as SurfaceStatus, P as VaultRegistryRow, Q as mergeCompartment, T as mergeDecryptedRecords, U as resolveFieldAuthority, W as resolveRecordByFieldAuthority } from './vault-group-BchRCDm5.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-SfkQJ3CM.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 FederatedRetrieveHit, q as FederatedRetrieveOptions, r as FederatedRetrieveResult, s as FederationMeta, t as FieldAuthorityInputs, u as FieldAuthorityPolicy, v as FieldAuthorityPolicyMissingError, w as FieldAuthorityRule, x as FieldLevelDeferredError, y as GroupMeta, I as InsightAutoPushConfig, L as LiveQueryOptions, z as MergeConflict, A as MergeStrategy, B as MigrationStatusRow, R as RefreshInsightsResult, E as SchemaManifestRow, H as SchemaRolloutResult, J as ShardedCollection, K as ShardedGroupedQuery, N as ShardedQuery, O as ShardingConfig, P as SurfaceStatus, Q as VaultRegistryRow, T as mergeCompartment, U as mergeDecryptedRecords, W as resolveFieldAuthority, X as resolveRecordByFieldAuthority } from './vault-group-SfkQJ3CM.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
@@ -1209,28 +1209,33 @@ var init_insight_auto_push = __esm({
1209
1209
  "src/federation/insight-auto-push.ts"() {
1210
1210
  "use strict";
1211
1211
  InsightAutoPush = class {
1212
- constructor(recompute, isSource, onError = (err, pk) => console.warn(`[klum-db] insight auto-push failed for shard "${pk}":`, err)) {
1212
+ constructor(recompute, isSource, onError = (err, pk) => console.warn(`[klum-db] insight auto-push failed for shard "${pk}":`, err), debounceMs) {
1213
1213
  this.recompute = recompute;
1214
1214
  this.isSource = isSource;
1215
1215
  this.onError = onError;
1216
+ this.debounceMs = debounceMs;
1216
1217
  }
1217
1218
  recompute;
1218
1219
  isSource;
1219
1220
  onError;
1220
- /** Partition keys awaiting recompute. */
1221
+ debounceMs;
1221
1222
  dirty = /* @__PURE__ */ new Set();
1222
- /** The in-flight flush, or null when idle. */
1223
1223
  pending = null;
1224
+ timer = null;
1225
+ resolvePending = null;
1226
+ flushing = false;
1224
1227
  /** Called from a shard's onAfterWrite hook. Marks the shard dirty + schedules a flush. */
1225
1228
  noteWrite(partitionKey, collection) {
1226
1229
  if (!this.isSource(collection)) return;
1227
1230
  this.dirty.add(partitionKey);
1228
- this.schedule();
1231
+ if (this.debounceMs !== void 0) this.scheduleDebounced();
1232
+ else this.schedule();
1229
1233
  }
1230
1234
  /** Resolve once no flush is pending (drains rescheduled flushes too). */
1231
1235
  async whenSettled() {
1232
1236
  while (this.pending) await this.pending;
1233
1237
  }
1238
+ // ── microtask path (unchanged default) ──
1234
1239
  schedule() {
1235
1240
  if (this.pending) return;
1236
1241
  this.pending = this.runFlush().finally(() => {
@@ -1238,6 +1243,29 @@ var init_insight_auto_push = __esm({
1238
1243
  if (this.dirty.size > 0) this.schedule();
1239
1244
  });
1240
1245
  }
1246
+ // ── debounce path (#13) ──
1247
+ scheduleDebounced() {
1248
+ if (!this.pending) this.pending = new Promise((r) => {
1249
+ this.resolvePending = r;
1250
+ });
1251
+ if (this.timer) clearTimeout(this.timer);
1252
+ this.timer = setTimeout(() => {
1253
+ this.timer = null;
1254
+ if (this.flushing) return;
1255
+ this.flushing = true;
1256
+ void this.runFlush().finally(() => {
1257
+ this.flushing = false;
1258
+ if (this.dirty.size > 0) {
1259
+ this.scheduleDebounced();
1260
+ } else {
1261
+ const resolve = this.resolvePending;
1262
+ this.resolvePending = null;
1263
+ this.pending = null;
1264
+ resolve?.();
1265
+ }
1266
+ });
1267
+ }, this.debounceMs);
1268
+ }
1241
1269
  async runFlush() {
1242
1270
  await Promise.resolve();
1243
1271
  const pks = [...this.dirty];
@@ -1478,6 +1506,10 @@ __export(vault_group_exports, {
1478
1506
  VaultGroup: () => VaultGroup
1479
1507
  });
1480
1508
  import { CrossShardJoinError, DataResidencyError, ReservedVaultNameError, ShardProvisioningError, UnknownShardError, ValidationError } from "@noy-db/hub/kernel";
1509
+ function autoPushConfig(spec) {
1510
+ if (!spec.autoPush) return null;
1511
+ return spec.autoPush === true ? {} : spec.autoPush;
1512
+ }
1481
1513
  function assertSafePartitionKey(partitionKey) {
1482
1514
  if (partitionKey.length === 0) {
1483
1515
  throw new ValidationError("partitionKey must be a non-empty string");
@@ -1741,9 +1773,12 @@ var init_vault_group = __esm({
1741
1773
  }
1742
1774
  this.crossVaultDerivations.push(spec);
1743
1775
  if (spec.autoPush && !this.insightAutoPush) {
1776
+ const cfg = autoPushConfig(spec);
1744
1777
  const controller = new InsightAutoPush(
1745
1778
  (pk) => this._recomputeShardInsights(pk),
1746
- (collection) => this.crossVaultDerivations.some((s) => s.autoPush && s.source === collection)
1779
+ (collection) => this.crossVaultDerivations.some((s) => s.autoPush && s.source === collection),
1780
+ void 0,
1781
+ cfg?.debounceMs
1747
1782
  );
1748
1783
  this.insightAutoPush = controller;
1749
1784
  const prefix = `${this.name}${SHARD_SEPARATOR}`;
@@ -1824,6 +1859,8 @@ var init_vault_group = __esm({
1824
1859
  };
1825
1860
  for (const spec of this.crossVaultDerivations) {
1826
1861
  if (!spec.autoPush) continue;
1862
+ const min = autoPushConfig(spec)?.minVersion;
1863
+ if (min !== void 0 && row.schemaVersion < min) continue;
1827
1864
  const records = await shard.collection(spec.source).list();
1828
1865
  const summary = spec.derive(records, ctx);
1829
1866
  const insight = await this.db.openVault(spec.target.vault);
@@ -2104,23 +2141,23 @@ var init_vault_group = __esm({
2104
2141
  isRelevant: (e) => e.collection === collectionName && e.vault.startsWith(`${group.name}--`)
2105
2142
  };
2106
2143
  }
2107
- /** @internal — joined queries don't support reactive/aggregate surfaces in v1. */
2108
- assertNoJoinLegs(surface) {
2109
- if (this.coPartitionedLegs.length || this.broadcastLegs.length) {
2110
- throw new CrossShardJoinError(
2111
- `${surface}() is not supported on a ShardedQuery with crossShardJoin/broadcastJoin legs in v1. Use toArray() for joined cross-shard queries.`
2112
- );
2113
- }
2114
- }
2115
- /** Returns a reactive cross-shard live query — a facade over CrossVaultLive. */
2144
+ /**
2145
+ * Returns a reactive cross-shard live query — a facade over CrossVaultLive.
2146
+ *
2147
+ * Joined queries (crossShardJoin / broadcastJoin) are supported (#14): the live
2148
+ * value reflects the fully-joined rows. **v1 limitation:** recomputes only on
2149
+ * writes to the primary (left) collection; writes to a co-partitioned right
2150
+ * collection or a broadcast-dimension collection do NOT trigger a recompute —
2151
+ * re-run the query to pick those up.
2152
+ */
2116
2153
  live(options = {}) {
2117
- this.assertNoJoinLegs("live");
2118
2154
  const bind = this.liveBinding();
2119
2155
  const core = new CrossVaultLive({
2120
2156
  ...bind,
2121
2157
  compute: async () => {
2122
2158
  const { records, skippedVaults } = await this.fanoutRecords(options);
2123
- return { records, skipped: skippedVaults };
2159
+ const joined = await applyBroadcastLegs(records, this.broadcastLegs);
2160
+ return { records: joined, skipped: skippedVaults };
2124
2161
  },
2125
2162
  initialSnapshot: { records: [], skipped: [] },
2126
2163
  ...options.debounceMs !== void 0 ? { debounceMs: options.debounceMs } : {}
@@ -2140,14 +2177,28 @@ var init_vault_group = __esm({
2140
2177
  stop: () => core.stop()
2141
2178
  };
2142
2179
  }
2180
+ /**
2181
+ * @internal — the FanoutRecordSource for aggregate surfaces. With no join legs,
2182
+ * returns `this` (partial-reduce-eligible, #8). With join legs, returns a
2183
+ * toArray-backed source (fully-joined rows) and NO fanoutReduce, forcing
2184
+ * central-reduce over the joined rows (partial-reduce can't span the central
2185
+ * broadcast join). Used by scalar `aggregate()` and `ShardedGroupedQuery`.
2186
+ */
2187
+ aggregateSource() {
2188
+ if (!this.coPartitionedLegs.length && !this.broadcastLegs.length) return this;
2189
+ return {
2190
+ fanoutRecords: async (o) => {
2191
+ const { results, skippedVaults } = await this.toArray(o);
2192
+ return { records: results, skippedVaults };
2193
+ }
2194
+ };
2195
+ }
2143
2196
  /** One-shot distributed aggregate — central reduce over all shard records. */
2144
2197
  aggregate(spec) {
2145
- this.assertNoJoinLegs("aggregate");
2146
- return new CrossVaultAggregation(this, spec, this.liveBinding());
2198
+ return new CrossVaultAggregation(this.aggregateSource(), spec, this.liveBinding());
2147
2199
  }
2148
2200
  /** Begin a grouped cross-shard aggregate. */
2149
2201
  groupBy(field) {
2150
- this.assertNoJoinLegs("groupBy");
2151
2202
  return new ShardedGroupedQuery(this, field);
2152
2203
  }
2153
2204
  };
@@ -2160,7 +2211,7 @@ var init_vault_group = __esm({
2160
2211
  field;
2161
2212
  aggregate(spec) {
2162
2213
  return new CrossVaultGroupedAggregation(
2163
- { fanoutRecords: (o) => this.query.fanoutRecords(o) },
2214
+ this.query.aggregateSource(),
2164
2215
  this.field,
2165
2216
  spec,
2166
2217
  this.query.liveBinding()