@klum-db/lobby 0.2.0-pre.27 → 0.2.0-pre.28
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/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 +66 -0
- 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 +64 -0
- package/dist/index.js.map +1 -1
- package/dist/vault-group-DeBoCFT9.d.cts +763 -0
- package/dist/vault-group-DeBoCFT9.d.ts +763 -0
- package/package.json +14 -6
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/bin/klum.ts
|
|
21
|
+
var klum_exports = {};
|
|
22
|
+
__export(klum_exports, {
|
|
23
|
+
main: () => main,
|
|
24
|
+
parseArgs: () => parseArgs,
|
|
25
|
+
runInspectGroup: () => runInspectGroup,
|
|
26
|
+
runMeterGroup: () => runMeterGroup
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(klum_exports);
|
|
29
|
+
var import_in_devtools = require("@noy-db/in-devtools");
|
|
30
|
+
|
|
31
|
+
// src/federation/group-inspector.ts
|
|
32
|
+
function groupInspector(group) {
|
|
33
|
+
let shardIds = /* @__PURE__ */ new Set();
|
|
34
|
+
const refresh = async () => {
|
|
35
|
+
const rows = await group.allRows();
|
|
36
|
+
shardIds = new Set(rows.map((r) => r.vaultId));
|
|
37
|
+
return rows;
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
async listAccessibleVaults() {
|
|
41
|
+
const rows = await refresh();
|
|
42
|
+
return rows.map((r) => ({ id: r.vaultId, role: "owner" }));
|
|
43
|
+
},
|
|
44
|
+
async openVault(name) {
|
|
45
|
+
const vault = await group.db.openVault(name);
|
|
46
|
+
group.template.configure(vault);
|
|
47
|
+
return vault;
|
|
48
|
+
},
|
|
49
|
+
onAfterWrite(handler) {
|
|
50
|
+
return group.db.onAfterWrite((event) => {
|
|
51
|
+
if (shardIds.has(event.vault)) return handler(event);
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
onWriteConflict(handler) {
|
|
55
|
+
return group.db.onWriteConflict((c) => {
|
|
56
|
+
if (shardIds.has(c.vault)) handler(c);
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
get writeQueue() {
|
|
60
|
+
return group.db.writeQueue;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/federation/meter-group.ts
|
|
66
|
+
async function meterGroup(group, opts = {}) {
|
|
67
|
+
const { eligible, skipped } = await group.resolveEligible(
|
|
68
|
+
opts.minVersion !== void 0 ? { minVersion: opts.minVersion } : {}
|
|
69
|
+
);
|
|
70
|
+
const perShard = [];
|
|
71
|
+
const names = /* @__PURE__ */ new Set();
|
|
72
|
+
let records = 0;
|
|
73
|
+
for (const row of eligible) {
|
|
74
|
+
const vault = await group.shard(row.partitionKey);
|
|
75
|
+
const collNames = await vault.collections();
|
|
76
|
+
let shardRecords = 0;
|
|
77
|
+
for (const n of collNames) {
|
|
78
|
+
names.add(n);
|
|
79
|
+
shardRecords += await vault.collection(n).count();
|
|
80
|
+
}
|
|
81
|
+
records += shardRecords;
|
|
82
|
+
perShard.push({
|
|
83
|
+
vaultId: row.vaultId,
|
|
84
|
+
partitionKey: row.partitionKey,
|
|
85
|
+
schemaVersion: row.schemaVersion,
|
|
86
|
+
collections: collNames.length,
|
|
87
|
+
records: shardRecords
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return { vaults: eligible.length, collections: names.size, records, perShard, skipped };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/bin/klum.ts
|
|
94
|
+
var import_meta = {};
|
|
95
|
+
function parseArgs(argv) {
|
|
96
|
+
const out = { command: argv[0] ?? "", meter: false };
|
|
97
|
+
for (const a of argv.slice(1)) {
|
|
98
|
+
if (a.startsWith("--group=")) out.group = a.slice("--group=".length);
|
|
99
|
+
else if (a.startsWith("--vault=")) out.vault = a.slice("--vault=".length);
|
|
100
|
+
else if (a === "--meter") out.meter = true;
|
|
101
|
+
else if (!a.startsWith("--")) out.configPath = a;
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
async function loadGroup(args) {
|
|
106
|
+
const mod = await import(args.configPath);
|
|
107
|
+
return mod.default(args.group);
|
|
108
|
+
}
|
|
109
|
+
async function runInspectGroup(args, log) {
|
|
110
|
+
if (!args.configPath) {
|
|
111
|
+
log("usage: klum inspect-group <config> --group=<name> [--vault=<id>]");
|
|
112
|
+
return 2;
|
|
113
|
+
}
|
|
114
|
+
const group = await loadGroup(args);
|
|
115
|
+
const inspector = (0, import_in_devtools.createInspector)(groupInspector(group));
|
|
116
|
+
const vaults = await inspector.listVaults();
|
|
117
|
+
log(`group "${args.group ?? ""}" \u2014 ${vaults.length} shard(s):`);
|
|
118
|
+
for (const v of vaults) log(` ${v.id} [${v.role}]`);
|
|
119
|
+
if (args.vault) {
|
|
120
|
+
const vault = await group.db.openVault(args.vault);
|
|
121
|
+
group.template.configure(vault);
|
|
122
|
+
const snap = await inspector.snapshot(vault);
|
|
123
|
+
log(` collections in ${args.vault}: ${snap.collections.map((c) => c.name).join(", ")}`);
|
|
124
|
+
}
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
async function runMeterGroup(args, log) {
|
|
128
|
+
if (!args.configPath) {
|
|
129
|
+
log("usage: klum meter-group <config> --group=<name>");
|
|
130
|
+
return 2;
|
|
131
|
+
}
|
|
132
|
+
const group = await loadGroup(args);
|
|
133
|
+
const r = await meterGroup(group);
|
|
134
|
+
log(`group "${args.group ?? ""}" \u2014 ${r.vaults} vault(s), ${r.collections} collection(s), ${r.records} record(s)`);
|
|
135
|
+
for (const s of r.perShard) {
|
|
136
|
+
log(` ${s.vaultId} (${s.partitionKey}) v${s.schemaVersion}: ${s.collections} coll, ${s.records} rec`);
|
|
137
|
+
}
|
|
138
|
+
if (r.skipped.length) log(` skipped: ${r.skipped.length} shard(s)`);
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
async function main(argv, log = console.log) {
|
|
142
|
+
const args = parseArgs(argv);
|
|
143
|
+
switch (args.command) {
|
|
144
|
+
case "inspect-group":
|
|
145
|
+
return runInspectGroup(args, log);
|
|
146
|
+
case "meter-group":
|
|
147
|
+
return runMeterGroup(args, log);
|
|
148
|
+
default:
|
|
149
|
+
log("klum <inspect-group|meter-group> <config> --group=<name> [--vault=<id>]");
|
|
150
|
+
return args.command ? 1 : 0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (process.argv[1] && import_meta.url === `file://${process.argv[1]}`) {
|
|
154
|
+
main(process.argv.slice(2)).then((code) => {
|
|
155
|
+
process.exitCode = code;
|
|
156
|
+
}).catch((e) => {
|
|
157
|
+
console.error(e);
|
|
158
|
+
process.exitCode = 1;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
162
|
+
0 && (module.exports = {
|
|
163
|
+
main,
|
|
164
|
+
parseArgs,
|
|
165
|
+
runInspectGroup,
|
|
166
|
+
runMeterGroup
|
|
167
|
+
});
|
|
168
|
+
//# sourceMappingURL=klum.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bin/klum.ts","../../src/federation/group-inspector.ts","../../src/federation/meter-group.ts"],"sourcesContent":["import { createInspector } from '@noy-db/in-devtools'\nimport { groupInspector } from '../federation/group-inspector.js'\nimport { meterGroup } from '../federation/meter-group.js'\nimport type { VaultGroup } from '../federation/vault-group.js'\n\n/**\n * A config module for the `klum` CLI default-exports this factory: given an\n * optional group name, it returns an opened VaultGroup (the user's module owns\n * the store, templates, and sharding config — the CLI stays agnostic of them).\n */\nexport type GroupFactory = (groupName?: string) => Promise<VaultGroup<unknown>>\n\ntype Log = (s: string) => void\n\nexport interface ParsedArgs {\n command: string\n configPath?: string\n group?: string\n vault?: string\n meter: boolean\n}\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const out: ParsedArgs = { command: argv[0] ?? '', meter: false }\n for (const a of argv.slice(1)) {\n if (a.startsWith('--group=')) out.group = a.slice('--group='.length)\n else if (a.startsWith('--vault=')) out.vault = a.slice('--vault='.length)\n else if (a === '--meter') out.meter = true\n else if (!a.startsWith('--')) out.configPath = a\n }\n return out\n}\n\nasync function loadGroup(args: ParsedArgs): Promise<VaultGroup<unknown>> {\n const mod = (await import(args.configPath!)) as { default: GroupFactory }\n return mod.default(args.group)\n}\n\nexport async function runInspectGroup(args: ParsedArgs, log: Log): Promise<number> {\n if (!args.configPath) {\n log('usage: klum inspect-group <config> --group=<name> [--vault=<id>]')\n return 2\n }\n const group = await loadGroup(args)\n const inspector = createInspector(groupInspector(group))\n const vaults = await inspector.listVaults()\n log(`group \"${args.group ?? ''}\" — ${vaults.length} shard(s):`)\n for (const v of vaults) log(` ${v.id} [${v.role}]`)\n if (args.vault) {\n const vault = await group.db.openVault(args.vault)\n group.template.configure(vault)\n const snap = await inspector.snapshot(vault)\n log(` collections in ${args.vault}: ${snap.collections.map((c) => c.name).join(', ')}`)\n }\n return 0\n}\n\nexport async function runMeterGroup(args: ParsedArgs, log: Log): Promise<number> {\n if (!args.configPath) {\n log('usage: klum meter-group <config> --group=<name>')\n return 2\n }\n const group = await loadGroup(args)\n const r = await meterGroup(group)\n log(`group \"${args.group ?? ''}\" — ${r.vaults} vault(s), ${r.collections} collection(s), ${r.records} record(s)`)\n for (const s of r.perShard) {\n log(` ${s.vaultId} (${s.partitionKey}) v${s.schemaVersion}: ${s.collections} coll, ${s.records} rec`)\n }\n if (r.skipped.length) log(` skipped: ${r.skipped.length} shard(s)`)\n return 0\n}\n\nexport async function main(argv: readonly string[], log: Log = console.log): Promise<number> {\n const args = parseArgs(argv)\n switch (args.command) {\n case 'inspect-group':\n return runInspectGroup(args, log)\n case 'meter-group':\n return runMeterGroup(args, log)\n default:\n log('klum <inspect-group|meter-group> <config> --group=<name> [--vault=<id>]')\n return args.command ? 1 : 0\n }\n}\n\n// bin entrypoint — only runs when executed directly, not when imported in tests.\nif (process.argv[1] && import.meta.url === `file://${process.argv[1]}`) {\n main(process.argv.slice(2))\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n console.error(e)\n process.exitCode = 1\n })\n}\n","import type { InspectableContainer } from '@noy-db/in-devtools'\nimport type { AccessibleVault, Vault, WriteHook, WriteConflict, WriteQueue, Unsubscribe } from '@noy-db/hub'\nimport type { VaultGroup } from './vault-group.js'\n\n/**\n * Adapt a federation {@link VaultGroup} to the dev-tools `InspectableContainer`\n * contract from `@noy-db/in-devtools`, so the inspector / TUI can browse a\n * whole fleet exactly like a single instance.\n *\n * Built entirely on the group's public surface (`allRows`, `db`, `template`) —\n * no `VaultGroup` changes, and (critically) no `@klum-db` import lands in any\n * `@noy-db` package: the dependency runs one way, klum → noy.\n *\n * Write-event scoping: `group.db` may host vaults outside this group, so write\n * and conflict events are filtered to the group's shard ids. The id set is\n * primed/refreshed on every `listAccessibleVaults()` call — drive `listVaults()`\n * (the inspector's normal first step) before relying on event scoping.\n */\nexport function groupInspector<T>(group: VaultGroup<T>): InspectableContainer {\n let shardIds = new Set<string>()\n const refresh = async () => {\n const rows = await group.allRows()\n shardIds = new Set(rows.map((r) => r.vaultId))\n return rows\n }\n return {\n async listAccessibleVaults(): Promise<readonly AccessibleVault[]> {\n const rows = await refresh()\n return rows.map((r): AccessibleVault => ({ id: r.vaultId, role: 'owner' }))\n },\n async openVault(name: string): Promise<Vault> {\n const vault = await group.db.openVault(name)\n group.template.configure(vault)\n return vault\n },\n onAfterWrite(handler: WriteHook): Unsubscribe {\n return group.db.onAfterWrite((event) => {\n if (shardIds.has(event.vault)) return handler(event)\n })\n },\n onWriteConflict(handler: (c: WriteConflict) => void): Unsubscribe {\n return group.db.onWriteConflict((c) => {\n if (shardIds.has(c.vault)) handler(c)\n })\n },\n get writeQueue(): WriteQueue {\n return group.db.writeQueue\n },\n }\n}\n","import type { VaultGroup } from './vault-group.js'\nimport type { SkippedVault } from './types.js'\n\nexport interface GroupShardMetrics {\n readonly vaultId: string\n readonly partitionKey: string\n readonly schemaVersion: number\n readonly collections: number\n readonly records: number\n}\n\nexport interface GroupMeterReport {\n /** Number of eligible shards measured. */\n readonly vaults: number\n /** Distinct collection names across the group. */\n readonly collections: number\n /** Total record count summed across shards. */\n readonly records: number\n readonly perShard: ReadonlyArray<GroupShardMetrics>\n /** Drifted / provisioning-failed shards — surfaced, never counted or hidden. */\n readonly skipped: ReadonlyArray<SkippedVault>\n}\n\n/**\n * Fan shape-metrics (collection count + record count) across the group's\n * ELIGIBLE shards. Skipped shards (schema-drift / provisioning failures) are\n * reported in `skipped`, never silently dropped. Reuses the per-vault pattern\n * from `multi-bundle.ts` (`vault.collections()` → `collection(n).count()`).\n *\n * Operational store metrics (calls, CAS conflicts) are a separate concern and\n * are already group-wide via `@noy-db/to-meter` on the underlying store.\n */\nexport async function meterGroup<T>(\n group: VaultGroup<T>,\n opts: { minVersion?: number } = {},\n): Promise<GroupMeterReport> {\n const { eligible, skipped } = await group.resolveEligible(\n opts.minVersion !== undefined ? { minVersion: opts.minVersion } : {},\n )\n const perShard: GroupShardMetrics[] = []\n const names = new Set<string>()\n let records = 0\n for (const row of eligible) {\n const vault = await group.shard(row.partitionKey)\n const collNames = await vault.collections()\n let shardRecords = 0\n for (const n of collNames) {\n names.add(n)\n shardRecords += await vault.collection(n).count()\n }\n records += shardRecords\n perShard.push({\n vaultId: row.vaultId,\n partitionKey: row.partitionKey,\n schemaVersion: row.schemaVersion,\n collections: collNames.length,\n records: shardRecords,\n })\n }\n return { vaults: eligible.length, collections: names.size, records, perShard, skipped }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { V as VaultGroup } from '../vault-group-DeBoCFT9.cjs';
|
|
2
|
+
import '@noy-db/hub/kernel';
|
|
3
|
+
import '@noy-db/hub';
|
|
4
|
+
import '@noy-db/hub/bundle';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A config module for the `klum` CLI default-exports this factory: given an
|
|
8
|
+
* optional group name, it returns an opened VaultGroup (the user's module owns
|
|
9
|
+
* the store, templates, and sharding config — the CLI stays agnostic of them).
|
|
10
|
+
*/
|
|
11
|
+
type GroupFactory = (groupName?: string) => Promise<VaultGroup<unknown>>;
|
|
12
|
+
type Log = (s: string) => void;
|
|
13
|
+
interface ParsedArgs {
|
|
14
|
+
command: string;
|
|
15
|
+
configPath?: string;
|
|
16
|
+
group?: string;
|
|
17
|
+
vault?: string;
|
|
18
|
+
meter: boolean;
|
|
19
|
+
}
|
|
20
|
+
declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
21
|
+
declare function runInspectGroup(args: ParsedArgs, log: Log): Promise<number>;
|
|
22
|
+
declare function runMeterGroup(args: ParsedArgs, log: Log): Promise<number>;
|
|
23
|
+
declare function main(argv: readonly string[], log?: Log): Promise<number>;
|
|
24
|
+
|
|
25
|
+
export { type GroupFactory, type ParsedArgs, main, parseArgs, runInspectGroup, runMeterGroup };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { V as VaultGroup } from '../vault-group-DeBoCFT9.js';
|
|
2
|
+
import '@noy-db/hub/kernel';
|
|
3
|
+
import '@noy-db/hub';
|
|
4
|
+
import '@noy-db/hub/bundle';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A config module for the `klum` CLI default-exports this factory: given an
|
|
8
|
+
* optional group name, it returns an opened VaultGroup (the user's module owns
|
|
9
|
+
* the store, templates, and sharding config — the CLI stays agnostic of them).
|
|
10
|
+
*/
|
|
11
|
+
type GroupFactory = (groupName?: string) => Promise<VaultGroup<unknown>>;
|
|
12
|
+
type Log = (s: string) => void;
|
|
13
|
+
interface ParsedArgs {
|
|
14
|
+
command: string;
|
|
15
|
+
configPath?: string;
|
|
16
|
+
group?: string;
|
|
17
|
+
vault?: string;
|
|
18
|
+
meter: boolean;
|
|
19
|
+
}
|
|
20
|
+
declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
21
|
+
declare function runInspectGroup(args: ParsedArgs, log: Log): Promise<number>;
|
|
22
|
+
declare function runMeterGroup(args: ParsedArgs, log: Log): Promise<number>;
|
|
23
|
+
declare function main(argv: readonly string[], log?: Log): Promise<number>;
|
|
24
|
+
|
|
25
|
+
export { type GroupFactory, type ParsedArgs, main, parseArgs, runInspectGroup, runMeterGroup };
|
package/dist/bin/klum.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// src/bin/klum.ts
|
|
2
|
+
import { createInspector } from "@noy-db/in-devtools";
|
|
3
|
+
|
|
4
|
+
// src/federation/group-inspector.ts
|
|
5
|
+
function groupInspector(group) {
|
|
6
|
+
let shardIds = /* @__PURE__ */ new Set();
|
|
7
|
+
const refresh = async () => {
|
|
8
|
+
const rows = await group.allRows();
|
|
9
|
+
shardIds = new Set(rows.map((r) => r.vaultId));
|
|
10
|
+
return rows;
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
async listAccessibleVaults() {
|
|
14
|
+
const rows = await refresh();
|
|
15
|
+
return rows.map((r) => ({ id: r.vaultId, role: "owner" }));
|
|
16
|
+
},
|
|
17
|
+
async openVault(name) {
|
|
18
|
+
const vault = await group.db.openVault(name);
|
|
19
|
+
group.template.configure(vault);
|
|
20
|
+
return vault;
|
|
21
|
+
},
|
|
22
|
+
onAfterWrite(handler) {
|
|
23
|
+
return group.db.onAfterWrite((event) => {
|
|
24
|
+
if (shardIds.has(event.vault)) return handler(event);
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
onWriteConflict(handler) {
|
|
28
|
+
return group.db.onWriteConflict((c) => {
|
|
29
|
+
if (shardIds.has(c.vault)) handler(c);
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
get writeQueue() {
|
|
33
|
+
return group.db.writeQueue;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/federation/meter-group.ts
|
|
39
|
+
async function meterGroup(group, opts = {}) {
|
|
40
|
+
const { eligible, skipped } = await group.resolveEligible(
|
|
41
|
+
opts.minVersion !== void 0 ? { minVersion: opts.minVersion } : {}
|
|
42
|
+
);
|
|
43
|
+
const perShard = [];
|
|
44
|
+
const names = /* @__PURE__ */ new Set();
|
|
45
|
+
let records = 0;
|
|
46
|
+
for (const row of eligible) {
|
|
47
|
+
const vault = await group.shard(row.partitionKey);
|
|
48
|
+
const collNames = await vault.collections();
|
|
49
|
+
let shardRecords = 0;
|
|
50
|
+
for (const n of collNames) {
|
|
51
|
+
names.add(n);
|
|
52
|
+
shardRecords += await vault.collection(n).count();
|
|
53
|
+
}
|
|
54
|
+
records += shardRecords;
|
|
55
|
+
perShard.push({
|
|
56
|
+
vaultId: row.vaultId,
|
|
57
|
+
partitionKey: row.partitionKey,
|
|
58
|
+
schemaVersion: row.schemaVersion,
|
|
59
|
+
collections: collNames.length,
|
|
60
|
+
records: shardRecords
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { vaults: eligible.length, collections: names.size, records, perShard, skipped };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/bin/klum.ts
|
|
67
|
+
function parseArgs(argv) {
|
|
68
|
+
const out = { command: argv[0] ?? "", meter: false };
|
|
69
|
+
for (const a of argv.slice(1)) {
|
|
70
|
+
if (a.startsWith("--group=")) out.group = a.slice("--group=".length);
|
|
71
|
+
else if (a.startsWith("--vault=")) out.vault = a.slice("--vault=".length);
|
|
72
|
+
else if (a === "--meter") out.meter = true;
|
|
73
|
+
else if (!a.startsWith("--")) out.configPath = a;
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
async function loadGroup(args) {
|
|
78
|
+
const mod = await import(args.configPath);
|
|
79
|
+
return mod.default(args.group);
|
|
80
|
+
}
|
|
81
|
+
async function runInspectGroup(args, log) {
|
|
82
|
+
if (!args.configPath) {
|
|
83
|
+
log("usage: klum inspect-group <config> --group=<name> [--vault=<id>]");
|
|
84
|
+
return 2;
|
|
85
|
+
}
|
|
86
|
+
const group = await loadGroup(args);
|
|
87
|
+
const inspector = createInspector(groupInspector(group));
|
|
88
|
+
const vaults = await inspector.listVaults();
|
|
89
|
+
log(`group "${args.group ?? ""}" \u2014 ${vaults.length} shard(s):`);
|
|
90
|
+
for (const v of vaults) log(` ${v.id} [${v.role}]`);
|
|
91
|
+
if (args.vault) {
|
|
92
|
+
const vault = await group.db.openVault(args.vault);
|
|
93
|
+
group.template.configure(vault);
|
|
94
|
+
const snap = await inspector.snapshot(vault);
|
|
95
|
+
log(` collections in ${args.vault}: ${snap.collections.map((c) => c.name).join(", ")}`);
|
|
96
|
+
}
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
async function runMeterGroup(args, log) {
|
|
100
|
+
if (!args.configPath) {
|
|
101
|
+
log("usage: klum meter-group <config> --group=<name>");
|
|
102
|
+
return 2;
|
|
103
|
+
}
|
|
104
|
+
const group = await loadGroup(args);
|
|
105
|
+
const r = await meterGroup(group);
|
|
106
|
+
log(`group "${args.group ?? ""}" \u2014 ${r.vaults} vault(s), ${r.collections} collection(s), ${r.records} record(s)`);
|
|
107
|
+
for (const s of r.perShard) {
|
|
108
|
+
log(` ${s.vaultId} (${s.partitionKey}) v${s.schemaVersion}: ${s.collections} coll, ${s.records} rec`);
|
|
109
|
+
}
|
|
110
|
+
if (r.skipped.length) log(` skipped: ${r.skipped.length} shard(s)`);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
async function main(argv, log = console.log) {
|
|
114
|
+
const args = parseArgs(argv);
|
|
115
|
+
switch (args.command) {
|
|
116
|
+
case "inspect-group":
|
|
117
|
+
return runInspectGroup(args, log);
|
|
118
|
+
case "meter-group":
|
|
119
|
+
return runMeterGroup(args, log);
|
|
120
|
+
default:
|
|
121
|
+
log("klum <inspect-group|meter-group> <config> --group=<name> [--vault=<id>]");
|
|
122
|
+
return args.command ? 1 : 0;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (process.argv[1] && import.meta.url === `file://${process.argv[1]}`) {
|
|
126
|
+
main(process.argv.slice(2)).then((code) => {
|
|
127
|
+
process.exitCode = code;
|
|
128
|
+
}).catch((e) => {
|
|
129
|
+
console.error(e);
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
export {
|
|
134
|
+
main,
|
|
135
|
+
parseArgs,
|
|
136
|
+
runInspectGroup,
|
|
137
|
+
runMeterGroup
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=klum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bin/klum.ts","../../src/federation/group-inspector.ts","../../src/federation/meter-group.ts"],"sourcesContent":["import { createInspector } from '@noy-db/in-devtools'\nimport { groupInspector } from '../federation/group-inspector.js'\nimport { meterGroup } from '../federation/meter-group.js'\nimport type { VaultGroup } from '../federation/vault-group.js'\n\n/**\n * A config module for the `klum` CLI default-exports this factory: given an\n * optional group name, it returns an opened VaultGroup (the user's module owns\n * the store, templates, and sharding config — the CLI stays agnostic of them).\n */\nexport type GroupFactory = (groupName?: string) => Promise<VaultGroup<unknown>>\n\ntype Log = (s: string) => void\n\nexport interface ParsedArgs {\n command: string\n configPath?: string\n group?: string\n vault?: string\n meter: boolean\n}\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const out: ParsedArgs = { command: argv[0] ?? '', meter: false }\n for (const a of argv.slice(1)) {\n if (a.startsWith('--group=')) out.group = a.slice('--group='.length)\n else if (a.startsWith('--vault=')) out.vault = a.slice('--vault='.length)\n else if (a === '--meter') out.meter = true\n else if (!a.startsWith('--')) out.configPath = a\n }\n return out\n}\n\nasync function loadGroup(args: ParsedArgs): Promise<VaultGroup<unknown>> {\n const mod = (await import(args.configPath!)) as { default: GroupFactory }\n return mod.default(args.group)\n}\n\nexport async function runInspectGroup(args: ParsedArgs, log: Log): Promise<number> {\n if (!args.configPath) {\n log('usage: klum inspect-group <config> --group=<name> [--vault=<id>]')\n return 2\n }\n const group = await loadGroup(args)\n const inspector = createInspector(groupInspector(group))\n const vaults = await inspector.listVaults()\n log(`group \"${args.group ?? ''}\" — ${vaults.length} shard(s):`)\n for (const v of vaults) log(` ${v.id} [${v.role}]`)\n if (args.vault) {\n const vault = await group.db.openVault(args.vault)\n group.template.configure(vault)\n const snap = await inspector.snapshot(vault)\n log(` collections in ${args.vault}: ${snap.collections.map((c) => c.name).join(', ')}`)\n }\n return 0\n}\n\nexport async function runMeterGroup(args: ParsedArgs, log: Log): Promise<number> {\n if (!args.configPath) {\n log('usage: klum meter-group <config> --group=<name>')\n return 2\n }\n const group = await loadGroup(args)\n const r = await meterGroup(group)\n log(`group \"${args.group ?? ''}\" — ${r.vaults} vault(s), ${r.collections} collection(s), ${r.records} record(s)`)\n for (const s of r.perShard) {\n log(` ${s.vaultId} (${s.partitionKey}) v${s.schemaVersion}: ${s.collections} coll, ${s.records} rec`)\n }\n if (r.skipped.length) log(` skipped: ${r.skipped.length} shard(s)`)\n return 0\n}\n\nexport async function main(argv: readonly string[], log: Log = console.log): Promise<number> {\n const args = parseArgs(argv)\n switch (args.command) {\n case 'inspect-group':\n return runInspectGroup(args, log)\n case 'meter-group':\n return runMeterGroup(args, log)\n default:\n log('klum <inspect-group|meter-group> <config> --group=<name> [--vault=<id>]')\n return args.command ? 1 : 0\n }\n}\n\n// bin entrypoint — only runs when executed directly, not when imported in tests.\nif (process.argv[1] && import.meta.url === `file://${process.argv[1]}`) {\n main(process.argv.slice(2))\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n console.error(e)\n process.exitCode = 1\n })\n}\n","import type { InspectableContainer } from '@noy-db/in-devtools'\nimport type { AccessibleVault, Vault, WriteHook, WriteConflict, WriteQueue, Unsubscribe } from '@noy-db/hub'\nimport type { VaultGroup } from './vault-group.js'\n\n/**\n * Adapt a federation {@link VaultGroup} to the dev-tools `InspectableContainer`\n * contract from `@noy-db/in-devtools`, so the inspector / TUI can browse a\n * whole fleet exactly like a single instance.\n *\n * Built entirely on the group's public surface (`allRows`, `db`, `template`) —\n * no `VaultGroup` changes, and (critically) no `@klum-db` import lands in any\n * `@noy-db` package: the dependency runs one way, klum → noy.\n *\n * Write-event scoping: `group.db` may host vaults outside this group, so write\n * and conflict events are filtered to the group's shard ids. The id set is\n * primed/refreshed on every `listAccessibleVaults()` call — drive `listVaults()`\n * (the inspector's normal first step) before relying on event scoping.\n */\nexport function groupInspector<T>(group: VaultGroup<T>): InspectableContainer {\n let shardIds = new Set<string>()\n const refresh = async () => {\n const rows = await group.allRows()\n shardIds = new Set(rows.map((r) => r.vaultId))\n return rows\n }\n return {\n async listAccessibleVaults(): Promise<readonly AccessibleVault[]> {\n const rows = await refresh()\n return rows.map((r): AccessibleVault => ({ id: r.vaultId, role: 'owner' }))\n },\n async openVault(name: string): Promise<Vault> {\n const vault = await group.db.openVault(name)\n group.template.configure(vault)\n return vault\n },\n onAfterWrite(handler: WriteHook): Unsubscribe {\n return group.db.onAfterWrite((event) => {\n if (shardIds.has(event.vault)) return handler(event)\n })\n },\n onWriteConflict(handler: (c: WriteConflict) => void): Unsubscribe {\n return group.db.onWriteConflict((c) => {\n if (shardIds.has(c.vault)) handler(c)\n })\n },\n get writeQueue(): WriteQueue {\n return group.db.writeQueue\n },\n }\n}\n","import type { VaultGroup } from './vault-group.js'\nimport type { SkippedVault } from './types.js'\n\nexport interface GroupShardMetrics {\n readonly vaultId: string\n readonly partitionKey: string\n readonly schemaVersion: number\n readonly collections: number\n readonly records: number\n}\n\nexport interface GroupMeterReport {\n /** Number of eligible shards measured. */\n readonly vaults: number\n /** Distinct collection names across the group. */\n readonly collections: number\n /** Total record count summed across shards. */\n readonly records: number\n readonly perShard: ReadonlyArray<GroupShardMetrics>\n /** Drifted / provisioning-failed shards — surfaced, never counted or hidden. */\n readonly skipped: ReadonlyArray<SkippedVault>\n}\n\n/**\n * Fan shape-metrics (collection count + record count) across the group's\n * ELIGIBLE shards. Skipped shards (schema-drift / provisioning failures) are\n * reported in `skipped`, never silently dropped. Reuses the per-vault pattern\n * from `multi-bundle.ts` (`vault.collections()` → `collection(n).count()`).\n *\n * Operational store metrics (calls, CAS conflicts) are a separate concern and\n * are already group-wide via `@noy-db/to-meter` on the underlying store.\n */\nexport async function meterGroup<T>(\n group: VaultGroup<T>,\n opts: { minVersion?: number } = {},\n): Promise<GroupMeterReport> {\n const { eligible, skipped } = await group.resolveEligible(\n opts.minVersion !== undefined ? { minVersion: opts.minVersion } : {},\n )\n const perShard: GroupShardMetrics[] = []\n const names = new Set<string>()\n let records = 0\n for (const row of eligible) {\n const vault = await group.shard(row.partitionKey)\n const collNames = await vault.collections()\n let shardRecords = 0\n for (const n of collNames) {\n names.add(n)\n shardRecords += await vault.collection(n).count()\n }\n records += shardRecords\n perShard.push({\n vaultId: row.vaultId,\n partitionKey: row.partitionKey,\n schemaVersion: row.schemaVersion,\n collections: collNames.length,\n records: shardRecords,\n })\n }\n return { vaults: eligible.length, collections: names.size, records, perShard, skipped }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -2015,6 +2015,7 @@ __export(index_exports, {
|
|
|
2015
2015
|
encodeMultiBundle: () => encodeMultiBundle,
|
|
2016
2016
|
exportSurface: () => exportSurface,
|
|
2017
2017
|
extractCrossVaultPartition: () => extractCrossVaultPartition,
|
|
2018
|
+
groupInspector: () => groupInspector,
|
|
2018
2019
|
isDeedVault: () => import_hub6.isDeedVault,
|
|
2019
2020
|
isSurfaceDue: () => isSurfaceDue,
|
|
2020
2021
|
liberateVault: () => import_hub6.liberateVault,
|
|
@@ -2023,6 +2024,7 @@ __export(index_exports, {
|
|
|
2023
2024
|
markSynced: () => markSynced,
|
|
2024
2025
|
mergeCompartment: () => mergeCompartment,
|
|
2025
2026
|
mergeDecryptedRecords: () => mergeDecryptedRecords,
|
|
2027
|
+
meterGroup: () => meterGroup,
|
|
2026
2028
|
migrateThenMerge: () => migrateThenMerge,
|
|
2027
2029
|
proposeSurface: () => proposeSurface,
|
|
2028
2030
|
readMultiVaultBundleCompartment: () => readMultiVaultBundleCompartment,
|
|
@@ -2053,6 +2055,68 @@ var DockedUnit = class {
|
|
|
2053
2055
|
}
|
|
2054
2056
|
};
|
|
2055
2057
|
|
|
2058
|
+
// src/federation/group-inspector.ts
|
|
2059
|
+
function groupInspector(group) {
|
|
2060
|
+
let shardIds = /* @__PURE__ */ new Set();
|
|
2061
|
+
const refresh = async () => {
|
|
2062
|
+
const rows = await group.allRows();
|
|
2063
|
+
shardIds = new Set(rows.map((r) => r.vaultId));
|
|
2064
|
+
return rows;
|
|
2065
|
+
};
|
|
2066
|
+
return {
|
|
2067
|
+
async listAccessibleVaults() {
|
|
2068
|
+
const rows = await refresh();
|
|
2069
|
+
return rows.map((r) => ({ id: r.vaultId, role: "owner" }));
|
|
2070
|
+
},
|
|
2071
|
+
async openVault(name) {
|
|
2072
|
+
const vault = await group.db.openVault(name);
|
|
2073
|
+
group.template.configure(vault);
|
|
2074
|
+
return vault;
|
|
2075
|
+
},
|
|
2076
|
+
onAfterWrite(handler) {
|
|
2077
|
+
return group.db.onAfterWrite((event) => {
|
|
2078
|
+
if (shardIds.has(event.vault)) return handler(event);
|
|
2079
|
+
});
|
|
2080
|
+
},
|
|
2081
|
+
onWriteConflict(handler) {
|
|
2082
|
+
return group.db.onWriteConflict((c) => {
|
|
2083
|
+
if (shardIds.has(c.vault)) handler(c);
|
|
2084
|
+
});
|
|
2085
|
+
},
|
|
2086
|
+
get writeQueue() {
|
|
2087
|
+
return group.db.writeQueue;
|
|
2088
|
+
}
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// src/federation/meter-group.ts
|
|
2093
|
+
async function meterGroup(group, opts = {}) {
|
|
2094
|
+
const { eligible, skipped } = await group.resolveEligible(
|
|
2095
|
+
opts.minVersion !== void 0 ? { minVersion: opts.minVersion } : {}
|
|
2096
|
+
);
|
|
2097
|
+
const perShard = [];
|
|
2098
|
+
const names = /* @__PURE__ */ new Set();
|
|
2099
|
+
let records = 0;
|
|
2100
|
+
for (const row of eligible) {
|
|
2101
|
+
const vault = await group.shard(row.partitionKey);
|
|
2102
|
+
const collNames = await vault.collections();
|
|
2103
|
+
let shardRecords = 0;
|
|
2104
|
+
for (const n of collNames) {
|
|
2105
|
+
names.add(n);
|
|
2106
|
+
shardRecords += await vault.collection(n).count();
|
|
2107
|
+
}
|
|
2108
|
+
records += shardRecords;
|
|
2109
|
+
perShard.push({
|
|
2110
|
+
vaultId: row.vaultId,
|
|
2111
|
+
partitionKey: row.partitionKey,
|
|
2112
|
+
schemaVersion: row.schemaVersion,
|
|
2113
|
+
collections: collNames.length,
|
|
2114
|
+
records: shardRecords
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
return { vaults: eligible.length, collections: names.size, records, perShard, skipped };
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2056
2120
|
// src/index.ts
|
|
2057
2121
|
var import_kernel12 = require("@noy-db/hub/kernel");
|
|
2058
2122
|
init_multi_bundle();
|
|
@@ -2283,6 +2347,7 @@ function createLobby(noydb) {
|
|
|
2283
2347
|
encodeMultiBundle,
|
|
2284
2348
|
exportSurface,
|
|
2285
2349
|
extractCrossVaultPartition,
|
|
2350
|
+
groupInspector,
|
|
2286
2351
|
isDeedVault,
|
|
2287
2352
|
isSurfaceDue,
|
|
2288
2353
|
liberateVault,
|
|
@@ -2291,6 +2356,7 @@ function createLobby(noydb) {
|
|
|
2291
2356
|
markSynced,
|
|
2292
2357
|
mergeCompartment,
|
|
2293
2358
|
mergeDecryptedRecords,
|
|
2359
|
+
meterGroup,
|
|
2294
2360
|
migrateThenMerge,
|
|
2295
2361
|
proposeSurface,
|
|
2296
2362
|
readMultiVaultBundleCompartment,
|