@query-farm/vgi-rpc 0.6.4 → 0.7.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 (160) hide show
  1. package/dist/access-log.d.ts +50 -0
  2. package/dist/access-log.d.ts.map +1 -0
  3. package/dist/arrow/impl-arrowjs/index.d.ts +96 -0
  4. package/dist/arrow/impl-arrowjs/index.d.ts.map +1 -0
  5. package/dist/arrow/impl-flechette/index.d.ts +102 -0
  6. package/dist/arrow/impl-flechette/index.d.ts.map +1 -0
  7. package/dist/arrow/impl-flechette/message-meta.d.ts +11 -0
  8. package/dist/arrow/impl-flechette/message-meta.d.ts.map +1 -0
  9. package/dist/arrow/index.d.ts +4 -0
  10. package/dist/arrow/index.d.ts.map +1 -0
  11. package/dist/arrow/predicates.d.ts +44 -0
  12. package/dist/arrow/predicates.d.ts.map +1 -0
  13. package/dist/arrow/types.d.ts +62 -0
  14. package/dist/arrow/types.d.ts.map +1 -0
  15. package/dist/client/capabilities.d.ts +25 -0
  16. package/dist/client/capabilities.d.ts.map +1 -0
  17. package/dist/client/connect.d.ts.map +1 -1
  18. package/dist/client/introspect.d.ts +7 -0
  19. package/dist/client/introspect.d.ts.map +1 -1
  20. package/dist/client/ipc.d.ts +8 -2
  21. package/dist/client/ipc.d.ts.map +1 -1
  22. package/dist/client/pipe.d.ts.map +1 -1
  23. package/dist/client/stream.d.ts +11 -2
  24. package/dist/client/stream.d.ts.map +1 -1
  25. package/dist/client/uploadUrl.d.ts +25 -0
  26. package/dist/client/uploadUrl.d.ts.map +1 -0
  27. package/dist/constants.d.ts +15 -1
  28. package/dist/constants.d.ts.map +1 -1
  29. package/dist/crypto.d.ts +22 -0
  30. package/dist/crypto.d.ts.map +1 -0
  31. package/dist/dispatch/describe.d.ts +10 -6
  32. package/dist/dispatch/describe.d.ts.map +1 -1
  33. package/dist/dispatch/stream.d.ts +2 -2
  34. package/dist/dispatch/stream.d.ts.map +1 -1
  35. package/dist/dispatch/unary.d.ts +2 -2
  36. package/dist/dispatch/unary.d.ts.map +1 -1
  37. package/dist/errors.d.ts +46 -0
  38. package/dist/errors.d.ts.map +1 -1
  39. package/dist/external.d.ts +25 -5
  40. package/dist/external.d.ts.map +1 -1
  41. package/dist/http/bearer.d.ts.map +1 -1
  42. package/dist/http/common.d.ts +42 -7
  43. package/dist/http/common.d.ts.map +1 -1
  44. package/dist/http/dispatch.d.ts +20 -2
  45. package/dist/http/dispatch.d.ts.map +1 -1
  46. package/dist/http/handler.d.ts.map +1 -1
  47. package/dist/http/index.d.ts +1 -0
  48. package/dist/http/index.d.ts.map +1 -1
  49. package/dist/http/mtls.d.ts +2 -1
  50. package/dist/http/mtls.d.ts.map +1 -1
  51. package/dist/http/oauth-pkce.d.ts +141 -0
  52. package/dist/http/oauth-pkce.d.ts.map +1 -0
  53. package/dist/http/pages.d.ts +3 -0
  54. package/dist/http/pages.d.ts.map +1 -1
  55. package/dist/http/sticky.d.ts +124 -0
  56. package/dist/http/sticky.d.ts.map +1 -0
  57. package/dist/http/token.d.ts +38 -12
  58. package/dist/http/token.d.ts.map +1 -1
  59. package/dist/http/types.d.ts +66 -5
  60. package/dist/http/types.d.ts.map +1 -1
  61. package/dist/index.d.ts +6 -4
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +1275 -3511
  64. package/dist/index.js.map +19 -37
  65. package/dist/launcher/hash.d.ts +22 -0
  66. package/dist/launcher/hash.d.ts.map +1 -0
  67. package/dist/launcher/index.d.ts +23 -0
  68. package/dist/launcher/index.d.ts.map +1 -0
  69. package/dist/launcher/launch.d.ts +27 -0
  70. package/dist/launcher/launch.d.ts.map +1 -0
  71. package/dist/launcher/lock.d.ts +19 -0
  72. package/dist/launcher/lock.d.ts.map +1 -0
  73. package/dist/launcher/serve-unix.d.ts +54 -0
  74. package/dist/launcher/serve-unix.d.ts.map +1 -0
  75. package/dist/launcher/state.d.ts +59 -0
  76. package/dist/launcher/state.d.ts.map +1 -0
  77. package/dist/otel.d.ts.map +1 -1
  78. package/dist/protocol.d.ts +16 -2
  79. package/dist/protocol.d.ts.map +1 -1
  80. package/dist/schema.d.ts +45 -18
  81. package/dist/schema.d.ts.map +1 -1
  82. package/dist/server.d.ts +23 -2
  83. package/dist/server.d.ts.map +1 -1
  84. package/dist/types.d.ts +216 -12
  85. package/dist/types.d.ts.map +1 -1
  86. package/dist/util/gzip.d.ts +10 -0
  87. package/dist/util/gzip.d.ts.map +1 -0
  88. package/dist/util/schema.d.ts +3 -15
  89. package/dist/util/schema.d.ts.map +1 -1
  90. package/dist/util/web-crypto.d.ts +22 -0
  91. package/dist/util/web-crypto.d.ts.map +1 -0
  92. package/dist/util/zstd.d.ts +26 -3
  93. package/dist/util/zstd.d.ts.map +1 -1
  94. package/dist/wire/opaque.d.ts +11 -0
  95. package/dist/wire/opaque.d.ts.map +1 -0
  96. package/dist/wire/reader.d.ts +5 -5
  97. package/dist/wire/reader.d.ts.map +1 -1
  98. package/dist/wire/request.d.ts +11 -3
  99. package/dist/wire/request.d.ts.map +1 -1
  100. package/dist/wire/response.d.ts +6 -6
  101. package/dist/wire/response.d.ts.map +1 -1
  102. package/dist/wire/writer.d.ts +49 -39
  103. package/dist/wire/writer.d.ts.map +1 -1
  104. package/package.json +24 -10
  105. package/src/access-log.ts +195 -0
  106. package/src/arrow/impl-arrowjs/index.ts +433 -0
  107. package/src/arrow/impl-flechette/index.ts +414 -0
  108. package/src/arrow/impl-flechette/message-meta.ts +174 -0
  109. package/src/arrow/index.ts +89 -0
  110. package/src/arrow/predicates.ts +56 -0
  111. package/src/arrow/types.ts +73 -0
  112. package/src/client/capabilities.ts +84 -0
  113. package/src/client/connect.ts +103 -26
  114. package/src/client/introspect.ts +60 -38
  115. package/src/client/ipc.ts +37 -27
  116. package/src/client/pipe.ts +12 -9
  117. package/src/client/stream.ts +34 -19
  118. package/src/client/uploadUrl.ts +169 -0
  119. package/src/constants.ts +18 -1
  120. package/src/crypto.ts +95 -0
  121. package/src/dispatch/describe.ts +146 -107
  122. package/src/dispatch/stream.ts +53 -24
  123. package/src/dispatch/unary.ts +5 -4
  124. package/src/errors.ts +76 -0
  125. package/src/external.ts +43 -29
  126. package/src/http/bearer.ts +2 -5
  127. package/src/http/common.ts +90 -23
  128. package/src/http/dispatch.ts +373 -46
  129. package/src/http/handler.ts +790 -68
  130. package/src/http/index.ts +1 -0
  131. package/src/http/mtls.ts +18 -3
  132. package/src/http/oauth-pkce.ts +1035 -0
  133. package/src/http/pages.ts +30 -15
  134. package/src/http/sticky.ts +429 -0
  135. package/src/http/token.ts +165 -75
  136. package/src/http/types.ts +67 -5
  137. package/src/index.ts +40 -1
  138. package/src/launcher/hash.ts +104 -0
  139. package/src/launcher/index.ts +35 -0
  140. package/src/launcher/launch.ts +284 -0
  141. package/src/launcher/lock.ts +171 -0
  142. package/src/launcher/serve-unix.ts +385 -0
  143. package/src/launcher/state.ts +245 -0
  144. package/src/otel.ts +39 -33
  145. package/src/protocol.ts +27 -3
  146. package/src/schema.ts +107 -56
  147. package/src/server.ts +196 -20
  148. package/src/types.ts +322 -18
  149. package/src/util/gzip.ts +63 -0
  150. package/src/util/schema.ts +4 -22
  151. package/src/util/web-crypto.ts +98 -0
  152. package/src/util/zstd.ts +133 -14
  153. package/src/wire/opaque.ts +37 -0
  154. package/src/wire/reader.ts +5 -4
  155. package/src/wire/request.ts +67 -8
  156. package/src/wire/response.ts +51 -85
  157. package/src/wire/writer.ts +165 -69
  158. package/dist/util/conform.d.ts +0 -18
  159. package/dist/util/conform.d.ts.map +0 -1
  160. package/src/util/conform.ts +0 -94
package/src/otel.ts CHANGED
@@ -119,42 +119,48 @@ export function createOtelHook(config?: OtelConfig): DispatchHook {
119
119
  const durationS = (performance.now() - t.startTime) / 1000;
120
120
  const status = error ? "error" : "ok";
121
121
 
122
- // Finalize span
123
- if (t.span) {
124
- if (stats) {
125
- t.span.setAttributes({
126
- "rpc.vgi_rpc.input_batches": stats.inputBatches,
127
- "rpc.vgi_rpc.output_batches": stats.outputBatches,
128
- "rpc.vgi_rpc.input_rows": stats.inputRows,
129
- "rpc.vgi_rpc.output_rows": stats.outputRows,
130
- "rpc.vgi_rpc.input_bytes": stats.inputBytes,
131
- "rpc.vgi_rpc.output_bytes": stats.outputBytes,
132
- });
133
- }
122
+ // Finalize span — wrap in try/finally so metric recording still
123
+ // runs if an exporter inside span.end() raises. Mirrors the Python
124
+ // fix that detaches the otel context unconditionally; TS doesn't
125
+ // attach context, but the same shape protects metric counters from
126
+ // a single misbehaving exporter taking out request observability.
127
+ try {
128
+ if (t.span) {
129
+ if (stats) {
130
+ t.span.setAttributes({
131
+ "rpc.vgi_rpc.input_batches": stats.inputBatches,
132
+ "rpc.vgi_rpc.output_batches": stats.outputBatches,
133
+ "rpc.vgi_rpc.input_rows": stats.inputRows,
134
+ "rpc.vgi_rpc.output_rows": stats.outputRows,
135
+ "rpc.vgi_rpc.input_bytes": stats.inputBytes,
136
+ "rpc.vgi_rpc.output_bytes": stats.outputBytes,
137
+ });
138
+ }
134
139
 
135
- if (error) {
136
- t.span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
137
- t.span.setAttribute("rpc.vgi_rpc.error_type", error.constructor.name);
138
- if (recordExceptions) {
139
- t.span.recordException(error);
140
+ if (error) {
141
+ t.span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
142
+ t.span.setAttribute("rpc.vgi_rpc.error_type", error.constructor.name);
143
+ if (recordExceptions) {
144
+ t.span.recordException(error);
145
+ }
146
+ } else {
147
+ t.span.setStatus({ code: SpanStatusCode.OK });
140
148
  }
141
- } else {
142
- t.span.setStatus({ code: SpanStatusCode.OK });
149
+ t.span.end();
150
+ }
151
+ } finally {
152
+ // Record metrics — runs even if span finalisation above raises.
153
+ if (enableMetrics) {
154
+ const metricAttrs: Attributes = {
155
+ "rpc.system": "vgi_rpc",
156
+ "rpc.service": serviceName,
157
+ "rpc.method": info.method,
158
+ "rpc.vgi_rpc.method_type": info.methodType,
159
+ status,
160
+ };
161
+ requestCounter?.add(1, metricAttrs);
162
+ durationHistogram?.record(durationS, metricAttrs);
143
163
  }
144
- t.span.end();
145
- }
146
-
147
- // Record metrics
148
- if (enableMetrics) {
149
- const metricAttrs: Attributes = {
150
- "rpc.system": "vgi_rpc",
151
- "rpc.service": serviceName,
152
- "rpc.method": info.method,
153
- "rpc.vgi_rpc.method_type": info.methodType,
154
- status,
155
- };
156
- requestCounter?.add(1, metricAttrs);
157
- durationHistogram?.record(durationS, metricAttrs);
158
164
  }
159
165
  },
160
166
  };
package/src/protocol.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  // © Copyright 2025-2026, Query.Farm LLC - https://query.farm
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { Schema } from "@query-farm/apache-arrow";
4
+ import { schema as makeSchema } from "./arrow/index.js";
5
+ import { parseProtocolVersion } from "./errors.js";
5
6
  import { inferParamTypes, type SchemaLike, toSchema } from "./schema.js";
6
7
  import {
7
8
  type ExchangeFn,
@@ -9,12 +10,13 @@ import {
9
10
  type HeaderInit,
10
11
  type MethodDefinition,
11
12
  MethodType,
13
+ type OnCancelFn,
12
14
  type ProducerFn,
13
15
  type ProducerInit,
14
16
  type UnaryHandler,
15
17
  } from "./types.js";
16
18
 
17
- const EMPTY_SCHEMA = new Schema([]);
19
+ const EMPTY_SCHEMA = makeSchema([]);
18
20
 
19
21
  /**
20
22
  * Fluent builder for defining RPC methods.
@@ -22,10 +24,28 @@ const EMPTY_SCHEMA = new Schema([]);
22
24
  */
23
25
  export class Protocol {
24
26
  readonly name: string;
27
+ /**
28
+ * Application protocol surface version. When non-empty, the server enforces
29
+ * exact major+minor match (patch ignored) against every request's
30
+ * `vgi_rpc.protocol_version` metadata; clients bound to this Protocol emit
31
+ * the value on every request. Format: canonical semver MAJOR.MINOR.PATCH.
32
+ * Mirrors Python's `Protocol.protocol_version` ClassVar.
33
+ */
34
+ readonly protocolVersion: string;
35
+ /** Parsed semver tuple; null when `protocolVersion` is unset. */
36
+ readonly protocolVersionParts: readonly [number, number, number] | null;
25
37
  private _methods: Map<string, MethodDefinition> = new Map();
26
38
 
27
- constructor(name: string) {
39
+ constructor(name: string, options?: { protocolVersion?: string }) {
28
40
  this.name = name;
41
+ const raw = options?.protocolVersion;
42
+ if (raw === undefined || raw === "") {
43
+ this.protocolVersion = "";
44
+ this.protocolVersionParts = null;
45
+ } else {
46
+ this.protocolVersion = raw;
47
+ this.protocolVersionParts = parseProtocolVersion(raw);
48
+ }
29
49
  }
30
50
 
31
51
  /**
@@ -74,6 +94,7 @@ export class Protocol {
74
94
  outputSchema: SchemaLike;
75
95
  init: ProducerInit<S>;
76
96
  produce: ProducerFn<S>;
97
+ onCancel?: OnCancelFn<S>;
77
98
  headerSchema?: SchemaLike;
78
99
  headerInit?: HeaderInit;
79
100
  doc?: string;
@@ -91,6 +112,7 @@ export class Protocol {
91
112
  inputSchema: EMPTY_SCHEMA,
92
113
  producerInit: config.init as ProducerInit,
93
114
  producerFn: config.produce as ProducerFn,
115
+ onCancel: config.onCancel as OnCancelFn | undefined,
94
116
  headerSchema: config.headerSchema ? toSchema(config.headerSchema) : undefined,
95
117
  headerInit: config.headerInit,
96
118
  doc: config.doc,
@@ -112,6 +134,7 @@ export class Protocol {
112
134
  outputSchema: SchemaLike;
113
135
  init: ExchangeInit<S>;
114
136
  exchange: ExchangeFn<S>;
137
+ onCancel?: OnCancelFn<S>;
115
138
  headerSchema?: SchemaLike;
116
139
  headerInit?: HeaderInit;
117
140
  doc?: string;
@@ -129,6 +152,7 @@ export class Protocol {
129
152
  outputSchema: toSchema(config.outputSchema),
130
153
  exchangeInit: config.init as ExchangeInit,
131
154
  exchangeFn: config.exchange as ExchangeFn,
155
+ onCancel: config.onCancel as OnCancelFn | undefined,
132
156
  headerSchema: config.headerSchema ? toSchema(config.headerSchema) : undefined,
133
157
  headerInit: config.headerInit,
134
158
  doc: config.doc,
package/src/schema.ts CHANGED
@@ -2,109 +2,160 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import {
5
- Binary,
6
- Bool,
7
- DataType,
8
- Field,
9
- Float32,
10
- Float64,
11
- Int16,
12
- Int32,
13
- Int64,
14
- Schema,
15
- Utf8,
16
- } from "@query-farm/apache-arrow";
5
+ binary,
6
+ bool as boolType,
7
+ float32 as float32Type,
8
+ float64 as float64Type,
9
+ int8 as int8Type,
10
+ int16 as int16Type,
11
+ int32 as int32Type,
12
+ int64 as int64Type,
13
+ isBinary,
14
+ isBool,
15
+ isFloat,
16
+ isInt,
17
+ isUtf8,
18
+ field as makeField,
19
+ schema as makeSchema,
20
+ uint8 as uint8Type,
21
+ uint16 as uint16Type,
22
+ uint32 as uint32Type,
23
+ uint64 as uint64Type,
24
+ utf8,
25
+ type VgiDataType,
26
+ type VgiField,
27
+ type VgiSchema,
28
+ } from "./arrow/index.js";
17
29
 
18
30
  // ---------------------------------------------------------------------------
19
31
  // Convenient DataType singletons — re-export so users avoid arrow imports
20
32
  // ---------------------------------------------------------------------------
21
33
 
22
34
  /** Apache Arrow Utf8 type. Use as schema shorthand: `{ name: str }` */
23
- export const str = new Utf8();
35
+ export const str = utf8();
24
36
  /** Apache Arrow Binary type. Use as schema shorthand: `{ data: bytes }` */
25
- export const bytes = new Binary();
37
+ export const bytes = binary();
26
38
  /** Apache Arrow Int64 type. Use as schema shorthand: `{ count: int }` */
27
- export const int = new Int64();
39
+ export const int = int64Type();
28
40
  /** Apache Arrow Int32 type. Use as schema shorthand: `{ count: int32 }` */
29
- export const int32 = new Int32();
41
+ export const int32 = int32Type();
42
+ /** Apache Arrow Int16 type. Use as schema shorthand: `{ count: int16 }` */
43
+ export const int16 = int16Type();
44
+ /** Apache Arrow Int8 type. Use as schema shorthand: `{ count: int8 }` */
45
+ export const int8 = int8Type();
46
+ /** Apache Arrow Uint8 type. Use as schema shorthand: `{ count: uint8 }` */
47
+ export const uint8 = uint8Type();
48
+ /** Apache Arrow Uint16 type. Use as schema shorthand: `{ count: uint16 }` */
49
+ export const uint16 = uint16Type();
50
+ /** Apache Arrow Uint32 type. Use as schema shorthand: `{ count: uint32 }` */
51
+ export const uint32 = uint32Type();
52
+ /** Apache Arrow Uint64 type. Use as schema shorthand: `{ count: uint64 }` */
53
+ export const uint64 = uint64Type();
30
54
  /** Apache Arrow Float64 type. Use as schema shorthand: `{ value: float }` */
31
- export const float = new Float64();
55
+ export const float = float64Type();
32
56
  /** Apache Arrow Float32 type. Use as schema shorthand: `{ value: float32 }` */
33
- export const float32 = new Float32();
57
+ export const float32 = float32Type();
34
58
  /** Apache Arrow Bool type. Use as schema shorthand: `{ flag: bool }` */
35
- export const bool = new Bool();
59
+ export const bool = boolType();
36
60
 
37
61
  // ---------------------------------------------------------------------------
38
62
  // SchemaLike — shorthand for declaring schemas
39
63
  // ---------------------------------------------------------------------------
40
64
 
65
+ /**
66
+ * Structural minimum that any backend's Schema must satisfy. arrow-js's
67
+ * `Schema`, vgi-typescript's `VgiSchema`, and flechette's `Schema` all match
68
+ * this shape. Used so vgi-rpc consumers don't have to know which Arrow
69
+ * library is on the other side of the wire.
70
+ *
71
+ * Kept exported for backwards compatibility — equivalent to `VgiSchema`.
72
+ */
73
+ export interface SchemaShape {
74
+ readonly fields: ReadonlyArray<{
75
+ readonly name: string;
76
+ readonly type: { readonly typeId: number };
77
+ readonly nullable?: boolean;
78
+ readonly metadata?: Map<string, string>;
79
+ }>;
80
+ readonly metadata?: Map<string, string> | null;
81
+ }
82
+
41
83
  /**
42
84
  * A schema specification that accepts:
43
- * - A real `Schema` (passed through)
44
- * - A record mapping field names to `DataType` instances or `Field` instances
85
+ * - A real `VgiSchema` (passed through)
86
+ * - Anything structurally `SchemaShape`
87
+ * - A record mapping field names to `VgiDataType` instances or `VgiField` instances
45
88
  * - An empty `{}` for an empty schema
46
89
  */
47
- export type SchemaLike = Schema | Record<string, DataType | Field>;
90
+ export type SchemaLike = VgiSchema | SchemaShape | Record<string, VgiDataType | VgiField>;
91
+
92
+ function isField(x: unknown): x is VgiField {
93
+ return (
94
+ x != null &&
95
+ typeof (x as any).name === "string" &&
96
+ (x as any).type != null &&
97
+ typeof (x as any).nullable === "boolean"
98
+ );
99
+ }
100
+
101
+ function isDataType(x: unknown): x is VgiDataType {
102
+ return x != null && typeof (x as any).typeId === "number";
103
+ }
48
104
 
49
105
  /**
50
- * Convert a SchemaLike spec into a real `Schema`.
51
- *
52
- * - `Schema` → returned as-is
53
- * - `Record<string, DataType>` → each entry becomes `new Field(name, type, false)`
54
- * - `Record<string, Field>` → each entry is passed through
55
- * - `{}` → `new Schema([])`
106
+ * Convert a SchemaLike spec into a real `VgiSchema`.
56
107
  */
57
- export function toSchema(spec: SchemaLike): Schema {
58
- if (spec instanceof Schema) return spec;
108
+ export function toSchema(spec: SchemaLike): VgiSchema {
109
+ // VgiSchema / SchemaShape branch: anything with a `fields` array.
110
+ const maybeFields = (spec as { fields?: unknown }).fields;
111
+ if (Array.isArray(maybeFields)) {
112
+ const out: VgiField[] = [];
113
+ for (const f of maybeFields as ReadonlyArray<any>) {
114
+ if (isField(f)) {
115
+ out.push(f);
116
+ } else {
117
+ out.push(makeField(f.name, f.type, f.nullable ?? true, f.metadata));
118
+ }
119
+ }
120
+ return makeSchema(out);
121
+ }
59
122
 
60
- const fields: Field[] = [];
123
+ const fields: VgiField[] = [];
61
124
  for (const [name, value] of Object.entries(spec)) {
62
- if (value instanceof Field) {
125
+ if (isField(value)) {
63
126
  fields.push(value);
64
- } else if (value instanceof DataType) {
65
- fields.push(new Field(name, value, false));
127
+ } else if (isDataType(value)) {
128
+ fields.push(makeField(name, value, false));
66
129
  } else {
67
130
  throw new TypeError(`Invalid schema value for "${name}": expected DataType or Field, got ${typeof value}`);
68
131
  }
69
132
  }
70
- return new Schema(fields);
133
+ return makeSchema(fields);
71
134
  }
72
135
 
73
136
  // ---------------------------------------------------------------------------
74
137
  // inferParamTypes — derive paramTypes from a schema spec
75
138
  // ---------------------------------------------------------------------------
76
139
 
77
- const TYPE_MAP: [new (...args: any[]) => DataType, string][] = [
78
- [Utf8, "str"],
79
- [Binary, "bytes"],
80
- [Bool, "bool"],
81
- [Float64, "float"],
82
- [Float32, "float"],
83
- [Int64, "int"],
84
- [Int32, "int"],
85
- [Int16, "int"],
86
- ];
87
-
88
140
  /**
89
141
  * Derive a `paramTypes` record from a SchemaLike spec.
90
142
  * Maps common Arrow scalar types to Python-style type strings.
91
143
  * Returns `undefined` if any field has a complex type (List, Map_, Dictionary, etc.).
92
144
  */
93
145
  export function inferParamTypes(spec: SchemaLike): Record<string, string> | undefined {
94
- const schema = toSchema(spec);
95
- if (schema.fields.length === 0) return undefined;
146
+ const sch = toSchema(spec);
147
+ if (sch.fields.length === 0) return undefined;
96
148
 
97
149
  const result: Record<string, string> = {};
98
- for (const field of schema.fields) {
150
+ for (const f of sch.fields) {
99
151
  let mapped: string | undefined;
100
- for (const [ctor, name] of TYPE_MAP) {
101
- if (field.type instanceof ctor) {
102
- mapped = name;
103
- break;
104
- }
105
- }
152
+ if (isUtf8(f.type)) mapped = "str";
153
+ else if (isBinary(f.type)) mapped = "bytes";
154
+ else if (isBool(f.type)) mapped = "bool";
155
+ else if (isFloat(f.type)) mapped = "float";
156
+ else if (isInt(f.type)) mapped = "int";
106
157
  if (!mapped) return undefined;
107
- result[field.name] = mapped;
158
+ result[f.name] = mapped;
108
159
  }
109
160
  return result;
110
161
  }