@naeemo/capnp 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,85 @@
1
1
 
2
+ //#region src/debug/config.ts
3
+ /**
4
+ * Global debug state
5
+ */
6
+ const debugState = {
7
+ enabled: false,
8
+ options: {
9
+ colors: true,
10
+ maxBytes: 256,
11
+ filter: ""
12
+ }
13
+ };
14
+ /**
15
+ * Check if running in Node.js environment
16
+ */
17
+ function isNode$1() {
18
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
19
+ }
20
+ /**
21
+ * Check CAPNP_DEBUG environment variable in Node.js
22
+ */
23
+ function checkEnvVar() {
24
+ if (isNode$1()) try {
25
+ const envValue = process.env.CAPNP_DEBUG;
26
+ return envValue === "1" || envValue === "true";
27
+ } catch {
28
+ return false;
29
+ }
30
+ return false;
31
+ }
32
+ if (checkEnvVar()) debugState.enabled = true;
33
+ /**
34
+ * Enable debug mode with optional configuration
35
+ *
36
+ * @param options - Debug configuration options
37
+ * @example
38
+ * ```typescript
39
+ * enableDebug({ colors: true, maxBytes: 512 });
40
+ * ```
41
+ */
42
+ function enableDebug(options) {
43
+ debugState.enabled = true;
44
+ if (options) debugState.options = {
45
+ ...debugState.options,
46
+ ...options
47
+ };
48
+ }
49
+ /**
50
+ * Disable debug mode
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * disableDebug();
55
+ * ```
56
+ */
57
+ function disableDebug() {
58
+ debugState.enabled = false;
59
+ }
60
+ /**
61
+ * Check if debug mode is currently enabled
62
+ *
63
+ * @returns True if debug mode is enabled
64
+ * @example
65
+ * ```typescript
66
+ * if (isDebugEnabled()) {
67
+ * console.log('Debug is on');
68
+ * }
69
+ * ```
70
+ */
71
+ function isDebugEnabled() {
72
+ return debugState.enabled;
73
+ }
74
+ /**
75
+ * Get current debug options (internal use)
76
+ * @internal
77
+ */
78
+ function getDebugOptions() {
79
+ return Object.freeze({ ...debugState.options });
80
+ }
81
+
82
+ //#endregion
2
83
  //#region src/rpc/four-tables.ts
3
84
  /** Manages the question table for outbound calls */
4
85
  var QuestionTable = class {
@@ -197,6 +278,238 @@ var ExportTable = class {
197
278
  }
198
279
  };
199
280
 
281
+ //#endregion
282
+ //#region src/debug/index.ts
283
+ /**
284
+ * Default configuration for debug logging
285
+ */
286
+ const DEFAULT_CONFIG = {
287
+ enabled: false,
288
+ colors: true,
289
+ maxBytesToLog: 1024
290
+ };
291
+ /**
292
+ * ANSI color codes for Node.js output
293
+ */
294
+ const ANSI_COLORS = {
295
+ reset: "\x1B[0m",
296
+ bright: "\x1B[1m",
297
+ dim: "\x1B[2m",
298
+ red: "\x1B[31m",
299
+ green: "\x1B[32m",
300
+ yellow: "\x1B[33m",
301
+ blue: "\x1B[34m",
302
+ magenta: "\x1B[35m",
303
+ cyan: "\x1B[36m",
304
+ white: "\x1B[37m",
305
+ gray: "\x1B[90m"
306
+ };
307
+ /**
308
+ * CSS styles for browser console output
309
+ */
310
+ const BROWSER_STYLES = {
311
+ header: "color: #6c757d; font-weight: bold;",
312
+ send: "color: #28a745; font-weight: bold;",
313
+ recv: "color: #007bff; font-weight: bold;",
314
+ hex: "color: #6c757d;",
315
+ ascii: "color: #495057;",
316
+ arrow: "color: #6c757d;",
317
+ parsed: "color: #17a2b8;"
318
+ };
319
+ /**
320
+ * Check if running in Node.js environment
321
+ */
322
+ function isNode() {
323
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
324
+ }
325
+ /**
326
+ * Format a byte as two-digit hex string
327
+ */
328
+ function byteToHex(byte) {
329
+ return byte.toString(16).padStart(2, "0");
330
+ }
331
+ /**
332
+ * Check if a byte is printable ASCII
333
+ */
334
+ function isPrintable(byte) {
335
+ return byte >= 32 && byte < 127;
336
+ }
337
+ /**
338
+ * Format binary data as hex + ASCII (like hexdump -C)
339
+ *
340
+ * Output format:
341
+ * 00000000: 00 00 00 00 02 00 00 00 │........│
342
+ *
343
+ * @param data - The binary data to format
344
+ * @param maxBytes - Maximum number of bytes to format
345
+ * @param useColors - Whether to include ANSI colors
346
+ * @returns Array of formatted lines
347
+ */
348
+ function formatHexDump(data, maxBytes = 1024, useColors = false) {
349
+ const lines = [];
350
+ const bytesToFormat = Math.min(data.length, maxBytes);
351
+ const bytesPerLine = 16;
352
+ for (let offset = 0; offset < bytesToFormat; offset += bytesPerLine) {
353
+ const chunk = data.slice(offset, Math.min(offset + bytesPerLine, bytesToFormat));
354
+ let line = `${byteToHex(offset >> 24 & 255)}${byteToHex(offset >> 16 & 255)}${byteToHex(offset >> 8 & 255)}${byteToHex(offset & 255)}: `;
355
+ const hexParts = [];
356
+ for (let i = 0; i < bytesPerLine; i++) {
357
+ if (i < chunk.length) hexParts.push(byteToHex(chunk[i]));
358
+ else hexParts.push(" ");
359
+ if (i === 7) hexParts.push("");
360
+ }
361
+ line += hexParts.join(" ");
362
+ let ascii = " │";
363
+ for (let i = 0; i < chunk.length; i++) ascii += isPrintable(chunk[i]) ? String.fromCharCode(chunk[i]) : ".";
364
+ ascii += "│";
365
+ line += ascii;
366
+ if (useColors && isNode()) {
367
+ const hexStart = line.indexOf(":") + 2;
368
+ const delimiterIndex = line.indexOf("│");
369
+ const hexPart = line.slice(hexStart, delimiterIndex);
370
+ const asciiPart = line.slice(delimiterIndex);
371
+ line = line.slice(0, hexStart) + ANSI_COLORS.gray + hexPart + ANSI_COLORS.reset + ANSI_COLORS.dim + asciiPart + ANSI_COLORS.reset;
372
+ }
373
+ lines.push(line);
374
+ }
375
+ if (data.length > maxBytes) {
376
+ const remaining = data.length - maxBytes;
377
+ lines.push(`... (${remaining} more bytes)`);
378
+ }
379
+ return lines;
380
+ }
381
+ /**
382
+ * Debug logger for Cap'n Proto RPC messages
383
+ */
384
+ var DebugLogger = class {
385
+ config;
386
+ /**
387
+ * Create a new DebugLogger instance
388
+ * @param config - Partial configuration to override defaults
389
+ */
390
+ constructor(config = {}) {
391
+ this.config = {
392
+ ...DEFAULT_CONFIG,
393
+ ...config
394
+ };
395
+ }
396
+ /**
397
+ * Update the logger configuration
398
+ * @param config - Partial configuration to merge
399
+ */
400
+ setConfig(config) {
401
+ this.config = {
402
+ ...this.config,
403
+ ...config
404
+ };
405
+ }
406
+ /**
407
+ * Get current configuration
408
+ */
409
+ getConfig() {
410
+ return { ...this.config };
411
+ }
412
+ /**
413
+ * Check if debugging is enabled
414
+ */
415
+ isEnabled() {
416
+ return this.config.enabled;
417
+ }
418
+ /**
419
+ * Enable debug logging
420
+ */
421
+ enable() {
422
+ this.config.enabled = true;
423
+ }
424
+ /**
425
+ * Disable debug logging
426
+ */
427
+ disable() {
428
+ this.config.enabled = false;
429
+ }
430
+ /**
431
+ * Format the header for a log message
432
+ * @param direction - 'send' or 'recv'
433
+ * @param byteLength - Number of bytes
434
+ * @returns Formatted header string
435
+ */
436
+ formatHeader(direction, byteLength) {
437
+ const prefix = direction === "send" ? "CAPNP:SEND" : "CAPNP:RECV";
438
+ if (isNode() && this.config.colors) return `${direction === "send" ? ANSI_COLORS.green : ANSI_COLORS.blue}[${prefix}]${ANSI_COLORS.reset} ${byteLength} bytes`;
439
+ return `[${prefix}] ${byteLength} bytes`;
440
+ }
441
+ /**
442
+ * Log a Cap'n Proto message
443
+ *
444
+ * Output format:
445
+ * [CAPNP:SEND] 64 bytes
446
+ * 00000000: 00 00 00 00 02 00 00 00 │........│
447
+ * → { messageType: 'Bootstrap', ... }
448
+ *
449
+ * @param direction - 'send' for outgoing, 'recv' for incoming
450
+ * @param data - The raw binary message data
451
+ * @param parsed - Optional parsed message object to display
452
+ */
453
+ logMessage(direction, data, parsed) {
454
+ if (!this.config.enabled) return;
455
+ const isNodeEnv = isNode();
456
+ const useColors = this.config.colors;
457
+ const header = this.formatHeader(direction, data.length);
458
+ const hexLines = formatHexDump(data, this.config.maxBytesToLog, useColors);
459
+ if (isNodeEnv) {
460
+ console.log(header);
461
+ for (const line of hexLines) console.log(line);
462
+ if (parsed !== void 0) {
463
+ const arrow = useColors ? `${ANSI_COLORS.gray}→${ANSI_COLORS.reset}` : "→";
464
+ const parsedStr = JSON.stringify(parsed, null, 2);
465
+ const coloredParsed = useColors ? `${ANSI_COLORS.cyan}${parsedStr}${ANSI_COLORS.reset}` : parsedStr;
466
+ console.log(`${arrow} ${coloredParsed}`);
467
+ }
468
+ } else if (useColors) {
469
+ const style = direction === "send" ? BROWSER_STYLES.send : BROWSER_STYLES.recv;
470
+ console.log(`%c[CAPNP:${direction.toUpperCase()}]%c ${data.length} bytes`, style, "color: inherit;");
471
+ for (const line of hexLines) console.log(`%c${line}`, BROWSER_STYLES.hex);
472
+ if (parsed !== void 0) console.log("%c→%c %o", BROWSER_STYLES.arrow, BROWSER_STYLES.parsed, parsed);
473
+ } else {
474
+ console.log(header);
475
+ for (const line of hexLines) console.log(line);
476
+ if (parsed !== void 0) console.log("→", parsed);
477
+ }
478
+ }
479
+ /**
480
+ * Log a generic debug message (only if enabled)
481
+ * @param message - Message to log
482
+ * @param args - Additional arguments
483
+ */
484
+ log(message, ...args) {
485
+ if (!this.config.enabled) return;
486
+ if (isNode() && this.config.colors) console.log(`${ANSI_COLORS.gray}[CAPNP:DEBUG]${ANSI_COLORS.reset} ${message}`, ...args);
487
+ else console.log(`[CAPNP:DEBUG] ${message}`, ...args);
488
+ }
489
+ /**
490
+ * Log an error message (always shown if debug is enabled)
491
+ * @param message - Error message
492
+ * @param error - Optional error object
493
+ */
494
+ error(message, error) {
495
+ if (!this.config.enabled) return;
496
+ if (isNode() && this.config.colors) console.error(`${ANSI_COLORS.red}[CAPNP:ERROR]${ANSI_COLORS.reset} ${message}`, error ?? "");
497
+ else console.error(`[CAPNP:ERROR] ${message}`, error ?? "");
498
+ }
499
+ };
500
+ /**
501
+ * Create a default debug logger instance
502
+ * @param config - Optional configuration
503
+ * @returns DebugLogger instance
504
+ */
505
+ function createDebugLogger(config) {
506
+ return new DebugLogger(config);
507
+ }
508
+ /**
509
+ * Global debug logger instance for convenience
510
+ */
511
+ const debug = new DebugLogger();
512
+
200
513
  //#endregion
201
514
  //#region src/rpc/pipeline.ts
202
515
  /**
@@ -1458,9 +1771,26 @@ function serializeListSchemasResults(results) {
1458
1771
 
1459
1772
  //#endregion
1460
1773
  //#region src/rpc/rpc-connection.ts
1774
+ /**
1775
+ * RpcConnection
1776
+ *
1777
+ * Manages a single RPC connection, handling message routing and the Four Tables.
1778
+ * This is the core of the RPC implementation.
1779
+ *
1780
+ * Phase 2 Updates:
1781
+ * - Added Promise Pipelining support
1782
+ * - Added capability passing
1783
+ * - Added Resolve/Release/Disembargo message handling
1784
+ *
1785
+ * Phase 4 Updates:
1786
+ * - Added Level 3 RPC support (Provide/Accept)
1787
+ * - Added third-party capability handling
1788
+ * - Integrated with ConnectionManager for multi-vat scenarios
1789
+ */
1461
1790
  var RpcConnection = class {
1462
1791
  transport;
1463
1792
  options;
1793
+ debugLogger = createDebugLogger();
1464
1794
  questions = new QuestionTable();
1465
1795
  answers = new AnswerTable();
1466
1796
  imports = new ImportTable();
@@ -1479,6 +1809,11 @@ var RpcConnection = class {
1479
1809
  this.transport = transport;
1480
1810
  this.options = options;
1481
1811
  this.level3Handlers = options.level3Handlers;
1812
+ if (options.debug ?? isDebugEnabled()) {
1813
+ this.debugLogger.enable();
1814
+ this.debugLogger.setConfig(getDebugOptions());
1815
+ this.debugLogger.log("RPC connection created");
1816
+ }
1482
1817
  this.transport.onClose = (reason) => {
1483
1818
  this.handleDisconnect(reason);
1484
1819
  };
@@ -1509,7 +1844,7 @@ var RpcConnection = class {
1509
1844
  type: "bootstrap",
1510
1845
  bootstrap: { questionId: question.id }
1511
1846
  };
1512
- await this.transport.send(bootstrapMsg);
1847
+ await this.sendWithLogging(bootstrapMsg);
1513
1848
  await question.completionPromise;
1514
1849
  return {};
1515
1850
  }
@@ -1534,7 +1869,7 @@ var RpcConnection = class {
1534
1869
  sendResultsTo: { type: "caller" }
1535
1870
  }
1536
1871
  };
1537
- await this.transport.send(callMsg);
1872
+ await this.sendWithLogging(callMsg);
1538
1873
  return question.completionPromise;
1539
1874
  }
1540
1875
  /**
@@ -1560,7 +1895,7 @@ var RpcConnection = class {
1560
1895
  sendResultsTo: { type: "caller" }
1561
1896
  }
1562
1897
  };
1563
- await this.transport.send(callMsg);
1898
+ await this.sendWithLogging(callMsg);
1564
1899
  return createPipelineClient({
1565
1900
  connection: this,
1566
1901
  questionId: question.id
@@ -1577,7 +1912,7 @@ var RpcConnection = class {
1577
1912
  requireEarlyCancellationWorkaround: false
1578
1913
  }
1579
1914
  };
1580
- await this.transport.send(finishMsg);
1915
+ await this.sendWithLogging(finishMsg);
1581
1916
  this.questions.markFinishSent(questionId);
1582
1917
  this.questions.remove(questionId);
1583
1918
  }
@@ -1590,7 +1925,7 @@ var RpcConnection = class {
1590
1925
  referenceCount
1591
1926
  }
1592
1927
  };
1593
- await this.transport.send(releaseMsg);
1928
+ await this.sendWithLogging(releaseMsg);
1594
1929
  }
1595
1930
  /** Send a resolve message to indicate a promise has resolved */
1596
1931
  async resolve(promiseId, cap) {
@@ -1604,7 +1939,7 @@ var RpcConnection = class {
1604
1939
  }
1605
1940
  }
1606
1941
  };
1607
- await this.transport.send(resolveMsg);
1942
+ await this.sendWithLogging(resolveMsg);
1608
1943
  }
1609
1944
  /** Send a resolve message indicating a promise was broken */
1610
1945
  async resolveException(promiseId, reason) {
@@ -1621,7 +1956,7 @@ var RpcConnection = class {
1621
1956
  }
1622
1957
  }
1623
1958
  };
1624
- await this.transport.send(resolveMsg);
1959
+ await this.sendWithLogging(resolveMsg);
1625
1960
  }
1626
1961
  /** Send a return message (internal use) */
1627
1962
  async sendReturn(ret) {
@@ -1629,7 +1964,7 @@ var RpcConnection = class {
1629
1964
  type: "return",
1630
1965
  return: ret
1631
1966
  };
1632
- await this.transport.send(returnMsg);
1967
+ await this.sendWithLogging(returnMsg);
1633
1968
  }
1634
1969
  /** Send a disembargo message (internal use) */
1635
1970
  async sendDisembargo(disembargo) {
@@ -1637,7 +1972,7 @@ var RpcConnection = class {
1637
1972
  type: "disembargo",
1638
1973
  disembargo
1639
1974
  };
1640
- await this.transport.send(disembargoMsg);
1975
+ await this.sendWithLogging(disembargoMsg);
1641
1976
  }
1642
1977
  /** Internal method: Create a new question (used by pipeline) */
1643
1978
  createQuestion() {
@@ -1649,7 +1984,7 @@ var RpcConnection = class {
1649
1984
  type: "call",
1650
1985
  call
1651
1986
  };
1652
- await this.transport.send(callMsg);
1987
+ await this.sendWithLogging(callMsg);
1653
1988
  }
1654
1989
  /** Internal method: Wait for an answer (used by pipeline) */
1655
1990
  async waitForAnswer(questionId) {
@@ -1660,7 +1995,7 @@ var RpcConnection = class {
1660
1995
  /** Main message processing loop */
1661
1996
  async messageLoop() {
1662
1997
  while (this.running) try {
1663
- const message = await this.transport.receive();
1998
+ const message = await this.receiveWithLogging();
1664
1999
  if (message === null) break;
1665
2000
  await this.handleMessage(message);
1666
2001
  } catch (error) {
@@ -1725,7 +2060,7 @@ var RpcConnection = class {
1725
2060
  }
1726
2061
  }
1727
2062
  };
1728
- await this.transport.send(returnMsg);
2063
+ await this.sendWithLogging(returnMsg);
1729
2064
  this.answers.markReturnSent(bootstrap.questionId);
1730
2065
  }
1731
2066
  /** Handle incoming call */
@@ -1746,7 +2081,7 @@ var RpcConnection = class {
1746
2081
  }
1747
2082
  }
1748
2083
  };
1749
- await this.transport.send(returnMsg);
2084
+ await this.sendWithLogging(returnMsg);
1750
2085
  this.answers.markReturnSent(call.questionId);
1751
2086
  }
1752
2087
  /** Handle return message */
@@ -1816,7 +2151,7 @@ var RpcConnection = class {
1816
2151
  }
1817
2152
  }
1818
2153
  };
1819
- await this.transport.send(echoMsg);
2154
+ await this.sendWithLogging(echoMsg);
1820
2155
  }
1821
2156
  }
1822
2157
  /** Handle provide message (Level 3) */
@@ -1873,7 +2208,7 @@ var RpcConnection = class {
1873
2208
  type: "unimplemented",
1874
2209
  message: originalMessage
1875
2210
  };
1876
- await this.transport.send(msg);
2211
+ await this.sendWithLogging(msg);
1877
2212
  }
1878
2213
  /** Send return exception (helper) */
1879
2214
  async sendReturnException(questionId, reason) {
@@ -1892,7 +2227,7 @@ var RpcConnection = class {
1892
2227
  }
1893
2228
  }
1894
2229
  };
1895
- await this.transport.send(returnMsg);
2230
+ await this.sendWithLogging(returnMsg);
1896
2231
  }
1897
2232
  /**
1898
2233
  * Set the Level 4 handlers for this connection.
@@ -2039,7 +2374,7 @@ var RpcConnection = class {
2039
2374
  sendResultsTo: { type: "caller" }
2040
2375
  }
2041
2376
  };
2042
- await this.transport.send(schemaRequestMsg);
2377
+ await this.sendWithLogging(schemaRequestMsg);
2043
2378
  const question = this.questions.create();
2044
2379
  question.id = questionId;
2045
2380
  try {
@@ -2133,7 +2468,7 @@ var RpcConnection = class {
2133
2468
  sendResultsTo: { type: "caller" }
2134
2469
  }
2135
2470
  };
2136
- await this.transport.send(listRequestMsg);
2471
+ await this.sendWithLogging(listRequestMsg);
2137
2472
  const question = this.questions.create();
2138
2473
  question.id = questionId;
2139
2474
  try {
@@ -2152,6 +2487,17 @@ var RpcConnection = class {
2152
2487
  throw error;
2153
2488
  }
2154
2489
  }
2490
+ /** Send a message with debug logging */
2491
+ async sendWithLogging(message) {
2492
+ if (this.debugLogger.isEnabled()) this.debugLogger.log(`[RPC:SEND] ${message.type}`);
2493
+ await this.transport.send(message);
2494
+ }
2495
+ /** Receive a message with debug logging */
2496
+ async receiveWithLogging() {
2497
+ const message = await this.transport.receive();
2498
+ if (message !== null && this.debugLogger.isEnabled()) this.debugLogger.log(`[RPC:RECV] ${message.type}`);
2499
+ return message;
2500
+ }
2155
2501
  };
2156
2502
 
2157
2503
  //#endregion
@@ -2251,6 +2597,24 @@ Object.defineProperty(exports, 'deserializeSchemaResponse', {
2251
2597
  return deserializeSchemaResponse;
2252
2598
  }
2253
2599
  });
2600
+ Object.defineProperty(exports, 'disableDebug', {
2601
+ enumerable: true,
2602
+ get: function () {
2603
+ return disableDebug;
2604
+ }
2605
+ });
2606
+ Object.defineProperty(exports, 'enableDebug', {
2607
+ enumerable: true,
2608
+ get: function () {
2609
+ return enableDebug;
2610
+ }
2611
+ });
2612
+ Object.defineProperty(exports, 'isDebugEnabled', {
2613
+ enumerable: true,
2614
+ get: function () {
2615
+ return isDebugEnabled;
2616
+ }
2617
+ });
2254
2618
  Object.defineProperty(exports, 'isPipelineClient', {
2255
2619
  enumerable: true,
2256
2620
  get: function () {
@@ -2293,4 +2657,4 @@ Object.defineProperty(exports, 'serializeSchemaResponse', {
2293
2657
  return serializeSchemaResponse;
2294
2658
  }
2295
2659
  });
2296
- //# sourceMappingURL=rpc-connection-_eHtWsk2.js.map
2660
+ //# sourceMappingURL=rpc-connection-OuadMfAW.js.map