@procwire/bun-client 1.0.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/client.d.ts +153 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +423 -0
- package/dist/client.js.map +1 -0
- package/dist/drain-waiter.d.ts +74 -0
- package/dist/drain-waiter.d.ts.map +1 -0
- package/dist/drain-waiter.js +108 -0
- package/dist/drain-waiter.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/request-context.d.ts +57 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +128 -0
- package/dist/request-context.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client class - Child-side API for Procwire IPC.
|
|
3
|
+
*
|
|
4
|
+
* This is the Bun.js optimized version using Bun.listen() for named pipe server.
|
|
5
|
+
*
|
|
6
|
+
* RESPONSIBILITIES:
|
|
7
|
+
* - Register method handlers
|
|
8
|
+
* - Register events
|
|
9
|
+
* - Create named pipe server
|
|
10
|
+
* - Send $init to parent
|
|
11
|
+
* - Handle incoming requests
|
|
12
|
+
* - Emit events to parent
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { EventEmitter } from "node:events";
|
|
17
|
+
import type { MethodDefinition, EventDefinition, MethodHandler, ClientOptions } from "./types.js";
|
|
18
|
+
import { BunDrainWaiter } from "./drain-waiter.js";
|
|
19
|
+
type BunSocket = Awaited<ReturnType<typeof Bun.connect>>;
|
|
20
|
+
/**
|
|
21
|
+
* Client - Child-side API for Procwire IPC.
|
|
22
|
+
*
|
|
23
|
+
* This is the Bun.js optimized version.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const client = new Client()
|
|
28
|
+
* .handle('query', async (data, ctx) => {
|
|
29
|
+
* const results = await search(data);
|
|
30
|
+
* ctx.respond(results);
|
|
31
|
+
* })
|
|
32
|
+
* .handle('insert', async (data, ctx) => {
|
|
33
|
+
* ctx.ack({ accepted: true });
|
|
34
|
+
* await processInBackground(data);
|
|
35
|
+
* })
|
|
36
|
+
* .event('progress');
|
|
37
|
+
*
|
|
38
|
+
* await client.start();
|
|
39
|
+
*
|
|
40
|
+
* // Emit events to parent
|
|
41
|
+
* client.emitEvent('progress', { percent: 50 });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class Client extends EventEmitter {
|
|
45
|
+
private _defaultCodec;
|
|
46
|
+
private _methods;
|
|
47
|
+
private _events;
|
|
48
|
+
private _server;
|
|
49
|
+
private _socket;
|
|
50
|
+
private _frameBuffer;
|
|
51
|
+
private _methodNameToId;
|
|
52
|
+
private _methodIdToName;
|
|
53
|
+
private _eventNameToId;
|
|
54
|
+
private _abortCallbacks;
|
|
55
|
+
private _activeContexts;
|
|
56
|
+
private _started;
|
|
57
|
+
private readonly _headerPool;
|
|
58
|
+
private _headerPoolIndex;
|
|
59
|
+
private _drainWaiter;
|
|
60
|
+
constructor(options?: ClientOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Register a method handler.
|
|
63
|
+
*
|
|
64
|
+
* @param method - Method name
|
|
65
|
+
* @param handler - Handler function
|
|
66
|
+
* @param options - Method configuration
|
|
67
|
+
* @returns this for chaining
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* client.handle('query', async (data, ctx) => {
|
|
72
|
+
* ctx.respond({ results: [] });
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
handle<TData = unknown>(method: string, handler: MethodHandler<TData>, options?: Partial<MethodDefinition>): this;
|
|
77
|
+
/**
|
|
78
|
+
* Register an event that can be emitted to parent.
|
|
79
|
+
*
|
|
80
|
+
* @param name - Event name
|
|
81
|
+
* @param options - Event configuration
|
|
82
|
+
* @returns this for chaining
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* client.event('progress');
|
|
87
|
+
* client.event('status', { codec: arrowCodec });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
event(name: string, options?: Partial<EventDefinition>): this;
|
|
91
|
+
/**
|
|
92
|
+
* Start the client.
|
|
93
|
+
*
|
|
94
|
+
* Creates named pipe server using Bun.listen(), waits for server to be ready,
|
|
95
|
+
* then sends $init to parent.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* await client.start();
|
|
100
|
+
* // Client is now ready to receive requests
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
start(): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Emit an event to parent.
|
|
106
|
+
*
|
|
107
|
+
* @param eventName - Event name (must be registered with .event())
|
|
108
|
+
* @param data - Event data
|
|
109
|
+
* @returns Promise that resolves when the event has been written
|
|
110
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* await client.emitEvent('progress', { percent: 50 });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
emitEvent(eventName: string, data: unknown): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Graceful shutdown.
|
|
120
|
+
*/
|
|
121
|
+
shutdown(): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Whether client is connected to parent.
|
|
124
|
+
*/
|
|
125
|
+
get connected(): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* @internal Acquire a header buffer from the ring pool.
|
|
128
|
+
*/
|
|
129
|
+
_acquireHeaderBuffer(): Buffer;
|
|
130
|
+
/**
|
|
131
|
+
* @internal Get the drain waiter instance.
|
|
132
|
+
*/
|
|
133
|
+
_getDrainWaiter(): BunDrainWaiter | null;
|
|
134
|
+
/**
|
|
135
|
+
* @internal Get the socket instance.
|
|
136
|
+
*/
|
|
137
|
+
_getSocket(): BunSocket | null;
|
|
138
|
+
private _generatePipePath;
|
|
139
|
+
private _createPipeServer;
|
|
140
|
+
private _sendInit;
|
|
141
|
+
private _handleFrame;
|
|
142
|
+
private _handleAbort;
|
|
143
|
+
private _sendErrorResponse;
|
|
144
|
+
/**
|
|
145
|
+
* Send a frame with proper backpressure handling.
|
|
146
|
+
* Used for emitting events to parent.
|
|
147
|
+
*
|
|
148
|
+
* Bun sockets don't have cork/uncork, so we concatenate buffers.
|
|
149
|
+
*/
|
|
150
|
+
private _sendFrame;
|
|
151
|
+
}
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGlG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAInD,KAAK,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,MAAO,SAAQ,YAAY;IACtC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAwE;IACxF,OAAO,CAAC,OAAO,CAAsC;IAErD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,YAAY,CAA4B;IAEhD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,eAAe,CAAsC;IAC7D,OAAO,CAAC,eAAe,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAE1B;IACF,OAAO,CAAC,gBAAgB,CAAK;IAG7B,OAAO,CAAC,YAAY,CAA+B;gBAEvC,OAAO,CAAC,EAAE,aAAa;IASnC;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,KAAK,GAAG,OAAO,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAC7B,OAAO,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAClC,IAAI;IAiBP;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAY7D;;;;;;;;;;;OAWG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B5B;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBhE;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAMD;;OAEG;IACH,oBAAoB,IAAI,MAAM;IAM9B;;OAEG;IACH,eAAe,IAAI,cAAc,GAAG,IAAI;IAIxC;;OAEG;IACH,UAAU,IAAI,SAAS,GAAG,IAAI;IAQ9B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,iBAAiB;IA2CzB,OAAO,CAAC,SAAS;IAqCjB,OAAO,CAAC,YAAY;IAyEpB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,kBAAkB;IAsB1B;;;;;OAKG;YACW,UAAU;CA6BzB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client class - Child-side API for Procwire IPC.
|
|
3
|
+
*
|
|
4
|
+
* This is the Bun.js optimized version using Bun.listen() for named pipe server.
|
|
5
|
+
*
|
|
6
|
+
* RESPONSIBILITIES:
|
|
7
|
+
* - Register method handlers
|
|
8
|
+
* - Register events
|
|
9
|
+
* - Create named pipe server
|
|
10
|
+
* - Send $init to parent
|
|
11
|
+
* - Handle incoming requests
|
|
12
|
+
* - Emit events to parent
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { EventEmitter } from "node:events";
|
|
17
|
+
import { FrameBuffer, Flags, encodeHeaderInto, HEADER_SIZE, HEADER_POOL_SIZE, ABORT_METHOD_ID, } from "@procwire/protocol";
|
|
18
|
+
import { msgpackCodec, codecDeserialize } from "@procwire/codecs";
|
|
19
|
+
import { RequestContextImpl } from "./request-context.js";
|
|
20
|
+
import { ClientErrors } from "./errors.js";
|
|
21
|
+
import { BunDrainWaiter } from "./drain-waiter.js";
|
|
22
|
+
/**
|
|
23
|
+
* Client - Child-side API for Procwire IPC.
|
|
24
|
+
*
|
|
25
|
+
* This is the Bun.js optimized version.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const client = new Client()
|
|
30
|
+
* .handle('query', async (data, ctx) => {
|
|
31
|
+
* const results = await search(data);
|
|
32
|
+
* ctx.respond(results);
|
|
33
|
+
* })
|
|
34
|
+
* .handle('insert', async (data, ctx) => {
|
|
35
|
+
* ctx.ack({ accepted: true });
|
|
36
|
+
* await processInBackground(data);
|
|
37
|
+
* })
|
|
38
|
+
* .event('progress');
|
|
39
|
+
*
|
|
40
|
+
* await client.start();
|
|
41
|
+
*
|
|
42
|
+
* // Emit events to parent
|
|
43
|
+
* client.emitEvent('progress', { percent: 50 });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class Client extends EventEmitter {
|
|
47
|
+
_defaultCodec;
|
|
48
|
+
_methods = new Map();
|
|
49
|
+
_events = new Map();
|
|
50
|
+
_server = null;
|
|
51
|
+
_socket = null;
|
|
52
|
+
_frameBuffer = null;
|
|
53
|
+
_methodNameToId = new Map();
|
|
54
|
+
_methodIdToName = new Map();
|
|
55
|
+
_eventNameToId = new Map();
|
|
56
|
+
_abortCallbacks = new Map();
|
|
57
|
+
_activeContexts = new Map();
|
|
58
|
+
_started = false;
|
|
59
|
+
// Ring buffer for headers (OPT-02: allocation-free sends)
|
|
60
|
+
_headerPool = Array.from({ length: HEADER_POOL_SIZE }, () => Buffer.allocUnsafe(HEADER_SIZE));
|
|
61
|
+
_headerPoolIndex = 0;
|
|
62
|
+
// OPT-04: Backpressure tracking via BunDrainWaiter
|
|
63
|
+
_drainWaiter = null;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
super();
|
|
66
|
+
this._defaultCodec = options?.defaultCodec ?? msgpackCodec;
|
|
67
|
+
}
|
|
68
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
69
|
+
// BUILDER API
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
71
|
+
/**
|
|
72
|
+
* Register a method handler.
|
|
73
|
+
*
|
|
74
|
+
* @param method - Method name
|
|
75
|
+
* @param handler - Handler function
|
|
76
|
+
* @param options - Method configuration
|
|
77
|
+
* @returns this for chaining
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* client.handle('query', async (data, ctx) => {
|
|
82
|
+
* ctx.respond({ results: [] });
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
handle(method, handler, options) {
|
|
87
|
+
if (this._started) {
|
|
88
|
+
throw ClientErrors.cannotAddHandlerAfterStart();
|
|
89
|
+
}
|
|
90
|
+
this._methods.set(method, {
|
|
91
|
+
def: {
|
|
92
|
+
response: options?.response ?? "result",
|
|
93
|
+
codec: options?.codec ?? this._defaultCodec,
|
|
94
|
+
cancellable: options?.cancellable ?? false,
|
|
95
|
+
},
|
|
96
|
+
handler: handler,
|
|
97
|
+
});
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Register an event that can be emitted to parent.
|
|
102
|
+
*
|
|
103
|
+
* @param name - Event name
|
|
104
|
+
* @param options - Event configuration
|
|
105
|
+
* @returns this for chaining
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* client.event('progress');
|
|
110
|
+
* client.event('status', { codec: arrowCodec });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
event(name, options) {
|
|
114
|
+
if (this._started) {
|
|
115
|
+
throw ClientErrors.cannotAddEventAfterStart();
|
|
116
|
+
}
|
|
117
|
+
this._events.set(name, {
|
|
118
|
+
codec: options?.codec ?? this._defaultCodec,
|
|
119
|
+
});
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Start the client.
|
|
124
|
+
*
|
|
125
|
+
* Creates named pipe server using Bun.listen(), waits for server to be ready,
|
|
126
|
+
* then sends $init to parent.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* await client.start();
|
|
131
|
+
* // Client is now ready to receive requests
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
async start() {
|
|
135
|
+
if (this._started) {
|
|
136
|
+
throw ClientErrors.alreadyStarted();
|
|
137
|
+
}
|
|
138
|
+
this._started = true;
|
|
139
|
+
// Assign IDs to methods and events
|
|
140
|
+
let methodId = 1;
|
|
141
|
+
for (const name of this._methods.keys()) {
|
|
142
|
+
this._methodNameToId.set(name, methodId);
|
|
143
|
+
this._methodIdToName.set(methodId, name);
|
|
144
|
+
methodId++;
|
|
145
|
+
}
|
|
146
|
+
let eventId = 1;
|
|
147
|
+
for (const name of this._events.keys()) {
|
|
148
|
+
this._eventNameToId.set(name, eventId);
|
|
149
|
+
eventId++;
|
|
150
|
+
}
|
|
151
|
+
// Create pipe path
|
|
152
|
+
const pipePath = this._generatePipePath();
|
|
153
|
+
// Create server and wait for listen
|
|
154
|
+
await this._createPipeServer(pipePath);
|
|
155
|
+
// Send $init to parent (via stdout, JSON-RPC control plane)
|
|
156
|
+
this._sendInit(pipePath);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Emit an event to parent.
|
|
160
|
+
*
|
|
161
|
+
* @param eventName - Event name (must be registered with .event())
|
|
162
|
+
* @param data - Event data
|
|
163
|
+
* @returns Promise that resolves when the event has been written
|
|
164
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* await client.emitEvent('progress', { percent: 50 });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
async emitEvent(eventName, data) {
|
|
172
|
+
if (!this._socket) {
|
|
173
|
+
throw ClientErrors.notConnected();
|
|
174
|
+
}
|
|
175
|
+
const eventId = this._eventNameToId.get(eventName);
|
|
176
|
+
if (eventId === undefined) {
|
|
177
|
+
throw ClientErrors.unknownEvent(eventName);
|
|
178
|
+
}
|
|
179
|
+
const eventDef = this._events.get(eventName);
|
|
180
|
+
const codec = eventDef.codec ?? this._defaultCodec;
|
|
181
|
+
await this._sendFrame(eventId, 0, data, codec, Flags.DIRECTION_TO_PARENT);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Graceful shutdown.
|
|
185
|
+
*/
|
|
186
|
+
async shutdown() {
|
|
187
|
+
this._socket?.end();
|
|
188
|
+
this._server?.stop(true);
|
|
189
|
+
this._drainWaiter?.clear();
|
|
190
|
+
this._socket = null;
|
|
191
|
+
this._server = null;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Whether client is connected to parent.
|
|
195
|
+
*/
|
|
196
|
+
get connected() {
|
|
197
|
+
return this._socket !== null;
|
|
198
|
+
}
|
|
199
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
200
|
+
// INTERNAL API (for RequestContextImpl)
|
|
201
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
202
|
+
/**
|
|
203
|
+
* @internal Acquire a header buffer from the ring pool.
|
|
204
|
+
*/
|
|
205
|
+
_acquireHeaderBuffer() {
|
|
206
|
+
const buffer = this._headerPool[this._headerPoolIndex];
|
|
207
|
+
this._headerPoolIndex = (this._headerPoolIndex + 1) % HEADER_POOL_SIZE;
|
|
208
|
+
return buffer;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* @internal Get the drain waiter instance.
|
|
212
|
+
*/
|
|
213
|
+
_getDrainWaiter() {
|
|
214
|
+
return this._drainWaiter;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* @internal Get the socket instance.
|
|
218
|
+
*/
|
|
219
|
+
_getSocket() {
|
|
220
|
+
return this._socket;
|
|
221
|
+
}
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
223
|
+
// PRIVATE: Initialization
|
|
224
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
225
|
+
_generatePipePath() {
|
|
226
|
+
const id = Math.random().toString(36).slice(2, 10);
|
|
227
|
+
return process.platform === "win32"
|
|
228
|
+
? `\\\\.\\pipe\\procwire-${process.pid}-${id}`
|
|
229
|
+
: `/tmp/procwire-${process.pid}-${id}.sock`;
|
|
230
|
+
}
|
|
231
|
+
_createPipeServer(pipePath) {
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
try {
|
|
234
|
+
// Create server using Bun.listen with unix socket
|
|
235
|
+
this._server = Bun.listen({
|
|
236
|
+
unix: pipePath,
|
|
237
|
+
socket: {
|
|
238
|
+
open: (socket) => {
|
|
239
|
+
// Parent connected
|
|
240
|
+
this._socket = socket;
|
|
241
|
+
this._drainWaiter = new BunDrainWaiter();
|
|
242
|
+
this._frameBuffer = new FrameBuffer();
|
|
243
|
+
},
|
|
244
|
+
data: (_socket, data) => {
|
|
245
|
+
// Handle incoming data
|
|
246
|
+
if (!this._frameBuffer)
|
|
247
|
+
return;
|
|
248
|
+
const frames = this._frameBuffer.push(data);
|
|
249
|
+
for (const frame of frames) {
|
|
250
|
+
this._handleFrame(frame);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
error: (_socket, err) => {
|
|
254
|
+
this.emit("error", err);
|
|
255
|
+
},
|
|
256
|
+
close: (_socket) => {
|
|
257
|
+
this._drainWaiter?.clear();
|
|
258
|
+
this.emit("disconnected");
|
|
259
|
+
},
|
|
260
|
+
drain: (_socket) => {
|
|
261
|
+
// Backpressure released
|
|
262
|
+
this._drainWaiter?.onDrain();
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
// Server is listening
|
|
267
|
+
resolve();
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
reject(error);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
_sendInit(pipePath) {
|
|
275
|
+
const schema = {
|
|
276
|
+
methods: Object.fromEntries(Array.from(this._methods.entries()).map(([name, { def }]) => [
|
|
277
|
+
name,
|
|
278
|
+
{
|
|
279
|
+
id: this._methodNameToId.get(name),
|
|
280
|
+
response: def.response,
|
|
281
|
+
},
|
|
282
|
+
])),
|
|
283
|
+
events: Object.fromEntries(Array.from(this._events.keys()).map((name) => [
|
|
284
|
+
name,
|
|
285
|
+
{ id: this._eventNameToId.get(name) },
|
|
286
|
+
])),
|
|
287
|
+
};
|
|
288
|
+
const initMessage = {
|
|
289
|
+
jsonrpc: "2.0",
|
|
290
|
+
method: "$init",
|
|
291
|
+
params: {
|
|
292
|
+
pipe: pipePath,
|
|
293
|
+
schema,
|
|
294
|
+
version: "2.0.0",
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
// Write to stdout (JSON-RPC control plane)
|
|
298
|
+
console.log(JSON.stringify(initMessage));
|
|
299
|
+
}
|
|
300
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
301
|
+
// PRIVATE: Frame Handling
|
|
302
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
303
|
+
_handleFrame(frame) {
|
|
304
|
+
const { header } = frame;
|
|
305
|
+
// Abort signal (reserved methodId)
|
|
306
|
+
if (header.methodId === ABORT_METHOD_ID) {
|
|
307
|
+
this._handleAbort(header.requestId);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// Request from parent
|
|
311
|
+
const methodName = this._methodIdToName.get(header.methodId);
|
|
312
|
+
if (!methodName) {
|
|
313
|
+
// Unknown method - send error response
|
|
314
|
+
this._sendErrorResponse(header.requestId, header.methodId, `Unknown method ID: ${header.methodId}`);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const methodEntry = this._methods.get(methodName);
|
|
318
|
+
if (!methodEntry)
|
|
319
|
+
return;
|
|
320
|
+
const { def, handler } = methodEntry;
|
|
321
|
+
const codec = def.codec ?? this._defaultCodec;
|
|
322
|
+
const data = codecDeserialize(codec, frame);
|
|
323
|
+
// Create request context
|
|
324
|
+
const ctx = new RequestContextImpl(header.requestId, methodName, header.methodId, codec, this._socket, this._abortCallbacks, () => this._acquireHeaderBuffer(), this._drainWaiter);
|
|
325
|
+
// Track active context for abort handling
|
|
326
|
+
this._activeContexts.set(header.requestId, ctx);
|
|
327
|
+
// Call handler
|
|
328
|
+
try {
|
|
329
|
+
const result = handler(data, ctx);
|
|
330
|
+
if (result instanceof Promise) {
|
|
331
|
+
result
|
|
332
|
+
.catch((err) => {
|
|
333
|
+
if (!ctx.responded) {
|
|
334
|
+
// ctx.error() is async - fire and forget with error handling
|
|
335
|
+
ctx.error(err).catch(() => {
|
|
336
|
+
/* ignore - socket may be closed */
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
.finally(() => {
|
|
341
|
+
this._activeContexts.delete(header.requestId);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
this._activeContexts.delete(header.requestId);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
if (!ctx.responded) {
|
|
350
|
+
// ctx.error() is async - fire and forget with error handling
|
|
351
|
+
ctx.error(err).catch(() => {
|
|
352
|
+
/* ignore - socket may be closed */
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
this._activeContexts.delete(header.requestId);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
_handleAbort(requestId) {
|
|
359
|
+
// Mark context as aborted
|
|
360
|
+
const ctx = this._activeContexts.get(requestId);
|
|
361
|
+
if (ctx) {
|
|
362
|
+
ctx._markAborted();
|
|
363
|
+
}
|
|
364
|
+
// Call abort callbacks
|
|
365
|
+
const callbacks = this._abortCallbacks.get(requestId);
|
|
366
|
+
if (callbacks) {
|
|
367
|
+
for (const cb of callbacks) {
|
|
368
|
+
try {
|
|
369
|
+
cb();
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
/* ignore */
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
this._abortCallbacks.delete(requestId);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
_sendErrorResponse(requestId, methodId, message) {
|
|
379
|
+
if (!this._socket)
|
|
380
|
+
return;
|
|
381
|
+
const payload = this._defaultCodec.serialize(message);
|
|
382
|
+
const headerBuf = this._acquireHeaderBuffer();
|
|
383
|
+
encodeHeaderInto(headerBuf, {
|
|
384
|
+
methodId,
|
|
385
|
+
flags: Flags.IS_RESPONSE | Flags.IS_ERROR | Flags.DIRECTION_TO_PARENT,
|
|
386
|
+
requestId,
|
|
387
|
+
payloadLength: payload.length,
|
|
388
|
+
});
|
|
389
|
+
// Bun doesn't have cork/uncork, concatenate for atomic write
|
|
390
|
+
const combined = Buffer.concat([headerBuf, payload]);
|
|
391
|
+
this._socket.write(combined);
|
|
392
|
+
}
|
|
393
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
394
|
+
// PRIVATE: Frame Sending
|
|
395
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
396
|
+
/**
|
|
397
|
+
* Send a frame with proper backpressure handling.
|
|
398
|
+
* Used for emitting events to parent.
|
|
399
|
+
*
|
|
400
|
+
* Bun sockets don't have cork/uncork, so we concatenate buffers.
|
|
401
|
+
*/
|
|
402
|
+
async _sendFrame(methodId, requestId, data, codec, flags) {
|
|
403
|
+
if (!this._socket || !this._drainWaiter)
|
|
404
|
+
return;
|
|
405
|
+
const payload = codec.serialize(data);
|
|
406
|
+
const headerBuf = this._acquireHeaderBuffer();
|
|
407
|
+
encodeHeaderInto(headerBuf, {
|
|
408
|
+
methodId,
|
|
409
|
+
flags,
|
|
410
|
+
requestId,
|
|
411
|
+
payloadLength: payload.length,
|
|
412
|
+
});
|
|
413
|
+
// Bun doesn't have cork/uncork, concatenate for atomic write
|
|
414
|
+
const combined = Buffer.concat([headerBuf, payload]);
|
|
415
|
+
const canContinue = this._socket.write(combined);
|
|
416
|
+
// OPT-04: Wait AFTER write if backpressure
|
|
417
|
+
if (!canContinue) {
|
|
418
|
+
this._drainWaiter.markNeedsDrain();
|
|
419
|
+
await this._drainWaiter.waitForDrain();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BunDrainWaiter - Singleton pattern for Bun socket drain waiting.
|
|
3
|
+
*
|
|
4
|
+
* PROBLEM: In Bun, socket.write() returns a boolean indicating if more data
|
|
5
|
+
* can be written. When it returns false, you need to wait for the drain
|
|
6
|
+
* callback before writing more data.
|
|
7
|
+
*
|
|
8
|
+
* SOLUTION: This class maintains pending drain waiters and resolves them
|
|
9
|
+
* when the drain callback is called.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const drainWaiter = new BunDrainWaiter();
|
|
14
|
+
*
|
|
15
|
+
* // In socket handlers:
|
|
16
|
+
* socket: {
|
|
17
|
+
* drain(socket) {
|
|
18
|
+
* drainWaiter.onDrain();
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* // When writing:
|
|
23
|
+
* const canContinue = socket.write(data);
|
|
24
|
+
* if (!canContinue) {
|
|
25
|
+
* drainWaiter.markNeedsDrain();
|
|
26
|
+
* await drainWaiter.waitForDrain();
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Singleton drain waiter for Bun sockets.
|
|
34
|
+
*
|
|
35
|
+
* Allows multiple concurrent requests to wait for drain
|
|
36
|
+
* with a simple callback-based pattern.
|
|
37
|
+
*/
|
|
38
|
+
export declare class BunDrainWaiter {
|
|
39
|
+
private _waiters;
|
|
40
|
+
private _needsDrain;
|
|
41
|
+
private _closed;
|
|
42
|
+
/**
|
|
43
|
+
* Call this from the socket's drain handler.
|
|
44
|
+
* Resolves all pending waiters.
|
|
45
|
+
*/
|
|
46
|
+
onDrain(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Mark that drain is needed (socket.write returned false).
|
|
49
|
+
*/
|
|
50
|
+
markNeedsDrain(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Check if drain is needed.
|
|
53
|
+
*/
|
|
54
|
+
get needsDrain(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Wait for socket drain.
|
|
57
|
+
*
|
|
58
|
+
* Call markNeedsDrain() before calling this if socket.write returned false.
|
|
59
|
+
*
|
|
60
|
+
* @throws {Error} If socket is closed while waiting
|
|
61
|
+
*/
|
|
62
|
+
waitForDrain(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Clear all pending waiters.
|
|
65
|
+
* Call this on socket close/disconnect.
|
|
66
|
+
*/
|
|
67
|
+
clear(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Mark socket as closed but don't clear waiters yet.
|
|
70
|
+
* They will be cleared when they complete.
|
|
71
|
+
*/
|
|
72
|
+
markClosed(): void;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=drain-waiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drain-waiter.d.ts","sourceRoot":"","sources":["../src/drain-waiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAExB;;;OAGG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;;;OAMG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAUb;;;OAGG;IACH,UAAU,IAAI,IAAI;CAGnB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BunDrainWaiter - Singleton pattern for Bun socket drain waiting.
|
|
3
|
+
*
|
|
4
|
+
* PROBLEM: In Bun, socket.write() returns a boolean indicating if more data
|
|
5
|
+
* can be written. When it returns false, you need to wait for the drain
|
|
6
|
+
* callback before writing more data.
|
|
7
|
+
*
|
|
8
|
+
* SOLUTION: This class maintains pending drain waiters and resolves them
|
|
9
|
+
* when the drain callback is called.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const drainWaiter = new BunDrainWaiter();
|
|
14
|
+
*
|
|
15
|
+
* // In socket handlers:
|
|
16
|
+
* socket: {
|
|
17
|
+
* drain(socket) {
|
|
18
|
+
* drainWaiter.onDrain();
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* // When writing:
|
|
23
|
+
* const canContinue = socket.write(data);
|
|
24
|
+
* if (!canContinue) {
|
|
25
|
+
* drainWaiter.markNeedsDrain();
|
|
26
|
+
* await drainWaiter.waitForDrain();
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Singleton drain waiter for Bun sockets.
|
|
34
|
+
*
|
|
35
|
+
* Allows multiple concurrent requests to wait for drain
|
|
36
|
+
* with a simple callback-based pattern.
|
|
37
|
+
*/
|
|
38
|
+
export class BunDrainWaiter {
|
|
39
|
+
_waiters = new Set();
|
|
40
|
+
_needsDrain = false;
|
|
41
|
+
_closed = false;
|
|
42
|
+
/**
|
|
43
|
+
* Call this from the socket's drain handler.
|
|
44
|
+
* Resolves all pending waiters.
|
|
45
|
+
*/
|
|
46
|
+
onDrain() {
|
|
47
|
+
this._needsDrain = false;
|
|
48
|
+
// Resolve all waiters
|
|
49
|
+
for (const resolve of this._waiters) {
|
|
50
|
+
resolve();
|
|
51
|
+
}
|
|
52
|
+
this._waiters.clear();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Mark that drain is needed (socket.write returned false).
|
|
56
|
+
*/
|
|
57
|
+
markNeedsDrain() {
|
|
58
|
+
this._needsDrain = true;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if drain is needed.
|
|
62
|
+
*/
|
|
63
|
+
get needsDrain() {
|
|
64
|
+
return this._needsDrain;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Wait for socket drain.
|
|
68
|
+
*
|
|
69
|
+
* Call markNeedsDrain() before calling this if socket.write returned false.
|
|
70
|
+
*
|
|
71
|
+
* @throws {Error} If socket is closed while waiting
|
|
72
|
+
*/
|
|
73
|
+
async waitForDrain() {
|
|
74
|
+
// Fast path: no backpressure
|
|
75
|
+
if (!this._needsDrain) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Socket closed check
|
|
79
|
+
if (this._closed) {
|
|
80
|
+
throw new Error("Socket closed during backpressure wait");
|
|
81
|
+
}
|
|
82
|
+
// Add this request to waiters
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
this._waiters.add(resolve);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Clear all pending waiters.
|
|
89
|
+
* Call this on socket close/disconnect.
|
|
90
|
+
*/
|
|
91
|
+
clear() {
|
|
92
|
+
this._needsDrain = false;
|
|
93
|
+
this._closed = true;
|
|
94
|
+
// Resolve all waiters so they don't hang
|
|
95
|
+
for (const resolve of this._waiters) {
|
|
96
|
+
resolve();
|
|
97
|
+
}
|
|
98
|
+
this._waiters.clear();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Mark socket as closed but don't clear waiters yet.
|
|
102
|
+
* They will be cleared when they complete.
|
|
103
|
+
*/
|
|
104
|
+
markClosed() {
|
|
105
|
+
this._closed = true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=drain-waiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drain-waiter.js","sourceRoot":"","sources":["../src/drain-waiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACjB,QAAQ,GAAoB,IAAI,GAAG,EAAE,CAAC;IACtC,WAAW,GAAG,KAAK,CAAC;IACpB,OAAO,GAAG,KAAK,CAAC;IAExB;;;OAGG;IACH,OAAO;QACL,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,sBAAsB;QACtB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY;QAChB,6BAA6B;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,sBAAsB;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,8BAA8B;QAC9B,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,yCAAyC;QACzC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,UAAU;QACR,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;CACF"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types and factory functions for @procwire-bun/client.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Base error class for all Procwire client errors.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ProcwireClientError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Factory functions for Client-related errors.
|
|
14
|
+
*/
|
|
15
|
+
export declare const ClientErrors: {
|
|
16
|
+
/** Cannot add handlers after start */
|
|
17
|
+
readonly cannotAddHandlerAfterStart: () => ProcwireClientError;
|
|
18
|
+
/** Cannot add events after start */
|
|
19
|
+
readonly cannotAddEventAfterStart: () => ProcwireClientError;
|
|
20
|
+
/** Client already started */
|
|
21
|
+
readonly alreadyStarted: () => ProcwireClientError;
|
|
22
|
+
/** Client not connected */
|
|
23
|
+
readonly notConnected: () => ProcwireClientError;
|
|
24
|
+
/** Unknown event name */
|
|
25
|
+
readonly unknownEvent: (eventName: string) => ProcwireClientError;
|
|
26
|
+
/** Response already sent */
|
|
27
|
+
readonly responseAlreadySent: () => ProcwireClientError;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB,sCAAsC;;IAGtC,oCAAoC;;IAGpC,6BAA6B;;IAG7B,2BAA2B;;IAG3B,yBAAyB;uCACC,MAAM;IAEhC,4BAA4B;;CAEpB,CAAC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types and factory functions for @procwire-bun/client.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Base error class for all Procwire client errors.
|
|
8
|
+
*/
|
|
9
|
+
export class ProcwireClientError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "ProcwireClientError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Factory functions for Client-related errors.
|
|
17
|
+
*/
|
|
18
|
+
export const ClientErrors = {
|
|
19
|
+
/** Cannot add handlers after start */
|
|
20
|
+
cannotAddHandlerAfterStart: () => new ProcwireClientError("Cannot add handlers after start()"),
|
|
21
|
+
/** Cannot add events after start */
|
|
22
|
+
cannotAddEventAfterStart: () => new ProcwireClientError("Cannot add events after start()"),
|
|
23
|
+
/** Client already started */
|
|
24
|
+
alreadyStarted: () => new ProcwireClientError("Client already started"),
|
|
25
|
+
/** Client not connected */
|
|
26
|
+
notConnected: () => new ProcwireClientError("Client not connected"),
|
|
27
|
+
/** Unknown event name */
|
|
28
|
+
unknownEvent: (eventName) => new ProcwireClientError(`Unknown event: ${eventName}`),
|
|
29
|
+
/** Response already sent */
|
|
30
|
+
responseAlreadySent: () => new ProcwireClientError("Response already sent"),
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,sCAAsC;IACtC,0BAA0B,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAC,mCAAmC,CAAC;IAE9F,oCAAoC;IACpC,wBAAwB,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAC,iCAAiC,CAAC;IAE1F,6BAA6B;IAC7B,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAC,wBAAwB,CAAC;IAEvE,2BAA2B;IAC3B,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAC,sBAAsB,CAAC;IAEnE,yBAAyB;IACzB,YAAY,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,kBAAkB,SAAS,EAAE,CAAC;IAE3F,4BAA4B;IAC5B,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAC,uBAAuB,CAAC;CACnE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @procwire-bun/client - Child-side API for Procwire IPC (Bun.js optimized).
|
|
3
|
+
*
|
|
4
|
+
* This package provides the client-side implementation for child processes
|
|
5
|
+
* to communicate with the parent process using Procwire's binary protocol.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Client } from '@procwire-bun/client';
|
|
10
|
+
*
|
|
11
|
+
* const client = new Client()
|
|
12
|
+
* .handle('query', async (data, ctx) => {
|
|
13
|
+
* const results = await search(data);
|
|
14
|
+
* ctx.respond(results);
|
|
15
|
+
* })
|
|
16
|
+
* .handle('insert', async (data, ctx) => {
|
|
17
|
+
* ctx.ack({ accepted: true });
|
|
18
|
+
* await processInBackground(data);
|
|
19
|
+
* })
|
|
20
|
+
* .event('progress');
|
|
21
|
+
*
|
|
22
|
+
* await client.start();
|
|
23
|
+
*
|
|
24
|
+
* // Emit events to parent
|
|
25
|
+
* client.emitEvent('progress', { percent: 50 });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
export { Client } from "./client.js";
|
|
31
|
+
export { RequestContextImpl } from "./request-context.js";
|
|
32
|
+
export { BunDrainWaiter } from "./drain-waiter.js";
|
|
33
|
+
export { ProcwireClientError, ClientErrors } from "./errors.js";
|
|
34
|
+
export type { ResponseType, MethodDefinition, EventDefinition, ClientOptions, MethodHandler, RequestContext, } from "./types.js";
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @procwire-bun/client - Child-side API for Procwire IPC (Bun.js optimized).
|
|
3
|
+
*
|
|
4
|
+
* This package provides the client-side implementation for child processes
|
|
5
|
+
* to communicate with the parent process using Procwire's binary protocol.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Client } from '@procwire-bun/client';
|
|
10
|
+
*
|
|
11
|
+
* const client = new Client()
|
|
12
|
+
* .handle('query', async (data, ctx) => {
|
|
13
|
+
* const results = await search(data);
|
|
14
|
+
* ctx.respond(results);
|
|
15
|
+
* })
|
|
16
|
+
* .handle('insert', async (data, ctx) => {
|
|
17
|
+
* ctx.ack({ accepted: true });
|
|
18
|
+
* await processInBackground(data);
|
|
19
|
+
* })
|
|
20
|
+
* .event('progress');
|
|
21
|
+
*
|
|
22
|
+
* await client.start();
|
|
23
|
+
*
|
|
24
|
+
* // Emit events to parent
|
|
25
|
+
* client.emitEvent('progress', { percent: 50 });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
export { Client } from "./client.js";
|
|
31
|
+
export { RequestContextImpl } from "./request-context.js";
|
|
32
|
+
export { BunDrainWaiter } from "./drain-waiter.js";
|
|
33
|
+
export { ProcwireClientError, ClientErrors } from "./errors.js";
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RequestContext implementation for method handlers.
|
|
3
|
+
*
|
|
4
|
+
* This is the Bun.js optimized version using Bun socket API.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { Codec } from "@procwire/codecs";
|
|
9
|
+
import type { RequestContext } from "./types.js";
|
|
10
|
+
import type { BunDrainWaiter } from "./drain-waiter.js";
|
|
11
|
+
type BunSocket = Awaited<ReturnType<typeof Bun.connect>>;
|
|
12
|
+
/**
|
|
13
|
+
* Internal implementation of RequestContext.
|
|
14
|
+
*
|
|
15
|
+
* Passed to method handlers to allow sending responses.
|
|
16
|
+
* All response methods are async to properly handle socket backpressure.
|
|
17
|
+
*/
|
|
18
|
+
export declare class RequestContextImpl implements RequestContext {
|
|
19
|
+
readonly requestId: number;
|
|
20
|
+
readonly method: string;
|
|
21
|
+
private readonly _methodId;
|
|
22
|
+
private readonly _codec;
|
|
23
|
+
private readonly _socket;
|
|
24
|
+
private readonly _abortCallbacks;
|
|
25
|
+
private readonly _acquireHeader;
|
|
26
|
+
private readonly _drainWaiter;
|
|
27
|
+
private _aborted;
|
|
28
|
+
private _responded;
|
|
29
|
+
constructor(requestId: number, method: string, _methodId: number, _codec: Codec, _socket: BunSocket, _abortCallbacks: Map<number, Set<() => void>>, _acquireHeader: () => Buffer, _drainWaiter: BunDrainWaiter);
|
|
30
|
+
get aborted(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Whether a response has been sent.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
get responded(): boolean;
|
|
36
|
+
onAbort(callback: () => void): void;
|
|
37
|
+
respond(data: unknown): Promise<void>;
|
|
38
|
+
ack(data?: unknown): Promise<void>;
|
|
39
|
+
chunk(data: unknown): Promise<void>;
|
|
40
|
+
end(): Promise<void>;
|
|
41
|
+
error(err: Error | string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Mark context as aborted.
|
|
44
|
+
* @internal Called by Client when abort frame received.
|
|
45
|
+
*/
|
|
46
|
+
_markAborted(): void;
|
|
47
|
+
private _ensureNotResponded;
|
|
48
|
+
/**
|
|
49
|
+
* Send response data with proper backpressure handling.
|
|
50
|
+
*
|
|
51
|
+
* Bun sockets don't have cork/uncork, so we concatenate buffers for atomic write.
|
|
52
|
+
*/
|
|
53
|
+
private _sendResponse;
|
|
54
|
+
private _cleanup;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=request-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,KAAK,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,qBAAa,kBAAmB,YAAW,cAAc;aAKrC,SAAS,EAAE,MAAM;aACjB,MAAM,EAAE,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAX/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAS;gBAGT,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,KAAK,EACb,OAAO,EAAE,SAAS,EAClB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EAC7C,cAAc,EAAE,MAAM,MAAM,EAC5B,YAAY,EAAE,cAAc;IAG/C,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;OAGG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAS7B,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlC,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAUpB,KAAK,CAAC,GAAG,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/C;;;OAGG;IACH,YAAY,IAAI,IAAI;IAIpB,OAAO,CAAC,mBAAmB;IAM3B;;;;OAIG;YACW,aAAa;IA4B3B,OAAO,CAAC,QAAQ;CAGjB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RequestContext implementation for method handlers.
|
|
3
|
+
*
|
|
4
|
+
* This is the Bun.js optimized version using Bun socket API.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { Flags, encodeHeaderInto } from "@procwire/protocol";
|
|
9
|
+
import { ClientErrors } from "./errors.js";
|
|
10
|
+
/**
|
|
11
|
+
* Internal implementation of RequestContext.
|
|
12
|
+
*
|
|
13
|
+
* Passed to method handlers to allow sending responses.
|
|
14
|
+
* All response methods are async to properly handle socket backpressure.
|
|
15
|
+
*/
|
|
16
|
+
export class RequestContextImpl {
|
|
17
|
+
requestId;
|
|
18
|
+
method;
|
|
19
|
+
_methodId;
|
|
20
|
+
_codec;
|
|
21
|
+
_socket;
|
|
22
|
+
_abortCallbacks;
|
|
23
|
+
_acquireHeader;
|
|
24
|
+
_drainWaiter;
|
|
25
|
+
_aborted = false;
|
|
26
|
+
_responded = false;
|
|
27
|
+
constructor(requestId, method, _methodId, _codec, _socket, _abortCallbacks, _acquireHeader, _drainWaiter) {
|
|
28
|
+
this.requestId = requestId;
|
|
29
|
+
this.method = method;
|
|
30
|
+
this._methodId = _methodId;
|
|
31
|
+
this._codec = _codec;
|
|
32
|
+
this._socket = _socket;
|
|
33
|
+
this._abortCallbacks = _abortCallbacks;
|
|
34
|
+
this._acquireHeader = _acquireHeader;
|
|
35
|
+
this._drainWaiter = _drainWaiter;
|
|
36
|
+
}
|
|
37
|
+
get aborted() {
|
|
38
|
+
return this._aborted;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether a response has been sent.
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
get responded() {
|
|
45
|
+
return this._responded;
|
|
46
|
+
}
|
|
47
|
+
onAbort(callback) {
|
|
48
|
+
let callbacks = this._abortCallbacks.get(this.requestId);
|
|
49
|
+
if (!callbacks) {
|
|
50
|
+
callbacks = new Set();
|
|
51
|
+
this._abortCallbacks.set(this.requestId, callbacks);
|
|
52
|
+
}
|
|
53
|
+
callbacks.add(callback);
|
|
54
|
+
}
|
|
55
|
+
async respond(data) {
|
|
56
|
+
this._ensureNotResponded();
|
|
57
|
+
this._responded = true;
|
|
58
|
+
await this._sendResponse(data, Flags.IS_RESPONSE | Flags.DIRECTION_TO_PARENT);
|
|
59
|
+
this._cleanup();
|
|
60
|
+
}
|
|
61
|
+
async ack(data) {
|
|
62
|
+
this._ensureNotResponded();
|
|
63
|
+
this._responded = true;
|
|
64
|
+
await this._sendResponse(data ?? null, Flags.IS_RESPONSE | Flags.IS_ACK | Flags.DIRECTION_TO_PARENT);
|
|
65
|
+
this._cleanup();
|
|
66
|
+
}
|
|
67
|
+
async chunk(data) {
|
|
68
|
+
await this._sendResponse(data, Flags.IS_RESPONSE | Flags.IS_STREAM | Flags.DIRECTION_TO_PARENT);
|
|
69
|
+
}
|
|
70
|
+
async end() {
|
|
71
|
+
this._ensureNotResponded();
|
|
72
|
+
this._responded = true;
|
|
73
|
+
await this._sendResponse(null, Flags.IS_RESPONSE | Flags.IS_STREAM | Flags.STREAM_END | Flags.DIRECTION_TO_PARENT);
|
|
74
|
+
this._cleanup();
|
|
75
|
+
}
|
|
76
|
+
async error(err) {
|
|
77
|
+
this._ensureNotResponded();
|
|
78
|
+
this._responded = true;
|
|
79
|
+
const message = err instanceof Error ? err.message : err;
|
|
80
|
+
await this._sendResponse(message, Flags.IS_RESPONSE | Flags.IS_ERROR | Flags.DIRECTION_TO_PARENT);
|
|
81
|
+
this._cleanup();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Mark context as aborted.
|
|
85
|
+
* @internal Called by Client when abort frame received.
|
|
86
|
+
*/
|
|
87
|
+
_markAborted() {
|
|
88
|
+
this._aborted = true;
|
|
89
|
+
}
|
|
90
|
+
_ensureNotResponded() {
|
|
91
|
+
if (this._responded) {
|
|
92
|
+
throw ClientErrors.responseAlreadySent();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Send response data with proper backpressure handling.
|
|
97
|
+
*
|
|
98
|
+
* Bun sockets don't have cork/uncork, so we concatenate buffers for atomic write.
|
|
99
|
+
*/
|
|
100
|
+
async _sendResponse(data, flags) {
|
|
101
|
+
// Empty payload cases:
|
|
102
|
+
// 1. STREAM_END frames (null data)
|
|
103
|
+
// 2. ACK without data (null/undefined data with IS_ACK flag)
|
|
104
|
+
// Don't serialize null - just use empty buffer (required for rawCodec compatibility)
|
|
105
|
+
const isStreamEnd = (flags & Flags.STREAM_END) !== 0;
|
|
106
|
+
const isEmptyAck = (flags & Flags.IS_ACK) !== 0 && data == null;
|
|
107
|
+
const payload = isStreamEnd || isEmptyAck ? Buffer.alloc(0) : this._codec.serialize(data);
|
|
108
|
+
const headerBuf = this._acquireHeader();
|
|
109
|
+
encodeHeaderInto(headerBuf, {
|
|
110
|
+
methodId: this._methodId,
|
|
111
|
+
flags,
|
|
112
|
+
requestId: this.requestId,
|
|
113
|
+
payloadLength: payload.length,
|
|
114
|
+
});
|
|
115
|
+
// Bun doesn't have cork/uncork, concatenate for atomic write
|
|
116
|
+
const combined = Buffer.concat([headerBuf, payload]);
|
|
117
|
+
const canContinue = this._socket.write(combined);
|
|
118
|
+
// OPT-04: Wait AFTER write if backpressure
|
|
119
|
+
if (!canContinue) {
|
|
120
|
+
this._drainWaiter.markNeedsDrain();
|
|
121
|
+
await this._drainWaiter.waitForDrain();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
_cleanup() {
|
|
125
|
+
this._abortCallbacks.delete(this.requestId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=request-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-context.js","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C;;;;;GAKG;AACH,MAAM,OAAO,kBAAkB;IAKX;IACA;IACC;IACA;IACA;IACA;IACA;IACA;IAXX,QAAQ,GAAG,KAAK,CAAC;IACjB,UAAU,GAAG,KAAK,CAAC;IAE3B,YACkB,SAAiB,EACjB,MAAc,EACb,SAAiB,EACjB,MAAa,EACb,OAAkB,EAClB,eAA6C,EAC7C,cAA4B,EAC5B,YAA4B;QAP7B,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAQ;QACb,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAO;QACb,YAAO,GAAP,OAAO,CAAW;QAClB,oBAAe,GAAf,eAAe,CAA8B;QAC7C,mBAAc,GAAd,cAAc,CAAc;QAC5B,iBAAY,GAAZ,YAAY,CAAgB;IAC5C,CAAC;IAEJ,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,QAAoB;QAC1B,IAAI,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACtD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAa;QACzB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC9E,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAc;QACtB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,IAAI,CAAC,aAAa,CACtB,IAAI,IAAI,IAAI,EACZ,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,mBAAmB,CAC7D,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAa;QACvB,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAClG,CAAC;IAED,KAAK,CAAC,GAAG;QACP,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,IAAI,CAAC,aAAa,CACtB,IAAI,EACJ,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,mBAAmB,CACnF,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAmB;QAC7B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;QACzD,MAAM,IAAI,CAAC,aAAa,CACtB,OAAO,EACP,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,mBAAmB,CAC/D,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAEO,mBAAmB;QACzB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;QAC3C,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,aAAa,CAAC,IAAa,EAAE,KAAa;QACtD,uBAAuB;QACvB,mCAAmC;QACnC,6DAA6D;QAC7D,qFAAqF;QACrF,MAAM,WAAW,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC;QAChE,MAAM,OAAO,GAAG,WAAW,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC1F,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAExC,gBAAgB,CAAC,SAAS,EAAE;YAC1B,QAAQ,EAAE,IAAI,CAAC,SAAS;YACxB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,aAAa,EAAE,OAAO,CAAC,MAAM;SAC9B,CAAC,CAAC;QAEH,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEjD,2CAA2C;QAC3C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;YACnC,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;QACzC,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for @procwire-bun/client.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Codec } from "@procwire/codecs";
|
|
7
|
+
/**
|
|
8
|
+
* Response type for methods.
|
|
9
|
+
*/
|
|
10
|
+
export type ResponseType = "result" | "stream" | "ack" | "none";
|
|
11
|
+
/**
|
|
12
|
+
* Method definition for registration.
|
|
13
|
+
*/
|
|
14
|
+
export interface MethodDefinition {
|
|
15
|
+
/** Expected response type */
|
|
16
|
+
response: ResponseType;
|
|
17
|
+
/** Codec for serialization (defaults to msgpack) */
|
|
18
|
+
codec?: Codec;
|
|
19
|
+
/** Can be cancelled via AbortSignal? */
|
|
20
|
+
cancellable?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Event definition for registration.
|
|
24
|
+
*/
|
|
25
|
+
export interface EventDefinition {
|
|
26
|
+
/** Codec for serialization (defaults to msgpack) */
|
|
27
|
+
codec?: Codec;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Client configuration options.
|
|
31
|
+
*/
|
|
32
|
+
export interface ClientOptions {
|
|
33
|
+
/** Default codec for methods and events */
|
|
34
|
+
defaultCodec?: Codec;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Method handler function type.
|
|
38
|
+
*/
|
|
39
|
+
export type MethodHandler<TData = unknown> = (data: TData, ctx: RequestContext) => void | Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Request context passed to method handlers.
|
|
42
|
+
*
|
|
43
|
+
* Provides methods to send responses back to parent.
|
|
44
|
+
*
|
|
45
|
+
* All response methods are async to properly handle backpressure.
|
|
46
|
+
* Always await these methods to prevent deadlocks with large payloads.
|
|
47
|
+
*/
|
|
48
|
+
export interface RequestContext {
|
|
49
|
+
/** Request ID for correlation */
|
|
50
|
+
readonly requestId: number;
|
|
51
|
+
/** Method name being handled */
|
|
52
|
+
readonly method: string;
|
|
53
|
+
/** Was request aborted by parent? */
|
|
54
|
+
readonly aborted: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Register callback to be called when request is aborted.
|
|
57
|
+
*/
|
|
58
|
+
onAbort(callback: () => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Send full response to parent.
|
|
61
|
+
* Sets IS_RESPONSE flag.
|
|
62
|
+
*
|
|
63
|
+
* @returns Promise that resolves when the response has been written
|
|
64
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
65
|
+
*/
|
|
66
|
+
respond(data: unknown): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Send acknowledgment to parent.
|
|
69
|
+
* Sets IS_RESPONSE | IS_ACK flags.
|
|
70
|
+
*
|
|
71
|
+
* @returns Promise that resolves when the response has been written
|
|
72
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
73
|
+
*/
|
|
74
|
+
ack(data?: unknown): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Send stream chunk to parent.
|
|
77
|
+
* Sets IS_RESPONSE | IS_STREAM flags.
|
|
78
|
+
*
|
|
79
|
+
* @returns Promise that resolves when the chunk has been written
|
|
80
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
81
|
+
*/
|
|
82
|
+
chunk(data: unknown): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* End stream.
|
|
85
|
+
* Sets IS_RESPONSE | IS_STREAM | STREAM_END flags.
|
|
86
|
+
*
|
|
87
|
+
* @returns Promise that resolves when the end marker has been written
|
|
88
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
89
|
+
*/
|
|
90
|
+
end(): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Send error response to parent.
|
|
93
|
+
* Sets IS_RESPONSE | IS_ERROR flags.
|
|
94
|
+
*
|
|
95
|
+
* @returns Promise that resolves when the error has been written
|
|
96
|
+
* and socket buffer has drained (if backpressure occurred).
|
|
97
|
+
*/
|
|
98
|
+
error(err: Error | string): Promise<void>;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,wCAAwC;IACxC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,GAAG,OAAO,IAAI,CAC3C,IAAI,EAAE,KAAK,EACX,GAAG,EAAE,cAAc,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAEpC;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;;;OAMG;IACH,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC;;;;;;OAMG;IACH,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAErB;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@procwire/bun-client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Child-side client for Procwire IPC (Bun.js optimized)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"engines": {
|
|
9
|
+
"bun": ">=1.0"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.build.json",
|
|
24
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"clean": "rimraf dist \"*.tsbuildinfo\""
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@procwire/protocol": "workspace:*",
|
|
30
|
+
"@procwire/codecs": "workspace:*"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/bun": "latest",
|
|
34
|
+
"rimraf": "^6.0.1",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"ipc",
|
|
39
|
+
"procwire",
|
|
40
|
+
"client",
|
|
41
|
+
"child-process",
|
|
42
|
+
"bun"
|
|
43
|
+
]
|
|
44
|
+
}
|