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,252 @@
1
+ /**
2
+ * PooledTransport - Transport adapter that wraps WorkerPool for multi-process support.
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,
6
+ * and releases the worker back to the pool.
7
+ *
8
+ * @see https://github.com/bbopen/tywrap/issues/149
9
+ */
10
+
11
+ import { BoundedContext } from './bounded-context.js';
12
+ import { BridgeDisposedError, BridgeExecutionError } from './errors.js';
13
+ import type { Transport } from './transport.js';
14
+ import { WorkerPool, type PooledWorker } from './worker-pool.js';
15
+
16
+ // =============================================================================
17
+ // TYPES
18
+ // =============================================================================
19
+
20
+ /**
21
+ * Options for creating a PooledTransport.
22
+ */
23
+ export interface PooledTransportOptions {
24
+ /** Factory function to create transports for each worker */
25
+ createTransport: () => Transport;
26
+
27
+ /** Maximum number of workers in the pool. Default: 1 */
28
+ maxWorkers?: number;
29
+
30
+ /** Minimum number of workers to pre-spawn during init. Default: 0 (lazy) */
31
+ minWorkers?: number;
32
+
33
+ /** Timeout for waiting in queue (ms). Default: 30000 */
34
+ queueTimeoutMs?: number;
35
+
36
+ /** Maximum concurrent requests per worker. Default: 10 */
37
+ maxConcurrentPerWorker?: number;
38
+
39
+ /**
40
+ * Callback invoked after each worker is created and initialized.
41
+ * Use this for per-worker warmup (e.g., importing modules, running setup).
42
+ */
43
+ onWorkerReady?: (worker: PooledWorker) => Promise<void>;
44
+ }
45
+
46
+ // =============================================================================
47
+ // POOLED TRANSPORT
48
+ // =============================================================================
49
+
50
+ /**
51
+ * Transport adapter that wraps WorkerPool for multi-process message handling.
52
+ *
53
+ * PooledTransport presents a single Transport interface while internally
54
+ * distributing requests across multiple worker transports (typically ProcessIO).
55
+ *
56
+ * Features:
57
+ * - Lazy worker creation (transports created on demand)
58
+ * - Configurable pool size and concurrency per worker
59
+ * - Automatic worker acquisition and release
60
+ * - Queue timeout for backpressure management
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const transport = new PooledTransport({
65
+ * createTransport: () => new ProcessIO({
66
+ * bridgeScript: '/path/to/bridge.py',
67
+ * }),
68
+ * maxWorkers: 4,
69
+ * maxConcurrentPerWorker: 2,
70
+ * });
71
+ *
72
+ * await transport.init();
73
+ *
74
+ * // send() automatically uses pool
75
+ * const response = await transport.send(message, timeout);
76
+ *
77
+ * await transport.dispose();
78
+ * ```
79
+ */
80
+ export class PooledTransport extends BoundedContext implements Transport {
81
+ private readonly poolOptions: Omit<Required<PooledTransportOptions>, 'onWorkerReady'> & {
82
+ onWorkerReady?: (worker: PooledWorker) => Promise<void>;
83
+ };
84
+ private pool?: WorkerPool;
85
+
86
+ /**
87
+ * Create a new PooledTransport.
88
+ *
89
+ * @param options - Pool configuration options
90
+ */
91
+ constructor(options: PooledTransportOptions) {
92
+ super();
93
+
94
+ if (typeof options.createTransport !== 'function') {
95
+ throw new BridgeExecutionError('createTransport must be a function');
96
+ }
97
+
98
+ this.poolOptions = {
99
+ createTransport: options.createTransport,
100
+ maxWorkers: options.maxWorkers ?? 1,
101
+ minWorkers: options.minWorkers ?? 0,
102
+ queueTimeoutMs: options.queueTimeoutMs ?? 30000,
103
+ maxConcurrentPerWorker: options.maxConcurrentPerWorker ?? 10,
104
+ onWorkerReady: options.onWorkerReady,
105
+ };
106
+ }
107
+
108
+ // ===========================================================================
109
+ // LIFECYCLE
110
+ // ===========================================================================
111
+
112
+ /**
113
+ * Initialize the pooled transport.
114
+ *
115
+ * Creates and initializes the internal WorkerPool.
116
+ * If minWorkers > 0, workers are pre-spawned during init.
117
+ */
118
+ protected async doInit(): Promise<void> {
119
+ this.pool = new WorkerPool({
120
+ createTransport: this.poolOptions.createTransport,
121
+ maxWorkers: this.poolOptions.maxWorkers,
122
+ minWorkers: this.poolOptions.minWorkers,
123
+ queueTimeoutMs: this.poolOptions.queueTimeoutMs,
124
+ maxConcurrentPerWorker: this.poolOptions.maxConcurrentPerWorker,
125
+ onWorkerReady: this.poolOptions.onWorkerReady,
126
+ });
127
+
128
+ await this.pool.init();
129
+ }
130
+
131
+ /**
132
+ * Dispose the pooled transport.
133
+ *
134
+ * Disposes the internal WorkerPool, which disposes all workers.
135
+ */
136
+ protected async doDispose(): Promise<void> {
137
+ if (this.pool) {
138
+ await this.pool.dispose();
139
+ this.pool = undefined;
140
+ }
141
+ }
142
+
143
+ // ===========================================================================
144
+ // TRANSPORT INTERFACE
145
+ // ===========================================================================
146
+
147
+ /**
148
+ * Send a message through a pooled worker.
149
+ *
150
+ * This method:
151
+ * 1. Acquires a worker from the pool (waiting if necessary)
152
+ * 2. Sends the message through the worker's transport
153
+ * 3. Releases the worker back to the pool
154
+ *
155
+ * @param message - The JSON-encoded protocol message
156
+ * @param timeoutMs - Timeout in milliseconds (0 = no timeout)
157
+ * @param signal - Optional AbortSignal for cancellation
158
+ * @returns The raw JSON response string
159
+ *
160
+ * @throws BridgeDisposedError if transport is disposed
161
+ * @throws BridgeTimeoutError if queue timeout or request timeout expires
162
+ */
163
+ async send(message: string, timeoutMs: number, signal?: AbortSignal): Promise<string> {
164
+ if (this.isDisposed || !this.pool) {
165
+ throw new BridgeDisposedError('Transport has been disposed');
166
+ }
167
+
168
+ return this.pool.withWorker(async worker => {
169
+ return worker.transport.send(message, timeoutMs, signal);
170
+ });
171
+ }
172
+
173
+ // ===========================================================================
174
+ // POOL STATISTICS
175
+ // ===========================================================================
176
+
177
+ /**
178
+ * Current number of workers in the pool.
179
+ */
180
+ get workerCount(): number {
181
+ return this.pool?.workerCount ?? 0;
182
+ }
183
+
184
+ /**
185
+ * Number of callers waiting in the queue.
186
+ */
187
+ get queueLength(): number {
188
+ return this.pool?.queueLength ?? 0;
189
+ }
190
+
191
+ /**
192
+ * Total number of in-flight requests across all workers.
193
+ */
194
+ get totalInFlight(): number {
195
+ return this.pool?.totalInFlight ?? 0;
196
+ }
197
+
198
+ // ===========================================================================
199
+ // RUNTIME EXECUTION (Not implemented - PooledTransport is just a transport)
200
+ // ===========================================================================
201
+
202
+ /**
203
+ * Not implemented - PooledTransport is a transport, use BridgeProtocol.
204
+ */
205
+ async call<T = unknown>(
206
+ _module: string,
207
+ _functionName: string,
208
+ _args: unknown[],
209
+ _kwargs?: Record<string, unknown>
210
+ ): Promise<T> {
211
+ throw new BridgeExecutionError(
212
+ 'PooledTransport is a transport, use BridgeProtocol for operations'
213
+ );
214
+ }
215
+
216
+ /**
217
+ * Not implemented - PooledTransport is a transport, use BridgeProtocol.
218
+ */
219
+ async instantiate<T = unknown>(
220
+ _module: string,
221
+ _className: string,
222
+ _args: unknown[],
223
+ _kwargs?: Record<string, unknown>
224
+ ): Promise<T> {
225
+ throw new BridgeExecutionError(
226
+ 'PooledTransport is a transport, use BridgeProtocol for operations'
227
+ );
228
+ }
229
+
230
+ /**
231
+ * Not implemented - PooledTransport is a transport, use BridgeProtocol.
232
+ */
233
+ async callMethod<T = unknown>(
234
+ _handle: string,
235
+ _methodName: string,
236
+ _args: unknown[],
237
+ _kwargs?: Record<string, unknown>
238
+ ): Promise<T> {
239
+ throw new BridgeExecutionError(
240
+ 'PooledTransport is a transport, use BridgeProtocol for operations'
241
+ );
242
+ }
243
+
244
+ /**
245
+ * Not implemented - PooledTransport is a transport, use BridgeProtocol.
246
+ */
247
+ async disposeInstance(_handle: string): Promise<void> {
248
+ throw new BridgeExecutionError(
249
+ 'PooledTransport is a transport, use BridgeProtocol for operations'
250
+ );
251
+ }
252
+ }