@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,75 @@
1
+ /**
2
+ * Subnet configuration — hierarchical 4-level grouping for routing
3
+ * and visibility enforcement.
4
+ *
5
+ * Each node pins itself to one `SubnetId` (1–4 bytes, levels 0–3)
6
+ * and optionally derives peer subnets from their capability
7
+ * announcements via a `SubnetPolicy`. Channel visibility on the
8
+ * publish + subscribe paths then consults `SubnetId` geometry to
9
+ * decide whether a peer may see a given packet.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { MeshNode } from '@net-mesh/sdk';
14
+ *
15
+ * const policy = {
16
+ * rules: [
17
+ * { tagPrefix: 'region:', level: 0, values: { us: 3, eu: 4 } },
18
+ * { tagPrefix: 'fleet:', level: 1, values: { blue: 7, green: 8 } },
19
+ * ],
20
+ * };
21
+ *
22
+ * const node = await MeshNode.create({
23
+ * bindAddr: '127.0.0.1:9000',
24
+ * psk: '42'.repeat(32),
25
+ * subnet: { levels: [3, 7] },
26
+ * subnetPolicy: policy,
27
+ * });
28
+ * ```
29
+ *
30
+ * Today visibility enforcement covers `'subnet-local'` and
31
+ * `'parent-visible'`. `'exported'` (per-channel export tables) and
32
+ * multi-hop gateway routing are follow-ups.
33
+ */
34
+ export interface SubnetId {
35
+ /**
36
+ * 1–4 level bytes. Example: `[3, 7, 2]` = level 0 bucket 3,
37
+ * level 1 bucket 7, level 2 bucket 2, level 3 unset.
38
+ *
39
+ * Each value must fit in a u8 (0–255); at most 4 entries.
40
+ */
41
+ levels: number[];
42
+ }
43
+ /** Construct the conventional "no restriction" subnet. */
44
+ export declare const GLOBAL_SUBNET: SubnetId;
45
+ /**
46
+ * A single rule in a [`SubnetPolicy`]. When the policy runs against
47
+ * a node's `CapabilitySet`, the first capability tag starting with
48
+ * `tagPrefix` is looked up in `values`; the mapped byte fills the
49
+ * rule's `level` slot in the derived `SubnetId`.
50
+ */
51
+ export interface SubnetRule {
52
+ /** Tag prefix to match — e.g. `'region:'`. */
53
+ tagPrefix: string;
54
+ /** Hierarchy level this rule fills (0–3). */
55
+ level: number;
56
+ /**
57
+ * Map from tag suffix to subnet byte. E.g.
58
+ * `{ eu: 1, us: 2, apac: 3 }` — a tag `"region:us"` against a
59
+ * rule with `tagPrefix: "region:"` produces subnet byte `2` at
60
+ * the rule's level.
61
+ */
62
+ values: Record<string, number>;
63
+ }
64
+ /**
65
+ * Policy that derives each peer's `SubnetId` from their capability
66
+ * tags. Rules are evaluated in order; unmatched levels remain zero.
67
+ *
68
+ * Mesh-wide policy consistency is assumed — mismatched policies
69
+ * across nodes lead to asymmetric views of peer subnets.
70
+ */
71
+ export interface SubnetPolicy {
72
+ rules: SubnetRule[];
73
+ }
74
+ /** Build a `SubnetId` from an inline byte list, validating ranges. */
75
+ export declare function subnetId(...levels: number[]): SubnetId;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Subnet configuration — hierarchical 4-level grouping for routing
4
+ * and visibility enforcement.
5
+ *
6
+ * Each node pins itself to one `SubnetId` (1–4 bytes, levels 0–3)
7
+ * and optionally derives peer subnets from their capability
8
+ * announcements via a `SubnetPolicy`. Channel visibility on the
9
+ * publish + subscribe paths then consults `SubnetId` geometry to
10
+ * decide whether a peer may see a given packet.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { MeshNode } from '@net-mesh/sdk';
15
+ *
16
+ * const policy = {
17
+ * rules: [
18
+ * { tagPrefix: 'region:', level: 0, values: { us: 3, eu: 4 } },
19
+ * { tagPrefix: 'fleet:', level: 1, values: { blue: 7, green: 8 } },
20
+ * ],
21
+ * };
22
+ *
23
+ * const node = await MeshNode.create({
24
+ * bindAddr: '127.0.0.1:9000',
25
+ * psk: '42'.repeat(32),
26
+ * subnet: { levels: [3, 7] },
27
+ * subnetPolicy: policy,
28
+ * });
29
+ * ```
30
+ *
31
+ * Today visibility enforcement covers `'subnet-local'` and
32
+ * `'parent-visible'`. `'exported'` (per-channel export tables) and
33
+ * multi-hop gateway routing are follow-ups.
34
+ */
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.GLOBAL_SUBNET = void 0;
37
+ exports.subnetId = subnetId;
38
+ /** Construct the conventional "no restriction" subnet. */
39
+ exports.GLOBAL_SUBNET = { levels: [0] };
40
+ // ----------------------------------------------------------------------------
41
+ // Helpers
42
+ // ----------------------------------------------------------------------------
43
+ /** Build a `SubnetId` from an inline byte list, validating ranges. */
44
+ function subnetId(...levels) {
45
+ if (levels.length === 0 || levels.length > 4) {
46
+ throw new Error(`subnet: levels must have 1–4 entries, got ${levels.length}`);
47
+ }
48
+ for (const [i, v] of levels.entries()) {
49
+ if (!Number.isInteger(v) || v < 0 || v > 255) {
50
+ throw new Error(`subnet: level ${i} value ${v} must be an integer in [0, 255]`);
51
+ }
52
+ }
53
+ return { levels };
54
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Shared types for the Net SDK.
3
+ */
4
+ import type { Net as NapiNet, EventBusOptions, PollResponse as NapiPollResponse, StoredEvent as NapiStoredEvent, IngestResult as NapiIngestResult, Stats as NapiStats, RedisOptions, JetStreamOptions } from '@net-mesh/core';
5
+ export type { RedisOptions, JetStreamOptions, NapiNet, EventBusOptions, NapiPollResponse, NapiStoredEvent, NapiIngestResult, NapiStats, };
6
+ /** Transport configuration. */
7
+ export type Transport = {
8
+ type: 'memory';
9
+ } | ({
10
+ type: 'redis';
11
+ } & RedisOptions) | ({
12
+ type: 'jetstream';
13
+ } & JetStreamOptions) | {
14
+ type: 'mesh';
15
+ bind: string;
16
+ peer: string;
17
+ psk: string;
18
+ role?: 'initiator' | 'responder';
19
+ peerPublicKey?: string;
20
+ secretKey?: string;
21
+ publicKey?: string;
22
+ reliability?: 'none' | 'light' | 'full';
23
+ heartbeatIntervalMs?: number;
24
+ sessionTimeoutMs?: number;
25
+ batchedIo?: boolean;
26
+ packetPoolSize?: number;
27
+ };
28
+ /** Configuration for creating a NetNode. */
29
+ export interface NetNodeConfig {
30
+ /** Number of shards (defaults to CPU core count). */
31
+ shards?: number;
32
+ /** Ring buffer capacity per shard (must be power of 2). */
33
+ bufferCapacity?: number;
34
+ /** Backpressure strategy. */
35
+ backpressure?: 'drop_newest' | 'drop_oldest' | 'fail_producer';
36
+ /** Transport configuration. */
37
+ transport?: Transport;
38
+ }
39
+ /** Receipt from a successful ingestion. */
40
+ export interface Receipt {
41
+ /** The shard the event was assigned to. */
42
+ shardId: number;
43
+ /** Insertion timestamp (nanoseconds). */
44
+ timestamp: number;
45
+ }
46
+ /** A stored event from the bus. */
47
+ export interface StoredEvent {
48
+ /** Backend-specific event ID. */
49
+ id: string;
50
+ /** Raw JSON payload. */
51
+ raw: string;
52
+ /** Insertion timestamp (nanoseconds). */
53
+ insertionTs: number;
54
+ /** Shard ID. */
55
+ shardId: number;
56
+ }
57
+ /** Poll request options. */
58
+ export interface PollRequest {
59
+ /** Maximum events to return. */
60
+ limit: number;
61
+ /** Cursor to resume from. */
62
+ cursor?: string;
63
+ /** JSON filter expression. */
64
+ filter?: string;
65
+ /** Event ordering. */
66
+ ordering?: 'none' | 'insertion_ts';
67
+ }
68
+ /** Poll response. */
69
+ export interface PollResponseData {
70
+ /** Events returned. */
71
+ events: StoredEvent[];
72
+ /** Cursor for the next poll. */
73
+ nextId?: string;
74
+ /** Whether more events are available. */
75
+ hasMore: boolean;
76
+ }
77
+ /** Ingestion statistics.
78
+ *
79
+ * Counters cross the napi boundary as `bigint` because a long-running
80
+ * bus can outrun `Number.MAX_SAFE_INTEGER` (2^53) over weeks at high
81
+ * event rates. Use `Number(stats.eventsIngested)` for display when you
82
+ * know the value fits; keep as `bigint` for arithmetic.
83
+ */
84
+ export interface Stats {
85
+ /** Total events ingested. */
86
+ eventsIngested: bigint;
87
+ /** Events dropped due to backpressure. */
88
+ eventsDropped: bigint;
89
+ }
90
+ /** Options for subscribing to events. */
91
+ export interface SubscribeOpts {
92
+ /** Maximum events per poll batch. */
93
+ limit?: number;
94
+ /** JSON filter expression. */
95
+ filter?: string;
96
+ /** Event ordering. */
97
+ ordering?: 'none' | 'insertion_ts';
98
+ /** Base poll interval in ms. */
99
+ pollIntervalMs?: number;
100
+ /** Maximum backoff interval in ms. */
101
+ maxBackoffMs?: number;
102
+ }
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for the Net SDK.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@net-mesh/sdk",
3
+ "version": "0.19.0",
4
+ "description": "Ergonomic TypeScript SDK for the Net mesh network",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "license": "Apache-2.0",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/ai-2070/net"
11
+ },
12
+ "keywords": [
13
+ "net",
14
+ "mesh",
15
+ "event-bus",
16
+ "streaming",
17
+ "ai",
18
+ "llm",
19
+ "inference",
20
+ "rust"
21
+ ],
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "prebuild": "node -e \"const fs=require('fs'),cp=require('child_process');if(!fs.existsSync('../bindings/node/index.d.ts')){cp.execSync('npm --prefix ../bindings/node i --ignore-scripts',{stdio:'inherit'});cp.execSync('npm --prefix ../bindings/node run build',{stdio:'inherit'})}\"",
27
+ "build": "tsc",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest"
30
+ },
31
+ "peerDependencies": {
32
+ "@net-mesh/core": ">=0.19.0"
33
+ },
34
+ "devDependencies": {
35
+ "@net-mesh/core": "file:../bindings/node",
36
+ "@types/node": "^24.0.0",
37
+ "typescript": "^6.0.0",
38
+ "vitest": "^4.0.0"
39
+ },
40
+ "engines": {
41
+ "node": ">=20"
42
+ }
43
+ }