@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.
@@ -15,7 +15,9 @@
15
15
  import { type VgiSchema } from "../arrow/index.js";
16
16
  /**
17
17
  * Encode a typed object as a single-row Arrow IPC stream using `schema`.
18
- * Matches Python's `ArrowSerializableDataclass.serialize_to_bytes()`.
18
+ * Matches Python's `ArrowSerializableDataclass.serialize_to_bytes()`, including
19
+ * its container rules: a non-nullable list/map left out or null is written as
20
+ * empty, and list items / map values are never null (see `conformRecord`).
19
21
  */
20
22
  export declare function encodeASD(schema: VgiSchema, obj: Record<string, any>): Uint8Array;
21
23
  /** Compare two strings by Unicode code point (= UTF-8 byte order). */
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Wire conformance for protocol records.
3
+ *
4
+ * vgi-python is the reference for the wire shape, and two of its rules are not
5
+ * expressed by a record's Arrow schema nullability flags alone:
6
+ *
7
+ * 1. A **non-nullable list or map column is never null.** Python's dataclass
8
+ * defaults a `list[...]` / `dict[...]` field to an empty container, so an
9
+ * "absent" list goes out as `[]`. A JS caller that leaves the field out (or
10
+ * passes `null`) would otherwise put a null in a column the schema calls
11
+ * non-null — `CatalogInfo.releases`, `CatalogInfo.attach_option_specs`,
12
+ * ... — which a strict client rejects as a protocol error.
13
+ *
14
+ * 2. **List items and map values are never null** unless the Python annotation
15
+ * says so (`list[str | None]`). pyarrow marks every list item field nullable,
16
+ * so the generated schemas carry `item: nullable=true` everywhere and cannot
17
+ * tell the two apart. In the whole protocol exactly one field has optional
18
+ * items — `argument_names` on `BindRequest` / `AggregateBindRequest` (a
19
+ * positional argument has no name). Every other null item is a bug on the
20
+ * sending side (e.g. `BindResponse.lookup_names` built from an unset secret
21
+ * name, where Python sends `""`).
22
+ *
23
+ * `conformRecord` applies both rules to a record about to be encoded: a null or
24
+ * absent non-nullable list/map becomes empty, and a null list item / map value
25
+ * becomes its type's zero value (`""`, `0`, `false`, empty bytes, empty list),
26
+ * which is also what the C++ client reads such an item as. It never mutates its
27
+ * input (catalog items may be frozen and shared) and returns the input itself
28
+ * when nothing needed changing. Nullable columns, and scalars, pass through
29
+ * untouched: a null in a non-nullable scalar column has no safe default and is
30
+ * left for the caller to fix (see `wireViolations`).
31
+ */
32
+ import { type VgiSchema, type VgiDataType } from "../arrow/index.js";
33
+ /**
34
+ * Top-level / struct-child field names whose list items may legitimately be
35
+ * null (the Python annotation is `list[X | None]`). Derived from vgi-python by
36
+ * walking every protocol dataclass's type hints; keep in sync if the protocol
37
+ * adds another optional-item list.
38
+ */
39
+ export declare const OPTIONAL_ITEM_FIELDS: ReadonlySet<string>;
40
+ /** The value a non-null slot of `type` takes when the sender left it null. */
41
+ export declare function zeroValue(type: VgiDataType): unknown;
42
+ /**
43
+ * `obj` conformed to `schema`'s wire rules (see the module comment). Returns
44
+ * `obj` itself when nothing changed.
45
+ */
46
+ export declare function conformRecord<T extends Record<string, any>>(schema: VgiSchema, obj: T): T;
47
+ /**
48
+ * Column-dict form of `conformRecord` for `batchFromColumns` callers: each
49
+ * value is a one-element array holding the row's value.
50
+ */
51
+ export declare function conformColumns(schema: VgiSchema, columns: Record<string, unknown[]>): Record<string, unknown[]>;
package/dist/errors.d.ts CHANGED
@@ -1,6 +1,10 @@
1
+ import type { ErrorCode } from "@query-farm/vgi-rpc";
1
2
  export declare class VgiError extends Error {
2
- constructor(message: string);
3
+ /** Canonical code hoisted as `vgi_rpc.error_code`; unset means `UNKNOWN`. */
4
+ readonly errorCode?: ErrorCode;
5
+ constructor(message: string, code?: ErrorCode);
3
6
  }
7
+ /** A worker bug (the function returned the wrong number of rows): UNKNOWN. */
4
8
  export declare class RowCountMismatchError extends VgiError {
5
9
  constructor(expected: number, actual: number);
6
10
  }
@@ -28,7 +28,7 @@ export type { LandingInfo } from "./http/landing.js";
28
28
  export { createLandingRoutes } from "./http/landing.js";
29
29
  export { BindResultSchema, ScanFunctionResultSchema } from "./generated/vgi-protocol-schemas.js";
30
30
  export { type AttachOptionSpec, serializeAttachOptionSpec, serializeAttachOptionSpecs, deserializeAttachOptionSpec, deserializeAttachOptionSpecs, RESERVED_ATTACH_OPTION, ReservedAttachOptionError, } from "./catalog/attach-option.js";
31
- export { ATTACH_TICKET_OPTION, ATTACH_TICKET_PREFIX, ATTACH_TICKETS_PROTOCOL_NAME, ATTACH_TICKETS_PROTOCOL_VERSION, ATTACH_TICKET_SCHEMA, SEAL_ATTACH_REQUEST_SCHEMA, AttachTicketExpiredError, AttachTicketInvalidError, AttachTicketRequestError, SealAttachDeniedError, type AttachTicketClaims, type RestoredAttach, attachTicketAad, mintAttachTicket, openAttachTicket, redeemAttachTicket, } from "./attach-ticket.js";
31
+ export { ATTACH_TICKET_OPTION, ATTACH_TICKET_PREFIX, ATTACH_TICKETS_PROTOCOL_NAME, ATTACH_TICKETS_PROTOCOL_VERSION, ATTACH_TICKET_SCHEMA, SEAL_ATTACH_REQUEST_SCHEMA, AttachTicketExpiredError, AttachTicketInvalidError, AttachTicketRequestError, SealAttachDeniedError, type AttachTicket, type AttachTicketClaims, type RestoredAttach, encodeAttachTicket, attachTicketAad, mintAttachTicket, openAttachTicket, redeemAttachTicket, } from "./attach-ticket.js";
32
32
  export { type ColumnStatistics, serializeColumnStatistics } from "./util/statistics.js";
33
33
  export { toUint8Array } from "./util/bytes.js";
34
34
  export { iterRows, batchFromRows, batchFromColumns, emptyBatch, filterBatch, projectSchema, projectBatch, batchToScalarDict, batchToSecretDict, safeNumber, } from "./util/arrow/index.js";
package/dist/index.js CHANGED
@@ -1,4 +1,27 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
2
25
  var __returnValue = (v) => v;
3
26
  function __exportSetter(name, newValue) {
4
27
  this[name] = __returnValue.bind(null, newValue);
@@ -2021,6 +2044,11 @@ var init_arrow = __esm(() => {
2021
2044
  });
2022
2045
 
2023
2046
  // src/functions/storage-cf-do.ts
2047
+ var exports_storage_cf_do = {};
2048
+ __export(exports_storage_cf_do, {
2049
+ FunctionStorageCfDo: () => FunctionStorageCfDo
2050
+ });
2051
+
2024
2052
  class FunctionStorageCfDo {
2025
2053
  _baseUrl;
2026
2054
  _token;
@@ -2466,7 +2494,7 @@ function resolveStorageFromEnv() {
2466
2494
  return new FunctionStorageSqlite;
2467
2495
  }
2468
2496
  if (backend === "cloudflare-do") {
2469
- init_storage_cf_do();
2497
+ const { FunctionStorageCfDo } = (init_storage_cf_do(), __toCommonJS(exports_storage_cf_do));
2470
2498
  return FunctionStorageCfDo.fromEnv();
2471
2499
  }
2472
2500
  throw new Error(`Unknown VGI_WORKER_SHARED_STORAGE backend: '${backend}'. Supported: 'memory', 'sqlite', 'cloudflare-do'.`);
@@ -2637,9 +2665,12 @@ var DEFAULT_MAX_WORKERS = 99999;
2637
2665
 
2638
2666
  // src/errors.ts
2639
2667
  class VgiError extends Error {
2640
- constructor(message) {
2668
+ errorCode;
2669
+ constructor(message, code) {
2641
2670
  super(message);
2642
2671
  this.name = "VgiError";
2672
+ if (code !== undefined)
2673
+ this.errorCode = code;
2643
2674
  }
2644
2675
  }
2645
2676
 
@@ -2652,42 +2683,42 @@ class RowCountMismatchError extends VgiError {
2652
2683
 
2653
2684
  class FunctionNotFoundError extends VgiError {
2654
2685
  constructor(name, available) {
2655
- super(`Unknown function '${name}'`);
2686
+ super(`Unknown function '${name}'`, "NOT_FOUND");
2656
2687
  this.name = "FunctionNotFoundError";
2657
2688
  }
2658
2689
  }
2659
2690
 
2660
2691
  class CatalogReadOnlyError extends VgiError {
2661
2692
  constructor(operation) {
2662
- super(`catalog is read-only: ${operation} is not supported`);
2693
+ super(`catalog is read-only: ${operation} is not supported`, "FAILED_PRECONDITION");
2663
2694
  this.name = "CatalogReadOnlyError";
2664
2695
  }
2665
2696
  }
2666
2697
 
2667
2698
  class CatalogNotFoundError extends VgiError {
2668
2699
  constructor(entity, name) {
2669
- super(`${entity} '${name}' not found`);
2700
+ super(`${entity} '${name}' not found`, "NOT_FOUND");
2670
2701
  this.name = "CatalogNotFoundError";
2671
2702
  }
2672
2703
  }
2673
2704
 
2674
2705
  class CatalogAlreadyExistsError extends VgiError {
2675
2706
  constructor(entity, name) {
2676
- super(`${entity} '${name}' already exists`);
2707
+ super(`${entity} '${name}' already exists`, "ALREADY_EXISTS");
2677
2708
  this.name = "CatalogAlreadyExistsError";
2678
2709
  }
2679
2710
  }
2680
2711
 
2681
2712
  class ArgumentValidationError extends VgiError {
2682
2713
  constructor(message) {
2683
- super(message);
2714
+ super(message, "INVALID_ARGUMENT");
2684
2715
  this.name = "ArgumentValidationError";
2685
2716
  }
2686
2717
  }
2687
2718
 
2688
2719
  class NoCatalogError extends VgiError {
2689
2720
  constructor() {
2690
- super("No catalog is configured for this worker");
2721
+ super("No catalog is configured for this worker", "UNIMPLEMENTED");
2691
2722
  this.name = "NoCatalogError";
2692
2723
  }
2693
2724
  }
@@ -5381,6 +5412,137 @@ init_arrow();
5381
5412
 
5382
5413
  // src/protocol/serializers/shared.ts
5383
5414
  init_arrow();
5415
+
5416
+ // src/codec/conform.ts
5417
+ init_arrow();
5418
+ var OPTIONAL_ITEM_FIELDS = new Set(["argument_names"]);
5419
+ function children(type) {
5420
+ return type.children ?? [];
5421
+ }
5422
+ function mapValueType(type) {
5423
+ const entries = children(type)[0].type;
5424
+ return children(entries)[1].type;
5425
+ }
5426
+ function mapPairs(raw) {
5427
+ if (Array.isArray(raw))
5428
+ return raw.map((e) => Array.isArray(e) ? [e[0], e[1]] : [e?.key, e?.value]);
5429
+ if (raw instanceof Map)
5430
+ return Array.from(raw.entries());
5431
+ if (typeof raw[Symbol.iterator] === "function")
5432
+ return Array.from(raw);
5433
+ return Object.entries(raw);
5434
+ }
5435
+ function zeroValue(type) {
5436
+ if (isUtf8(type) || isDictionary(type))
5437
+ return "";
5438
+ if (isBinary(type))
5439
+ return new Uint8Array(0);
5440
+ if (isBool(type))
5441
+ return false;
5442
+ if (isInt(type))
5443
+ return type.bitWidth === 64 ? 0n : 0;
5444
+ if (isFloat(type))
5445
+ return 0;
5446
+ if (isList(type) || isMap(type))
5447
+ return [];
5448
+ if (isStruct(type)) {
5449
+ const out = {};
5450
+ for (const c of children(type))
5451
+ out[c.name] = c.nullable ? null : conformValue(c.type, undefined, false, c.name);
5452
+ return out;
5453
+ }
5454
+ return null;
5455
+ }
5456
+ var HAS_CONTAINER = new WeakMap;
5457
+ function hasContainer(type) {
5458
+ const cached = HAS_CONTAINER.get(type);
5459
+ if (cached !== undefined)
5460
+ return cached;
5461
+ let has = isList(type) || isMap(type);
5462
+ if (!has && isStruct(type))
5463
+ has = children(type).some((c) => hasContainer(c.type));
5464
+ HAS_CONTAINER.set(type, has);
5465
+ return has;
5466
+ }
5467
+ function conformValue(type, value, nullable, name) {
5468
+ if (value == null) {
5469
+ if (nullable)
5470
+ return value ?? null;
5471
+ if (isList(type) || isMap(type))
5472
+ return [];
5473
+ return value;
5474
+ }
5475
+ if (!hasContainer(type))
5476
+ return value;
5477
+ if (isList(type)) {
5478
+ const itemType = children(type)[0].type;
5479
+ const itemsNullable = OPTIONAL_ITEM_FIELDS.has(name);
5480
+ const items = Array.isArray(value) ? value : Array.from(value);
5481
+ let changed = !Array.isArray(value);
5482
+ const out = items.map((item) => {
5483
+ const next = item == null && !itemsNullable ? zeroValue(itemType) : conformValue(itemType, item, true, name);
5484
+ if (next !== item)
5485
+ changed = true;
5486
+ return next;
5487
+ });
5488
+ return changed ? out : value;
5489
+ }
5490
+ if (isMap(type)) {
5491
+ const valueType = mapValueType(type);
5492
+ const pairs = mapPairs(value);
5493
+ let changed = false;
5494
+ const out = pairs.map(([k, v]) => {
5495
+ const next = v == null ? zeroValue(valueType) : conformValue(valueType, v, true, name);
5496
+ if (next !== v)
5497
+ changed = true;
5498
+ return [k, next];
5499
+ });
5500
+ return changed ? out : value;
5501
+ }
5502
+ if (isStruct(type)) {
5503
+ let out = null;
5504
+ for (const c of children(type)) {
5505
+ const v = value[c.name];
5506
+ const next = conformValue(c.type, v, c.nullable, c.name);
5507
+ if (next !== v) {
5508
+ (out ??= { ...value })[c.name] = next;
5509
+ }
5510
+ }
5511
+ return out ?? value;
5512
+ }
5513
+ return value;
5514
+ }
5515
+ function conformRecord(schema, obj) {
5516
+ let out = null;
5517
+ for (const f of schema.fields) {
5518
+ const v = obj[f.name];
5519
+ const next = conformValue(f.type, v, f.nullable, f.name);
5520
+ if (next !== v) {
5521
+ (out ??= { ...obj })[f.name] = next;
5522
+ }
5523
+ }
5524
+ return out ?? obj;
5525
+ }
5526
+ function conformColumns(schema, columns) {
5527
+ let out = null;
5528
+ for (const f of schema.fields) {
5529
+ const col = columns[f.name];
5530
+ const rows = col ?? [undefined];
5531
+ let changed = col === undefined;
5532
+ const next = rows.map((v) => {
5533
+ const c = conformValue(f.type, v, f.nullable, f.name);
5534
+ if (c !== v)
5535
+ changed = true;
5536
+ return c;
5537
+ });
5538
+ if (changed) {
5539
+ (out ??= { ...columns })[f.name] = next;
5540
+ }
5541
+ }
5542
+ return out ?? columns;
5543
+ }
5544
+
5545
+ // src/protocol/serializers/shared.ts
5384
5546
  function toUint8Array2(val) {
5385
5547
  if (typeof val === "string")
5386
5548
  return new TextEncoder().encode(val);
@@ -5392,8 +5554,9 @@ function toUint8Array2(val) {
5392
5554
  }
5393
5555
  function buildSingleRowBatch(schema, values) {
5394
5556
  const cols = {};
5557
+ const row = conformRecord(schema, values);
5395
5558
  for (const f of schema.fields) {
5396
- let val = values[f.name];
5559
+ let val = row[f.name];
5397
5560
  if (isInt(f.type) && f.type.bitWidth === 64 && typeof val === "number") {
5398
5561
  val = BigInt(val);
5399
5562
  }
@@ -5433,7 +5596,7 @@ function serializeBindRequest(req) {
5433
5596
  return buildSingleRowBatch(BIND_REQUEST_SCHEMA, {
5434
5597
  function_name: req.function_name,
5435
5598
  arguments: serializeArguments(req.arguments),
5436
- function_type: req.function_type,
5599
+ function_type: req.function_type == null ? req.function_type : String(req.function_type).toUpperCase(),
5437
5600
  input_schema: req.input_schema ? serializeSchema(req.input_schema) : null,
5438
5601
  settings: req.settings ? serializeBatch(req.settings) : null,
5439
5602
  secrets: req.secrets ? serializeBatch(req.secrets) : null,
@@ -7035,7 +7198,7 @@ function schemaPathDisplay(path) {
7035
7198
  // src/codec/asd.ts
7036
7199
  init_arrow();
7037
7200
  function encodeASD(schema, obj) {
7038
- return serializeBatch(batchFromRows([sortMapsForSchema(schema, obj)], schema));
7201
+ return serializeBatch(batchFromRows([sortMapsForSchema(schema, conformRecord(schema, obj))], schema));
7039
7202
  }
7040
7203
  function compareCodePoints(a, b) {
7041
7204
  const n = Math.min(a.length, b.length);
@@ -7052,7 +7215,7 @@ function compareCodePoints(a, b) {
7052
7215
  }
7053
7216
  return a.length - b.length;
7054
7217
  }
7055
- function mapPairs(raw) {
7218
+ function mapPairs2(raw) {
7056
7219
  if (Array.isArray(raw))
7057
7220
  return raw.map((e) => Array.isArray(e) ? [e[0], e[1]] : [e?.key, e?.value]);
7058
7221
  if (raw instanceof Map)
@@ -7087,7 +7250,7 @@ function sortMapsForType(type, value) {
7087
7250
  if (isMap(type)) {
7088
7251
  const entries = type.children[0].type;
7089
7252
  const valueType = entries.children[1].type;
7090
- return mapPairs(value).map(([k, v]) => [k, sortMapsForType(valueType, v)]).sort((x, y) => compareKeys(x[0], y[0]));
7253
+ return mapPairs2(value).map(([k, v]) => [k, sortMapsForType(valueType, v)]).sort((x, y) => compareKeys(x[0], y[0]));
7091
7254
  }
7092
7255
  if (isList(type)) {
7093
7256
  const child = type.children[0].type;
@@ -8252,12 +8415,12 @@ var encodeAttachCatalogInfo = (v) => encodeASD(AttachCatalogInfoSchema, {
8252
8415
  secret_ref: v.secret_ref ?? ""
8253
8416
  });
8254
8417
  function encodeScanFunctionResult(functionName, argumentsBytes, requiredExtensions = [], schemaPath = null) {
8255
- return serializeBatch(batchFromColumns({
8418
+ return serializeBatch(batchFromColumns(conformColumns(ScanFunctionResultSchema, {
8256
8419
  function_name: [functionName],
8257
8420
  arguments: [argumentsBytes],
8258
8421
  required_extensions: [requiredExtensions],
8259
8422
  schema_path: [schemaPath]
8260
- }, ScanFunctionResultSchema));
8423
+ }), ScanFunctionResultSchema));
8261
8424
  }
8262
8425
  function decodeScanFunctionResult(inner) {
8263
8426
  const argsBytes = inner.arguments;
@@ -8301,7 +8464,7 @@ function singleBranchResult(legacy) {
8301
8464
  };
8302
8465
  }
8303
8466
  function encodeScanBranch(cols) {
8304
- return serializeBatch(batchFromColumns({
8467
+ return serializeBatch(batchFromColumns(conformColumns(ScanBranchSchema, {
8305
8468
  function_name: [cols.function_name],
8306
8469
  arguments: [cols.arguments],
8307
8470
  branch_filter: [cols.branch_filter ?? null],
@@ -8313,7 +8476,7 @@ function encodeScanBranch(cols) {
8313
8476
  format_locations: [cols.format_locations ?? null],
8314
8477
  format_options: [cols.format_options ?? null],
8315
8478
  schema_path: [cols.schema_path ?? null]
8316
- }, ScanBranchSchema));
8479
+ }), ScanBranchSchema));
8317
8480
  }
8318
8481
  function encodeFormatOptions(options) {
8319
8482
  const fields = [];
@@ -8884,7 +9047,7 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
8884
9047
  }
8885
9048
  attach(name, options, dataVersionSpec, implementationVersion) {
8886
9049
  if (!this.catalogs().includes(name)) {
8887
- throw new Error(`No worker handles catalog '${name}'`);
9050
+ throw new VgiError(`No worker handles catalog '${name}'`, "NOT_FOUND");
8888
9051
  }
8889
9052
  validateRequiredAttachOptions(name, this.attachOptionSpecs(name), options ?? {});
8890
9053
  const attachOpaqueData = new Uint8Array(16);
@@ -9284,11 +9447,11 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
9284
9447
  validateAtParams(atUnit, atValue);
9285
9448
  const schema = this._descriptor.schemas.find((s) => schemaPathsEqual(schemaDescriptorPath(s), schemaPath));
9286
9449
  if (!schema || !schema.tables) {
9287
- throw new Error(`Table '${name}' not found in schema ${schemaPathDisplay(schemaPath)}`);
9450
+ throw new VgiError(`Table '${name}' not found in schema ${schemaPathDisplay(schemaPath)}`, "NOT_FOUND");
9288
9451
  }
9289
9452
  const table = schema.tables.find((t) => t.name === name);
9290
9453
  if (!table) {
9291
- throw new Error(`Table '${name}' not found in schema ${schemaPathDisplay(schemaPath)}`);
9454
+ throw new VgiError(`Table '${name}' not found in schema ${schemaPathDisplay(schemaPath)}`, "NOT_FOUND");
9292
9455
  }
9293
9456
  if (atUnit && !table.supportsTimeTravel) {
9294
9457
  throw new Error(`Table ${schemaPathDisplay(schemaPath)}.${name} does not support time travel queries`);
@@ -9373,12 +9536,12 @@ function resolveIndexGroups(schema, groups) {
9373
9536
  function serializeForeignKeys(fks, schemaPath) {
9374
9537
  if (!fks || fks.length === 0)
9375
9538
  return [];
9376
- return fks.map((fk) => serializeBatch(batchFromColumns({
9539
+ return fks.map((fk) => serializeBatch(batchFromColumns(conformColumns(ForeignKeyInfoSchema, {
9377
9540
  fk_columns: [fk.columns],
9378
9541
  pk_columns: [fk.referencedColumns],
9379
9542
  referenced_table: [fk.referencedTable],
9380
9543
  referenced_schema_path: [fk.referencedSchemaPath ?? schemaPath ?? ["main"]]
9381
- }, ForeignKeyInfoSchema)));
9544
+ }), ForeignKeyInfoSchema)));
9382
9545
  }
9383
9546
  function defaultToSql(value) {
9384
9547
  if (value === null || value === undefined)
@@ -9518,7 +9681,7 @@ function serializeArgsBatch(args, argSpecSchema) {
9518
9681
  }
9519
9682
  function validateAtParams(atUnit, atValue) {
9520
9683
  if (Boolean(atUnit) !== Boolean(atValue)) {
9521
- throw new Error("at_unit and at_value must both be provided or both be absent");
9684
+ throw new VgiError("at_unit and at_value must both be provided or both be absent", "INVALID_ARGUMENT");
9522
9685
  }
9523
9686
  }
9524
9687
  function inferScalarType2(val) {
@@ -10403,7 +10566,7 @@ class CompositeCatalogInterface extends CatalogInterface {
10403
10566
  return result;
10404
10567
  }
10405
10568
  }
10406
- throw new Error(`No worker handles catalog '${name}'`);
10569
+ throw new VgiError(`No worker handles catalog '${name}'`, "NOT_FOUND");
10407
10570
  }
10408
10571
  async detach(attachOpaqueData) {
10409
10572
  await this._route(attachOpaqueData).detach(attachOpaqueData);
@@ -10727,7 +10890,7 @@ class FunctionRegistry {
10727
10890
  } else if (candidates && candidates.length > 0) {
10728
10891
  const schemas = this.schemasFor(name);
10729
10892
  if (schemas.length > 0) {
10730
- throw new Error(`Function '${name}' is not registered in schema ${schemaPathDisplay(schemaPath)}. ` + `It is available in: [${schemas.map(schemaPathDisplay).join(", ")}]`);
10893
+ throw new VgiError(`Function '${name}' is not registered in schema ${schemaPathDisplay(schemaPath)}. ` + `It is available in: [${schemas.map(schemaPathDisplay).join(", ")}]`, "NOT_FOUND");
10731
10894
  }
10732
10895
  }
10733
10896
  }
@@ -12315,7 +12478,8 @@ function normalizeRequestSchemaPaths(params) {
12315
12478
  }
12316
12479
  function wrapResult(values, innerSchema) {
12317
12480
  const a = innerSchema;
12318
- const batch = batchFromColumns(Object.fromEntries(a.fields.map((f) => [f.name, [values[f.name] ?? null]])), a);
12481
+ const row = conformRecord(a, values);
12482
+ const batch = batchFromColumns(Object.fromEntries(a.fields.map((f) => [f.name, [row[f.name] ?? null]])), a);
12319
12483
  return { result: serializeBatch(batch) };
12320
12484
  }
12321
12485
  function overloadContext(req, catalogInterface) {
@@ -13331,7 +13495,7 @@ import {
13331
13495
  var ATTACH_TICKET_PREFIX = "vgia1.";
13332
13496
  var ATTACH_TICKET_OPTION = RESERVED_ATTACH_OPTION;
13333
13497
  var ATTACH_TICKETS_PROTOCOL_NAME = "vgi.attach_tickets.v1";
13334
- var ATTACH_TICKETS_PROTOCOL_VERSION = "1.0.0";
13498
+ var ATTACH_TICKETS_PROTOCOL_VERSION = "2.0.0";
13335
13499
  var TICKET_ENVELOPE_VERSION = 1;
13336
13500
  var MAX_OPTIONS_BYTES = 16 * 1024;
13337
13501
  var MAX_TICKET_CHARS = 32 * 1024;
@@ -13606,8 +13770,19 @@ var SEAL_ATTACH_REQUEST_SCHEMA = schema2([
13606
13770
  ]);
13607
13771
  var ATTACH_TICKET_SCHEMA = schema2([
13608
13772
  field2("ticket", utf82(), false),
13609
- field2("expires_at", float642(), false)
13773
+ field2("expires_at", timestamp2(TimeUnit2.MICROSECOND, "UTC"), true)
13610
13774
  ]);
13775
+ function expiresAtMicros(value) {
13776
+ if (value === null)
13777
+ return null;
13778
+ const ms = value.getTime();
13779
+ if (!Number.isFinite(ms))
13780
+ throw new TypeError("AttachTicket.expires_at must be a valid Date or null");
13781
+ return BigInt(ms) * 1000n;
13782
+ }
13783
+ function encodeAttachTicket(ticket) {
13784
+ return serializeBatch(batchFromColumns({ ticket: [ticket.ticket], expires_at: [expiresAtMicros(ticket.expires_at)] }, ATTACH_TICKET_SCHEMA));
13785
+ }
13611
13786
  function resolveTicketMaxTtl(grantKeys, env) {
13612
13787
  if (grantKeys)
13613
13788
  return Math.trunc(grantKeys.maxTtlSeconds);
@@ -13694,7 +13869,7 @@ async function sealAttach2(config, request, auth) {
13694
13869
  } catch (e) {
13695
13870
  throw new AttachTicketRequestError("seal_attach request is invalid", [["request", e.message]]);
13696
13871
  }
13697
- return { ticket: token, expires_at: expiresAt === 0 ? Number.POSITIVE_INFINITY : expiresAt };
13872
+ return { ticket: token, expires_at: expiresAt === 0 ? null : new Date(expiresAt * 1000) };
13698
13873
  }
13699
13874
  function buildAttachTicketsProtocol(config) {
13700
13875
  const p = new Protocol2(ATTACH_TICKETS_PROTOCOL_NAME, { protocolVersion: ATTACH_TICKETS_PROTOCOL_VERSION });
@@ -13705,8 +13880,7 @@ function buildAttachTicketsProtocol(config) {
13705
13880
  handler: async (params, ctx) => {
13706
13881
  const request = unwrapRequest(params.request);
13707
13882
  const sealed = await sealAttach2(config, request, ctx?.auth);
13708
- const batch = batchFromColumns({ ticket: [sealed.ticket], expires_at: [sealed.expires_at] }, ATTACH_TICKET_SCHEMA);
13709
- return { result: serializeBatch(batch) };
13883
+ return { result: encodeAttachTicket(sealed) };
13710
13884
  }
13711
13885
  });
13712
13886
  return p;
@@ -14386,6 +14560,10 @@ function toAsyncIterator(input) {
14386
14560
  }
14387
14561
 
14388
14562
  // src/client/client.ts
14563
+ function onConflictName(onConflict) {
14564
+ return String(onConflict).toUpperCase();
14565
+ }
14566
+
14389
14567
  class VgiClient {
14390
14568
  rpc;
14391
14569
  defaultAttachOpaqueData;
@@ -14841,7 +15019,7 @@ class VgiClient {
14841
15019
  }
14842
15020
  await this.rpc.call("catalog_create", {
14843
15021
  name,
14844
- on_conflict: onConflict,
15022
+ on_conflict: onConflictName(onConflict),
14845
15023
  options: wireOptions
14846
15024
  });
14847
15025
  }
@@ -14909,7 +15087,7 @@ class VgiClient {
14909
15087
  await this.rpc.call("catalog_schema_create", {
14910
15088
  attach_opaque_data: attachOpaqueData,
14911
15089
  path: normalizeSchemaPath(path),
14912
- on_conflict: opts?.onConflict ?? "error",
15090
+ on_conflict: onConflictName(opts?.onConflict ?? "error"),
14913
15091
  comment: opts?.comment ?? null,
14914
15092
  tags: tagsMap,
14915
15093
  transaction_opaque_data: opts?.transactionOpaqueData ?? null
@@ -14988,7 +15166,7 @@ class VgiClient {
14988
15166
  schema_path: normalizeSchemaPath(schemaPath),
14989
15167
  name,
14990
15168
  columns,
14991
- on_conflict: onConflict,
15169
+ on_conflict: onConflictName(onConflict),
14992
15170
  not_null_constraints: notNullConstraints ?? null,
14993
15171
  unique_constraints: uniqueConstraints ?? null,
14994
15172
  check_constraints: checkConstraints ?? null,
@@ -15142,7 +15320,7 @@ class VgiClient {
15142
15320
  schema_path: normalizeSchemaPath(schemaPath),
15143
15321
  name,
15144
15322
  definition,
15145
- on_conflict: onConflict,
15323
+ on_conflict: onConflictName(onConflict),
15146
15324
  transaction_opaque_data: transactionOpaqueData ?? null
15147
15325
  });
15148
15326
  }
@@ -15209,7 +15387,7 @@ class VgiClient {
15209
15387
  macro_type: [macroType],
15210
15388
  parameters: [parameters],
15211
15389
  definition: [definition],
15212
- on_conflict: [onConflict],
15390
+ on_conflict: [onConflictName(onConflict)],
15213
15391
  parameter_default_values: [parameterDefaultValues ?? null],
15214
15392
  arguments_schema: [argumentsSchema ?? null],
15215
15393
  transaction_opaque_data: [transactionOpaqueData ?? null]
@@ -15286,7 +15464,7 @@ function validatedHostedProtocols(hosting, primary) {
15286
15464
  }
15287
15465
  const name = p.name;
15288
15466
  if (name.startsWith(RESERVED_PREFIX)) {
15289
- throw new Error(`${owner} entry ${index} is named '${name}', which claims the reserved '${RESERVED_PREFIX}' prefix. ` + "Framework protocols are not supplied through this hook: reflection is hosted automatically, and " + "vgi_rpc.Identity.v1 is enabled by supplying resolveToken and/or mintGrant.");
15467
+ throw new Error(`${owner} entry ${index} is named '${name}', which claims the reserved '${RESERVED_PREFIX}' prefix. ` + "Framework protocols are not supplied through this hook: reflection is hosted automatically, and " + "vgi_rpc.Identity.v2 is enabled by supplying resolveToken and/or mintGrant.");
15290
15468
  }
15291
15469
  if (!/^[A-Za-z_][A-Za-z0-9_.]*$/.test(name)) {
15292
15470
  throw new Error(`${owner} entry ${index}: protocol name '${name}' is not an identifier, optionally dot-qualified ` + "(e.g. 'acme.Reports.v1').");
@@ -15336,7 +15514,7 @@ function resolveIntrospectPrincipals(explicit, env) {
15336
15514
  principals = raw.split(",").map((p) => p.trim()).filter((p) => p !== "");
15337
15515
  }
15338
15516
  if (principals.length === 0) {
15339
- throw new Error("This worker supplies resolveToken, which hosts the vgi_rpc.Identity.v1 protocol, but no " + `introspector allowlist was configured. Set ${INTROSPECT_PRINCIPALS_ENV} (comma-separated) or pass ` + `introspectPrincipals.
15517
+ throw new Error("This worker supplies resolveToken, which hosts the vgi_rpc.Identity.v2 protocol, but no " + `introspector allowlist was configured. Set ${INTROSPECT_PRINCIPALS_ENV} (comma-separated) or pass ` + `introspectPrincipals.
15340
15518
 
15341
15519
  ` + "There is no permissive default on purpose: introspection is a separate capability from " + "authentication, and allowing every authenticated caller lets any user resolve any other user's " + "credential to its owner. Remove resolveToken to leave the protocol unhosted entirely.");
15342
15520
  }
@@ -15719,6 +15897,7 @@ export {
15719
15897
  durationNanos,
15720
15898
  durationSeconds,
15721
15899
  emptyBatch,
15900
+ encodeAttachTicket,
15722
15901
  encodeCatalogInfo,
15723
15902
  encodeCopyFromFormatInfo,
15724
15903
  encodeFormatOptions,
@@ -15832,4 +16011,4 @@ export {
15832
16011
  utf82 as utf8
15833
16012
  };
15834
16013
 
15835
- //# debugId=4A48D657E6B1E41464756E2164756E21
16014
+ //# debugId=2C6F34EB0944BDD764756E2164756E21