tywrap 0.5.1 → 0.6.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.
Files changed (155) hide show
  1. package/dist/cli.js +8 -6
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/index.js +236 -147
  5. package/dist/config/index.js.map +1 -1
  6. package/dist/core/annotation-parser.d.ts.map +1 -1
  7. package/dist/core/annotation-parser.js +93 -83
  8. package/dist/core/annotation-parser.js.map +1 -1
  9. package/dist/core/discovery.d.ts.map +1 -1
  10. package/dist/core/discovery.js +26 -0
  11. package/dist/core/discovery.js.map +1 -1
  12. package/dist/core/emit-call.d.ts +58 -0
  13. package/dist/core/emit-call.d.ts.map +1 -0
  14. package/dist/core/emit-call.js +103 -0
  15. package/dist/core/emit-call.js.map +1 -0
  16. package/dist/core/generator.d.ts +2 -0
  17. package/dist/core/generator.d.ts.map +1 -1
  18. package/dist/core/generator.js +54 -211
  19. package/dist/core/generator.js.map +1 -1
  20. package/dist/core/mapper.d.ts.map +1 -1
  21. package/dist/core/mapper.js +118 -104
  22. package/dist/core/mapper.js.map +1 -1
  23. package/dist/index.d.ts +6 -25
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +9 -31
  26. package/dist/index.js.map +1 -1
  27. package/dist/runtime/bounded-context.d.ts +2 -2
  28. package/dist/runtime/bounded-context.js +2 -2
  29. package/dist/runtime/{safe-codec.d.ts → bridge-codec.d.ts} +11 -11
  30. package/dist/runtime/bridge-codec.d.ts.map +1 -0
  31. package/dist/runtime/{safe-codec.js → bridge-codec.js} +26 -26
  32. package/dist/runtime/bridge-codec.js.map +1 -0
  33. package/dist/runtime/{http-io.d.ts → http-transport.d.ts} +6 -6
  34. package/dist/runtime/http-transport.d.ts.map +1 -0
  35. package/dist/runtime/{http-io.js → http-transport.js} +3 -3
  36. package/dist/runtime/http-transport.js.map +1 -0
  37. package/dist/runtime/http.d.ts +3 -3
  38. package/dist/runtime/http.d.ts.map +1 -1
  39. package/dist/runtime/http.js +4 -4
  40. package/dist/runtime/http.js.map +1 -1
  41. package/dist/runtime/index.d.ts +9 -1
  42. package/dist/runtime/index.d.ts.map +1 -1
  43. package/dist/runtime/index.js +9 -1
  44. package/dist/runtime/index.js.map +1 -1
  45. package/dist/runtime/node.d.ts +6 -6
  46. package/dist/runtime/node.d.ts.map +1 -1
  47. package/dist/runtime/node.js +7 -7
  48. package/dist/runtime/node.js.map +1 -1
  49. package/dist/runtime/pooled-transport.d.ts +11 -11
  50. package/dist/runtime/pooled-transport.d.ts.map +1 -1
  51. package/dist/runtime/pooled-transport.js +10 -10
  52. package/dist/runtime/pooled-transport.js.map +1 -1
  53. package/dist/runtime/pyodide-bootstrap-core.generated.d.ts.map +1 -1
  54. package/dist/runtime/pyodide-bootstrap-core.generated.js +1 -1
  55. package/dist/runtime/pyodide-bootstrap-core.generated.js.map +1 -1
  56. package/dist/runtime/{pyodide-io.d.ts → pyodide-transport.d.ts} +8 -8
  57. package/dist/runtime/pyodide-transport.d.ts.map +1 -0
  58. package/dist/runtime/{pyodide-io.js → pyodide-transport.js} +5 -5
  59. package/dist/runtime/pyodide-transport.js.map +1 -0
  60. package/dist/runtime/pyodide.d.ts +3 -3
  61. package/dist/runtime/pyodide.d.ts.map +1 -1
  62. package/dist/runtime/pyodide.js +5 -5
  63. package/dist/runtime/pyodide.js.map +1 -1
  64. package/dist/runtime/rpc-client.d.ts +5 -5
  65. package/dist/runtime/rpc-client.d.ts.map +1 -1
  66. package/dist/runtime/rpc-client.js +6 -7
  67. package/dist/runtime/rpc-client.js.map +1 -1
  68. package/dist/runtime/{process-io.d.ts → subprocess-transport.d.ts} +9 -9
  69. package/dist/runtime/subprocess-transport.d.ts.map +1 -0
  70. package/dist/runtime/{process-io.js → subprocess-transport.js} +6 -6
  71. package/dist/runtime/subprocess-transport.js.map +1 -0
  72. package/dist/runtime/{worker-pool.d.ts → transport-pool.d.ts} +15 -15
  73. package/dist/runtime/transport-pool.d.ts.map +1 -0
  74. package/dist/runtime/{worker-pool.js → transport-pool.js} +6 -6
  75. package/dist/runtime/transport-pool.js.map +1 -0
  76. package/dist/runtime/transport.d.ts +14 -8
  77. package/dist/runtime/transport.d.ts.map +1 -1
  78. package/dist/runtime/transport.js +10 -4
  79. package/dist/runtime/transport.js.map +1 -1
  80. package/dist/types/index.d.ts +10 -1
  81. package/dist/types/index.d.ts.map +1 -1
  82. package/dist/utils/cache.d.ts +2 -2
  83. package/dist/utils/cache.d.ts.map +1 -1
  84. package/dist/utils/cache.js +2 -2
  85. package/dist/utils/cache.js.map +1 -1
  86. package/dist/utils/codec.d.ts +1 -1
  87. package/dist/utils/codec.d.ts.map +1 -1
  88. package/dist/utils/codec.js +181 -182
  89. package/dist/utils/codec.js.map +1 -1
  90. package/dist/version.d.ts +12 -0
  91. package/dist/version.d.ts.map +1 -0
  92. package/dist/version.js +12 -0
  93. package/dist/version.js.map +1 -0
  94. package/package.json +3 -2
  95. package/runtime/__pycache__/safe_codec.cpython-311.pyc +0 -0
  96. package/runtime/__pycache__/tywrap_bridge_core.cpython-311.pyc +0 -0
  97. package/runtime/python_bridge.py +54 -6
  98. package/runtime/safe_codec.py +8 -8
  99. package/runtime/tywrap_bridge_core.py +159 -23
  100. package/src/cli.ts +8 -12
  101. package/src/config/index.ts +271 -165
  102. package/src/core/annotation-parser.ts +112 -105
  103. package/src/core/discovery.ts +32 -0
  104. package/src/core/emit-call.ts +171 -0
  105. package/src/core/generator.ts +67 -263
  106. package/src/core/mapper.ts +125 -110
  107. package/src/index.ts +11 -68
  108. package/src/runtime/bounded-context.ts +2 -2
  109. package/src/runtime/{safe-codec.ts → bridge-codec.ts} +27 -27
  110. package/src/runtime/{http-io.ts → http-transport.ts} +5 -5
  111. package/src/runtime/http.ts +5 -5
  112. package/src/runtime/index.ts +23 -1
  113. package/src/runtime/node.ts +15 -15
  114. package/src/runtime/pooled-transport.ts +15 -15
  115. package/src/runtime/pyodide-bootstrap-core.generated.ts +1 -1
  116. package/src/runtime/{pyodide-io.ts → pyodide-transport.ts} +7 -7
  117. package/src/runtime/pyodide.ts +6 -6
  118. package/src/runtime/rpc-client.ts +12 -8
  119. package/src/runtime/{process-io.ts → subprocess-transport.ts} +8 -8
  120. package/src/runtime/{worker-pool.ts → transport-pool.ts} +26 -26
  121. package/src/runtime/transport.ts +15 -8
  122. package/src/types/index.ts +10 -1
  123. package/src/utils/cache.ts +2 -2
  124. package/src/utils/codec.ts +217 -196
  125. package/src/version.ts +12 -0
  126. package/dist/runtime/http-io.d.ts.map +0 -1
  127. package/dist/runtime/http-io.js.map +0 -1
  128. package/dist/runtime/optimized-node.d.ts +0 -23
  129. package/dist/runtime/optimized-node.d.ts.map +0 -1
  130. package/dist/runtime/optimized-node.js +0 -23
  131. package/dist/runtime/optimized-node.js.map +0 -1
  132. package/dist/runtime/process-io.d.ts.map +0 -1
  133. package/dist/runtime/process-io.js.map +0 -1
  134. package/dist/runtime/protocol.d.ts +0 -3
  135. package/dist/runtime/protocol.d.ts.map +0 -1
  136. package/dist/runtime/protocol.js +0 -3
  137. package/dist/runtime/protocol.js.map +0 -1
  138. package/dist/runtime/pyodide-io.d.ts.map +0 -1
  139. package/dist/runtime/pyodide-io.js.map +0 -1
  140. package/dist/runtime/safe-codec.d.ts.map +0 -1
  141. package/dist/runtime/safe-codec.js.map +0 -1
  142. package/dist/runtime/worker-pool.d.ts.map +0 -1
  143. package/dist/runtime/worker-pool.js.map +0 -1
  144. package/dist/utils/bundle-optimizer.d.ts +0 -182
  145. package/dist/utils/bundle-optimizer.d.ts.map +0 -1
  146. package/dist/utils/bundle-optimizer.js +0 -680
  147. package/dist/utils/bundle-optimizer.js.map +0 -1
  148. package/dist/utils/memory-profiler.d.ts +0 -123
  149. package/dist/utils/memory-profiler.d.ts.map +0 -1
  150. package/dist/utils/memory-profiler.js +0 -426
  151. package/dist/utils/memory-profiler.js.map +0 -1
  152. package/src/runtime/optimized-node.ts +0 -25
  153. package/src/runtime/protocol.ts +0 -2
  154. package/src/utils/bundle-optimizer.ts +0 -876
  155. package/src/utils/memory-profiler.ts +0 -582
package/src/index.ts CHANGED
@@ -3,70 +3,20 @@
3
3
  *
4
4
  * @description Build-time code generation system that makes Python libraries
5
5
  * feel native in TypeScript with zero runtime overhead
6
+ *
7
+ * This is the package root. It intentionally exposes only the stable,
8
+ * consumer-facing surface. Runtime plumbing (codec, transport, bridge
9
+ * implementations, disposables, validators) lives behind the subpath
10
+ * entrypoints: `tywrap/runtime`, `tywrap/node`, `tywrap/pyodide`, `tywrap/http`.
6
11
  */
7
12
 
8
13
  import { tywrap } from './tywrap.js';
9
14
 
15
+ // Configuration
10
16
  export type { TywrapConfig, ResolvedTywrapConfig } from './config/index.js';
11
17
  export { defineConfig, resolveConfig } from './config/index.js';
12
- // DisposableBase - lifecycle/resource base for cross-boundary components
13
- export {
14
- DisposableBase,
15
- type ContextState,
16
- type ExecuteOptions,
17
- } from './runtime/bounded-context.js';
18
- // RpcClient - the single correlated-RPC client (codec + transport), held by bridges
19
- export { RpcClient, type RpcClientOptions } from './runtime/rpc-client.js';
20
- // SafeCodec - validation and serialization for JS<->Python boundary
21
- export { SafeCodec, type CodecOptions } from './runtime/safe-codec.js';
22
- // Transport - abstract I/O channel interface
23
- export type {
24
- Transport,
25
- TransportOptions,
26
- ProtocolMessage,
27
- ProtocolResponse,
28
- } from './runtime/transport.js';
29
- export {
30
- PROTOCOL_ID,
31
- isTransport,
32
- isProtocolMessage,
33
- isProtocolResponse,
34
- } from './runtime/transport.js';
35
- // Transport implementations
36
- export { ProcessIO, type ProcessIOOptions } from './runtime/process-io.js';
37
- export { HttpIO, type HttpIOOptions } from './runtime/http-io.js';
38
- export { PyodideIO, type PyodideIOOptions } from './runtime/pyodide-io.js';
39
- // WorkerPool - concurrent transport management
40
- export { WorkerPool, type WorkerPoolOptions, type PooledWorker } from './runtime/worker-pool.js';
41
- // PooledTransport - Transport adapter that wraps WorkerPool
42
- export { PooledTransport, type PooledTransportOptions } from './runtime/pooled-transport.js';
43
- export type { Disposable } from './runtime/disposable.js';
44
- export { isDisposable, safeDispose, disposeAll } from './runtime/disposable.js';
45
- export {
46
- ValidationError,
47
- isFiniteNumber,
48
- isPositiveNumber,
49
- isNonNegativeNumber,
50
- isNonEmptyString,
51
- isPlainObject,
52
- assertFiniteNumber,
53
- assertPositive,
54
- assertNonNegative,
55
- assertString,
56
- assertNonEmptyString,
57
- assertArray,
58
- assertObject,
59
- containsSpecialFloat,
60
- assertNoSpecialFloats,
61
- sanitizeForFilename,
62
- containsPathTraversal,
63
- } from './runtime/validators.js';
64
-
65
- /**
66
- * @deprecated Use DisposableBase instead. RuntimeBridge will be removed in the next major version.
67
- */
68
- export { RuntimeBridge } from './runtime/base.js';
69
18
 
19
+ // Bridge error hierarchy
70
20
  export {
71
21
  BridgeError,
72
22
  BridgeCodecError,
@@ -75,12 +25,6 @@ export {
75
25
  BridgeDisposedError,
76
26
  BridgeExecutionError,
77
27
  } from './runtime/errors.js';
78
- export { getRuntimeBridge, setRuntimeBridge, clearRuntimeBridge } from './runtime/index.js';
79
-
80
- // Runtime-specific exports (Bridge facades that HOLD an RpcClient)
81
- export { NodeBridge, type NodeBridgeOptions } from './runtime/node.js';
82
- export { PyodideBridge, type PyodideBridgeOptions } from './runtime/pyodide.js';
83
- export { HttpBridge, type HttpBridgeOptions } from './runtime/http.js';
84
28
 
85
29
  // Core types
86
30
  export type {
@@ -138,6 +82,8 @@ export type { GenerateFailure, GenerateResult, GenerateRunOptions } from './tywr
138
82
 
139
83
  // Runtime detection utilities
140
84
  export { detectRuntime, isNodejs, isDeno, isBun, isBrowser } from './utils/runtime.js';
85
+
86
+ // Arrow/codec public helpers
141
87
  export {
142
88
  decodeValue,
143
89
  decodeValueAsync,
@@ -146,11 +92,8 @@ export {
146
92
  clearArrowDecoder,
147
93
  } from './utils/codec.js';
148
94
 
149
- // Version info
150
- export const VERSION = '0.3.0';
95
+ // Version info — single-sourced from package.json via scripts/generate-version.mjs
96
+ export { VERSION } from './version.js';
151
97
 
152
- /**
153
- * Quick setup function for getting started
154
- */
155
98
  // Default export for convenience
156
99
  export default tywrap;
@@ -6,8 +6,8 @@
6
6
  * ownership tracking. It carries ZERO RPC methods by design — the
7
7
  * cross-boundary RPC contract (call/instantiate/callMethod/disposeInstance)
8
8
  * is PythonRuntime, implemented only by the bridge facades, never by a base
9
- * class or a transport. This separation is what keeps transports (ProcessIO,
10
- * PooledTransport, WorkerPool, PyodideIO) and RpcClient from having to stub
9
+ * class or a transport. This separation is what keeps transports (SubprocessTransport,
10
+ * PooledTransport, TransportPool, PyodideTransport) and RpcClient from having to stub
11
11
  * RPC methods they do not implement.
12
12
  *
13
13
  * Reused by RpcClient and all transports.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SafeCodec - Unified validation and serialization for JS<->Python boundary crossing.
2
+ * BridgeCodec - Unified validation and serialization for JS<->Python boundary crossing.
3
3
  *
4
4
  * Provides safe encoding/decoding with configurable guardrails for:
5
5
  * - Special float rejection (NaN, Infinity)
@@ -18,7 +18,7 @@ import { PROTOCOL_ID } from './transport.js';
18
18
  // ═══════════════════════════════════════════════════════════════════════════
19
19
 
20
20
  /**
21
- * Configuration options for SafeCodec behavior.
21
+ * Configuration options for BridgeCodec behavior.
22
22
  */
23
23
  export interface CodecOptions {
24
24
  /** Reject NaN/Infinity in arguments. Default: true */
@@ -48,7 +48,7 @@ interface NormalizedPythonError {
48
48
  traceback?: string;
49
49
  }
50
50
 
51
- interface ProtocolEnvelope {
51
+ interface RpcResponse {
52
52
  id: number;
53
53
  protocol?: string;
54
54
  result?: unknown;
@@ -167,10 +167,10 @@ function isPythonErrorResponse(value: unknown): value is PythonErrorResponse {
167
167
  }
168
168
 
169
169
  /**
170
- * Type guard for protocol response envelope.
171
- * Envelopes must include a numeric id.
170
+ * Type guard for the RPC response wrapper ({ id, result | error }).
171
+ * Responses must include a numeric id.
172
172
  */
173
- function isProtocolEnvelope(value: unknown): value is ProtocolEnvelope {
173
+ function isRpcResponse(value: unknown): value is RpcResponse {
174
174
  if (value === null || typeof value !== 'object') {
175
175
  return false;
176
176
  }
@@ -233,7 +233,7 @@ function summarizePayloadForError(payload: string): string {
233
233
 
234
234
  /**
235
235
  * Validate the protocol version in a response.
236
- * Only validates when the response looks like a protocol envelope (has 'id' field).
236
+ * Only validates when the response looks like an RPC response (has 'id' field).
237
237
  * Throws if protocol is present but doesn't match expected version.
238
238
  * Allows missing protocol for backwards compatibility.
239
239
  */
@@ -242,7 +242,7 @@ function validateProtocolVersion(value: unknown): void {
242
242
  return;
243
243
  }
244
244
  const obj = value as Record<string, unknown>;
245
- // Only validate protocol on protocol envelopes (responses with 'id' field)
245
+ // Only validate protocol on RPC responses (responses with 'id' field)
246
246
  // This avoids false positives on user data that happens to contain 'protocol' key
247
247
  if (!('id' in obj)) {
248
248
  return;
@@ -293,16 +293,16 @@ function findSpecialFloatPath(
293
293
  }
294
294
 
295
295
  // ═══════════════════════════════════════════════════════════════════════════
296
- // SAFE CODEC CLASS
296
+ // BRIDGE CODEC CLASS
297
297
  // ═══════════════════════════════════════════════════════════════════════════
298
298
 
299
299
  /**
300
- * SafeCodec provides unified validation and serialization for JS<->Python
300
+ * BridgeCodec provides unified validation and serialization for JS<->Python
301
301
  * boundary crossing with configurable guardrails.
302
302
  *
303
303
  * @example
304
304
  * ```typescript
305
- * const codec = new SafeCodec({ rejectSpecialFloats: true });
305
+ * const codec = new BridgeCodec({ rejectSpecialFloats: true });
306
306
  *
307
307
  * // Encoding a request
308
308
  * const payload = codec.encodeRequest({ data: [1, 2, 3] });
@@ -314,7 +314,7 @@ function findSpecialFloatPath(
314
314
  * const dataframe = await codec.decodeResponseAsync<ArrowTable>(arrowPayload);
315
315
  * ```
316
316
  */
317
- export class SafeCodec {
317
+ export class BridgeCodec {
318
318
  private readonly rejectSpecialFloats: boolean;
319
319
  private readonly rejectNonStringKeys: boolean;
320
320
  private readonly maxPayloadBytes: number;
@@ -332,7 +332,7 @@ export class SafeCodec {
332
332
  }
333
333
 
334
334
  private assertValidBase64(b64: string): void {
335
- if (!SafeCodec.base64Pattern.test(b64)) {
335
+ if (!BridgeCodec.base64Pattern.test(b64)) {
336
336
  throw new BridgeCodecError('Invalid base64 in bytes envelope', {
337
337
  codecPhase: 'decode',
338
338
  valueType: 'bytes',
@@ -368,8 +368,8 @@ export class SafeCodec {
368
368
  * JSON.parse reviver that decodes bytes envelopes.
369
369
  *
370
370
  * Supported shapes:
371
- * - { "__tywrap_bytes__": true, "b64": "..." } (JS SafeCodec.encodeRequest; also allowed in responses)
372
- * - { "__type__": "bytes", "encoding": "base64", "data": "..." } (Python SafeCodec default encoder)
371
+ * - { "__tywrap_bytes__": true, "b64": "..." } (JS BridgeCodec.encodeRequest; also allowed in responses)
372
+ * - { "__type__": "bytes", "encoding": "base64", "data": "..." } (Python BridgeCodec default encoder)
373
373
  */
374
374
  private reviveValue(_key: string, value: unknown): unknown {
375
375
  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
@@ -410,20 +410,20 @@ export class SafeCodec {
410
410
  return bridgeError;
411
411
  }
412
412
 
413
- private extractResultFromResponseEnvelope(parsed: unknown): unknown {
414
- if (isProtocolEnvelope(parsed)) {
415
- const envelope = parsed;
416
- const hasResult = hasOwnKey(envelope, 'result');
417
- const hasError = hasOwnKey(envelope, 'error');
413
+ private extractResultFromRpcResponse(parsed: unknown): unknown {
414
+ if (isRpcResponse(parsed)) {
415
+ const response = parsed;
416
+ const hasResult = hasOwnKey(response, 'result');
417
+ const hasError = hasOwnKey(response, 'error');
418
418
 
419
419
  if (hasResult && hasError) {
420
420
  throw new BridgeProtocolError('Protocol response cannot include both "result" and "error"');
421
421
  }
422
422
 
423
423
  if (hasError) {
424
- const normalizedError = normalizeErrorPayload(envelope.error);
424
+ const normalizedError = normalizeErrorPayload(response.error);
425
425
  if (!normalizedError) {
426
- const details = describeInvalidErrorPayload(envelope.error);
426
+ const details = describeInvalidErrorPayload(response.error);
427
427
  throw new BridgeProtocolError(`Invalid response "error" payload: ${details}`);
428
428
  }
429
429
  throw this.toBridgeExecutionError(normalizedError);
@@ -433,7 +433,7 @@ export class SafeCodec {
433
433
  throw new BridgeProtocolError('Protocol response missing "result" or "error" field');
434
434
  }
435
435
 
436
- return envelope.result;
436
+ return response.result;
437
437
  }
438
438
 
439
439
  if (isPythonErrorResponse(parsed)) {
@@ -522,7 +522,7 @@ export class SafeCodec {
522
522
  * @param payload - The JSON string received from Python
523
523
  * @returns Decoded and validated result
524
524
  * @throws BridgeCodecError if payload is invalid or decoding fails
525
- * @throws BridgeProtocolError if protocol envelope is invalid
525
+ * @throws BridgeProtocolError if the RPC response is invalid
526
526
  * @throws BridgeExecutionError if response contains a Python error
527
527
  */
528
528
  decodeResponse<T>(payload: string): T {
@@ -553,7 +553,7 @@ export class SafeCodec {
553
553
  // Validate protocol version (if present)
554
554
  validateProtocolVersion(parsed);
555
555
 
556
- const result = this.extractResultFromResponseEnvelope(parsed);
556
+ const result = this.extractResultFromRpcResponse(parsed);
557
557
 
558
558
  // Post-decode validation for special floats if enabled
559
559
  if (this.rejectSpecialFloats && containsSpecialFloat(result)) {
@@ -574,7 +574,7 @@ export class SafeCodec {
574
574
  * @param payload - The JSON string received from Python
575
575
  * @returns Decoded and validated result with Arrow decoding applied
576
576
  * @throws BridgeCodecError if payload is invalid or decoding fails
577
- * @throws BridgeProtocolError if protocol envelope is invalid
577
+ * @throws BridgeProtocolError if the RPC response is invalid
578
578
  * @throws BridgeExecutionError if response contains a Python error
579
579
  */
580
580
  async decodeResponseAsync<T>(payload: string): Promise<T> {
@@ -605,7 +605,7 @@ export class SafeCodec {
605
605
  // Validate protocol version (if present)
606
606
  validateProtocolVersion(parsed);
607
607
 
608
- const result = this.extractResultFromResponseEnvelope(parsed);
608
+ const result = this.extractResultFromRpcResponse(parsed);
609
609
 
610
610
  // Apply Arrow decoding to the result
611
611
  let decoded: unknown;
@@ -20,9 +20,9 @@ import type { Transport } from './transport.js';
20
20
  // =============================================================================
21
21
 
22
22
  /**
23
- * Configuration options for HttpIO transport.
23
+ * Configuration options for the HttpTransport.
24
24
  */
25
- export interface HttpIOOptions {
25
+ export interface HttpTransportOptions {
26
26
  /** Base URL for the Python server (e.g., 'http://localhost:8000') */
27
27
  baseURL: string;
28
28
 
@@ -52,7 +52,7 @@ export interface HttpIOOptions {
52
52
  *
53
53
  * @example
54
54
  * ```typescript
55
- * const transport = new HttpIO({ baseURL: 'http://localhost:8000' });
55
+ * const transport = new HttpTransport({ baseURL: 'http://localhost:8000' });
56
56
  * await transport.init(); // No-op but follows Transport contract
57
57
  *
58
58
  * const response = await transport.send(
@@ -63,13 +63,13 @@ export interface HttpIOOptions {
63
63
  * await transport.dispose(); // Marks as disposed
64
64
  * ```
65
65
  */
66
- export class HttpIO implements Transport {
66
+ export class HttpTransport implements Transport {
67
67
  private readonly baseURL: string;
68
68
  private readonly headers: Record<string, string>;
69
69
  private readonly defaultTimeoutMs: number;
70
70
  private _isDisposed = false;
71
71
 
72
- constructor(options: HttpIOOptions) {
72
+ constructor(options: HttpTransportOptions) {
73
73
  // Normalize URL - remove trailing slash
74
74
  this.baseURL = options.baseURL.replace(/\/$/, '');
75
75
  this.headers = {
@@ -2,7 +2,7 @@
2
2
  * HTTP runtime bridge.
3
3
  *
4
4
  * HttpBridge is a thin facade: it extends DisposableBase (lifecycle/resources)
5
- * and implements PythonRuntime by HOLDING an RpcClient over an HttpIO transport
5
+ * and implements PythonRuntime by HOLDING an RpcClient over an HttpTransport
6
6
  * for stateless HTTP POST-based communication with a Python server.
7
7
  *
8
8
  * @see https://github.com/bbopen/tywrap/issues/149
@@ -13,8 +13,8 @@ import { autoRegisterArrowDecoder } from '../utils/codec.js';
13
13
 
14
14
  import { DisposableBase } from './bounded-context.js';
15
15
  import { RpcClient, type GetBridgeInfoOptions } from './rpc-client.js';
16
- import { HttpIO } from './http-io.js';
17
- import type { CodecOptions } from './safe-codec.js';
16
+ import { HttpTransport } from './http-transport.js';
17
+ import type { CodecOptions } from './bridge-codec.js';
18
18
 
19
19
  // =============================================================================
20
20
  // OPTIONS
@@ -51,7 +51,7 @@ export interface HttpBridgeOptions {
51
51
  * Features:
52
52
  * - Stateless HTTP POST communication
53
53
  * - Timeout handling via AbortController
54
- * - Full SafeCodec validation (NaN/Infinity rejection, key validation)
54
+ * - Full BridgeCodec validation (NaN/Infinity rejection, key validation)
55
55
  * - Automatic Arrow decoding for DataFrames/ndarrays
56
56
  *
57
57
  * @example
@@ -76,7 +76,7 @@ export class HttpBridge extends DisposableBase implements PythonRuntime {
76
76
  constructor(options: HttpBridgeOptions) {
77
77
  super();
78
78
 
79
- const transport = new HttpIO({
79
+ const transport = new HttpTransport({
80
80
  baseURL: options.baseURL,
81
81
  headers: options.headers,
82
82
  defaultTimeoutMs: options.timeoutMs,
@@ -1,9 +1,31 @@
1
1
  /**
2
- * Runtime bridge registry for generated wrappers.
2
+ * tywrap/runtime entrypoint.
3
+ *
4
+ * Exposes the runtime bridge registry used by generated wrappers, plus the
5
+ * lower-level boundary primitives (codec + transport contract) for consumers
6
+ * building custom bridges. These were previously re-exported from the package
7
+ * root; they now live here so the root surface stays small.
3
8
  */
4
9
 
5
10
  import type { RuntimeExecution } from '../types/index.js';
6
11
 
12
+ // BridgeCodec — validation and serialization for the JS<->Python boundary
13
+ export { BridgeCodec, type CodecOptions } from './bridge-codec.js';
14
+
15
+ // Transport contract — abstract I/O channel interface and guards
16
+ export type {
17
+ Transport,
18
+ TransportOptions,
19
+ ProtocolMessage,
20
+ ProtocolResponse,
21
+ } from './transport.js';
22
+ export {
23
+ PROTOCOL_ID,
24
+ isTransport,
25
+ isProtocolMessage,
26
+ isProtocolResponse,
27
+ } from './transport.js';
28
+
7
29
  let runtimeBridge: RuntimeExecution | null = null;
8
30
 
9
31
  export function setRuntimeBridge(bridge: RuntimeExecution): void {
@@ -2,7 +2,7 @@
2
2
  * Node.js runtime bridge.
3
3
  *
4
4
  * NodeBridge is a thin facade: it extends DisposableBase (lifecycle/resources)
5
- * and implements PythonRuntime by HOLDING an RpcClient. It uses ProcessIO
5
+ * and implements PythonRuntime by HOLDING an RpcClient. It uses SubprocessTransport
6
6
  * transports with optional pooling for concurrent Python execution.
7
7
  *
8
8
  * @see https://github.com/bbopen/tywrap/issues/149
@@ -22,10 +22,10 @@ import { globalCache } from '../utils/cache.js';
22
22
  import { DisposableBase } from './bounded-context.js';
23
23
  import { RpcClient, type GetBridgeInfoOptions } from './rpc-client.js';
24
24
  import { BridgeCodecError, BridgeExecutionError, BridgeProtocolError } from './errors.js';
25
- import { ProcessIO } from './process-io.js';
25
+ import { SubprocessTransport } from './subprocess-transport.js';
26
26
  import { PooledTransport } from './pooled-transport.js';
27
- import type { CodecOptions } from './safe-codec.js';
28
- import type { PooledWorker } from './worker-pool.js';
27
+ import type { CodecOptions } from './bridge-codec.js';
28
+ import type { TransportLease } from './transport-pool.js';
29
29
 
30
30
  // =============================================================================
31
31
  // OPTIONS
@@ -84,12 +84,12 @@ export interface NodeBridgeOptions {
84
84
  // ===========================================================================
85
85
 
86
86
  /**
87
- * @deprecated No longer used. Pool idle time is managed by WorkerPool.
87
+ * @deprecated No longer used. Pool idle time is managed by TransportPool.
88
88
  */
89
89
  maxIdleTime?: number;
90
90
 
91
91
  /**
92
- * @deprecated No longer used. Process restart is managed by ProcessIO.
92
+ * @deprecated No longer used. Process restart is managed by SubprocessTransport.
93
93
  */
94
94
  maxRequestsPerProcess?: number;
95
95
 
@@ -99,7 +99,7 @@ export interface NodeBridgeOptions {
99
99
  enableJsonFallback?: boolean;
100
100
 
101
101
  /**
102
- * @deprecated Use ProcessIO options instead.
102
+ * @deprecated Use SubprocessTransport options instead.
103
103
  */
104
104
  maxLineLength?: number;
105
105
  }
@@ -277,7 +277,7 @@ function normalizeWarmupCommands(commands: NodeBridgeOptions['warmupCommands']):
277
277
  * Features:
278
278
  * - Single or multi-process execution via process pooling
279
279
  * - Virtual environment support
280
- * - Full SafeCodec validation (NaN/Infinity rejection, key validation)
280
+ * - Full BridgeCodec validation (NaN/Infinity rejection, key validation)
281
281
  * - Automatic Arrow decoding for DataFrames/ndarrays
282
282
  * - Optional result caching for pure functions
283
283
  * - Process warmup commands
@@ -343,7 +343,7 @@ export class NodeBridge extends DisposableBase implements PythonRuntime {
343
343
  codec: options.codec,
344
344
  warmupCommands,
345
345
  };
346
- // Build environment for ProcessIO
346
+ // Build environment for SubprocessTransport
347
347
  const processEnv = buildProcessEnv(resolvedOptions);
348
348
 
349
349
  // Why a late-bound holder: PooledTransport copies onWorkerReady eagerly at
@@ -360,10 +360,10 @@ export class NodeBridge extends DisposableBase implements PythonRuntime {
360
360
  resolvedOptions.timeoutMs
361
361
  );
362
362
 
363
- // Create pooled transport with ProcessIO workers
363
+ // Create pooled transport with SubprocessTransport workers
364
364
  const transport = new PooledTransport({
365
- createTransport: (): ProcessIO =>
366
- new ProcessIO({
365
+ createTransport: (): SubprocessTransport =>
366
+ new SubprocessTransport({
367
367
  pythonPath: resolvedOptions.pythonPath,
368
368
  bridgeScript: resolvedOptions.scriptPath,
369
369
  env: processEnv,
@@ -676,8 +676,8 @@ function createWorkerReadyCallback(
676
676
  rpcHolder: { rpc?: RpcClient },
677
677
  warmupCommands: WarmupCommand[],
678
678
  timeoutMs: number
679
- ): (worker: PooledWorker) => Promise<void> {
680
- return async (worker: PooledWorker) => {
679
+ ): (worker: TransportLease) => Promise<void> {
680
+ return async (worker: TransportLease) => {
681
681
  const rpc = rpcHolder.rpc;
682
682
  if (!rpc) {
683
683
  throw new BridgeExecutionError('Worker warmup attempted before RpcClient was wired');
@@ -721,7 +721,7 @@ function createWorkerReadyCallback(
721
721
  // =============================================================================
722
722
 
723
723
  /**
724
- * Build environment variables for ProcessIO.
724
+ * Build environment variables for SubprocessTransport.
725
725
  */
726
726
  function buildProcessEnv(options: ResolvedOptions): Record<string, string> {
727
727
  const allowedPrefixes = ['TYWRAP_'];
@@ -1,8 +1,8 @@
1
1
  /**
2
- * PooledTransport - Transport adapter that wraps WorkerPool for multi-process support.
2
+ * PooledTransport - Transport adapter that wraps TransportPool for multi-process support.
3
3
  *
4
- * This transport implements the Transport interface by delegating to a WorkerPool
5
- * of ProcessIO transports. Each send() acquires a worker, sends the message,
4
+ * This transport implements the Transport interface by delegating to a TransportPool
5
+ * of SubprocessTransport transports. Each send() acquires a worker, sends the message,
6
6
  * and releases the worker back to the pool.
7
7
  *
8
8
  * @see https://github.com/bbopen/tywrap/issues/149
@@ -11,7 +11,7 @@
11
11
  import { DisposableBase } from './bounded-context.js';
12
12
  import { BridgeDisposedError, BridgeExecutionError } from './errors.js';
13
13
  import type { Transport } from './transport.js';
14
- import { WorkerPool, type PooledWorker } from './worker-pool.js';
14
+ import { TransportPool, type TransportLease } from './transport-pool.js';
15
15
 
16
16
  // =============================================================================
17
17
  // TYPES
@@ -40,12 +40,12 @@ export interface PooledTransportOptions {
40
40
  * Callback invoked after each worker is created and initialized.
41
41
  * Use this for per-worker warmup (e.g., importing modules, running setup).
42
42
  */
43
- onWorkerReady?: (worker: PooledWorker) => Promise<void>;
43
+ onWorkerReady?: (worker: TransportLease) => Promise<void>;
44
44
 
45
45
  /**
46
46
  * Optional callback used only for background replacement workers.
47
47
  */
48
- onReplacementWorkerReady?: (worker: PooledWorker) => Promise<void>;
48
+ onReplacementWorkerReady?: (worker: TransportLease) => Promise<void>;
49
49
  }
50
50
 
51
51
  // =============================================================================
@@ -53,10 +53,10 @@ export interface PooledTransportOptions {
53
53
  // =============================================================================
54
54
 
55
55
  /**
56
- * Transport adapter that wraps WorkerPool for multi-process message handling.
56
+ * Transport adapter that wraps TransportPool for multi-process message handling.
57
57
  *
58
58
  * PooledTransport presents a single Transport interface while internally
59
- * distributing requests across multiple worker transports (typically ProcessIO).
59
+ * distributing requests across multiple worker transports (typically SubprocessTransport).
60
60
  *
61
61
  * Features:
62
62
  * - Lazy worker creation (transports created on demand)
@@ -67,7 +67,7 @@ export interface PooledTransportOptions {
67
67
  * @example
68
68
  * ```typescript
69
69
  * const transport = new PooledTransport({
70
- * createTransport: () => new ProcessIO({
70
+ * createTransport: () => new SubprocessTransport({
71
71
  * bridgeScript: '/path/to/bridge.py',
72
72
  * }),
73
73
  * maxWorkers: 4,
@@ -87,10 +87,10 @@ export class PooledTransport extends DisposableBase implements Transport {
87
87
  Required<PooledTransportOptions>,
88
88
  'onWorkerReady' | 'onReplacementWorkerReady'
89
89
  > & {
90
- onWorkerReady?: (worker: PooledWorker) => Promise<void>;
91
- onReplacementWorkerReady?: (worker: PooledWorker) => Promise<void>;
90
+ onWorkerReady?: (worker: TransportLease) => Promise<void>;
91
+ onReplacementWorkerReady?: (worker: TransportLease) => Promise<void>;
92
92
  };
93
- private pool?: WorkerPool;
93
+ private pool?: TransportPool;
94
94
 
95
95
  /**
96
96
  * Create a new PooledTransport.
@@ -122,11 +122,11 @@ export class PooledTransport extends DisposableBase implements Transport {
122
122
  /**
123
123
  * Initialize the pooled transport.
124
124
  *
125
- * Creates and initializes the internal WorkerPool.
125
+ * Creates and initializes the internal TransportPool.
126
126
  * If minWorkers > 0, workers are pre-spawned during init.
127
127
  */
128
128
  protected async doInit(): Promise<void> {
129
- this.pool = new WorkerPool({
129
+ this.pool = new TransportPool({
130
130
  createTransport: this.poolOptions.createTransport,
131
131
  maxWorkers: this.poolOptions.maxWorkers,
132
132
  minWorkers: this.poolOptions.minWorkers,
@@ -142,7 +142,7 @@ export class PooledTransport extends DisposableBase implements Transport {
142
142
  /**
143
143
  * Dispose the pooled transport.
144
144
  *
145
- * Disposes the internal WorkerPool, which disposes all workers.
145
+ * Disposes the internal TransportPool, which disposes all workers.
146
146
  */
147
147
  protected async doDispose(): Promise<void> {
148
148
  if (this.pool) {