@klum-db/lobby 0.2.0-pre.27 → 0.2.0-pre.29
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/README.md +4 -4
- package/dist/bin/klum.cjs +168 -0
- package/dist/bin/klum.cjs.map +1 -0
- package/dist/bin/klum.d.cts +25 -0
- package/dist/bin/klum.d.ts +25 -0
- package/dist/bin/klum.js +139 -0
- package/dist/bin/klum.js.map +1 -0
- package/dist/index.cjs +77 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -766
- package/dist/index.d.ts +58 -766
- package/dist/index.js +75 -11
- package/dist/index.js.map +1 -1
- package/dist/vault-group-BXjO5kHB.d.cts +763 -0
- package/dist/vault-group-BXjO5kHB.d.ts +763 -0
- package/package.json +14 -6
package/dist/index.js
CHANGED
|
@@ -1401,13 +1401,13 @@ var init_vault_group = __esm({
|
|
|
1401
1401
|
SHARD_SEPARATOR = "--";
|
|
1402
1402
|
SAFE_PARTITION_KEY = /^[A-Za-z0-9._-]+$/;
|
|
1403
1403
|
VaultGroup = class {
|
|
1404
|
-
constructor(db, name, registry, sharding, template,
|
|
1404
|
+
constructor(db, name, registry, sharding, template, cutoverOnOpen = false) {
|
|
1405
1405
|
this.db = db;
|
|
1406
1406
|
this.name = name;
|
|
1407
1407
|
this.registry = registry;
|
|
1408
1408
|
this.sharding = sharding;
|
|
1409
1409
|
this.template = template;
|
|
1410
|
-
this.
|
|
1410
|
+
this.cutoverOnOpen = cutoverOnOpen;
|
|
1411
1411
|
if (name.includes(SHARD_SEPARATOR)) {
|
|
1412
1412
|
throw new ValidationError(
|
|
1413
1413
|
`VaultGroup name "${name}" must not contain "--" (reserved shard vault-id separator).`
|
|
@@ -1419,7 +1419,7 @@ var init_vault_group = __esm({
|
|
|
1419
1419
|
registry;
|
|
1420
1420
|
sharding;
|
|
1421
1421
|
template;
|
|
1422
|
-
|
|
1422
|
+
cutoverOnOpen;
|
|
1423
1423
|
/** @internal — set when the group is managed (no explicit registry). */
|
|
1424
1424
|
stateVault;
|
|
1425
1425
|
/** @internal */
|
|
@@ -1454,20 +1454,20 @@ var init_vault_group = __esm({
|
|
|
1454
1454
|
return rows.filter((r) => r.group === this.name);
|
|
1455
1455
|
}
|
|
1456
1456
|
/**
|
|
1457
|
-
* Open an existing shard and apply the template. When `
|
|
1457
|
+
* Open an existing shard and apply the template. When `cutoverOnOpen` is set
|
|
1458
1458
|
* (#271) and the shard's registry version is behind the template, its cutover
|
|
1459
1459
|
* runs inline first — so a behind shard never surfaces a stale handle.
|
|
1460
1460
|
*/
|
|
1461
1461
|
async openShard(partitionKey) {
|
|
1462
|
-
if (this.
|
|
1462
|
+
if (this.cutoverOnOpen) {
|
|
1463
1463
|
const row = await this.registry.get(this.registryId(partitionKey));
|
|
1464
1464
|
if (row && row.schemaVersion < this.template.version) {
|
|
1465
|
-
await this.
|
|
1465
|
+
await this.cutoverShard(partitionKey);
|
|
1466
1466
|
}
|
|
1467
1467
|
}
|
|
1468
1468
|
return this._openShardRaw(partitionKey);
|
|
1469
1469
|
}
|
|
1470
|
-
/** @internal — open + configure with no
|
|
1470
|
+
/** @internal — open + configure with no cutover-on-open hook (used by the migration path itself to avoid recursion). */
|
|
1471
1471
|
async _openShardRaw(partitionKey) {
|
|
1472
1472
|
const vault = await this.db.openVault(this.shardVaultId(partitionKey), { create: false });
|
|
1473
1473
|
this.template.configure(vault);
|
|
@@ -1689,7 +1689,7 @@ var init_vault_group = __esm({
|
|
|
1689
1689
|
* Never throws on a cutover failure — it records `status: 'failed'` and
|
|
1690
1690
|
* returns the row, so a fleet run continues past a bad shard.
|
|
1691
1691
|
*/
|
|
1692
|
-
async
|
|
1692
|
+
async cutoverShard(partitionKey) {
|
|
1693
1693
|
const vaultId = this.shardVaultId(partitionKey);
|
|
1694
1694
|
const row = await this.registry.get(this.registryId(partitionKey));
|
|
1695
1695
|
if (!row) throw new UnknownShardError(partitionKey, this.name);
|
|
@@ -1740,7 +1740,7 @@ var init_vault_group = __esm({
|
|
|
1740
1740
|
* - `batchSize` — max shards migrated concurrently per batch (back-pressure).
|
|
1741
1741
|
* Default 4. Batches run sequentially; shards within a batch run in parallel.
|
|
1742
1742
|
*/
|
|
1743
|
-
async
|
|
1743
|
+
async rolloutSchema(options = {}) {
|
|
1744
1744
|
const target = this.template.version;
|
|
1745
1745
|
const rows = await this.allRows();
|
|
1746
1746
|
const cohort = options.cohort;
|
|
@@ -1752,7 +1752,7 @@ var init_vault_group = __esm({
|
|
|
1752
1752
|
const failed = [];
|
|
1753
1753
|
for (let i = 0; i < todo.length; i += batchSize) {
|
|
1754
1754
|
const batch = todo.slice(i, i + batchSize);
|
|
1755
|
-
const settled = await Promise.all(batch.map((r) => this.
|
|
1755
|
+
const settled = await Promise.all(batch.map((r) => this.cutoverShard(r.partitionKey)));
|
|
1756
1756
|
for (const res of settled) {
|
|
1757
1757
|
if (res.status === "done") migrated.push(res.vaultId);
|
|
1758
1758
|
else failed.push({ vaultId: res.vaultId, error: res.error ?? "unknown" });
|
|
@@ -1988,6 +1988,68 @@ var DockedUnit = class {
|
|
|
1988
1988
|
}
|
|
1989
1989
|
};
|
|
1990
1990
|
|
|
1991
|
+
// src/federation/group-inspector.ts
|
|
1992
|
+
function groupInspector(group) {
|
|
1993
|
+
let shardIds = /* @__PURE__ */ new Set();
|
|
1994
|
+
const refresh = async () => {
|
|
1995
|
+
const rows = await group.allRows();
|
|
1996
|
+
shardIds = new Set(rows.map((r) => r.vaultId));
|
|
1997
|
+
return rows;
|
|
1998
|
+
};
|
|
1999
|
+
return {
|
|
2000
|
+
async listAccessibleVaults() {
|
|
2001
|
+
const rows = await refresh();
|
|
2002
|
+
return rows.map((r) => ({ id: r.vaultId, role: "owner" }));
|
|
2003
|
+
},
|
|
2004
|
+
async openVault(name) {
|
|
2005
|
+
const vault = await group.db.openVault(name);
|
|
2006
|
+
group.template.configure(vault);
|
|
2007
|
+
return vault;
|
|
2008
|
+
},
|
|
2009
|
+
onAfterWrite(handler) {
|
|
2010
|
+
return group.db.onAfterWrite((event) => {
|
|
2011
|
+
if (shardIds.has(event.vault)) return handler(event);
|
|
2012
|
+
});
|
|
2013
|
+
},
|
|
2014
|
+
onWriteConflict(handler) {
|
|
2015
|
+
return group.db.onWriteConflict((c) => {
|
|
2016
|
+
if (shardIds.has(c.vault)) handler(c);
|
|
2017
|
+
});
|
|
2018
|
+
},
|
|
2019
|
+
get writeQueue() {
|
|
2020
|
+
return group.db.writeQueue;
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
// src/federation/meter-group.ts
|
|
2026
|
+
async function meterGroup(group, opts = {}) {
|
|
2027
|
+
const { eligible, skipped } = await group.resolveEligible(
|
|
2028
|
+
opts.minVersion !== void 0 ? { minVersion: opts.minVersion } : {}
|
|
2029
|
+
);
|
|
2030
|
+
const perShard = [];
|
|
2031
|
+
const names = /* @__PURE__ */ new Set();
|
|
2032
|
+
let records = 0;
|
|
2033
|
+
for (const row of eligible) {
|
|
2034
|
+
const vault = await group.shard(row.partitionKey);
|
|
2035
|
+
const collNames = await vault.collections();
|
|
2036
|
+
let shardRecords = 0;
|
|
2037
|
+
for (const n of collNames) {
|
|
2038
|
+
names.add(n);
|
|
2039
|
+
shardRecords += await vault.collection(n).count();
|
|
2040
|
+
}
|
|
2041
|
+
records += shardRecords;
|
|
2042
|
+
perShard.push({
|
|
2043
|
+
vaultId: row.vaultId,
|
|
2044
|
+
partitionKey: row.partitionKey,
|
|
2045
|
+
schemaVersion: row.schemaVersion,
|
|
2046
|
+
collections: collNames.length,
|
|
2047
|
+
records: shardRecords
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
return { vaults: eligible.length, collections: names.size, records, perShard, skipped };
|
|
2051
|
+
}
|
|
2052
|
+
|
|
1991
2053
|
// src/index.ts
|
|
1992
2054
|
init_multi_bundle();
|
|
1993
2055
|
init_extract_cross_vault();
|
|
@@ -2092,7 +2154,7 @@ var Lobby = class {
|
|
|
2092
2154
|
const { StateManagementVault: StateManagementVault2 } = await Promise.resolve().then(() => (init_state_vault(), state_vault_exports));
|
|
2093
2155
|
const stateVault = opts.registry ? void 0 : await StateManagementVault2.open(db);
|
|
2094
2156
|
const registry = opts.registry ?? stateVault.registry;
|
|
2095
|
-
const group = new VaultGroup2(db, name, registry, opts.sharding, template, opts.
|
|
2157
|
+
const group = new VaultGroup2(db, name, registry, opts.sharding, template, opts.cutoverOnOpen ?? false);
|
|
2096
2158
|
if (stateVault) {
|
|
2097
2159
|
group._attachStateVault(stateVault);
|
|
2098
2160
|
await stateVault.recordManifest(opts.sharding.vaultTemplate, template);
|
|
@@ -2224,6 +2286,7 @@ export {
|
|
|
2224
2286
|
encodeMultiBundle,
|
|
2225
2287
|
exportSurface,
|
|
2226
2288
|
extractCrossVaultPartition,
|
|
2289
|
+
groupInspector,
|
|
2227
2290
|
isDeedVault,
|
|
2228
2291
|
isSurfaceDue,
|
|
2229
2292
|
liberateVault,
|
|
@@ -2232,6 +2295,7 @@ export {
|
|
|
2232
2295
|
markSynced,
|
|
2233
2296
|
mergeCompartment,
|
|
2234
2297
|
mergeDecryptedRecords,
|
|
2298
|
+
meterGroup,
|
|
2235
2299
|
migrateThenMerge,
|
|
2236
2300
|
proposeSurface,
|
|
2237
2301
|
readMultiVaultBundleCompartment,
|