@delali/narsil 0.2.2 → 0.2.3-next.33

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 (66) hide show
  1. package/README.md +12 -9
  2. package/dist/adapters/filesystem.d.ts +1 -1
  3. package/dist/adapters/filesystem.mjs +1 -1
  4. package/dist/adapters/indexeddb.d.ts +1 -1
  5. package/dist/adapters/indexeddb.mjs +1 -1
  6. package/dist/adapters/memory.d.ts +1 -1
  7. package/dist/{adapters-CVqI5NBt.d.ts → adapters-79OIa4xm.d.ts} +1 -1
  8. package/dist/brute-force-DbHYCTc3.d.ts +8 -0
  9. package/dist/chunk-BFIH7OV5.mjs +185 -0
  10. package/dist/chunk-C6VVLMRX.mjs +63 -0
  11. package/dist/{chunk-UNJZ7ZDB.mjs → chunk-EMI63EXP.mjs} +33 -2
  12. package/dist/chunk-MFFAJ2NR.mjs +135 -0
  13. package/dist/chunk-OBXS7OZM.mjs +376 -0
  14. package/dist/{chunk-ASI6AOW2.mjs → chunk-RO4EFWE6.mjs} +7833 -3524
  15. package/dist/{chunk-WLR5BFL3.mjs → chunk-TEAJO7CU.mjs} +3067 -2087
  16. package/dist/{chunk-S7RJJMHI.mjs → chunk-WDL632CN.mjs} +699 -222
  17. package/dist/{chunk-BKAI2WXI.mjs → chunk-WTONLDU3.mjs} +5 -0
  18. package/dist/client-DQHB_swQ.d.ts +793 -0
  19. package/dist/client.d.ts +6 -0
  20. package/dist/client.mjs +843 -0
  21. package/dist/{config-DXypXAfN.d.ts → config-ChZ7lfqc.d.ts} +3 -3
  22. package/dist/direct-executor-YARCDMJF.mjs +8 -0
  23. package/dist/distribution/coordinator/etcd.d.ts +3 -3
  24. package/dist/distribution/coordinator/etcd.mjs +471 -2
  25. package/dist/distribution/coordinator/in-memory.d.ts +3 -3
  26. package/dist/distribution/coordinator/in-memory.mjs +286 -1
  27. package/dist/distribution/transport/grpc.d.ts +45 -0
  28. package/dist/distribution/transport/grpc.mjs +586 -0
  29. package/dist/distribution/transport/in-memory.d.ts +118 -0
  30. package/dist/distribution/transport/in-memory.mjs +214 -0
  31. package/dist/distribution/transport/tcp.d.ts +27 -0
  32. package/dist/distribution/transport/tcp.mjs +595 -0
  33. package/dist/distribution.d.ts +241 -192
  34. package/dist/distribution.mjs +6620 -4795
  35. package/dist/embeddings/openai.d.ts +1 -1
  36. package/dist/embeddings/openai.mjs +1 -1
  37. package/dist/{engine-CO9Wnfie.d.ts → engine-DScGlT2Z.d.ts} +30 -3
  38. package/dist/index.browser.mjs +10035 -3914
  39. package/dist/index.d.ts +8 -8
  40. package/dist/index.mjs +8 -5
  41. package/dist/invalidation/broadcast-channel.d.ts +1 -1
  42. package/dist/invalidation/filesystem.d.ts +1 -1
  43. package/dist/invalidation/filesystem.mjs +3 -1
  44. package/dist/invalidation/noop.d.ts +1 -1
  45. package/dist/options-BORJg5XB.d.ts +234 -0
  46. package/dist/persistence/durability/checkpoint-worker.d.ts +4 -2
  47. package/dist/persistence/durability/checkpoint-worker.mjs +8 -5
  48. package/dist/react.d.ts +340 -0
  49. package/dist/react.mjs +687 -0
  50. package/dist/{schema-CE6S_aAr.d.ts → schema-emTQfEiX.d.ts} +21 -7
  51. package/dist/{search-DLBtiPdQ.d.ts → search-CQ-9bKxo.d.ts} +226 -14
  52. package/dist/server.d.ts +42 -356
  53. package/dist/server.mjs +493 -106
  54. package/dist/tasks-CnMLpfk-.d.ts +274 -0
  55. package/dist/types-BQDlIvfS.d.ts +34 -0
  56. package/dist/{types-BV3nAKTL.d.ts → types-Bfhhnh3G.d.ts} +23 -1
  57. package/dist/types-D5OwhtsQ.d.ts +97 -0
  58. package/dist/vector/hnsw-build-worker.d.ts +2 -7
  59. package/dist/vector/hnsw-build-worker.mjs +2 -1
  60. package/dist/vector/search-worker.d.ts +373 -0
  61. package/dist/vector/search-worker.mjs +279 -0
  62. package/dist/workers/entry.mjs +43 -25
  63. package/package.json +42 -2
  64. package/dist/chunk-FKK76OR7.mjs +0 -456
  65. package/dist/chunk-RQLXC2YS.mjs +0 -269
  66. package/dist/direct-executor-3W4QRA4E.mjs +0 -5
@@ -0,0 +1,586 @@
1
+ import { decodeTransportMessage, encodeTransportMessage } from '../../chunk-MFFAJ2NR.mjs';
2
+ import { TransportError, TransportErrorCodes, MAX_MESSAGE_SIZE_BYTES } from '../../chunk-C6VVLMRX.mjs';
3
+ import { NarsilError, ErrorCodes } from '../../chunk-EMI63EXP.mjs';
4
+
5
+ // src/distribution/transport/grpc/codec.ts
6
+ var FIELD_ONE_LENGTH_DELIMITED_KEY = 10;
7
+ var WIRE_TYPE_VARINT = 0;
8
+ var WIRE_TYPE_FIXED64 = 1;
9
+ var WIRE_TYPE_LENGTH_DELIMITED = 2;
10
+ var WIRE_TYPE_FIXED32 = 5;
11
+ var MAX_VARINT_BYTES = 5;
12
+ function decodeError(reason) {
13
+ return new TransportError(TransportErrorCodes.DECODE_FAILED, `Failed to decode a protobuf envelope: ${reason}`);
14
+ }
15
+ function readVarint(data, pos) {
16
+ let value = 0;
17
+ let factor = 1;
18
+ for (let index = 0; index < MAX_VARINT_BYTES; index++) {
19
+ if (pos + index >= data.byteLength) {
20
+ throw decodeError("a varint runs past the end of the buffer");
21
+ }
22
+ const byte = data[pos + index];
23
+ value += (byte & 127) * factor;
24
+ if ((byte & 128) === 0) {
25
+ return { value, next: pos + index + 1 };
26
+ }
27
+ factor *= 128;
28
+ }
29
+ throw decodeError("a varint exceeds five bytes");
30
+ }
31
+ function encodeBytesMessage(data) {
32
+ const header = [FIELD_ONE_LENGTH_DELIMITED_KEY];
33
+ let remaining = data.byteLength;
34
+ while (remaining > 127) {
35
+ header.push(remaining & 127 | 128);
36
+ remaining >>>= 7;
37
+ }
38
+ header.push(remaining);
39
+ const out = Buffer.allocUnsafe(header.length + data.byteLength);
40
+ out.set(header, 0);
41
+ out.set(data, header.length);
42
+ return out;
43
+ }
44
+ function decodeBytesMessage(data) {
45
+ let pos = 0;
46
+ let field = null;
47
+ while (pos < data.byteLength) {
48
+ const key = readVarint(data, pos);
49
+ pos = key.next;
50
+ const fieldNumber = Math.floor(key.value / 8);
51
+ const wireType = key.value % 8;
52
+ if (fieldNumber === 0) {
53
+ throw decodeError("field number zero is invalid");
54
+ }
55
+ if (wireType === WIRE_TYPE_LENGTH_DELIMITED) {
56
+ const length = readVarint(data, pos);
57
+ pos = length.next;
58
+ if (length.value > data.byteLength - pos) {
59
+ throw decodeError("a length-delimited field runs past the end of the buffer");
60
+ }
61
+ const end = pos + length.value;
62
+ if (fieldNumber === 1) {
63
+ field = data.subarray(pos, end);
64
+ }
65
+ pos = end;
66
+ } else if (wireType === WIRE_TYPE_VARINT) {
67
+ pos = readVarint(data, pos).next;
68
+ } else if (wireType === WIRE_TYPE_FIXED64) {
69
+ if (data.byteLength - pos < 8) {
70
+ throw decodeError("a fixed64 field runs past the end of the buffer");
71
+ }
72
+ pos += 8;
73
+ } else if (wireType === WIRE_TYPE_FIXED32) {
74
+ if (data.byteLength - pos < 4) {
75
+ throw decodeError("a fixed32 field runs past the end of the buffer");
76
+ }
77
+ pos += 4;
78
+ } else {
79
+ throw decodeError(`wire type ${wireType} is unsupported`);
80
+ }
81
+ }
82
+ return field ?? new Uint8Array(0);
83
+ }
84
+
85
+ // src/distribution/transport/grpc/service.ts
86
+ var SEND_METHOD_PATH = "/narsil.transport.v1.NodeTransport/Send";
87
+ var OPEN_STREAM_METHOD_PATH = "/narsil.transport.v1.NodeTransport/OpenStream";
88
+ function serializeBytes(value) {
89
+ return encodeBytesMessage(value);
90
+ }
91
+ function deserializeBytes(value) {
92
+ return decodeBytesMessage(value);
93
+ }
94
+ var sendMethod = {
95
+ path: SEND_METHOD_PATH,
96
+ requestStream: false,
97
+ responseStream: false,
98
+ requestSerialize: serializeBytes,
99
+ requestDeserialize: deserializeBytes,
100
+ responseSerialize: serializeBytes,
101
+ responseDeserialize: deserializeBytes
102
+ };
103
+ var openStreamMethod = {
104
+ path: OPEN_STREAM_METHOD_PATH,
105
+ requestStream: false,
106
+ responseStream: true,
107
+ requestSerialize: serializeBytes,
108
+ requestDeserialize: deserializeBytes,
109
+ responseSerialize: serializeBytes,
110
+ responseDeserialize: deserializeBytes
111
+ };
112
+ var nodeTransportService = {
113
+ send: sendMethod,
114
+ openStream: openStreamMethod
115
+ };
116
+
117
+ // src/distribution/transport/grpc/types.ts
118
+ var DEFAULT_GRPC_CONFIG = {
119
+ host: "0.0.0.0",
120
+ port: 9301,
121
+ connectTimeout: 5e3,
122
+ requestTimeout: 3e4,
123
+ replicationTimeout: 1e4,
124
+ snapshotTimeout: 3e5
125
+ };
126
+ var ENVELOPE_OVERHEAD_BYTES = 1024;
127
+ var KEEPALIVE_TIME_MS = 3e4;
128
+ var KEEPALIVE_TIMEOUT_MS = 1e4;
129
+ function channelOptions() {
130
+ return {
131
+ "grpc.max_receive_message_length": MAX_MESSAGE_SIZE_BYTES + ENVELOPE_OVERHEAD_BYTES,
132
+ "grpc.max_send_message_length": MAX_MESSAGE_SIZE_BYTES + ENVELOPE_OVERHEAD_BYTES,
133
+ "grpc.keepalive_time_ms": KEEPALIVE_TIME_MS,
134
+ "grpc.keepalive_timeout_ms": KEEPALIVE_TIMEOUT_MS,
135
+ "grpc.keepalive_permit_without_calls": 1
136
+ };
137
+ }
138
+ function toCredentialBuffer(material) {
139
+ return typeof material === "string" ? Buffer.from(material) : material;
140
+ }
141
+
142
+ // src/distribution/transport/grpc/client.ts
143
+ var GrpcClientPool = class {
144
+ grpc;
145
+ config;
146
+ clients = /* @__PURE__ */ new Map();
147
+ closed = false;
148
+ constructor(grpc, config) {
149
+ this.grpc = grpc;
150
+ this.config = config;
151
+ }
152
+ async send(target, message) {
153
+ const messageBytes = this.encodeChecked(target, message);
154
+ const client = await this.getClient(target);
155
+ const responseBytes = await this.unaryCall(client, target, message.requestId, messageBytes);
156
+ try {
157
+ return decodeTransportMessage(responseBytes);
158
+ } catch (err) {
159
+ throw new TransportError(
160
+ TransportErrorCodes.DECODE_FAILED,
161
+ `Failed to decode response: ${err instanceof Error ? err.message : String(err)}`,
162
+ { target, requestId: message.requestId }
163
+ );
164
+ }
165
+ }
166
+ async stream(target, message, handler) {
167
+ const messageBytes = this.encodeChecked(target, message);
168
+ const client = await this.getClient(target);
169
+ const call = client.makeServerStreamRequest(
170
+ openStreamMethod.path,
171
+ openStreamMethod.requestSerialize,
172
+ openStreamMethod.responseDeserialize,
173
+ messageBytes,
174
+ this.metadata(),
175
+ this.callOptions(this.config.snapshotTimeout)
176
+ );
177
+ return new Promise((resolve, reject) => {
178
+ let settled = false;
179
+ const settle = (fn) => {
180
+ if (!settled) {
181
+ settled = true;
182
+ fn();
183
+ }
184
+ };
185
+ call.on("data", (chunk) => {
186
+ try {
187
+ handler(chunk);
188
+ } catch (err) {
189
+ call.cancel();
190
+ settle(
191
+ () => reject(
192
+ new TransportError(
193
+ TransportErrorCodes.DECODE_FAILED,
194
+ `Stream chunk handler failed: ${err instanceof Error ? err.message : String(err)}`,
195
+ { target, requestId: message.requestId }
196
+ )
197
+ )
198
+ );
199
+ }
200
+ });
201
+ call.on("end", () => {
202
+ settle(resolve);
203
+ });
204
+ call.on("error", (err) => {
205
+ settle(() => reject(this.mapCallError(target, message.requestId, err)));
206
+ });
207
+ });
208
+ }
209
+ async shutdown() {
210
+ if (this.closed) {
211
+ return;
212
+ }
213
+ this.closed = true;
214
+ const pending = Array.from(this.clients.values());
215
+ this.clients.clear();
216
+ await Promise.all(
217
+ pending.map(
218
+ (clientPromise) => clientPromise.then(
219
+ (client) => {
220
+ client.close();
221
+ },
222
+ () => void 0
223
+ )
224
+ )
225
+ );
226
+ }
227
+ encodeChecked(target, message) {
228
+ this.assertOpen();
229
+ const messageBytes = encodeTransportMessage(message);
230
+ if (messageBytes.byteLength > MAX_MESSAGE_SIZE_BYTES) {
231
+ throw new TransportError(
232
+ TransportErrorCodes.MESSAGE_TOO_LARGE,
233
+ `Message payload (${messageBytes.byteLength} bytes) exceeds the ${MAX_MESSAGE_SIZE_BYTES} byte limit`,
234
+ { target, requestId: message.requestId, payloadSize: messageBytes.byteLength }
235
+ );
236
+ }
237
+ return messageBytes;
238
+ }
239
+ assertOpen() {
240
+ if (this.closed) {
241
+ throw new TransportError(TransportErrorCodes.PEER_UNAVAILABLE, "gRPC client pool has been shut down");
242
+ }
243
+ }
244
+ getClient(target) {
245
+ this.assertOpen();
246
+ const existing = this.clients.get(target);
247
+ if (existing !== void 0) {
248
+ return existing;
249
+ }
250
+ const clientPromise = this.connect(target);
251
+ this.clients.set(target, clientPromise);
252
+ clientPromise.catch(() => {
253
+ if (this.clients.get(target) === clientPromise) {
254
+ this.clients.delete(target);
255
+ }
256
+ });
257
+ return clientPromise;
258
+ }
259
+ connect(target) {
260
+ const client = new this.grpc.Client(target, this.credentials(), channelOptions());
261
+ return new Promise((resolve, reject) => {
262
+ client.waitForReady(Date.now() + this.config.connectTimeout, (err) => {
263
+ if (err === void 0) {
264
+ resolve(client);
265
+ return;
266
+ }
267
+ client.close();
268
+ reject(
269
+ new TransportError(TransportErrorCodes.CONNECT_FAILED, `Failed to connect to '${target}': ${err.message}`, {
270
+ target
271
+ })
272
+ );
273
+ });
274
+ });
275
+ }
276
+ credentials() {
277
+ const tls = this.config.tls;
278
+ if (tls === void 0) {
279
+ return this.grpc.credentials.createInsecure();
280
+ }
281
+ return this.grpc.credentials.createSsl(
282
+ tls.ca !== void 0 ? toCredentialBuffer(tls.ca) : null,
283
+ toCredentialBuffer(tls.key),
284
+ toCredentialBuffer(tls.cert),
285
+ {
286
+ rejectUnauthorized: tls.rejectUnauthorized ?? true
287
+ }
288
+ );
289
+ }
290
+ metadata() {
291
+ return new this.grpc.Metadata();
292
+ }
293
+ callOptions(timeoutMs) {
294
+ return { deadline: Date.now() + timeoutMs };
295
+ }
296
+ unaryCall(client, target, requestId, messageBytes) {
297
+ return new Promise((resolve, reject) => {
298
+ client.makeUnaryRequest(
299
+ sendMethod.path,
300
+ sendMethod.requestSerialize,
301
+ sendMethod.responseDeserialize,
302
+ messageBytes,
303
+ this.metadata(),
304
+ this.callOptions(this.config.requestTimeout),
305
+ (err, response) => {
306
+ if (err !== null) {
307
+ reject(this.mapCallError(target, requestId, err));
308
+ return;
309
+ }
310
+ if (response === void 0) {
311
+ reject(
312
+ new TransportError(TransportErrorCodes.DECODE_FAILED, `Empty response from '${target}'`, {
313
+ target,
314
+ requestId
315
+ })
316
+ );
317
+ return;
318
+ }
319
+ resolve(response);
320
+ }
321
+ );
322
+ });
323
+ }
324
+ mapCallError(target, requestId, err) {
325
+ const status = err.code;
326
+ const details = { target, requestId };
327
+ if (status === this.grpc.status.DEADLINE_EXCEEDED) {
328
+ return new TransportError(
329
+ TransportErrorCodes.TIMEOUT,
330
+ `Request to '${target}' timed out: ${err.message}`,
331
+ details
332
+ );
333
+ }
334
+ if (status === this.grpc.status.RESOURCE_EXHAUSTED) {
335
+ return new TransportError(
336
+ TransportErrorCodes.MESSAGE_TOO_LARGE,
337
+ `Message to '${target}' exceeded a size limit: ${err.message}`,
338
+ details
339
+ );
340
+ }
341
+ return new TransportError(
342
+ TransportErrorCodes.PEER_UNAVAILABLE,
343
+ `Request to '${target}' failed: ${err.message}`,
344
+ details
345
+ );
346
+ }
347
+ };
348
+
349
+ // src/distribution/transport/grpc/loader.ts
350
+ async function loadGrpcModule() {
351
+ try {
352
+ return await import('@grpc/grpc-js');
353
+ } catch (err) {
354
+ throw new NarsilError(
355
+ ErrorCodes.TRANSPORT_DEPENDENCY_MISSING,
356
+ "The `@grpc/grpc-js` package is not installed. Install it with `pnpm add @grpc/grpc-js` (or the npm or yarn equivalent) to use createGrpcTransport.",
357
+ { cause: err instanceof Error ? err.message : String(err) }
358
+ );
359
+ }
360
+ }
361
+
362
+ // src/distribution/transport/grpc/server.ts
363
+ function errorEnvelope(requestId, err) {
364
+ const errorMsg = err instanceof Error ? err.message : String(err);
365
+ return {
366
+ type: "error",
367
+ sourceId: "",
368
+ requestId,
369
+ payload: new TextEncoder().encode(errorMsg)
370
+ };
371
+ }
372
+ var GrpcServerHost = class {
373
+ grpc;
374
+ config;
375
+ server = null;
376
+ handler = null;
377
+ boundPort = 0;
378
+ closed = false;
379
+ constructor(grpc, config) {
380
+ this.grpc = grpc;
381
+ this.config = config;
382
+ }
383
+ getPort() {
384
+ return this.boundPort;
385
+ }
386
+ async start(handler) {
387
+ if (this.closed) {
388
+ throw new TransportError(TransportErrorCodes.PEER_UNAVAILABLE, "gRPC server has been shut down");
389
+ }
390
+ const previousHandler = this.handler;
391
+ this.handler = handler;
392
+ const restore = () => {
393
+ if (this.handler === handler) {
394
+ this.handler = previousHandler ?? null;
395
+ }
396
+ };
397
+ if (this.server !== null) {
398
+ return restore;
399
+ }
400
+ const server = new this.grpc.Server(channelOptions());
401
+ server.addService(nodeTransportService, {
402
+ send: (call, callback) => {
403
+ this.handleSend(call, callback);
404
+ },
405
+ openStream: (call) => {
406
+ this.handleOpenStream(call);
407
+ }
408
+ });
409
+ const address = `${this.config.host}:${this.config.port}`;
410
+ return new Promise((resolve, reject) => {
411
+ server.bindAsync(address, this.serverCredentials(), (err, port) => {
412
+ if (err !== null) {
413
+ reject(
414
+ new TransportError(TransportErrorCodes.CONNECT_FAILED, `gRPC server failed to start: ${err.message}`, {
415
+ address
416
+ })
417
+ );
418
+ return;
419
+ }
420
+ this.server = server;
421
+ this.boundPort = port;
422
+ resolve(restore);
423
+ });
424
+ });
425
+ }
426
+ async shutdown() {
427
+ if (this.closed) {
428
+ return;
429
+ }
430
+ this.closed = true;
431
+ this.handler = null;
432
+ if (this.server !== null) {
433
+ this.server.forceShutdown();
434
+ this.server = null;
435
+ }
436
+ }
437
+ serverCredentials() {
438
+ const tls = this.config.tls;
439
+ if (tls === void 0) {
440
+ return this.grpc.ServerCredentials.createInsecure();
441
+ }
442
+ return this.grpc.ServerCredentials.createSsl(
443
+ tls.ca !== void 0 ? toCredentialBuffer(tls.ca) : null,
444
+ [{ private_key: toCredentialBuffer(tls.key), cert_chain: toCredentialBuffer(tls.cert) }],
445
+ tls.rejectUnauthorized ?? true
446
+ );
447
+ }
448
+ handleSend(call, callback) {
449
+ const handler = this.handler;
450
+ if (handler === null) {
451
+ callback(this.statusError(this.grpc.status.UNAVAILABLE, "No listener is registered"));
452
+ return;
453
+ }
454
+ let message;
455
+ try {
456
+ message = decodeTransportMessage(call.request);
457
+ } catch (err) {
458
+ callback(null, encodeTransportMessage(errorEnvelope("", err)));
459
+ return;
460
+ }
461
+ let responded = false;
462
+ const respond = async (response) => {
463
+ if (responded) {
464
+ return;
465
+ }
466
+ responded = true;
467
+ callback(null, encodeTransportMessage(response));
468
+ };
469
+ this.runHandler(handler, message, respond, (err) => {
470
+ if (!responded) {
471
+ responded = true;
472
+ callback(null, encodeTransportMessage(errorEnvelope(message.requestId, err)));
473
+ }
474
+ });
475
+ }
476
+ handleOpenStream(call) {
477
+ const handler = this.handler;
478
+ if (handler === null) {
479
+ call.emit("error", this.statusError(this.grpc.status.UNAVAILABLE, "No listener is registered"));
480
+ return;
481
+ }
482
+ let message;
483
+ try {
484
+ message = decodeTransportMessage(call.request);
485
+ } catch (err) {
486
+ call.emit(
487
+ "error",
488
+ this.statusError(this.grpc.status.INVALID_ARGUMENT, err instanceof Error ? err.message : String(err))
489
+ );
490
+ return;
491
+ }
492
+ let chunkCount = 0;
493
+ const respond = (response) => {
494
+ if (!call.writable) {
495
+ return Promise.resolve();
496
+ }
497
+ chunkCount++;
498
+ if (call.write(response.payload)) {
499
+ return Promise.resolve();
500
+ }
501
+ return new Promise((resolve) => {
502
+ call.once("drain", resolve);
503
+ });
504
+ };
505
+ const fail = (err) => {
506
+ call.emit("error", this.statusError(this.grpc.status.UNKNOWN, err instanceof Error ? err.message : String(err)));
507
+ };
508
+ const finish = () => {
509
+ if (chunkCount > 0) {
510
+ call.end();
511
+ } else {
512
+ fail(new Error("The stream handler produced no chunks"));
513
+ }
514
+ };
515
+ try {
516
+ const result = handler(message, respond);
517
+ if (result instanceof Promise) {
518
+ result.then(finish, fail);
519
+ } else {
520
+ finish();
521
+ }
522
+ } catch (err) {
523
+ fail(err);
524
+ }
525
+ }
526
+ statusError(code, details) {
527
+ return Object.assign(new Error(details), { code, details });
528
+ }
529
+ runHandler(handler, message, respond, onFailure) {
530
+ try {
531
+ const result = handler(message, respond);
532
+ if (result instanceof Promise) {
533
+ result.catch(onFailure);
534
+ }
535
+ } catch (err) {
536
+ onFailure(err);
537
+ }
538
+ }
539
+ };
540
+
541
+ // src/distribution/transport/grpc/index.ts
542
+ async function createGrpcTransport(nodeId, config) {
543
+ const grpc = await loadGrpcModule();
544
+ const resolvedConfig = {
545
+ ...DEFAULT_GRPC_CONFIG,
546
+ ...config
547
+ };
548
+ const pool = new GrpcClientPool(grpc, resolvedConfig);
549
+ const server = new GrpcServerHost(grpc, resolvedConfig);
550
+ let isShutdown = false;
551
+ function assertNotShutdown() {
552
+ if (isShutdown) {
553
+ throw new TransportError(
554
+ TransportErrorCodes.PEER_UNAVAILABLE,
555
+ `gRPC transport for node '${nodeId}' has been shut down`,
556
+ { nodeId }
557
+ );
558
+ }
559
+ }
560
+ return {
561
+ getPort() {
562
+ return server.getPort();
563
+ },
564
+ async send(target, message) {
565
+ assertNotShutdown();
566
+ return pool.send(target, message);
567
+ },
568
+ async stream(target, message, handler) {
569
+ assertNotShutdown();
570
+ return pool.stream(target, message, handler);
571
+ },
572
+ async listen(handler) {
573
+ assertNotShutdown();
574
+ return server.start(handler);
575
+ },
576
+ async shutdown() {
577
+ if (isShutdown) {
578
+ return;
579
+ }
580
+ isShutdown = true;
581
+ await Promise.all([pool.shutdown(), server.shutdown()]);
582
+ }
583
+ };
584
+ }
585
+
586
+ export { createGrpcTransport };
@@ -0,0 +1,118 @@
1
+ import { N as NodeTransport, a as TransportMessage, R as RespondFn, T as TransportConfig } from '../../types-D5OwhtsQ.js';
2
+ export { L as ListenHandler } from '../../types-D5OwhtsQ.js';
3
+
4
+ /**
5
+ * Receives a streamed response one chunk at a time.
6
+ *
7
+ * A sender hands each chunk over through {@link InMemoryStreamSink.chunk} and
8
+ * waits for it before building the next, so a snapshot travels no faster than
9
+ * the receiver reads it. A stream that breaks part way through ends at
10
+ * {@link InMemoryStreamSink.fail} rather than at
11
+ * {@link InMemoryStreamSink.end}, which is what stops a half-copied snapshot
12
+ * from reading as a whole one.
13
+ *
14
+ * @public
15
+ */
16
+ interface InMemoryStreamSink {
17
+ /**
18
+ * Hands one chunk to the caller waiting on the stream.
19
+ *
20
+ * @param payload - The bytes this chunk carries.
21
+ * @returns A promise that settles once the caller has taken the chunk.
22
+ */
23
+ chunk(payload: Uint8Array): Promise<void>;
24
+ /** Closes the stream, which settles the caller's `stream` call. */
25
+ end(): void;
26
+ /**
27
+ * Breaks the stream, which rejects the caller's `stream` call.
28
+ *
29
+ * @param error - Why the stream broke.
30
+ */
31
+ fail(error: Error): void;
32
+ }
33
+
34
+ /**
35
+ * The delivery side of an in-memory transport, which the network calls to hand
36
+ * a peer its message.
37
+ *
38
+ * You reach this through {@link InMemoryNetwork} rather than building one, so
39
+ * treat it as the connection between two in-process nodes.
40
+ *
41
+ * @public
42
+ */
43
+ interface InMemoryTransportInternal extends NodeTransport {
44
+ /**
45
+ * Delivers one request to this node's listener.
46
+ *
47
+ * @param message - The request the sender posted.
48
+ * @param respond - Hands the reply back to the sender.
49
+ */
50
+ deliverMessage(message: TransportMessage, respond: RespondFn): void;
51
+ /**
52
+ * Delivers one streamed request to this node's listener.
53
+ *
54
+ * @param message - The request the sender posted.
55
+ * @param sink - Takes each chunk, and the end or the failure of the stream.
56
+ */
57
+ deliverStream(message: TransportMessage, sink: InMemoryStreamSink): void;
58
+ }
59
+ /**
60
+ * The switchboard that connects in-process cluster nodes to each other.
61
+ *
62
+ * Every node registers its transport under its own id, and a message addressed
63
+ * to a node is handed straight to the transport registered under that id. This
64
+ * runs a whole cluster inside one process, which is what tests and local
65
+ * development use in place of TCP.
66
+ *
67
+ * @public
68
+ */
69
+ interface InMemoryNetwork {
70
+ /**
71
+ * Makes a node reachable under its id.
72
+ *
73
+ * @param nodeId - The id peers address this node by.
74
+ * @param transport - The transport that receives its messages.
75
+ */
76
+ register(nodeId: string, transport: InMemoryTransportInternal): void;
77
+ /**
78
+ * Makes a node unreachable, so a message addressed to it fails.
79
+ *
80
+ * @param nodeId - The node to remove.
81
+ */
82
+ unregister(nodeId: string): void;
83
+ /**
84
+ * Looks a node's transport up.
85
+ *
86
+ * @param nodeId - The node to find.
87
+ * @returns Its transport, or `undefined` when no node holds that id.
88
+ */
89
+ getTransport(nodeId: string): InMemoryTransportInternal | undefined;
90
+ }
91
+ /**
92
+ * Builds the switchboard that connects in-process cluster nodes.
93
+ *
94
+ * Create one network, then create a transport per node against it, which is
95
+ * how a whole cluster runs inside a single process.
96
+ *
97
+ * @returns An empty network, ready for nodes to register against.
98
+ *
99
+ * @public
100
+ */
101
+ declare function createInMemoryNetwork(): InMemoryNetwork;
102
+ /**
103
+ * Builds one node's transport and registers it on an in-process network.
104
+ *
105
+ * The network hands each message straight to the addressed node with no socket
106
+ * in between, so a cluster built this way behaves like a real one without any
107
+ * ports to open.
108
+ *
109
+ * @param nodeId - The id peers address this node by.
110
+ * @param network - The network this node joins.
111
+ * @param config - The timeouts to override. Omit it to accept the defaults.
112
+ * @returns The transport you pass as a cluster node's `transport`.
113
+ *
114
+ * @public
115
+ */
116
+ declare function createInMemoryTransport(nodeId: string, network: InMemoryNetwork, config?: Partial<TransportConfig>): NodeTransport;
117
+
118
+ export { type InMemoryNetwork, type InMemoryStreamSink, type InMemoryTransportInternal, RespondFn, createInMemoryNetwork, createInMemoryTransport };