@openrai/nano-core 1.0.0 → 2.1.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.
Files changed (42) hide show
  1. package/README.md +119 -47
  2. package/dist/client.d.ts +18 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +71 -3
  5. package/dist/client.js.map +1 -1
  6. package/dist/index.d.ts +3 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/transport/EndpointPool.d.ts +16 -0
  11. package/dist/transport/EndpointPool.d.ts.map +1 -0
  12. package/dist/transport/EndpointPool.js +105 -0
  13. package/dist/transport/EndpointPool.js.map +1 -0
  14. package/dist/transport/errors.d.ts +4 -0
  15. package/dist/transport/errors.d.ts.map +1 -0
  16. package/dist/transport/errors.js +7 -0
  17. package/dist/transport/errors.js.map +1 -0
  18. package/dist/transport/http.d.ts +13 -0
  19. package/dist/transport/http.d.ts.map +1 -0
  20. package/dist/transport/http.js +60 -0
  21. package/dist/transport/http.js.map +1 -0
  22. package/dist/transport/index.d.ts +7 -0
  23. package/dist/transport/index.d.ts.map +1 -0
  24. package/dist/transport/index.js +6 -0
  25. package/dist/transport/index.js.map +1 -0
  26. package/dist/transport/normalize.d.ts +10 -0
  27. package/dist/transport/normalize.d.ts.map +1 -0
  28. package/dist/transport/normalize.js +100 -0
  29. package/dist/transport/normalize.js.map +1 -0
  30. package/dist/transport/types.d.ts +57 -0
  31. package/dist/transport/types.d.ts.map +1 -0
  32. package/dist/transport/types.js +2 -0
  33. package/dist/transport/types.js.map +1 -0
  34. package/dist/transport/ws.d.ts +10 -0
  35. package/dist/transport/ws.d.ts.map +1 -0
  36. package/dist/transport/ws.js +29 -0
  37. package/dist/transport/ws.js.map +1 -0
  38. package/dist/work/WorkProvider.d.ts +7 -0
  39. package/dist/work/WorkProvider.d.ts.map +1 -1
  40. package/dist/work/WorkProvider.js +33 -3
  41. package/dist/work/WorkProvider.js.map +1 -1
  42. package/package.json +17 -1
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  Historically, Nano developers have faced a fragmented integration landscape: ranging from "heavy, enterprise:y" backends to lightweight "frontend-only" implementation, suffering either from rigid vendor lock-in or fragile PoW architecture.
13
13
 
14
- **`@openrai/nano-core`** extracts the most robust cryptographic, domain-driven design, and network-fallback primitives into a single, highly extensible foundation. It solves the hardest protocol challenges - such as block synchronization and different constraint between browser & backend environments - allowing developers to focus on application logic.
14
+ **`@openrai/nano-core`** aims to be the canonical TypeScript Nano package: typed primitives, sane defaults, transport failover, endpoint normalization, auth handling, and a stable first-party API surface even when the internals wrap other best-of-breed libraries.
15
15
 
16
16
  ---
17
17
 
@@ -20,7 +20,8 @@ Historically, Nano developers have faced a fragmented integration landscape: ran
20
20
  * **Bypassing the "Frontier Dilemma":** Nano is a state-based block-lattice where each block depends strictly on the exact final state of the previous frontier. This strong design choise is one of the main reasons why Nano can be feeless and energy efficient, but it often becomes a stumbling block for integrations. `@openrai/nano-core` provides internal concurrent Mutex queuing to perfectly sequentialize blocks even under heavy asynchronous loads, eliminating "Fork" or "Gap" errors.
21
21
  * **Isomorphic Proof-of-Work (JIT Profiling):** Wraps `nano-pow-with-fallback` in a Just-In-Time (JIT) environment profiler via `WorkProvider.auto()`. What it means is that whether running on an Apple Silicon Node.js server (jumping straight to local WebGPU) or on an aging mobile browser (delegating safely to remote servers by default), which generation method to use can be decided dynamically, without UI blocking or interfering with the current user flow.
22
22
  * **No Primitive-Obsession:** Heavily-typed, precision-safe wrappers for `NanoAmount` and `NanoAddress` entirely eliminate the "Stringly-Typed Money" programming anti-pattern.
23
- * **Resilient RPC Fallbacks:** Configure a progressive `TransportFallback` pool to gracefully route RPC requests across independent block validators without manual catch-blocks.
23
+ * **Resilient RPC / WS / Work Fallbacks:** Endpoint pools validate eagerly, deduplicate, apply endpoint-local exponential backoff, and only fail once all viable options are exhausted.
24
+ * **Secret-Safe Endpoint Normalization:** API keys from query params or URL userinfo are converted into structured auth metadata and redacted from canonical URLs and audit output.
24
25
  * **Cross-Language FFI Preparation**: The TypeScript architecture strictly follows Domain-Driven Design (DDD) to promote close API compatibility across different eventual programming language ports of the library.
25
26
 
26
27
  ## 📦 Installation
@@ -32,85 +33,155 @@ npm install @openrai/nano-core
32
33
 
33
34
  ## 🛠 Quick Start
34
35
 
35
- ### 1. Progressive Client Initialization
36
- The `NanoClient` uses a "Convention over Configuration" approach.
36
+ ### 1. Minimal Client
37
+ The default surface should feel obvious on first read:
37
38
 
38
- #### Easy Mode (All Defaults)
39
- Out of the box, `NanoClient.initialize()` falls back to a public node pool and auto-configures the JIT Proof-of-Work environment profiler:
39
+ ```typescript
40
+ import { NanoClient } from '@openrai/nano-core';
41
+
42
+ const client = NanoClient.initialize({
43
+ rpc: [
44
+ 'https://rpc.primary.example.com?apiKey=secret-rpc',
45
+ 'https://rpc.nano.to',
46
+ ], // [Optional] Defaults to the April 2026 public RPC set
47
+ ws: [
48
+ 'wss://ws.primary.example.com?api_key=secret-ws',
49
+ 'wss://rpc.nano.to',
50
+ ], // [Optional] Defaults to public WebSocket endpoints
51
+ work: [
52
+ 'https://work.primary.example.com?key=secret-work',
53
+ 'https://rpc.nano.to',
54
+ ], // [Optional] Defaults to `https://rpc.nano.to` as the current public work endpoint
55
+ warn: (message) => console.warn(message), // [Optional] Defaults to console.warn with nano-core prefix
56
+ });
57
+
58
+ console.log(client.getAuditReport());
59
+ ```
60
+
61
+ ### 1.1 Observe Endpoint Selection
62
+
63
+ Long-running services can observe which upstream endpoint became active without
64
+ mutating transport configuration at runtime:
40
65
 
41
66
  ```typescript
42
67
  import { NanoClient } from '@openrai/nano-core';
43
68
 
44
- // Zero configuration required for prototyping
45
- const protocolClient = NanoClient.initialize();
69
+ const client = NanoClient.initialize();
70
+
71
+ const unsubscribe = client.onEndpointChange((event) => {
72
+ console.log(event.kind, event.status, event.activeUrl, event.previousUrl);
73
+ });
74
+
75
+ console.log(client.getActiveEndpoints());
76
+ // { rpc?: string, ws?: string, work?: string }
77
+
78
+ // Later:
79
+ unsubscribe();
46
80
  ```
47
81
 
48
- #### Enterprise Mode (Explicit Overrides)
49
- For production environments, every single layer of the stack is fully overridable:
82
+ This is an observe-only API. It does not reconfigure pools or alter failover
83
+ policy; it simply exposes which endpoint was selected after a successful RPC,
84
+ WS, or work operation.
85
+
86
+ What this buys you immediately:
87
+
88
+ - comma-separated env vars also work: `NANO_RPC_URL`, `NANO_WS_URL`, `NANO_WORK_URL`
89
+ - malformed or duplicate endpoints are dropped during construction
90
+ - API keys in query params or URL userinfo are extracted and redacted from audit output
91
+ - failover and endpoint-local backoff happen inside the pool, not in your app code
92
+
93
+ Current built-in defaults as of April 2026:
94
+
95
+ - RPC: `https://rpc.nano.to`, `https://node.somenano.com/proxy`, `https://rainstorm.city/api`, `https://nanoslo.0x.no/proxy`
96
+ - WS: `wss://rpc.nano.to`
97
+ - Work: `https://rpc.nano.to`
98
+
99
+ ### 2. Zero-Config Prototype Mode
100
+ Out of the box, `NanoClient.initialize()` falls back to default public RPC / WS / work pools and auto-configures the work provider:
101
+
102
+ ```typescript
103
+ import { NanoClient } from '@openrai/nano-core';
104
+
105
+ const client = NanoClient.initialize();
106
+ ```
107
+
108
+ ### 3. Explicit Override Mode
109
+ For production environments, you can override only the pieces you care about while keeping the same normalized pool behavior:
50
110
 
51
111
  ```typescript
52
- import {
53
- NanoClient,
54
- TransportFallback,
112
+ import {
113
+ NanoClient,
55
114
  WorkProvider,
56
115
  RemoteWorkServer,
57
- LocalCompute
116
+ LocalCompute,
58
117
  } from '@openrai/nano-core';
59
118
 
60
- const protocolClient = NanoClient.initialize({
61
- network: 'mainnet', // [Optional] Default is 'mainnet'
62
-
63
- // [Optional] Resilient public/private node pooling
64
- transports: TransportFallback.of([
65
- 'https://rpc.my-private-node.com',
66
- 'https://rpc.nano.org'
67
- ]),
68
-
69
- // [Optional] JIT Environment Profiling overrides
119
+ const client = NanoClient.initialize({
120
+ network: 'mainnet', // [Optional] Defaults to 'mainnet'
121
+ rpc: [
122
+ 'https://rpc.private.example.com?apiKey=secret-rpc',
123
+ 'https://rpc.nano.to',
124
+ ], // [Optional] Defaults to the April 2026 public RPC set
125
+ ws: [
126
+ 'wss://ws.private.example.com?api_key=secret-ws',
127
+ 'wss://rpc.nano.to',
128
+ ], // [Optional] Defaults to public WebSocket endpoints
70
129
  workProvider: WorkProvider.auto({
130
+ urls: [
131
+ 'https://work.private.example.com?key=secret-work',
132
+ ], // [Optional] Defaults to `https://rpc.nano.to` when omitted
71
133
  remotes: [
72
- RemoteWorkServer.of('https://api.openrai.com/work', { timeoutMs: 5000, circuitBreakerMs: 30000 })
73
- ],
134
+ RemoteWorkServer.of(
135
+ 'https://work-backup.example.com',
136
+ {
137
+ timeoutMs: 5000, // [Optional] Defaults to 5000
138
+ circuitBreakerMs: 30000, // [Optional] Reserved for future tuning
139
+ },
140
+ ),
141
+ ], // [Optional] Additional remote work backends
74
142
  localChain: [
75
- LocalCompute.WEBGPU,
76
- LocalCompute.WASM_THREADS,
77
- LocalCompute.CPU
78
- ],
143
+ LocalCompute.WEBGPU,
144
+ LocalCompute.WASM_THREADS,
145
+ LocalCompute.CPU,
146
+ ], // [Optional] Local fallback order
79
147
  profiler: {
80
- mode: 'manual', // Explicit calibration to protect TTI
81
- preferLocalAboveMhs: 30, // Override threshold for server hardware
82
- cacheStrategy: 'persistent'
83
- }
84
- })
148
+ mode: 'manual',
149
+ preferLocalAboveMhs: 30,
150
+ cacheStrategy: 'persistent',
151
+ }, // [Optional] Calibration strategy overrides
152
+ warn: (message) => console.warn(message), // [Optional] Defaults to console.warn with nano-core prefix
153
+ }), // [Optional] Defaults to WorkProvider.auto(...) using normalized work endpoints
154
+ warn: (message) => console.warn(message), // [Optional] Defaults to console.warn with nano-core prefix
85
155
  });
86
156
  ```
87
157
 
88
- ### 2. Isomorphic Work Calibration
158
+ ### 4. Isomorphic Work Calibration
89
159
  It's critical not to freeze the browser threads. On boot, evaluate the environment. `nano-core` remembers the hardware constraints across sessions.
90
160
 
91
161
  ```typescript
92
162
  // Auto-detects whether local WebGPU/WASM is faster than network latency to remotes
93
- const profile = await protocolClient.workProvider.calibrate();
163
+ const profile = await client.workProvider.calibrate();
94
164
  console.log(`Determined active PoW strategy: ${profile.activeStrategy} at ${profile.measuredMhs} MH/s.`);
95
165
  ```
96
166
 
97
- ### 3. Precision-Safe Mutex Execution
98
- `NanoAmount` enforces standard 30-decimal limits at compile time, rejecting invalid floats. Sending is automatically queued per-account.
167
+ ### 5. Precision-Safe Execution
168
+ `NanoAmount` and `NanoAddress` give you typed protocol primitives immediately, even while the higher-level wallet surface is still being filled out.
99
169
 
100
170
  ```typescript
101
171
  import { NanoAddress, NanoAmount } from '@openrai/nano-core';
102
172
 
103
- // 1. Hydrate the Frontier
104
- const wallet = await protocolClient.hydrateWallet(process.env.NANO_SEED, { index: 0 });
173
+ const destination = NanoAddress.parse(
174
+ 'nano_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4',
175
+ );
176
+
177
+ const amount = NanoAmount.fromNano('1.25');
105
178
 
106
- // 2. Transact
107
- // The engine auto-queues the lock, generates PoW in the background, and broadcasts to the RPC pool.
108
- const receipt = await wallet.send(
109
- NanoAddress.parse('nano_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4'),
110
- NanoAmount.fromNano('1.25')
179
+ const wallet = await client.hydrateWallet(
180
+ process.env.NANO_SEED,
181
+ { index: 0 }, // [Optional] Defaults to account index 0
111
182
  );
112
183
 
113
- console.log(`Transaction finalized. Hash: ${receipt}`);
184
+ console.log({ destination, amount, wallet });
114
185
  ```
115
186
 
116
187
  ## 📐 Architecture Comparison
@@ -160,3 +231,4 @@ Across all tested engines, WebGL is the most consistently paced API. Because it
160
231
  These findings conclusively validate the `WorkProvider.auto()` architecture. The SDK cannot assume local hardware is safe just because `navigator.gpu` exists.
161
232
 
162
233
  The JIT Environment Profiler must execute a sub-50ms micro-probe on load. If the probe detects a sandboxed environment where a `Send` block will trigger the "Throttle Cliff" (taking >5 seconds), the SDK must intelligently route the work to a remote BPoW server, ensuring the application remains responsive and the user's battery is preserved.
234
+ See `docs/architecture/transport-auth.md` for the full transport/auth design.
package/dist/client.d.ts CHANGED
@@ -1,4 +1,7 @@
1
+ import { HttpEndpointPool } from './transport/http.js';
2
+ import { WsEndpointPool } from './transport/ws.js';
1
3
  import { WorkProvider } from './work/WorkProvider.js';
4
+ import type { EndpointActivityEvent } from './transport/types.js';
2
5
  export interface TransportFallback {
3
6
  urls: string[];
4
7
  }
@@ -8,13 +11,28 @@ export declare const TransportFallback: {
8
11
  export interface NanoClientOptions {
9
12
  network?: 'mainnet' | 'testnet' | 'beta';
10
13
  transports?: TransportFallback;
14
+ rpc?: string[];
15
+ ws?: string[];
16
+ work?: string[];
11
17
  workProvider?: WorkProvider;
18
+ warn?: (message: string) => void;
19
+ }
20
+ export interface NanoClientActiveEndpoints {
21
+ rpc?: string;
22
+ ws?: string;
23
+ work?: string;
12
24
  }
13
25
  export declare class NanoClient {
14
26
  workProvider: WorkProvider;
27
+ rpcPool: HttpEndpointPool;
28
+ wsPool: WsEndpointPool;
15
29
  private options;
30
+ private readonly endpointListeners;
31
+ private readonly activeEndpoints;
16
32
  private constructor();
17
33
  static initialize(options?: NanoClientOptions): NanoClient;
34
+ onEndpointChange(listener: (event: EndpointActivityEvent) => void): () => void;
35
+ getActiveEndpoints(): NanoClientActiveEndpoints;
18
36
  /**
19
37
  * Generates a minimal JSON-serializable report of the active configuration.
20
38
  * Useful for deploy-time auditing and startup logs to detect misconfigurations.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,eAAO,MAAM,iBAAiB;eACjB,MAAM,EAAE,KAAG,iBAAiB;CACxC,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACzC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,qBAAa,UAAU;IACd,YAAY,EAAE,YAAY,CAAC;IAClC,OAAO,CAAC,OAAO,CAAoB;IAEnC,OAAO;WAKO,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU;IAIrE;;;OAGG;IACI,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAS/B,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;wBAG/C,GAAG,UAAU,GAAG;;CAK3C"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAwB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAsB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,YAAY,EAA4B,MAAM,wBAAwB,CAAC;AAChF,OAAO,KAAK,EAAE,qBAAqB,EAAgB,MAAM,sBAAsB,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,eAAO,MAAM,iBAAiB;eACjB,MAAM,EAAE,KAAG,iBAAiB;CACxC,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACzC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,UAAU;IACd,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;IAC9B,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA8C;IAChF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAwC;IAExE,OAAO;WAsDO,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU;IAI9D,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI;IAK9E,kBAAkB,IAAI,yBAAyB;IAQtD;;;OAGG;IACI,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAS/B,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;wBAG/C,GAAG,UAAU,GAAG;;CAK3C"}
package/dist/client.js CHANGED
@@ -1,26 +1,94 @@
1
+ import { HttpEndpointPool } from './transport/http.js';
2
+ import { WsEndpointPool } from './transport/ws.js';
1
3
  import { WorkProvider } from './work/WorkProvider.js';
2
4
  export const TransportFallback = {
3
5
  of: (urls) => ({ urls })
4
6
  };
5
7
  export class NanoClient {
6
8
  workProvider;
9
+ rpcPool;
10
+ wsPool;
7
11
  options;
12
+ endpointListeners;
13
+ activeEndpoints;
8
14
  constructor(options) {
9
15
  this.options = options;
10
- this.workProvider = options.workProvider ?? WorkProvider.auto({});
16
+ this.endpointListeners = new Set();
17
+ this.activeEndpoints = {};
18
+ const warn = options.warn ?? ((message) => console.warn(`[nano-core] ${message}`));
19
+ const forwardEndpointChange = (event) => {
20
+ this.activeEndpoints[event.kind] = event.activeUrl;
21
+ for (const listener of this.endpointListeners) {
22
+ listener(event);
23
+ }
24
+ };
25
+ const defaultRpc = [
26
+ 'https://rpc.nano.to',
27
+ 'https://node.somenano.com/proxy',
28
+ 'https://rainstorm.city/api',
29
+ 'https://nanoslo.0x.no/proxy',
30
+ ];
31
+ const defaultWs = ['wss://rpc.nano.to'];
32
+ const defaultWork = ['https://rpc.nano.to'];
33
+ const rpcUrls = options.rpc ?? options.transports?.urls;
34
+ const rpcEnv = process.env['NANO_RPC_URL'];
35
+ const wsEnv = process.env['NANO_WS_URL'];
36
+ const workEnv = process.env['NANO_WORK_URL'];
37
+ const rpcOptions = {
38
+ kind: 'rpc',
39
+ defaults: defaultRpc,
40
+ warn,
41
+ onActiveEndpointChange: forwardEndpointChange,
42
+ };
43
+ if (rpcUrls && rpcUrls.length > 0)
44
+ rpcOptions.urls = rpcUrls;
45
+ if (rpcEnv)
46
+ rpcOptions.env = rpcEnv;
47
+ this.rpcPool = new HttpEndpointPool(rpcOptions);
48
+ const wsOptions = {
49
+ defaults: defaultWs,
50
+ warn,
51
+ onActiveEndpointChange: forwardEndpointChange,
52
+ };
53
+ if (options.ws && options.ws.length > 0)
54
+ wsOptions.urls = options.ws;
55
+ if (wsEnv)
56
+ wsOptions.env = wsEnv;
57
+ this.wsPool = new WsEndpointPool(wsOptions);
58
+ const workOptions = {
59
+ defaults: defaultWork,
60
+ warn,
61
+ onActiveEndpointChange: forwardEndpointChange,
62
+ };
63
+ if (options.work && options.work.length > 0)
64
+ workOptions.urls = options.work;
65
+ if (workEnv)
66
+ workOptions.env = workEnv;
67
+ this.workProvider = options.workProvider ?? WorkProvider.auto(workOptions);
11
68
  }
12
69
  static initialize(options = {}) {
13
70
  return new NanoClient(options);
14
71
  }
72
+ onEndpointChange(listener) {
73
+ this.endpointListeners.add(listener);
74
+ return () => this.endpointListeners.delete(listener);
75
+ }
76
+ getActiveEndpoints() {
77
+ return {
78
+ ...(this.activeEndpoints.rpc ? { rpc: this.activeEndpoints.rpc } : {}),
79
+ ...(this.activeEndpoints.ws ? { ws: this.activeEndpoints.ws } : {}),
80
+ ...(this.activeEndpoints.work ? { work: this.activeEndpoints.work } : {}),
81
+ };
82
+ }
15
83
  /**
16
84
  * Generates a minimal JSON-serializable report of the active configuration.
17
85
  * Useful for deploy-time auditing and startup logs to detect misconfigurations.
18
86
  */
19
87
  getAuditReport() {
20
- const defaultTransports = ['https://rpc.nano.org'];
21
88
  return {
22
89
  network: this.options.network ?? 'mainnet',
23
- transports: this.options.transports?.urls ?? defaultTransports,
90
+ rpc: this.rpcPool.getAuditReport(),
91
+ ws: this.wsPool.getAuditReport(),
24
92
  workProvider: this.workProvider.getAuditReport()
25
93
  };
26
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAMtD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,CAAC,IAAc,EAAqB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;CACtD,CAAC;AAQF,MAAM,OAAO,UAAU;IACd,YAAY,CAAe;IAC1B,OAAO,CAAoB;IAEnC,YAAoB,OAA0B;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IAEM,MAAM,CAAC,UAAU,CAAC,UAA6B,EAAE;QACtD,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,MAAM,iBAAiB,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACnD,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,SAAS;YAC1C,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,IAAI,iBAAiB;YAC9D,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE;SACjD,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,IAAY,EAAE,UAA8B,EAAE;QACvE,wCAAwC;QACxC,OAAO;YACL,IAAI,EAAE,KAAK,EAAE,OAAY,EAAE,MAAW,EAAE,EAAE;gBACxC,OAAO,YAAY,CAAC;YACtB,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAwB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAsB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,YAAY,EAA4B,MAAM,wBAAwB,CAAC;AAOhF,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,CAAC,IAAc,EAAqB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;CACtD,CAAC;AAkBF,MAAM,OAAO,UAAU;IACd,YAAY,CAAe;IAC3B,OAAO,CAAmB;IAC1B,MAAM,CAAiB;IACtB,OAAO,CAAoB;IAClB,iBAAiB,CAA8C;IAC/D,eAAe,CAAwC;IAExE,YAAoB,OAA0B;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC,CAAC;QAC3F,MAAM,qBAAqB,GAAG,CAAC,KAA4B,EAAQ,EAAE;YACnE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;YACnD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC9C,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;QACF,MAAM,UAAU,GAAG;YACjB,qBAAqB;YACrB,iCAAiC;YACjC,4BAA4B;YAC5B,6BAA6B;SAC9B,CAAC;QACF,MAAM,SAAS,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACxC,MAAM,WAAW,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC;QACxD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAE7C,MAAM,UAAU,GAAoB;YAClC,IAAI,EAAE,KAAK;YACX,QAAQ,EAAE,UAAU;YACpB,IAAI;YACJ,sBAAsB,EAAE,qBAAqB;SAC9C,CAAC;QACF,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,UAAU,CAAC,IAAI,GAAG,OAAO,CAAC;QAC7D,IAAI,MAAM;YAAE,UAAU,CAAC,GAAG,GAAG,MAAM,CAAC;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAEhD,MAAM,SAAS,GAAkB;YAC/B,QAAQ,EAAE,SAAS;YACnB,IAAI;YACJ,sBAAsB,EAAE,qBAAqB;SAC9C,CAAC;QACF,IAAI,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC;QACrE,IAAI,KAAK;YAAE,SAAS,CAAC,GAAG,GAAG,KAAK,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC;QAE5C,MAAM,WAAW,GAAwB;YACvC,QAAQ,EAAE,WAAW;YACrB,IAAI;YACJ,sBAAsB,EAAE,qBAAqB;SAC9C,CAAC;QACF,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,WAAW,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAC7E,IAAI,OAAO;YAAE,WAAW,CAAC,GAAG,GAAG,OAAO,CAAC;QAEvC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7E,CAAC;IAEM,MAAM,CAAC,UAAU,CAAC,UAA6B,EAAE;QACtD,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAEM,gBAAgB,CAAC,QAAgD;QACtE,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAEM,kBAAkB;QACvB,OAAO;YACL,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,SAAS;YAC1C,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;YAClC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;YAChC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE;SACjD,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,IAAY,EAAE,UAA8B,EAAE;QACvE,wCAAwC;QACxC,OAAO;YACL,IAAI,EAAE,KAAK,EAAE,OAAY,EAAE,MAAW,EAAE,EAAE;gBACxC,OAAO,YAAY,CAAC;YACtB,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export { NanoAddress } from './primitives/NanoAddress.js';
2
2
  export { NanoAmount } from './primitives/NanoAmount.js';
3
3
  export { WorkProvider, RemoteWorkServer, LocalCompute, type WorkProviderOptions } from './work/WorkProvider.js';
4
- export { NanoClient, TransportFallback, type NanoClientOptions } from './client.js';
4
+ export { NanoClient, TransportFallback, type NanoClientOptions, type NanoClientActiveEndpoints } from './client.js';
5
+ export { EndpointPool, HttpEndpointPool, NanoTransportConfigError, WsEndpointPool, normalizeEndpoints, } from './transport/index.js';
6
+ export type { AuthSource, EndpointActivityEvent, EndpointAuditRecord, EndpointAuth, EndpointKind, EndpointPoolOptions, EndpointState, NormalizedEndpoint, TransportPolicy, } from './transport/index.js';
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,KAAK,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,UAAU,EACV,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -2,4 +2,5 @@ export { NanoAddress } from './primitives/NanoAddress.js';
2
2
  export { NanoAmount } from './primitives/NanoAmount.js';
3
3
  export { WorkProvider, RemoteWorkServer, LocalCompute } from './work/WorkProvider.js';
4
4
  export { NanoClient, TransportFallback } from './client.js';
5
+ export { EndpointPool, HttpEndpointPool, NanoTransportConfigError, WsEndpointPool, normalizeEndpoints, } from './transport/index.js';
5
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAA4B,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAA0B,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAA4B,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAA0D,MAAM,aAAa,CAAC;AACpH,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,kBAAkB,GACnB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { EndpointAuditRecord, EndpointPoolOptions, NormalizedEndpoint } from './types.js';
2
+ export declare class EndpointPool {
3
+ private readonly states;
4
+ private readonly warn;
5
+ private readonly now;
6
+ private readonly baseDelayMs;
7
+ private readonly maxDelayMs;
8
+ private readonly onActiveEndpointChange;
9
+ private activeEndpointUrl;
10
+ constructor(options: EndpointPoolOptions);
11
+ private emitActiveEndpointChange;
12
+ getEndpoints(): NormalizedEndpoint[];
13
+ getAuditReport(): EndpointAuditRecord[];
14
+ execute<T>(attempt: (endpoint: NormalizedEndpoint) => Promise<T>): Promise<T>;
15
+ }
16
+ //# sourceMappingURL=EndpointPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EndpointPool.d.ts","sourceRoot":"","sources":["../../src/transport/EndpointPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,mBAAmB,EACnB,mBAAmB,EAEnB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAQpB,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAkD;IACzF,OAAO,CAAC,iBAAiB,CAAgB;gBAE7B,OAAO,EAAE,mBAAmB;IA2BxC,OAAO,CAAC,wBAAwB;IAczB,YAAY,IAAI,kBAAkB,EAAE;IAIpC,cAAc,IAAI,mBAAmB,EAAE;IAejC,OAAO,CAAC,CAAC,EACpB,OAAO,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GACpD,OAAO,CAAC,CAAC,CAAC;CAoCd"}
@@ -0,0 +1,105 @@
1
+ import { normalizeEndpoints } from './normalize.js';
2
+ function withJitter(delay) {
3
+ const factor = 0.85 + (Math.random() * 0.3);
4
+ return Math.round(delay * factor);
5
+ }
6
+ export class EndpointPool {
7
+ states;
8
+ warn;
9
+ now;
10
+ baseDelayMs;
11
+ maxDelayMs;
12
+ onActiveEndpointChange;
13
+ activeEndpointUrl;
14
+ constructor(options) {
15
+ this.warn = options.warn ?? (() => { });
16
+ this.now = options.now ?? (() => Date.now());
17
+ this.baseDelayMs = options.baseDelayMs ?? 500;
18
+ this.maxDelayMs = options.maxDelayMs ?? 30000;
19
+ this.onActiveEndpointChange = options.onActiveEndpointChange ?? null;
20
+ const endpoints = normalizeEndpoints({
21
+ kind: options.kind,
22
+ defaults: options.defaults,
23
+ warn: this.warn,
24
+ ...(options.urls ? { inputs: options.urls } : {}),
25
+ ...(options.env ? { env: options.env } : {}),
26
+ ...(options.transportPolicy ? { transportPolicy: options.transportPolicy } : {}),
27
+ });
28
+ this.states = endpoints.map((endpoint) => ({
29
+ endpoint,
30
+ consecutiveFailures: 0,
31
+ lastSuccessAt: null,
32
+ lastFailureAt: null,
33
+ cooldownUntil: 0,
34
+ lastLatencyMs: null,
35
+ }));
36
+ this.activeEndpointUrl = null;
37
+ }
38
+ emitActiveEndpointChange(nextUrl) {
39
+ if (!this.onActiveEndpointChange)
40
+ return;
41
+ if (this.activeEndpointUrl === nextUrl)
42
+ return;
43
+ const previousUrl = this.activeEndpointUrl ?? undefined;
44
+ this.activeEndpointUrl = nextUrl;
45
+ this.onActiveEndpointChange({
46
+ kind: this.states[0]?.endpoint.kind ?? 'rpc',
47
+ status: previousUrl ? 'failover' : 'connected',
48
+ activeUrl: nextUrl,
49
+ ...(previousUrl ? { previousUrl } : {}),
50
+ });
51
+ }
52
+ getEndpoints() {
53
+ return this.states.map((state) => state.endpoint);
54
+ }
55
+ getAuditReport() {
56
+ return this.states.map((state) => ({
57
+ kind: state.endpoint.kind,
58
+ url: state.endpoint.url.toString(),
59
+ authUsed: state.endpoint.auth.type === 'api-key',
60
+ authSource: state.endpoint.auth.type === 'api-key' ? state.endpoint.auth.source : null,
61
+ policy: state.endpoint.auth.type === 'api-key' ? state.endpoint.auth.policy : null,
62
+ consecutiveFailures: state.consecutiveFailures,
63
+ lastSuccessAt: state.lastSuccessAt,
64
+ lastFailureAt: state.lastFailureAt,
65
+ cooldownUntil: state.cooldownUntil > 0 ? new Date(state.cooldownUntil).toISOString() : null,
66
+ lastLatencyMs: state.lastLatencyMs,
67
+ }));
68
+ }
69
+ async execute(attempt) {
70
+ const start = this.now();
71
+ const orderedStates = [...this.states].sort((a, b) => {
72
+ const aReady = a.cooldownUntil <= start ? 0 : 1;
73
+ const bReady = b.cooldownUntil <= start ? 0 : 1;
74
+ if (aReady !== bReady)
75
+ return aReady - bReady;
76
+ const aLatency = a.lastLatencyMs ?? Number.MAX_SAFE_INTEGER;
77
+ const bLatency = b.lastLatencyMs ?? Number.MAX_SAFE_INTEGER;
78
+ return aLatency - bLatency;
79
+ });
80
+ let lastError;
81
+ for (const state of orderedStates) {
82
+ if (state.cooldownUntil > start)
83
+ continue;
84
+ const attemptStarted = this.now();
85
+ try {
86
+ const result = await attempt(state.endpoint);
87
+ state.consecutiveFailures = 0;
88
+ state.cooldownUntil = 0;
89
+ state.lastSuccessAt = new Date(this.now()).toISOString();
90
+ state.lastLatencyMs = this.now() - attemptStarted;
91
+ this.emitActiveEndpointChange(state.endpoint.url.toString());
92
+ return result;
93
+ }
94
+ catch (error) {
95
+ lastError = error;
96
+ state.consecutiveFailures += 1;
97
+ state.lastFailureAt = new Date(this.now()).toISOString();
98
+ const delay = Math.min(this.baseDelayMs * (2 ** (state.consecutiveFailures - 1)), this.maxDelayMs);
99
+ state.cooldownUntil = this.now() + withJitter(delay);
100
+ }
101
+ }
102
+ throw lastError instanceof Error ? lastError : new Error('All endpoints exhausted');
103
+ }
104
+ }
105
+ //# sourceMappingURL=EndpointPool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EndpointPool.js","sourceRoot":"","sources":["../../src/transport/EndpointPool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare class NanoTransportConfigError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/transport/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,EAAE,MAAM;CAI5B"}
@@ -0,0 +1,7 @@
1
+ export class NanoTransportConfigError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'NanoTransportConfigError';
5
+ }
6
+ }
7
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/transport/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { EndpointAuditRecord, EndpointPoolOptions } from './types.js';
2
+ export interface HttpPoolOptions extends Omit<EndpointPoolOptions, 'kind'> {
3
+ kind?: 'rpc' | 'work';
4
+ timeoutMs?: number;
5
+ }
6
+ export declare class HttpEndpointPool {
7
+ private readonly pool;
8
+ private readonly timeoutMs;
9
+ constructor(options: HttpPoolOptions);
10
+ getAuditReport(): EndpointAuditRecord[];
11
+ postJson<T>(body: Record<string, unknown>, extraHeaders?: Record<string, string>): Promise<T>;
12
+ }
13
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAsB,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACxE,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAeD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;gBAE9B,OAAO,EAAE,eAAe;IAQ7B,cAAc,IAAI,mBAAmB,EAAE;IAIjC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAqC3G"}
@@ -0,0 +1,60 @@
1
+ import { EndpointPool } from './EndpointPool.js';
2
+ function buildHeaders(endpoint, extraHeaders) {
3
+ const headers = {
4
+ 'Content-Type': 'application/json',
5
+ ...(extraHeaders ?? {}),
6
+ };
7
+ if (endpoint.auth.type === 'api-key') {
8
+ headers['Authorization'] = `Bearer ${endpoint.auth.value}`;
9
+ }
10
+ return headers;
11
+ }
12
+ export class HttpEndpointPool {
13
+ pool;
14
+ timeoutMs;
15
+ constructor(options) {
16
+ this.timeoutMs = options.timeoutMs ?? null;
17
+ this.pool = new EndpointPool({
18
+ ...options,
19
+ kind: options.kind ?? 'rpc',
20
+ });
21
+ }
22
+ getAuditReport() {
23
+ return this.pool.getAuditReport();
24
+ }
25
+ async postJson(body, extraHeaders) {
26
+ return this.pool.execute(async (endpoint) => {
27
+ const payload = endpoint.auth.type === 'api-key' && endpoint.auth.policy === 'json-body-key'
28
+ ? { ...body, key: endpoint.auth.value }
29
+ : endpoint.auth.type === 'api-key' && endpoint.auth.policy === 'bearer-and-json-body-key'
30
+ ? { ...body, key: endpoint.auth.value }
31
+ : body;
32
+ const controller = this.timeoutMs !== null ? new AbortController() : null;
33
+ const timer = controller && this.timeoutMs !== null
34
+ ? setTimeout(() => controller.abort(), this.timeoutMs)
35
+ : null;
36
+ let response;
37
+ try {
38
+ response = await fetch(endpoint.url, {
39
+ method: 'POST',
40
+ headers: buildHeaders(endpoint, extraHeaders),
41
+ body: JSON.stringify(payload),
42
+ ...(controller ? { signal: controller.signal } : {}),
43
+ });
44
+ }
45
+ finally {
46
+ if (timer !== null)
47
+ clearTimeout(timer);
48
+ }
49
+ if (!response.ok) {
50
+ throw new Error(`HTTP error ${response.status} ${response.statusText}`);
51
+ }
52
+ const json = await response.json();
53
+ if (json.error) {
54
+ throw new Error(json.error);
55
+ }
56
+ return json;
57
+ });
58
+ }
59
+ }
60
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { NanoTransportConfigError } from './errors.js';
2
+ export { normalizeEndpoints } from './normalize.js';
3
+ export { EndpointPool } from './EndpointPool.js';
4
+ export { HttpEndpointPool, type HttpPoolOptions } from './http.js';
5
+ export { WsEndpointPool, type WsPoolOptions } from './ws.js';
6
+ export type { AuthSource, EndpointActivityEvent, EndpointAuth, EndpointAuditRecord, EndpointKind, EndpointPoolOptions, EndpointState, NormalizedEndpoint, TransportPolicy, } from './types.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,YAAY,EACV,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { NanoTransportConfigError } from './errors.js';
2
+ export { normalizeEndpoints } from './normalize.js';
3
+ export { EndpointPool } from './EndpointPool.js';
4
+ export { HttpEndpointPool } from './http.js';
5
+ export { WsEndpointPool } from './ws.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAwB,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,cAAc,EAAsB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { EndpointKind, NormalizedEndpoint, TransportPolicy } from './types.js';
2
+ export declare function normalizeEndpoints(options: {
3
+ kind: EndpointKind;
4
+ inputs?: string[];
5
+ env?: string;
6
+ defaults: string[];
7
+ warn?: (message: string) => void;
8
+ transportPolicy?: TransportPolicy;
9
+ }): NormalizedEndpoint[];
10
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/transport/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,eAAe,EAChB,MAAM,YAAY,CAAC;AA6BpB,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC,GAAG,kBAAkB,EAAE,CAsFvB"}
@@ -0,0 +1,100 @@
1
+ import { NanoTransportConfigError } from './errors.js';
2
+ const API_KEY_QUERY_KEYS = ['key', 'apiKey', 'api_key'];
3
+ function allowedProtocols(kind) {
4
+ switch (kind) {
5
+ case 'rpc':
6
+ case 'work':
7
+ return ['http:', 'https:'];
8
+ case 'ws':
9
+ return ['ws:', 'wss:'];
10
+ }
11
+ }
12
+ function defaultPolicy(kind) {
13
+ return kind === 'ws' ? 'bearer-header' : 'bearer-header';
14
+ }
15
+ function normalizePath(url) {
16
+ if (url.pathname === '')
17
+ url.pathname = '/';
18
+ }
19
+ function canonicalKey(endpoint) {
20
+ const authKey = endpoint.auth.type === 'api-key'
21
+ ? `${endpoint.auth.type}:${endpoint.auth.value}:${endpoint.auth.policy}`
22
+ : 'none';
23
+ return `${endpoint.kind}:${endpoint.url.toString()}:${authKey}`;
24
+ }
25
+ export function normalizeEndpoints(options) {
26
+ const warn = options.warn ?? (() => { });
27
+ const rawInputs = options.inputs && options.inputs.length > 0
28
+ ? options.inputs
29
+ : options.env && options.env.trim() !== ''
30
+ ? options.env.split(',')
31
+ : options.defaults;
32
+ const allowed = allowedProtocols(options.kind);
33
+ const normalized = [];
34
+ const seen = new Set();
35
+ for (const raw of rawInputs) {
36
+ const input = raw.trim();
37
+ if (input === '')
38
+ continue;
39
+ let url;
40
+ try {
41
+ url = new URL(input);
42
+ }
43
+ catch {
44
+ warn(`Ignoring malformed ${options.kind.toUpperCase()} endpoint "${input}": invalid URL`);
45
+ continue;
46
+ }
47
+ if (!allowed.includes(url.protocol)) {
48
+ warn(`Ignoring invalid ${options.kind.toUpperCase()} endpoint "${input}": expected ${allowed.join(' or ')}`);
49
+ continue;
50
+ }
51
+ if (url.hostname.trim() === '') {
52
+ warn(`Ignoring invalid ${options.kind.toUpperCase()} endpoint "${input}": hostname is required`);
53
+ continue;
54
+ }
55
+ let auth = { type: 'none' };
56
+ for (const key of API_KEY_QUERY_KEYS) {
57
+ const value = url.searchParams.get(key);
58
+ if (value && value.trim() !== '') {
59
+ auth = {
60
+ type: 'api-key',
61
+ value,
62
+ source: 'query',
63
+ policy: options.transportPolicy ?? defaultPolicy(options.kind),
64
+ };
65
+ url.searchParams.delete(key);
66
+ break;
67
+ }
68
+ }
69
+ if (auth.type === 'none' && url.username.trim() !== '') {
70
+ auth = {
71
+ type: 'api-key',
72
+ value: decodeURIComponent(url.username),
73
+ source: 'userinfo',
74
+ policy: options.transportPolicy ?? defaultPolicy(options.kind),
75
+ };
76
+ url.username = '';
77
+ url.password = '';
78
+ }
79
+ normalizePath(url);
80
+ const endpoint = {
81
+ kind: options.kind,
82
+ originalInput: input,
83
+ url,
84
+ auth,
85
+ auditLabel: `${url.toString()}${auth.type === 'api-key' ? ' (api-key used)' : ' (no auth)'}`,
86
+ };
87
+ const dedupeKey = canonicalKey(endpoint);
88
+ if (seen.has(dedupeKey)) {
89
+ warn(`Ignoring duplicate ${options.kind.toUpperCase()} endpoint "${endpoint.auditLabel}"`);
90
+ continue;
91
+ }
92
+ seen.add(dedupeKey);
93
+ normalized.push(endpoint);
94
+ }
95
+ if (normalized.length === 0) {
96
+ throw new NanoTransportConfigError(`No valid ${options.kind.toUpperCase()} endpoints remain after validation`);
97
+ }
98
+ return normalized;
99
+ }
100
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/transport/normalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ export type EndpointKind = 'rpc' | 'ws' | 'work';
2
+ export type AuthSource = 'explicit' | 'query' | 'userinfo';
3
+ export type TransportPolicy = 'bearer-header' | 'json-body-key' | 'bearer-and-json-body-key';
4
+ export type EndpointAuth = {
5
+ type: 'none';
6
+ } | {
7
+ type: 'api-key';
8
+ value: string;
9
+ source: AuthSource;
10
+ policy: TransportPolicy;
11
+ };
12
+ export interface NormalizedEndpoint {
13
+ kind: EndpointKind;
14
+ originalInput: string;
15
+ url: URL;
16
+ auth: EndpointAuth;
17
+ auditLabel: string;
18
+ }
19
+ export interface EndpointState {
20
+ endpoint: NormalizedEndpoint;
21
+ consecutiveFailures: number;
22
+ lastSuccessAt: string | null;
23
+ lastFailureAt: string | null;
24
+ cooldownUntil: number;
25
+ lastLatencyMs: number | null;
26
+ }
27
+ export interface EndpointAuditRecord {
28
+ kind: EndpointKind;
29
+ url: string;
30
+ authUsed: boolean;
31
+ authSource: AuthSource | null;
32
+ policy: TransportPolicy | null;
33
+ consecutiveFailures: number;
34
+ lastSuccessAt: string | null;
35
+ lastFailureAt: string | null;
36
+ cooldownUntil: string | null;
37
+ lastLatencyMs: number | null;
38
+ }
39
+ export interface EndpointActivityEvent {
40
+ kind: EndpointKind;
41
+ status: 'connected' | 'failover';
42
+ activeUrl: string;
43
+ previousUrl?: string;
44
+ }
45
+ export interface EndpointPoolOptions {
46
+ kind: EndpointKind;
47
+ env?: string;
48
+ urls?: string[];
49
+ defaults: string[];
50
+ warn?: (message: string) => void;
51
+ now?: () => number;
52
+ transportPolicy?: TransportPolicy;
53
+ baseDelayMs?: number;
54
+ maxDelayMs?: number;
55
+ onActiveEndpointChange?: (event: EndpointActivityEvent) => void;
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAEjD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,eAAe,GAAG,0BAA0B,CAAC;AAE7F,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAEpF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,WAAW,GAAG,UAAU,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACjE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import type { EndpointAuditRecord, EndpointPoolOptions } from './types.js';
2
+ export interface WsPoolOptions extends Omit<EndpointPoolOptions, 'kind'> {
3
+ }
4
+ export declare class WsEndpointPool {
5
+ private readonly pool;
6
+ constructor(options: WsPoolOptions);
7
+ getAuditReport(): EndpointAuditRecord[];
8
+ connect(): Promise<WebSocket>;
9
+ }
10
+ //# sourceMappingURL=ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAsB,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC;CAAG;AAE3E,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;gBAExB,OAAO,EAAE,aAAa;IAO3B,cAAc,IAAI,mBAAmB,EAAE;IAIjC,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;CAiB3C"}
@@ -0,0 +1,29 @@
1
+ import { EndpointPool } from './EndpointPool.js';
2
+ export class WsEndpointPool {
3
+ pool;
4
+ constructor(options) {
5
+ this.pool = new EndpointPool({
6
+ ...options,
7
+ kind: 'ws',
8
+ });
9
+ }
10
+ getAuditReport() {
11
+ return this.pool.getAuditReport();
12
+ }
13
+ async connect() {
14
+ return this.pool.execute(async (endpoint) => {
15
+ let connectUrl = endpoint.url.toString();
16
+ if (endpoint.auth.type === 'api-key') {
17
+ const url = new URL(connectUrl);
18
+ url.searchParams.set('api_key', endpoint.auth.value);
19
+ connectUrl = url.toString();
20
+ }
21
+ return await new Promise((resolve, reject) => {
22
+ const ws = new WebSocket(connectUrl);
23
+ ws.onopen = () => resolve(ws);
24
+ ws.onerror = () => reject(new Error(`WebSocket connect failed: ${endpoint.auditLabel}`));
25
+ });
26
+ });
27
+ }
28
+ }
29
+ //# sourceMappingURL=ws.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD,MAAM,OAAO,cAAc;IACR,IAAI,CAAe;IAEpC,YAAY,OAAsB;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,YAAY,CAAC;YAC3B,GAAG,OAAO;YACV,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAEM,cAAc;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,OAAO;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,QAA4B,EAAE,EAAE;YAC9D,IAAI,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAEzC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBACrC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;gBAChC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrD,UAAU,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC9B,CAAC;YAED,OAAO,MAAM,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACtD,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC;gBACrC,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC9B,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC3F,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -1,3 +1,4 @@
1
+ import type { EndpointActivityEvent } from '../transport/types.js';
1
2
  /**
2
3
  * Local compute engines available.
3
4
  */
@@ -19,6 +20,11 @@ export declare class RemoteWorkServer {
19
20
  }): RemoteWorkServer;
20
21
  }
21
22
  export interface WorkProviderOptions {
23
+ urls?: string[];
24
+ env?: string;
25
+ defaults?: string[];
26
+ warn?: (message: string) => void;
27
+ onActiveEndpointChange?: (event: EndpointActivityEvent) => void;
22
28
  remotes?: RemoteWorkServer[];
23
29
  localChain?: LocalCompute[];
24
30
  profiler?: {
@@ -29,6 +35,7 @@ export interface WorkProviderOptions {
29
35
  }
30
36
  export declare class WorkProvider {
31
37
  private options;
38
+ private remotePool;
32
39
  private constructor();
33
40
  static auto(options: WorkProviderOptions): WorkProvider;
34
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"WorkProvider.d.ts","sourceRoot":"","sources":["../../src/work/WorkProvider.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,oBAAY,YAAY;IACtB,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,YAAY,SAAS;IACrB,GAAG,QAAQ;CACZ;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,UAAU,CAAS;gBAEf,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAK1C,IAAW,GAAG,IAAI,MAAM,CAAsB;IAC9C,IAAW,SAAS,IAAI,MAAM,CAA4B;IAE1D,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAO;CAGvF;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,YAAY,GAAG,QAAQ,CAAC;KACxC,CAAC;CACH;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;IAErC,OAAO;WAIO,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY;IAI9D;;OAEG;IACI,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAQ5C;;;OAGG;IACU,SAAS,IAAI,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAWlF;;OAEG;IACU,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAKzE"}
1
+ {"version":3,"file":"WorkProvider.d.ts","sourceRoot":"","sources":["../../src/work/WorkProvider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAGnE;;GAEG;AACH,oBAAY,YAAY;IACtB,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,YAAY,SAAS;IACrB,GAAG,QAAQ;CACZ;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,UAAU,CAAS;gBAEf,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAK1C,IAAW,GAAG,IAAI,MAAM,CAAsB;IAC9C,IAAW,SAAS,IAAI,MAAM,CAA4B;IAE1D,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAO;CAGvF;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAChE,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,YAAY,GAAG,QAAQ,CAAC;KACxC,CAAC;CACH;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,UAAU,CAA0B;IAE5C,OAAO;WAsBO,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY;IAI9D;;OAEG;IACI,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAS5C;;;OAGG;IACU,SAAS,IAAI,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAWlF;;OAEG;IACU,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAazE"}
@@ -1,3 +1,4 @@
1
+ import { HttpEndpointPool } from '../transport/http.js';
1
2
  /**
2
3
  * Local compute engines available.
3
4
  */
@@ -23,8 +24,28 @@ export class RemoteWorkServer {
23
24
  }
24
25
  export class WorkProvider {
25
26
  options;
27
+ remotePool;
26
28
  constructor(options) {
27
29
  this.options = options;
30
+ const hasRemotePool = (options.urls && options.urls.length > 0) || options.env || (options.defaults && options.defaults.length > 0);
31
+ if (!hasRemotePool) {
32
+ this.remotePool = null;
33
+ return;
34
+ }
35
+ const remotePoolOptions = {
36
+ kind: 'work',
37
+ defaults: options.defaults ?? [],
38
+ transportPolicy: 'bearer-and-json-body-key',
39
+ };
40
+ if (options.urls && options.urls.length > 0)
41
+ remotePoolOptions.urls = options.urls;
42
+ if (options.env)
43
+ remotePoolOptions.env = options.env;
44
+ if (options.warn)
45
+ remotePoolOptions.warn = options.warn;
46
+ if (options.onActiveEndpointChange)
47
+ remotePoolOptions.onActiveEndpointChange = options.onActiveEndpointChange;
48
+ this.remotePool = new HttpEndpointPool(remotePoolOptions);
28
49
  }
29
50
  static auto(options) {
30
51
  return new WorkProvider(options);
@@ -34,6 +55,7 @@ export class WorkProvider {
34
55
  */
35
56
  getAuditReport() {
36
57
  return {
58
+ remotePool: this.remotePool?.getAuditReport() ?? [],
37
59
  remotes: this.options.remotes?.map(r => ({ url: r.url, timeoutMs: r.timeoutMs })) || [],
38
60
  localChain: this.options.localChain || [],
39
61
  profiler: this.options.profiler || 'default'
@@ -56,9 +78,17 @@ export class WorkProvider {
56
78
  * Generate Proof-of-Work for a given hash.
57
79
  */
58
80
  async generate(hash, difficulty) {
59
- // In real implementation, this would route to Local vs Remote.
60
- // Placeholder to satisfy signature matching the design.
61
- return '0000000000000000'; // dummy work
81
+ if (this.remotePool) {
82
+ const response = await this.remotePool.postJson({
83
+ action: 'work_generate',
84
+ hash,
85
+ difficulty,
86
+ });
87
+ if (response.work)
88
+ return response.work;
89
+ }
90
+ // In real implementation, this would route to local fallback engines.
91
+ return '0000000000000000';
62
92
  }
63
93
  }
64
94
  //# sourceMappingURL=WorkProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WorkProvider.js","sourceRoot":"","sources":["../../src/work/WorkProvider.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAN,IAAY,YAKX;AALD,WAAY,YAAY;IACtB,iCAAiB,CAAA;IACjB,+BAAe,CAAA;IACf,qCAAqB,CAAA;IACrB,2BAAW,CAAA;AACb,CAAC,EALW,YAAY,KAAZ,YAAY,QAKvB;AAED,MAAM,OAAO,gBAAgB;IACnB,IAAI,CAAS;IACb,UAAU,CAAS;IAE3B,YAAY,GAAW,EAAE,SAAiB;QACxC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED,IAAW,GAAG,KAAa,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,IAAW,SAAS,KAAa,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,MAAM,CAAC,EAAE,CAAC,GAAW,EAAE,UAA6D,EAAE;QACpF,OAAO,IAAI,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;IAC9D,CAAC;CACF;AAYD,MAAM,OAAO,YAAY;IACf,OAAO,CAAsB;IAErC,YAAoB,OAA4B;QAC9C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAEM,MAAM,CAAC,IAAI,CAAC,OAA4B;QAC7C,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACI,cAAc;QACnB,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE;YACvF,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE;YACzC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,SAAS;SAC7C,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,SAAS;QACpB,wEAAwE;QACxE,kDAAkD;QAElD,yDAAyD;QACzD,OAAO;YACL,WAAW,EAAE,KAAK,EAAE,iCAAiC;YACrD,cAAc,EAAE,eAAe;SAChC,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,UAAkB;QACpD,+DAA+D;QAC/D,wDAAwD;QACxD,OAAO,kBAAkB,CAAC,CAAC,aAAa;IAC1C,CAAC;CACF"}
1
+ {"version":3,"file":"WorkProvider.js","sourceRoot":"","sources":["../../src/work/WorkProvider.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openrai/nano-core",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Protocol engine for Nano integration ecosystem",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,6 +9,18 @@
9
9
  ".": {
10
10
  "import": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts"
12
+ },
13
+ "./transport": {
14
+ "import": "./dist/transport/index.js",
15
+ "types": "./dist/transport/index.d.ts"
16
+ },
17
+ "./transport/http": {
18
+ "import": "./dist/transport/http.js",
19
+ "types": "./dist/transport/http.d.ts"
20
+ },
21
+ "./transport/ws": {
22
+ "import": "./dist/transport/ws.js",
23
+ "types": "./dist/transport/ws.d.ts"
12
24
  }
13
25
  },
14
26
  "scripts": {
@@ -22,6 +34,9 @@
22
34
  ],
23
35
  "author": "OpenRai",
24
36
  "license": "MIT",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
25
40
  "files": [
26
41
  "dist"
27
42
  ],
@@ -30,6 +45,7 @@
30
45
  "nanocurrency": "^2.5.0"
31
46
  },
32
47
  "devDependencies": {
48
+ "@types/node": "^24.6.0",
33
49
  "typescript": "^6.0.2",
34
50
  "vitest": "^4.1.2"
35
51
  }