@procwire/transport 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +844 -0
  3. package/dist/channel/builder.d.ts +68 -0
  4. package/dist/channel/builder.d.ts.map +1 -0
  5. package/dist/channel/builder.js +120 -0
  6. package/dist/channel/builder.js.map +1 -0
  7. package/dist/channel/index.d.ts +6 -0
  8. package/dist/channel/index.d.ts.map +1 -0
  9. package/dist/channel/index.js +6 -0
  10. package/dist/channel/index.js.map +1 -0
  11. package/dist/channel/quickstart.d.ts +94 -0
  12. package/dist/channel/quickstart.d.ts.map +1 -0
  13. package/dist/channel/quickstart.js +104 -0
  14. package/dist/channel/quickstart.js.map +1 -0
  15. package/dist/channel/request-channel.d.ts +119 -0
  16. package/dist/channel/request-channel.d.ts.map +1 -0
  17. package/dist/channel/request-channel.js +476 -0
  18. package/dist/channel/request-channel.js.map +1 -0
  19. package/dist/channel/types.d.ts +226 -0
  20. package/dist/channel/types.d.ts.map +1 -0
  21. package/dist/channel/types.js +2 -0
  22. package/dist/channel/types.js.map +1 -0
  23. package/dist/framing/index.d.ts +4 -0
  24. package/dist/framing/index.d.ts.map +1 -0
  25. package/dist/framing/index.js +4 -0
  26. package/dist/framing/index.js.map +1 -0
  27. package/dist/framing/length-prefixed.d.ts +55 -0
  28. package/dist/framing/length-prefixed.d.ts.map +1 -0
  29. package/dist/framing/length-prefixed.js +102 -0
  30. package/dist/framing/length-prefixed.js.map +1 -0
  31. package/dist/framing/line-delimited.d.ts +61 -0
  32. package/dist/framing/line-delimited.d.ts.map +1 -0
  33. package/dist/framing/line-delimited.js +94 -0
  34. package/dist/framing/line-delimited.js.map +1 -0
  35. package/dist/framing/types.d.ts +35 -0
  36. package/dist/framing/types.d.ts.map +1 -0
  37. package/dist/framing/types.js +2 -0
  38. package/dist/framing/types.js.map +1 -0
  39. package/dist/index.d.ts +24 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +26 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/process/handle.d.ts +64 -0
  44. package/dist/process/handle.d.ts.map +1 -0
  45. package/dist/process/handle.js +107 -0
  46. package/dist/process/handle.js.map +1 -0
  47. package/dist/process/index.d.ts +37 -0
  48. package/dist/process/index.d.ts.map +1 -0
  49. package/dist/process/index.js +37 -0
  50. package/dist/process/index.js.map +1 -0
  51. package/dist/process/manager.d.ts +58 -0
  52. package/dist/process/manager.d.ts.map +1 -0
  53. package/dist/process/manager.js +360 -0
  54. package/dist/process/manager.js.map +1 -0
  55. package/dist/process/types.d.ts +322 -0
  56. package/dist/process/types.d.ts.map +1 -0
  57. package/dist/process/types.js +2 -0
  58. package/dist/process/types.js.map +1 -0
  59. package/dist/protocol/index.d.ts +4 -0
  60. package/dist/protocol/index.d.ts.map +1 -0
  61. package/dist/protocol/index.js +6 -0
  62. package/dist/protocol/index.js.map +1 -0
  63. package/dist/protocol/jsonrpc.d.ts +146 -0
  64. package/dist/protocol/jsonrpc.d.ts.map +1 -0
  65. package/dist/protocol/jsonrpc.js +288 -0
  66. package/dist/protocol/jsonrpc.js.map +1 -0
  67. package/dist/protocol/simple.d.ts +139 -0
  68. package/dist/protocol/simple.d.ts.map +1 -0
  69. package/dist/protocol/simple.js +297 -0
  70. package/dist/protocol/simple.js.map +1 -0
  71. package/dist/protocol/types.d.ts +117 -0
  72. package/dist/protocol/types.d.ts.map +1 -0
  73. package/dist/protocol/types.js +2 -0
  74. package/dist/protocol/types.js.map +1 -0
  75. package/dist/serialization/index.d.ts +5 -0
  76. package/dist/serialization/index.d.ts.map +1 -0
  77. package/dist/serialization/index.js +5 -0
  78. package/dist/serialization/index.js.map +1 -0
  79. package/dist/serialization/json.d.ts +66 -0
  80. package/dist/serialization/json.d.ts.map +1 -0
  81. package/dist/serialization/json.js +66 -0
  82. package/dist/serialization/json.js.map +1 -0
  83. package/dist/serialization/raw.d.ts +38 -0
  84. package/dist/serialization/raw.d.ts.map +1 -0
  85. package/dist/serialization/raw.js +41 -0
  86. package/dist/serialization/raw.js.map +1 -0
  87. package/dist/serialization/registry.d.ts +91 -0
  88. package/dist/serialization/registry.d.ts.map +1 -0
  89. package/dist/serialization/registry.js +119 -0
  90. package/dist/serialization/registry.js.map +1 -0
  91. package/dist/serialization/types.d.ts +27 -0
  92. package/dist/serialization/types.d.ts.map +1 -0
  93. package/dist/serialization/types.js +2 -0
  94. package/dist/serialization/types.js.map +1 -0
  95. package/dist/transport/factory.d.ts +139 -0
  96. package/dist/transport/factory.d.ts.map +1 -0
  97. package/dist/transport/factory.js +162 -0
  98. package/dist/transport/factory.js.map +1 -0
  99. package/dist/transport/index.d.ts +6 -0
  100. package/dist/transport/index.d.ts.map +1 -0
  101. package/dist/transport/index.js +9 -0
  102. package/dist/transport/index.js.map +1 -0
  103. package/dist/transport/socket-server.d.ts +48 -0
  104. package/dist/transport/socket-server.d.ts.map +1 -0
  105. package/dist/transport/socket-server.js +215 -0
  106. package/dist/transport/socket-server.js.map +1 -0
  107. package/dist/transport/socket-transport.d.ts +67 -0
  108. package/dist/transport/socket-transport.d.ts.map +1 -0
  109. package/dist/transport/socket-transport.js +193 -0
  110. package/dist/transport/socket-transport.js.map +1 -0
  111. package/dist/transport/stdio-transport.d.ts +94 -0
  112. package/dist/transport/stdio-transport.d.ts.map +1 -0
  113. package/dist/transport/stdio-transport.js +234 -0
  114. package/dist/transport/stdio-transport.js.map +1 -0
  115. package/dist/transport/types.d.ts +131 -0
  116. package/dist/transport/types.d.ts.map +1 -0
  117. package/dist/transport/types.js +2 -0
  118. package/dist/transport/types.js.map +1 -0
  119. package/dist/utils/assert.d.ts +16 -0
  120. package/dist/utils/assert.d.ts.map +1 -0
  121. package/dist/utils/assert.js +31 -0
  122. package/dist/utils/assert.js.map +1 -0
  123. package/dist/utils/disposables.d.ts +38 -0
  124. package/dist/utils/disposables.d.ts.map +1 -0
  125. package/dist/utils/disposables.js +59 -0
  126. package/dist/utils/disposables.js.map +1 -0
  127. package/dist/utils/errors.d.ts +43 -0
  128. package/dist/utils/errors.d.ts.map +1 -0
  129. package/dist/utils/errors.js +69 -0
  130. package/dist/utils/errors.js.map +1 -0
  131. package/dist/utils/events.d.ts +58 -0
  132. package/dist/utils/events.d.ts.map +1 -0
  133. package/dist/utils/events.js +95 -0
  134. package/dist/utils/events.js.map +1 -0
  135. package/dist/utils/index.d.ts +8 -0
  136. package/dist/utils/index.d.ts.map +1 -0
  137. package/dist/utils/index.js +8 -0
  138. package/dist/utils/index.js.map +1 -0
  139. package/dist/utils/pipe-path.d.ts +48 -0
  140. package/dist/utils/pipe-path.d.ts.map +1 -0
  141. package/dist/utils/pipe-path.js +89 -0
  142. package/dist/utils/pipe-path.js.map +1 -0
  143. package/dist/utils/platform.d.ts +16 -0
  144. package/dist/utils/platform.d.ts.map +1 -0
  145. package/dist/utils/platform.js +22 -0
  146. package/dist/utils/platform.js.map +1 -0
  147. package/dist/utils/time.d.ts +38 -0
  148. package/dist/utils/time.d.ts.map +1 -0
  149. package/dist/utils/time.js +55 -0
  150. package/dist/utils/time.js.map +1 -0
  151. package/package.json +85 -0
package/README.md ADDED
@@ -0,0 +1,844 @@
1
+ # @procwire/transport
2
+
3
+ Standalone, modular IPC (Inter-Process Communication) transport library for Node.js with **zero runtime dependencies**.
4
+
5
+ Build production-grade IPC channels with full control over every layer: transport, framing, serialization, and protocol.
6
+
7
+ ## Features
8
+
9
+ - **Zero dependencies** - Core package has no runtime dependencies
10
+ - **Modular architecture** - Replace any layer independently
11
+ - **Type-safe** - Full TypeScript support with generics
12
+ - **Cross-platform** - Windows (Named Pipes), macOS/Linux (Unix Sockets)
13
+ - **Multiple transports** - stdio, named pipes, unix sockets
14
+ - **Flexible framing** - Line-delimited, length-prefixed, custom
15
+ - **Pluggable serialization** - JSON, MessagePack, Protobuf, Arrow, custom
16
+ - **Protocol agnostic** - JSON-RPC 2.0, custom protocols
17
+ - **ProcessManager** - Managed child processes with restart policies
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @procwire/transport
23
+ ```
24
+
25
+ Or with optional codecs:
26
+
27
+ ```bash
28
+ # With MessagePack support
29
+ npm install @procwire/transport @procwire/codec-msgpack @msgpack/msgpack
30
+
31
+ # With Protocol Buffers support
32
+ npm install @procwire/transport @procwire/codec-protobuf protobufjs
33
+
34
+ # With Apache Arrow support
35
+ npm install @procwire/transport @procwire/codec-arrow apache-arrow
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ### Basic stdio IPC
41
+
42
+ ```typescript
43
+ import { createStdioChannel } from "@procwire/transport";
44
+
45
+ // Parent process
46
+ const channel = await createStdioChannel("node", {
47
+ args: ["worker.js"],
48
+ timeout: 5000,
49
+ });
50
+
51
+ // Send request
52
+ const result = await channel.request("calculate", { expr: "2+2" });
53
+ console.log(result); // 4
54
+
55
+ // Listen for notifications
56
+ channel.onNotification("log", (params) => {
57
+ console.log(params.message);
58
+ });
59
+
60
+ await channel.close();
61
+ ```
62
+
63
+ ### ProcessManager with dual channels
64
+
65
+ ```typescript
66
+ import { ProcessManager } from "@procwire/transport";
67
+ import { MessagePackCodec } from "@procwire/codec-msgpack";
68
+
69
+ const manager = new ProcessManager({
70
+ namespace: "my-app",
71
+ restartPolicy: { enabled: true, maxRestarts: 3 },
72
+ });
73
+
74
+ const handle = await manager.spawn("worker-1", {
75
+ executablePath: "node",
76
+ args: ["worker.js"],
77
+
78
+ // Control channel (stdio)
79
+ controlChannel: {},
80
+
81
+ // Data channel (pipe/socket with MessagePack)
82
+ dataChannel: {
83
+ enabled: true,
84
+ channel: {
85
+ framing: "length-prefixed",
86
+ serialization: new MessagePackCodec(),
87
+ },
88
+ },
89
+ });
90
+
91
+ // Lightweight commands via control channel
92
+ const status = await handle.request("getStatus");
93
+
94
+ // Bulk data via data channel
95
+ const result = await handle.requestViaData("processItems", { items: [...] });
96
+ ```
97
+
98
+ ### Custom channel with builder
99
+
100
+ ```typescript
101
+ import {
102
+ ChannelBuilder,
103
+ TransportFactory,
104
+ LineDelimitedFraming,
105
+ JsonCodec,
106
+ JsonRpcProtocol,
107
+ } from "@procwire/transport";
108
+
109
+ const transport = TransportFactory.createStdio({
110
+ executablePath: "node",
111
+ args: ["worker.js"],
112
+ });
113
+
114
+ const channel = new ChannelBuilder()
115
+ .withTransport(transport)
116
+ .withFraming(new LineDelimitedFraming())
117
+ .withSerialization(new JsonCodec())
118
+ .withProtocol(new JsonRpcProtocol())
119
+ .withTimeout(10000)
120
+ .build();
121
+
122
+ await channel.start();
123
+ ```
124
+
125
+ ## Architecture
126
+
127
+ The library uses a layered architecture where each layer is independent and replaceable:
128
+
129
+ ```
130
+ Application Layer (Your Code)
131
+
132
+ Process Management (ProcessManager, ProcessHandle)
133
+
134
+ Channel Layer (RequestChannel, ChannelBuilder)
135
+
136
+ Protocol Layer (JSON-RPC 2.0, custom)
137
+
138
+ Serialization Layer (JSON, MessagePack, Protobuf, Arrow)
139
+
140
+ Framing Layer (line-delimited, length-prefixed)
141
+
142
+ Transport Layer (stdio, named pipes, unix sockets)
143
+
144
+ OS Layer (child_process, net.Server/Socket)
145
+ ```
146
+
147
+ ### Core Abstractions
148
+
149
+ 1. **Transport**: Raw byte transfer between endpoints
150
+ 2. **Framing**: Message boundary detection in byte streams
151
+ 3. **Serialization**: Object ↔ binary conversion
152
+ 4. **Protocol**: Application-level message protocol
153
+ 5. **Channel**: High-level request/response communication
154
+ 6. **Process**: Managed child process lifecycle
155
+
156
+ ## API Reference
157
+
158
+ ### Transports
159
+
160
+ #### StdioTransport
161
+
162
+ Spawns child process and communicates via stdin/stdout.
163
+
164
+ ```typescript
165
+ import { StdioTransport } from "@procwire/transport";
166
+
167
+ const transport = new StdioTransport({
168
+ executablePath: "node",
169
+ args: ["worker.js"],
170
+ cwd: process.cwd(),
171
+ env: { ...process.env, CUSTOM_VAR: "value" },
172
+ startupTimeout: 10000,
173
+ });
174
+
175
+ await transport.connect();
176
+ transport.write(Buffer.from("data"));
177
+ transport.onData((data) => console.log(data));
178
+ await transport.close();
179
+ ```
180
+
181
+ #### SocketTransport (Client)
182
+
183
+ Connects to named pipe (Windows) or unix socket (Unix).
184
+
185
+ ```typescript
186
+ import { SocketTransport } from "@procwire/transport";
187
+ import { isWindows } from "@procwire/transport/utils";
188
+
189
+ const path = isWindows() ? "\\\\.\\pipe\\my-pipe" : "/tmp/my-socket.sock";
190
+
191
+ const transport = new SocketTransport({
192
+ path,
193
+ connectionTimeout: 5000,
194
+ });
195
+
196
+ await transport.connect();
197
+ ```
198
+
199
+ #### SocketServer
200
+
201
+ Creates named pipe/unix socket server.
202
+
203
+ ```typescript
204
+ import { SocketServer } from "@procwire/transport";
205
+
206
+ const server = new SocketServer({
207
+ unlinkOnListen: true, // Remove stale socket
208
+ });
209
+
210
+ server.onConnection((transport) => {
211
+ console.log("Client connected");
212
+ transport.onData((data) => {
213
+ transport.write(data); // Echo
214
+ });
215
+ });
216
+
217
+ await server.listen("/tmp/my-socket.sock");
218
+ ```
219
+
220
+ #### TransportFactory
221
+
222
+ Convenience factory for creating transports.
223
+
224
+ ```typescript
225
+ import { TransportFactory } from "@procwire/transport";
226
+
227
+ // Stdio
228
+ const stdio = TransportFactory.createStdio({
229
+ executablePath: "node",
230
+ args: ["worker.js"],
231
+ });
232
+
233
+ // Pipe client
234
+ const client = TransportFactory.createPipeClient({
235
+ path: "/tmp/socket.sock",
236
+ });
237
+
238
+ // Pipe server
239
+ const server = TransportFactory.createPipeServer();
240
+ ```
241
+
242
+ ### Framing
243
+
244
+ #### LineDelimitedFraming
245
+
246
+ Splits messages by newline characters.
247
+
248
+ ```typescript
249
+ import { LineDelimitedFraming } from "@procwire/transport/framing";
250
+
251
+ const framing = new LineDelimitedFraming({
252
+ maxLineLength: 100000, // Default: 100KB
253
+ });
254
+ ```
255
+
256
+ **Best for**:
257
+ - Text protocols (JSON-RPC over stdio)
258
+ - Human-readable debugging
259
+ - Simple implementations
260
+
261
+ **Not suitable for**:
262
+ - Binary data with embedded newlines
263
+ - Very large messages (>1MB)
264
+
265
+ #### LengthPrefixedFraming
266
+
267
+ Prefixes each message with 4-byte length (big-endian).
268
+
269
+ ```typescript
270
+ import { LengthPrefixedFraming } from "@procwire/transport/framing";
271
+
272
+ const framing = new LengthPrefixedFraming({
273
+ maxMessageSize: 10 * 1024 * 1024, // Default: 10MB
274
+ });
275
+ ```
276
+
277
+ **Best for**:
278
+ - Binary protocols (MessagePack, Protobuf)
279
+ - Large messages
280
+ - High throughput
281
+
282
+ **Format**: `[4-byte length][message]`
283
+
284
+ ### Serialization
285
+
286
+ #### JsonCodec
287
+
288
+ JSON serialization using native `JSON.parse`/`JSON.stringify`.
289
+
290
+ ```typescript
291
+ import { JsonCodec } from "@procwire/transport/serialization";
292
+
293
+ const codec = new JsonCodec();
294
+ ```
295
+
296
+ **Pros**: Built-in, human-readable, widely supported
297
+ **Cons**: Larger payloads, slower for large data
298
+
299
+ #### RawCodec
300
+
301
+ Pass-through codec for binary data.
302
+
303
+ ```typescript
304
+ import { RawCodec } from "@procwire/transport/serialization";
305
+
306
+ const codec = new RawCodec();
307
+ ```
308
+
309
+ **Use case**: When you handle serialization yourself.
310
+
311
+ #### CodecRegistry
312
+
313
+ Dynamically select codec based on content type.
314
+
315
+ ```typescript
316
+ import { CodecRegistry } from "@procwire/transport/serialization";
317
+ import { JsonCodec } from "@procwire/transport/serialization";
318
+ import { MessagePackCodec } from "@procwire/codec-msgpack";
319
+
320
+ const registry = new CodecRegistry();
321
+ registry.register(new JsonCodec());
322
+ registry.register(new MessagePackCodec());
323
+
324
+ // Use with protocol that supports content negotiation
325
+ ```
326
+
327
+ #### Custom Codecs
328
+
329
+ ```typescript
330
+ import type { SerializationCodec } from "@procwire/transport/serialization";
331
+
332
+ class MyCodec implements SerializationCodec<MyType> {
333
+ readonly name = "my-codec";
334
+ readonly contentType = "application/x-my-codec";
335
+
336
+ serialize(value: MyType): Buffer {
337
+ // ... encoding logic
338
+ return buffer;
339
+ }
340
+
341
+ deserialize(buffer: Buffer): MyType {
342
+ // ... decoding logic
343
+ return value;
344
+ }
345
+ }
346
+ ```
347
+
348
+ ### Protocols
349
+
350
+ #### JsonRpcProtocol
351
+
352
+ JSON-RPC 2.0 implementation with request/response and notifications.
353
+
354
+ ```typescript
355
+ import { JsonRpcProtocol } from "@procwire/transport/protocol";
356
+
357
+ const protocol = new JsonRpcProtocol();
358
+ ```
359
+
360
+ **Request**:
361
+ ```json
362
+ {"jsonrpc":"2.0","id":1,"method":"add","params":{"a":2,"b":3}}
363
+ ```
364
+
365
+ **Response**:
366
+ ```json
367
+ {"jsonrpc":"2.0","id":1,"result":5}
368
+ ```
369
+
370
+ **Notification** (no response):
371
+ ```json
372
+ {"jsonrpc":"2.0","method":"log","params":{"message":"Hello"}}
373
+ ```
374
+
375
+ #### SimpleProtocol
376
+
377
+ Minimal protocol with method and params.
378
+
379
+ ```typescript
380
+ import { SimpleProtocol } from "@procwire/transport/protocol";
381
+
382
+ const protocol = new SimpleProtocol();
383
+ ```
384
+
385
+ **Message**:
386
+ ```json
387
+ {"method":"add","params":{"a":2,"b":3}}
388
+ ```
389
+
390
+ #### Custom Protocols
391
+
392
+ ```typescript
393
+ import type { Protocol } from "@procwire/transport/protocol";
394
+
395
+ class MyProtocol implements Protocol {
396
+ encodeRequest(method: string, params: unknown, id: number): unknown {
397
+ return { m: method, p: params, i: id };
398
+ }
399
+
400
+ encodeResponse(result: unknown, id: number): unknown {
401
+ return { r: result, i: id };
402
+ }
403
+
404
+ // ... implement other methods
405
+ }
406
+ ```
407
+
408
+ ### Channels
409
+
410
+ #### RequestChannel
411
+
412
+ High-level channel for request/response communication.
413
+
414
+ ```typescript
415
+ import type { Channel } from "@procwire/transport/channel";
416
+
417
+ // Send request
418
+ const result = await channel.request<number>("add", { a: 2, b: 3 });
419
+
420
+ // Send notification (no response)
421
+ channel.notify("log", { message: "Hello" });
422
+
423
+ // Handle incoming requests
424
+ channel.onRequest("multiply", async (params) => {
425
+ return params.a * params.b;
426
+ });
427
+
428
+ // Handle incoming notifications
429
+ channel.onNotification("shutdown", () => {
430
+ process.exit(0);
431
+ });
432
+
433
+ // Lifecycle
434
+ await channel.start();
435
+ await channel.close();
436
+ ```
437
+
438
+ #### ChannelBuilder
439
+
440
+ Fluent API for building channels.
441
+
442
+ ```typescript
443
+ import { ChannelBuilder } from "@procwire/transport";
444
+
445
+ const channel = new ChannelBuilder()
446
+ .withTransport(transport)
447
+ .withFraming(framing)
448
+ .withSerialization(serialization)
449
+ .withProtocol(protocol)
450
+ .withTimeout(5000)
451
+ .build();
452
+ ```
453
+
454
+ ### Process Management
455
+
456
+ #### ProcessManager
457
+
458
+ Manages multiple child processes with restart policies.
459
+
460
+ ```typescript
461
+ import { ProcessManager } from "@procwire/transport";
462
+
463
+ const manager = new ProcessManager({
464
+ defaultTimeout: 30000,
465
+ namespace: "my-app",
466
+ restartPolicy: {
467
+ enabled: true,
468
+ maxRestarts: 3,
469
+ backoffMs: 1000,
470
+ maxBackoffMs: 30000,
471
+ },
472
+ gracefulShutdownMs: 5000,
473
+ });
474
+
475
+ // Spawn process
476
+ const handle = await manager.spawn("worker-1", {
477
+ executablePath: "node",
478
+ args: ["worker.js"],
479
+ cwd: process.cwd(),
480
+ env: { ...process.env },
481
+
482
+ controlChannel: {
483
+ // Optional channel config
484
+ },
485
+
486
+ dataChannel: {
487
+ enabled: true,
488
+ path: "/tmp/custom-path.sock", // Optional, auto-generated if omitted
489
+ channel: {
490
+ framing: "length-prefixed",
491
+ serialization: new MessagePackCodec(),
492
+ },
493
+ },
494
+
495
+ restartPolicy: {
496
+ enabled: true,
497
+ maxRestarts: 5,
498
+ },
499
+ });
500
+
501
+ // Events
502
+ manager.on("spawn", ({ id }) => console.log(`Spawned: ${id}`));
503
+ manager.on("ready", ({ id }) => console.log(`Ready: ${id}`));
504
+ manager.on("exit", ({ id, code }) => console.log(`Exited: ${id} (${code})`));
505
+ manager.on("restart", ({ id, attempt }) => console.log(`Restart: ${id} (${attempt})`));
506
+ manager.on("error", ({ id, error }) => console.log(`Error: ${id}`, error));
507
+
508
+ // Stop process
509
+ await manager.stop("worker-1");
510
+
511
+ // Stop all
512
+ await manager.stopAll();
513
+ ```
514
+
515
+ #### ProcessHandle
516
+
517
+ Handle to managed process with dual-channel support.
518
+
519
+ ```typescript
520
+ // Control channel (default)
521
+ const status = await handle.request("getStatus");
522
+
523
+ // Data channel
524
+ const result = await handle.requestViaData("processItems", { items: [...] });
525
+
526
+ // Notifications
527
+ handle.notify("config", { key: "value" });
528
+
529
+ // Events
530
+ handle.on("exit", ({ code }) => console.log(`Exited: ${code}`));
531
+
532
+ // Stop
533
+ await handle.stop();
534
+ ```
535
+
536
+ ## Utilities
537
+
538
+ ### PipePath
539
+
540
+ Generate platform-specific pipe/socket paths.
541
+
542
+ ```typescript
543
+ import { PipePath } from "@procwire/transport/utils";
544
+
545
+ // Auto-generated path
546
+ const path = PipePath.forModule("my-app", "worker-1");
547
+ // Windows: \\.\pipe\my-app-worker-1
548
+ // Unix: /tmp/my-app-worker-1.sock
549
+
550
+ // Validate path
551
+ const isValid = PipePath.isValid(path);
552
+
553
+ // Cleanup (Unix only)
554
+ await PipePath.cleanup(path);
555
+ ```
556
+
557
+ ### Platform Detection
558
+
559
+ ```typescript
560
+ import { isWindows, getProcessId } from "@procwire/transport/utils";
561
+
562
+ if (isWindows()) {
563
+ // Windows-specific logic
564
+ }
565
+
566
+ const pid = getProcessId();
567
+ ```
568
+
569
+ ## Platform Notes
570
+
571
+ ### Windows Named Pipes
572
+
573
+ - **Path format**: `\\\\.\\pipe\\<name>`
574
+ - **Namespace**: Global by default
575
+ - **Permissions**: Controlled by ACLs
576
+ - **Cleanup**: Automatic on server close
577
+
578
+ Example:
579
+ ```typescript
580
+ const path = "\\\\.\\pipe\\my-app-worker-1";
581
+ ```
582
+
583
+ ### Unix Domain Sockets
584
+
585
+ - **Path format**: Absolute path (e.g., `/tmp/socket.sock`)
586
+ - **Max length**: 108 characters (Linux), 104 (macOS)
587
+ - **Permissions**: File system permissions (chmod)
588
+ - **Cleanup**: Manual (remove socket file)
589
+
590
+ Example:
591
+ ```typescript
592
+ const path = "/tmp/my-app-worker-1.sock";
593
+
594
+ // Cleanup stale socket
595
+ const server = new SocketServer({ unlinkOnListen: true });
596
+ await server.listen(path);
597
+ ```
598
+
599
+ ### Path Recommendations
600
+
601
+ - **Development**: Use `/tmp/` on Unix, `\\\\.\\pipe\\` on Windows
602
+ - **Production**: Use app-specific directory with proper permissions
603
+ - **Multiple instances**: Include PID or unique ID in path
604
+
605
+ ```typescript
606
+ import { tmpdir } from "os";
607
+ import { join } from "path";
608
+
609
+ const path = isWindows()
610
+ ? `\\\\.\\pipe\\my-app-${process.pid}`
611
+ : join(tmpdir(), `my-app-${process.pid}.sock`);
612
+ ```
613
+
614
+ ## Troubleshooting
615
+
616
+ ### Hanging Requests
617
+
618
+ **Symptoms**: `channel.request()` never resolves.
619
+
620
+ **Common causes**:
621
+ 1. **Framing mismatch**: Parent uses line-delimited, child uses length-prefixed
622
+ 2. **Codec mismatch**: Parent uses JSON, child uses MessagePack
623
+ 3. **Protocol mismatch**: Parent uses JSON-RPC, child uses custom protocol
624
+ 4. **Child not responding**: Child crashed or deadlocked
625
+
626
+ **Solutions**:
627
+ - Verify both sides use identical framing/codec/protocol
628
+ - Check child process stderr for errors
629
+ - Add timeout to requests: `{ timeout: 5000 }`
630
+ - Enable debug logging (see below)
631
+
632
+ ### Connection Refused (ECONNREFUSED)
633
+
634
+ **Symptoms**: `SocketTransport.connect()` fails with ECONNREFUSED.
635
+
636
+ **Common causes**:
637
+ 1. Server not listening yet
638
+ 2. Wrong path
639
+ 3. Stale socket file (Unix)
640
+
641
+ **Solutions**:
642
+ ```typescript
643
+ // Increase connection timeout
644
+ const transport = new SocketTransport({
645
+ path: "/tmp/socket.sock",
646
+ connectionTimeout: 10000, // Wait up to 10s
647
+ });
648
+
649
+ // Or cleanup stale sockets
650
+ const server = new SocketServer({ unlinkOnListen: true });
651
+ ```
652
+
653
+ ### Buffer Limits Exceeded
654
+
655
+ **Symptoms**: Errors about message size or buffer limits.
656
+
657
+ **Common causes**:
658
+ - Message exceeds `maxMessageSize` (length-prefixed)
659
+ - Line exceeds `maxLineLength` (line-delimited)
660
+
661
+ **Solutions**:
662
+ ```typescript
663
+ // Increase limits
664
+ const framing = new LengthPrefixedFraming({
665
+ maxMessageSize: 100 * 1024 * 1024, // 100MB
666
+ });
667
+
668
+ // Or split large messages
669
+ const chunks = splitIntoChunks(largeData, 1024 * 1024);
670
+ for (const chunk of chunks) {
671
+ await channel.request("processChunk", chunk);
672
+ }
673
+ ```
674
+
675
+ ### Worker Crashes on Startup
676
+
677
+ **Symptoms**: `ProcessManager.spawn()` fails or worker exits immediately.
678
+
679
+ **Common causes**:
680
+ 1. Syntax error in worker code
681
+ 2. Missing dependencies
682
+ 3. Wrong executable path
683
+
684
+ **Solutions**:
685
+ - Test worker standalone: `node worker.js`
686
+ - Check stderr: `startupTimeout` should be long enough
687
+ - Verify executable path and args
688
+
689
+ ### Memory Leaks
690
+
691
+ **Symptoms**: Memory usage grows over time.
692
+
693
+ **Common causes**:
694
+ - Unclosed channels
695
+ - Unremoved event listeners
696
+ - Buffered data not consumed
697
+
698
+ **Solutions**:
699
+ ```typescript
700
+ // Always close channels
701
+ try {
702
+ await channel.request(...);
703
+ } finally {
704
+ await channel.close();
705
+ }
706
+
707
+ // Remove listeners
708
+ const unsub = channel.onNotification("log", handler);
709
+ // Later...
710
+ unsub();
711
+
712
+ // Set maxListeners if needed
713
+ channel.setMaxListeners(100);
714
+ ```
715
+
716
+ ## Debugging
717
+
718
+ ### Enable Debug Logging
719
+
720
+ ```typescript
721
+ // Set environment variable
722
+ process.env.DEBUG = "@procwire:*";
723
+
724
+ // Or programmatically (if debug package is used in future)
725
+ ```
726
+
727
+ ### Inspect Raw Data
728
+
729
+ ```typescript
730
+ import { inspect } from "util";
731
+
732
+ transport.onData((data) => {
733
+ console.error("Raw data:", inspect(data, { depth: null }));
734
+ });
735
+ ```
736
+
737
+ ### Test Worker Standalone
738
+
739
+ Test child process independently:
740
+
741
+ ```bash
742
+ # Send JSON-RPC request manually
743
+ echo '{"jsonrpc":"2.0","id":1,"method":"add","params":{"a":2,"b":3}}' | node worker.js
744
+ ```
745
+
746
+ ## Examples
747
+
748
+ See the [examples/](../../examples/) directory for complete, runnable examples:
749
+
750
+ - [basic-stdio](../../examples/basic-stdio/) - Simple parent/child with stdio
751
+ - [dual-channel](../../examples/dual-channel/) - Control + data channels with MessagePack
752
+ - [rust-worker](../../examples/rust-worker/) - Cross-language IPC with Rust
753
+
754
+ ## Performance Tips
755
+
756
+ 1. **Choose the right framing**:
757
+ - Line-delimited: Best for text protocols (JSON-RPC over stdio)
758
+ - Length-prefixed: Best for binary protocols (MessagePack, Protobuf)
759
+
760
+ 2. **Choose the right codec**:
761
+ - JSON: Human-readable, debugging
762
+ - MessagePack: 20-50% smaller, 2-5x faster than JSON
763
+ - Protobuf: Schema validation, cross-language
764
+ - Arrow: Columnar data, analytics workloads
765
+
766
+ 3. **Use dual channels**:
767
+ - Control channel (stdio): Lightweight commands
768
+ - Data channel (pipe): Bulk data transfer
769
+
770
+ 4. **Batch requests**:
771
+ - Send multiple items in one request instead of many small requests
772
+ - Reduces protocol overhead
773
+
774
+ 5. **Reuse channels**:
775
+ - Keep channels open for multiple requests
776
+ - Avoid spawning processes repeatedly
777
+
778
+ 6. **Monitor resource usage**:
779
+ - Track memory with `process.memoryUsage()`
780
+ - Profile CPU with `--prof` flag
781
+ - Use `clinic` for performance analysis
782
+
783
+ ## TypeScript
784
+
785
+ Full TypeScript support with generics:
786
+
787
+ ```typescript
788
+ interface User {
789
+ id: number;
790
+ name: string;
791
+ }
792
+
793
+ // Typed request
794
+ const user = await channel.request<User>("getUser", { id: 123 });
795
+ console.log(user.name); // Type-safe
796
+
797
+ // Typed handler
798
+ channel.onRequest<{ id: number }, User>("getUser", async (params) => {
799
+ // params.id is number
800
+ return { id: params.id, name: "Alice" }; // Must return User
801
+ });
802
+ ```
803
+
804
+ ## Contributing
805
+
806
+ See [CONTRIBUTING.md](../CONTRIBUTING.md) for development setup and guidelines.
807
+
808
+ ## License
809
+
810
+ MIT - See [LICENSE](../LICENSE) for details.
811
+
812
+ ## Roadmap
813
+
814
+ ### v0.1.0 (Current)
815
+ - Core transport, framing, serialization, protocol layers
816
+ - Stdio and pipe/socket transports
817
+ - JSON-RPC 2.0 and simple protocols
818
+ - ProcessManager with restart policies
819
+ - Optional codecs: MessagePack, Protobuf, Arrow
820
+
821
+ ### v0.2.0 (Planned)
822
+ - HTTP/WebSocket transports
823
+ - Streaming support
824
+ - Compression layer (gzip, brotli)
825
+ - Authentication/authorization hooks
826
+ - Metrics and monitoring
827
+
828
+ ### v1.0.0 (Future)
829
+ - Production-ready stable API
830
+ - Performance optimizations
831
+ - Comprehensive docs and examples
832
+ - Battle-tested in production
833
+
834
+ ## Related Packages
835
+
836
+ - [@procwire/codec-msgpack](../codec-msgpack/) - MessagePack serialization
837
+ - [@procwire/codec-protobuf](../codec-protobuf/) - Protocol Buffers serialization
838
+ - [@procwire/codec-arrow](../codec-arrow/) - Apache Arrow serialization
839
+
840
+ ## Support
841
+
842
+ - **Issues**: [GitHub Issues](https://github.com/your-org/ipc-bridge-core/issues)
843
+ - **Discussions**: [GitHub Discussions](https://github.com/your-org/ipc-bridge-core/discussions)
844
+ - **Documentation**: [Architecture Docs](../docs/procwire-transport-architecture.md)