@query-farm/vgi-rpc 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.core.d.ts +1 -0
- package/dist/index.core.d.ts.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +5 -4
- package/dist/serve-stream.d.ts +23 -0
- package/dist/serve-stream.d.ts.map +1 -0
- package/dist/server.d.ts +18 -2
- package/dist/server.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.core.ts +1 -0
- package/src/serve-stream.ts +38 -0
- package/src/server.ts +31 -10
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Socket } from "node:net";
|
|
2
|
+
import type { Protocol } from "./protocol.js";
|
|
3
|
+
import { VgiRpcServer } from "./server.js";
|
|
4
|
+
import { TransportKind } from "./types.js";
|
|
5
|
+
export interface ServeStreamOptions {
|
|
6
|
+
/** Incoming request bytes — a web `ReadableStream<Uint8Array>` or a Node
|
|
7
|
+
* `Readable` (e.g. a `Duplex` bridging a MessagePort). */
|
|
8
|
+
readable: ReadableStream<Uint8Array> | NodeJS.ReadableStream;
|
|
9
|
+
/** Outgoing response sink — a stdout-like fd number, or a `net.Socket` /
|
|
10
|
+
* structurally-compatible `Duplex`. Omit for the stdout fd. */
|
|
11
|
+
writable?: number | Socket;
|
|
12
|
+
/** Passed through to the `VgiRpcServer` constructor (describe, hooks, …). */
|
|
13
|
+
serverOptions?: ConstructorParameters<typeof VgiRpcServer>[1];
|
|
14
|
+
/** Reported to the `on_serve_start` hook. Defaults to `PIPE`. */
|
|
15
|
+
transportKind?: TransportKind;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Serve `protocol` over the provided `readable`/`writable` until the readable
|
|
19
|
+
* ends. Thin wrapper over {@link VgiRpcServer.serveConnection}. Resolves on
|
|
20
|
+
* clean EOF; rejects on a real protocol/transport error.
|
|
21
|
+
*/
|
|
22
|
+
export declare function serveStream(protocol: Protocol, options: ServeStreamOptions): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=serve-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-stream.d.ts","sourceRoot":"","sources":["../src/serve-stream.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,kBAAkB;IACjC;+DAC2D;IAC3D,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC;IAC7D;oEACgE;IAChE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,qBAAqB,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,iEAAiE;IACjE,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExternalLocationConfig } from "./external.js";
|
|
2
2
|
import type { Protocol } from "./protocol.js";
|
|
3
|
-
import { type DispatchHook, type ServeStartHook } from "./types.js";
|
|
3
|
+
import { type DispatchHook, type ServeStartHook, TransportKind } from "./types.js";
|
|
4
4
|
/**
|
|
5
5
|
* RPC server that reads Arrow IPC requests from stdin and writes responses to stdout.
|
|
6
6
|
* Supports unary and streaming (producer/exchange) methods.
|
|
@@ -39,8 +39,24 @@ export declare class VgiRpcServer {
|
|
|
39
39
|
* `RpcServer._check_protocol_version`: exact major+minor match, patch
|
|
40
40
|
* ignored; directional error message names which side is older. */
|
|
41
41
|
private checkProtocolVersion;
|
|
42
|
-
/** Start the server loop. Reads requests until stdin closes. */
|
|
42
|
+
/** Start the server loop over stdin/stdout. Reads requests until stdin closes. */
|
|
43
43
|
run(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Serve requests over an explicit byte-stream pair until the readable ends —
|
|
46
|
+
* the transport-agnostic core that {@link run} (stdin/stdout) is built on.
|
|
47
|
+
*
|
|
48
|
+
* Use this to serve over any duplex channel that the stdio/unix/tcp helpers
|
|
49
|
+
* don't cover: a Web Worker / `MessagePort` bridge, an in-memory pipe, or a
|
|
50
|
+
* pre-connected socket. The loop, on_serve_start firing, and EOF/broken-pipe
|
|
51
|
+
* handling are identical to {@link run}.
|
|
52
|
+
*
|
|
53
|
+
* @param readable incoming request bytes — a web `ReadableStream<Uint8Array>`
|
|
54
|
+
* or a Node `Readable` (e.g. a `Duplex` bridging a MessagePort).
|
|
55
|
+
* @param writable outgoing response sink — a stdout-like fd number, or a
|
|
56
|
+
* `net.Socket` / structurally-compatible `Duplex`. Omit for the stdout fd.
|
|
57
|
+
* @param transportKind reported to the `on_serve_start` hook (default `PIPE`).
|
|
58
|
+
*/
|
|
59
|
+
serveConnection(readable: ReadableStream<Uint8Array> | NodeJS.ReadableStream, writable?: number | import("node:net").Socket, transportKind?: TransportKind): Promise<void>;
|
|
44
60
|
private serveOne;
|
|
45
61
|
}
|
|
46
62
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAEL,KAAK,YAAY,EAGjB,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAEL,KAAK,YAAY,EAGjB,KAAK,cAAc,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AAkBpB;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,QAAQ,CAAS;IAIzB,OAAO,CAAC,gBAAgB,CAGP;IACjB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,cAAc,CAAqC;IAC3D,OAAO,CAAC,YAAY,CAA+B;IACnD;;;0EAGsE;IACtE,OAAO,CAAC,eAAe,CAAS;gBAG9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,YAAY,CAAC;QAC5B,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;QAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,qEAAqE;QACrE,YAAY,CAAC,EAAE,cAAc,CAAC;KAC/B;IAWH;yEACqE;YACvD,eAAe;IAQ7B,iEAAiE;YACnD,YAAY;IAkB1B;;;;wEAIoE;IACpE,OAAO,CAAC,oBAAoB;IAyC5B,kFAAkF;IAC5E,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAe1B;;;;;;;;;;;;;;OAcG;IACG,eAAe,CACnB,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,cAAc,EAC5D,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,UAAU,EAAE,MAAM,EAC7C,aAAa,GAAE,aAAkC,GAChD,OAAO,CAAC,IAAI,CAAC;YAgCF,QAAQ;CA2IvB"}
|
package/package.json
CHANGED
package/src/index.core.ts
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// © Copyright 2025-2026, Query.Farm LLC - https://query.farm
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
//! Serve a protocol over a caller-provided byte-stream pair — the stream
|
|
5
|
+
//! sibling of `serveTcp` / `serveUnix`, with no socket/listener of its own.
|
|
6
|
+
//!
|
|
7
|
+
//! Useful for transports the launcher helpers don't cover: a Web Worker /
|
|
8
|
+
//! `MessagePort` bridge (postMessage), an in-memory pipe, or a pre-connected
|
|
9
|
+
//! socket. The host side already has this symmetry via `pipeConnect`.
|
|
10
|
+
|
|
11
|
+
import type { Socket } from "node:net";
|
|
12
|
+
|
|
13
|
+
import type { Protocol } from "./protocol.js";
|
|
14
|
+
import { VgiRpcServer } from "./server.js";
|
|
15
|
+
import { TransportKind } from "./types.js";
|
|
16
|
+
|
|
17
|
+
export interface ServeStreamOptions {
|
|
18
|
+
/** Incoming request bytes — a web `ReadableStream<Uint8Array>` or a Node
|
|
19
|
+
* `Readable` (e.g. a `Duplex` bridging a MessagePort). */
|
|
20
|
+
readable: ReadableStream<Uint8Array> | NodeJS.ReadableStream;
|
|
21
|
+
/** Outgoing response sink — a stdout-like fd number, or a `net.Socket` /
|
|
22
|
+
* structurally-compatible `Duplex`. Omit for the stdout fd. */
|
|
23
|
+
writable?: number | Socket;
|
|
24
|
+
/** Passed through to the `VgiRpcServer` constructor (describe, hooks, …). */
|
|
25
|
+
serverOptions?: ConstructorParameters<typeof VgiRpcServer>[1];
|
|
26
|
+
/** Reported to the `on_serve_start` hook. Defaults to `PIPE`. */
|
|
27
|
+
transportKind?: TransportKind;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Serve `protocol` over the provided `readable`/`writable` until the readable
|
|
32
|
+
* ends. Thin wrapper over {@link VgiRpcServer.serveConnection}. Resolves on
|
|
33
|
+
* clean EOF; rejects on a real protocol/transport error.
|
|
34
|
+
*/
|
|
35
|
+
export async function serveStream(protocol: Protocol, options: ServeStreamOptions): Promise<void> {
|
|
36
|
+
const server = new VgiRpcServer(protocol, options.serverOptions);
|
|
37
|
+
await server.serveConnection(options.readable, options.writable, options.transportKind);
|
|
38
|
+
}
|
package/src/server.ts
CHANGED
|
@@ -161,10 +161,8 @@ export class VgiRpcServer {
|
|
|
161
161
|
);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
/** Start the server loop. Reads requests until stdin closes. */
|
|
164
|
+
/** Start the server loop over stdin/stdout. Reads requests until stdin closes. */
|
|
165
165
|
async run(): Promise<void> {
|
|
166
|
-
const stdin = process.stdin as unknown as ReadableStream<Uint8Array>;
|
|
167
|
-
|
|
168
166
|
// Warn if running interactively
|
|
169
167
|
if (process.stdin.isTTY || process.stdout.isTTY) {
|
|
170
168
|
process.stderr.write(
|
|
@@ -174,21 +172,44 @@ export class VgiRpcServer {
|
|
|
174
172
|
"(e.g. vgi_rpc.connect()).\n",
|
|
175
173
|
);
|
|
176
174
|
}
|
|
175
|
+
const stdin = process.stdin as unknown as ReadableStream<Uint8Array>;
|
|
176
|
+
// writable omitted → IpcStreamWriter defaults to the stdout fd.
|
|
177
|
+
await this.serveConnection(stdin);
|
|
178
|
+
}
|
|
177
179
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Serve requests over an explicit byte-stream pair until the readable ends —
|
|
182
|
+
* the transport-agnostic core that {@link run} (stdin/stdout) is built on.
|
|
183
|
+
*
|
|
184
|
+
* Use this to serve over any duplex channel that the stdio/unix/tcp helpers
|
|
185
|
+
* don't cover: a Web Worker / `MessagePort` bridge, an in-memory pipe, or a
|
|
186
|
+
* pre-connected socket. The loop, on_serve_start firing, and EOF/broken-pipe
|
|
187
|
+
* handling are identical to {@link run}.
|
|
188
|
+
*
|
|
189
|
+
* @param readable incoming request bytes — a web `ReadableStream<Uint8Array>`
|
|
190
|
+
* or a Node `Readable` (e.g. a `Duplex` bridging a MessagePort).
|
|
191
|
+
* @param writable outgoing response sink — a stdout-like fd number, or a
|
|
192
|
+
* `net.Socket` / structurally-compatible `Duplex`. Omit for the stdout fd.
|
|
193
|
+
* @param transportKind reported to the `on_serve_start` hook (default `PIPE`).
|
|
194
|
+
*/
|
|
195
|
+
async serveConnection(
|
|
196
|
+
readable: ReadableStream<Uint8Array> | NodeJS.ReadableStream,
|
|
197
|
+
writable?: number | import("node:net").Socket,
|
|
198
|
+
transportKind: TransportKind = TransportKind.PIPE,
|
|
199
|
+
): Promise<void> {
|
|
200
|
+
const reader = await IpcStreamReader.create(readable);
|
|
201
|
+
const writer = new IpcStreamWriter(writable);
|
|
180
202
|
|
|
181
203
|
try {
|
|
182
204
|
while (true) {
|
|
183
|
-
// Fire on_serve_start lazily so the hook can do work that
|
|
184
|
-
//
|
|
185
|
-
// it inside serve()). Inside the loop so a failure on the very
|
|
205
|
+
// Fire on_serve_start lazily so the hook can do work that depends on
|
|
206
|
+
// the transport binding. Inside the loop so a failure on the very
|
|
186
207
|
// first request can be retried.
|
|
187
|
-
await this.notifyTransport(
|
|
208
|
+
await this.notifyTransport(transportKind);
|
|
188
209
|
await this.serveOne(reader, writer);
|
|
189
210
|
}
|
|
190
211
|
} catch (e: any) {
|
|
191
|
-
// EOF or broken pipe → clean exit
|
|
212
|
+
// EOF or broken pipe / closed channel → clean exit
|
|
192
213
|
if (
|
|
193
214
|
e.message?.includes("closed") ||
|
|
194
215
|
e.message?.includes("Expected Schema Message") ||
|