tywrap 0.8.0 → 0.9.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 (157) hide show
  1. package/README.md +22 -7
  2. package/SECURITY.md +39 -0
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/index.js +8 -0
  5. package/dist/config/index.js.map +1 -1
  6. package/dist/core/annotation-parser.d.ts +2 -1
  7. package/dist/core/annotation-parser.d.ts.map +1 -1
  8. package/dist/core/annotation-parser.js +6 -3
  9. package/dist/core/annotation-parser.js.map +1 -1
  10. package/dist/core/generator.d.ts +23 -4
  11. package/dist/core/generator.d.ts.map +1 -1
  12. package/dist/core/generator.js +243 -170
  13. package/dist/core/generator.js.map +1 -1
  14. package/dist/core/mapper.d.ts +3 -2
  15. package/dist/core/mapper.d.ts.map +1 -1
  16. package/dist/core/mapper.js +5 -5
  17. package/dist/core/mapper.js.map +1 -1
  18. package/dist/index.d.ts +7 -5
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +6 -4
  21. package/dist/index.js.map +1 -1
  22. package/dist/runtime/base-bridge.d.ts +3 -7
  23. package/dist/runtime/base-bridge.d.ts.map +1 -1
  24. package/dist/runtime/base-bridge.js +4 -17
  25. package/dist/runtime/base-bridge.js.map +1 -1
  26. package/dist/runtime/bounded-context.d.ts +3 -22
  27. package/dist/runtime/bounded-context.d.ts.map +1 -1
  28. package/dist/runtime/bounded-context.js +13 -53
  29. package/dist/runtime/bounded-context.js.map +1 -1
  30. package/dist/runtime/bridge-codec.d.ts +1 -1
  31. package/dist/runtime/bridge-codec.d.ts.map +1 -1
  32. package/dist/runtime/bridge-codec.js +78 -55
  33. package/dist/runtime/bridge-codec.js.map +1 -1
  34. package/dist/runtime/errors.d.ts +16 -0
  35. package/dist/runtime/errors.d.ts.map +1 -1
  36. package/dist/runtime/errors.js +17 -0
  37. package/dist/runtime/errors.js.map +1 -1
  38. package/dist/runtime/http-transport.d.ts +1 -1
  39. package/dist/runtime/http-transport.d.ts.map +1 -1
  40. package/dist/runtime/http-transport.js +1 -1
  41. package/dist/runtime/http-transport.js.map +1 -1
  42. package/dist/runtime/index.d.ts +1 -0
  43. package/dist/runtime/index.d.ts.map +1 -1
  44. package/dist/runtime/index.js +1 -0
  45. package/dist/runtime/index.js.map +1 -1
  46. package/dist/runtime/node.d.ts +7 -36
  47. package/dist/runtime/node.d.ts.map +1 -1
  48. package/dist/runtime/node.js +2 -80
  49. package/dist/runtime/node.js.map +1 -1
  50. package/dist/runtime/pooled-transport.d.ts +120 -59
  51. package/dist/runtime/pooled-transport.d.ts.map +1 -1
  52. package/dist/runtime/pooled-transport.js +345 -78
  53. package/dist/runtime/pooled-transport.js.map +1 -1
  54. package/dist/runtime/pyodide-bootstrap-core.generated.d.ts.map +1 -1
  55. package/dist/runtime/pyodide-bootstrap-core.generated.js +1 -1
  56. package/dist/runtime/pyodide-bootstrap-core.generated.js.map +1 -1
  57. package/dist/runtime/pyodide-transport.d.ts +1 -1
  58. package/dist/runtime/pyodide-transport.d.ts.map +1 -1
  59. package/dist/runtime/pyodide-transport.js +2 -3
  60. package/dist/runtime/pyodide-transport.js.map +1 -1
  61. package/dist/runtime/rpc-client.d.ts +7 -36
  62. package/dist/runtime/rpc-client.d.ts.map +1 -1
  63. package/dist/runtime/rpc-client.js +20 -102
  64. package/dist/runtime/rpc-client.js.map +1 -1
  65. package/dist/runtime/subprocess-transport.d.ts +30 -69
  66. package/dist/runtime/subprocess-transport.d.ts.map +1 -1
  67. package/dist/runtime/subprocess-transport.js +179 -236
  68. package/dist/runtime/subprocess-transport.js.map +1 -1
  69. package/dist/runtime/timed-out-request-tracker.d.ts +2 -1
  70. package/dist/runtime/timed-out-request-tracker.d.ts.map +1 -1
  71. package/dist/runtime/transport.d.ts +9 -19
  72. package/dist/runtime/transport.d.ts.map +1 -1
  73. package/dist/runtime/transport.js +1 -1
  74. package/dist/runtime/transport.js.map +1 -1
  75. package/dist/runtime/validators.d.ts +49 -0
  76. package/dist/runtime/validators.d.ts.map +1 -1
  77. package/dist/runtime/validators.js +152 -0
  78. package/dist/runtime/validators.js.map +1 -1
  79. package/dist/types/index.d.ts +14 -39
  80. package/dist/types/index.d.ts.map +1 -1
  81. package/dist/tywrap.d.ts +3 -2
  82. package/dist/tywrap.d.ts.map +1 -1
  83. package/dist/tywrap.js +140 -13
  84. package/dist/tywrap.js.map +1 -1
  85. package/dist/utils/cache.d.ts +3 -16
  86. package/dist/utils/cache.d.ts.map +1 -1
  87. package/dist/utils/codec.d.ts +1 -0
  88. package/dist/utils/codec.d.ts.map +1 -1
  89. package/dist/utils/codec.js +13 -13
  90. package/dist/utils/codec.js.map +1 -1
  91. package/dist/utils/ir-cache.d.ts +2 -1
  92. package/dist/utils/ir-cache.d.ts.map +1 -1
  93. package/dist/utils/runtime.d.ts +0 -29
  94. package/dist/utils/runtime.d.ts.map +1 -1
  95. package/dist/utils/runtime.js +16 -107
  96. package/dist/utils/runtime.js.map +1 -1
  97. package/dist/version.js +1 -1
  98. package/package.json +7 -6
  99. package/runtime/frame_codec.py +7 -1
  100. package/runtime/python_bridge.py +85 -125
  101. package/runtime/tywrap_bridge_core.py +133 -150
  102. package/src/config/index.ts +11 -0
  103. package/src/core/annotation-parser.ts +7 -4
  104. package/src/core/generator.ts +315 -205
  105. package/src/core/mapper.ts +8 -8
  106. package/src/index.ts +7 -4
  107. package/src/runtime/base-bridge.ts +5 -30
  108. package/src/runtime/bounded-context.ts +12 -67
  109. package/src/runtime/bridge-codec.ts +94 -65
  110. package/src/runtime/errors.ts +21 -0
  111. package/src/runtime/http-transport.ts +6 -1
  112. package/src/runtime/index.ts +6 -0
  113. package/src/runtime/node.ts +9 -120
  114. package/src/runtime/pooled-transport.ts +424 -90
  115. package/src/runtime/pyodide-bootstrap-core.generated.ts +1 -1
  116. package/src/runtime/pyodide-transport.ts +7 -3
  117. package/src/runtime/rpc-client.ts +37 -139
  118. package/src/runtime/subprocess-transport.ts +210 -285
  119. package/src/runtime/timed-out-request-tracker.ts +1 -1
  120. package/src/runtime/transport.ts +15 -23
  121. package/src/runtime/validators.ts +204 -0
  122. package/src/types/index.ts +21 -60
  123. package/src/tywrap.ts +157 -22
  124. package/src/utils/cache.ts +3 -3
  125. package/src/utils/codec.ts +21 -13
  126. package/src/utils/ir-cache.ts +1 -1
  127. package/src/utils/runtime.ts +17 -128
  128. package/src/version.ts +1 -1
  129. package/dist/core/discovery.d.ts +0 -103
  130. package/dist/core/discovery.d.ts.map +0 -1
  131. package/dist/core/discovery.js +0 -380
  132. package/dist/core/discovery.js.map +0 -1
  133. package/dist/core/validation.d.ts +0 -102
  134. package/dist/core/validation.d.ts.map +0 -1
  135. package/dist/core/validation.js +0 -490
  136. package/dist/core/validation.js.map +0 -1
  137. package/dist/runtime/base.d.ts +0 -22
  138. package/dist/runtime/base.d.ts.map +0 -1
  139. package/dist/runtime/base.js +0 -23
  140. package/dist/runtime/base.js.map +0 -1
  141. package/dist/runtime/transport-pool.d.ts +0 -196
  142. package/dist/runtime/transport-pool.d.ts.map +0 -1
  143. package/dist/runtime/transport-pool.js +0 -418
  144. package/dist/runtime/transport-pool.js.map +0 -1
  145. package/runtime/__pycache__/_tywrap_conformance_chunking_fixtures.cpython-311.pyc +0 -0
  146. package/runtime/__pycache__/_tywrap_member_fixtures.cpython-311.pyc +0 -0
  147. package/runtime/__pycache__/_tywrap_w4_chunking_fixture.cpython-311.pyc +0 -0
  148. package/runtime/__pycache__/_tywrap_w5_request_chunking_fixture.cpython-311.pyc +0 -0
  149. package/runtime/__pycache__/_tywrap_w6_pool_chunking_fixture.cpython-311.pyc +0 -0
  150. package/runtime/__pycache__/frame_codec.cpython-311.pyc +0 -0
  151. package/runtime/__pycache__/safe_codec.cpython-311.pyc +0 -0
  152. package/runtime/__pycache__/tywrap_bridge_core.cpython-311.pyc +0 -0
  153. package/runtime/safe_codec.py +0 -352
  154. package/src/core/discovery.ts +0 -477
  155. package/src/core/validation.ts +0 -729
  156. package/src/runtime/base.ts +0 -24
  157. package/src/runtime/transport-pool.ts +0 -538
@@ -1,4 +1,4 @@
1
- export interface TimedOutRequestTrackerOptions {
1
+ interface TimedOutRequestTrackerOptions {
2
2
  ttlMs: number;
3
3
  maxSize?: number;
4
4
  }
@@ -57,9 +57,6 @@ export const FRAME_PROTOCOL_VERSION = Number.parseInt(FRAME_PROTOCOL_ID.split('/
57
57
  *
58
58
  * Each method corresponds to a BridgeProtocol operation:
59
59
  * - `call`: Invoke a module-level function
60
- * - `instantiate`: Create a new class instance
61
- * - `call_method`: Invoke a method on an existing instance
62
- * - `dispose_instance`: Release an instance handle
63
60
  * - `meta`: Get bridge metadata
64
61
  */
65
62
  export interface ProtocolMessage {
@@ -70,25 +67,16 @@ export interface ProtocolMessage {
70
67
  protocol: typeof PROTOCOL_ID;
71
68
 
72
69
  /** The method to invoke */
73
- method: 'call' | 'instantiate' | 'call_method' | 'dispose_instance' | 'meta';
70
+ method: 'call' | 'meta';
74
71
 
75
72
  /** Method parameters */
76
73
  params: {
77
- /** Python module path (for call and instantiate) */
74
+ /** Python module path (for call) */
78
75
  module?: string;
79
76
 
80
77
  /** Function name (for call) */
81
78
  functionName?: string;
82
79
 
83
- /** Class name (for instantiate) */
84
- className?: string;
85
-
86
- /** Instance handle (for call_method and dispose_instance) */
87
- handle?: string;
88
-
89
- /** Method name (for call_method) */
90
- methodName?: string;
91
-
92
80
  /** Positional arguments */
93
81
  args?: unknown[];
94
82
 
@@ -212,10 +200,8 @@ export interface ChunkFrame {
212
200
  * authoritative for transport-level flags; the meta report is authoritative for
213
201
  * library availability.
214
202
  *
215
- * Honest for TODAY's behavior: as of 0.8.0 `supportsChunking` is implemented for
216
- * the subprocess backend and reports the *configured* `tywrap-frame/1` path
217
- * (`enableChunking`) — static and lifecycle-independent, like `supportsArrow`;
218
- * the per-bridge negotiated fact lives on {@link BridgeInfo}'s `transport` block.
203
+ * `supportsChunking` is always true for the subprocess backend because the
204
+ * packaged Python bridge and JS transport always speak `tywrap-frame/1`.
219
205
  * HTTP and Pyodide stay `false`. `supportsStreaming` is `false` on every backend
220
206
  * (not implemented in 0.8.0). See docs/transport-capabilities.md for the full
221
207
  * matrix.
@@ -240,8 +226,8 @@ export interface TransportCapabilities {
240
226
 
241
227
  /**
242
228
  * Whether the transport splits a single logical message across multiple wire
243
- * frames. Not implemented on any backend yet (planned for 0.8.0) — always
244
- * `false`.
229
+ * frames. This is always `true` for the packaged subprocess transport and
230
+ * `false` for HTTP and Pyodide.
245
231
  */
246
232
  readonly supportsChunking: boolean;
247
233
 
@@ -255,7 +241,8 @@ export interface TransportCapabilities {
255
241
  * Maximum size, in bytes, of a single wire frame the transport will accept.
256
242
  * `Number.POSITIVE_INFINITY` means the transport imposes no frame ceiling of
257
243
  * its own (a higher layer — e.g. the codec's payload limit — may still cap the
258
- * size). For the subprocess backend this is the JSONL line-length limit.
244
+ * size). For the subprocess backend this is the always-on framing ceiling for
245
+ * each JSONL wire frame.
259
246
  */
260
247
  readonly maxFrameBytes: number;
261
248
  }
@@ -326,7 +313,12 @@ export interface Transport extends Disposable {
326
313
  * @throws BridgeProtocolError if the message format is invalid
327
314
  * @throws BridgeError for other transport-level failures
328
315
  */
329
- send(message: string, timeoutMs: number, signal?: AbortSignal): Promise<string>;
316
+ send(
317
+ message: string,
318
+ timeoutMs: number,
319
+ signal?: AbortSignal,
320
+ requestId?: number
321
+ ): Promise<string>;
330
322
 
331
323
  /**
332
324
  * Whether the transport is ready to send messages.
@@ -418,7 +410,7 @@ export function isProtocolMessage(value: unknown): value is ProtocolMessage {
418
410
  typeof msg.id === 'number' &&
419
411
  msg.protocol === PROTOCOL_ID &&
420
412
  typeof msg.method === 'string' &&
421
- ['call', 'instantiate', 'call_method', 'dispose_instance', 'meta'].includes(msg.method) &&
413
+ (msg.method === 'call' || msg.method === 'meta') &&
422
414
  typeof msg.params === 'object' &&
423
415
  msg.params !== null
424
416
  );
@@ -1,3 +1,5 @@
1
+ import { BridgeValidationError } from './errors.js';
2
+
1
3
  /**
2
4
  * Pure validation functions for runtime value checking.
3
5
  *
@@ -15,6 +17,208 @@ export class ValidationError extends Error {
15
17
  }
16
18
  }
17
19
 
20
+ /** A serializable return-contract description emitted by the code generator. */
21
+ export type ReturnSchema =
22
+ | { kind: 'any' }
23
+ | {
24
+ kind: 'primitive';
25
+ type: 'number' | 'string' | 'boolean' | 'null' | 'undefined' | 'Uint8Array' | 'object';
26
+ }
27
+ | { kind: 'literal'; value: string | number | boolean | null }
28
+ | { kind: 'array'; element: ReturnSchema }
29
+ | { kind: 'tuple'; elements: ReturnSchema[] }
30
+ | {
31
+ kind: 'record';
32
+ fields?: Record<string, { schema: ReturnSchema; optional?: boolean }>;
33
+ values?: ReturnSchema;
34
+ }
35
+ | { kind: 'union'; options: ReturnSchema[] }
36
+ | { kind: 'ref'; name: string }
37
+ | { kind: 'marker'; marker: 'dataframe' | 'series' | 'ndarray'; dims?: number; dtype?: string };
38
+
39
+ export type ReturnValidator<T = unknown> = (result: T) => T;
40
+
41
+ export interface DecodedShapeMetadata {
42
+ marker: 'dataframe' | 'series' | 'ndarray';
43
+ dims?: number;
44
+ dtype?: string;
45
+ }
46
+
47
+ const decodedShapeMetadata = new WeakMap<object, DecodedShapeMetadata>();
48
+
49
+ /** @internal Preserve wire provenance after codec decoding changes the JS shape. */
50
+ export function tagDecodedShape<T>(value: T, metadata: DecodedShapeMetadata): T {
51
+ if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
52
+ decodedShapeMetadata.set(value as object, metadata);
53
+ }
54
+ return value;
55
+ }
56
+
57
+ function isObjectLike(value: unknown): value is object {
58
+ return value !== null && (typeof value === 'object' || typeof value === 'function');
59
+ }
60
+
61
+ /** A short, bounded description suitable for an error message. */
62
+ export function describeReceivedShape(value: unknown): string {
63
+ if (value === null) {
64
+ return 'null';
65
+ }
66
+ if (value === undefined) {
67
+ return 'undefined';
68
+ }
69
+ if (value instanceof Uint8Array) {
70
+ return `Uint8Array(${value.byteLength})`;
71
+ }
72
+ if (Array.isArray(value)) {
73
+ return `array(${value.length})`;
74
+ }
75
+ if (typeof value === 'object') {
76
+ const marker = decodedShapeMetadata.get(value);
77
+ if (marker) {
78
+ const details = [marker.dims === undefined ? undefined : `${marker.dims}d`, marker.dtype]
79
+ .filter(Boolean)
80
+ .join(', ');
81
+ return `${marker.marker}${details ? ` (${details})` : ''}`;
82
+ }
83
+ const name = (value as { constructor?: { name?: unknown } }).constructor?.name;
84
+ return typeof name === 'string' && name !== 'Object' ? name : 'object';
85
+ }
86
+ return typeof value;
87
+ }
88
+
89
+ function renderSchema(schema: ReturnSchema): string {
90
+ switch (schema.kind) {
91
+ case 'any':
92
+ return 'unknown';
93
+ case 'primitive':
94
+ return schema.type;
95
+ case 'literal':
96
+ return JSON.stringify(schema.value);
97
+ case 'array':
98
+ return `${renderSchema(schema.element)}[]`;
99
+ case 'tuple':
100
+ return `[${schema.elements.map(renderSchema).join(', ')}]`;
101
+ case 'record':
102
+ return 'record';
103
+ case 'union':
104
+ return schema.options.map(renderSchema).join(' | ');
105
+ case 'ref':
106
+ return schema.name;
107
+ case 'marker':
108
+ return schema.marker;
109
+ }
110
+ }
111
+
112
+ interface CheckState {
113
+ readonly definitions: Readonly<Record<string, ReturnSchema>>;
114
+ readonly pairs: WeakMap<object, Set<string>>;
115
+ }
116
+
117
+ function check(schema: ReturnSchema, value: unknown, state: CheckState): boolean {
118
+ if (schema.kind === 'any') {
119
+ return true;
120
+ }
121
+
122
+ if (schema.kind === 'ref') {
123
+ const definition = state.definitions[schema.name];
124
+ if (!definition) {
125
+ return true;
126
+ } // unresolved/erased types deliberately degrade to unknown.
127
+ if (isObjectLike(value)) {
128
+ const seen = state.pairs.get(value) ?? new Set<string>();
129
+ if (seen.has(schema.name)) {
130
+ return true;
131
+ }
132
+ seen.add(schema.name);
133
+ state.pairs.set(value, seen);
134
+ }
135
+ return check(definition, value, state);
136
+ }
137
+
138
+ switch (schema.kind) {
139
+ case 'primitive':
140
+ if (schema.type === 'null') {
141
+ return value === null;
142
+ }
143
+ if (schema.type === 'undefined') {
144
+ return value === undefined;
145
+ }
146
+ if (schema.type === 'Uint8Array') {
147
+ return value instanceof Uint8Array;
148
+ }
149
+ if (schema.type === 'object') {
150
+ return isPlainObject(value);
151
+ }
152
+ return typeof value === schema.type;
153
+ case 'literal':
154
+ return Object.is(value, schema.value);
155
+ case 'array':
156
+ return Array.isArray(value) && value.every(item => check(schema.element, item, state));
157
+ case 'tuple':
158
+ return (
159
+ Array.isArray(value) &&
160
+ value.length === schema.elements.length &&
161
+ schema.elements.every((entry, index) => check(entry, value[index], state))
162
+ );
163
+ case 'record': {
164
+ if (!isPlainObject(value)) {
165
+ return false;
166
+ }
167
+ if (schema.fields) {
168
+ for (const [key, field] of Object.entries(schema.fields)) {
169
+ if (!(key in value)) {
170
+ if (field.optional) {
171
+ continue;
172
+ }
173
+ return false;
174
+ }
175
+ if (!check(field.schema, value[key], state)) {
176
+ return false;
177
+ }
178
+ }
179
+ }
180
+ return (
181
+ !schema.values ||
182
+ Object.values(value).every(item => check(schema.values as ReturnSchema, item, state))
183
+ );
184
+ }
185
+ case 'union':
186
+ return schema.options.some(option => check(option, value, state));
187
+ case 'marker': {
188
+ const metadata = isObjectLike(value) ? decodedShapeMetadata.get(value) : undefined;
189
+ if (metadata?.marker !== schema.marker) {
190
+ return false;
191
+ }
192
+ return (
193
+ (schema.dims === undefined || metadata.dims === schema.dims) &&
194
+ (schema.dtype === undefined || metadata.dtype === schema.dtype)
195
+ );
196
+ }
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Construct a cycle-safe structural validator for one generated callable.
202
+ * Unknown/Any/void schemas intentionally validate nothing.
203
+ */
204
+ export function createReturnValidator<T = unknown>(
205
+ schema: ReturnSchema,
206
+ callSite: string,
207
+ definitions: Readonly<Record<string, ReturnSchema>> = {}
208
+ ): ReturnValidator<T> {
209
+ const declaredType = renderSchema(schema);
210
+ return (result: T): T => {
211
+ if (!check(schema, result, { definitions, pairs: new WeakMap<object, Set<string>>() })) {
212
+ throw new BridgeValidationError({
213
+ declaredType,
214
+ receivedShape: describeReceivedShape(result),
215
+ callSite,
216
+ });
217
+ }
218
+ return result;
219
+ };
220
+ }
221
+
18
222
  // ═══════════════════════════════════════════════════════════════════════════
19
223
  // TYPE GUARDS
20
224
  // ═══════════════════════════════════════════════════════════════════════════
@@ -13,6 +13,13 @@ export interface PythonModule {
13
13
  exports: string[];
14
14
  }
15
15
 
16
+ /** A pinned, versioned JSON IR artifact emitted alongside generated wrappers. */
17
+ export interface IrContract {
18
+ ir_version: string;
19
+ module: string;
20
+ [key: string]: unknown;
21
+ }
22
+
16
23
  /**
17
24
  * How a callable is bound on its owning class.
18
25
  *
@@ -261,7 +268,8 @@ export interface TSPrimitiveType {
261
268
  | 'void'
262
269
  | 'unknown'
263
270
  | 'never'
264
- | 'object';
271
+ | 'object'
272
+ | 'Uint8Array';
265
273
  }
266
274
 
267
275
  export interface TSArrayType {
@@ -314,6 +322,7 @@ export interface TSParameter {
314
322
  export interface TSGenericType {
315
323
  kind: 'generic';
316
324
  name: string;
325
+ module?: string;
317
326
  typeArgs: TypescriptType[];
318
327
  }
319
328
 
@@ -338,6 +347,11 @@ export interface TywrapOptions {
338
347
  * and discovery (IR extraction). Useful for local modules not installed in site-packages.
339
348
  */
340
349
  pythonImportPath?: string[];
350
+ /**
351
+ * Read one pinned IR contract instead of spawning Python. A string applies to
352
+ * every configured module; a record selects a contract path per module.
353
+ */
354
+ contractInput?: string | Record<string, string>;
341
355
  output: OutputConfig;
342
356
  runtime: RuntimeConfig;
343
357
  performance: PerformanceConfig;
@@ -404,6 +418,8 @@ export interface PerformanceConfig {
404
418
  compression: 'auto' | 'gzip' | 'brotli' | 'none';
405
419
  }
406
420
 
421
+ // `numpy` is intentionally accepted as a no-op in 0.9: decoded ndarrays are JS
422
+ // arrays, and a faithful static shape awaits #268 return validation.
407
423
  export type TypePreset = 'numpy' | 'pandas' | 'pydantic' | 'stdlib' | 'scipy' | 'torch' | 'sklearn';
408
424
 
409
425
  export interface TypeMappingConfig {
@@ -413,25 +429,6 @@ export interface TypeMappingConfig {
413
429
  /** Known bridge backends. Each speaks the identical "tywrap/1" protocol. */
414
430
  export type BridgeBackend = 'python-subprocess' | 'pyodide' | 'http';
415
431
 
416
- /**
417
- * Optional chunked-transport negotiation block in {@link BridgeInfo}.
418
- *
419
- * Reported by a bridge that understands the `tywrap-frame/1` framing protocol
420
- * (subprocess only, 0.8.0). It lets the JS side learn, via the `meta` probe,
421
- * whether the bridge can reassemble chunked frames and the maximum single-frame
422
- * size it will accept. Absent on old bridges (and on HTTP/Pyodide, which stay
423
- * single-frame in 0.8.0) — absence means "no chunking", which is backward
424
- * compatible. See docs/transport-framing.md.
425
- */
426
- export interface BridgeTransportInfo {
427
- /** Framing protocol the bridge speaks (e.g. `'tywrap-frame/1'`). */
428
- frameProtocol: string;
429
- /** Whether the bridge can fragment/reassemble chunked frames. */
430
- supportsChunking: boolean;
431
- /** Maximum size, in bytes, of a single wire frame the bridge will accept. */
432
- maxFrameBytes: number;
433
- }
434
-
435
432
  export interface BridgeInfo {
436
433
  protocol: string;
437
434
  protocolVersion: number;
@@ -445,12 +442,6 @@ export interface BridgeInfo {
445
442
  torchAvailable: boolean;
446
443
  sklearnAvailable: boolean;
447
444
  instances: number;
448
- /**
449
- * Optional chunked-transport negotiation block. Present only when the bridge
450
- * advertises `tywrap-frame/1` framing; absent on old bridges and on
451
- * HTTP/Pyodide (single-frame in 0.8.0). See {@link BridgeTransportInfo}.
452
- */
453
- transport?: BridgeTransportInfo;
454
445
  }
455
446
 
456
447
  // Analysis and generation results
@@ -499,7 +490,7 @@ export interface GenerationMetadata {
499
490
  optimizations: string[];
500
491
  }
501
492
 
502
- // PythonRuntime — the four cross-boundary RPC methods generated wrappers call.
493
+ // PythonRuntime — the call-only cross-boundary RPC method generated wrappers call.
503
494
  // This is the contract that, after the composition rework, is implemented ONLY
504
495
  // by the bridge facades (NodeBridge/HttpBridge/PyodideBridge); the facades
505
496
  // satisfy it by delegating to an owned RpcClient. It deliberately carries NO
@@ -511,45 +502,15 @@ export interface PythonRuntime {
511
502
  module: string,
512
503
  functionName: string,
513
504
  args: unknown[],
514
- kwargs?: Record<string, unknown>
505
+ kwargs?: Record<string, unknown>,
506
+ validate?: (result: T) => void
515
507
  ): Promise<T>;
516
-
517
- instantiate<T = unknown>(
518
- module: string,
519
- className: string,
520
- args: unknown[],
521
- kwargs?: Record<string, unknown>
522
- ): Promise<T>;
523
-
524
- callMethod<T = unknown>(
525
- handle: string,
526
- methodName: string,
527
- args: unknown[],
528
- kwargs?: Record<string, unknown>
529
- ): Promise<T>;
530
-
531
- disposeInstance(handle: string): Promise<void>;
532
508
  }
533
509
 
534
- // Runtime bridge interface — the four RPC methods plus lifecycle dispose().
510
+ // Runtime bridge interface — the call RPC method plus lifecycle dispose().
535
511
  // Kept as PythonRuntime + dispose() so getRuntimeBridge() and every existing
536
512
  // `RuntimeExecution` reference (registry, dev.ts) compile with zero churn. The
537
513
  // RuntimeExecution -> PythonRuntime symbol rename is deferred to the T9 pass.
538
514
  export interface RuntimeExecution extends PythonRuntime {
539
515
  dispose(): Promise<void>;
540
516
  }
541
-
542
- // Utility types
543
- export type DeepReadonly<T> = {
544
- readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
545
- };
546
-
547
- export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
548
-
549
- export type RequiredKeys<T> = {
550
- [K in keyof T]-?: {} extends Pick<T, K> ? never : K;
551
- }[keyof T];
552
-
553
- export type OptionalKeys<T> = {
554
- [K in keyof T]-?: {} extends Pick<T, K> ? K : never;
555
- }[keyof T];