@net-mesh/core 0.21.0 → 0.22.0

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.
@@ -0,0 +1,56 @@
1
+ export type RegistryErrorKind = 'transport' | 'codec' | 'unknown-template' | 'duplicate-group-name' | 'spawn-rejected' | 'spawn-not-supported' | 'invalid-args';
2
+ export type FoldQueryErrorKind = 'transport' | 'codec' | 'unknown-kind' | 'invalid-args';
3
+ export declare class RegistryClientError extends Error {
4
+ readonly kind: RegistryErrorKind;
5
+ readonly serverDetail?: string;
6
+ constructor(kind: RegistryErrorKind, detail: string);
7
+ }
8
+ export declare class FoldQueryClientError extends Error {
9
+ readonly kind: FoldQueryErrorKind;
10
+ readonly serverDetail?: string;
11
+ constructor(kind: FoldQueryErrorKind, detail: string);
12
+ }
13
+ /**
14
+ * Inspect an error message for the `agg:` prefix and return the
15
+ * structured `{kind, detail}` if it matches. Returns `null` when
16
+ * the message is missing the prefix or is malformed.
17
+ */
18
+ export declare function parseAggregatorError(e: unknown): {
19
+ kind: string;
20
+ detail: string;
21
+ } | null;
22
+ /**
23
+ * Re-throw a typed error for the given raw error if it carries the
24
+ * `agg:` prefix. Non-matching errors pass through unchanged so
25
+ * `throw classifyAggregatorError(e)` is safe at any catch site.
26
+ *
27
+ * Routes to `RegistryClientError` for registry-shaped kinds and
28
+ * `FoldQueryClientError` for fold-query-shaped kinds. Both surfaces
29
+ * share `transport` / `codec` / `invalid-args`; we route by the
30
+ * caller's typing — pass an explicit `surface` if you know which
31
+ * client raised it, otherwise the default routing biases to
32
+ * `RegistryClientError` for shared kinds (the substrate's primary
33
+ * surface).
34
+ */
35
+ export declare function classifyAggregatorError(e: unknown, surface?: 'registry' | 'fold-query'): unknown;
36
+ export interface RegistryReplicaRow {
37
+ generation: bigint;
38
+ healthy: boolean;
39
+ diagnostic?: string;
40
+ placementNodeId?: bigint;
41
+ }
42
+ export interface RegistryGroupSummary {
43
+ name: string;
44
+ groupSeedHex: string;
45
+ replicas: RegistryReplicaRow[];
46
+ }
47
+ export interface SummaryBucket {
48
+ name: string;
49
+ count: bigint;
50
+ }
51
+ export interface SummaryAnnouncement {
52
+ foldKind: number;
53
+ sourceSubnet: string;
54
+ generation: bigint;
55
+ buckets: SummaryBucket[];
56
+ }
package/aggregator.js ADDED
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ // Typed error classes + classifier for the `aggregator.registry`
3
+ // / `fold.query` RPC clients.
4
+ //
5
+ // The napi binding throws plain Error with the stable `agg:`
6
+ // prefix (`agg:<kind>: <detail>`); `classifyAggregatorError`
7
+ // re-throws as a typed `RegistryClientError` /
8
+ // `FoldQueryClientError`. Prefix locked against
9
+ // `ERR_AGG_PREFIX` in `bindings/node/src/aggregator.rs`;
10
+ // `tests/error_kind_mirror.rs` is the cross-language pin.
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FoldQueryClientError = exports.RegistryClientError = void 0;
13
+ exports.parseAggregatorError = parseAggregatorError;
14
+ exports.classifyAggregatorError = classifyAggregatorError;
15
+ const ERR_AGG_PREFIX = 'agg:';
16
+ class RegistryClientError extends Error {
17
+ kind;
18
+ serverDetail;
19
+ constructor(kind, detail) {
20
+ super(`${kind}: ${detail}`);
21
+ this.name = 'RegistryClientError';
22
+ this.kind = kind;
23
+ this.serverDetail = detail;
24
+ Object.setPrototypeOf(this, RegistryClientError.prototype);
25
+ }
26
+ }
27
+ exports.RegistryClientError = RegistryClientError;
28
+ class FoldQueryClientError extends Error {
29
+ kind;
30
+ serverDetail;
31
+ constructor(kind, detail) {
32
+ super(`${kind}: ${detail}`);
33
+ this.name = 'FoldQueryClientError';
34
+ this.kind = kind;
35
+ this.serverDetail = detail;
36
+ Object.setPrototypeOf(this, FoldQueryClientError.prototype);
37
+ }
38
+ }
39
+ exports.FoldQueryClientError = FoldQueryClientError;
40
+ const REGISTRY_KINDS = new Set([
41
+ 'transport',
42
+ 'codec',
43
+ 'unknown-template',
44
+ 'duplicate-group-name',
45
+ 'spawn-rejected',
46
+ 'spawn-not-supported',
47
+ 'invalid-args',
48
+ ]);
49
+ const FOLD_KINDS = new Set([
50
+ 'transport',
51
+ 'codec',
52
+ 'unknown-kind',
53
+ 'invalid-args',
54
+ ]);
55
+ /**
56
+ * Inspect an error message for the `agg:` prefix and return the
57
+ * structured `{kind, detail}` if it matches. Returns `null` when
58
+ * the message is missing the prefix or is malformed.
59
+ */
60
+ function parseAggregatorError(e) {
61
+ const msg = extractMessage(e);
62
+ if (!msg.startsWith(ERR_AGG_PREFIX))
63
+ return null;
64
+ const after = msg.slice(ERR_AGG_PREFIX.length);
65
+ // Find the FIRST `: ` separator — kinds are stable kebab-case
66
+ // identifiers with no colons; the detail may contain colons.
67
+ const sepIdx = after.indexOf(': ');
68
+ if (sepIdx === -1) {
69
+ // No detail, just the kind (defensive — substrate always emits
70
+ // a detail string today).
71
+ return { kind: after, detail: '' };
72
+ }
73
+ return {
74
+ kind: after.slice(0, sepIdx),
75
+ detail: after.slice(sepIdx + 2),
76
+ };
77
+ }
78
+ /**
79
+ * Re-throw a typed error for the given raw error if it carries the
80
+ * `agg:` prefix. Non-matching errors pass through unchanged so
81
+ * `throw classifyAggregatorError(e)` is safe at any catch site.
82
+ *
83
+ * Routes to `RegistryClientError` for registry-shaped kinds and
84
+ * `FoldQueryClientError` for fold-query-shaped kinds. Both surfaces
85
+ * share `transport` / `codec` / `invalid-args`; we route by the
86
+ * caller's typing — pass an explicit `surface` if you know which
87
+ * client raised it, otherwise the default routing biases to
88
+ * `RegistryClientError` for shared kinds (the substrate's primary
89
+ * surface).
90
+ */
91
+ function classifyAggregatorError(e, surface) {
92
+ const parsed = parseAggregatorError(e);
93
+ if (!parsed)
94
+ return e;
95
+ // Surface-specific kinds take priority — they are unambiguous.
96
+ if (parsed.kind === 'unknown-kind') {
97
+ return new FoldQueryClientError('unknown-kind', parsed.detail);
98
+ }
99
+ if (parsed.kind === 'unknown-template' ||
100
+ parsed.kind === 'duplicate-group-name' ||
101
+ parsed.kind === 'spawn-rejected' ||
102
+ parsed.kind === 'spawn-not-supported') {
103
+ return new RegistryClientError(parsed.kind, parsed.detail);
104
+ }
105
+ // Shared kinds — route by caller hint, default to registry.
106
+ if (parsed.kind === 'transport' ||
107
+ parsed.kind === 'codec' ||
108
+ parsed.kind === 'invalid-args') {
109
+ if (surface === 'fold-query') {
110
+ return new FoldQueryClientError(parsed.kind, parsed.detail);
111
+ }
112
+ return new RegistryClientError(parsed.kind, parsed.detail);
113
+ }
114
+ // Unknown kind under the `agg:` umbrella — keep the original
115
+ // error so callers see the full string instead of a synthetic
116
+ // typed wrapper that drops information.
117
+ void REGISTRY_KINDS;
118
+ void FOLD_KINDS;
119
+ return e;
120
+ }
121
+ function extractMessage(e) {
122
+ if (e === null || e === undefined)
123
+ return '';
124
+ if (typeof e === 'string')
125
+ return e;
126
+ if (typeof e !== 'object')
127
+ return '';
128
+ const msg = e.message;
129
+ return typeof msg === 'string' ? msg : '';
130
+ }
package/meshdb.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Result of {@link parseMeshDbErrorKind}: extracted structured
3
+ * discriminator + the human-readable message stripped of the
4
+ * `<<meshdb-kind:...>>` prefix.
5
+ */
6
+ export interface ParsedMeshDbError {
7
+ kind: string;
8
+ message: string;
9
+ }
10
+ /**
11
+ * Pull the structured error kind out of a MeshDB error message.
12
+ *
13
+ * The Rust binding embeds the kind discriminator (one of the
14
+ * `MeshError` variant tags such as `planner_error`,
15
+ * `executor_error`, `query_cancelled`, `historical_range_unavailable`,
16
+ * `ambiguous_discovery`, etc.) at the start of the error message
17
+ * as `<<meshdb-kind:KIND>>MSG`. This helper parses it back.
18
+ *
19
+ * Returns `null` for errors that don't carry a kind prefix
20
+ * (SDK-side validation failures, factory rejections) — those
21
+ * surface with the plain message intact.
22
+ */
23
+ export declare function parseMeshDbErrorKind(err: unknown): ParsedMeshDbError | null;
package/meshdb.js ADDED
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ // MeshDB AsyncIterable shim.
3
+ //
4
+ // Augments the napi-rs–generated `MeshQueryStream` class with
5
+ // `[Symbol.asyncIterator]` so callers can write `for await (const row
6
+ // of await runner.execute(query)) { ... }`. The locked Node SDK
7
+ // decision is `Promise<AsyncIterable<Row>>`; importing this module
8
+ // once at startup makes the shape land.
9
+ //
10
+ // Usage:
11
+ //
12
+ // import "@net-mesh/core/meshdb"; // augments MeshQueryStream
13
+ // import { MeshQuery, MeshQueryRunner } from "@net-mesh/core";
14
+ //
15
+ // const runner = new MeshQueryRunner(reader);
16
+ // const stream = await runner.execute(MeshQuery.latest(0xABn));
17
+ // for await (const row of stream) {
18
+ // console.log(row.seq, row.payload);
19
+ // }
20
+ //
21
+ // The shim is idempotent — re-imports are no-ops. It detaches
22
+ // cleanly under tree-shaking too (no top-level side effects beyond
23
+ // the prototype attach, which only fires when `MeshQueryStream` is
24
+ // part of the loaded native binding).
25
+ //
26
+ // Phase-F note: this shim is a wire-shape ergonomics layer; it
27
+ // doesn't change semantics. The underlying `next()` / `toArray()`
28
+ // methods stay available for callers that prefer manual iteration
29
+ // or batch drain.
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.parseMeshDbErrorKind = parseMeshDbErrorKind;
32
+ // The napi-generated MeshQueryStream is a constructor function with a
33
+ // prototype, but the original cast typed it as a plain object — the
34
+ // later `typeof === "function"` narrowing then collapsed it to `never`
35
+ // and reading `.prototype` errored under `-D warnings`. Cast as a
36
+ // Function with a prototype so both type-guards line up.
37
+ const native = require("./index");
38
+ if (native.MeshQueryStream &&
39
+ typeof native.MeshQueryStream === "function" &&
40
+ !(Symbol.asyncIterator in native.MeshQueryStream.prototype)) {
41
+ Object.defineProperty(native.MeshQueryStream.prototype, Symbol.asyncIterator, {
42
+ value() {
43
+ const stream = this;
44
+ return {
45
+ async next() {
46
+ const row = await stream.next();
47
+ if (row === null || row === undefined) {
48
+ return { value: undefined, done: true };
49
+ }
50
+ return { value: row, done: false };
51
+ },
52
+ // `return(value)` is invoked when a `for await (...)` loop
53
+ // `break`s, `return`s from the enclosing function, or an
54
+ // exception unwinds out of the loop body. Without this,
55
+ // the backing row Vec stays pinned on the AsyncMutex
56
+ // until JS GC eventually drops the stream — for a 10k+
57
+ // row result that's a sizeable memory pin.
58
+ async return(value) {
59
+ if (typeof stream.release === "function") {
60
+ await stream.release();
61
+ }
62
+ return { value, done: true };
63
+ },
64
+ // `throw(err)` is the iteration-protocol's error path.
65
+ // Symmetric to `return()`: free the buffer, then
66
+ // re-surface the error to the caller.
67
+ async throw(err) {
68
+ if (typeof stream.release === "function") {
69
+ await stream.release();
70
+ }
71
+ throw err;
72
+ },
73
+ };
74
+ },
75
+ enumerable: false,
76
+ configurable: true,
77
+ writable: true,
78
+ });
79
+ }
80
+ /**
81
+ * Pull the structured error kind out of a MeshDB error message.
82
+ *
83
+ * The Rust binding embeds the kind discriminator (one of the
84
+ * `MeshError` variant tags such as `planner_error`,
85
+ * `executor_error`, `query_cancelled`, `historical_range_unavailable`,
86
+ * `ambiguous_discovery`, etc.) at the start of the error message
87
+ * as `<<meshdb-kind:KIND>>MSG`. This helper parses it back.
88
+ *
89
+ * Returns `null` for errors that don't carry a kind prefix
90
+ * (SDK-side validation failures, factory rejections) — those
91
+ * surface with the plain message intact.
92
+ */
93
+ function parseMeshDbErrorKind(err) {
94
+ if (!(err instanceof Error))
95
+ return null;
96
+ // Accept digits too (`protocol_v2_mismatch`-style future kinds).
97
+ const m = err.message.match(/^<<meshdb-kind:([a-z0-9_]+)>>(.*)$/s);
98
+ if (!m)
99
+ return null;
100
+ return { kind: m[1], message: m[2] };
101
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@net-mesh/core",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "High-performance, schema-agnostic event bus for AI runtime workloads",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -20,6 +20,10 @@
20
20
  "./meshdb": {
21
21
  "types": "./meshdb.d.ts",
22
22
  "default": "./meshdb.js"
23
+ },
24
+ "./aggregator": {
25
+ "types": "./aggregator.d.ts",
26
+ "default": "./aggregator.js"
23
27
  }
24
28
  },
25
29
  "napi": {
@@ -56,6 +60,10 @@
56
60
  "errors.d.ts",
57
61
  "mesh_rpc.js",
58
62
  "mesh_rpc.d.ts",
63
+ "meshdb.js",
64
+ "meshdb.d.ts",
65
+ "aggregator.js",
66
+ "aggregator.d.ts",
59
67
  "*.node"
60
68
  ],
61
69
  "devDependencies": {
@@ -66,9 +74,9 @@
66
74
  },
67
75
  "scripts": {
68
76
  "artifacts": "napi artifacts",
69
- "build": "napi build --platform --release --features redis,net,cortex,compute,groups,meshos,deck,meshdb",
70
- "build:debug": "napi build --platform --features redis,net,cortex,compute,groups,meshos,deck,meshdb",
71
- "build:test": "napi build --platform --features redis,net,cortex,compute,groups,meshos,deck,meshdb,test-helpers",
77
+ "build": "napi build --platform --release --features redis,net,cortex,compute,groups,meshos,deck,meshdb,aggregator",
78
+ "build:debug": "napi build --platform --features redis,net,cortex,compute,groups,meshos,deck,meshdb,aggregator",
79
+ "build:test": "napi build --platform --features redis,net,cortex,compute,groups,meshos,deck,meshdb,aggregator,test-helpers",
72
80
  "build:ts": "tsc -p tsconfig.build.json",
73
81
  "prepublishOnly": "npm run build:ts && napi prepublish -t npm",
74
82
  "test": "vitest run",
@@ -83,13 +91,13 @@
83
91
  "node": ">=20"
84
92
  },
85
93
  "optionalDependencies": {
86
- "@net-mesh/core-win32-x64-msvc": "0.21.0",
87
- "@net-mesh/core-win32-arm64-msvc": "0.21.0",
88
- "@net-mesh/core-darwin-x64": "0.21.0",
89
- "@net-mesh/core-darwin-arm64": "0.21.0",
90
- "@net-mesh/core-linux-x64-gnu": "0.21.0",
91
- "@net-mesh/core-linux-x64-musl": "0.21.0",
92
- "@net-mesh/core-linux-arm64-gnu": "0.21.0",
93
- "@net-mesh/core-linux-arm64-musl": "0.21.0"
94
+ "@net-mesh/core-win32-x64-msvc": "0.22.0",
95
+ "@net-mesh/core-win32-arm64-msvc": "0.22.0",
96
+ "@net-mesh/core-darwin-x64": "0.22.0",
97
+ "@net-mesh/core-darwin-arm64": "0.22.0",
98
+ "@net-mesh/core-linux-x64-gnu": "0.22.0",
99
+ "@net-mesh/core-linux-x64-musl": "0.22.0",
100
+ "@net-mesh/core-linux-arm64-gnu": "0.22.0",
101
+ "@net-mesh/core-linux-arm64-musl": "0.22.0"
94
102
  }
95
103
  }