@query-farm/vgi 0.37.1 → 0.39.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 +74 -0
- package/dist/catalog/composite.d.ts +23 -1
- package/dist/catalog/contents-digest.d.ts +25 -0
- package/dist/catalog/interface.d.ts +107 -2
- package/dist/catalog/read-only.d.ts +45 -1
- package/dist/client/client.d.ts +49 -2
- package/dist/client/types.d.ts +56 -1
- package/dist/client-entry.js +239 -11
- package/dist/client-entry.js.map +9 -8
- package/dist/codec/asd.d.ts +8 -0
- package/dist/functions/copy-to.d.ts +1 -1
- package/dist/generated/vgi-client.d.ts +19 -0
- package/dist/generated/vgi-protocol-schemas.d.ts +3 -0
- package/dist/generated/vgi-protocol-types.d.ts +26 -0
- package/dist/http/fetch.d.ts +2 -1
- package/dist/index.core.d.ts +6 -3
- package/dist/index.js +672 -43
- package/dist/index.js.map +21 -17
- package/dist/protocol/handlers/catalog/contents.d.ts +27 -0
- package/dist/rpc-server.d.ts +97 -0
- package/dist/serve-entry.d.ts +2 -1
- package/dist/serve-entry.js +405 -25
- package/dist/serve-entry.js.map +18 -14
- package/dist/worker-cf-entry.d.ts +3 -0
- package/dist/worker-cf-entry.js +528 -31
- package/dist/worker-cf-entry.js.map +20 -16
- package/dist/worker.d.ts +9 -1
- package/package.json +3 -3
- package/src/catalog/composite.ts +81 -0
- package/src/catalog/contents-digest.ts +78 -0
- package/src/catalog/interface.ts +167 -5
- package/src/catalog/read-only.ts +68 -6
- package/src/client/client.ts +201 -0
- package/src/client/types.ts +58 -1
- package/src/codec/asd.ts +108 -9
- package/src/functions/copy-to.ts +1 -1
- package/src/generated/vgi-client.ts +22 -1
- package/src/generated/vgi-protocol-schemas.ts +30 -1
- package/src/generated/vgi-protocol-types.ts +126 -0
- package/src/http/fetch.ts +10 -2
- package/src/index.core.ts +23 -2
- package/src/protocol/dispatch.ts +1 -1
- package/src/protocol/handlers/catalog/admin.ts +35 -26
- package/src/protocol/handlers/catalog/contents.ts +162 -0
- package/src/protocol/handlers/catalog/macro.ts +2 -1
- package/src/protocol/handlers/catalog/shared.ts +12 -1
- package/src/rpc-server.ts +273 -0
- package/src/serve-entry.ts +7 -1
- package/src/worker-cf-entry.ts +8 -0
- package/src/worker.ts +24 -6
package/dist/index.js
CHANGED
|
@@ -7035,7 +7035,84 @@ function schemaPathDisplay(path) {
|
|
|
7035
7035
|
// src/codec/asd.ts
|
|
7036
7036
|
init_arrow();
|
|
7037
7037
|
function encodeASD(schema, obj) {
|
|
7038
|
-
return serializeBatch(batchFromRows([obj], schema));
|
|
7038
|
+
return serializeBatch(batchFromRows([sortMapsForSchema(schema, obj)], schema));
|
|
7039
|
+
}
|
|
7040
|
+
function compareCodePoints(a, b) {
|
|
7041
|
+
const n = Math.min(a.length, b.length);
|
|
7042
|
+
for (let i = 0;i < n; i++) {
|
|
7043
|
+
const x = a.charCodeAt(i);
|
|
7044
|
+
const y = b.charCodeAt(i);
|
|
7045
|
+
if (x === y)
|
|
7046
|
+
continue;
|
|
7047
|
+
const xs = x >= 55296 && x <= 57343;
|
|
7048
|
+
const ys = y >= 55296 && y <= 57343;
|
|
7049
|
+
if (xs !== ys)
|
|
7050
|
+
return xs ? 1 : -1;
|
|
7051
|
+
return x - y;
|
|
7052
|
+
}
|
|
7053
|
+
return a.length - b.length;
|
|
7054
|
+
}
|
|
7055
|
+
function mapPairs(raw) {
|
|
7056
|
+
if (Array.isArray(raw))
|
|
7057
|
+
return raw.map((e) => Array.isArray(e) ? [e[0], e[1]] : [e?.key, e?.value]);
|
|
7058
|
+
if (raw instanceof Map)
|
|
7059
|
+
return Array.from(raw.entries());
|
|
7060
|
+
if (typeof raw[Symbol.iterator] === "function")
|
|
7061
|
+
return Array.from(raw);
|
|
7062
|
+
return Object.entries(raw);
|
|
7063
|
+
}
|
|
7064
|
+
function compareKeys(a, b) {
|
|
7065
|
+
if (typeof a === "string" && typeof b === "string")
|
|
7066
|
+
return compareCodePoints(a, b);
|
|
7067
|
+
if ((typeof a === "number" || typeof a === "bigint") && (typeof b === "number" || typeof b === "bigint")) {
|
|
7068
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
7069
|
+
}
|
|
7070
|
+
return compareCodePoints(String(a), String(b));
|
|
7071
|
+
}
|
|
7072
|
+
var HAS_MAP = new WeakMap;
|
|
7073
|
+
function typeHasMap(type) {
|
|
7074
|
+
const cached = HAS_MAP.get(type);
|
|
7075
|
+
if (cached !== undefined)
|
|
7076
|
+
return cached;
|
|
7077
|
+
let has = isMap(type);
|
|
7078
|
+
if (!has && (isList(type) || isStruct(type))) {
|
|
7079
|
+
has = type.children.some((c) => typeHasMap(c.type));
|
|
7080
|
+
}
|
|
7081
|
+
HAS_MAP.set(type, has);
|
|
7082
|
+
return has;
|
|
7083
|
+
}
|
|
7084
|
+
function sortMapsForType(type, value) {
|
|
7085
|
+
if (value == null || !typeHasMap(type))
|
|
7086
|
+
return value;
|
|
7087
|
+
if (isMap(type)) {
|
|
7088
|
+
const entries = type.children[0].type;
|
|
7089
|
+
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]));
|
|
7091
|
+
}
|
|
7092
|
+
if (isList(type)) {
|
|
7093
|
+
const child = type.children[0].type;
|
|
7094
|
+
return Array.from(value, (v) => sortMapsForType(child, v));
|
|
7095
|
+
}
|
|
7096
|
+
if (isStruct(type)) {
|
|
7097
|
+
const out = { ...value };
|
|
7098
|
+
for (const cf of type.children)
|
|
7099
|
+
out[cf.name] = sortMapsForType(cf.type, value[cf.name]);
|
|
7100
|
+
return out;
|
|
7101
|
+
}
|
|
7102
|
+
return value;
|
|
7103
|
+
}
|
|
7104
|
+
function sortMapsForSchema(schema, obj) {
|
|
7105
|
+
let out = null;
|
|
7106
|
+
for (const f of schema.fields) {
|
|
7107
|
+
if (!typeHasMap(f.type))
|
|
7108
|
+
continue;
|
|
7109
|
+
const v = obj[f.name];
|
|
7110
|
+
if (v == null)
|
|
7111
|
+
continue;
|
|
7112
|
+
out ??= { ...obj };
|
|
7113
|
+
out[f.name] = sortMapsForType(f.type, v);
|
|
7114
|
+
}
|
|
7115
|
+
return out ?? obj;
|
|
7039
7116
|
}
|
|
7040
7117
|
function decodeASD(schema, bytes) {
|
|
7041
7118
|
const batch = deserializeBatch(bytes);
|
|
@@ -7062,21 +7139,23 @@ function normalizeValue(raw, type) {
|
|
|
7062
7139
|
return out;
|
|
7063
7140
|
}
|
|
7064
7141
|
if (isMap(type)) {
|
|
7142
|
+
const entries = type.children[0].type;
|
|
7143
|
+
const valueType = entries.children[1].type;
|
|
7065
7144
|
const out = {};
|
|
7145
|
+
const put = (k, v) => {
|
|
7146
|
+
out[String(k)] = normalizeValue(v, valueType);
|
|
7147
|
+
};
|
|
7066
7148
|
if (raw[Symbol.iterator]) {
|
|
7067
7149
|
for (const entry of raw) {
|
|
7068
7150
|
if (Array.isArray(entry)) {
|
|
7069
|
-
|
|
7151
|
+
put(entry[0], entry[1]);
|
|
7070
7152
|
} else if (entry && typeof entry === "object") {
|
|
7071
|
-
|
|
7072
|
-
const v = entry.value ?? entry[1];
|
|
7073
|
-
out[String(k)] = v == null ? "" : String(v);
|
|
7153
|
+
put(entry.key ?? entry[0], entry.value ?? entry[1]);
|
|
7074
7154
|
}
|
|
7075
7155
|
}
|
|
7076
7156
|
} else if (typeof raw === "object") {
|
|
7077
|
-
for (const [k, v] of Object.entries(raw))
|
|
7078
|
-
|
|
7079
|
-
}
|
|
7157
|
+
for (const [k, v] of Object.entries(raw))
|
|
7158
|
+
put(k, v);
|
|
7080
7159
|
}
|
|
7081
7160
|
return out;
|
|
7082
7161
|
}
|
|
@@ -7292,6 +7371,18 @@ var ForeignKeyInfoSchema = schema2([
|
|
|
7292
7371
|
field2("referenced_table", utf82(), false),
|
|
7293
7372
|
field2("referenced_schema_path", list2(field2("item", utf82(), true)), false)
|
|
7294
7373
|
]);
|
|
7374
|
+
var SchemaContentsSchema = schema2([
|
|
7375
|
+
field2("path", list2(field2("item", utf82(), true)), false),
|
|
7376
|
+
field2("schema", binary2(), false),
|
|
7377
|
+
field2("tables", list2(field2("item", binary2(), true)), false),
|
|
7378
|
+
field2("views", list2(field2("item", binary2(), true)), false),
|
|
7379
|
+
field2("scalar_functions", list2(field2("item", binary2(), true)), false),
|
|
7380
|
+
field2("aggregate_functions", list2(field2("item", binary2(), true)), false),
|
|
7381
|
+
field2("table_functions", list2(field2("item", binary2(), true)), false),
|
|
7382
|
+
field2("scalar_macros", list2(field2("item", binary2(), true)), false),
|
|
7383
|
+
field2("table_macros", list2(field2("item", binary2(), true)), false),
|
|
7384
|
+
field2("indexes", list2(field2("item", binary2(), true)), false)
|
|
7385
|
+
]);
|
|
7295
7386
|
var AggregateBindRequestSchema = schema2([
|
|
7296
7387
|
field2("function_name", utf82(), false),
|
|
7297
7388
|
field2("arguments", binary2(), false),
|
|
@@ -7614,11 +7705,18 @@ var CatalogAttachResultSchema = schema2([
|
|
|
7614
7705
|
field2("global_functions", list2(field2("item", binary2(), true)), false),
|
|
7615
7706
|
field2("global_function_prefix", utf82(), false),
|
|
7616
7707
|
field2("resolved_data_version", utf82(), true),
|
|
7617
|
-
field2("resolved_implementation_version", utf82(), true)
|
|
7708
|
+
field2("resolved_implementation_version", utf82(), true),
|
|
7709
|
+
field2("supports_catalog_contents", bool2(), false)
|
|
7618
7710
|
]);
|
|
7619
7711
|
var CatalogCatalogsResultSchema = schema2([
|
|
7620
7712
|
field2("items", list2(field2("item", binary2(), true)), false)
|
|
7621
7713
|
]);
|
|
7714
|
+
var CatalogContentsResultSchema = schema2([
|
|
7715
|
+
field2("catalog_version", int642(), false),
|
|
7716
|
+
field2("etag", utf82(), true),
|
|
7717
|
+
field2("not_modified", bool2(), false),
|
|
7718
|
+
field2("schemas", list2(field2("item", struct2([field2("path", list2(field2("item", utf82(), true)), false), field2("schema", binary2(), false), field2("tables", list2(field2("item", binary2(), true)), false), field2("views", list2(field2("item", binary2(), true)), false), field2("scalar_functions", list2(field2("item", binary2(), true)), false), field2("aggregate_functions", list2(field2("item", binary2(), true)), false), field2("table_functions", list2(field2("item", binary2(), true)), false), field2("scalar_macros", list2(field2("item", binary2(), true)), false), field2("table_macros", list2(field2("item", binary2(), true)), false), field2("indexes", list2(field2("item", binary2(), true)), false)]), true)), false)
|
|
7719
|
+
]);
|
|
7622
7720
|
var CatalogCopyFromFormatsResultSchema = schema2([
|
|
7623
7721
|
field2("items", list2(field2("item", binary2(), true)), false)
|
|
7624
7722
|
]);
|
|
@@ -7737,6 +7835,10 @@ var CatalogAttachParamsSchema = schema2([
|
|
|
7737
7835
|
field2("request", binary2(), false)
|
|
7738
7836
|
]);
|
|
7739
7837
|
var CatalogCatalogsParamsSchema = schema2([]);
|
|
7838
|
+
var CatalogContentsParamsSchema = schema2([
|
|
7839
|
+
field2("attach_opaque_data", binary2(), false),
|
|
7840
|
+
field2("if_none_match", utf82(), true)
|
|
7841
|
+
]);
|
|
7740
7842
|
var CatalogCopyFromFormatsParamsSchema = schema2([
|
|
7741
7843
|
field2("attach_opaque_data", binary2(), false),
|
|
7742
7844
|
field2("transaction_opaque_data", binary2(), true)
|
|
@@ -8067,12 +8169,59 @@ var TableFunctionStatisticsParamsSchema = schema2([
|
|
|
8067
8169
|
field2("request", binary2(), false)
|
|
8068
8170
|
]);
|
|
8069
8171
|
|
|
8172
|
+
// src/generated/vgi-protocol-types.ts
|
|
8173
|
+
function buildCatalogAttachResult(init) {
|
|
8174
|
+
return {
|
|
8175
|
+
attach_opaque_data: init.attach_opaque_data,
|
|
8176
|
+
supports_transactions: init.supports_transactions,
|
|
8177
|
+
supports_time_travel: init.supports_time_travel,
|
|
8178
|
+
catalog_version_frozen: init.catalog_version_frozen,
|
|
8179
|
+
catalog_version: init.catalog_version,
|
|
8180
|
+
attach_opaque_data_required: init.attach_opaque_data_required ?? true,
|
|
8181
|
+
default_schema: init.default_schema ?? "main",
|
|
8182
|
+
settings: init.settings ?? [],
|
|
8183
|
+
secret_types: init.secret_types ?? [],
|
|
8184
|
+
attach_catalogs: init.attach_catalogs ?? [],
|
|
8185
|
+
comment: init.comment ?? null,
|
|
8186
|
+
tags: init.tags ?? {},
|
|
8187
|
+
supports_column_statistics: init.supports_column_statistics ?? false,
|
|
8188
|
+
global_functions: init.global_functions ?? [],
|
|
8189
|
+
global_function_prefix: init.global_function_prefix ?? "",
|
|
8190
|
+
resolved_data_version: init.resolved_data_version ?? null,
|
|
8191
|
+
resolved_implementation_version: init.resolved_implementation_version ?? null,
|
|
8192
|
+
supports_catalog_contents: init.supports_catalog_contents ?? false
|
|
8193
|
+
};
|
|
8194
|
+
}
|
|
8195
|
+
function buildSchemaContents(init) {
|
|
8196
|
+
return {
|
|
8197
|
+
path: init.path,
|
|
8198
|
+
schema: init.schema,
|
|
8199
|
+
tables: init.tables ?? [],
|
|
8200
|
+
views: init.views ?? [],
|
|
8201
|
+
scalar_functions: init.scalar_functions ?? [],
|
|
8202
|
+
aggregate_functions: init.aggregate_functions ?? [],
|
|
8203
|
+
table_functions: init.table_functions ?? [],
|
|
8204
|
+
scalar_macros: init.scalar_macros ?? [],
|
|
8205
|
+
table_macros: init.table_macros ?? [],
|
|
8206
|
+
indexes: init.indexes ?? []
|
|
8207
|
+
};
|
|
8208
|
+
}
|
|
8209
|
+
function buildCatalogContentsResponse(init) {
|
|
8210
|
+
return {
|
|
8211
|
+
catalog_version: init.catalog_version,
|
|
8212
|
+
etag: init.etag ?? null,
|
|
8213
|
+
not_modified: init.not_modified ?? false,
|
|
8214
|
+
schemas: init.schemas ?? []
|
|
8215
|
+
};
|
|
8216
|
+
}
|
|
8217
|
+
var decodeCatalogContentsResponse = (b) => decodeASD(CatalogContentsResultSchema, b);
|
|
8070
8218
|
// src/generated/vgi-client.ts
|
|
8071
8219
|
var encodeCatalogInfo = (v) => encodeASD(CatalogInfoSchema, v);
|
|
8072
8220
|
var decodeCatalogInfo = (b) => decodeASD(CatalogInfoSchema, b);
|
|
8073
8221
|
var encodeFunctionInfo = (v) => encodeASD(FunctionInfoSchema, v);
|
|
8074
8222
|
var decodeFunctionInfo = (b) => decodeASD(FunctionInfoSchema, b);
|
|
8075
8223
|
var encodeIndexInfo = (v) => encodeASD(IndexInfoSchema, v);
|
|
8224
|
+
var decodeIndexInfo = (b) => decodeASD(IndexInfoSchema, b);
|
|
8076
8225
|
var encodeMacroInfo = (v) => encodeASD(MacroInfoSchema, v);
|
|
8077
8226
|
var decodeMacroInfo = (b) => decodeASD(MacroInfoSchema, b);
|
|
8078
8227
|
var encodeSchemaInfo = (v) => encodeASD(SchemaInfoSchema, v);
|
|
@@ -8215,6 +8364,9 @@ function isPromise(v) {
|
|
|
8215
8364
|
}
|
|
8216
8365
|
|
|
8217
8366
|
class CatalogInterface {
|
|
8367
|
+
catalogContentsEtag = null;
|
|
8368
|
+
catalogContentsAttachIndependent = false;
|
|
8369
|
+
catalogVersionFrozen = false;
|
|
8218
8370
|
catalogNameForAttach(_attachOpaqueData) {
|
|
8219
8371
|
const names = this.catalogs();
|
|
8220
8372
|
return names.length === 1 ? names[0] : null;
|
|
@@ -8332,6 +8484,42 @@ class CatalogInterface {
|
|
|
8332
8484
|
copyFromFormats(attachOpaqueData, transactionOpaqueData) {
|
|
8333
8485
|
return [];
|
|
8334
8486
|
}
|
|
8487
|
+
async catalogContents(attachOpaqueData, _ifNoneMatch) {
|
|
8488
|
+
const schemas = await this.schemas(attachOpaqueData, undefined);
|
|
8489
|
+
const contents = await Promise.all(schemas.map(async (schema) => {
|
|
8490
|
+
const counts = schema.estimated_object_count ?? {};
|
|
8491
|
+
const path = schema.path;
|
|
8492
|
+
const kind = async (countKey, list) => (counts[countKey] ?? 1) === 0 ? [] : [...await list()];
|
|
8493
|
+
const [tables, views, scalarFunctions, aggregateFunctions, tableFunctions, scalarMacros, tableMacros, indexes] = await Promise.all([
|
|
8494
|
+
kind("table", () => this.schemaContentsTables(attachOpaqueData, path)),
|
|
8495
|
+
kind("view", () => this.schemaContentsViews(attachOpaqueData, path)),
|
|
8496
|
+
kind("scalar_function", () => this.schemaContentsFunctions(attachOpaqueData, path, "scalar_function")),
|
|
8497
|
+
kind("aggregate_function", () => this.schemaContentsFunctions(attachOpaqueData, path, "aggregate_function")),
|
|
8498
|
+
kind("table_function", () => this.schemaContentsFunctions(attachOpaqueData, path, "table_function")),
|
|
8499
|
+
kind("macro", () => this.schemaContentsMacros(attachOpaqueData, path, "scalar_macro")),
|
|
8500
|
+
kind("macro", () => this.schemaContentsMacros(attachOpaqueData, path, "table_macro")),
|
|
8501
|
+
kind("index", () => this.schemaContentsIndexes(attachOpaqueData, path))
|
|
8502
|
+
]);
|
|
8503
|
+
return {
|
|
8504
|
+
schema,
|
|
8505
|
+
tables,
|
|
8506
|
+
views,
|
|
8507
|
+
scalar_functions: scalarFunctions,
|
|
8508
|
+
aggregate_functions: aggregateFunctions,
|
|
8509
|
+
table_functions: tableFunctions,
|
|
8510
|
+
scalar_macros: scalarMacros,
|
|
8511
|
+
table_macros: tableMacros,
|
|
8512
|
+
indexes
|
|
8513
|
+
};
|
|
8514
|
+
}));
|
|
8515
|
+
return { schemas: contents };
|
|
8516
|
+
}
|
|
8517
|
+
catalogContentsCacheable() {
|
|
8518
|
+
return this.catalogContentsAttachIndependent && this.catalogVersionFrozen;
|
|
8519
|
+
}
|
|
8520
|
+
catalogContentsOwner(_attachOpaqueData) {
|
|
8521
|
+
return this;
|
|
8522
|
+
}
|
|
8335
8523
|
transactionBegin(attachOpaqueData) {
|
|
8336
8524
|
return null;
|
|
8337
8525
|
}
|
|
@@ -8594,17 +8782,25 @@ function encodeFunctionInfoOnce(info) {
|
|
|
8594
8782
|
}
|
|
8595
8783
|
|
|
8596
8784
|
// src/catalog/read-only.ts
|
|
8785
|
+
var READ_ONLY_ITEM_ATTACH_ID = new TextEncoder().encode("readonly-catalog-");
|
|
8786
|
+
|
|
8597
8787
|
class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
8788
|
+
supportsCatalogContents = true;
|
|
8789
|
+
catalogVersionFrozen = true;
|
|
8790
|
+
perAttachItemIds = false;
|
|
8791
|
+
catalogContentsAttachIndependent = true;
|
|
8598
8792
|
_descriptor;
|
|
8599
8793
|
_registry;
|
|
8600
8794
|
_attachments = new Map;
|
|
8601
8795
|
_version = 1;
|
|
8602
8796
|
_functionListings = new Map;
|
|
8603
8797
|
_functionInfos = new Map;
|
|
8604
|
-
constructor(descriptor, registry) {
|
|
8798
|
+
constructor(descriptor, registry, options = {}) {
|
|
8605
8799
|
super();
|
|
8606
8800
|
this._descriptor = descriptor;
|
|
8607
8801
|
this._registry = registry;
|
|
8802
|
+
if (options.perAttachItemIds)
|
|
8803
|
+
this.perAttachItemIds = true;
|
|
8608
8804
|
for (const sch of descriptor.schemas ?? []) {
|
|
8609
8805
|
for (const fn of sch.functions ?? [])
|
|
8610
8806
|
registry.registerInSchema(fn, schemaDescriptorPath(sch), descriptor.name);
|
|
@@ -8652,7 +8848,7 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8652
8848
|
const secretTypes = (this._descriptor.secretTypes ?? []).map((s) => serializeSecretType(s));
|
|
8653
8849
|
const attachCatalogs = (this._descriptor.attachCatalogs ?? []).map((c) => encodeAttachCatalogInfo(c));
|
|
8654
8850
|
const hasTimeTravel = this._descriptor.schemas.some((s) => s.tables?.some((t) => t.supportsTimeTravel) ?? false);
|
|
8655
|
-
return {
|
|
8851
|
+
return buildCatalogAttachResult({
|
|
8656
8852
|
attach_opaque_data: attachOpaqueData,
|
|
8657
8853
|
supports_transactions: false,
|
|
8658
8854
|
supports_time_travel: hasTimeTravel,
|
|
@@ -8669,8 +8865,9 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8669
8865
|
global_functions: this._globalFunctionInfos().map(encodeFunctionInfoOnce),
|
|
8670
8866
|
global_function_prefix: this._descriptor.globalFunctionPrefix ?? "",
|
|
8671
8867
|
resolved_data_version: null,
|
|
8672
|
-
resolved_implementation_version: null
|
|
8673
|
-
|
|
8868
|
+
resolved_implementation_version: null,
|
|
8869
|
+
supports_catalog_contents: this.supportsCatalogContents
|
|
8870
|
+
});
|
|
8674
8871
|
}
|
|
8675
8872
|
detach(attachOpaqueData) {
|
|
8676
8873
|
for (const [name, id] of this._attachments) {
|
|
@@ -8683,9 +8880,15 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8683
8880
|
version(attachOpaqueData, transactionOpaqueData) {
|
|
8684
8881
|
return this._version;
|
|
8685
8882
|
}
|
|
8883
|
+
itemAttachId(attachOpaqueData) {
|
|
8884
|
+
return this.perAttachItemIds ? attachOpaqueData : READ_ONLY_ITEM_ATTACH_ID;
|
|
8885
|
+
}
|
|
8886
|
+
catalogContentsCacheable() {
|
|
8887
|
+
return super.catalogContentsCacheable() && !this.perAttachItemIds;
|
|
8888
|
+
}
|
|
8686
8889
|
schemas(attachOpaqueData, transactionOpaqueData) {
|
|
8687
8890
|
return this._descriptor.schemas.map((s) => ({
|
|
8688
|
-
attach_opaque_data: attachOpaqueData,
|
|
8891
|
+
attach_opaque_data: this.itemAttachId(attachOpaqueData),
|
|
8689
8892
|
path: schemaDescriptorPath(s),
|
|
8690
8893
|
comment: s.comment ?? null,
|
|
8691
8894
|
tags: s.tags ?? {},
|
|
@@ -8717,7 +8920,7 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8717
8920
|
if (!desc)
|
|
8718
8921
|
return null;
|
|
8719
8922
|
return {
|
|
8720
|
-
attach_opaque_data: attachOpaqueData,
|
|
8923
|
+
attach_opaque_data: this.itemAttachId(attachOpaqueData),
|
|
8721
8924
|
path: schemaDescriptorPath(desc),
|
|
8722
8925
|
comment: desc.comment ?? null,
|
|
8723
8926
|
tags: desc.tags ?? {},
|
|
@@ -8743,7 +8946,7 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8743
8946
|
input_schema: null,
|
|
8744
8947
|
settings: null,
|
|
8745
8948
|
secrets: null,
|
|
8746
|
-
attach_opaque_data: attachOpaqueData,
|
|
8949
|
+
attach_opaque_data: this.itemAttachId(attachOpaqueData),
|
|
8747
8950
|
transaction_opaque_data: null,
|
|
8748
8951
|
resolved_secrets_provided: false
|
|
8749
8952
|
};
|
|
@@ -9417,6 +9620,72 @@ class CompositeCatalogInterface extends CatalogInterface {
|
|
|
9417
9620
|
async macroGet(attachOpaqueData, schemaPath, name, transactionOpaqueData) {
|
|
9418
9621
|
return await this._route(attachOpaqueData).macroGet(attachOpaqueData, schemaPath, name, transactionOpaqueData);
|
|
9419
9622
|
}
|
|
9623
|
+
async schemaCreate(...args) {
|
|
9624
|
+
await this._route(args[0]).schemaCreate(...args);
|
|
9625
|
+
}
|
|
9626
|
+
async schemaDrop(...args) {
|
|
9627
|
+
await this._route(args[0]).schemaDrop(...args);
|
|
9628
|
+
}
|
|
9629
|
+
async tableCreate(...args) {
|
|
9630
|
+
await this._route(args[0]).tableCreate(...args);
|
|
9631
|
+
}
|
|
9632
|
+
async tableDrop(...args) {
|
|
9633
|
+
await this._route(args[0]).tableDrop(...args);
|
|
9634
|
+
}
|
|
9635
|
+
async tableCommentSet(...args) {
|
|
9636
|
+
await this._route(args[0]).tableCommentSet(...args);
|
|
9637
|
+
}
|
|
9638
|
+
async tableRename(...args) {
|
|
9639
|
+
await this._route(args[0]).tableRename(...args);
|
|
9640
|
+
}
|
|
9641
|
+
async tableColumnAdd(...args) {
|
|
9642
|
+
await this._route(args[0]).tableColumnAdd(...args);
|
|
9643
|
+
}
|
|
9644
|
+
async tableColumnDrop(...args) {
|
|
9645
|
+
await this._route(args[0]).tableColumnDrop(...args);
|
|
9646
|
+
}
|
|
9647
|
+
async tableColumnRename(...args) {
|
|
9648
|
+
await this._route(args[0]).tableColumnRename(...args);
|
|
9649
|
+
}
|
|
9650
|
+
async tableColumnDefaultSet(...args) {
|
|
9651
|
+
await this._route(args[0]).tableColumnDefaultSet(...args);
|
|
9652
|
+
}
|
|
9653
|
+
async tableColumnDefaultDrop(...args) {
|
|
9654
|
+
await this._route(args[0]).tableColumnDefaultDrop(...args);
|
|
9655
|
+
}
|
|
9656
|
+
async tableColumnTypeChange(...args) {
|
|
9657
|
+
await this._route(args[0]).tableColumnTypeChange(...args);
|
|
9658
|
+
}
|
|
9659
|
+
async tableNotNullSet(...args) {
|
|
9660
|
+
await this._route(args[0]).tableNotNullSet(...args);
|
|
9661
|
+
}
|
|
9662
|
+
async tableNotNullDrop(...args) {
|
|
9663
|
+
await this._route(args[0]).tableNotNullDrop(...args);
|
|
9664
|
+
}
|
|
9665
|
+
async viewCreate(...args) {
|
|
9666
|
+
await this._route(args[0]).viewCreate(...args);
|
|
9667
|
+
}
|
|
9668
|
+
async viewDrop(...args) {
|
|
9669
|
+
await this._route(args[0]).viewDrop(...args);
|
|
9670
|
+
}
|
|
9671
|
+
async viewRename(...args) {
|
|
9672
|
+
await this._route(args[0]).viewRename(...args);
|
|
9673
|
+
}
|
|
9674
|
+
async viewCommentSet(...args) {
|
|
9675
|
+
await this._route(args[0]).viewCommentSet(...args);
|
|
9676
|
+
}
|
|
9677
|
+
async macroCreate(...args) {
|
|
9678
|
+
await this._route(args[0]).macroCreate(...args);
|
|
9679
|
+
}
|
|
9680
|
+
async macroDrop(...args) {
|
|
9681
|
+
await this._route(args[0]).macroDrop(...args);
|
|
9682
|
+
}
|
|
9683
|
+
async catalogContents(attachOpaqueData, ifNoneMatch) {
|
|
9684
|
+
return await this._route(attachOpaqueData).catalogContents(attachOpaqueData, ifNoneMatch);
|
|
9685
|
+
}
|
|
9686
|
+
catalogContentsOwner(attachOpaqueData) {
|
|
9687
|
+
return this._route(attachOpaqueData).catalogContentsOwner(attachOpaqueData);
|
|
9688
|
+
}
|
|
9420
9689
|
async copyFromFormats(attachOpaqueData, transactionOpaqueData) {
|
|
9421
9690
|
return await this._route(attachOpaqueData).copyFromFormats(attachOpaqueData, transactionOpaqueData);
|
|
9422
9691
|
}
|
|
@@ -10819,6 +11088,9 @@ function catalogUnary(protocol, signingKey, name, config) {
|
|
|
10819
11088
|
result: config.result,
|
|
10820
11089
|
doc: config.doc,
|
|
10821
11090
|
handler: async (params, ctx) => {
|
|
11091
|
+
if (params.request != null && params.attach_opaque_data === undefined && params.name === undefined) {
|
|
11092
|
+
params = unwrapRequest(params.request);
|
|
11093
|
+
}
|
|
10822
11094
|
normalizeRequestSchemaPaths(params);
|
|
10823
11095
|
await unwrapParamsOpaque(params, ctx, signingKey);
|
|
10824
11096
|
return config.handler(params, ctx);
|
|
@@ -11672,6 +11944,134 @@ function hex(buf) {
|
|
|
11672
11944
|
return Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
11673
11945
|
}
|
|
11674
11946
|
|
|
11947
|
+
// src/catalog/contents-digest.ts
|
|
11948
|
+
var KINDS = [
|
|
11949
|
+
"tables",
|
|
11950
|
+
"views",
|
|
11951
|
+
"scalar_functions",
|
|
11952
|
+
"aggregate_functions",
|
|
11953
|
+
"table_functions",
|
|
11954
|
+
"scalar_macros",
|
|
11955
|
+
"table_macros",
|
|
11956
|
+
"indexes"
|
|
11957
|
+
];
|
|
11958
|
+
async function catalogContentsDigest(schemas) {
|
|
11959
|
+
const utf8 = new TextEncoder;
|
|
11960
|
+
const parts = [];
|
|
11961
|
+
let total = 0;
|
|
11962
|
+
const count = (n) => {
|
|
11963
|
+
const b = new Uint8Array(8);
|
|
11964
|
+
new DataView(b.buffer).setBigUint64(0, BigInt(n), true);
|
|
11965
|
+
parts.push(b);
|
|
11966
|
+
total += 8;
|
|
11967
|
+
};
|
|
11968
|
+
const chunk = (data) => {
|
|
11969
|
+
count(data.byteLength);
|
|
11970
|
+
parts.push(data);
|
|
11971
|
+
total += data.byteLength;
|
|
11972
|
+
};
|
|
11973
|
+
const chunks = (values) => {
|
|
11974
|
+
count(values.length);
|
|
11975
|
+
for (const v of values)
|
|
11976
|
+
chunk(v);
|
|
11977
|
+
};
|
|
11978
|
+
count(schemas.length);
|
|
11979
|
+
for (const entry of schemas) {
|
|
11980
|
+
chunks(entry.path.map((p) => utf8.encode(p)));
|
|
11981
|
+
chunk(entry.schema);
|
|
11982
|
+
for (const kind of KINDS)
|
|
11983
|
+
chunks(entry[kind]);
|
|
11984
|
+
}
|
|
11985
|
+
const buf = new Uint8Array(total);
|
|
11986
|
+
let off = 0;
|
|
11987
|
+
for (const p of parts) {
|
|
11988
|
+
buf.set(p, off);
|
|
11989
|
+
off += p.byteLength;
|
|
11990
|
+
}
|
|
11991
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", buf));
|
|
11992
|
+
let hex = "";
|
|
11993
|
+
for (const b of digest)
|
|
11994
|
+
hex += b.toString(16).padStart(2, "0");
|
|
11995
|
+
return hex;
|
|
11996
|
+
}
|
|
11997
|
+
|
|
11998
|
+
// src/protocol/handlers/catalog/contents.ts
|
|
11999
|
+
var CACHE = new WeakMap;
|
|
12000
|
+
async function buildCatalogContents(cat, owner, attach, version, ifNoneMatch) {
|
|
12001
|
+
const result = await cat.catalogContents(attach, ifNoneMatch);
|
|
12002
|
+
const etag0 = result.etag ?? null;
|
|
12003
|
+
if (result.not_modified) {
|
|
12004
|
+
if (etag0 === null || ifNoneMatch === null || etag0 !== ifNoneMatch) {
|
|
12005
|
+
throw new Error("catalog_contents returned not_modified, but only a catalog whose etag equals " + "if_none_match may (and it must return that etag)");
|
|
12006
|
+
}
|
|
12007
|
+
if (result.schemas && result.schemas.length > 0) {
|
|
12008
|
+
throw new Error("catalog_contents returned not_modified with schemas; it must return none");
|
|
12009
|
+
}
|
|
12010
|
+
return buildCatalogContentsResponse({ catalog_version: version, etag: etag0, not_modified: true });
|
|
12011
|
+
}
|
|
12012
|
+
const infos = [...result.schemas ?? []];
|
|
12013
|
+
const keys = infos.map((c) => schemaPathKey(c.schema.path));
|
|
12014
|
+
const keySet = new Set(keys);
|
|
12015
|
+
if (keySet.size !== keys.length)
|
|
12016
|
+
throw new Error("catalog_contents returned duplicate schema paths");
|
|
12017
|
+
for (const c of infos) {
|
|
12018
|
+
if (c.schema.path.length > 1 && !keySet.has(schemaPathKey(c.schema.path.slice(0, -1)))) {
|
|
12019
|
+
throw new Error(`catalog_contents returned schema path ${JSON.stringify(c.schema.path)} without its parent`);
|
|
12020
|
+
}
|
|
12021
|
+
}
|
|
12022
|
+
const schemas = infos.sort((a, b) => a.schema.path.length - b.schema.path.length).map((c) => buildSchemaContents({
|
|
12023
|
+
path: [...c.schema.path],
|
|
12024
|
+
schema: encodeSchemaInfo(c.schema),
|
|
12025
|
+
tables: c.tables.map((t) => encodeTableInfo(t)),
|
|
12026
|
+
views: c.views.map((v) => encodeViewInfo(v)),
|
|
12027
|
+
scalar_functions: c.scalar_functions.map((f) => encodeFunctionInfoOnce(f)),
|
|
12028
|
+
aggregate_functions: c.aggregate_functions.map((f) => encodeFunctionInfoOnce(f)),
|
|
12029
|
+
table_functions: c.table_functions.map((f) => encodeFunctionInfoOnce(f)),
|
|
12030
|
+
scalar_macros: c.scalar_macros.map((m) => encodeMacroInfo(m)),
|
|
12031
|
+
table_macros: c.table_macros.map((m) => encodeMacroInfo(m)),
|
|
12032
|
+
indexes: c.indexes.map((i) => encodeIndexInfo(i))
|
|
12033
|
+
}));
|
|
12034
|
+
let etag = etag0;
|
|
12035
|
+
if (etag === null && owner.catalogContentsEtag === "content-hash") {
|
|
12036
|
+
etag = await catalogContentsDigest(schemas);
|
|
12037
|
+
}
|
|
12038
|
+
if (etag !== null && ifNoneMatch !== null && etag === ifNoneMatch) {
|
|
12039
|
+
return buildCatalogContentsResponse({ catalog_version: version, etag, not_modified: true });
|
|
12040
|
+
}
|
|
12041
|
+
return buildCatalogContentsResponse({ catalog_version: version, etag, schemas });
|
|
12042
|
+
}
|
|
12043
|
+
async function serveCatalogContents(cat, attach, ifNoneMatch) {
|
|
12044
|
+
const owner = cat.catalogContentsOwner(attach);
|
|
12045
|
+
const version = Number(await cat.version(attach));
|
|
12046
|
+
if (owner.catalogContentsCacheable()) {
|
|
12047
|
+
let pending = CACHE.get(owner);
|
|
12048
|
+
let snapshot = pending ? await pending.catch(() => null) : null;
|
|
12049
|
+
if (!snapshot || snapshot.version !== version) {
|
|
12050
|
+
pending = (async () => {
|
|
12051
|
+
const built = await buildCatalogContents(cat, owner, attach, version, null);
|
|
12052
|
+
return {
|
|
12053
|
+
version,
|
|
12054
|
+
etag: built.etag ?? null,
|
|
12055
|
+
wire: wrapResult(built, CatalogContentsResultSchema)
|
|
12056
|
+
};
|
|
12057
|
+
})();
|
|
12058
|
+
CACHE.set(owner, pending);
|
|
12059
|
+
try {
|
|
12060
|
+
snapshot = await pending;
|
|
12061
|
+
} catch (err) {
|
|
12062
|
+
if (CACHE.get(owner) === pending)
|
|
12063
|
+
CACHE.delete(owner);
|
|
12064
|
+
throw err;
|
|
12065
|
+
}
|
|
12066
|
+
}
|
|
12067
|
+
if (ifNoneMatch !== null && snapshot.etag !== null && ifNoneMatch === snapshot.etag) {
|
|
12068
|
+
return wrapResult(buildCatalogContentsResponse({ catalog_version: version, etag: snapshot.etag, not_modified: true }), CatalogContentsResultSchema);
|
|
12069
|
+
}
|
|
12070
|
+
return snapshot.wire;
|
|
12071
|
+
}
|
|
12072
|
+
return wrapResult(await buildCatalogContents(cat, owner, attach, version, ifNoneMatch), CatalogContentsResultSchema);
|
|
12073
|
+
}
|
|
12074
|
+
|
|
11675
12075
|
// src/protocol/handlers/catalog/admin.ts
|
|
11676
12076
|
function registerCatalogAdminMethods(protocol, getCatalog, signingKey) {
|
|
11677
12077
|
catalogUnary(protocol, signingKey, "catalog_catalogs", {
|
|
@@ -11699,25 +12099,11 @@ function registerCatalogAdminMethods(protocol, getCatalog, signingKey) {
|
|
|
11699
12099
|
const optionsDict = decodeOptionsBatch(innerParams.options);
|
|
11700
12100
|
const result = await cat.attach(innerParams.name, optionsDict, innerParams.data_version_spec ?? null, innerParams.implementation_version ?? null);
|
|
11701
12101
|
const sealedAttach = await sealAttach(toUint8Array(result.attach_opaque_data), ctx?.auth, signingKey);
|
|
11702
|
-
return wrapResult({
|
|
12102
|
+
return wrapResult(buildCatalogAttachResult({
|
|
12103
|
+
...result,
|
|
11703
12104
|
attach_opaque_data: sealedAttach,
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
catalog_version_frozen: result.catalog_version_frozen,
|
|
11707
|
-
catalog_version: result.catalog_version,
|
|
11708
|
-
attach_opaque_data_required: result.attach_opaque_data_required ?? true,
|
|
11709
|
-
default_schema: result.default_schema ?? "main",
|
|
11710
|
-
settings: result.settings ?? [],
|
|
11711
|
-
secret_types: result.secret_types ?? [],
|
|
11712
|
-
attach_catalogs: result.attach_catalogs ?? [],
|
|
11713
|
-
comment: result.comment ?? null,
|
|
11714
|
-
tags: result.tags ?? {},
|
|
11715
|
-
supports_column_statistics: result.supports_column_statistics ?? true,
|
|
11716
|
-
global_functions: result.global_functions ?? [],
|
|
11717
|
-
global_function_prefix: result.global_function_prefix ?? "",
|
|
11718
|
-
resolved_data_version: result.resolved_data_version ?? null,
|
|
11719
|
-
resolved_implementation_version: result.resolved_implementation_version ?? null
|
|
11720
|
-
}, CatalogAttachResultSchema);
|
|
12105
|
+
supports_column_statistics: result.supports_column_statistics ?? true
|
|
12106
|
+
}), CatalogAttachResultSchema);
|
|
11721
12107
|
}
|
|
11722
12108
|
});
|
|
11723
12109
|
catalogUnary(protocol, signingKey, "catalog_detach", {
|
|
@@ -11798,6 +12184,14 @@ function registerCatalogAdminMethods(protocol, getCatalog, signingKey) {
|
|
|
11798
12184
|
}, CatalogSchemasResultSchema);
|
|
11799
12185
|
}
|
|
11800
12186
|
});
|
|
12187
|
+
catalogUnary(protocol, signingKey, "catalog_contents", {
|
|
12188
|
+
params: CatalogContentsParamsSchema,
|
|
12189
|
+
result: RESULT_BINARY_SCHEMA,
|
|
12190
|
+
handler: async (params) => {
|
|
12191
|
+
const ifNoneMatch = params.if_none_match == null ? null : String(params.if_none_match);
|
|
12192
|
+
return serveCatalogContents(getCatalog(), toUint8Array(params.attach_opaque_data), ifNoneMatch);
|
|
12193
|
+
}
|
|
12194
|
+
});
|
|
11801
12195
|
catalogUnary(protocol, signingKey, "catalog_copy_from_formats", {
|
|
11802
12196
|
params: CatalogCopyFromFormatsParamsSchema,
|
|
11803
12197
|
result: RESULT_BINARY_SCHEMA,
|
|
@@ -12092,7 +12486,7 @@ function registerCatalogMacroMethods(protocol, getCatalog, signingKey) {
|
|
|
12092
12486
|
result: emptyResultSchema,
|
|
12093
12487
|
handler: async (params) => {
|
|
12094
12488
|
const cat = getCatalog();
|
|
12095
|
-
const innerParams =
|
|
12489
|
+
const innerParams = params;
|
|
12096
12490
|
await cat.macroCreate(toUint8Array(innerParams.attach_opaque_data), innerParams.schema_path, innerParams.name, innerParams.macro_type, innerParams.parameters ? Array.isArray(innerParams.parameters) ? innerParams.parameters : [...innerParams.parameters] : [], innerParams.definition, innerParams.on_conflict, innerParams.parameter_default_values ? toUint8Array(innerParams.parameter_default_values) : null, innerParams.arguments_schema ? toUint8Array(innerParams.arguments_schema) : null, innerParams.transaction_opaque_data ? toUint8Array(innerParams.transaction_opaque_data) : undefined);
|
|
12097
12491
|
return {};
|
|
12098
12492
|
}
|
|
@@ -12158,7 +12552,7 @@ function registerCatalogMethods(protocol, catalog, _catalogName, signingKey) {
|
|
|
12158
12552
|
// src/protocol/dispatch.ts
|
|
12159
12553
|
var VGI_PROTOCOL_NAME = "vgi.v2";
|
|
12160
12554
|
function buildVgiProtocol(config) {
|
|
12161
|
-
const protocol = new Protocol(VGI_PROTOCOL_NAME, { protocolVersion: "2.
|
|
12555
|
+
const protocol = new Protocol(VGI_PROTOCOL_NAME, { protocolVersion: "2.1.0" });
|
|
12162
12556
|
registerFunctionMethods(protocol, {
|
|
12163
12557
|
registry: config.registry,
|
|
12164
12558
|
signingKey: config.signingKey,
|
|
@@ -12798,7 +13192,118 @@ class VgiClient {
|
|
|
12798
13192
|
global_functions: inner.global_functions ? (Array.isArray(inner.global_functions) ? inner.global_functions : [...inner.global_functions]).map(toUint8Array) : [],
|
|
12799
13193
|
global_function_prefix: inner.global_function_prefix ?? "",
|
|
12800
13194
|
resolved_data_version: inner.resolved_data_version ?? null,
|
|
12801
|
-
resolved_implementation_version: inner.resolved_implementation_version ?? null
|
|
13195
|
+
resolved_implementation_version: inner.resolved_implementation_version ?? null,
|
|
13196
|
+
supports_catalog_contents: inner.supports_catalog_contents ?? false
|
|
13197
|
+
};
|
|
13198
|
+
}
|
|
13199
|
+
async catalogContents(attachOpaqueData, ifNoneMatch = null) {
|
|
13200
|
+
const result = await this.rpc.call("catalog_contents", {
|
|
13201
|
+
attach_opaque_data: attachOpaqueData,
|
|
13202
|
+
if_none_match: ifNoneMatch
|
|
13203
|
+
});
|
|
13204
|
+
if (!result)
|
|
13205
|
+
throw new VgiClientError("catalog_contents returned null");
|
|
13206
|
+
const response = decodeCatalogContentsResponse(toUint8Array(result.result));
|
|
13207
|
+
const schemas = response.schemas.map((c) => {
|
|
13208
|
+
const schema = decodeSchemaInfo(c.schema);
|
|
13209
|
+
if (JSON.stringify(c.path) !== JSON.stringify(schema.path)) {
|
|
13210
|
+
throw new VgiClientError(`catalog_contents: SchemaContents.path ${JSON.stringify(c.path)} != SchemaInfo.path ${JSON.stringify(schema.path)}`);
|
|
13211
|
+
}
|
|
13212
|
+
return {
|
|
13213
|
+
schema,
|
|
13214
|
+
tables: c.tables.map(decodeTableInfo),
|
|
13215
|
+
views: c.views.map(decodeViewInfo),
|
|
13216
|
+
scalar_functions: c.scalar_functions.map(decodeFunctionInfo),
|
|
13217
|
+
aggregate_functions: c.aggregate_functions.map(decodeFunctionInfo),
|
|
13218
|
+
table_functions: c.table_functions.map(decodeFunctionInfo),
|
|
13219
|
+
scalar_macros: c.scalar_macros.map(decodeMacroInfo),
|
|
13220
|
+
table_macros: c.table_macros.map(decodeMacroInfo),
|
|
13221
|
+
indexes: c.indexes.map(decodeIndexInfo)
|
|
13222
|
+
};
|
|
13223
|
+
});
|
|
13224
|
+
return {
|
|
13225
|
+
catalog_version: Number(response.catalog_version ?? 0),
|
|
13226
|
+
etag: response.etag ?? null,
|
|
13227
|
+
not_modified: Boolean(response.not_modified),
|
|
13228
|
+
schemas
|
|
13229
|
+
};
|
|
13230
|
+
}
|
|
13231
|
+
async loadCatalog(attach, opts) {
|
|
13232
|
+
const attachOpaqueData = attach.attach_opaque_data;
|
|
13233
|
+
const previous = opts?.previous ?? null;
|
|
13234
|
+
const useContents = attach.supports_catalog_contents === true && opts?.useCatalogContents !== false && opts?.transactionOpaqueData == null;
|
|
13235
|
+
if (!useContents) {
|
|
13236
|
+
return this._loadCatalogPerSchema(attachOpaqueData, opts?.transactionOpaqueData, null);
|
|
13237
|
+
}
|
|
13238
|
+
let fallbackError = null;
|
|
13239
|
+
const ifNoneMatch = previous?.etag ?? null;
|
|
13240
|
+
const knownVersion = previous?.catalog_version ?? 0;
|
|
13241
|
+
for (let attempt = 0;attempt < 2; attempt++) {
|
|
13242
|
+
let response;
|
|
13243
|
+
try {
|
|
13244
|
+
response = await this.catalogContents(attachOpaqueData, ifNoneMatch);
|
|
13245
|
+
} catch (err) {
|
|
13246
|
+
fallbackError = err instanceof Error ? err.message : String(err);
|
|
13247
|
+
break;
|
|
13248
|
+
}
|
|
13249
|
+
if (response.not_modified) {
|
|
13250
|
+
if (previous == null || ifNoneMatch == null) {
|
|
13251
|
+
fallbackError = "catalog_contents answered not_modified to an unconditional request";
|
|
13252
|
+
break;
|
|
13253
|
+
}
|
|
13254
|
+
return {
|
|
13255
|
+
...previous,
|
|
13256
|
+
catalog_version: response.catalog_version !== 0 ? response.catalog_version : previous.catalog_version,
|
|
13257
|
+
etag: response.etag ?? ifNoneMatch,
|
|
13258
|
+
not_modified: true,
|
|
13259
|
+
fallback_error: null
|
|
13260
|
+
};
|
|
13261
|
+
}
|
|
13262
|
+
if (response.catalog_version !== 0 && knownVersion !== 0 && response.catalog_version < knownVersion) {
|
|
13263
|
+
fallbackError = `catalog_contents snapshot version ${response.catalog_version} is older than the known version ${knownVersion}`;
|
|
13264
|
+
continue;
|
|
13265
|
+
}
|
|
13266
|
+
return {
|
|
13267
|
+
catalog_version: response.catalog_version,
|
|
13268
|
+
etag: response.etag,
|
|
13269
|
+
source: "catalog_contents",
|
|
13270
|
+
not_modified: false,
|
|
13271
|
+
fallback_error: null,
|
|
13272
|
+
schemas: response.schemas
|
|
13273
|
+
};
|
|
13274
|
+
}
|
|
13275
|
+
return this._loadCatalogPerSchema(attachOpaqueData, undefined, fallbackError);
|
|
13276
|
+
}
|
|
13277
|
+
async _loadCatalogPerSchema(attachOpaqueData, transactionOpaqueData, fallbackError) {
|
|
13278
|
+
const schemas = await this.schemas(attachOpaqueData, transactionOpaqueData);
|
|
13279
|
+
const out = [];
|
|
13280
|
+
for (const schema of schemas) {
|
|
13281
|
+
const counts = schema.estimated_object_count ?? {};
|
|
13282
|
+
const path = schema.path;
|
|
13283
|
+
const has = (kind) => {
|
|
13284
|
+
const n = counts[kind];
|
|
13285
|
+
return n == null || Number(n) !== 0;
|
|
13286
|
+
};
|
|
13287
|
+
const t = transactionOpaqueData;
|
|
13288
|
+
out.push({
|
|
13289
|
+
schema,
|
|
13290
|
+
tables: has("table") ? await this.schemaContentsTables(attachOpaqueData, path, t) : [],
|
|
13291
|
+
views: has("view") ? await this.schemaContentsViews(attachOpaqueData, path, t) : [],
|
|
13292
|
+
scalar_functions: has("scalar_function") ? await this.schemaContentsFunctions(attachOpaqueData, path, "SCALAR_FUNCTION", t) : [],
|
|
13293
|
+
aggregate_functions: has("aggregate_function") ? await this.schemaContentsFunctions(attachOpaqueData, path, "AGGREGATE_FUNCTION", t) : [],
|
|
13294
|
+
table_functions: has("table_function") ? await this.schemaContentsFunctions(attachOpaqueData, path, "TABLE_FUNCTION", t) : [],
|
|
13295
|
+
scalar_macros: has("macro") ? await this.schemaContentsMacros(attachOpaqueData, path, "SCALAR_MACRO", t) : [],
|
|
13296
|
+
table_macros: has("macro") ? await this.schemaContentsMacros(attachOpaqueData, path, "TABLE_MACRO", t) : [],
|
|
13297
|
+
indexes: has("index") ? await this.schemaContentsIndexes(attachOpaqueData, path, t) : []
|
|
13298
|
+
});
|
|
13299
|
+
}
|
|
13300
|
+
return {
|
|
13301
|
+
catalog_version: null,
|
|
13302
|
+
etag: null,
|
|
13303
|
+
source: "per_schema",
|
|
13304
|
+
not_modified: false,
|
|
13305
|
+
fallback_error: fallbackError,
|
|
13306
|
+
schemas: out
|
|
12802
13307
|
};
|
|
12803
13308
|
}
|
|
12804
13309
|
async catalogDetach(attachOpaqueData) {
|
|
@@ -12939,6 +13444,17 @@ class VgiClient {
|
|
|
12939
13444
|
const inner = unwrapResult(result);
|
|
12940
13445
|
return deserializeInfoList(inner.items, decodeFunctionInfo);
|
|
12941
13446
|
}
|
|
13447
|
+
async schemaContentsIndexes(attachOpaqueData, path, transactionOpaqueData) {
|
|
13448
|
+
const result = await this.rpc.call("catalog_schema_contents_indexes", {
|
|
13449
|
+
attach_opaque_data: attachOpaqueData,
|
|
13450
|
+
path: normalizeSchemaPath(path),
|
|
13451
|
+
transaction_opaque_data: transactionOpaqueData ?? null
|
|
13452
|
+
});
|
|
13453
|
+
if (!result)
|
|
13454
|
+
return [];
|
|
13455
|
+
const inner = unwrapResult(result);
|
|
13456
|
+
return deserializeInfoList(inner.items, decodeIndexInfo);
|
|
13457
|
+
}
|
|
12942
13458
|
async tableGet(attachOpaqueData, schemaPath, name, transactionOpaqueData) {
|
|
12943
13459
|
const result = await this.rpc.call("catalog_table_get", {
|
|
12944
13460
|
attach_opaque_data: attachOpaqueData,
|
|
@@ -13203,9 +13719,103 @@ class VgiClient {
|
|
|
13203
13719
|
// src/index.core.ts
|
|
13204
13720
|
import { str, bytes, int as int3, int32 as int323, float, float32 as float323, bool as bool3, toSchema, OutputCollector, AuthContext } from "@query-farm/vgi-rpc";
|
|
13205
13721
|
import { subprocessConnect, httpConnect, tcpConnect } from "@query-farm/vgi-rpc";
|
|
13722
|
+
|
|
13723
|
+
// src/rpc-server.ts
|
|
13724
|
+
import {
|
|
13725
|
+
IdentityImpl,
|
|
13726
|
+
VgiRpcServer
|
|
13727
|
+
} from "@query-farm/vgi-rpc";
|
|
13728
|
+
var TRANSPORTS = new Set(["pipe", "unix", "tcp", "iroh", "stream", "http"]);
|
|
13729
|
+
var IDENTITY_TRANSPORTS = new Set(["http"]);
|
|
13730
|
+
var RESERVED_PREFIX = "vgi_rpc.";
|
|
13731
|
+
var INTROSPECT_PRINCIPALS_ENV = "VGI_INTROSPECT_PRINCIPALS";
|
|
13732
|
+
function buildRpcServer(primary, hosting, options) {
|
|
13733
|
+
if (!TRANSPORTS.has(options.transport)) {
|
|
13734
|
+
throw new Error(`Unknown transport ${JSON.stringify(options.transport)}; expected one of ${[...TRANSPORTS].join(", ")}.`);
|
|
13735
|
+
}
|
|
13736
|
+
const protocols = validatedHostedProtocols(hosting, primary);
|
|
13737
|
+
const identity = IDENTITY_TRANSPORTS.has(options.transport) ? buildIdentity(hosting, options.env) : undefined;
|
|
13738
|
+
return new VgiRpcServer(primary, {
|
|
13739
|
+
serverId: options.serverId,
|
|
13740
|
+
protocols,
|
|
13741
|
+
identity
|
|
13742
|
+
});
|
|
13743
|
+
}
|
|
13744
|
+
function validatedHostedProtocols(hosting, primary) {
|
|
13745
|
+
if (hosting.hostedProtocols === undefined)
|
|
13746
|
+
return [];
|
|
13747
|
+
const owner = "hostedProtocols()";
|
|
13748
|
+
if (typeof hosting.hostedProtocols !== "function") {
|
|
13749
|
+
throw new TypeError(`${owner} must be a function returning vgi-rpc Protocols, got ${typeof hosting.hostedProtocols}.`);
|
|
13750
|
+
}
|
|
13751
|
+
const raw = hosting.hostedProtocols();
|
|
13752
|
+
if (raw == null || typeof raw[Symbol.iterator] !== "function" || typeof raw === "string") {
|
|
13753
|
+
throw new TypeError(`${owner} must return an iterable of vgi-rpc Protocols, got ${String(raw)}.`);
|
|
13754
|
+
}
|
|
13755
|
+
const seen = new Set;
|
|
13756
|
+
const out = [];
|
|
13757
|
+
let index = 0;
|
|
13758
|
+
for (const proto of raw) {
|
|
13759
|
+
const p = proto;
|
|
13760
|
+
if (p == null || typeof p.name !== "string" || typeof p.getMethod !== "function") {
|
|
13761
|
+
throw new TypeError(`${owner} entry ${index} must be a vgi-rpc Protocol, got ${String(proto)}.`);
|
|
13762
|
+
}
|
|
13763
|
+
const name = p.name;
|
|
13764
|
+
if (name.startsWith(RESERVED_PREFIX)) {
|
|
13765
|
+
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.");
|
|
13766
|
+
}
|
|
13767
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.]*$/.test(name)) {
|
|
13768
|
+
throw new Error(`${owner} entry ${index}: protocol name '${name}' is not an identifier, optionally dot-qualified ` + "(e.g. 'acme.Reports.v1').");
|
|
13769
|
+
}
|
|
13770
|
+
if (name === primary.name) {
|
|
13771
|
+
throw new Error(`${owner} entry ${index} is named '${name}', the worker's own protocol. Give it a distinct name.`);
|
|
13772
|
+
}
|
|
13773
|
+
if (seen.has(name)) {
|
|
13774
|
+
throw new Error(`${owner} lists protocol name '${name}' twice. The name is the routing key, so each hosted protocol ` + "needs a distinct name.");
|
|
13775
|
+
}
|
|
13776
|
+
seen.add(name);
|
|
13777
|
+
out.push(proto);
|
|
13778
|
+
index++;
|
|
13779
|
+
}
|
|
13780
|
+
return out;
|
|
13781
|
+
}
|
|
13782
|
+
function buildIdentity(hosting, env) {
|
|
13783
|
+
const { resolveToken, mintGrant } = hosting;
|
|
13784
|
+
if (!resolveToken && !mintGrant)
|
|
13785
|
+
return;
|
|
13786
|
+
return new IdentityImpl({
|
|
13787
|
+
resolveToken,
|
|
13788
|
+
mintGrant,
|
|
13789
|
+
introspectPrincipals: resolveToken ? resolveIntrospectPrincipals(hosting.introspectPrincipals, env) : undefined,
|
|
13790
|
+
maxAuthAge: hosting.maxAuthAge
|
|
13791
|
+
});
|
|
13792
|
+
}
|
|
13793
|
+
function resolveIntrospectPrincipals(explicit, env) {
|
|
13794
|
+
let principals;
|
|
13795
|
+
if (explicit !== undefined) {
|
|
13796
|
+
principals = [...explicit].map((p) => p.trim()).filter((p) => p !== "");
|
|
13797
|
+
} else {
|
|
13798
|
+
const source = env ?? globalThis.process?.env;
|
|
13799
|
+
const raw = source?.[INTROSPECT_PRINCIPALS_ENV] ?? "";
|
|
13800
|
+
principals = raw.split(",").map((p) => p.trim()).filter((p) => p !== "");
|
|
13801
|
+
}
|
|
13802
|
+
if (principals.length === 0) {
|
|
13803
|
+
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.
|
|
13804
|
+
|
|
13805
|
+
` + "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.");
|
|
13806
|
+
}
|
|
13807
|
+
return principals;
|
|
13808
|
+
}
|
|
13809
|
+
|
|
13810
|
+
// src/index.core.ts
|
|
13811
|
+
import {
|
|
13812
|
+
AuthUnavailableError,
|
|
13813
|
+
GrantRefusedError,
|
|
13814
|
+
IdentityUnavailableError,
|
|
13815
|
+
StatusError
|
|
13816
|
+
} from "@query-farm/vgi-rpc";
|
|
13206
13817
|
// src/worker.ts
|
|
13207
13818
|
import {
|
|
13208
|
-
VgiRpcServer,
|
|
13209
13819
|
observePeerIdentity,
|
|
13210
13820
|
peerIdentityPrimary,
|
|
13211
13821
|
serveUnix,
|
|
@@ -13269,11 +13879,19 @@ function parseLauncherArgs(argv) {
|
|
|
13269
13879
|
|
|
13270
13880
|
class Worker {
|
|
13271
13881
|
_registry;
|
|
13882
|
+
_hosting;
|
|
13272
13883
|
_catalogInterface;
|
|
13273
13884
|
_catalogName;
|
|
13274
13885
|
constructor(config) {
|
|
13275
13886
|
this._registry = config.registry ?? new FunctionRegistry;
|
|
13276
13887
|
this._catalogName = config.catalogName;
|
|
13888
|
+
this._hosting = {
|
|
13889
|
+
hostedProtocols: config.hostedProtocols,
|
|
13890
|
+
resolveToken: config.resolveToken,
|
|
13891
|
+
mintGrant: config.mintGrant,
|
|
13892
|
+
introspectPrincipals: config.introspectPrincipals,
|
|
13893
|
+
maxAuthAge: config.maxAuthAge
|
|
13894
|
+
};
|
|
13277
13895
|
if (config.functions) {
|
|
13278
13896
|
for (const func of config.functions) {
|
|
13279
13897
|
this._registry.register(func);
|
|
@@ -13313,7 +13931,7 @@ class Worker {
|
|
|
13313
13931
|
const envOverride = process.env.VGI_WORKER_IDLE_TIMEOUT;
|
|
13314
13932
|
const idleTimeout = envOverride !== undefined && envOverride !== "" ? Number(envOverride) : launcher.idleTimeout;
|
|
13315
13933
|
debug(() => `[worker] AF_UNIX mode: ${launcher.unixPath} idle=${idleTimeout ?? 300}s${envOverride !== undefined && envOverride !== "" ? " (env override)" : ""}`);
|
|
13316
|
-
serveUnix(protocol, {
|
|
13934
|
+
serveUnix(this.buildServer(protocol, "unix"), {
|
|
13317
13935
|
unixPath: launcher.unixPath,
|
|
13318
13936
|
idleTimeout
|
|
13319
13937
|
}).then((handle) => handle.done).then(() => {
|
|
@@ -13330,7 +13948,7 @@ ${err.stack}
|
|
|
13330
13948
|
const envOverride = process.env.VGI_WORKER_IDLE_TIMEOUT;
|
|
13331
13949
|
const idleTimeout = envOverride !== undefined && envOverride !== "" ? Number(envOverride) : launcher.idleTimeout;
|
|
13332
13950
|
debug(() => `[worker] TCP mode: ${launcher.tcpHost}:${launcher.tcpPort} idle=${idleTimeout ?? 300}s${envOverride !== undefined && envOverride !== "" ? " (env override)" : ""}`);
|
|
13333
|
-
serveTcp(protocol, {
|
|
13951
|
+
serveTcp(this.buildServer(protocol, launcher.irohRawUpstream ? "iroh" : "tcp"), {
|
|
13334
13952
|
host: launcher.tcpHost,
|
|
13335
13953
|
port: launcher.tcpPort,
|
|
13336
13954
|
idleTimeout,
|
|
@@ -13350,7 +13968,7 @@ ${err.stack}
|
|
|
13350
13968
|
});
|
|
13351
13969
|
return;
|
|
13352
13970
|
}
|
|
13353
|
-
const server =
|
|
13971
|
+
const server = this.buildServer(protocol, "pipe");
|
|
13354
13972
|
debug(() => `[worker] server created, calling run()`);
|
|
13355
13973
|
server.run().then(() => {
|
|
13356
13974
|
debug(() => `[worker] server.run() resolved cleanly`);
|
|
@@ -13367,6 +13985,9 @@ ${err.stack}
|
|
|
13367
13985
|
process.exit(1);
|
|
13368
13986
|
}
|
|
13369
13987
|
}
|
|
13988
|
+
buildServer(protocol, transport) {
|
|
13989
|
+
return buildRpcServer(protocol, this._hosting, { transport });
|
|
13990
|
+
}
|
|
13370
13991
|
buildProtocol() {
|
|
13371
13992
|
return buildVgiProtocol({
|
|
13372
13993
|
registry: this._registry,
|
|
@@ -13375,7 +13996,7 @@ ${err.stack}
|
|
|
13375
13996
|
});
|
|
13376
13997
|
}
|
|
13377
13998
|
async serveStream(readable, writable) {
|
|
13378
|
-
await serveStreamRpc(this.buildProtocol(), { readable, writable });
|
|
13999
|
+
await serveStreamRpc(this.buildServer(this.buildProtocol(), "stream"), { readable, writable });
|
|
13379
14000
|
}
|
|
13380
14001
|
}
|
|
13381
14002
|
export {
|
|
@@ -13383,6 +14004,7 @@ export {
|
|
|
13383
14004
|
ArgumentValidationError,
|
|
13384
14005
|
Arguments,
|
|
13385
14006
|
AuthContext,
|
|
14007
|
+
AuthUnavailableError,
|
|
13386
14008
|
BindResultSchema,
|
|
13387
14009
|
BoundStorage,
|
|
13388
14010
|
CACHE_ETAG_KEY,
|
|
@@ -13420,6 +14042,9 @@ export {
|
|
|
13420
14042
|
FunctionStorageSqlite,
|
|
13421
14043
|
FunctionType,
|
|
13422
14044
|
GROUP_COLUMN_NAME,
|
|
14045
|
+
GrantRefusedError,
|
|
14046
|
+
INTROSPECT_PRINCIPALS_ENV,
|
|
14047
|
+
IdentityUnavailableError,
|
|
13423
14048
|
IntervalUnit2 as IntervalUnit,
|
|
13424
14049
|
NoCatalogError,
|
|
13425
14050
|
NullHandling,
|
|
@@ -13428,9 +14053,11 @@ export {
|
|
|
13428
14053
|
OutputCollector,
|
|
13429
14054
|
PARENT_ROW_METADATA_KEY,
|
|
13430
14055
|
PushdownFilters,
|
|
14056
|
+
READ_ONLY_ITEM_ATTACH_ID,
|
|
13431
14057
|
ReadOnlyCatalogInterface,
|
|
13432
14058
|
RowCountMismatchError,
|
|
13433
14059
|
ScanFunctionResultSchema,
|
|
14060
|
+
StatusError,
|
|
13434
14061
|
TableInOutPhase,
|
|
13435
14062
|
TimeUnit2 as TimeUnit,
|
|
13436
14063
|
TypeId,
|
|
@@ -13468,7 +14095,9 @@ export {
|
|
|
13468
14095
|
batchToSecretDict,
|
|
13469
14096
|
binary2 as binary,
|
|
13470
14097
|
bool3 as bool,
|
|
14098
|
+
buildCatalogAttachResult,
|
|
13471
14099
|
buildJoinKeysLookup,
|
|
14100
|
+
buildRpcServer,
|
|
13472
14101
|
buildScanBranchesResult,
|
|
13473
14102
|
buildVgiProtocol,
|
|
13474
14103
|
bytes,
|
|
@@ -13621,4 +14250,4 @@ export {
|
|
|
13621
14250
|
utf82 as utf8
|
|
13622
14251
|
};
|
|
13623
14252
|
|
|
13624
|
-
//# debugId=
|
|
14253
|
+
//# debugId=03676B1C4ED9A21664756E2164756E21
|