@bakit/service 3.2.1 → 4.0.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.
package/dist/index.js CHANGED
@@ -1,29 +1,120 @@
1
- import { createServer, createConnection } from 'net';
2
- import { join } from 'path';
3
- import { existsSync, rmSync } from 'fs';
4
- import { pack, unpack } from 'msgpackr';
5
- import PQueue from 'p-queue';
6
- import { attachEventBus, Collection, isPlainObject } from '@bakit/utils';
1
+ import EventEmitter from 'events';
2
+ import { createConnection, createServer } from 'net';
3
+ import { Queue, Collection, instanceToObject, isPlainObject, glob, sleep } from '@bakit/utils';
4
+ import { existsSync, unlinkSync } from 'fs';
5
+ import { dirname, join, resolve, relative, normalize, sep } from 'path';
7
6
  import { randomUUID } from 'crypto';
7
+ import { fork } from 'child_process';
8
+ import { fileURLToPath } from 'url';
8
9
 
9
- // src/lib/driver/ipc.ts
10
- var UNIX_SOCKET_DIR = "/tmp", WINDOWS_PIPE_PREFIX = "\\\\.\\pipe\\", SocketState = {
11
- Idle: 0,
12
- Connecting: 1,
13
- Connected: 2,
14
- Disconnected: 3,
15
- Reconnecting: 4,
16
- Destroyed: 5
17
- }, IPCServerState = {
18
- Idle: 0,
19
- Listening: 1,
20
- Closed: 2
21
- }, DEFAULT_IPC_SOCKET_CONNECTION_OPTIONS = {
22
- autoReconnect: true,
23
- maxReconnectAttempts: 10,
24
- reconnectDelay: 5e3,
25
- requestConcurrency: 10
10
+ // src/lib/FrameCodec.ts
11
+ var SUPPORTED_LENGTH_BYTES = [1, 2, 4, 8], DEFAULT_OPTIONS = {
12
+ maxBufferSize: 16 * 1024 * 1024,
13
+ maxFrameSize: 16 * 1024 * 1024,
14
+ lengthBytes: 4,
15
+ endian: "big",
16
+ lengthIncludesHeader: false
17
+ }, FrameCodec = class _FrameCodec {
18
+ buffer = Buffer.alloc(0);
19
+ options;
20
+ stats = {
21
+ bytesReceived: 0,
22
+ bytesDecoded: 0,
23
+ framesDecoded: 0,
24
+ bufferCopies: 0
25
+ };
26
+ constructor(options = {}) {
27
+ if (this.options = { ...DEFAULT_OPTIONS, ...options }, !SUPPORTED_LENGTH_BYTES.includes(this.options.lengthBytes))
28
+ throw new Error("lengthBytes must be 1, 2, 4, or 8");
29
+ }
30
+ push(chunk) {
31
+ if (chunk.length === 0) return [];
32
+ if (this.stats.bytesReceived += chunk.length, this.buffer.length + chunk.length > this.options.maxBufferSize)
33
+ throw this.reset(), new Error(`Buffer overflow: ${this.buffer.length + chunk.length} > ${this.options.maxBufferSize}`);
34
+ this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
35
+ let frames = [], headerSize = this.options.lengthBytes;
36
+ for (; this.buffer.length >= headerSize; ) {
37
+ let lengthField = this.readLength(this.buffer), [payloadLength, frameLength] = this.options.lengthIncludesHeader ? [lengthField - headerSize, lengthField] : [lengthField, headerSize + lengthField];
38
+ if (payloadLength < 0 || payloadLength > this.options.maxFrameSize)
39
+ throw this.reset(), new Error(`Invalid frame size: ${payloadLength}`);
40
+ if (this.buffer.length < frameLength)
41
+ break;
42
+ frames.push(this.buffer.subarray(headerSize, frameLength)), this.stats.framesDecoded++, this.stats.bytesDecoded += payloadLength, this.buffer = frameLength === this.buffer.length ? Buffer.alloc(0) : this.buffer.subarray(frameLength);
43
+ }
44
+ return this.buffer.byteOffset > 1024 * 1024 && (this.buffer = Buffer.from(this.buffer), this.stats.bufferCopies++), frames;
45
+ }
46
+ get bufferedBytes() {
47
+ return this.buffer.length;
48
+ }
49
+ reset() {
50
+ this.buffer = Buffer.alloc(0), this.stats.bytesReceived = 0, this.stats.bytesDecoded = 0, this.stats.framesDecoded = 0, this.stats.bufferCopies = 0;
51
+ }
52
+ readLength(buf) {
53
+ let big = this.options.endian === "big";
54
+ switch (this.options.lengthBytes) {
55
+ case 1:
56
+ return buf.readUInt8(0);
57
+ case 2:
58
+ return big ? buf.readUInt16BE(0) : buf.readUInt16LE(0);
59
+ case 4:
60
+ return big ? buf.readUInt32BE(0) : buf.readUInt32LE(0);
61
+ case 8: {
62
+ let val = big ? buf.readBigUInt64BE(0) : buf.readBigUInt64LE(0);
63
+ if (val > BigInt(Number.MAX_SAFE_INTEGER))
64
+ throw new Error("Frame size exceeds safe integer range");
65
+ return Number(val);
66
+ }
67
+ }
68
+ }
69
+ encode(payload) {
70
+ return _FrameCodec.encode(payload, this.options);
71
+ }
72
+ static encode(payload, options) {
73
+ let opts = { ...DEFAULT_OPTIONS, ...options }, { lengthBytes, endian, lengthIncludesHeader } = opts, headerSize = lengthBytes, payloadSize = payload.length, totalFrameSize = lengthIncludesHeader ? headerSize + payloadSize : payloadSize, maxLength = 2 ** (lengthBytes * 8) - 1;
74
+ if (totalFrameSize > maxLength)
75
+ throw new Error(`Frame size ${totalFrameSize} exceeds maximum ${maxLength} for ${lengthBytes}-byte length field`);
76
+ let header = Buffer.allocUnsafe(headerSize), big = endian === "big";
77
+ switch (lengthBytes) {
78
+ case 1:
79
+ header.writeUInt8(totalFrameSize, 0);
80
+ break;
81
+ case 2:
82
+ header[big ? "writeUInt16BE" : "writeUInt16LE"](totalFrameSize, 0);
83
+ break;
84
+ case 4:
85
+ header[big ? "writeUInt32BE" : "writeUInt32LE"](totalFrameSize, 0);
86
+ break;
87
+ case 8: {
88
+ header[big ? "writeBigUInt64BE" : "writeBigUInt64LE"](BigInt(totalFrameSize), 0);
89
+ break;
90
+ }
91
+ default:
92
+ throw new Error(`Unsupported lengthBytes: ${lengthBytes}`);
93
+ }
94
+ return Buffer.concat([header, payload]);
95
+ }
96
+ static serialize(obj) {
97
+ return Buffer.from(JSON.stringify(obj));
98
+ }
99
+ static deserialize(buf) {
100
+ return JSON.parse(buf.toString());
101
+ }
26
102
  };
103
+ var BaseDriver = class extends EventEmitter {
104
+ constructor(options) {
105
+ super();
106
+ this.options = options;
107
+ }
108
+ }, BaseClientDriver = class extends BaseDriver {
109
+ constructor(options) {
110
+ super(options);
111
+ }
112
+ }, BaseServerDriver = class extends BaseDriver {
113
+ constructor(options) {
114
+ super(options);
115
+ }
116
+ };
117
+ var WINDOWS_PIPE_PREFIX = "\\\\.\\pipe\\", UNIX_SOCKET_DIR = "/tmp";
27
118
  function getIPCPath(id, platform = process.platform) {
28
119
  switch (platform) {
29
120
  case "win32":
@@ -32,391 +123,604 @@ function getIPCPath(id, platform = process.platform) {
32
123
  return join(UNIX_SOCKET_DIR, `${id}.sock`);
33
124
  }
34
125
  }
35
- function createIPCClient(options) {
36
- let ipcPath = getIPCPath(options.id, options.platform);
37
- return createIPCSocketConnection(ipcPath, options.connection);
38
- }
39
- function createIPCServer(options) {
40
- let ipcPath = getIPCPath(options.id, options.platform), clients = /* @__PURE__ */ new Set(), state = IPCServerState.Idle, self = attachEventBus({
41
- listen,
42
- close,
43
- broadcast,
44
- send,
45
- get state() {
46
- return state;
126
+ function isServerRunning(path) {
127
+ return new Promise((resolve2) => {
128
+ if (!existsSync(path)) {
129
+ resolve2(false);
130
+ return;
47
131
  }
48
- }), server = createServer((socket) => {
49
- clients.add(socket);
50
- let handler = createIPCSocketMessageHandler({
51
- onMessage: (msg) => self.emit("message", socket, msg),
52
- onWrite: (chunk) => writeSocket(socket, chunk)
132
+ let socket = createConnection(path), timer = setTimeout(() => {
133
+ socket.destroy(), resolve2(false);
134
+ }, 500);
135
+ socket.once("connect", () => {
136
+ clearTimeout(timer), socket.destroy(), resolve2(true);
137
+ }), socket.once("error", () => {
138
+ clearTimeout(timer), socket.destroy(), resolve2(false);
53
139
  });
54
- socket.on("data", handler.handleData), socket.on("error", (err) => self.emit("clientError", socket, err)), socket.on("close", () => {
55
- clients.delete(socket), self.emit("clientDisconnect", socket);
56
- }), self.emit("clientConnect", socket);
57
140
  });
58
- server.on("listening", () => {
59
- state = IPCServerState.Listening, self.emit("listen");
60
- }), server.on("close", () => {
61
- state = IPCServerState.Closed, self.emit("close");
141
+ }
142
+
143
+ // src/lib/drivers/ipc/IPCClient.ts
144
+ var IPCClientState = /* @__PURE__ */ ((IPCClientState2) => (IPCClientState2[IPCClientState2.Idle = 0] = "Idle", IPCClientState2[IPCClientState2.Connecting = 1] = "Connecting", IPCClientState2[IPCClientState2.Connected = 2] = "Connected", IPCClientState2[IPCClientState2.Disconnected = 3] = "Disconnected", IPCClientState2))(IPCClientState || {}), DEFAULT_IPC_CLIENT_RECONNECT_OPTIONS = {
145
+ enabled: true,
146
+ maxRetries: 5,
147
+ initialDelay: 1e3,
148
+ backoff: 1.5,
149
+ maxDelay: 3e4
150
+ }, IPCClient = class extends BaseClientDriver {
151
+ socket;
152
+ codec;
153
+ state = 0 /* Idle */;
154
+ _ready = false;
155
+ reconnectTimer;
156
+ reconnectOptions;
157
+ reconnectAttempt = 0;
158
+ isIntentionalClose = false;
159
+ queue = new Queue({
160
+ concurrency: 1,
161
+ autoStart: false
62
162
  });
63
- function listen() {
64
- existsSync(ipcPath) && rmSync(ipcPath), server.listen(ipcPath);
163
+ constructor(options) {
164
+ super(options), this.codec = new FrameCodec(options.codec), this.reconnectOptions = { ...DEFAULT_IPC_CLIENT_RECONNECT_OPTIONS, ...options.reconnect };
65
165
  }
66
- function close() {
67
- server.close();
166
+ get path() {
167
+ return getIPCPath(this.options.id);
68
168
  }
69
- function writeSocket(socket, chunk) {
70
- if (!socket.writable)
71
- return;
72
- socket.write(chunk) || socket.once("drain", () => self.emit("drain", socket));
73
- }
74
- function broadcast(message) {
75
- let payload = pack(message), header = Buffer.alloc(4);
76
- header.writeUInt32LE(payload.length);
77
- let packet = Buffer.concat([header, payload]);
78
- for (let socket of clients)
79
- writeSocket(socket, packet);
80
- }
81
- function send(socket, message) {
82
- let payload = pack(message), header = Buffer.alloc(4);
83
- header.writeUInt32LE(payload.length);
84
- let packet = Buffer.concat([header, payload]);
85
- writeSocket(socket, packet);
86
- }
87
- return self;
88
- }
89
- function createIPCSocketConnection(socketPath, options = {}) {
90
- let resolvedOptions = { ...DEFAULT_IPC_SOCKET_CONNECTION_OPTIONS, ...options }, handler = createIPCSocketMessageHandler({
91
- onMessage: (message) => connection.emit("message", message),
92
- onWrite: write
93
- }), queue = new PQueue({
94
- concurrency: resolvedOptions.requestConcurrency,
95
- autoStart: true
96
- });
97
- queue.pause();
98
- let socket, state = SocketState.Idle, isConnecting = false, shouldReconnect = resolvedOptions.autoReconnect, reconnectAttempts = 0, reconnectTimeout, connection = attachEventBus({
99
- ...handler,
100
- connect,
101
- disconnect,
102
- destroy,
103
- reconnect,
104
- write,
105
- get state() {
106
- return state;
107
- },
108
- get ready() {
109
- return state === SocketState.Connected;
110
- }
111
- });
112
- function connect() {
113
- if (state === SocketState.Destroyed) {
114
- connection.emit("error", new Error("Cannot start a new socket after destroyed."));
169
+ get ready() {
170
+ return this._ready;
171
+ }
172
+ connect() {
173
+ if (this.socket)
174
+ throw new Error(`Socket is already connected to '${this.options.id}'.`);
175
+ return new Promise((resolve2, reject) => {
176
+ this.once("connect", resolve2), this.init().catch(reject);
177
+ });
178
+ }
179
+ send(message) {
180
+ return this.queue.add(() => this.makeMessage(message));
181
+ }
182
+ disconnect() {
183
+ return new Promise((resolve2) => {
184
+ if (!this.socket || this.state === 0 /* Idle */) {
185
+ resolve2();
186
+ return;
187
+ }
188
+ this.once("disconnect", resolve2), this.isIntentionalClose = true, this.cleanup(true);
189
+ });
190
+ }
191
+ async init() {
192
+ if (this.socket)
193
+ throw new Error(`Socket is already connected to '${this.options.id}'.`);
194
+ this.state = 1 /* Connecting */, this.socket = createConnection(this.path), this.socket.on("connect", () => this.onSocketConnect()), this.socket.on("data", (data) => this.onSocketData(data)), this.socket.on("close", () => this.onSocketClose()), this.socket.on("error", (err) => this.onSocketError(err));
195
+ }
196
+ cleanup(hard = false) {
197
+ this.reconnectAttempt = 0, this.clearReconnectTimer(), this.queue.pause(), hard && this.queue.clear(), this.socket && (this.socket.destroyed || this.socket.destroy(), this.socket = void 0), this.state = 3 /* Disconnected */;
198
+ }
199
+ onSocketConnect() {
200
+ this.state = 2 /* Connected */;
201
+ let isReconnected = this.reconnectAttempt > 0 && this.ready;
202
+ this.reconnectAttempt = 0, this._ready = true, this.isIntentionalClose = false, this.queue.start(), isReconnected ? this.emit("reconnect") : this.emit("connect");
203
+ }
204
+ onSocketClose() {
205
+ if (this.isIntentionalClose) {
206
+ this.emit("disconnect");
115
207
  return;
116
208
  }
117
- if (state === SocketState.Connected || state === SocketState.Connecting) {
118
- connection.emit("error", new Error("The current socket is still running, use reconnect() instead."));
119
- return;
209
+ let shouldReconnect = this.reconnectOptions.enabled && (this.state === 2 /* Connected */ || this.reconnectAttempt < this.reconnectOptions.maxRetries);
210
+ this.cleanup(), shouldReconnect ? this.scheduleReconnect() : this.emit("disconnect");
211
+ }
212
+ onSocketError(err) {
213
+ "code" in err && (err.code === "ECONNREFUSED" || err.code === "ENOENT") || this.emit("error", err);
214
+ }
215
+ onSocketData(chunk) {
216
+ let packets = this.codec.push(chunk);
217
+ for (let packet of packets) {
218
+ let message = this.deserialize(packet);
219
+ this.emit("message", message);
120
220
  }
121
- if (isConnecting) {
122
- connection.emit("error", new Error("connect() shouldn't be called more than once."));
221
+ }
222
+ scheduleReconnect() {
223
+ if (this.reconnectAttempt >= this.reconnectOptions.maxRetries) {
224
+ this.emit("error", new Error(`Reconnect failed after ${this.reconnectOptions.maxRetries} attempts`)), this.disconnect();
123
225
  return;
124
226
  }
125
- state !== SocketState.Reconnecting && (state = SocketState.Connecting), isConnecting = true, socket = createConnection(socketPath), initSocket();
227
+ let delay = Math.min(
228
+ this.reconnectOptions.initialDelay * Math.pow(this.reconnectOptions.backoff, this.reconnectAttempt),
229
+ this.reconnectOptions.maxDelay
230
+ );
231
+ this.reconnectAttempt++, this.emit("reconnecting", this.reconnectAttempt, delay), this.reconnectTimer = setTimeout(() => {
232
+ this.init().catch((err) => {
233
+ this.emit("error", err);
234
+ });
235
+ }, delay);
126
236
  }
127
- function initSocket() {
128
- socket && (socket.on("connect", handleConnect), socket.on("data", handler.handleData), socket.on("error", handleError), socket.on("close", handleClose));
237
+ clearReconnectTimer() {
238
+ this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = void 0);
129
239
  }
130
- function handleConnect() {
131
- state = SocketState.Connected, isConnecting = false, reconnectAttempts = 0, shouldReconnect = resolvedOptions.autoReconnect, queue.start(), connection.emit("connect");
240
+ makeMessage(message) {
241
+ let { socket } = this;
242
+ if (!socket || socket.destroyed)
243
+ return Promise.reject(new Error("Socket not available"));
244
+ let payload = this.serialize(message), frame = this.codec.encode(payload);
245
+ return new Promise((resolve2, reject) => {
246
+ socket.write(frame, (err) => {
247
+ err ? reject(err) : resolve2();
248
+ });
249
+ });
132
250
  }
133
- function handleError(error) {
134
- error.code === "ECONNREFUSED" || error.code === "ENOENT" || connection.emit("error", error);
251
+ serialize(obj) {
252
+ return Buffer.from(JSON.stringify(obj));
135
253
  }
136
- function handleClose() {
137
- state = SocketState.Disconnected, queue.pause(), isConnecting = false, connection.emit("disconnect"), scheduleReconnect();
254
+ deserialize(buf) {
255
+ return JSON.parse(buf.toString());
138
256
  }
139
- function scheduleReconnect() {
140
- shouldReconnect && (resolvedOptions.maxReconnectAttempts > 0 && reconnectAttempts >= resolvedOptions.maxReconnectAttempts && (connection.emit("error", new Error(`Max reconnect attempts (${resolvedOptions.maxReconnectAttempts}) exceeded`)), state = SocketState.Disconnected), reconnectTimeout && (clearTimeout(reconnectTimeout), reconnectTimeout = void 0), reconnectTimeout = setTimeout(() => {
141
- reconnectTimeout = void 0, reconnect();
142
- }, resolvedOptions.reconnectDelay));
257
+ };
258
+ function createIPCClient(options) {
259
+ return new IPCClient(options);
260
+ }
261
+ var IPCConnection = class extends EventEmitter {
262
+ constructor(server, socket) {
263
+ super();
264
+ this.server = server;
265
+ this.socket = socket;
266
+ this.codec = new FrameCodec(server.codecOptions), this.setupListeners();
143
267
  }
144
- function reconnect() {
145
- state === SocketState.Destroyed || state === SocketState.Reconnecting || (reconnectAttempts++, state = SocketState.Reconnecting, cleanupSocket(), connect());
268
+ codec;
269
+ send(message) {
270
+ return this.server.sendSocket(this.socket, message);
146
271
  }
147
- function disconnect() {
148
- state = SocketState.Disconnected, shouldReconnect = false, cleanupSocket();
272
+ destroy() {
273
+ this.socket.destroy();
149
274
  }
150
- function destroy() {
151
- state = SocketState.Destroyed, shouldReconnect = false, queue.clear(), connection.removeAllListeners(), cleanupSocket();
275
+ setupListeners() {
276
+ this.socket.on("data", (chunk) => this.handleData(chunk)), this.socket.on("close", () => this.emit("close")), this.socket.on("error", (err) => this.emit("error", err));
152
277
  }
153
- function cleanupSocket() {
154
- queue.pause(), reconnectTimeout && (clearTimeout(reconnectTimeout), reconnectTimeout = void 0), socket && (socket.removeAllListeners(), socket.destroyed || socket.destroy(), socket = void 0);
278
+ handleData(chunk) {
279
+ try {
280
+ let packets = this.codec.push(chunk);
281
+ for (let packet of packets) {
282
+ let message = FrameCodec.deserialize(packet);
283
+ this.emit("message", message);
284
+ }
285
+ } catch (err) {
286
+ this.emit("error", err);
287
+ }
155
288
  }
156
- function write(chunk) {
157
- queue.add(() => new Promise((resolve, reject) => {
158
- if (!socket || !socket.writable)
159
- return resolve();
160
- let done = false, safeResolve = () => {
161
- done || (done = true, resolve());
162
- }, safeReject = (err) => {
163
- done || (done = true, reject(err));
164
- }, ok = socket.write(chunk, (err) => {
165
- err ? safeReject(err) : ok && safeResolve();
166
- });
167
- ok || socket.once("drain", safeResolve);
168
- }));
289
+ };
290
+ var IPCServer = class extends BaseServerDriver {
291
+ server;
292
+ codecOptions;
293
+ connections = new Collection();
294
+ codec;
295
+ constructor(options) {
296
+ super(options), this.codecOptions = options.codec ?? {}, this.codec = new FrameCodec(this.codecOptions);
169
297
  }
170
- return connection;
171
- }
172
- function createIPCSocketMessageHandler(options) {
173
- let buffer = Buffer.alloc(0);
174
- function handleData(chunk) {
175
- for (buffer = Buffer.concat([buffer, chunk]); !(buffer.length < 4); ) {
176
- let messageLength = buffer.readUInt32LE(0);
177
- if (buffer.length < 4 + messageLength)
178
- break;
179
- let payload = buffer.subarray(4, 4 + messageLength);
298
+ get path() {
299
+ return getIPCPath(this.options.id);
300
+ }
301
+ async listen() {
302
+ if (this.server)
303
+ throw new Error(`Server '${this.options.id}' is already listening`);
304
+ let { path } = this;
305
+ if (await isServerRunning(path))
306
+ throw new Error(`Server '${this.options.id}' is already running at ${path}`);
307
+ if (process.platform !== "win32")
180
308
  try {
181
- let message = unpack(payload);
182
- options.onMessage(message);
183
- } catch (error) {
184
- console.error("Failed to unpack message:", error);
309
+ unlinkSync(path);
310
+ } catch {
185
311
  }
186
- buffer = buffer.subarray(4 + messageLength);
187
- }
312
+ return new Promise((resolve2, reject) => {
313
+ this.server = createServer((socket) => this.handleConnection(socket)), this.server.on("error", (err) => {
314
+ err.code === "EADDRINUSE" ? reject(new Error(`Address already in use: ${path}. Is another server running?`)) : reject(err);
315
+ }), this.server.listen(path, () => {
316
+ this.emit("listen"), resolve2();
317
+ });
318
+ });
188
319
  }
189
- function send(message) {
190
- let payload = pack(message), header = Buffer.alloc(4);
191
- header.writeUInt32LE(payload.length);
192
- let packet = Buffer.concat([header, payload]);
193
- options.onWrite(packet);
320
+ handleConnection(socket) {
321
+ let connection = new IPCConnection(this, socket);
322
+ this.connections.set(socket, connection), this.emit("connectionAdd", connection), connection.on("message", (message) => this.emit("message", connection, message)), connection.on("error", (err) => this.emit("connectionError", connection, err)), connection.on("close", () => {
323
+ this.connections.delete(socket), this.emit("connectionRemove", connection);
324
+ });
194
325
  }
195
- return {
196
- handleData,
197
- send
198
- };
199
- }
200
-
201
- // src/errors/RPCError.ts
202
- var RPCError = class extends Error {
203
- code;
204
- data;
205
- constructor(message, options = {}) {
206
- super(message), this.name = "RPCError", this.code = options.code, this.data = options.data;
326
+ send(connection, message) {
327
+ return connection.send(message);
207
328
  }
329
+ /**
330
+ * Send message to a specific client
331
+ */
332
+ sendSocket(socket, message) {
333
+ let payload = FrameCodec.serialize(message), frame = this.codec.encode(payload);
334
+ return this.sendSocketFrame(socket, frame);
335
+ }
336
+ /**
337
+ * Broadcast to all connected clients
338
+ * Returns count of successful sends (fire-and-forget, errors emitted via 'clientError')
339
+ */
340
+ async broadcast(message) {
341
+ let payload = FrameCodec.serialize(message), frame = this.codec.encode(payload);
342
+ await Promise.all(this.connections.map((_, socket) => this.sendSocketFrame(socket, frame)));
343
+ }
344
+ /**
345
+ * Close server and disconnect all clients
346
+ */
347
+ close() {
348
+ return new Promise((resolve2) => {
349
+ for (let connection of this.connections.values())
350
+ connection.destroy();
351
+ if (this.connections.clear(), !this.server) {
352
+ resolve2();
353
+ return;
354
+ }
355
+ this.server.close(() => {
356
+ if (this.server = void 0, process.platform !== "win32")
357
+ try {
358
+ unlinkSync(this.path);
359
+ } catch {
360
+ }
361
+ this.emit("close"), resolve2();
362
+ });
363
+ });
364
+ }
365
+ sendSocketFrame(socket, frame) {
366
+ return new Promise((resolve2, reject) => {
367
+ if (socket.destroyed) {
368
+ reject(new Error("Socket destroyed"));
369
+ return;
370
+ }
371
+ socket.write(frame, (err) => {
372
+ err ? reject(err) : resolve2();
373
+ });
374
+ });
375
+ }
376
+ };
377
+ function createIPCServer(options) {
378
+ return new IPCServer(options);
379
+ }
380
+ var STANDARD_ERRORS = {
381
+ Error,
382
+ TypeError,
383
+ RangeError,
384
+ URIError,
385
+ SyntaxError,
386
+ ReferenceError,
387
+ EvalError
208
388
  };
209
- function serializeRPCError(error) {
210
- return error instanceof RPCError ? {
211
- message: error.message,
212
- code: error.code,
213
- data: error.data
214
- } : error instanceof Error ? {
215
- message: error.message,
216
- code: error.name
217
- } : {
218
- message: String(error)
389
+ function serializeRPCError(err) {
390
+ let serialized = {
391
+ ...instanceToObject(err),
392
+ message: err.message,
393
+ constructorName: err.constructor.name,
394
+ name: err.constructor.name,
395
+ stack: err.stack
219
396
  };
397
+ return err.cause instanceof Error && (serialized.cause = serializeRPCError(err.cause)), err instanceof AggregateError && Array.isArray(err.errors) && (serialized.errors = err.errors.map((e) => serializeRPCError(e))), serialized;
220
398
  }
221
- function deserializeRPCError(payload) {
222
- return new RPCError(payload.message, {
223
- code: payload.code,
224
- data: payload.data
225
- });
399
+ function createDynamicRPCError(data) {
400
+ let { constructorName, name, message, stack, cause, errors, ...customProps } = data;
401
+ validateConstructorName(constructorName);
402
+ let error = instantiateError(constructorName, message, errors);
403
+ return Object.assign(error, customProps), name && setProperty(error, "name", name), stack && setProperty(error, "stack", stack), cause && typeof cause == "object" && setProperty(error, "cause", createDynamicRPCError(cause)), error;
226
404
  }
227
-
228
- // src/lib/transport.ts
229
- var TransportDriver = {
230
- /**
231
- * Uses Unix Domain Sockets / Named Pipes for communications between processes.
232
- */
233
- IPC: "ipc"
234
- };
235
- function createTransportClient(options) {
236
- let driver;
237
- switch (options.driver) {
238
- case TransportDriver.IPC:
239
- driver = createIPCClient(options);
240
- }
241
- let base = {
242
- ...createTransportClientProtocol(driver),
243
- send: driver.send,
244
- connect: driver.connect,
245
- disconnect: driver.disconnect,
246
- get ready() {
247
- return driver.ready;
248
- }
249
- }, self = attachEventBus(base);
250
- return driver.on("connect", () => self.emit("connect")), driver.on("disconnect", () => self.emit("disconnect")), driver.on("error", (error) => self.emit("error", error)), self;
405
+ function validateConstructorName(name) {
406
+ if (!name || typeof name != "string")
407
+ throw new TypeError("Invalid constructorName in serialized error");
408
+ if (name.length > 100 || /[<>\\{}]/.test(name))
409
+ throw new TypeError(`Suspicious constructorName: ${name}`);
410
+ if (["__proto__", "constructor", "prototype"].includes(name))
411
+ throw new Error(`Forbidden constructor name: ${name}`);
251
412
  }
252
- function createTransportServer(options) {
253
- let driver;
254
- switch (options.driver) {
255
- case TransportDriver.IPC:
256
- driver = createIPCServer(options);
257
- }
258
- let base = {
259
- ...createTransportServerProtocol(driver),
260
- broadcast: driver.broadcast,
261
- listen: driver.listen,
262
- close: driver.close
263
- }, self = attachEventBus(base);
264
- return driver.on("listen", () => self.emit("listen")), driver.on("clientConnect", (conn) => self.emit("clientConnect", conn)), driver.on("clientDisconnect", (conn) => self.emit("clientDisconnect", conn)), driver.on("clientError", (_, error) => self.emit("error", error)), self;
413
+ function instantiateError(constructorName, message, errors) {
414
+ if (constructorName === "AggregateError") {
415
+ let childErrors = Array.isArray(errors) ? errors.map((e) => isSerializedError(e) ? createDynamicRPCError(e) : new Error(String(e))) : [];
416
+ return new AggregateError(childErrors, message);
417
+ }
418
+ if (constructorName in STANDARD_ERRORS) {
419
+ let Constructor = STANDARD_ERRORS[constructorName];
420
+ return new Constructor(message);
421
+ }
422
+ let CustomError = { [constructorName]: class extends Error {
423
+ } }[constructorName];
424
+ return new CustomError(message);
265
425
  }
266
- function createTransportClientProtocol(driver) {
267
- let requests = new Collection();
268
- driver.on("message", (message) => {
269
- if (!isResponseMessage(message))
270
- return;
271
- let entry = requests.get(message.id);
272
- entry && (requests.delete(message.id), message.error !== void 0 ? entry.reject(deserializeRPCError(message.error)) : entry.resolve(message.result));
273
- });
274
- function isResponseMessage(message) {
275
- if (!isPlainObject(message))
276
- return false;
277
- let hasType = "type" in message && message.type === "response", hasId = "id" in message && typeof message.id == "string", hasResult = "result" in message, hasError = "error" in message && message.error !== void 0;
278
- return hasType && hasId && hasResult !== hasError;
426
+ function setProperty(error, key, value) {
427
+ Object.defineProperty(error, key, { value, configurable: true, writable: true });
428
+ }
429
+ function isSerializedError(value) {
430
+ return typeof value == "object" && value !== null && "constructorName" in value && "message" in value;
431
+ }
432
+
433
+ // src/lib/transport/TransportClient.ts
434
+ var TransportClient = class extends EventEmitter {
435
+ constructor(driver) {
436
+ super();
437
+ this.driver = driver;
438
+ this.setupDriverListeners();
279
439
  }
280
- function request(method, ...args) {
281
- let requestId = randomUUID();
282
- return new Promise((resolve, reject) => {
440
+ pending = new Collection();
441
+ connect() {
442
+ return this.driver.connect();
443
+ }
444
+ disconnect() {
445
+ for (let req of this.pending.values())
446
+ clearTimeout(req.timeout), req.reject(new Error(`Disconnected while waiting for response to "${req.method}"`));
447
+ return this.pending.clear(), this.driver.disconnect();
448
+ }
449
+ request(method, ...args) {
450
+ if (!this.driver.ready)
451
+ throw new Error("Transport driver is not ready");
452
+ let id = randomUUID(), clientStack = this.captureCallStack();
453
+ return new Promise((resolve2, reject) => {
283
454
  let timeout = setTimeout(() => {
284
- let request2 = requests.get(requestId);
285
- request2 && (request2.reject(new Error("RPC timeout")), requests.delete(requestId));
286
- }, 3e4);
287
- requests.set(requestId, {
288
- resolve: (v) => {
289
- clearTimeout(timeout), resolve(v);
290
- },
291
- reject: (e) => {
292
- clearTimeout(timeout), reject(e);
293
- }
294
- }), driver.send({
295
- type: "request",
296
- id: requestId,
455
+ this.pending.delete(id), reject(new Error(`Request to "${method}" timed out`));
456
+ }, 5e3);
457
+ this.pending.set(id, {
458
+ resolve: resolve2,
459
+ reject,
460
+ timeout,
297
461
  method,
298
- args
462
+ clientStack
463
+ }), Promise.resolve(
464
+ this.driver.send({
465
+ type: "request",
466
+ id,
467
+ method,
468
+ args
469
+ })
470
+ ).catch((err) => {
471
+ clearTimeout(timeout), this.pending.delete(id), reject(err);
299
472
  });
300
473
  });
301
474
  }
302
- return {
303
- request
304
- };
475
+ send(message) {
476
+ return this.driver.send(message);
477
+ }
478
+ setupDriverListeners() {
479
+ this.driver.on("connect", () => this.emit("connect")), this.driver.on("disconnect", () => this.emit("disconnect")), this.driver.on("error", (err) => this.emit("error", err)), this.driver.on("message", (msg) => this.handleMessage(msg));
480
+ }
481
+ handleMessage(message) {
482
+ if (this.emit("message", message), !this.isResponseMessage(message))
483
+ return;
484
+ let pending = this.pending.get(message.id);
485
+ pending && (clearTimeout(pending.timeout), this.pending.delete(message.id), message.error ? pending.reject(this.hydrateError(message.error, pending.clientStack)) : pending.resolve(message.result));
486
+ }
487
+ hydrateError(errorData, callerStack) {
488
+ let err = createDynamicRPCError(errorData), serverStack = err.stack?.split(`
489
+ `).slice(1).join(`
490
+ `) ?? "", separator = `
491
+ --- Error originated on RPC server ---
492
+ `;
493
+ return err.stack = `${err}
494
+ ${callerStack}${separator}${serverStack}`, err;
495
+ }
496
+ captureCallStack() {
497
+ let dummy = new Error();
498
+ return dummy.stack ? dummy.stack.split(`
499
+ `).slice(2).join(`
500
+ `) : "";
501
+ }
502
+ isResponseMessage(message) {
503
+ if (!isPlainObject(message))
504
+ return false;
505
+ let hasType = "type" in message && message.type === "response", hasId = "id" in message && typeof message.id == "string", hasResult = "result" in message, hasError = "error" in message && message.error !== void 0;
506
+ return hasType && hasId && hasResult !== hasError;
507
+ }
508
+ };
509
+ function createTransportClient(driver) {
510
+ return new TransportClient(driver);
305
511
  }
306
- function createTransportServerProtocol(driver) {
307
- let handlers = new Collection();
308
- driver.on("message", async (connection, message) => {
309
- if (!isRequestMessage(message))
512
+ var TransportServer = class extends EventEmitter {
513
+ constructor(driver) {
514
+ super();
515
+ this.driver = driver;
516
+ this.setupDriverListeners();
517
+ }
518
+ handlers = /* @__PURE__ */ new Map();
519
+ get connections() {
520
+ return this.driver.connections;
521
+ }
522
+ handle(method, handler) {
523
+ if (this.handlers.has(method))
524
+ throw new Error(`Method ${method} is already registered`);
525
+ this.handlers.set(method, handler);
526
+ }
527
+ listen() {
528
+ return this.driver.listen();
529
+ }
530
+ close() {
531
+ return this.driver.close();
532
+ }
533
+ broadcast(message) {
534
+ return this.driver.broadcast(message);
535
+ }
536
+ setupDriverListeners() {
537
+ this.driver.on("listen", () => this.emit("listen")), this.driver.on("close", () => this.emit("close")), this.driver.on("error", (err) => this.emit("error", err)), this.driver.on("connectionAdd", (conn) => this.emit("connectionAdd", conn)), this.driver.on("connectionRemove", (conn) => this.emit("connectionRemove", conn)), this.driver.on("connectionError", (conn, err) => this.emit("connectionError", conn, err)), this.driver.on("message", (conn, msg) => this.handleMessage(conn, msg));
538
+ }
539
+ async handleMessage(connection, message) {
540
+ if (this.emit("message", connection, message), !this.isRequestMessage(message))
310
541
  return;
311
- let handler = handlers.get(message.method), sendError = (error) => {
312
- let err = error instanceof Error ? serializeRPCError(error) : error, payload = {
542
+ let handler = this.handlers.get(message.method), sendResponse = (result2, error) => {
543
+ let response = {
313
544
  type: "response",
314
545
  id: message.id,
315
- error: err
546
+ result: error ? void 0 : result2,
547
+ error: error instanceof Error ? serializeRPCError(error) : void 0
316
548
  };
317
- driver.send(connection, payload);
318
- }, sendResult = (result) => {
319
- driver.send(connection, {
320
- type: "response",
321
- id: message.id,
322
- result
549
+ Promise.resolve(this.driver.send(connection, response)).catch((err) => {
550
+ this.emit("error", new Error(`Failed to send response to ${message.method}: ${err.message}`));
323
551
  });
324
552
  };
325
- if (!handler) {
326
- sendError({ message: `Unknown method: ${message.method}` });
553
+ if (!handler || typeof handler != "function") {
554
+ sendResponse(void 0, new Error(`Unknown or invalid method: ${message.method}`));
327
555
  return;
328
556
  }
329
- try {
330
- let result = await handler(...message.args);
331
- sendResult(result);
332
- } catch (error) {
333
- sendError(error);
334
- }
335
- });
336
- function isRequestMessage(message) {
557
+ let result = await handler(...message.args);
558
+ result instanceof Error ? sendResponse(void 0, result) : sendResponse(result);
559
+ }
560
+ isRequestMessage(message) {
337
561
  if (!isPlainObject(message))
338
562
  return false;
339
563
  let hasType = "type" in message && message.type === "request", hasId = "id" in message && typeof message.id == "string", hasMethod = "method" in message && typeof message.method == "string", hasArgs = "args" in message && Array.isArray(message.args);
340
564
  return hasType && hasId && hasMethod && hasArgs;
341
565
  }
342
- function handle(method, handler) {
343
- let wrapped = (...args) => handler(...args);
344
- handlers.set(method, wrapped);
345
- }
346
- return {
347
- handle
348
- };
566
+ };
567
+ function createTransportServer(driver) {
568
+ return new TransportServer(driver);
349
569
  }
350
- var ServiceRole = {
351
- Client: "client",
352
- Server: "server"
353
- }, SERVICE_INTERNAL = Symbol("service-internal");
354
- function createService(options) {
355
- let handlers = new Collection(), runtime = { role: "unknown" }, service = {
356
- get name() {
357
- return options.name;
358
- },
359
- get role() {
360
- if (runtime.role === "unknown")
361
- throw new Error(`Service "${options.name}" is not bound`);
362
- return runtime.role;
363
- },
364
- define
365
- };
366
- function define(method, handler) {
367
- if (handlers.has(method))
570
+ var ServiceDriver = /* @__PURE__ */ ((ServiceDriver2) => (ServiceDriver2.IPC = "ipc", ServiceDriver2))(ServiceDriver || {}), Service = class {
571
+ constructor(options) {
572
+ this.options = options;
573
+ }
574
+ runtime;
575
+ handlers = /* @__PURE__ */ new Map();
576
+ binding;
577
+ get role() {
578
+ if (!this.runtime)
579
+ throw new Error("Service is not bound");
580
+ return this.runtime.role;
581
+ }
582
+ define(method, handler) {
583
+ if (this.handlers.has(method))
368
584
  throw new Error(`Service method "${method}" already defined`);
369
- return handlers.set(method, handler), (async (...args) => {
370
- if (ensureClientBound(), runtime.role === "unknown")
371
- throw new Error(`Service "${options.name}" is not bound (method "${method}")`);
372
- return runtime.role === "server" ? handler(...args) : (assertRuntimeClient(service, runtime), runtime.transport.request(method, ...args));
585
+ return this.handlers.set(method, handler), (async (...args) => {
586
+ if (await this.ensureClientBound(), !this.runtime)
587
+ throw new Error(`Service is not bound (method "${method}")`);
588
+ return this.runtime.role === "server" ? handler(...args) : this.runtime.transport.request(method, ...args);
373
589
  });
374
590
  }
375
- function ensureClientBound() {
376
- runtime.role !== "unknown" || process.env.BAKIT_SERVICE_NAME === options.name || (bind(ServiceRole.Client), assertRuntimeClient(service, runtime), runtime.transport.ready || runtime.transport.connect());
377
- }
378
- function bind(role) {
379
- if (runtime.role !== "unknown")
380
- throw new Error(`Service "${options.name}" already bound`);
381
- if (role === "server") {
382
- let server = createTransportServer(options.transport);
383
- for (let [method, handler] of handlers)
384
- server.handle(method, handler);
385
- runtime.role = "server", runtime.transport = server;
386
- } else if (role === "client") {
387
- let client = createTransportClient(options.transport);
388
- runtime.role = "client", runtime.transport = client;
389
- }
591
+ ensureServerBound() {
592
+ if (!this.runtime)
593
+ return this.binding ? this.binding : (this.binding = (async () => {
594
+ let transport;
595
+ switch (this.options.driver) {
596
+ case "ipc" /* IPC */: {
597
+ let driver = createIPCServer({
598
+ id: this.options.id,
599
+ ...this.options.server
600
+ });
601
+ transport = createTransportServer(driver);
602
+ break;
603
+ }
604
+ }
605
+ this.runtime = {
606
+ role: "server",
607
+ transport
608
+ };
609
+ for (let [name, handler] of this.handlers)
610
+ transport.handle(name, handler);
611
+ await new Promise((resolve2, reject) => {
612
+ let onResolve = () => {
613
+ cleanup(), resolve2();
614
+ }, onReject = (err) => {
615
+ cleanup(), reject(err);
616
+ }, cleanup = () => {
617
+ transport.off("listen", onResolve), transport.off("error", onReject);
618
+ };
619
+ transport.once("listen", onResolve), transport.once("error", onReject), transport.listen();
620
+ }), this.binding = void 0;
621
+ })(), this.binding);
390
622
  }
391
- return Object.defineProperty(service, SERVICE_INTERNAL, {
392
- value: {
393
- get runtime() {
394
- if (runtime.role === "unknown")
395
- throw new Error(`Service "${options.name}" is not bound`);
396
- return runtime;
397
- },
398
- bind
399
- }
400
- }), service;
401
- }
402
- async function startServiceServer(service) {
403
- let internal = getInternalService(service);
404
- return internal.bind(ServiceRole.Server), await service.initialize?.(), await new Promise((resolve) => {
405
- assertRuntimeServer(service, internal.runtime), internal.runtime.transport.once("listen", async () => {
406
- resolve(), await service.onReady?.();
407
- }), internal.runtime.transport.listen();
408
- });
409
- }
410
- function assertRuntimeClient(service, runtime) {
411
- if (runtime.role !== "client")
412
- throw new Error(`Service "${service.name}" is not a client`);
623
+ ensureClientBound() {
624
+ if (!this.runtime)
625
+ return this.binding ? this.binding : (this.binding = (async () => {
626
+ let transport;
627
+ switch (this.options.driver) {
628
+ case "ipc" /* IPC */: {
629
+ let driver = createIPCClient({
630
+ id: this.options.id,
631
+ ...this.options.client
632
+ });
633
+ transport = createTransportClient(driver);
634
+ break;
635
+ }
636
+ }
637
+ this.runtime = {
638
+ role: "client",
639
+ transport
640
+ }, await new Promise((resolve2, reject) => {
641
+ let onResolve = () => {
642
+ cleanup(), resolve2();
643
+ }, onReject = (err) => {
644
+ cleanup(), reject(err);
645
+ }, cleanup = () => {
646
+ transport.off("connect", onResolve), transport.off("error", onReject);
647
+ };
648
+ transport.once("connect", onResolve), transport.once("error", onReject), transport.connect();
649
+ }), this.binding = void 0;
650
+ })(), this.binding);
651
+ }
652
+ };
653
+ function createService(options) {
654
+ return new Service(options);
413
655
  }
414
- function assertRuntimeServer(service, runtime) {
415
- if (runtime.role !== "server")
416
- throw new Error(`Service "${service.name}" is not a server`);
656
+ async function getServices(entryDir = "./services", cwd = process.cwd()) {
657
+ let path = resolve(entryDir, "**", "*.service.{ts,js}");
658
+ return await glob(path, { cwd });
417
659
  }
418
- function getInternalService(service) {
419
- return service[SERVICE_INTERNAL];
660
+ function getServiceName(servicePath, cwd = process.cwd()) {
661
+ let rel = relative(cwd, servicePath);
662
+ return rel = normalize(rel), rel = rel.replace(/^services[\\/]/, ""), rel = rel.replace(/\.service\.(ts|js)$/, ""), rel.split(sep).join("/");
420
663
  }
664
+ var __filename$1 = fileURLToPath(import.meta.url), __dirname$1 = dirname(__filename$1), ServiceState = /* @__PURE__ */ ((ServiceState2) => (ServiceState2[ServiceState2.Idle = 0] = "Idle", ServiceState2[ServiceState2.Starting = 1] = "Starting", ServiceState2[ServiceState2.Running = 2] = "Running", ServiceState2[ServiceState2.Restarting = 3] = "Restarting", ServiceState2[ServiceState2.Stopping = 4] = "Stopping", ServiceState2[ServiceState2.Stopped = 5] = "Stopped", ServiceState2))(ServiceState || {}), ServiceProcess = class extends EventEmitter {
665
+ constructor(path) {
666
+ super();
667
+ this.path = path;
668
+ }
669
+ child;
670
+ spawnTimestamp = -1;
671
+ _state = 0 /* Idle */;
672
+ get name() {
673
+ return getServiceName(this.path);
674
+ }
675
+ get state() {
676
+ return this._state;
677
+ }
678
+ get ready() {
679
+ return this.state === 2 /* Running */;
680
+ }
681
+ get uptime() {
682
+ return this.spawnTimestamp === -1 ? -1 : Date.now() - this.spawnTimestamp;
683
+ }
684
+ start() {
685
+ this.state !== 2 /* Running */ && this.init();
686
+ }
687
+ async stop() {
688
+ this.state === 5 /* Stopped */ || this.state === 4 /* Stopping */ || (this._state = 4 /* Stopping */, await new Promise((resolve2) => {
689
+ let timeout = setTimeout(() => {
690
+ this.child?.killed || this.child?.kill("SIGKILL");
691
+ }, 5e3);
692
+ this.once("exit", () => {
693
+ clearTimeout(timeout), resolve2();
694
+ }), this.child?.kill("SIGINT");
695
+ }), this._state = 5 /* Stopped */, this.cleanup());
696
+ }
697
+ async restart() {
698
+ this.state !== 3 /* Restarting */ && (await this.stop(), await sleep(1e3), this.start());
699
+ }
700
+ init() {
701
+ if (this.child && this.child.connected)
702
+ return;
703
+ this._state = 1 /* Starting */;
704
+ let file = join(__dirname$1, "service.js");
705
+ this.child = fork(file, [], {
706
+ env: {
707
+ BAKIT_SERVICE_NAME: this.name,
708
+ BAKIT_SERVICE_PATH: this.path,
709
+ FORCE_COLOR: "1"
710
+ },
711
+ stdio: ["inherit", "pipe", "pipe", "ipc"]
712
+ }), this.child.on("exit", (code, signal) => this.onChildExit(code, signal)), this.child.on("error", (err) => this.emit("error", err)), this.child.on("spawn", () => this.onChildSpawn()), this.child.stdout?.on("data", (chunk) => this.emit("stdout", chunk)), this.child.stderr?.on("data", (chunk) => this.emit("stderr", chunk));
713
+ }
714
+ cleanup() {
715
+ this.child && (this.child.killed || this.child.kill(), this.child.removeAllListeners(), this.child = void 0), this.spawnTimestamp = -1;
716
+ }
717
+ onChildSpawn() {
718
+ this._state = 2 /* Running */, this.spawnTimestamp = Date.now(), this.emit("spawn");
719
+ }
720
+ onChildExit(code, signal) {
721
+ let oldState = this._state;
722
+ this._state = 5 /* Stopped */, this.cleanup(), this.emit("exit", code, signal), oldState !== 4 /* Stopping */ && oldState !== 3 /* Restarting */ && code !== 0 && this.restart();
723
+ }
724
+ };
421
725
 
422
- export { DEFAULT_IPC_SOCKET_CONNECTION_OPTIONS, IPCServerState, RPCError, ServiceRole, SocketState, TransportDriver, assertRuntimeClient, assertRuntimeServer, createIPCClient, createIPCServer, createIPCSocketConnection, createIPCSocketMessageHandler, createService, createTransportClient, createTransportClientProtocol, createTransportServer, createTransportServerProtocol, deserializeRPCError, getIPCPath, getInternalService, serializeRPCError, startServiceServer };
726
+ export { BaseClientDriver, BaseServerDriver, DEFAULT_IPC_CLIENT_RECONNECT_OPTIONS, FrameCodec, IPCClient, IPCClientState, IPCServer, Service, ServiceDriver, ServiceProcess, ServiceState, TransportClient, TransportServer, createDynamicRPCError, createIPCClient, createIPCServer, createService, createTransportClient, createTransportServer, getIPCPath, getServiceName, getServices, isSerializedError, isServerRunning, serializeRPCError };