agentic-flow 3.4.2 → 3.4.4
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/CHANGELOG.md +13 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.d.ts.map +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/quic-loader.d.ts +31 -10
- package/dist/transport/quic-loader.d.ts.map +1 -1
- package/dist/transport/quic-loader.js +35 -39
- package/dist/transport/quic-loader.js.map +1 -1
- package/dist/transport/quic.d.ts +1 -0
- package/dist/transport/quic.d.ts.map +1 -1
- package/dist/transport/quic.js +10 -1
- package/dist/transport/quic.js.map +1 -1
- package/docs/quic/QUIC-STATUS.md +20 -0
- package/package.json +5 -5
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './quic.js';
|
|
2
|
-
export { loadQuicTransport, isQuicAvailable, getTransportCapabilities, WebSocketFallbackTransport, DEFAULT_STREAM_ID, type AgentTransport, type AgentMessage, type InboundMessageHandler, type OnMessageOptions, type PoolStatistics, type TransportCapabilities, type QuicTransportConfig as LoaderQuicTransportConfig, type TlsConfig, } from './quic-loader.js';
|
|
2
|
+
export { loadQuicTransport, isQuicAvailable, getQuicStatus, QUIC_UNAVAILABLE_REASON, getTransportCapabilities, WebSocketFallbackTransport, DEFAULT_STREAM_ID, type AgentTransport, type AgentMessage, type InboundMessageHandler, type OnMessageOptions, type PoolStatistics, type TransportCapabilities, type QuicStatus, type QuicTransportConfig as LoaderQuicTransportConfig, type TlsConfig, } from './quic-loader.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,wBAAwB,EACxB,0BAA0B,EAC1B,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,IAAI,yBAAyB,EACrD,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,mBAAmB,IAAI,yBAAyB,EACrD,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC"}
|
package/dist/transport/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Transport Layer Exports
|
|
2
2
|
export * from './quic.js';
|
|
3
|
-
export { loadQuicTransport, isQuicAvailable, getTransportCapabilities, WebSocketFallbackTransport, DEFAULT_STREAM_ID, } from './quic-loader.js';
|
|
3
|
+
export { loadQuicTransport, isQuicAvailable, getQuicStatus, QUIC_UNAVAILABLE_REASON, getTransportCapabilities, WebSocketFallbackTransport, DEFAULT_STREAM_ID, } from './quic-loader.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,wBAAwB,EACxB,0BAA0B,EAC1B,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,iBAAiB,GAUlB,MAAM,kBAAkB,CAAC","sourcesContent":["// Transport Layer Exports\nexport * from './quic.js';\nexport {\n loadQuicTransport,\n isQuicAvailable,\n getQuicStatus,\n QUIC_UNAVAILABLE_REASON,\n getTransportCapabilities,\n WebSocketFallbackTransport,\n DEFAULT_STREAM_ID,\n type AgentTransport,\n type AgentMessage,\n type InboundMessageHandler,\n type OnMessageOptions,\n type PoolStatistics,\n type TransportCapabilities,\n type QuicStatus,\n type QuicTransportConfig as LoaderQuicTransportConfig,\n type TlsConfig,\n} from './quic-loader.js';\n"]}
|
|
@@ -51,8 +51,7 @@ export interface AgentMessage {
|
|
|
51
51
|
* - One stream per task (`taskId` doubled as streamId)
|
|
52
52
|
* - One stream per priority class (`'high'`, `'normal'`, `'low'`)
|
|
53
53
|
*
|
|
54
|
-
*
|
|
55
|
-
* (each app-layer streamId becomes a QUIC stream id at that point).
|
|
54
|
+
* Would map to native QUIC stream ids if a native binding is ever added.
|
|
56
55
|
*/
|
|
57
56
|
streamId?: string | number;
|
|
58
57
|
}
|
|
@@ -240,24 +239,46 @@ declare class WebSocketFallbackTransport implements AgentTransport {
|
|
|
240
239
|
close(): Promise<void>;
|
|
241
240
|
}
|
|
242
241
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
242
|
+
* Why real QUIC is not available in npm builds of agentic-flow.
|
|
243
|
+
*
|
|
244
|
+
* - No native (N-API) QUIC binding exists. The quinn-based client/server in
|
|
245
|
+
* `crates/agentic-flow-quic` has no Node bindings and no build/publish
|
|
246
|
+
* pipeline, so nothing native ships in the tarball.
|
|
247
|
+
* - `wasm/quic/` is a browser build of that crate with quinn/tokio compiled
|
|
248
|
+
* out (browsers cannot open UDP sockets). It cannot move QUIC packets.
|
|
249
|
+
* - `agentic-flow/transport/quic` (QuicClient/QuicServer/QuicTransport) is a
|
|
250
|
+
* placeholder API that does not transmit bytes.
|
|
251
|
+
*
|
|
252
|
+
* The working transport is the WebSocket fallback returned by
|
|
253
|
+
* {@link loadQuicTransport}.
|
|
254
|
+
*/
|
|
255
|
+
export declare const QUIC_UNAVAILABLE_REASON: string;
|
|
256
|
+
/** Honest status for the QUIC backend. */
|
|
257
|
+
export interface QuicStatus {
|
|
258
|
+
available: boolean;
|
|
259
|
+
/** Present when available is false. */
|
|
260
|
+
reason?: string;
|
|
261
|
+
/** The transport loadQuicTransport() actually returns. */
|
|
262
|
+
fallback: 'websocket';
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Public API — load a working transport. Real QUIC is not available in npm
|
|
266
|
+
* builds (see {@link QUIC_UNAVAILABLE_REASON}), so this returns the WebSocket
|
|
267
|
+
* fallback, which satisfies the AgentTransport interface.
|
|
246
268
|
*
|
|
247
269
|
* Example:
|
|
248
270
|
* const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });
|
|
249
271
|
* await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });
|
|
250
|
-
*
|
|
251
|
-
* Federation v1 ships on the WebSocket fallback (this is the actual
|
|
252
|
-
* working transport today). When the native QUIC binding lands, set
|
|
253
|
-
* the AGENTIC_FLOW_QUIC_NATIVE=1 environment variable and the same
|
|
254
|
-
* code path picks up the upgrade with no API changes.
|
|
255
272
|
*/
|
|
256
273
|
export declare function loadQuicTransport(config?: QuicTransportConfig): Promise<AgentTransport>;
|
|
257
274
|
/** Quick capability probe for the doctor / health surface. */
|
|
258
275
|
export declare function isQuicAvailable(): Promise<boolean>;
|
|
276
|
+
/** Availability plus the reason when QUIC is unavailable. */
|
|
277
|
+
export declare function getQuicStatus(): Promise<QuicStatus>;
|
|
259
278
|
export interface TransportCapabilities {
|
|
260
279
|
quicAvailable: boolean;
|
|
280
|
+
/** Why QUIC is unavailable; present when quicAvailable is false. */
|
|
281
|
+
quicUnavailableReason?: string;
|
|
261
282
|
webSocketFallbackAvailable: true;
|
|
262
283
|
selectedBackend: 'quic' | 'websocket';
|
|
263
284
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quic-loader.d.ts","sourceRoot":"","sources":["../../src/transport/quic-loader.ts"],"names":[],"mappings":"AA4BA,oDAAoD;AACpD,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,WAAW,GAAG,MAAM,CAAC;IAC3E,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC
|
|
1
|
+
{"version":3,"file":"quic-loader.d.ts","sourceRoot":"","sources":["../../src/transport/quic-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -479,56 +479,44 @@ class WebSocketFallbackTransport {
|
|
|
479
479
|
}
|
|
480
480
|
}
|
|
481
481
|
/**
|
|
482
|
-
*
|
|
483
|
-
* actually moves bytes on the wire) vs the current stub. The stub
|
|
484
|
-
* returns 0ms for connect+send and never increments the server's
|
|
485
|
-
* received-bytes counter. We probe by observing a documented marker
|
|
486
|
-
* on the WASM module: when it's truly wired the loader function
|
|
487
|
-
* `defaultConfig` returns an object whose round-trip through
|
|
488
|
-
* `WasmQuicClient.new` actually opens a UDP socket — failing fast on
|
|
489
|
-
* an OS that blocks UDP outbound (e.g. some sandboxed CI envs).
|
|
482
|
+
* Why real QUIC is not available in npm builds of agentic-flow.
|
|
490
483
|
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
484
|
+
* - No native (N-API) QUIC binding exists. The quinn-based client/server in
|
|
485
|
+
* `crates/agentic-flow-quic` has no Node bindings and no build/publish
|
|
486
|
+
* pipeline, so nothing native ships in the tarball.
|
|
487
|
+
* - `wasm/quic/` is a browser build of that crate with quinn/tokio compiled
|
|
488
|
+
* out (browsers cannot open UDP sockets). It cannot move QUIC packets.
|
|
489
|
+
* - `agentic-flow/transport/quic` (QuicClient/QuicServer/QuicTransport) is a
|
|
490
|
+
* placeholder API that does not transmit bytes.
|
|
491
|
+
*
|
|
492
|
+
* The working transport is the WebSocket fallback returned by
|
|
493
|
+
* {@link loadQuicTransport}.
|
|
494
|
+
*/
|
|
495
|
+
export const QUIC_UNAVAILABLE_REASON = 'No native QUIC binding is published for agentic-flow: the quinn-based ' +
|
|
496
|
+
'crates/agentic-flow-quic has no N-API build, wasm/quic is a browser stub ' +
|
|
497
|
+
'without UDP, and agentic-flow/transport/quic is a placeholder that sends ' +
|
|
498
|
+
'no bytes. loadQuicTransport() uses the WebSocket fallback.';
|
|
499
|
+
/**
|
|
500
|
+
* Real QUIC is available only when a native binding has been loaded. None
|
|
501
|
+
* is published, so this is always false. Earlier releases returned true when
|
|
502
|
+
* AGENTIC_FLOW_QUIC_NATIVE=1 was set, even though the loader still returned
|
|
503
|
+
* the WebSocket transport. That variable is now ignored.
|
|
494
504
|
*/
|
|
495
505
|
async function isRealQuicAvailable() {
|
|
496
|
-
|
|
497
|
-
// The WASM file is published in `wasm/quic/` of this package. We
|
|
498
|
-
// do NOT use it for federation today (per the wasm.rs note: it's a
|
|
499
|
-
// stub since browsers can't do UDP). When a native binding is added
|
|
500
|
-
// this probe should switch to detect that binding instead.
|
|
501
|
-
const native = process.env.AGENTIC_FLOW_QUIC_NATIVE === '1';
|
|
502
|
-
return native;
|
|
503
|
-
}
|
|
504
|
-
catch {
|
|
505
|
-
return false;
|
|
506
|
-
}
|
|
506
|
+
return false;
|
|
507
507
|
}
|
|
508
508
|
/**
|
|
509
|
-
* Public API — load a working transport
|
|
510
|
-
*
|
|
511
|
-
* satisfies the AgentTransport interface
|
|
509
|
+
* Public API — load a working transport. Real QUIC is not available in npm
|
|
510
|
+
* builds (see {@link QUIC_UNAVAILABLE_REASON}), so this returns the WebSocket
|
|
511
|
+
* fallback, which satisfies the AgentTransport interface.
|
|
512
512
|
*
|
|
513
513
|
* Example:
|
|
514
514
|
* const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });
|
|
515
515
|
* await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });
|
|
516
|
-
*
|
|
517
|
-
* Federation v1 ships on the WebSocket fallback (this is the actual
|
|
518
|
-
* working transport today). When the native QUIC binding lands, set
|
|
519
|
-
* the AGENTIC_FLOW_QUIC_NATIVE=1 environment variable and the same
|
|
520
|
-
* code path picks up the upgrade with no API changes.
|
|
521
516
|
*/
|
|
522
517
|
export async function loadQuicTransport(config = {}) {
|
|
523
|
-
if (
|
|
524
|
-
|
|
525
|
-
logger.info('QUIC transport: native binding selected');
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
529
|
-
logger.warn('QUIC native binding not available; using WebSocket fallback. ' +
|
|
530
|
-
'Set AGENTIC_FLOW_QUIC_NATIVE=1 once a native build is installed.');
|
|
531
|
-
}
|
|
518
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
519
|
+
logger.warn('QUIC unavailable; using WebSocket fallback. ' + QUIC_UNAVAILABLE_REASON);
|
|
532
520
|
}
|
|
533
521
|
return WebSocketFallbackTransport.create(config);
|
|
534
522
|
}
|
|
@@ -536,10 +524,18 @@ export async function loadQuicTransport(config = {}) {
|
|
|
536
524
|
export async function isQuicAvailable() {
|
|
537
525
|
return isRealQuicAvailable();
|
|
538
526
|
}
|
|
527
|
+
/** Availability plus the reason when QUIC is unavailable. */
|
|
528
|
+
export async function getQuicStatus() {
|
|
529
|
+
const available = await isRealQuicAvailable();
|
|
530
|
+
return available
|
|
531
|
+
? { available, fallback: 'websocket' }
|
|
532
|
+
: { available, reason: QUIC_UNAVAILABLE_REASON, fallback: 'websocket' };
|
|
533
|
+
}
|
|
539
534
|
export async function getTransportCapabilities() {
|
|
540
535
|
const quic = await isRealQuicAvailable();
|
|
541
536
|
return {
|
|
542
537
|
quicAvailable: quic,
|
|
538
|
+
...(quic ? {} : { quicUnavailableReason: QUIC_UNAVAILABLE_REASON }),
|
|
543
539
|
webSocketFallbackAvailable: true,
|
|
544
540
|
selectedBackend: quic ? 'quic' : 'websocket',
|
|
545
541
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quic-loader.js","sourceRoot":"","sources":["../../src/transport/quic-loader.ts"],"names":[],"mappings":"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","sourcesContent":["// QUIC Transport Loader with WebSocket fallback\n//\n// Backported from outer repo loader pattern. Exposes a single\n// loadQuicTransport(config) entry point that:\n//\n// 1. Tries to load the WASM-backed QuicClient/QuicServer (real QUIC if a\n// native build is wired in the future).\n// 2. Falls back to WebSocketFallbackTransport when QUIC is unavailable\n// OR when the WASM stub is detected (current state — see\n// crates/agentic-flow-quic/src/wasm.rs comment: WASM build is a stub\n// because browsers can't do raw UDP/QUIC; production QUIC needs\n// native Node.js builds which haven't shipped yet).\n//\n// The fallback uses standard WebSocket (ws://) so it works on all Node\n// versions without complex native dependencies. Same async send/receive\n// API surface as QuicTransport.\n//\n// Federation use case (ruvnet/ruflo ADR-104): two peers on the same\n// tailnet can call loadQuicTransport({ serverName: 'peer.tailnet' }) and\n// exchange signed envelopes today, with zero code change required when\n// the native QUIC build lands later.\n\nimport { logger } from '../utils/logger.js';\nimport WebSocket, { WebSocketServer, type RawData } from 'ws';\nimport { createHash } from 'node:crypto';\nimport { createServer as createHttpsServer } from 'node:https';\nimport { readFileSync } from 'node:fs';\n\n/** TLS configuration for wss:// peers (ADR-107). */\nexport interface TlsConfig {\n /** Path to PEM cert file (server side — bind certs for the listener). */\n certPath?: string;\n /** Path to PEM key file (server side). */\n keyPath?: string;\n /**\n * Pinned `sha256/<base64>` fingerprints of acceptable peer certs\n * (client side — outbound connections).\n *\n * When set, ONLY these exact certs are accepted. CA validation is\n * skipped — the fingerprint IS the trust anchor. Fail-closed: if the\n * peer's cert rotates and the fingerprint doesn't match, the\n * connection is refused (operator must update config + restart).\n *\n * This prevents:\n * - Compromised public CAs issuing rogue certs for our domain\n * - TLS-MITM attacks where the attacker holds a valid cert chain\n */\n pinnedFingerprints?: string[];\n /**\n * Optional CA bundle path for non-pinned mode (e.g. private CA).\n * Used only when `pinnedFingerprints` is empty/unset.\n */\n caPath?: string;\n}\n\n/** Caller-facing config — minimal common surface across both backends. */\nexport interface QuicTransportConfig {\n serverName?: string;\n maxIdleTimeoutMs?: number;\n maxConcurrentStreams?: number;\n enable0Rtt?: boolean;\n /** TLS materials for wss:// listeners + clients (ADR-107). */\n tls?: TlsConfig;\n}\n\nexport interface AgentMessage {\n id: string;\n type: 'task' | 'result' | 'status' | 'coordination' | 'heartbeat' | string;\n payload: unknown;\n metadata?: Record<string, unknown>;\n /**\n * Stream multiplexing identifier. Messages with different streamIds\n * to the same peer are independent — receive queues and onMessage\n * handlers can scope per-stream, eliminating head-of-line blocking\n * for sequential `await` patterns on a single peer connection.\n *\n * Defaults to `'default'` if omitted (backward compat). Common\n * patterns:\n * - One stream per logical request type (`'rpc'`, `'event'`,\n * `'control'`)\n * - One stream per task (`taskId` doubled as streamId)\n * - One stream per priority class (`'high'`, `'normal'`, `'low'`)\n *\n * Maps cleanly to native QUIC streams when AGENTIC_FLOW_QUIC_NATIVE=1\n * (each app-layer streamId becomes a QUIC stream id at that point).\n */\n streamId?: string | number;\n}\n\n/** Default streamId when caller omits it. Backward-compat sentinel. */\nexport const DEFAULT_STREAM_ID = 'default';\n\n/** Largest WebSocket frame accepted from a peer (federation envelopes are ~100B-10KB). */\nexport const MAX_WS_PAYLOAD_BYTES = 1024 * 1024;\n/** Unconsumed messages kept per (peer, stream) for receive(); oldest dropped beyond this. */\nexport const MAX_QUEUED_PER_STREAM = 1000;\n/** Distinct (peer, stream) queues kept; messages for further new streams are dropped. */\nexport const MAX_QUEUE_STREAMS = 1024;\n\nexport interface PoolStatistics {\n active: number;\n idle: number;\n created: number;\n closed: number;\n}\n\n/** Inbound message handler — called for every received message. */\nexport type InboundMessageHandler = (\n address: string,\n message: AgentMessage,\n) => void | Promise<void>;\n\n/**\n * Per-stream subscription options. Pass to `onMessage` to scope a\n * handler to a specific streamId (only fires for messages with that\n * exact streamId). Omit to receive all streams.\n */\nexport interface OnMessageOptions {\n readonly streamId?: string | number;\n}\n\n/** Common interface both real-QUIC and fallback transports satisfy. */\nexport interface AgentTransport {\n send(address: string, message: AgentMessage): Promise<void>;\n /**\n * Receive the next message from a peer. Optional `streamId` scopes\n * to that stream's queue (independent of other streams to the same\n * peer). Omit to use the default stream — backward-compat behavior.\n */\n receive(address: string, streamId?: string | number): Promise<AgentMessage>;\n request(address: string, message: AgentMessage): Promise<AgentMessage>;\n sendBatch(address: string, messages: AgentMessage[]): Promise<void>;\n getStats(): Promise<PoolStatistics>;\n close(): Promise<void>;\n /**\n * Subscribe to inbound messages. The handler fires for every received\n * message that matches `options.streamId` (if provided) or for every\n * message regardless of streamId (if options omitted).\n *\n * Multiple handlers may be registered (per-stream OR all-streams or\n * a mix). Errors thrown by a handler are logged but do not stop\n * delivery to other handlers.\n *\n * Optional method — implementations that don't support push-style\n * delivery may omit it. Callers should use `transport.onMessage?.(h)`\n * to gracefully degrade.\n */\n onMessage?(handler: InboundMessageHandler, options?: OnMessageOptions): void;\n}\n\n/**\n * WebSocket fallback transport.\n *\n * Spec compliance: implements the AgentTransport interface using\n * `ws://` (or `wss://` if address starts with `wss://`). Each call to\n * `send` lazily opens (or reuses) a connection to `address`. The\n * `receive(address)` call drains the next queued message for that\n * address; if none is queued it polls every 100ms until one arrives.\n *\n * Limits vs real QUIC: no 0-RTT resumption, no multiplexed streams\n * (one TCP connection per peer), TLS handled by the WS layer (use\n * `wss://` for encryption). Performance is \"good enough\" for federation\n * messages at human/agent rates (≤ 100 RPS per peer).\n */\nclass WebSocketFallbackTransport implements AgentTransport {\n private connections = new Map<string, WebSocket>();\n /**\n * Per-(address, streamId) message queue. Composite key shape\n * `${address}#${streamId}` — see {@link queueKey}. Each stream gets\n * its own FIFO so receive(addr, streamA) is independent of\n * receive(addr, streamB) — eliminates head-of-line blocking on a\n * single peer connection.\n */\n private messageQueue = new Map<string, AgentMessage[]>();\n private connectionsCreated = 0;\n private connectionsClosed = 0;\n private servers = new Map<number, WebSocketServer>();\n /**\n * Inbound handlers. Each entry is { handler, streamId? }. When\n * streamId is undefined the handler receives ALL messages\n * regardless of stream; otherwise only messages with the matching\n * streamId. Lets callers register both per-stream + catch-all.\n */\n private inboundHandlers = new Set<{\n handler: InboundMessageHandler;\n streamId?: string | number;\n }>();\n /**\n * Server-accepted (inbound) sockets indexed by peer host (#162). A\n * peer that already dialed us has a live, full-duplex socket here;\n * {@link getOrCreateConnection} reuses it for replies instead of\n * opening a fresh outbound connection — which, on a direct\n * point-to-point link, can hit a per-process stale scoped route\n * (`EHOSTUNREACH`) even while the inbound direction is healthy.\n */\n private inboundByHost = new Map<string, WebSocket>();\n /** Active liveness-probe intervals, cleared on close (#162). */\n private heartbeats = new Set<ReturnType<typeof setInterval>>();\n\n /**\n * Liveness ping cadence, derived from `maxIdleTimeoutMs` (#162 — this\n * config was previously accepted but never used). Pings at 1/6 of the\n * idle timeout so a dead socket is caught within ~1/3 of it. Default\n * 30000ms → 5000ms.\n */\n private get pingIntervalMs(): number {\n return Math.max(1000, Math.floor(this.config.maxIdleTimeoutMs / 6));\n }\n\n /**\n * Normalize an address or socket `remoteAddress` to a bare host key\n * for {@link inboundByHost} lookups. Strips `ws(s)://` scheme, an\n * IPv6-mapped IPv4 prefix (`::ffff:`), bracketed IPv6 (`[::1]:port`),\n * and a trailing `:port` on plain `host:port` forms. Bare IPv6\n * (multiple colons, no brackets) is returned unchanged.\n */\n private hostOf(addr: string): string {\n let s = addr.replace(/^wss?:\\/\\//i, '');\n const bracket = s.match(/^\\[([^\\]]+)\\](?::\\d+)?$/);\n if (bracket) s = bracket[1];\n else if (/^[^:]+:\\d+$/.test(s)) s = s.slice(0, s.lastIndexOf(':'));\n return s.replace(/^::ffff:/i, '');\n }\n\n /**\n * Liveness probe for a socket (#162). Pings on {@link pingIntervalMs};\n * a socket that misses a ping/pong window is terminated so a stale\n * connection can't silently black-hole sends. The interval is unref'd\n * (never keeps the process alive on its own) and cleared on close/error.\n */\n private startHeartbeat(ws: WebSocket): void {\n let alive = true;\n ws.on('pong', () => { alive = true; });\n const interval = setInterval(() => {\n if (!alive) {\n try { ws.terminate(); } catch { /* already gone */ }\n return; // 'close' fires → stop() clears this interval\n }\n alive = false;\n try { ws.ping(); } catch { /* socket is closing */ }\n }, this.pingIntervalMs);\n (interval as { unref?: () => void }).unref?.();\n this.heartbeats.add(interval);\n const stop = () => {\n clearInterval(interval);\n this.heartbeats.delete(interval);\n };\n ws.on('close', stop);\n ws.on('error', stop);\n }\n\n /** Compose the per-(address, streamId) queue key. */\n private queueKey(address: string, streamId: string | number): string {\n return `${address}#${streamId}`;\n }\n\n /** Resolve the streamId for a message — defaults to DEFAULT_STREAM_ID. */\n private streamOf(message: AgentMessage): string | number {\n return message.streamId ?? DEFAULT_STREAM_ID;\n }\n\n constructor(private readonly config: Required<QuicTransportConfig>) {}\n\n static async create(config: QuicTransportConfig = {}): Promise<WebSocketFallbackTransport> {\n const fullConfig: Required<QuicTransportConfig> = {\n serverName: config.serverName ?? 'localhost',\n maxIdleTimeoutMs: config.maxIdleTimeoutMs ?? 30000,\n maxConcurrentStreams: config.maxConcurrentStreams ?? 100,\n // Not applicable for WebSocket — record but ignore\n enable0Rtt: config.enable0Rtt ?? false,\n tls: config.tls ?? {},\n };\n return new WebSocketFallbackTransport(fullConfig);\n }\n\n /**\n * Bind a server-side listener so this transport instance can RECEIVE\n * messages from a remote peer (in addition to sending). Federation\n * peers run BOTH a listener and a client — calling listen(9100) plus\n * send('peer:9100', ...) gives bidirectional connectivity.\n *\n * Enables `permessage-deflate` compression with thresholds chosen\n * for federation envelopes (typically JSON, 100B-10KB):\n * - threshold: 256B — don't waste CPU compressing tiny pings\n * - level: 3 — balanced compression vs CPU (zlib's BEST_SPEED→6 range)\n * - serverNoContextTakeover: true — bound per-conn memory growth\n */\n async listen(port: number, host = '127.0.0.1'): Promise<void> {\n if (this.servers.has(port)) return;\n return new Promise((resolve, reject) => {\n const tls = this.config.tls;\n const wssOpts: ConstructorParameters<typeof WebSocketServer>[0] = {\n maxPayload: MAX_WS_PAYLOAD_BYTES,\n perMessageDeflate: {\n threshold: 256,\n zlibDeflateOptions: { level: 3 },\n serverNoContextTakeover: true,\n clientNoContextTakeover: true,\n },\n };\n // ADR-107: if cert+key paths are configured, bind via https.Server\n // (wss://). Otherwise bind plain ws:// directly.\n if (tls?.certPath && tls?.keyPath) {\n const cert = readFileSync(tls.certPath);\n const key = readFileSync(tls.keyPath);\n const httpsServer = createHttpsServer({ cert, key });\n httpsServer.listen(port, host, () => {\n const wss = new WebSocketServer({ ...wssOpts, server: httpsServer });\n this.attachServerHandlers(wss);\n this.servers.set(port, wss);\n resolve();\n });\n httpsServer.on('error', reject);\n return;\n }\n const wss = new WebSocketServer({ ...wssOpts, port, host });\n wss.on('listening', () => {\n this.servers.set(port, wss);\n resolve();\n });\n wss.on('error', reject);\n this.attachServerHandlers(wss);\n });\n }\n\n /**\n * Wire the server's `connection` and per-socket `message` handlers.\n * Extracted so the wss:// path (where the WebSocketServer is attached\n * to a pre-created https.Server) can share the same logic.\n */\n private attachServerHandlers(wss: WebSocketServer): void {\n wss.on('connection', (ws, req) => {\n const remoteAddr = `${req.socket.remoteAddress}:${req.socket.remotePort}`;\n // #162: register this accepted socket for outbound reuse, and probe\n // it for liveness. Reusing it for replies avoids a fresh (stale-route\n // prone) outbound dial back to the same peer.\n const host = this.hostOf(req.socket.remoteAddress ?? remoteAddr);\n this.inboundByHost.set(host, ws);\n this.startHeartbeat(ws);\n const dropInbound = () => {\n if (this.inboundByHost.get(host) === ws) this.inboundByHost.delete(host);\n };\n ws.on('close', dropInbound);\n ws.on('error', dropInbound);\n\n ws.on('message', (raw: RawData) => {\n try {\n const message = JSON.parse(raw.toString()) as AgentMessage;\n this.deliverInbound(remoteAddr, message);\n } catch (err) {\n logger.warn('Dropped malformed inbound WS message', { remoteAddr, err });\n }\n });\n });\n }\n\n private async getOrCreateConnection(address: string): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const existing = this.connections.get(address);\n if (existing && existing.readyState === WebSocket.OPEN) {\n resolve(existing);\n return;\n }\n\n // #162: prefer an already-open INBOUND socket from the same peer host\n // before dialing. WebSocket is full-duplex, so the server-accepted\n // socket can carry our replies — and the inbound direction stays\n // healthy when a fresh outbound dial would hit a stale scoped route.\n const inbound = this.inboundByHost.get(this.hostOf(address));\n if (inbound && inbound.readyState === WebSocket.OPEN) {\n resolve(inbound);\n return;\n }\n\n const url = address.startsWith('ws://') || address.startsWith('wss://')\n ? address\n : `ws://${address}`;\n\n // ADR-107: cert pinning for wss:// peers. Build the WS options\n // with both compression (perf) and TLS hooks (security).\n const tls = this.config.tls;\n const isWss = url.startsWith('wss://');\n const wsOpts: WebSocket.ClientOptions = {\n maxPayload: MAX_WS_PAYLOAD_BYTES,\n perMessageDeflate: {\n threshold: 256,\n zlibDeflateOptions: { level: 3 },\n serverNoContextTakeover: true,\n clientNoContextTakeover: true,\n },\n };\n\n if (isWss && tls?.pinnedFingerprints && tls.pinnedFingerprints.length > 0) {\n // Fail-closed pinning: ONLY accept the listed cert fingerprints.\n // CA path validation is irrelevant — the fingerprint IS the trust\n // anchor. If the cert rotates, the operator must update config.\n const pinned = new Set(tls.pinnedFingerprints);\n // Cast: ws's `checkServerIdentity` is typed as returning boolean\n // but the underlying `tls.checkServerIdentity` (which it\n // forwards to) accepts `Error | undefined`. The runtime\n // semantics are: throw OR return Error → reject; otherwise accept.\n // The boolean type signature is overly restrictive.\n (wsOpts as unknown as { checkServerIdentity: unknown }).checkServerIdentity = (\n _host: string,\n cert: { raw: Buffer },\n ): Error | undefined => {\n // cert.raw is the DER-encoded cert bytes; sha256/<base64> matches\n // common pinning notation (and what `openssl x509 -fingerprint\n // -sha256` outputs after base64-encoding).\n const fp = `sha256/${createHash('sha256').update(cert.raw).digest('base64')}`;\n if (!pinned.has(fp)) {\n return new Error(\n `Federation TLS: peer cert fingerprint ${fp} not in pinned set ` +\n `(${pinned.size} fingerprint(s) configured)`,\n );\n }\n return undefined; // accept\n };\n // When pinning is on, we explicitly DON'T want CA validation\n // (the fingerprint check above is the real auth). But we also\n // DON'T want to silently accept ANY cert — the checkServerIdentity\n // above is still called.\n wsOpts.rejectUnauthorized = false;\n } else if (isWss && tls?.caPath) {\n // Non-pinned mode: validate against the configured CA bundle.\n wsOpts.ca = readFileSync(tls.caPath);\n wsOpts.rejectUnauthorized = true;\n }\n // (no tls config + ws:// → plain unencrypted; ADR-104 documents\n // tailnet-as-TLS as the recommended path)\n\n const ws = new WebSocket(url, wsOpts);\n\n ws.on('open', () => {\n this.connections.set(address, ws);\n this.connectionsCreated++;\n this.startHeartbeat(ws); // #162: keep the outbound link probed\n resolve(ws);\n });\n\n ws.on('error', (error: Error) => {\n reject(new Error(`WebSocket connection to ${url} failed: ${error.message}`));\n });\n\n ws.on('close', () => {\n this.connectionsClosed++;\n this.connections.delete(address);\n });\n\n ws.on('message', (raw: RawData) => {\n try {\n const message = JSON.parse(raw.toString()) as AgentMessage;\n this.deliverInbound(address, message);\n } catch (err) {\n logger.warn('Dropped malformed WebSocket message', { address, err });\n }\n });\n });\n }\n\n async send(address: string, message: AgentMessage): Promise<void> {\n const ws = await this.getOrCreateConnection(address);\n ws.send(JSON.stringify(message));\n }\n\n /**\n * Register an inbound handler. Optional `options.streamId` scopes\n * the handler to a specific stream (only fires for messages with\n * matching streamId). Omit to subscribe to ALL streams.\n *\n * Patterns:\n * onMessage(h) — receives all\n * onMessage(h, { streamId: 'rpc' }) — receives only rpc\n * onMessage(h, { streamId: 'event' }) — receives only event\n * (both registered) — both fire on\n * their respective streams\n */\n onMessage(handler: InboundMessageHandler, options: OnMessageOptions = {}): void {\n this.inboundHandlers.add({ handler, streamId: options.streamId });\n }\n\n /**\n * Fire all matching handlers for a received message. Stream-scoped\n * handlers only fire when the message's streamId matches; all-stream\n * handlers always fire. Errors thrown sync OR async-rejected by one\n * handler don't stop delivery to others.\n */\n private dispatchInbound(address: string, message: AgentMessage): boolean {\n if (this.inboundHandlers.size === 0) return false;\n const msgStream = this.streamOf(message);\n let delivered = false;\n for (const entry of this.inboundHandlers) {\n // Stream filter: scoped handler only fires on matching streamId\n if (entry.streamId !== undefined && entry.streamId !== msgStream) continue;\n delivered = true;\n try {\n const r = entry.handler(address, message);\n if (r && typeof (r as Promise<void>).catch === 'function') {\n (r as Promise<void>).catch((err) => {\n logger.warn('Inbound handler rejected', { address, err });\n });\n }\n } catch (err) {\n logger.warn('Inbound handler threw', { address, err });\n }\n }\n return delivered;\n }\n\n /**\n * Hand an inbound message to the matching onMessage handlers. Only a\n * message no handler consumed is queued for receive(), and the queues are\n * bounded so a peer cannot grow memory without limit.\n */\n private deliverInbound(address: string, message: AgentMessage): void {\n if (this.dispatchInbound(address, message)) return;\n // Per-stream queue (default stream when message.streamId omitted)\n const key = this.queueKey(address, this.streamOf(message));\n let queue = this.messageQueue.get(key);\n if (!queue) {\n if (this.messageQueue.size >= MAX_QUEUE_STREAMS) {\n logger.warn('Dropped inbound message: too many queued streams', { address, key });\n return;\n }\n queue = [];\n this.messageQueue.set(key, queue);\n }\n queue.push(message);\n if (queue.length > MAX_QUEUED_PER_STREAM) {\n queue.shift();\n logger.warn('Inbound queue full; dropped oldest message', { address, key });\n }\n }\n\n /** Shift the head of a queue, dropping the queue once empty so stream keys don't accumulate. */\n private takeFrom(key: string, queue: AgentMessage[]): AgentMessage {\n const message = queue.shift()!;\n if (queue.length === 0) this.messageQueue.delete(key);\n return message;\n }\n\n /** Messages waiting for receive(), across all peers and streams. */\n queuedMessageCount(): number {\n let total = 0;\n for (const queue of this.messageQueue.values()) total += queue.length;\n return total;\n }\n\n async receive(address: string, streamId: string | number = DEFAULT_STREAM_ID): Promise<AgentMessage> {\n const key = this.queueKey(address, streamId);\n // Fast path\n const queue = this.messageQueue.get(key) ?? [];\n if (queue.length > 0) return this.takeFrom(key, queue);\n\n // Poll (caller must time out externally if they don't want to wait)\n return new Promise((resolve) => {\n const interval = setInterval(() => {\n const q = this.messageQueue.get(key) ?? [];\n if (q.length > 0) {\n clearInterval(interval);\n resolve(this.takeFrom(key, q));\n }\n }, 100);\n });\n }\n\n async request(address: string, message: AgentMessage): Promise<AgentMessage> {\n await this.send(address, message);\n return this.receive(address);\n }\n\n async sendBatch(address: string, messages: AgentMessage[]): Promise<void> {\n await Promise.all(messages.map((m) => this.send(address, m)));\n }\n\n async getStats(): Promise<PoolStatistics> {\n return {\n active: this.connections.size,\n idle: 0,\n created: this.connectionsCreated,\n closed: this.connectionsClosed,\n };\n }\n\n async close(): Promise<void> {\n // Outbound clients first.\n for (const ws of this.connections.values()) {\n ws.terminate();\n }\n this.connections.clear();\n this.messageQueue.clear();\n\n // Stop all liveness probes and drop the inbound index (#162).\n for (const interval of this.heartbeats) clearInterval(interval);\n this.heartbeats.clear();\n this.inboundByHost.clear();\n\n // Inbound: WebSocketServer.close() blocks until every accepted\n // socket disconnects. Forcibly terminate them so the close\n // callback fires within the test/CI timeout window.\n for (const wss of this.servers.values()) {\n for (const client of wss.clients) {\n try {\n client.terminate();\n } catch {\n /* socket already gone */\n }\n }\n await new Promise<void>((resolve) => wss.close(() => resolve()));\n }\n this.servers.clear();\n }\n}\n\n/**\n * Detect whether the WASM-backed QUIC transport is \"real\" (i.e. it\n * actually moves bytes on the wire) vs the current stub. The stub\n * returns 0ms for connect+send and never increments the server's\n * received-bytes counter. We probe by observing a documented marker\n * on the WASM module: when it's truly wired the loader function\n * `defaultConfig` returns an object whose round-trip through\n * `WasmQuicClient.new` actually opens a UDP socket — failing fast on\n * an OS that blocks UDP outbound (e.g. some sandboxed CI envs).\n *\n * Until the native build lands this returns false; the loader picks\n * WebSocket. When the native binding is wired this returns true and\n * the loader picks real QUIC. Callers get the same API either way.\n */\nasync function isRealQuicAvailable(): Promise<boolean> {\n try {\n // The WASM file is published in `wasm/quic/` of this package. We\n // do NOT use it for federation today (per the wasm.rs note: it's a\n // stub since browsers can't do UDP). When a native binding is added\n // this probe should switch to detect that binding instead.\n const native = process.env.AGENTIC_FLOW_QUIC_NATIVE === '1';\n return native;\n } catch {\n return false;\n }\n}\n\n/**\n * Public API — load a working transport, preferring real QUIC when\n * available, falling back to WebSocket otherwise. The returned object\n * satisfies the AgentTransport interface in both cases.\n *\n * Example:\n * const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });\n * await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });\n *\n * Federation v1 ships on the WebSocket fallback (this is the actual\n * working transport today). When the native QUIC binding lands, set\n * the AGENTIC_FLOW_QUIC_NATIVE=1 environment variable and the same\n * code path picks up the upgrade with no API changes.\n */\nexport async function loadQuicTransport(\n config: QuicTransportConfig = {},\n): Promise<AgentTransport> {\n if (await isRealQuicAvailable()) {\n // Future: wire to the native binding here.\n logger.info('QUIC transport: native binding selected');\n } else {\n if (process.env.NODE_ENV !== 'test') {\n logger.warn(\n 'QUIC native binding not available; using WebSocket fallback. ' +\n 'Set AGENTIC_FLOW_QUIC_NATIVE=1 once a native build is installed.',\n );\n }\n }\n return WebSocketFallbackTransport.create(config);\n}\n\n/** Quick capability probe for the doctor / health surface. */\nexport async function isQuicAvailable(): Promise<boolean> {\n return isRealQuicAvailable();\n}\n\nexport interface TransportCapabilities {\n quicAvailable: boolean;\n webSocketFallbackAvailable: true;\n selectedBackend: 'quic' | 'websocket';\n}\n\nexport async function getTransportCapabilities(): Promise<TransportCapabilities> {\n const quic = await isRealQuicAvailable();\n return {\n quicAvailable: quic,\n webSocketFallbackAvailable: true,\n selectedBackend: quic ? 'quic' : 'websocket',\n };\n}\n\nexport { WebSocketFallbackTransport };\n"]}
|
|
1
|
+
{"version":3,"file":"quic-loader.js","sourceRoot":"","sources":["../../src/transport/quic-loader.ts"],"names":[],"mappings":"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","sourcesContent":["// QUIC Transport Loader with WebSocket fallback\n//\n// Backported from outer repo loader pattern. Exposes a single\n// loadQuicTransport(config) entry point that:\n//\n// 1. Tries to load the WASM-backed QuicClient/QuicServer (real QUIC if a\n// native build is wired in the future).\n// 2. Falls back to WebSocketFallbackTransport when QUIC is unavailable\n// OR when the WASM stub is detected (current state — see\n// crates/agentic-flow-quic/src/wasm.rs comment: WASM build is a stub\n// because browsers can't do raw UDP/QUIC; production QUIC needs\n// native Node.js builds which haven't shipped yet).\n//\n// The fallback uses standard WebSocket (ws://) so it works on all Node\n// versions without complex native dependencies. Same async send/receive\n// API surface as QuicTransport.\n//\n// Federation use case (ruvnet/ruflo ADR-104): two peers on the same\n// tailnet can call loadQuicTransport({ serverName: 'peer.tailnet' }) and\n// exchange signed envelopes today, with zero code change required when\n// the native QUIC build lands later.\n\nimport { logger } from '../utils/logger.js';\nimport WebSocket, { WebSocketServer, type RawData } from 'ws';\nimport { createHash } from 'node:crypto';\nimport { createServer as createHttpsServer } from 'node:https';\nimport { readFileSync } from 'node:fs';\n\n/** TLS configuration for wss:// peers (ADR-107). */\nexport interface TlsConfig {\n /** Path to PEM cert file (server side — bind certs for the listener). */\n certPath?: string;\n /** Path to PEM key file (server side). */\n keyPath?: string;\n /**\n * Pinned `sha256/<base64>` fingerprints of acceptable peer certs\n * (client side — outbound connections).\n *\n * When set, ONLY these exact certs are accepted. CA validation is\n * skipped — the fingerprint IS the trust anchor. Fail-closed: if the\n * peer's cert rotates and the fingerprint doesn't match, the\n * connection is refused (operator must update config + restart).\n *\n * This prevents:\n * - Compromised public CAs issuing rogue certs for our domain\n * - TLS-MITM attacks where the attacker holds a valid cert chain\n */\n pinnedFingerprints?: string[];\n /**\n * Optional CA bundle path for non-pinned mode (e.g. private CA).\n * Used only when `pinnedFingerprints` is empty/unset.\n */\n caPath?: string;\n}\n\n/** Caller-facing config — minimal common surface across both backends. */\nexport interface QuicTransportConfig {\n serverName?: string;\n maxIdleTimeoutMs?: number;\n maxConcurrentStreams?: number;\n enable0Rtt?: boolean;\n /** TLS materials for wss:// listeners + clients (ADR-107). */\n tls?: TlsConfig;\n}\n\nexport interface AgentMessage {\n id: string;\n type: 'task' | 'result' | 'status' | 'coordination' | 'heartbeat' | string;\n payload: unknown;\n metadata?: Record<string, unknown>;\n /**\n * Stream multiplexing identifier. Messages with different streamIds\n * to the same peer are independent — receive queues and onMessage\n * handlers can scope per-stream, eliminating head-of-line blocking\n * for sequential `await` patterns on a single peer connection.\n *\n * Defaults to `'default'` if omitted (backward compat). Common\n * patterns:\n * - One stream per logical request type (`'rpc'`, `'event'`,\n * `'control'`)\n * - One stream per task (`taskId` doubled as streamId)\n * - One stream per priority class (`'high'`, `'normal'`, `'low'`)\n *\n * Would map to native QUIC stream ids if a native binding is ever added.\n */\n streamId?: string | number;\n}\n\n/** Default streamId when caller omits it. Backward-compat sentinel. */\nexport const DEFAULT_STREAM_ID = 'default';\n\n/** Largest WebSocket frame accepted from a peer (federation envelopes are ~100B-10KB). */\nexport const MAX_WS_PAYLOAD_BYTES = 1024 * 1024;\n/** Unconsumed messages kept per (peer, stream) for receive(); oldest dropped beyond this. */\nexport const MAX_QUEUED_PER_STREAM = 1000;\n/** Distinct (peer, stream) queues kept; messages for further new streams are dropped. */\nexport const MAX_QUEUE_STREAMS = 1024;\n\nexport interface PoolStatistics {\n active: number;\n idle: number;\n created: number;\n closed: number;\n}\n\n/** Inbound message handler — called for every received message. */\nexport type InboundMessageHandler = (\n address: string,\n message: AgentMessage,\n) => void | Promise<void>;\n\n/**\n * Per-stream subscription options. Pass to `onMessage` to scope a\n * handler to a specific streamId (only fires for messages with that\n * exact streamId). Omit to receive all streams.\n */\nexport interface OnMessageOptions {\n readonly streamId?: string | number;\n}\n\n/** Common interface both real-QUIC and fallback transports satisfy. */\nexport interface AgentTransport {\n send(address: string, message: AgentMessage): Promise<void>;\n /**\n * Receive the next message from a peer. Optional `streamId` scopes\n * to that stream's queue (independent of other streams to the same\n * peer). Omit to use the default stream — backward-compat behavior.\n */\n receive(address: string, streamId?: string | number): Promise<AgentMessage>;\n request(address: string, message: AgentMessage): Promise<AgentMessage>;\n sendBatch(address: string, messages: AgentMessage[]): Promise<void>;\n getStats(): Promise<PoolStatistics>;\n close(): Promise<void>;\n /**\n * Subscribe to inbound messages. The handler fires for every received\n * message that matches `options.streamId` (if provided) or for every\n * message regardless of streamId (if options omitted).\n *\n * Multiple handlers may be registered (per-stream OR all-streams or\n * a mix). Errors thrown by a handler are logged but do not stop\n * delivery to other handlers.\n *\n * Optional method — implementations that don't support push-style\n * delivery may omit it. Callers should use `transport.onMessage?.(h)`\n * to gracefully degrade.\n */\n onMessage?(handler: InboundMessageHandler, options?: OnMessageOptions): void;\n}\n\n/**\n * WebSocket fallback transport.\n *\n * Spec compliance: implements the AgentTransport interface using\n * `ws://` (or `wss://` if address starts with `wss://`). Each call to\n * `send` lazily opens (or reuses) a connection to `address`. The\n * `receive(address)` call drains the next queued message for that\n * address; if none is queued it polls every 100ms until one arrives.\n *\n * Limits vs real QUIC: no 0-RTT resumption, no multiplexed streams\n * (one TCP connection per peer), TLS handled by the WS layer (use\n * `wss://` for encryption). Performance is \"good enough\" for federation\n * messages at human/agent rates (≤ 100 RPS per peer).\n */\nclass WebSocketFallbackTransport implements AgentTransport {\n private connections = new Map<string, WebSocket>();\n /**\n * Per-(address, streamId) message queue. Composite key shape\n * `${address}#${streamId}` — see {@link queueKey}. Each stream gets\n * its own FIFO so receive(addr, streamA) is independent of\n * receive(addr, streamB) — eliminates head-of-line blocking on a\n * single peer connection.\n */\n private messageQueue = new Map<string, AgentMessage[]>();\n private connectionsCreated = 0;\n private connectionsClosed = 0;\n private servers = new Map<number, WebSocketServer>();\n /**\n * Inbound handlers. Each entry is { handler, streamId? }. When\n * streamId is undefined the handler receives ALL messages\n * regardless of stream; otherwise only messages with the matching\n * streamId. Lets callers register both per-stream + catch-all.\n */\n private inboundHandlers = new Set<{\n handler: InboundMessageHandler;\n streamId?: string | number;\n }>();\n /**\n * Server-accepted (inbound) sockets indexed by peer host (#162). A\n * peer that already dialed us has a live, full-duplex socket here;\n * {@link getOrCreateConnection} reuses it for replies instead of\n * opening a fresh outbound connection — which, on a direct\n * point-to-point link, can hit a per-process stale scoped route\n * (`EHOSTUNREACH`) even while the inbound direction is healthy.\n */\n private inboundByHost = new Map<string, WebSocket>();\n /** Active liveness-probe intervals, cleared on close (#162). */\n private heartbeats = new Set<ReturnType<typeof setInterval>>();\n\n /**\n * Liveness ping cadence, derived from `maxIdleTimeoutMs` (#162 — this\n * config was previously accepted but never used). Pings at 1/6 of the\n * idle timeout so a dead socket is caught within ~1/3 of it. Default\n * 30000ms → 5000ms.\n */\n private get pingIntervalMs(): number {\n return Math.max(1000, Math.floor(this.config.maxIdleTimeoutMs / 6));\n }\n\n /**\n * Normalize an address or socket `remoteAddress` to a bare host key\n * for {@link inboundByHost} lookups. Strips `ws(s)://` scheme, an\n * IPv6-mapped IPv4 prefix (`::ffff:`), bracketed IPv6 (`[::1]:port`),\n * and a trailing `:port` on plain `host:port` forms. Bare IPv6\n * (multiple colons, no brackets) is returned unchanged.\n */\n private hostOf(addr: string): string {\n let s = addr.replace(/^wss?:\\/\\//i, '');\n const bracket = s.match(/^\\[([^\\]]+)\\](?::\\d+)?$/);\n if (bracket) s = bracket[1];\n else if (/^[^:]+:\\d+$/.test(s)) s = s.slice(0, s.lastIndexOf(':'));\n return s.replace(/^::ffff:/i, '');\n }\n\n /**\n * Liveness probe for a socket (#162). Pings on {@link pingIntervalMs};\n * a socket that misses a ping/pong window is terminated so a stale\n * connection can't silently black-hole sends. The interval is unref'd\n * (never keeps the process alive on its own) and cleared on close/error.\n */\n private startHeartbeat(ws: WebSocket): void {\n let alive = true;\n ws.on('pong', () => { alive = true; });\n const interval = setInterval(() => {\n if (!alive) {\n try { ws.terminate(); } catch { /* already gone */ }\n return; // 'close' fires → stop() clears this interval\n }\n alive = false;\n try { ws.ping(); } catch { /* socket is closing */ }\n }, this.pingIntervalMs);\n (interval as { unref?: () => void }).unref?.();\n this.heartbeats.add(interval);\n const stop = () => {\n clearInterval(interval);\n this.heartbeats.delete(interval);\n };\n ws.on('close', stop);\n ws.on('error', stop);\n }\n\n /** Compose the per-(address, streamId) queue key. */\n private queueKey(address: string, streamId: string | number): string {\n return `${address}#${streamId}`;\n }\n\n /** Resolve the streamId for a message — defaults to DEFAULT_STREAM_ID. */\n private streamOf(message: AgentMessage): string | number {\n return message.streamId ?? DEFAULT_STREAM_ID;\n }\n\n constructor(private readonly config: Required<QuicTransportConfig>) {}\n\n static async create(config: QuicTransportConfig = {}): Promise<WebSocketFallbackTransport> {\n const fullConfig: Required<QuicTransportConfig> = {\n serverName: config.serverName ?? 'localhost',\n maxIdleTimeoutMs: config.maxIdleTimeoutMs ?? 30000,\n maxConcurrentStreams: config.maxConcurrentStreams ?? 100,\n // Not applicable for WebSocket — record but ignore\n enable0Rtt: config.enable0Rtt ?? false,\n tls: config.tls ?? {},\n };\n return new WebSocketFallbackTransport(fullConfig);\n }\n\n /**\n * Bind a server-side listener so this transport instance can RECEIVE\n * messages from a remote peer (in addition to sending). Federation\n * peers run BOTH a listener and a client — calling listen(9100) plus\n * send('peer:9100', ...) gives bidirectional connectivity.\n *\n * Enables `permessage-deflate` compression with thresholds chosen\n * for federation envelopes (typically JSON, 100B-10KB):\n * - threshold: 256B — don't waste CPU compressing tiny pings\n * - level: 3 — balanced compression vs CPU (zlib's BEST_SPEED→6 range)\n * - serverNoContextTakeover: true — bound per-conn memory growth\n */\n async listen(port: number, host = '127.0.0.1'): Promise<void> {\n if (this.servers.has(port)) return;\n return new Promise((resolve, reject) => {\n const tls = this.config.tls;\n const wssOpts: ConstructorParameters<typeof WebSocketServer>[0] = {\n maxPayload: MAX_WS_PAYLOAD_BYTES,\n perMessageDeflate: {\n threshold: 256,\n zlibDeflateOptions: { level: 3 },\n serverNoContextTakeover: true,\n clientNoContextTakeover: true,\n },\n };\n // ADR-107: if cert+key paths are configured, bind via https.Server\n // (wss://). Otherwise bind plain ws:// directly.\n if (tls?.certPath && tls?.keyPath) {\n const cert = readFileSync(tls.certPath);\n const key = readFileSync(tls.keyPath);\n const httpsServer = createHttpsServer({ cert, key });\n httpsServer.listen(port, host, () => {\n const wss = new WebSocketServer({ ...wssOpts, server: httpsServer });\n this.attachServerHandlers(wss);\n this.servers.set(port, wss);\n resolve();\n });\n httpsServer.on('error', reject);\n return;\n }\n const wss = new WebSocketServer({ ...wssOpts, port, host });\n wss.on('listening', () => {\n this.servers.set(port, wss);\n resolve();\n });\n wss.on('error', reject);\n this.attachServerHandlers(wss);\n });\n }\n\n /**\n * Wire the server's `connection` and per-socket `message` handlers.\n * Extracted so the wss:// path (where the WebSocketServer is attached\n * to a pre-created https.Server) can share the same logic.\n */\n private attachServerHandlers(wss: WebSocketServer): void {\n wss.on('connection', (ws, req) => {\n const remoteAddr = `${req.socket.remoteAddress}:${req.socket.remotePort}`;\n // #162: register this accepted socket for outbound reuse, and probe\n // it for liveness. Reusing it for replies avoids a fresh (stale-route\n // prone) outbound dial back to the same peer.\n const host = this.hostOf(req.socket.remoteAddress ?? remoteAddr);\n this.inboundByHost.set(host, ws);\n this.startHeartbeat(ws);\n const dropInbound = () => {\n if (this.inboundByHost.get(host) === ws) this.inboundByHost.delete(host);\n };\n ws.on('close', dropInbound);\n ws.on('error', dropInbound);\n\n ws.on('message', (raw: RawData) => {\n try {\n const message = JSON.parse(raw.toString()) as AgentMessage;\n this.deliverInbound(remoteAddr, message);\n } catch (err) {\n logger.warn('Dropped malformed inbound WS message', { remoteAddr, err });\n }\n });\n });\n }\n\n private async getOrCreateConnection(address: string): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const existing = this.connections.get(address);\n if (existing && existing.readyState === WebSocket.OPEN) {\n resolve(existing);\n return;\n }\n\n // #162: prefer an already-open INBOUND socket from the same peer host\n // before dialing. WebSocket is full-duplex, so the server-accepted\n // socket can carry our replies — and the inbound direction stays\n // healthy when a fresh outbound dial would hit a stale scoped route.\n const inbound = this.inboundByHost.get(this.hostOf(address));\n if (inbound && inbound.readyState === WebSocket.OPEN) {\n resolve(inbound);\n return;\n }\n\n const url = address.startsWith('ws://') || address.startsWith('wss://')\n ? address\n : `ws://${address}`;\n\n // ADR-107: cert pinning for wss:// peers. Build the WS options\n // with both compression (perf) and TLS hooks (security).\n const tls = this.config.tls;\n const isWss = url.startsWith('wss://');\n const wsOpts: WebSocket.ClientOptions = {\n maxPayload: MAX_WS_PAYLOAD_BYTES,\n perMessageDeflate: {\n threshold: 256,\n zlibDeflateOptions: { level: 3 },\n serverNoContextTakeover: true,\n clientNoContextTakeover: true,\n },\n };\n\n if (isWss && tls?.pinnedFingerprints && tls.pinnedFingerprints.length > 0) {\n // Fail-closed pinning: ONLY accept the listed cert fingerprints.\n // CA path validation is irrelevant — the fingerprint IS the trust\n // anchor. If the cert rotates, the operator must update config.\n const pinned = new Set(tls.pinnedFingerprints);\n // Cast: ws's `checkServerIdentity` is typed as returning boolean\n // but the underlying `tls.checkServerIdentity` (which it\n // forwards to) accepts `Error | undefined`. The runtime\n // semantics are: throw OR return Error → reject; otherwise accept.\n // The boolean type signature is overly restrictive.\n (wsOpts as unknown as { checkServerIdentity: unknown }).checkServerIdentity = (\n _host: string,\n cert: { raw: Buffer },\n ): Error | undefined => {\n // cert.raw is the DER-encoded cert bytes; sha256/<base64> matches\n // common pinning notation (and what `openssl x509 -fingerprint\n // -sha256` outputs after base64-encoding).\n const fp = `sha256/${createHash('sha256').update(cert.raw).digest('base64')}`;\n if (!pinned.has(fp)) {\n return new Error(\n `Federation TLS: peer cert fingerprint ${fp} not in pinned set ` +\n `(${pinned.size} fingerprint(s) configured)`,\n );\n }\n return undefined; // accept\n };\n // When pinning is on, we explicitly DON'T want CA validation\n // (the fingerprint check above is the real auth). But we also\n // DON'T want to silently accept ANY cert — the checkServerIdentity\n // above is still called.\n wsOpts.rejectUnauthorized = false;\n } else if (isWss && tls?.caPath) {\n // Non-pinned mode: validate against the configured CA bundle.\n wsOpts.ca = readFileSync(tls.caPath);\n wsOpts.rejectUnauthorized = true;\n }\n // (no tls config + ws:// → plain unencrypted; ADR-104 documents\n // tailnet-as-TLS as the recommended path)\n\n const ws = new WebSocket(url, wsOpts);\n\n ws.on('open', () => {\n this.connections.set(address, ws);\n this.connectionsCreated++;\n this.startHeartbeat(ws); // #162: keep the outbound link probed\n resolve(ws);\n });\n\n ws.on('error', (error: Error) => {\n reject(new Error(`WebSocket connection to ${url} failed: ${error.message}`));\n });\n\n ws.on('close', () => {\n this.connectionsClosed++;\n this.connections.delete(address);\n });\n\n ws.on('message', (raw: RawData) => {\n try {\n const message = JSON.parse(raw.toString()) as AgentMessage;\n this.deliverInbound(address, message);\n } catch (err) {\n logger.warn('Dropped malformed WebSocket message', { address, err });\n }\n });\n });\n }\n\n async send(address: string, message: AgentMessage): Promise<void> {\n const ws = await this.getOrCreateConnection(address);\n ws.send(JSON.stringify(message));\n }\n\n /**\n * Register an inbound handler. Optional `options.streamId` scopes\n * the handler to a specific stream (only fires for messages with\n * matching streamId). Omit to subscribe to ALL streams.\n *\n * Patterns:\n * onMessage(h) — receives all\n * onMessage(h, { streamId: 'rpc' }) — receives only rpc\n * onMessage(h, { streamId: 'event' }) — receives only event\n * (both registered) — both fire on\n * their respective streams\n */\n onMessage(handler: InboundMessageHandler, options: OnMessageOptions = {}): void {\n this.inboundHandlers.add({ handler, streamId: options.streamId });\n }\n\n /**\n * Fire all matching handlers for a received message. Stream-scoped\n * handlers only fire when the message's streamId matches; all-stream\n * handlers always fire. Errors thrown sync OR async-rejected by one\n * handler don't stop delivery to others.\n */\n private dispatchInbound(address: string, message: AgentMessage): boolean {\n if (this.inboundHandlers.size === 0) return false;\n const msgStream = this.streamOf(message);\n let delivered = false;\n for (const entry of this.inboundHandlers) {\n // Stream filter: scoped handler only fires on matching streamId\n if (entry.streamId !== undefined && entry.streamId !== msgStream) continue;\n delivered = true;\n try {\n const r = entry.handler(address, message);\n if (r && typeof (r as Promise<void>).catch === 'function') {\n (r as Promise<void>).catch((err) => {\n logger.warn('Inbound handler rejected', { address, err });\n });\n }\n } catch (err) {\n logger.warn('Inbound handler threw', { address, err });\n }\n }\n return delivered;\n }\n\n /**\n * Hand an inbound message to the matching onMessage handlers. Only a\n * message no handler consumed is queued for receive(), and the queues are\n * bounded so a peer cannot grow memory without limit.\n */\n private deliverInbound(address: string, message: AgentMessage): void {\n if (this.dispatchInbound(address, message)) return;\n // Per-stream queue (default stream when message.streamId omitted)\n const key = this.queueKey(address, this.streamOf(message));\n let queue = this.messageQueue.get(key);\n if (!queue) {\n if (this.messageQueue.size >= MAX_QUEUE_STREAMS) {\n logger.warn('Dropped inbound message: too many queued streams', { address, key });\n return;\n }\n queue = [];\n this.messageQueue.set(key, queue);\n }\n queue.push(message);\n if (queue.length > MAX_QUEUED_PER_STREAM) {\n queue.shift();\n logger.warn('Inbound queue full; dropped oldest message', { address, key });\n }\n }\n\n /** Shift the head of a queue, dropping the queue once empty so stream keys don't accumulate. */\n private takeFrom(key: string, queue: AgentMessage[]): AgentMessage {\n const message = queue.shift()!;\n if (queue.length === 0) this.messageQueue.delete(key);\n return message;\n }\n\n /** Messages waiting for receive(), across all peers and streams. */\n queuedMessageCount(): number {\n let total = 0;\n for (const queue of this.messageQueue.values()) total += queue.length;\n return total;\n }\n\n async receive(address: string, streamId: string | number = DEFAULT_STREAM_ID): Promise<AgentMessage> {\n const key = this.queueKey(address, streamId);\n // Fast path\n const queue = this.messageQueue.get(key) ?? [];\n if (queue.length > 0) return this.takeFrom(key, queue);\n\n // Poll (caller must time out externally if they don't want to wait)\n return new Promise((resolve) => {\n const interval = setInterval(() => {\n const q = this.messageQueue.get(key) ?? [];\n if (q.length > 0) {\n clearInterval(interval);\n resolve(this.takeFrom(key, q));\n }\n }, 100);\n });\n }\n\n async request(address: string, message: AgentMessage): Promise<AgentMessage> {\n await this.send(address, message);\n return this.receive(address);\n }\n\n async sendBatch(address: string, messages: AgentMessage[]): Promise<void> {\n await Promise.all(messages.map((m) => this.send(address, m)));\n }\n\n async getStats(): Promise<PoolStatistics> {\n return {\n active: this.connections.size,\n idle: 0,\n created: this.connectionsCreated,\n closed: this.connectionsClosed,\n };\n }\n\n async close(): Promise<void> {\n // Outbound clients first.\n for (const ws of this.connections.values()) {\n ws.terminate();\n }\n this.connections.clear();\n this.messageQueue.clear();\n\n // Stop all liveness probes and drop the inbound index (#162).\n for (const interval of this.heartbeats) clearInterval(interval);\n this.heartbeats.clear();\n this.inboundByHost.clear();\n\n // Inbound: WebSocketServer.close() blocks until every accepted\n // socket disconnects. Forcibly terminate them so the close\n // callback fires within the test/CI timeout window.\n for (const wss of this.servers.values()) {\n for (const client of wss.clients) {\n try {\n client.terminate();\n } catch {\n /* socket already gone */\n }\n }\n await new Promise<void>((resolve) => wss.close(() => resolve()));\n }\n this.servers.clear();\n }\n}\n\n/**\n * Why real QUIC is not available in npm builds of agentic-flow.\n *\n * - No native (N-API) QUIC binding exists. The quinn-based client/server in\n * `crates/agentic-flow-quic` has no Node bindings and no build/publish\n * pipeline, so nothing native ships in the tarball.\n * - `wasm/quic/` is a browser build of that crate with quinn/tokio compiled\n * out (browsers cannot open UDP sockets). It cannot move QUIC packets.\n * - `agentic-flow/transport/quic` (QuicClient/QuicServer/QuicTransport) is a\n * placeholder API that does not transmit bytes.\n *\n * The working transport is the WebSocket fallback returned by\n * {@link loadQuicTransport}.\n */\nexport const QUIC_UNAVAILABLE_REASON =\n 'No native QUIC binding is published for agentic-flow: the quinn-based ' +\n 'crates/agentic-flow-quic has no N-API build, wasm/quic is a browser stub ' +\n 'without UDP, and agentic-flow/transport/quic is a placeholder that sends ' +\n 'no bytes. loadQuicTransport() uses the WebSocket fallback.';\n\n/** Honest status for the QUIC backend. */\nexport interface QuicStatus {\n available: boolean;\n /** Present when available is false. */\n reason?: string;\n /** The transport loadQuicTransport() actually returns. */\n fallback: 'websocket';\n}\n\n/**\n * Real QUIC is available only when a native binding has been loaded. None\n * is published, so this is always false. Earlier releases returned true when\n * AGENTIC_FLOW_QUIC_NATIVE=1 was set, even though the loader still returned\n * the WebSocket transport. That variable is now ignored.\n */\nasync function isRealQuicAvailable(): Promise<boolean> {\n return false;\n}\n\n/**\n * Public API — load a working transport. Real QUIC is not available in npm\n * builds (see {@link QUIC_UNAVAILABLE_REASON}), so this returns the WebSocket\n * fallback, which satisfies the AgentTransport interface.\n *\n * Example:\n * const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });\n * await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });\n */\nexport async function loadQuicTransport(\n config: QuicTransportConfig = {},\n): Promise<AgentTransport> {\n if (process.env.NODE_ENV !== 'test') {\n logger.warn('QUIC unavailable; using WebSocket fallback. ' + QUIC_UNAVAILABLE_REASON);\n }\n return WebSocketFallbackTransport.create(config);\n}\n\n/** Quick capability probe for the doctor / health surface. */\nexport async function isQuicAvailable(): Promise<boolean> {\n return isRealQuicAvailable();\n}\n\n/** Availability plus the reason when QUIC is unavailable. */\nexport async function getQuicStatus(): Promise<QuicStatus> {\n const available = await isRealQuicAvailable();\n return available\n ? { available, fallback: 'websocket' }\n : { available, reason: QUIC_UNAVAILABLE_REASON, fallback: 'websocket' };\n}\n\nexport interface TransportCapabilities {\n quicAvailable: boolean;\n /** Why QUIC is unavailable; present when quicAvailable is false. */\n quicUnavailableReason?: string;\n webSocketFallbackAvailable: true;\n selectedBackend: 'quic' | 'websocket';\n}\n\nexport async function getTransportCapabilities(): Promise<TransportCapabilities> {\n const quic = await isRealQuicAvailable();\n return {\n quicAvailable: quic,\n ...(quic ? {} : { quicUnavailableReason: QUIC_UNAVAILABLE_REASON }),\n webSocketFallbackAvailable: true,\n selectedBackend: quic ? 'quic' : 'websocket',\n };\n}\n\nexport { WebSocketFallbackTransport };\n"]}
|
package/dist/transport/quic.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quic.d.ts","sourceRoot":"","sources":["../../src/transport/quic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"quic.d.ts","sourceRoot":"","sources":["../../src/transport/quic.ts"],"names":[],"mappings":"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"}
|
package/dist/transport/quic.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// QUIC Transport Layer for Agentic Flow
|
|
2
|
-
//
|
|
2
|
+
//
|
|
3
|
+
// PLACEHOLDER API: QuicClient, QuicServer and QuicTransport do not open UDP
|
|
4
|
+
// sockets or transmit bytes. No native QUIC binding is published for
|
|
5
|
+
// agentic-flow, and wasm/quic is a browser stub without UDP. Probe with
|
|
6
|
+
// isQuicAvailable() / getQuicStatus() (re-exported below); for a transport
|
|
7
|
+
// that moves bytes use loadQuicTransport() from 'agentic-flow/transport/loader'.
|
|
3
8
|
import { logger } from '../utils/logger.js';
|
|
9
|
+
import { QUIC_UNAVAILABLE_REASON } from './quic-loader.js';
|
|
10
|
+
export { isQuicAvailable, getQuicStatus, QUIC_UNAVAILABLE_REASON, } from './quic-loader.js';
|
|
4
11
|
/**
|
|
5
12
|
* QUIC Client - Manages outbound QUIC connections and stream multiplexing
|
|
6
13
|
*/
|
|
@@ -46,6 +53,7 @@ export class QuicClient {
|
|
|
46
53
|
});
|
|
47
54
|
// Load WASM module (implementation depends on WASM binding)
|
|
48
55
|
// For now, this is a placeholder for the actual WASM loading
|
|
56
|
+
logger.warn('agentic-flow/transport/quic is a placeholder; no QUIC packets are sent. ' + QUIC_UNAVAILABLE_REASON);
|
|
49
57
|
this.wasmModule = await this.loadWasmModule();
|
|
50
58
|
this.initialized = true;
|
|
51
59
|
logger.info('QUIC client initialized successfully');
|
|
@@ -265,6 +273,7 @@ export class QuicServer {
|
|
|
265
273
|
certPath: this.config.certPath
|
|
266
274
|
});
|
|
267
275
|
// Load WASM module
|
|
276
|
+
logger.warn('agentic-flow/transport/quic is a placeholder; no QUIC packets are sent. ' + QUIC_UNAVAILABLE_REASON);
|
|
268
277
|
this.wasmModule = await this.loadWasmModule();
|
|
269
278
|
this.initialized = true;
|
|
270
279
|
logger.info('QUIC server initialized successfully');
|