@net-mesh/sdk 0.19.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,25 @@
1
+ /**
2
+ * Module-internal handles used by sibling SDK modules to share
3
+ * the underlying NAPI objects without exposing them on the
4
+ * public class surface.
5
+ *
6
+ * Previously this was a leading-underscore method (`_napiRuntime`,
7
+ * `_napiNetMesh`) on each wrapper class. That left a runtime-
8
+ * discoverable escape hatch: a consumer casting the class instance
9
+ * to `any` could call the method and reach the unstable NAPI
10
+ * surface, bypassing the wrapper's typed error / lifecycle
11
+ * boundaries. `stripInternal: true` hid the method from emitted
12
+ * `.d.ts` but the method still existed on every instance.
13
+ *
14
+ * This file swaps that for a WeakMap-per-handle so the napi
15
+ * pointer is keyed off the wrapper instance but is NOT a property
16
+ * of it. Only code that imports these helpers directly can reach
17
+ * the native pointer; the helpers are `@internal` and never
18
+ * re-exported from `index.ts`, so a consumer would have to deep-
19
+ * import this file deliberately — the usual "you're breaking the
20
+ * seal" ergonomics.
21
+ *
22
+ * @internal
23
+ * @packageDocumentation
24
+ */
25
+ export {};
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /**
3
+ * Module-internal handles used by sibling SDK modules to share
4
+ * the underlying NAPI objects without exposing them on the
5
+ * public class surface.
6
+ *
7
+ * Previously this was a leading-underscore method (`_napiRuntime`,
8
+ * `_napiNetMesh`) on each wrapper class. That left a runtime-
9
+ * discoverable escape hatch: a consumer casting the class instance
10
+ * to `any` could call the method and reach the unstable NAPI
11
+ * surface, bypassing the wrapper's typed error / lifecycle
12
+ * boundaries. `stripInternal: true` hid the method from emitted
13
+ * `.d.ts` but the method still existed on every instance.
14
+ *
15
+ * This file swaps that for a WeakMap-per-handle so the napi
16
+ * pointer is keyed off the wrapper instance but is NOT a property
17
+ * of it. Only code that imports these helpers directly can reach
18
+ * the native pointer; the helpers are `@internal` and never
19
+ * re-exported from `index.ts`, so a consumer would have to deep-
20
+ * import this file deliberately — the usual "you're breaking the
21
+ * seal" ergonomics.
22
+ *
23
+ * @internal
24
+ * @packageDocumentation
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.setNapiRuntime = setNapiRuntime;
28
+ exports.getNapiRuntime = getNapiRuntime;
29
+ exports.setNapiMesh = setNapiMesh;
30
+ exports.getNapiMesh = getNapiMesh;
31
+ // `WeakMap<object, …>` avoids pinning the wrapper in memory — when
32
+ // a DaemonRuntime is garbage-collected the entry evicts automatically.
33
+ const napiRuntimes = new WeakMap();
34
+ const napiMeshes = new WeakMap();
35
+ /** @internal */
36
+ function setNapiRuntime(host, napi) {
37
+ napiRuntimes.set(host, napi);
38
+ }
39
+ /** @internal */
40
+ function getNapiRuntime(host) {
41
+ const r = napiRuntimes.get(host);
42
+ if (!r) {
43
+ throw new Error('internal: no NAPI runtime registered for this DaemonRuntime — ' +
44
+ 'constructor may not have run');
45
+ }
46
+ return r;
47
+ }
48
+ /** @internal */
49
+ function setNapiMesh(host, napi) {
50
+ napiMeshes.set(host, napi);
51
+ }
52
+ /** @internal */
53
+ function getNapiMesh(host) {
54
+ const r = napiMeshes.get(host);
55
+ if (!r) {
56
+ throw new Error('internal: no NAPI mesh registered for this MeshNode — ' +
57
+ 'constructor may not have run');
58
+ }
59
+ return r;
60
+ }
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Capability declarations — hardware / software / models / tools /
3
+ * tags / resource limits — and the filters that query them.
4
+ *
5
+ * Construct a {@link CapabilitySet} from whatever your node actually
6
+ * runs, hand it to {@link MeshNode.announceCapabilities}, and the
7
+ * mesh pushes it to every directly-connected peer. Peers keep the
8
+ * latest announcement from each node in their local capability
9
+ * index; {@link MeshNode.findNodes} queries that index.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { MeshNode } from '@net-mesh/sdk';
14
+ *
15
+ * await node.announceCapabilities({
16
+ * hardware: {
17
+ * cpuCores: 16,
18
+ * memoryGb: 64,
19
+ * gpu: { vendor: 'nvidia', model: 'RTX 4090', vramGb: 24 },
20
+ * },
21
+ * tags: ['gpu', 'inference'],
22
+ * models: [{ modelId: 'llama-3.1-70b', family: 'llama' }],
23
+ * });
24
+ *
25
+ * const peers = node.findNodes({ requireTags: ['gpu'], minVramMb: 16_384 });
26
+ * ```
27
+ *
28
+ * Multi-hop propagation is deferred; today peers more than one hop
29
+ * away are not visible.
30
+ */
31
+ /**
32
+ * GPU vendor. Case-insensitive on input (`'NVIDIA'`, `'nvidia'`,
33
+ * `'Nvidia'` all normalize to `'nvidia'`). Unknown / misspelled
34
+ * vendors collapse to `'unknown'`.
35
+ */
36
+ export type GpuVendor = 'nvidia' | 'amd' | 'intel' | 'apple' | 'qualcomm' | 'unknown';
37
+ export interface GpuInfo {
38
+ vendor?: GpuVendor;
39
+ model: string;
40
+ vramGb: number;
41
+ computeUnits?: number;
42
+ tensorCores?: number;
43
+ /** FP16 TFLOPS × 10 (integer) — e.g. 825 for 82.5 TFLOPS. */
44
+ fp16TflopsX10?: number;
45
+ }
46
+ export type AcceleratorKind = 'tpu' | 'npu' | 'fpga' | 'asic' | 'dsp' | 'unknown';
47
+ export interface Accelerator {
48
+ kind: AcceleratorKind;
49
+ model: string;
50
+ memoryGb?: number;
51
+ /** TOPS × 10 (integer). */
52
+ topsX10?: number;
53
+ }
54
+ export interface Hardware {
55
+ cpuCores?: number;
56
+ cpuThreads?: number;
57
+ memoryGb?: number;
58
+ gpu?: GpuInfo;
59
+ additionalGpus?: GpuInfo[];
60
+ /** Storage in GB. BigInt to carry multi-TB values without loss. */
61
+ storageGb?: bigint;
62
+ networkGbps?: number;
63
+ accelerators?: Accelerator[];
64
+ }
65
+ /** `[runtime_name, version]` pair used by runtimes/frameworks/drivers. */
66
+ export type SoftwarePair = [string, string];
67
+ export interface Software {
68
+ os?: string;
69
+ osVersion?: string;
70
+ runtimes?: SoftwarePair[];
71
+ frameworks?: SoftwarePair[];
72
+ cudaVersion?: string;
73
+ drivers?: SoftwarePair[];
74
+ }
75
+ export type Modality = 'text' | 'image' | 'audio' | 'video' | 'code' | 'embedding' | 'tool-use';
76
+ export interface ModelCapability {
77
+ modelId: string;
78
+ family?: string;
79
+ /**
80
+ * Parameter count, billions × 10 (70 B ⇒ 700). Integer-encoded to
81
+ * avoid float precision loss; the core uses the same layout.
82
+ */
83
+ parametersBX10?: number;
84
+ contextLength?: number;
85
+ quantization?: string;
86
+ modalities?: Modality[];
87
+ tokensPerSec?: number;
88
+ loaded?: boolean;
89
+ }
90
+ export interface ToolCapability {
91
+ toolId: string;
92
+ name?: string;
93
+ version?: string;
94
+ /** JSON-Schema string. */
95
+ inputSchema?: string;
96
+ /** JSON-Schema string. */
97
+ outputSchema?: string;
98
+ requires?: string[];
99
+ estimatedTimeMs?: number;
100
+ stateless?: boolean;
101
+ }
102
+ export interface CapabilityLimits {
103
+ maxConcurrentRequests?: number;
104
+ maxTokensPerRequest?: number;
105
+ rateLimitRpm?: number;
106
+ maxBatchSize?: number;
107
+ maxInputBytes?: number;
108
+ maxOutputBytes?: number;
109
+ }
110
+ export interface CapabilitySet {
111
+ hardware?: Hardware;
112
+ software?: Software;
113
+ models?: ModelCapability[];
114
+ tools?: ToolCapability[];
115
+ tags?: string[];
116
+ limits?: CapabilityLimits;
117
+ }
118
+ export interface CapabilityFilter {
119
+ requireTags?: string[];
120
+ requireModels?: string[];
121
+ requireTools?: string[];
122
+ minMemoryMb?: number;
123
+ requireGpu?: boolean;
124
+ gpuVendor?: GpuVendor;
125
+ minVramMb?: number;
126
+ minContextLength?: number;
127
+ requireModalities?: Modality[];
128
+ }
129
+ interface NapiGpuInfo {
130
+ vendor?: string;
131
+ model: string;
132
+ vramGb: number;
133
+ computeUnits?: number;
134
+ tensorCores?: number;
135
+ fp16TflopsX10?: number;
136
+ }
137
+ interface NapiAccelerator {
138
+ kind: string;
139
+ model: string;
140
+ memoryGb?: number;
141
+ topsX10?: number;
142
+ }
143
+ interface NapiHardware {
144
+ cpuCores?: number;
145
+ cpuThreads?: number;
146
+ memoryGb?: number;
147
+ gpu?: NapiGpuInfo;
148
+ additionalGpus?: NapiGpuInfo[];
149
+ storageGb?: bigint;
150
+ networkGbps?: number;
151
+ accelerators?: NapiAccelerator[];
152
+ }
153
+ interface NapiSoftware {
154
+ os?: string;
155
+ osVersion?: string;
156
+ runtimes?: string[][];
157
+ frameworks?: string[][];
158
+ cudaVersion?: string;
159
+ drivers?: string[][];
160
+ }
161
+ interface NapiModel {
162
+ modelId: string;
163
+ family?: string;
164
+ parametersBX10?: number;
165
+ contextLength?: number;
166
+ quantization?: string;
167
+ modalities?: string[];
168
+ tokensPerSec?: number;
169
+ loaded?: boolean;
170
+ }
171
+ interface NapiTool {
172
+ toolId: string;
173
+ name?: string;
174
+ version?: string;
175
+ inputSchema?: string;
176
+ outputSchema?: string;
177
+ requires?: string[];
178
+ estimatedTimeMs?: number;
179
+ stateless?: boolean;
180
+ }
181
+ interface NapiLimits {
182
+ maxConcurrentRequests?: number;
183
+ maxTokensPerRequest?: number;
184
+ rateLimitRpm?: number;
185
+ maxBatchSize?: number;
186
+ maxInputBytes?: number;
187
+ maxOutputBytes?: number;
188
+ }
189
+ /** Shape that napi-rs expects for `announceCapabilities`. */
190
+ export interface NapiCapabilitySet {
191
+ hardware?: NapiHardware;
192
+ software?: NapiSoftware;
193
+ models?: NapiModel[];
194
+ tools?: NapiTool[];
195
+ tags?: string[];
196
+ limits?: NapiLimits;
197
+ }
198
+ /** Shape that napi-rs expects for `findNodes`. */
199
+ export interface NapiCapabilityFilter {
200
+ requireTags?: string[];
201
+ requireModels?: string[];
202
+ requireTools?: string[];
203
+ minMemoryMb?: number;
204
+ requireGpu?: boolean;
205
+ gpuVendor?: string;
206
+ minVramMb?: number;
207
+ minContextLength?: number;
208
+ requireModalities?: string[];
209
+ }
210
+ export declare function capabilitySetToNapi(caps: CapabilitySet): NapiCapabilitySet;
211
+ export declare function capabilityFilterToNapi(f: CapabilityFilter): NapiCapabilityFilter;
212
+ /**
213
+ * Caller's intent for narrowing peer discovery by reserved
214
+ * `scope:*` tags. See {@link MeshNode.findNodesScoped}.
215
+ *
216
+ * Tag-based scope is a query-time concern — the wire format is
217
+ * untouched. Untagged peers resolve to `Global` and stay visible
218
+ * under most filters by design (matches the v1-permissive
219
+ * default). Peers tagged `scope:subnet-local` only show up under
220
+ * `sameSubnet`.
221
+ */
222
+ export type ScopeFilter = {
223
+ kind: 'any';
224
+ } | {
225
+ kind: 'globalOnly';
226
+ } | {
227
+ kind: 'sameSubnet';
228
+ } | {
229
+ kind: 'tenant';
230
+ tenant: string;
231
+ } | {
232
+ kind: 'tenants';
233
+ tenants: string[];
234
+ } | {
235
+ kind: 'region';
236
+ region: string;
237
+ } | {
238
+ kind: 'regions';
239
+ regions: string[];
240
+ };
241
+ /** Shape that napi-rs expects for `findNodesScoped`. */
242
+ export interface NapiScopeFilter {
243
+ kind: string;
244
+ tenant?: string;
245
+ tenants?: string[];
246
+ region?: string;
247
+ regions?: string[];
248
+ }
249
+ export declare function scopeFilterToNapi(s: ScopeFilter): NapiScopeFilter;
250
+ /** Reserved tag prefix for tenant-scoped announcements. */
251
+ export declare const SCOPE_TENANT_PREFIX = "scope:tenant:";
252
+ /** Reserved tag prefix for region-scoped announcements. */
253
+ export declare const SCOPE_REGION_PREFIX = "scope:region:";
254
+ /** Reserved tag marking an announcement subnet-local. */
255
+ export declare const SCOPE_SUBNET_LOCAL = "scope:subnet-local";
256
+ /**
257
+ * Append a `scope:tenant:<id>` tag to a tag list. Idempotent —
258
+ * safe to call repeatedly with the same id. Empty `tenantId` is a
259
+ * no-op.
260
+ */
261
+ export declare function withTenantScope(tags: string[] | undefined, tenantId: string): string[];
262
+ /** Append a `scope:region:<name>` tag to a tag list. Idempotent. */
263
+ export declare function withRegionScope(tags: string[] | undefined, region: string): string[];
264
+ /**
265
+ * Append the `scope:subnet-local` tag to a tag list. Idempotent.
266
+ * Strictest form wins on the resolver — when this tag is present,
267
+ * tenant/region tags on the same set are ignored by
268
+ * `CapabilityScope`.
269
+ */
270
+ export declare function withSubnetLocalScope(tags: string[] | undefined): string[];
271
+ export {};
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /**
3
+ * Capability declarations — hardware / software / models / tools /
4
+ * tags / resource limits — and the filters that query them.
5
+ *
6
+ * Construct a {@link CapabilitySet} from whatever your node actually
7
+ * runs, hand it to {@link MeshNode.announceCapabilities}, and the
8
+ * mesh pushes it to every directly-connected peer. Peers keep the
9
+ * latest announcement from each node in their local capability
10
+ * index; {@link MeshNode.findNodes} queries that index.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { MeshNode } from '@net-mesh/sdk';
15
+ *
16
+ * await node.announceCapabilities({
17
+ * hardware: {
18
+ * cpuCores: 16,
19
+ * memoryGb: 64,
20
+ * gpu: { vendor: 'nvidia', model: 'RTX 4090', vramGb: 24 },
21
+ * },
22
+ * tags: ['gpu', 'inference'],
23
+ * models: [{ modelId: 'llama-3.1-70b', family: 'llama' }],
24
+ * });
25
+ *
26
+ * const peers = node.findNodes({ requireTags: ['gpu'], minVramMb: 16_384 });
27
+ * ```
28
+ *
29
+ * Multi-hop propagation is deferred; today peers more than one hop
30
+ * away are not visible.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.SCOPE_SUBNET_LOCAL = exports.SCOPE_REGION_PREFIX = exports.SCOPE_TENANT_PREFIX = void 0;
34
+ exports.capabilitySetToNapi = capabilitySetToNapi;
35
+ exports.capabilityFilterToNapi = capabilityFilterToNapi;
36
+ exports.scopeFilterToNapi = scopeFilterToNapi;
37
+ exports.withTenantScope = withTenantScope;
38
+ exports.withRegionScope = withRegionScope;
39
+ exports.withSubnetLocalScope = withSubnetLocalScope;
40
+ function gpuToNapi(g) {
41
+ return {
42
+ vendor: g.vendor,
43
+ model: g.model,
44
+ vramGb: g.vramGb,
45
+ computeUnits: g.computeUnits,
46
+ tensorCores: g.tensorCores,
47
+ fp16TflopsX10: g.fp16TflopsX10,
48
+ };
49
+ }
50
+ function acceleratorToNapi(a) {
51
+ return {
52
+ kind: a.kind,
53
+ model: a.model,
54
+ memoryGb: a.memoryGb,
55
+ topsX10: a.topsX10,
56
+ };
57
+ }
58
+ function hardwareToNapi(h) {
59
+ return {
60
+ cpuCores: h.cpuCores,
61
+ cpuThreads: h.cpuThreads,
62
+ memoryGb: h.memoryGb,
63
+ gpu: h.gpu ? gpuToNapi(h.gpu) : undefined,
64
+ additionalGpus: h.additionalGpus?.map(gpuToNapi),
65
+ storageGb: h.storageGb,
66
+ networkGbps: h.networkGbps,
67
+ accelerators: h.accelerators?.map(acceleratorToNapi),
68
+ };
69
+ }
70
+ function pairToArray(p) {
71
+ return [p[0], p[1]];
72
+ }
73
+ function softwareToNapi(s) {
74
+ return {
75
+ os: s.os,
76
+ osVersion: s.osVersion,
77
+ runtimes: s.runtimes?.map(pairToArray),
78
+ frameworks: s.frameworks?.map(pairToArray),
79
+ cudaVersion: s.cudaVersion,
80
+ drivers: s.drivers?.map(pairToArray),
81
+ };
82
+ }
83
+ function modelToNapi(m) {
84
+ return {
85
+ modelId: m.modelId,
86
+ family: m.family,
87
+ parametersBX10: m.parametersBX10,
88
+ contextLength: m.contextLength,
89
+ quantization: m.quantization,
90
+ modalities: m.modalities,
91
+ tokensPerSec: m.tokensPerSec,
92
+ loaded: m.loaded,
93
+ };
94
+ }
95
+ function toolToNapi(t) {
96
+ return {
97
+ toolId: t.toolId,
98
+ name: t.name,
99
+ version: t.version,
100
+ inputSchema: t.inputSchema,
101
+ outputSchema: t.outputSchema,
102
+ requires: t.requires,
103
+ estimatedTimeMs: t.estimatedTimeMs,
104
+ stateless: t.stateless,
105
+ };
106
+ }
107
+ function capabilitySetToNapi(caps) {
108
+ return {
109
+ hardware: caps.hardware ? hardwareToNapi(caps.hardware) : undefined,
110
+ software: caps.software ? softwareToNapi(caps.software) : undefined,
111
+ models: caps.models?.map(modelToNapi),
112
+ tools: caps.tools?.map(toolToNapi),
113
+ tags: caps.tags,
114
+ limits: caps.limits,
115
+ };
116
+ }
117
+ function capabilityFilterToNapi(f) {
118
+ return {
119
+ requireTags: f.requireTags,
120
+ requireModels: f.requireModels,
121
+ requireTools: f.requireTools,
122
+ minMemoryMb: f.minMemoryMb,
123
+ requireGpu: f.requireGpu,
124
+ gpuVendor: f.gpuVendor,
125
+ minVramMb: f.minVramMb,
126
+ minContextLength: f.minContextLength,
127
+ requireModalities: f.requireModalities,
128
+ };
129
+ }
130
+ function scopeFilterToNapi(s) {
131
+ switch (s.kind) {
132
+ case 'any':
133
+ case 'globalOnly':
134
+ case 'sameSubnet':
135
+ return { kind: s.kind };
136
+ case 'tenant':
137
+ return { kind: 'tenant', tenant: s.tenant };
138
+ case 'tenants':
139
+ return { kind: 'tenants', tenants: s.tenants };
140
+ case 'region':
141
+ return { kind: 'region', region: s.region };
142
+ case 'regions':
143
+ return { kind: 'regions', regions: s.regions };
144
+ }
145
+ }
146
+ // =====================================================
147
+ // Reserved scope tag helpers
148
+ // =====================================================
149
+ /** Reserved tag prefix for tenant-scoped announcements. */
150
+ exports.SCOPE_TENANT_PREFIX = 'scope:tenant:';
151
+ /** Reserved tag prefix for region-scoped announcements. */
152
+ exports.SCOPE_REGION_PREFIX = 'scope:region:';
153
+ /** Reserved tag marking an announcement subnet-local. */
154
+ exports.SCOPE_SUBNET_LOCAL = 'scope:subnet-local';
155
+ /**
156
+ * Append a `scope:tenant:<id>` tag to a tag list. Idempotent —
157
+ * safe to call repeatedly with the same id. Empty `tenantId` is a
158
+ * no-op.
159
+ */
160
+ function withTenantScope(tags, tenantId) {
161
+ if (!tenantId)
162
+ return tags ?? [];
163
+ const tag = `${exports.SCOPE_TENANT_PREFIX}${tenantId}`;
164
+ const list = tags ?? [];
165
+ return list.includes(tag) ? list : [...list, tag];
166
+ }
167
+ /** Append a `scope:region:<name>` tag to a tag list. Idempotent. */
168
+ function withRegionScope(tags, region) {
169
+ if (!region)
170
+ return tags ?? [];
171
+ const tag = `${exports.SCOPE_REGION_PREFIX}${region}`;
172
+ const list = tags ?? [];
173
+ return list.includes(tag) ? list : [...list, tag];
174
+ }
175
+ /**
176
+ * Append the `scope:subnet-local` tag to a tag list. Idempotent.
177
+ * Strictest form wins on the resolver — when this tag is present,
178
+ * tenant/region tags on the same set are ignored by
179
+ * `CapabilityScope`.
180
+ */
181
+ function withSubnetLocalScope(tags) {
182
+ const list = tags ?? [];
183
+ return list.includes(exports.SCOPE_SUBNET_LOCAL)
184
+ ? list
185
+ : [...list, exports.SCOPE_SUBNET_LOCAL];
186
+ }