tywrap 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +20 -4
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +22 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/runtime/base.d.ts +17 -7
  7. package/dist/runtime/base.d.ts.map +1 -1
  8. package/dist/runtime/base.js +18 -1
  9. package/dist/runtime/base.js.map +1 -1
  10. package/dist/runtime/bounded-context.d.ts +252 -0
  11. package/dist/runtime/bounded-context.d.ts.map +1 -0
  12. package/dist/runtime/bounded-context.js +454 -0
  13. package/dist/runtime/bounded-context.js.map +1 -0
  14. package/dist/runtime/bridge-protocol.d.ts +167 -0
  15. package/dist/runtime/bridge-protocol.d.ts.map +1 -0
  16. package/dist/runtime/bridge-protocol.js +247 -0
  17. package/dist/runtime/bridge-protocol.js.map +1 -0
  18. package/dist/runtime/disposable.d.ts +40 -0
  19. package/dist/runtime/disposable.d.ts.map +1 -0
  20. package/dist/runtime/disposable.js +49 -0
  21. package/dist/runtime/disposable.js.map +1 -0
  22. package/dist/runtime/http-io.d.ts +91 -0
  23. package/dist/runtime/http-io.d.ts.map +1 -0
  24. package/dist/runtime/http-io.js +195 -0
  25. package/dist/runtime/http-io.js.map +1 -0
  26. package/dist/runtime/http.d.ts +47 -13
  27. package/dist/runtime/http.d.ts.map +1 -1
  28. package/dist/runtime/http.js +55 -74
  29. package/dist/runtime/http.js.map +1 -1
  30. package/dist/runtime/node.d.ts +97 -130
  31. package/dist/runtime/node.d.ts.map +1 -1
  32. package/dist/runtime/node.js +256 -523
  33. package/dist/runtime/node.js.map +1 -1
  34. package/dist/runtime/pooled-transport.d.ts +131 -0
  35. package/dist/runtime/pooled-transport.d.ts.map +1 -0
  36. package/dist/runtime/pooled-transport.js +175 -0
  37. package/dist/runtime/pooled-transport.js.map +1 -0
  38. package/dist/runtime/process-io.d.ts +204 -0
  39. package/dist/runtime/process-io.d.ts.map +1 -0
  40. package/dist/runtime/process-io.js +695 -0
  41. package/dist/runtime/process-io.js.map +1 -0
  42. package/dist/runtime/pyodide-io.d.ts +155 -0
  43. package/dist/runtime/pyodide-io.d.ts.map +1 -0
  44. package/dist/runtime/pyodide-io.js +397 -0
  45. package/dist/runtime/pyodide-io.js.map +1 -0
  46. package/dist/runtime/pyodide.d.ts +51 -19
  47. package/dist/runtime/pyodide.d.ts.map +1 -1
  48. package/dist/runtime/pyodide.js +57 -186
  49. package/dist/runtime/pyodide.js.map +1 -1
  50. package/dist/runtime/safe-codec.d.ts +81 -0
  51. package/dist/runtime/safe-codec.d.ts.map +1 -0
  52. package/dist/runtime/safe-codec.js +345 -0
  53. package/dist/runtime/safe-codec.js.map +1 -0
  54. package/dist/runtime/transport.d.ts +186 -0
  55. package/dist/runtime/transport.d.ts.map +1 -0
  56. package/dist/runtime/transport.js +86 -0
  57. package/dist/runtime/transport.js.map +1 -0
  58. package/dist/runtime/validators.d.ts +131 -0
  59. package/dist/runtime/validators.d.ts.map +1 -0
  60. package/dist/runtime/validators.js +219 -0
  61. package/dist/runtime/validators.js.map +1 -0
  62. package/dist/runtime/worker-pool.d.ts +196 -0
  63. package/dist/runtime/worker-pool.d.ts.map +1 -0
  64. package/dist/runtime/worker-pool.js +371 -0
  65. package/dist/runtime/worker-pool.js.map +1 -0
  66. package/dist/utils/codec.d.ts.map +1 -1
  67. package/dist/utils/codec.js +120 -1
  68. package/dist/utils/codec.js.map +1 -1
  69. package/package.json +2 -2
  70. package/runtime/python_bridge.py +30 -3
  71. package/runtime/safe_codec.py +344 -0
  72. package/src/index.ts +48 -5
  73. package/src/runtime/base.ts +18 -26
  74. package/src/runtime/bounded-context.ts +608 -0
  75. package/src/runtime/bridge-protocol.ts +319 -0
  76. package/src/runtime/disposable.ts +65 -0
  77. package/src/runtime/http-io.ts +244 -0
  78. package/src/runtime/http.ts +71 -117
  79. package/src/runtime/node.ts +358 -691
  80. package/src/runtime/pooled-transport.ts +252 -0
  81. package/src/runtime/process-io.ts +902 -0
  82. package/src/runtime/pyodide-io.ts +485 -0
  83. package/src/runtime/pyodide.ts +75 -215
  84. package/src/runtime/safe-codec.ts +443 -0
  85. package/src/runtime/transport.ts +273 -0
  86. package/src/runtime/validators.ts +241 -0
  87. package/src/runtime/worker-pool.ts +498 -0
  88. package/src/utils/codec.ts +126 -1
@@ -0,0 +1,345 @@
1
+ /**
2
+ * SafeCodec - Unified validation and serialization for JS<->Python boundary crossing.
3
+ *
4
+ * Provides safe encoding/decoding with configurable guardrails for:
5
+ * - Special float rejection (NaN, Infinity)
6
+ * - Non-string key detection
7
+ * - Payload size limits
8
+ * - Binary data handling
9
+ */
10
+ import { BridgeProtocolError, BridgeExecutionError } from './errors.js';
11
+ import { containsSpecialFloat } from './validators.js';
12
+ import { decodeValueAsync as decodeArrowValue } from '../utils/codec.js';
13
+ import { PROTOCOL_ID } from './transport.js';
14
+ // ═══════════════════════════════════════════════════════════════════════════
15
+ // CONSTANTS
16
+ // ═══════════════════════════════════════════════════════════════════════════
17
+ const DEFAULT_MAX_PAYLOAD_BYTES = 10 * 1024 * 1024; // 10MB
18
+ // ═══════════════════════════════════════════════════════════════════════════
19
+ // HELPER FUNCTIONS
20
+ // ═══════════════════════════════════════════════════════════════════════════
21
+ /**
22
+ * Check if a value is a plain object (not null, not array, not Map/Set/etc).
23
+ */
24
+ function isPlainObject(value) {
25
+ if (value === null || typeof value !== 'object') {
26
+ return false;
27
+ }
28
+ const proto = Object.getPrototypeOf(value);
29
+ return proto === Object.prototype || proto === null;
30
+ }
31
+ /**
32
+ * Build a path string for error messages.
33
+ */
34
+ function buildPath(basePath, key) {
35
+ if (basePath === '') {
36
+ return typeof key === 'number' ? `[${key}]` : key;
37
+ }
38
+ return typeof key === 'number' ? `${basePath}[${key}]` : `${basePath}.${key}`;
39
+ }
40
+ /**
41
+ * Recursively check for non-string keys in objects and Maps.
42
+ * Throws BridgeProtocolError with path indication if found.
43
+ */
44
+ function assertStringKeys(value, path = '') {
45
+ if (value === null || typeof value !== 'object') {
46
+ return;
47
+ }
48
+ // Check Map instances for non-string keys
49
+ if (value instanceof Map) {
50
+ for (const key of value.keys()) {
51
+ if (typeof key !== 'string') {
52
+ const keyDesc = typeof key === 'symbol' ? key.toString() : String(key);
53
+ const location = path ? ` at ${path}` : '';
54
+ throw new BridgeProtocolError(`Non-string key found in Map${location}: ${keyDesc} (${typeof key})`);
55
+ }
56
+ }
57
+ // Recurse into Map values
58
+ for (const [key, val] of value.entries()) {
59
+ assertStringKeys(val, buildPath(path, key));
60
+ }
61
+ return;
62
+ }
63
+ // Check arrays
64
+ if (Array.isArray(value)) {
65
+ for (let i = 0; i < value.length; i++) {
66
+ assertStringKeys(value[i], buildPath(path, i));
67
+ }
68
+ return;
69
+ }
70
+ // Check plain objects for symbol keys
71
+ if (isPlainObject(value)) {
72
+ // Symbol keys are not enumerated by Object.keys, use getOwnPropertySymbols
73
+ const symbolKeys = Object.getOwnPropertySymbols(value);
74
+ const firstSymbol = symbolKeys[0];
75
+ if (firstSymbol !== undefined) {
76
+ const symbolDesc = firstSymbol.toString();
77
+ const location = path ? ` at ${path}` : '';
78
+ throw new BridgeProtocolError(`Symbol key found in object${location}: ${symbolDesc}`);
79
+ }
80
+ // Recurse into object values
81
+ for (const key of Object.keys(value)) {
82
+ assertStringKeys(value[key], buildPath(path, key));
83
+ }
84
+ }
85
+ }
86
+ /**
87
+ * Check if a value is a Python error response.
88
+ */
89
+ function isPythonErrorResponse(value) {
90
+ if (value === null || typeof value !== 'object') {
91
+ return false;
92
+ }
93
+ const obj = value;
94
+ if (!obj.error || typeof obj.error !== 'object' || obj.error === null) {
95
+ return false;
96
+ }
97
+ const error = obj.error;
98
+ return typeof error.type === 'string' && typeof error.message === 'string';
99
+ }
100
+ function isProtocolResultResponse(value) {
101
+ if (value === null || typeof value !== 'object') {
102
+ return false;
103
+ }
104
+ const obj = value;
105
+ return typeof obj.id === 'number' && 'result' in obj;
106
+ }
107
+ /**
108
+ * Validate the protocol version in a response.
109
+ * Only validates when the response looks like a protocol envelope (has 'id' field).
110
+ * Throws if protocol is present but doesn't match expected version.
111
+ * Allows missing protocol for backwards compatibility.
112
+ */
113
+ function validateProtocolVersion(value) {
114
+ if (value === null || typeof value !== 'object') {
115
+ return;
116
+ }
117
+ const obj = value;
118
+ // Only validate protocol on protocol envelopes (responses with 'id' field)
119
+ // This avoids false positives on user data that happens to contain 'protocol' key
120
+ if (!('id' in obj)) {
121
+ return;
122
+ }
123
+ if ('protocol' in obj && obj.protocol !== PROTOCOL_ID) {
124
+ throw new BridgeProtocolError(`Invalid protocol version: expected "${PROTOCOL_ID}", got "${obj.protocol}"`);
125
+ }
126
+ }
127
+ /**
128
+ * Find the path to a special float in a value structure.
129
+ * Returns undefined if no special float is found.
130
+ */
131
+ function findSpecialFloatPath(value, path = '') {
132
+ if (typeof value === 'number' && !Number.isFinite(value)) {
133
+ return path || 'root';
134
+ }
135
+ if (Array.isArray(value)) {
136
+ for (let i = 0; i < value.length; i++) {
137
+ const result = findSpecialFloatPath(value[i], buildPath(path, i));
138
+ if (result !== undefined) {
139
+ return result;
140
+ }
141
+ }
142
+ }
143
+ if (isPlainObject(value)) {
144
+ for (const key of Object.keys(value)) {
145
+ const result = findSpecialFloatPath(value[key], buildPath(path, key));
146
+ if (result !== undefined) {
147
+ return result;
148
+ }
149
+ }
150
+ }
151
+ return undefined;
152
+ }
153
+ // ═══════════════════════════════════════════════════════════════════════════
154
+ // SAFE CODEC CLASS
155
+ // ═══════════════════════════════════════════════════════════════════════════
156
+ /**
157
+ * SafeCodec provides unified validation and serialization for JS<->Python
158
+ * boundary crossing with configurable guardrails.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const codec = new SafeCodec({ rejectSpecialFloats: true });
163
+ *
164
+ * // Encoding a request
165
+ * const payload = codec.encodeRequest({ data: [1, 2, 3] });
166
+ *
167
+ * // Decoding a response
168
+ * const result = codec.decodeResponse<MyType>(responsePayload);
169
+ *
170
+ * // Async decoding with Arrow support
171
+ * const dataframe = await codec.decodeResponseAsync<ArrowTable>(arrowPayload);
172
+ * ```
173
+ */
174
+ export class SafeCodec {
175
+ rejectSpecialFloats;
176
+ rejectNonStringKeys;
177
+ maxPayloadBytes;
178
+ bytesHandling;
179
+ constructor(options = {}) {
180
+ this.rejectSpecialFloats = options.rejectSpecialFloats ?? true;
181
+ this.rejectNonStringKeys = options.rejectNonStringKeys ?? true;
182
+ this.maxPayloadBytes = options.maxPayloadBytes ?? DEFAULT_MAX_PAYLOAD_BYTES;
183
+ this.bytesHandling = options.bytesHandling ?? 'base64';
184
+ }
185
+ /**
186
+ * Validate and encode a request payload.
187
+ * Called before sending to Python.
188
+ *
189
+ * @param message - The message to encode
190
+ * @returns JSON string ready to send
191
+ * @throws BridgeProtocolError if validation fails or encoding fails
192
+ */
193
+ encodeRequest(message) {
194
+ // Validate special floats if enabled
195
+ if (this.rejectSpecialFloats && containsSpecialFloat(message)) {
196
+ const floatPath = findSpecialFloatPath(message);
197
+ throw new BridgeProtocolError(`Cannot encode request: contains non-finite number (NaN or Infinity) at ${floatPath}`);
198
+ }
199
+ // Validate string keys if enabled
200
+ if (this.rejectNonStringKeys) {
201
+ assertStringKeys(message);
202
+ }
203
+ // Serialize to JSON with error handling
204
+ let payload;
205
+ try {
206
+ payload = JSON.stringify(message, (key, value) => {
207
+ // Handle bytes based on configuration
208
+ if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
209
+ switch (this.bytesHandling) {
210
+ case 'reject':
211
+ throw new BridgeProtocolError(`Cannot encode request: binary data found at ${key || 'root'} (bytesHandling: reject)`);
212
+ case 'base64': {
213
+ const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : value;
214
+ const b64 = this.toBase64(bytes);
215
+ return { __tywrap_bytes__: true, b64 };
216
+ }
217
+ case 'passthrough':
218
+ default:
219
+ return value;
220
+ }
221
+ }
222
+ return value;
223
+ });
224
+ }
225
+ catch (err) {
226
+ if (err instanceof BridgeProtocolError) {
227
+ throw err;
228
+ }
229
+ const message = err instanceof Error ? err.message : String(err);
230
+ throw new BridgeProtocolError(`JSON serialization failed: ${message}`);
231
+ }
232
+ // Check payload size
233
+ const payloadBytes = new TextEncoder().encode(payload).length;
234
+ if (payloadBytes > this.maxPayloadBytes) {
235
+ throw new BridgeProtocolError(`Payload size ${payloadBytes} bytes exceeds maximum ${this.maxPayloadBytes} bytes`);
236
+ }
237
+ return payload;
238
+ }
239
+ /**
240
+ * Decode and validate a response payload.
241
+ * Called after receiving from Python.
242
+ *
243
+ * @param payload - The JSON string received from Python
244
+ * @returns Decoded and validated result
245
+ * @throws BridgeProtocolError if payload is invalid
246
+ * @throws BridgeExecutionError if response contains a Python error
247
+ */
248
+ decodeResponse(payload) {
249
+ // Check payload size first
250
+ const payloadBytes = new TextEncoder().encode(payload).length;
251
+ if (payloadBytes > this.maxPayloadBytes) {
252
+ throw new BridgeProtocolError(`Response payload size ${payloadBytes} bytes exceeds maximum ${this.maxPayloadBytes} bytes`);
253
+ }
254
+ // Parse JSON
255
+ let parsed;
256
+ try {
257
+ parsed = JSON.parse(payload);
258
+ }
259
+ catch (err) {
260
+ const message = err instanceof Error ? err.message : String(err);
261
+ throw new BridgeProtocolError(`JSON parse failed: ${message}`);
262
+ }
263
+ // Validate protocol version (if present)
264
+ validateProtocolVersion(parsed);
265
+ // Check for Python error response
266
+ if (isPythonErrorResponse(parsed)) {
267
+ const error = new BridgeExecutionError(`${parsed.error.type}: ${parsed.error.message}`);
268
+ error.traceback = parsed.error.traceback;
269
+ throw error;
270
+ }
271
+ // Extract the result field from the response envelope
272
+ const result = isProtocolResultResponse(parsed) ? parsed.result : parsed;
273
+ // Post-decode validation for special floats if enabled
274
+ if (this.rejectSpecialFloats && containsSpecialFloat(result)) {
275
+ const floatPath = findSpecialFloatPath(result);
276
+ throw new BridgeProtocolError(`Response contains non-finite number (NaN or Infinity) at ${floatPath}`);
277
+ }
278
+ return result;
279
+ }
280
+ /**
281
+ * Async version that applies Arrow decoders.
282
+ * Use this when the response may contain encoded DataFrames or ndarrays.
283
+ *
284
+ * @param payload - The JSON string received from Python
285
+ * @returns Decoded and validated result with Arrow decoding applied
286
+ * @throws BridgeProtocolError if payload is invalid
287
+ * @throws BridgeExecutionError if response contains a Python error
288
+ */
289
+ async decodeResponseAsync(payload) {
290
+ // Check payload size first
291
+ const payloadBytes = new TextEncoder().encode(payload).length;
292
+ if (payloadBytes > this.maxPayloadBytes) {
293
+ throw new BridgeProtocolError(`Response payload size ${payloadBytes} bytes exceeds maximum ${this.maxPayloadBytes} bytes`);
294
+ }
295
+ // Parse JSON
296
+ let parsed;
297
+ try {
298
+ parsed = JSON.parse(payload);
299
+ }
300
+ catch (err) {
301
+ const message = err instanceof Error ? err.message : String(err);
302
+ throw new BridgeProtocolError(`JSON parse failed: ${message}`);
303
+ }
304
+ // Validate protocol version (if present)
305
+ validateProtocolVersion(parsed);
306
+ // Check for Python error response
307
+ if (isPythonErrorResponse(parsed)) {
308
+ const error = new BridgeExecutionError(`${parsed.error.type}: ${parsed.error.message}`);
309
+ error.traceback = parsed.error.traceback;
310
+ throw error;
311
+ }
312
+ // Extract the result field from the response envelope
313
+ const result = isProtocolResultResponse(parsed) ? parsed.result : parsed;
314
+ // Apply Arrow decoding to the result
315
+ let decoded;
316
+ try {
317
+ decoded = await decodeArrowValue(result);
318
+ }
319
+ catch (err) {
320
+ const message = err instanceof Error ? err.message : String(err);
321
+ throw new BridgeProtocolError(`Arrow decoding failed: ${message}`);
322
+ }
323
+ // Post-decode validation for special floats if enabled
324
+ // Note: We check the result value since that's what we're returning
325
+ if (this.rejectSpecialFloats && containsSpecialFloat(result)) {
326
+ const floatPath = findSpecialFloatPath(result);
327
+ throw new BridgeProtocolError(`Response contains non-finite number (NaN or Infinity) at ${floatPath}`);
328
+ }
329
+ return decoded;
330
+ }
331
+ /**
332
+ * Convert Uint8Array to base64 string.
333
+ */
334
+ toBase64(bytes) {
335
+ if (typeof Buffer !== 'undefined') {
336
+ return Buffer.from(bytes).toString('base64');
337
+ }
338
+ if (globalThis.btoa) {
339
+ const binary = String.fromCharCode(...bytes);
340
+ return globalThis.btoa(binary);
341
+ }
342
+ throw new BridgeProtocolError('Base64 encoding is not available in this runtime');
343
+ }
344
+ }
345
+ //# sourceMappingURL=safe-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-codec.js","sourceRoot":"","sources":["../../src/runtime/safe-codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Transport layer for BridgeProtocol.
3
+ *
4
+ * Provides an abstract I/O channel for all bridge communications across
5
+ * the JS-Python boundary. Concrete implementations handle different runtimes:
6
+ * - ProcessIO: Child process with stdio streams (Node.js)
7
+ * - HttpIO: HTTP POST requests (remote Python server)
8
+ * - PyodideIO: In-memory Pyodide calls (browser/WASM)
9
+ *
10
+ * @see https://github.com/bbopen/tywrap/issues/149
11
+ */
12
+ import type { Disposable } from './disposable.js';
13
+ /** Protocol identifier for tywrap communication */
14
+ export declare const PROTOCOL_ID = "tywrap/1";
15
+ /**
16
+ * Protocol message format for all transports.
17
+ *
18
+ * Each method corresponds to a BridgeProtocol operation:
19
+ * - `call`: Invoke a module-level function
20
+ * - `instantiate`: Create a new class instance
21
+ * - `call_method`: Invoke a method on an existing instance
22
+ * - `dispose_instance`: Release an instance handle
23
+ * - `meta`: Get bridge metadata
24
+ */
25
+ export interface ProtocolMessage {
26
+ /** Unique message identifier for request-response correlation */
27
+ id: number;
28
+ /** Protocol identifier (must be 'tywrap/1') */
29
+ protocol: typeof PROTOCOL_ID;
30
+ /** The method to invoke */
31
+ method: 'call' | 'instantiate' | 'call_method' | 'dispose_instance' | 'meta';
32
+ /** Method parameters */
33
+ params: {
34
+ /** Python module path (for call and instantiate) */
35
+ module?: string;
36
+ /** Function name (for call) */
37
+ functionName?: string;
38
+ /** Class name (for instantiate) */
39
+ className?: string;
40
+ /** Instance handle (for call_method and dispose_instance) */
41
+ handle?: string;
42
+ /** Method name (for call_method) */
43
+ methodName?: string;
44
+ /** Positional arguments */
45
+ args?: unknown[];
46
+ /** Keyword arguments */
47
+ kwargs?: Record<string, unknown>;
48
+ };
49
+ }
50
+ /**
51
+ * Protocol response format from the Python side.
52
+ *
53
+ * A response contains either a result or an error, never both.
54
+ * The `id` field correlates the response to its originating request.
55
+ */
56
+ export interface ProtocolResponse {
57
+ /** Message identifier matching the originating request */
58
+ id: number;
59
+ /** Protocol identifier (echoed back from request) */
60
+ protocol?: string;
61
+ /** Successful result value (undefined if error occurred) */
62
+ result?: unknown;
63
+ /** Error information (undefined if operation succeeded) */
64
+ error?: {
65
+ /** Python exception type name */
66
+ type: string;
67
+ /** Error message */
68
+ message: string;
69
+ /** Optional Python traceback for debugging */
70
+ traceback?: string;
71
+ };
72
+ }
73
+ /**
74
+ * Abstract transport for sending messages across the JS-Python boundary.
75
+ *
76
+ * Transport implementations handle the low-level I/O details while
77
+ * providing a consistent interface for the higher-level BridgeProtocol.
78
+ *
79
+ * Lifecycle:
80
+ * 1. Create transport instance
81
+ * 2. Call `init()` to establish the connection
82
+ * 3. Use `send()` to exchange messages
83
+ * 4. Call `dispose()` to release resources
84
+ *
85
+ * Implementations:
86
+ * - ProcessIO: Spawns a Python child process, communicates via stdio
87
+ * - HttpIO: Sends HTTP POST requests to a Python server
88
+ * - PyodideIO: Calls Pyodide directly in-memory (WASM)
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const transport = new ProcessIO({ pythonPath: 'python3' });
93
+ * await transport.init();
94
+ *
95
+ * const response = await transport.send(
96
+ * JSON.stringify({ id: '1', type: 'call', module: 'math', functionName: 'sqrt', args: [16] }),
97
+ * 5000
98
+ * );
99
+ *
100
+ * await transport.dispose();
101
+ * ```
102
+ */
103
+ export interface Transport extends Disposable {
104
+ /**
105
+ * Initialize the transport.
106
+ *
107
+ * This method establishes the underlying connection (e.g., spawns a process,
108
+ * opens a connection). It must be called before `send()` can be used.
109
+ *
110
+ * This method should be idempotent - calling it multiple times after
111
+ * successful initialization should be a no-op.
112
+ *
113
+ * @throws BridgeError if initialization fails
114
+ */
115
+ init(): Promise<void>;
116
+ /**
117
+ * Send a message and wait for the response.
118
+ *
119
+ * @param message - The JSON-encoded protocol message to send
120
+ * @param timeoutMs - Timeout in milliseconds (0 = no timeout)
121
+ * @param signal - Optional AbortSignal for external cancellation
122
+ * @returns The raw response string (JSON-encoded ProtocolResponse)
123
+ *
124
+ * @throws BridgeTimeoutError if the operation times out or is aborted
125
+ * @throws BridgeDisposedError if the transport has been disposed
126
+ * @throws BridgeProtocolError if the message format is invalid
127
+ * @throws BridgeError for other transport-level failures
128
+ */
129
+ send(message: string, timeoutMs: number, signal?: AbortSignal): Promise<string>;
130
+ /**
131
+ * Whether the transport is ready to send messages.
132
+ *
133
+ * Returns `true` after successful `init()` and before `dispose()`.
134
+ * Returns `false` in all other states.
135
+ */
136
+ readonly isReady: boolean;
137
+ }
138
+ /**
139
+ * Base options for creating a Transport.
140
+ *
141
+ * Concrete transport implementations may extend this with
142
+ * additional configuration options.
143
+ */
144
+ export interface TransportOptions {
145
+ /**
146
+ * Default timeout for operations in milliseconds.
147
+ *
148
+ * This timeout applies to individual `send()` calls when
149
+ * no explicit timeout is provided.
150
+ *
151
+ * @default 30000 (30 seconds)
152
+ */
153
+ defaultTimeoutMs?: number;
154
+ }
155
+ /**
156
+ * Type guard to check if a value implements the Transport interface.
157
+ *
158
+ * @param value - The value to check
159
+ * @returns True if the value has all required Transport methods and properties
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * function useTransport(maybeTransport: unknown) {
164
+ * if (isTransport(maybeTransport)) {
165
+ * await maybeTransport.init();
166
+ * // TypeScript now knows maybeTransport is Transport
167
+ * }
168
+ * }
169
+ * ```
170
+ */
171
+ export declare function isTransport(value: unknown): value is Transport;
172
+ /**
173
+ * Type guard to check if a value is a valid ProtocolMessage.
174
+ *
175
+ * @param value - The value to check
176
+ * @returns True if the value conforms to the ProtocolMessage structure
177
+ */
178
+ export declare function isProtocolMessage(value: unknown): value is ProtocolMessage;
179
+ /**
180
+ * Type guard to check if a value is a valid ProtocolResponse.
181
+ *
182
+ * @param value - The value to check
183
+ * @returns True if the value conforms to the ProtocolResponse structure
184
+ */
185
+ export declare function isProtocolResponse(value: unknown): value is ProtocolResponse;
186
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/runtime/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMlD,mDAAmD;AACnD,eAAO,MAAM,WAAW,aAAa,CAAC;AAMtC;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,WAAW,CAAC;IAE7B,2BAA2B;IAC3B,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,kBAAkB,GAAG,MAAM,CAAC;IAE7E,wBAAwB;IACxB,MAAM,EAAE;QACN,oDAAoD;QACpD,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB,+BAA+B;QAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;QAEtB,mCAAmC;QACnC,SAAS,CAAC,EAAE,MAAM,CAAC;QAEnB,6DAA6D;QAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB,oCAAoC;QACpC,UAAU,CAAC,EAAE,MAAM,CAAC;QAEpB,2BAA2B;QAC3B,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;QAEjB,wBAAwB;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,CAAC;CACH;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IAEX,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,2DAA2D;IAC3D,KAAK,CAAC,EAAE;QACN,iCAAiC;QACjC,IAAI,EAAE,MAAM,CAAC;QACb,oBAAoB;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,8CAA8C;QAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C;;;;;;;;;;OAUG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhF;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAMD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAS9D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAe1E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAqB5E"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Transport layer for BridgeProtocol.
3
+ *
4
+ * Provides an abstract I/O channel for all bridge communications across
5
+ * the JS-Python boundary. Concrete implementations handle different runtimes:
6
+ * - ProcessIO: Child process with stdio streams (Node.js)
7
+ * - HttpIO: HTTP POST requests (remote Python server)
8
+ * - PyodideIO: In-memory Pyodide calls (browser/WASM)
9
+ *
10
+ * @see https://github.com/bbopen/tywrap/issues/149
11
+ */
12
+ // =============================================================================
13
+ // PROTOCOL CONSTANTS
14
+ // =============================================================================
15
+ /** Protocol identifier for tywrap communication */
16
+ export const PROTOCOL_ID = 'tywrap/1';
17
+ // =============================================================================
18
+ // TYPE GUARDS
19
+ // =============================================================================
20
+ /**
21
+ * Type guard to check if a value implements the Transport interface.
22
+ *
23
+ * @param value - The value to check
24
+ * @returns True if the value has all required Transport methods and properties
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * function useTransport(maybeTransport: unknown) {
29
+ * if (isTransport(maybeTransport)) {
30
+ * await maybeTransport.init();
31
+ * // TypeScript now knows maybeTransport is Transport
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+ export function isTransport(value) {
37
+ return (value !== null &&
38
+ typeof value === 'object' &&
39
+ typeof value.init === 'function' &&
40
+ typeof value.send === 'function' &&
41
+ typeof value.dispose === 'function' &&
42
+ 'isReady' in value);
43
+ }
44
+ /**
45
+ * Type guard to check if a value is a valid ProtocolMessage.
46
+ *
47
+ * @param value - The value to check
48
+ * @returns True if the value conforms to the ProtocolMessage structure
49
+ */
50
+ export function isProtocolMessage(value) {
51
+ if (value === null || typeof value !== 'object') {
52
+ return false;
53
+ }
54
+ const msg = value;
55
+ return (typeof msg.id === 'number' &&
56
+ msg.protocol === PROTOCOL_ID &&
57
+ typeof msg.method === 'string' &&
58
+ ['call', 'instantiate', 'call_method', 'dispose_instance', 'meta'].includes(msg.method) &&
59
+ typeof msg.params === 'object' &&
60
+ msg.params !== null);
61
+ }
62
+ /**
63
+ * Type guard to check if a value is a valid ProtocolResponse.
64
+ *
65
+ * @param value - The value to check
66
+ * @returns True if the value conforms to the ProtocolResponse structure
67
+ */
68
+ export function isProtocolResponse(value) {
69
+ if (value === null || typeof value !== 'object') {
70
+ return false;
71
+ }
72
+ const resp = value;
73
+ if (typeof resp.id !== 'number') {
74
+ return false;
75
+ }
76
+ // Must have either result or error (or neither for void returns)
77
+ if (resp.error !== undefined) {
78
+ if (typeof resp.error !== 'object' || resp.error === null) {
79
+ return false;
80
+ }
81
+ const err = resp.error;
82
+ return typeof err.type === 'string' && typeof err.message === 'string';
83
+ }
84
+ return true;
85
+ }
86
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/runtime/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,mDAAmD;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AA4KtC,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAQ,KAAmB,CAAC,IAAI,KAAK,UAAU;QAC/C,OAAQ,KAAmB,CAAC,IAAI,KAAK,UAAU;QAC/C,OAAQ,KAAmB,CAAC,OAAO,KAAK,UAAU;QAClD,SAAS,IAAI,KAAK,CACnB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAG,KAAwB,CAAC;IAErC,OAAO,CACL,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;QAC1B,GAAG,CAAC,QAAQ,KAAK,WAAW;QAC5B,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QAC9B,CAAC,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;QACvF,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QAC9B,GAAG,CAAC,MAAM,KAAK,IAAI,CACpB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAG,KAAyB,CAAC;IAEvC,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,iEAAiE;IACjE,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1D,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;QACvB,OAAO,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC;IACzE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}