@query-farm/vgi 0.43.0 → 0.44.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.
- package/README.md +5 -2
- package/dist/attach-ticket.d.ts +18 -7
- package/dist/client-entry.js +215 -91
- package/dist/client-entry.js.map +10 -9
- package/dist/codec/asd.d.ts +3 -1
- package/dist/codec/conform.d.ts +51 -0
- package/dist/errors.d.ts +5 -1
- package/dist/index.core.d.ts +1 -1
- package/dist/index.js +218 -39
- package/dist/index.js.map +17 -16
- package/dist/protocol/handlers/shared.d.ts +2 -1
- package/dist/protocol/serializers/shared.d.ts +2 -1
- package/dist/rpc-server.d.ts +2 -2
- package/dist/serve-entry.js +259 -89
- package/dist/serve-entry.js.map +13 -12
- package/dist/worker-cf-entry.js +201 -30
- package/dist/worker-cf-entry.js.map +17 -16
- package/package.json +3 -3
- package/src/attach-ticket.ts +41 -13
- package/src/catalog/composite.ts +2 -1
- package/src/catalog/interface.ts +5 -4
- package/src/catalog/read-only.ts +8 -6
- package/src/client/client.ts +13 -5
- package/src/codec/asd.ts +5 -2
- package/src/codec/conform.ts +193 -0
- package/src/errors.ts +27 -7
- package/src/functions/registry.ts +3 -2
- package/src/http/fetch.ts +1 -1
- package/src/index.core.ts +3 -1
- package/src/protocol/handlers/shared.ts +8 -2
- package/src/protocol/serializers/bind.ts +3 -1
- package/src/protocol/serializers/shared.ts +5 -2
- package/src/rpc-server.ts +7 -7
|
@@ -6,6 +6,7 @@ import type { OverloadContext } from "../../functions/registry.js";
|
|
|
6
6
|
import { batchToScalarDict, deserializeBatch, serializeBatch, batchFromColumns } from "../../util/arrow/index.js";
|
|
7
7
|
import { toUint8Array } from "../../util/bytes.js";
|
|
8
8
|
import { normalizeSchemaPath } from "../../schema-path.js";
|
|
9
|
+
import { conformRecord } from "../../codec/conform.js";
|
|
9
10
|
|
|
10
11
|
// The Python vgi-rpc framework wraps ALL non-void unary results in a single
|
|
11
12
|
// "result" column. For ArrowSerializableDataclass types, the result is serialized
|
|
@@ -39,7 +40,8 @@ export function normalizeRequestSchemaPaths(params: Record<string, any>): void {
|
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
* Wrap a dict of values into a single "result" Binary column.
|
|
42
|
-
* Builds a 1-row batch from the values using the given schema
|
|
43
|
+
* Builds a 1-row batch from the values using the given schema (conformed to
|
|
44
|
+
* the protocol's container rules, see `conformRecord`),
|
|
43
45
|
* serializes it to IPC bytes, and returns { result: bytes }.
|
|
44
46
|
*/
|
|
45
47
|
export function wrapResult(
|
|
@@ -47,8 +49,12 @@ export function wrapResult(
|
|
|
47
49
|
innerSchema: VgiSchema | import("../../arrow/index.js").VgiSchema,
|
|
48
50
|
): { result: Uint8Array } {
|
|
49
51
|
const a = innerSchema as VgiSchema;
|
|
52
|
+
// Python's container rules (a non-nullable list/map is never null, list
|
|
53
|
+
// items never are): `conformRecord` writes `[]` where a handler left a list
|
|
54
|
+
// out, and an unset list item as its zero value.
|
|
55
|
+
const row = conformRecord(a, values);
|
|
50
56
|
const batch = batchFromColumns(
|
|
51
|
-
Object.fromEntries(a.fields.map(f => [f.name, [
|
|
57
|
+
Object.fromEntries(a.fields.map(f => [f.name, [row[f.name] ?? null]])),
|
|
52
58
|
a,
|
|
53
59
|
);
|
|
54
60
|
return { result: serializeBatch(batch) };
|
|
@@ -72,7 +72,9 @@ export function serializeBindRequest(req: BindRequest): VgiBatch {
|
|
|
72
72
|
return buildSingleRowBatch(BIND_REQUEST_SCHEMA, {
|
|
73
73
|
function_name: req.function_name,
|
|
74
74
|
arguments: serializeArguments(req.arguments),
|
|
75
|
-
|
|
75
|
+
// The wire carries the Python enum member NAME ("TABLE"), not the TS
|
|
76
|
+
// enum's value ("table"); each FunctionType value upper-cases to its name.
|
|
77
|
+
function_type: req.function_type == null ? req.function_type : String(req.function_type).toUpperCase(),
|
|
76
78
|
input_schema: req.input_schema ? serializeSchema(req.input_schema) : null,
|
|
77
79
|
settings: req.settings ? serializeBatch(req.settings) : null,
|
|
78
80
|
secrets: req.secrets ? serializeBatch(req.secrets) : null,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
batchFromColumns,
|
|
9
9
|
} from "../../arrow/index.js";
|
|
10
10
|
import { toUint8Array as toUint8ArrayBase } from "../../util/bytes.js";
|
|
11
|
+
import { conformRecord } from "../../codec/conform.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Coerce a wire value (string / Uint8Array / Buffer / etc.) to a Uint8Array.
|
|
@@ -25,7 +26,8 @@ export function toUint8Array(val: any): Uint8Array {
|
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Build a single-row RecordBatch from a {fieldName: value} dict matching the
|
|
28
|
-
* given schema. Auto-coerces JS numbers to BigInt for Int64 fields
|
|
29
|
+
* given schema. Auto-coerces JS numbers to BigInt for Int64 fields, and
|
|
30
|
+
* applies the protocol's container rules (`conformRecord`).
|
|
29
31
|
*/
|
|
30
32
|
export function buildSingleRowBatch(
|
|
31
33
|
schema: VgiSchema,
|
|
@@ -35,8 +37,9 @@ export function buildSingleRowBatch(
|
|
|
35
37
|
// declares one — vectorFromArray/columnFromArray rejects plain Number for
|
|
36
38
|
// 64-bit ints under both backends.
|
|
37
39
|
const cols: Record<string, any[]> = {};
|
|
40
|
+
const row = conformRecord(schema, values);
|
|
38
41
|
for (const f of schema.fields) {
|
|
39
|
-
let val =
|
|
42
|
+
let val = row[f.name];
|
|
40
43
|
if (isInt(f.type) && (f.type as any).bitWidth === 64 && typeof val === "number") {
|
|
41
44
|
val = BigInt(val);
|
|
42
45
|
}
|
package/src/rpc-server.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// 2. The worker's `hostedProtocols()`, in the order returned -- on EVERY
|
|
14
14
|
// transport.
|
|
15
15
|
// 3. `vgi_rpc.Reflection.v1` -- on every transport.
|
|
16
|
-
// 4. `vgi_rpc.Identity.
|
|
16
|
+
// 4. `vgi_rpc.Identity.v2` -- HTTP only, and only when the worker supplies
|
|
17
17
|
// `resolveToken` and/or `mintGrant` (or grant keys are configured).
|
|
18
18
|
// 5. `vgi.attach_tickets.v1` -- HTTP only, and only when the signing key was
|
|
19
19
|
// configured explicitly (never a generated one) *and* the worker can
|
|
@@ -44,7 +44,7 @@ export type ServerTransport = "pipe" | "unix" | "tcp" | "iroh" | "stream" | "htt
|
|
|
44
44
|
const TRANSPORTS: ReadonlySet<string> = new Set<ServerTransport>(["pipe", "unix", "tcp", "iroh", "stream", "http"]);
|
|
45
45
|
|
|
46
46
|
/** Transports that authenticate their callers, and so may host
|
|
47
|
-
* `vgi_rpc.Identity.
|
|
47
|
+
* `vgi_rpc.Identity.v2`. Identity answers questions about *other* callers'
|
|
48
48
|
* credentials; its allowlist is a list of principals, which a transport with
|
|
49
49
|
* no caller identity cannot check. */
|
|
50
50
|
const IDENTITY_TRANSPORTS: ReadonlySet<string> = new Set<ServerTransport>(["http"]);
|
|
@@ -78,14 +78,14 @@ export interface HostingOptions {
|
|
|
78
78
|
*
|
|
79
79
|
* Each needs a distinct wire name, which may not be `vgi.v2` and may not
|
|
80
80
|
* use the reserved `vgi_rpc.` prefix: reflection is hosted automatically and
|
|
81
|
-
* `vgi_rpc.Identity.
|
|
81
|
+
* `vgi_rpc.Identity.v2` is enabled through {@link resolveToken} /
|
|
82
82
|
* {@link mintGrant}. Violations are a startup error naming this hook.
|
|
83
83
|
*/
|
|
84
84
|
hostedProtocols?: () => Iterable<Protocol>;
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
87
|
* Resolve an opaque bearer credential to the identity it authenticates as.
|
|
88
|
-
* Supplying it hosts `vgi_rpc.Identity.
|
|
88
|
+
* Supplying it hosts `vgi_rpc.Identity.v2`'s `introspect_token` -- on HTTP,
|
|
89
89
|
* the transport that authenticates callers. Absent, the method is absent
|
|
90
90
|
* (not hosted-and-refusing), which keeps a dependency upgrade from growing a
|
|
91
91
|
* credential-to-identity oracle on every existing worker.
|
|
@@ -232,7 +232,7 @@ function validatedHostedProtocols(hosting: HostingOptions, primary: Protocol): P
|
|
|
232
232
|
throw new Error(
|
|
233
233
|
`${owner} entry ${index} is named '${name}', which claims the reserved '${RESERVED_PREFIX}' prefix. ` +
|
|
234
234
|
"Framework protocols are not supplied through this hook: reflection is hosted automatically, and " +
|
|
235
|
-
"vgi_rpc.Identity.
|
|
235
|
+
"vgi_rpc.Identity.v2 is enabled by supplying resolveToken and/or mintGrant.",
|
|
236
236
|
);
|
|
237
237
|
}
|
|
238
238
|
if (!/^[A-Za-z_][A-Za-z0-9_.]*$/.test(name)) {
|
|
@@ -259,7 +259,7 @@ function validatedHostedProtocols(hosting: HostingOptions, primary: Protocol): P
|
|
|
259
259
|
return out;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
/** Build the `vgi_rpc.Identity.
|
|
262
|
+
/** Build the `vgi_rpc.Identity.v2` implementation, or `undefined`.
|
|
263
263
|
*
|
|
264
264
|
* `undefined` unless the worker supplies at least one hook -- and that is the
|
|
265
265
|
* point: the server then does not host the protocol at all, rather than
|
|
@@ -329,7 +329,7 @@ function resolveIntrospectPrincipals(
|
|
|
329
329
|
}
|
|
330
330
|
if (principals.length === 0) {
|
|
331
331
|
throw new Error(
|
|
332
|
-
"This worker supplies resolveToken, which hosts the vgi_rpc.Identity.
|
|
332
|
+
"This worker supplies resolveToken, which hosts the vgi_rpc.Identity.v2 protocol, but no " +
|
|
333
333
|
`introspector allowlist was configured. Set ${INTROSPECT_PRINCIPALS_ENV} (comma-separated) or pass ` +
|
|
334
334
|
"introspectPrincipals.\n\n" +
|
|
335
335
|
"There is no permissive default on purpose: introspection is a separate capability from " +
|