@net-mesh/sdk 0.20.2 → 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.
- package/dist/capability-aggregation.d.ts +129 -0
- package/dist/capability-aggregation.js +124 -0
- package/dist/index.d.ts +1 -0
- package/dist/mesh.d.ts +59 -0
- package/dist/mesh.js +79 -0
- package/package.json +2 -2
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability aggregation surface — Phase 6c of
|
|
3
|
+
* `MULTIFOLD_PHASE_6C_CAPACITY_AGGREGATION.md`.
|
|
4
|
+
*
|
|
5
|
+
* Three composable primitives map onto the Rust core's
|
|
6
|
+
* `Fold::aggregate` and `Fold::capacity_ranking`:
|
|
7
|
+
*
|
|
8
|
+
* - {@link TagMatcher} — picks which entries the aggregation
|
|
9
|
+
* walks. Tagged-union: `kind: 'exact' | 'prefix' | 'axis' |
|
|
10
|
+
* 'axisKey' | 'regex' | 'versionRange'`.
|
|
11
|
+
* - {@link GroupBy} — buckets matching entries.
|
|
12
|
+
* - {@link Aggregation} — reduces each bucket to a number.
|
|
13
|
+
*
|
|
14
|
+
* {@link CapacityQuery} composes a matcher + groupBy + optional RTT
|
|
15
|
+
* filter + optional summed-capacity axis into a single
|
|
16
|
+
* `capacityRanking(...)` call; the materialized view returns
|
|
17
|
+
* per-bucket state breakdown sorted by available capacity.
|
|
18
|
+
*
|
|
19
|
+
* The Rust core takes JSON-encoded tagged unions over the napi
|
|
20
|
+
* boundary; these helpers handle the conversion so TS callers work
|
|
21
|
+
* with idiomatic discriminated unions.
|
|
22
|
+
*/
|
|
23
|
+
import type { TaxonomyAxis } from './capability-enhancements';
|
|
24
|
+
export type { TaxonomyAxis };
|
|
25
|
+
/**
|
|
26
|
+
* Pre-grouping filter. An entry is included if any of its tags
|
|
27
|
+
* matches the matcher.
|
|
28
|
+
*/
|
|
29
|
+
export type TagMatcher = {
|
|
30
|
+
kind: 'exact';
|
|
31
|
+
value: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'prefix';
|
|
34
|
+
value: string;
|
|
35
|
+
} | {
|
|
36
|
+
kind: 'axis';
|
|
37
|
+
axis: TaxonomyAxis;
|
|
38
|
+
} | {
|
|
39
|
+
kind: 'axisKey';
|
|
40
|
+
axis: TaxonomyAxis;
|
|
41
|
+
key: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'regex';
|
|
44
|
+
pattern: string;
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'versionRange';
|
|
47
|
+
axisKey: string;
|
|
48
|
+
min?: string;
|
|
49
|
+
max?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Bucket-key derivation. */
|
|
52
|
+
export type GroupBy = {
|
|
53
|
+
kind: 'class';
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'state';
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'region';
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'publisher';
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'tagStem';
|
|
62
|
+
prefix: string;
|
|
63
|
+
} | {
|
|
64
|
+
kind: 'tagValue';
|
|
65
|
+
axis: TaxonomyAxis;
|
|
66
|
+
key: string;
|
|
67
|
+
};
|
|
68
|
+
/** Per-bucket reduction. */
|
|
69
|
+
export type Aggregation = {
|
|
70
|
+
kind: 'count';
|
|
71
|
+
} | {
|
|
72
|
+
kind: 'distinctPublishers';
|
|
73
|
+
} | {
|
|
74
|
+
kind: 'distinctValues';
|
|
75
|
+
axis: TaxonomyAxis;
|
|
76
|
+
key: string;
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'sumNumericTag';
|
|
79
|
+
axisKey: string;
|
|
80
|
+
} | {
|
|
81
|
+
kind: 'minNumericTag';
|
|
82
|
+
axisKey: string;
|
|
83
|
+
} | {
|
|
84
|
+
kind: 'maxNumericTag';
|
|
85
|
+
axisKey: string;
|
|
86
|
+
};
|
|
87
|
+
/** Composed capacity-ranking query. */
|
|
88
|
+
export interface CapacityQuery {
|
|
89
|
+
/** Optional pre-filter. */
|
|
90
|
+
matcher?: TagMatcher;
|
|
91
|
+
/** How to bucket matching entries. */
|
|
92
|
+
groupBy: GroupBy;
|
|
93
|
+
/**
|
|
94
|
+
* Drop entries whose publisher's RTT exceeds this. `undefined`
|
|
95
|
+
* disables the RTT filter (the `rttEntries` argument to
|
|
96
|
+
* {@link MeshNode.capabilityCapacityRanking} is unused regardless).
|
|
97
|
+
*/
|
|
98
|
+
maxRttMs?: number;
|
|
99
|
+
/**
|
|
100
|
+
* Canonical `<axis>.<key>` of a numeric tag to sum across each
|
|
101
|
+
* bucket (e.g. `"hardware.gpu.count"`).
|
|
102
|
+
*/
|
|
103
|
+
sumAxisKey?: string;
|
|
104
|
+
/** Top-N buckets by `available` descending. `0` = no truncation. */
|
|
105
|
+
limit: number;
|
|
106
|
+
}
|
|
107
|
+
/** One row of an aggregate result. */
|
|
108
|
+
export interface AggregateRow {
|
|
109
|
+
bucket: string;
|
|
110
|
+
value: bigint;
|
|
111
|
+
}
|
|
112
|
+
/** One row of a capacity-ranking result. */
|
|
113
|
+
export interface CapacityRow {
|
|
114
|
+
/** Bucket key. */
|
|
115
|
+
bucket: string;
|
|
116
|
+
/** Entries in `Idle` that pass the matcher + RTT gates. */
|
|
117
|
+
idle: bigint;
|
|
118
|
+
/** Entries in `Busy` that pass. */
|
|
119
|
+
busy: bigint;
|
|
120
|
+
/** Entries in `Reserved` that pass. */
|
|
121
|
+
reserved: bigint;
|
|
122
|
+
/** `idle + busy + reserved`. Faulty entries are always excluded. */
|
|
123
|
+
available: bigint;
|
|
124
|
+
/**
|
|
125
|
+
* Sum of the `sumAxisKey` numeric tag across the bucket;
|
|
126
|
+
* `undefined` when no `sumAxisKey` was requested.
|
|
127
|
+
*/
|
|
128
|
+
summedCapacity?: bigint;
|
|
129
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Capability aggregation surface — Phase 6c of
|
|
4
|
+
* `MULTIFOLD_PHASE_6C_CAPACITY_AGGREGATION.md`.
|
|
5
|
+
*
|
|
6
|
+
* Three composable primitives map onto the Rust core's
|
|
7
|
+
* `Fold::aggregate` and `Fold::capacity_ranking`:
|
|
8
|
+
*
|
|
9
|
+
* - {@link TagMatcher} — picks which entries the aggregation
|
|
10
|
+
* walks. Tagged-union: `kind: 'exact' | 'prefix' | 'axis' |
|
|
11
|
+
* 'axisKey' | 'regex' | 'versionRange'`.
|
|
12
|
+
* - {@link GroupBy} — buckets matching entries.
|
|
13
|
+
* - {@link Aggregation} — reduces each bucket to a number.
|
|
14
|
+
*
|
|
15
|
+
* {@link CapacityQuery} composes a matcher + groupBy + optional RTT
|
|
16
|
+
* filter + optional summed-capacity axis into a single
|
|
17
|
+
* `capacityRanking(...)` call; the materialized view returns
|
|
18
|
+
* per-bucket state breakdown sorted by available capacity.
|
|
19
|
+
*
|
|
20
|
+
* The Rust core takes JSON-encoded tagged unions over the napi
|
|
21
|
+
* boundary; these helpers handle the conversion so TS callers work
|
|
22
|
+
* with idiomatic discriminated unions.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.tagMatcherToJson = tagMatcherToJson;
|
|
26
|
+
exports.groupByToJson = groupByToJson;
|
|
27
|
+
exports.aggregationToJson = aggregationToJson;
|
|
28
|
+
exports.capacityQueryToJson = capacityQueryToJson;
|
|
29
|
+
// =====================================================
|
|
30
|
+
// JSON encoding for the napi boundary
|
|
31
|
+
// =====================================================
|
|
32
|
+
//
|
|
33
|
+
// The Rust core's serde uses snake_case kind values + snake_case
|
|
34
|
+
// field names. The TS surface above uses camelCase per ergonomics;
|
|
35
|
+
// these helpers translate.
|
|
36
|
+
/** @internal */
|
|
37
|
+
function tagMatcherToJson(matcher) {
|
|
38
|
+
switch (matcher.kind) {
|
|
39
|
+
case 'exact':
|
|
40
|
+
return JSON.stringify({ kind: 'exact', value: matcher.value });
|
|
41
|
+
case 'prefix':
|
|
42
|
+
return JSON.stringify({ kind: 'prefix', value: matcher.value });
|
|
43
|
+
case 'axis':
|
|
44
|
+
return JSON.stringify({ kind: 'axis', axis: matcher.axis });
|
|
45
|
+
case 'axisKey':
|
|
46
|
+
return JSON.stringify({
|
|
47
|
+
kind: 'axis_key',
|
|
48
|
+
axis: matcher.axis,
|
|
49
|
+
key: matcher.key,
|
|
50
|
+
});
|
|
51
|
+
case 'regex':
|
|
52
|
+
return JSON.stringify({ kind: 'regex', pattern: matcher.pattern });
|
|
53
|
+
case 'versionRange':
|
|
54
|
+
return JSON.stringify({
|
|
55
|
+
kind: 'version_range',
|
|
56
|
+
axis_key: matcher.axisKey,
|
|
57
|
+
min: matcher.min ?? null,
|
|
58
|
+
max: matcher.max ?? null,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** @internal */
|
|
63
|
+
function groupByToJson(groupBy) {
|
|
64
|
+
switch (groupBy.kind) {
|
|
65
|
+
case 'class':
|
|
66
|
+
return JSON.stringify({ kind: 'class' });
|
|
67
|
+
case 'state':
|
|
68
|
+
return JSON.stringify({ kind: 'state' });
|
|
69
|
+
case 'region':
|
|
70
|
+
return JSON.stringify({ kind: 'region' });
|
|
71
|
+
case 'publisher':
|
|
72
|
+
return JSON.stringify({ kind: 'publisher' });
|
|
73
|
+
case 'tagStem':
|
|
74
|
+
return JSON.stringify({ kind: 'tag_stem', prefix: groupBy.prefix });
|
|
75
|
+
case 'tagValue':
|
|
76
|
+
return JSON.stringify({
|
|
77
|
+
kind: 'tag_value',
|
|
78
|
+
axis: groupBy.axis,
|
|
79
|
+
key: groupBy.key,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** @internal */
|
|
84
|
+
function aggregationToJson(agg) {
|
|
85
|
+
switch (agg.kind) {
|
|
86
|
+
case 'count':
|
|
87
|
+
return JSON.stringify({ kind: 'count' });
|
|
88
|
+
case 'distinctPublishers':
|
|
89
|
+
return JSON.stringify({ kind: 'distinct_publishers' });
|
|
90
|
+
case 'distinctValues':
|
|
91
|
+
return JSON.stringify({
|
|
92
|
+
kind: 'distinct_values',
|
|
93
|
+
axis: agg.axis,
|
|
94
|
+
key: agg.key,
|
|
95
|
+
});
|
|
96
|
+
case 'sumNumericTag':
|
|
97
|
+
return JSON.stringify({
|
|
98
|
+
kind: 'sum_numeric_tag',
|
|
99
|
+
axis_key: agg.axisKey,
|
|
100
|
+
});
|
|
101
|
+
case 'minNumericTag':
|
|
102
|
+
return JSON.stringify({
|
|
103
|
+
kind: 'min_numeric_tag',
|
|
104
|
+
axis_key: agg.axisKey,
|
|
105
|
+
});
|
|
106
|
+
case 'maxNumericTag':
|
|
107
|
+
return JSON.stringify({
|
|
108
|
+
kind: 'max_numeric_tag',
|
|
109
|
+
axis_key: agg.axisKey,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** @internal */
|
|
114
|
+
function capacityQueryToJson(query) {
|
|
115
|
+
return JSON.stringify({
|
|
116
|
+
matcher: query.matcher
|
|
117
|
+
? JSON.parse(tagMatcherToJson(query.matcher))
|
|
118
|
+
: null,
|
|
119
|
+
group_by: JSON.parse(groupByToJson(query.groupBy)),
|
|
120
|
+
max_rtt_ms: query.maxRttMs ?? null,
|
|
121
|
+
sum_axis_key: query.sumAxisKey ?? null,
|
|
122
|
+
limit: query.limit,
|
|
123
|
+
});
|
|
124
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export type { AxisEntry, AxisSchema, KeyEntry, KeyShape, KeyShapeKind, SchemaErr
|
|
|
43
43
|
export { AXIS_SCHEMA, METADATA_RESERVED_KEYS, METADATA_RESERVED_PREFIXES, METADATA_SOFT_CAP_BYTES, isReportClean, isReportValid, validateCapabilities, } from './capability-schema';
|
|
44
44
|
export { subnetId, GLOBAL_SUBNET } from './subnets';
|
|
45
45
|
export type { SubnetId, SubnetRule, SubnetPolicy } from './subnets';
|
|
46
|
+
export type { Aggregation, AggregateRow, CapacityQuery, CapacityRow, GroupBy, TagMatcher, } from './capability-aggregation';
|
|
46
47
|
export { DaemonRuntime, DaemonHandle, DaemonError, MigrationHandle, MigrationError, } from './compute';
|
|
47
48
|
export type { CausalEvent, MeshDaemon, DaemonFactory, DaemonHostConfig, DaemonStats, MigrationPhase, MigrationOptions, MigrationErrorKind, } from './compute';
|
|
48
49
|
export { DisposableMeshQueryRunner, InMemoryChainReader, MeshQuery, MeshQueryRunner, MeshQueryStream, QueryBuilder, parseMeshDbErrorKind, } from './meshdb';
|
package/dist/mesh.d.ts
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
38
|
import { type CapabilityFilter, type CapabilitySet, type ScopeFilter } from './capabilities';
|
|
39
|
+
import { type Aggregation, type AggregateRow, type CapacityQuery, type CapacityRow, type GroupBy, type TagMatcher } from './capability-aggregation';
|
|
39
40
|
import type { SubnetId, SubnetPolicy } from './subnets';
|
|
40
41
|
import type { Token } from './identity';
|
|
41
42
|
/** Reliability mode chosen at stream-open time. */
|
|
@@ -299,6 +300,64 @@ export declare class MeshNode {
|
|
|
299
300
|
* ```
|
|
300
301
|
*/
|
|
301
302
|
findNodesScoped(filter: CapabilityFilter, scope: ScopeFilter): bigint[];
|
|
303
|
+
/**
|
|
304
|
+
* Bucketed aggregation over the local capability fold —
|
|
305
|
+
* `Fold::aggregate(matcher, groupBy, agg)`. Composes a matcher,
|
|
306
|
+
* a bucket-derivation, and a per-bucket reduction into a
|
|
307
|
+
* lex-sorted `[bucket, value][]`. Phase 6c-A of
|
|
308
|
+
* `MULTIFOLD_PHASE_6C_CAPACITY_AGGREGATION.md`.
|
|
309
|
+
*
|
|
310
|
+
* `matcher === undefined` walks every entry.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* // Top GPU types by count.
|
|
315
|
+
* const rows = node.capabilityAggregate(
|
|
316
|
+
* { kind: 'prefix', value: 'hardware.gpu' },
|
|
317
|
+
* { kind: 'tagStem', prefix: 'hardware.gpu' },
|
|
318
|
+
* { kind: 'count' },
|
|
319
|
+
* );
|
|
320
|
+
* for (const r of rows) console.log(r.bucket, r.value);
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
capabilityAggregate(matcher: TagMatcher | undefined, groupBy: GroupBy, aggregation: Aggregation): AggregateRow[];
|
|
324
|
+
/**
|
|
325
|
+
* Capacity-ranked materialized view —
|
|
326
|
+
* `Fold::capacity_ranking(query, rttLookup)`. Per-bucket state
|
|
327
|
+
* breakdown + latency gate + optional summed numeric capacity,
|
|
328
|
+
* sorted by `available` desc (ties broken on bucket asc) and
|
|
329
|
+
* truncated to `query.limit`. Phase 6c-B.
|
|
330
|
+
*
|
|
331
|
+
* `rttEntries` is the materialized RTT map. `undefined`/empty
|
|
332
|
+
* disables the RTT filter regardless of `query.maxRttMs`. Per
|
|
333
|
+
* the plan, a `ThreadsafeFunction` closure variant is a follow-
|
|
334
|
+
* up; the map shape matches the Go / C wrappers and lines up
|
|
335
|
+
* with what operators typically have cached from the proximity
|
|
336
|
+
* graph.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```typescript
|
|
340
|
+
* // Top 5 GPU types available within 50 ms latency.
|
|
341
|
+
* const rttMap = [
|
|
342
|
+
* { nodeId: 0x1234n, rttMs: 25 },
|
|
343
|
+
* { nodeId: 0x5678n, rttMs: 75 },
|
|
344
|
+
* ];
|
|
345
|
+
* const rows = node.capabilityCapacityRanking(
|
|
346
|
+
* {
|
|
347
|
+
* matcher: { kind: 'prefix', value: 'hardware.gpu' },
|
|
348
|
+
* groupBy: { kind: 'tagStem', prefix: 'hardware.gpu' },
|
|
349
|
+
* maxRttMs: 50,
|
|
350
|
+
* sumAxisKey: 'hardware.gpu.count',
|
|
351
|
+
* limit: 5,
|
|
352
|
+
* },
|
|
353
|
+
* rttMap,
|
|
354
|
+
* );
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
capabilityCapacityRanking(query: CapacityQuery, rttEntries?: Array<{
|
|
358
|
+
nodeId: bigint;
|
|
359
|
+
rttMs: number;
|
|
360
|
+
}>): CapacityRow[];
|
|
302
361
|
/** Shutdown the mesh node. */
|
|
303
362
|
shutdown(): Promise<void>;
|
|
304
363
|
}
|
package/dist/mesh.js
CHANGED
|
@@ -41,6 +41,7 @@ exports.ChannelAuthError = exports.ChannelError = exports.MeshNode = exports.Not
|
|
|
41
41
|
const core_1 = require("@net-mesh/core");
|
|
42
42
|
const _internal_js_1 = require("./_internal.js");
|
|
43
43
|
const capabilities_1 = require("./capabilities");
|
|
44
|
+
const capability_aggregation_1 = require("./capability-aggregation");
|
|
44
45
|
/**
|
|
45
46
|
* Thrown by {@link MeshNode.sendOnStream} / `sendWithRetry` /
|
|
46
47
|
* `sendBlocking` when the stream's per-stream in-flight window is
|
|
@@ -122,6 +123,21 @@ class MeshNode {
|
|
|
122
123
|
}
|
|
123
124
|
native.testInjectSyntheticPeer(nodeId);
|
|
124
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Test-only — same shape as {@link _testInjectSyntheticPeer} but
|
|
128
|
+
* stages the synthetic peer with the supplied canonical tag
|
|
129
|
+
* strings. Used by the Phase 6c aggregation smoke tests to set
|
|
130
|
+
* up multi-bucket fixtures without spinning up multiple meshes.
|
|
131
|
+
*
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
_testInjectSyntheticPeerWithTags(nodeId, tags) {
|
|
135
|
+
const native = this.native;
|
|
136
|
+
if (typeof native.testInjectSyntheticPeerWithTags !== 'function') {
|
|
137
|
+
throw new Error('testInjectSyntheticPeerWithTags: NAPI build missing `test-helpers` feature');
|
|
138
|
+
}
|
|
139
|
+
native.testInjectSyntheticPeerWithTags(nodeId, tags);
|
|
140
|
+
}
|
|
125
141
|
/** Create and configure a new mesh node. */
|
|
126
142
|
static async create(config) {
|
|
127
143
|
const native = await core_1.NetMesh.create({
|
|
@@ -389,6 +405,69 @@ class MeshNode {
|
|
|
389
405
|
findNodesScoped(filter, scope) {
|
|
390
406
|
return this.native.findNodesScoped((0, capabilities_1.capabilityFilterToNapi)(filter), (0, capabilities_1.scopeFilterToNapi)(scope));
|
|
391
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Bucketed aggregation over the local capability fold —
|
|
410
|
+
* `Fold::aggregate(matcher, groupBy, agg)`. Composes a matcher,
|
|
411
|
+
* a bucket-derivation, and a per-bucket reduction into a
|
|
412
|
+
* lex-sorted `[bucket, value][]`. Phase 6c-A of
|
|
413
|
+
* `MULTIFOLD_PHASE_6C_CAPACITY_AGGREGATION.md`.
|
|
414
|
+
*
|
|
415
|
+
* `matcher === undefined` walks every entry.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* // Top GPU types by count.
|
|
420
|
+
* const rows = node.capabilityAggregate(
|
|
421
|
+
* { kind: 'prefix', value: 'hardware.gpu' },
|
|
422
|
+
* { kind: 'tagStem', prefix: 'hardware.gpu' },
|
|
423
|
+
* { kind: 'count' },
|
|
424
|
+
* );
|
|
425
|
+
* for (const r of rows) console.log(r.bucket, r.value);
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
capabilityAggregate(matcher, groupBy, aggregation) {
|
|
429
|
+
const matcherJson = matcher ? (0, capability_aggregation_1.tagMatcherToJson)(matcher) : null;
|
|
430
|
+
const groupByJson = (0, capability_aggregation_1.groupByToJson)(groupBy);
|
|
431
|
+
const aggregationJson = (0, capability_aggregation_1.aggregationToJson)(aggregation);
|
|
432
|
+
return this.native.capabilityAggregate(matcherJson, groupByJson, aggregationJson);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Capacity-ranked materialized view —
|
|
436
|
+
* `Fold::capacity_ranking(query, rttLookup)`. Per-bucket state
|
|
437
|
+
* breakdown + latency gate + optional summed numeric capacity,
|
|
438
|
+
* sorted by `available` desc (ties broken on bucket asc) and
|
|
439
|
+
* truncated to `query.limit`. Phase 6c-B.
|
|
440
|
+
*
|
|
441
|
+
* `rttEntries` is the materialized RTT map. `undefined`/empty
|
|
442
|
+
* disables the RTT filter regardless of `query.maxRttMs`. Per
|
|
443
|
+
* the plan, a `ThreadsafeFunction` closure variant is a follow-
|
|
444
|
+
* up; the map shape matches the Go / C wrappers and lines up
|
|
445
|
+
* with what operators typically have cached from the proximity
|
|
446
|
+
* graph.
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* // Top 5 GPU types available within 50 ms latency.
|
|
451
|
+
* const rttMap = [
|
|
452
|
+
* { nodeId: 0x1234n, rttMs: 25 },
|
|
453
|
+
* { nodeId: 0x5678n, rttMs: 75 },
|
|
454
|
+
* ];
|
|
455
|
+
* const rows = node.capabilityCapacityRanking(
|
|
456
|
+
* {
|
|
457
|
+
* matcher: { kind: 'prefix', value: 'hardware.gpu' },
|
|
458
|
+
* groupBy: { kind: 'tagStem', prefix: 'hardware.gpu' },
|
|
459
|
+
* maxRttMs: 50,
|
|
460
|
+
* sumAxisKey: 'hardware.gpu.count',
|
|
461
|
+
* limit: 5,
|
|
462
|
+
* },
|
|
463
|
+
* rttMap,
|
|
464
|
+
* );
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
capabilityCapacityRanking(query, rttEntries) {
|
|
468
|
+
const queryJson = (0, capability_aggregation_1.capacityQueryToJson)(query);
|
|
469
|
+
return this.native.capabilityCapacityRanking(queryJson, rttEntries ?? null);
|
|
470
|
+
}
|
|
392
471
|
/** Shutdown the mesh node. */
|
|
393
472
|
async shutdown() {
|
|
394
473
|
await this.native.shutdown();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@net-mesh/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Ergonomic TypeScript SDK for the Net mesh network",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"test:watch": "vitest"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@net-mesh/core": ">=0.
|
|
32
|
+
"@net-mesh/core": ">=0.22.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@net-mesh/core": "file:../bindings/node",
|