@query-farm/vgi 0.14.0 → 0.17.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.
@@ -1,28 +1,10 @@
1
- import { type ProtocolConfig } from "./protocol/dispatch.js";
2
- export interface VgiFetchOptions {
3
- /** Wire-protocol config (registry + catalogInterface). */
4
- protocol: Omit<ProtocolConfig, "recoverExchangeState">;
5
- /** HMAC key for state-token signing. Pass a stable, secret 32-byte key
6
- * (e.g. derived from a Wrangler secret). Required because Workers don't
7
- * preserve in-memory state across requests/instances. */
8
- signingKey: Uint8Array;
9
- /** State-token TTL in seconds (default 3600). */
10
- tokenTtl?: number;
11
- /** URL path prefix for VGI requests (default "/vgi"). */
12
- prefix?: string;
13
- /** Server ID for state-token attribution (default "vgi-cf"). */
14
- serverId?: string;
15
- }
16
- /**
17
- * Build a fetch handler suitable for `export default { fetch }` in a CF
18
- * Worker module. The returned handler is async-safe across Workers'
19
- * isolate-per-request execution model — all state round-trips through the
20
- * signed state token created here.
21
- */
22
- export declare function createVgiFetch(opts: VgiFetchOptions): (req: Request) => Promise<Response>;
1
+ export { createVgiFetch } from "./http/fetch.js";
2
+ export type { VgiFetchOptions } from "./http/fetch.js";
23
3
  export { defineScalarFunction, defineTableFunction, defineAggregate, defineTableInOutFunction, FunctionRegistry, ReadOnlyCatalogInterface, CompositeCatalogInterface, CatalogInterface, Arguments, FunctionType, serializeAttachOptionSpec, serializeAttachOptionSpecs, serializeColumnStatistics, BindResultSchema, ScanFunctionResultSchema, } from "./index.core.js";
24
4
  export type { AttachOptionSpec, ColumnStatistics, CatalogAttachResult, CatalogDescriptor, CatalogInfo, TableInfo, AttachOpaqueData, TransactionOpaqueData, SchemaInfo, VgiFunction, TableProcessParams, } from "./index.core.js";
25
5
  export type { ProtocolConfig } from "./protocol/dispatch.js";
6
+ export { createLandingDescribe } from "./http/describe-json.js";
7
+ export type { LandingDescribeProvider, WorkerDescribeInfo } from "./http/describe-json.js";
26
8
  export { TypeId, isNull, isInt, isFloat, isBinary, isUtf8, isBool, isDecimal, isDate, isTime, isTimestamp, isInterval, isList, isStruct, isUnion, isFixedSizeBinary, isFixedSizeList, isMap, isDuration, isDictionary, isBatch, backend, schema, field, nullType, bool, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float16, float32, float64, utf8, binary, fixedSizeBinary, decimal, decimal128, decimal256, date, dateDay, dateMillisecond, time, timeSecond, timeMillisecond, timeMicrosecond, timeNanosecond, timestamp, duration, interval, list, fixedSizeList, struct, map, dictionary, union, sparseUnion, denseUnion, TimeUnit, DateUnit, IntervalUnit, UnionMode, emptyBatch, batchFromRows, batchFromColumns, columnFromArray, iterRows, batchToScalarDict, batchToSecretDict, safeNumber, decodeDictValue, filterBatch, projectSchema, projectBatch, serializeSchema, deserializeSchema, serializeBatch, deserializeBatch, buildStatisticsBatch, } from "./arrow/index.js";
27
9
  export type { VgiTypeId, VgiDataType, VgiField, VgiSchema, VgiColumn, VgiColumnData, VgiBatch, VgiBackendInfo, } from "./arrow/index.js";
28
10
  export { arrowStateSerializer, EXCHANGE_STATE_SCHEMA } from "./protocol/state-serializer.js";
@@ -2543,7 +2543,7 @@ var init_storage = __esm(() => {
2543
2543
  });
2544
2544
  });
2545
2545
 
2546
- // src/worker-cf-entry.ts
2546
+ // src/http/fetch.ts
2547
2547
  import { createHttpHandler, unpackStateToken } from "@query-farm/vgi-rpc";
2548
2548
 
2549
2549
  // src/protocol/state-serializer.ts
@@ -7182,6 +7182,32 @@ function buildVgiProtocol(config) {
7182
7182
  return protocol;
7183
7183
  }
7184
7184
 
7185
+ // src/http/fetch.ts
7186
+ function createVgiFetch(opts) {
7187
+ const tokenTtl = opts.tokenTtl ?? 3600;
7188
+ const prefix = opts.prefix ?? "/vgi";
7189
+ const serverId = opts.serverId ?? "vgi-cf";
7190
+ const protocol = buildVgiProtocol({
7191
+ signingKey: opts.signingKey,
7192
+ ...opts.protocol,
7193
+ recoverExchangeState: async (opaqueData) => {
7194
+ const tokenString = new TextDecoder().decode(opaqueData);
7195
+ const unpacked = await unpackStateToken(tokenString, opts.signingKey, tokenTtl, undefined);
7196
+ return arrowStateSerializer.deserialize(unpacked.stateBytes);
7197
+ }
7198
+ });
7199
+ const handler = createHttpHandler(protocol, {
7200
+ prefix,
7201
+ serverId,
7202
+ tokenKey: opts.signingKey,
7203
+ tokenTtl,
7204
+ stateSerializer: arrowStateSerializer,
7205
+ corsOrigins: opts.corsOrigins,
7206
+ repositoryUrl: opts.repositoryUrl,
7207
+ landingDescribe: opts.landingDescribe
7208
+ });
7209
+ return async (req) => handler(req);
7210
+ }
7185
7211
  // src/functions/scalar.ts
7186
7212
  init_arrow();
7187
7213
  function defineScalarFunction(config) {
@@ -7340,6 +7366,12 @@ function defineScalarFunction(config) {
7340
7366
  init_arrow();
7341
7367
  init_registry();
7342
7368
  init_storage();
7369
+
7370
+ // src/cache-control.ts
7371
+ var CACHE_IF_NONE_MATCH_KEY = "vgi.cache.if_none_match";
7372
+ var CACHE_IF_MODIFIED_SINCE_KEY = "vgi.cache.if_modified_since";
7373
+
7374
+ // src/functions/table.ts
7343
7375
  function base64Decode(s) {
7344
7376
  const bin = globalThis.atob ? globalThis.atob(s) : Buffer.from(s, "base64").toString("binary");
7345
7377
  const out = new Uint8Array(bin.length);
@@ -7538,6 +7570,12 @@ function defineTableFunction(config) {
7538
7570
  onTick: (pState, tickMetadata) => {
7539
7571
  if (!tickMetadata)
7540
7572
  return;
7573
+ const ifNoneMatch = tickMetadata.get(CACHE_IF_NONE_MATCH_KEY);
7574
+ const ifModifiedSince = tickMetadata.get(CACHE_IF_MODIFIED_SINCE_KEY);
7575
+ if (ifNoneMatch !== undefined)
7576
+ pState.processParams.ifNoneMatch = ifNoneMatch;
7577
+ if (ifModifiedSince !== undefined)
7578
+ pState.processParams.ifModifiedSince = ifModifiedSince;
7541
7579
  const encoded = tickMetadata.get("vgi_pushdown_filters");
7542
7580
  if (!encoded)
7543
7581
  return;
@@ -8810,31 +8848,419 @@ function serializeAttachOptionSpec(spec) {
8810
8848
  function serializeAttachOptionSpecs(specs) {
8811
8849
  return Array.from(specs, serializeAttachOptionSpec);
8812
8850
  }
8813
- // src/worker-cf-entry.ts
8851
+ // src/http/describe-json.ts
8814
8852
  init_arrow();
8815
- import { OutputCollector as OutputCollector2, AuthContext as AuthContext2 } from "@query-farm/vgi-rpc";
8816
- function createVgiFetch(opts) {
8817
- const tokenTtl = opts.tokenTtl ?? 3600;
8818
- const prefix = opts.prefix ?? "/vgi";
8819
- const serverId = opts.serverId ?? "vgi-cf";
8820
- const protocol = buildVgiProtocol({
8821
- signingKey: opts.signingKey,
8822
- ...opts.protocol,
8823
- recoverExchangeState: async (opaqueData) => {
8824
- const tokenString = new TextDecoder().decode(opaqueData);
8825
- const unpacked = await unpackStateToken(tokenString, opts.signingKey, tokenTtl, undefined);
8826
- return arrowStateSerializer.deserialize(unpacked.stateBytes);
8853
+ var LANDING_SCHEMA_VERSION2 = 1;
8854
+ var CUPOLA_BASE2 = "https://cupola.query-farm.services";
8855
+ var STRING_TAGS = {
8856
+ title: "vgi.title",
8857
+ doc_md: "vgi.doc_md",
8858
+ source_url: "vgi.source_url",
8859
+ license: "vgi.license",
8860
+ author: "vgi.author",
8861
+ copyright: "vgi.copyright",
8862
+ support_contact: "vgi.support_contact",
8863
+ support_policy_url: "vgi.support_policy_url"
8864
+ };
8865
+ var KEYWORDS_TAG = "vgi.keywords";
8866
+ function typeToString(type) {
8867
+ if (isNull(type))
8868
+ return "NULL";
8869
+ if (isUtf8(type))
8870
+ return "VARCHAR";
8871
+ if (isBinary(type))
8872
+ return "BLOB";
8873
+ if (isBool(type))
8874
+ return "BOOLEAN";
8875
+ if (isInt(type)) {
8876
+ const bw = type.bitWidth ?? 32;
8877
+ return bw === 64 ? "BIGINT" : "INTEGER";
8878
+ }
8879
+ if (isFloat(type)) {
8880
+ const precision = type.precision ?? 2;
8881
+ return precision === 1 ? "FLOAT" : "DOUBLE";
8882
+ }
8883
+ const s = type.toString?.();
8884
+ return s ?? String(type.typeId);
8885
+ }
8886
+ function arrowTypeString(type) {
8887
+ if (isNull(type))
8888
+ return "null";
8889
+ if (isBool(type))
8890
+ return "bool";
8891
+ if (isUtf8(type))
8892
+ return "string";
8893
+ if (isBinary(type))
8894
+ return "binary";
8895
+ if (isInt(type)) {
8896
+ const bw = type.bitWidth ?? 32;
8897
+ const signed = type.isSigned ?? type.signed ?? true;
8898
+ return `${signed ? "" : "u"}int${bw}`;
8899
+ }
8900
+ if (isFloat(type)) {
8901
+ const precision = type.precision ?? 2;
8902
+ return precision === 0 ? "halffloat" : precision === 1 ? "float" : "double";
8903
+ }
8904
+ const s = type.toString?.();
8905
+ return (s ?? String(type.typeId)).toLowerCase();
8906
+ }
8907
+ function fieldMeta(field4, key) {
8908
+ return field4.metadata.get(key);
8909
+ }
8910
+ function fieldToColumn(field4) {
8911
+ const col = { name: field4.name, type: typeToString(field4.type) };
8912
+ const comment = fieldMeta(field4, "comment") ?? fieldMeta(field4, VGI_DOC_KEY);
8913
+ if (comment)
8914
+ col.comment = comment;
8915
+ return col;
8916
+ }
8917
+ function readSchemaSafe(bytes2) {
8918
+ if (!bytes2 || bytes2.length === 0)
8919
+ return null;
8920
+ try {
8921
+ return deserializeSchema(bytes2);
8922
+ } catch {
8923
+ return null;
8924
+ }
8925
+ }
8926
+ function functionDisplayType(fn) {
8927
+ const t = String(fn.function_type).toUpperCase();
8928
+ if (t === "SCALAR")
8929
+ return "scalar";
8930
+ if (t === "AGGREGATE")
8931
+ return "aggregate";
8932
+ if (fn.has_finalize)
8933
+ return "table_in_out";
8934
+ return "table";
8935
+ }
8936
+ function functionReturns(fn) {
8937
+ const schema4 = readSchemaSafe(fn.output_schema);
8938
+ if (schema4 === null || schema4.fields.length === 0)
8939
+ return;
8940
+ const t = String(fn.function_type).toUpperCase();
8941
+ if (t === "SCALAR" || t === "AGGREGATE") {
8942
+ return typeToString(schema4.fields[0].type);
8943
+ }
8944
+ const cols = schema4.fields.map((f) => `${f.name} ${typeToString(f.type)}`).join(", ");
8945
+ return `TABLE(${cols})`;
8946
+ }
8947
+ function functionArgs(fn) {
8948
+ const schema4 = readSchemaSafe(fn.arguments);
8949
+ if (schema4 === null)
8950
+ return [];
8951
+ const args = [];
8952
+ for (const field4 of schema4.fields) {
8953
+ if (fieldMeta(field4, VGI_TYPE_KEY) === VGI_TYPE_TABLE)
8954
+ continue;
8955
+ const arg = { name: field4.name, type: typeToString(field4.type) };
8956
+ if (fieldMeta(field4, VGI_ARG_KEY) === VGI_ARG_NAMED)
8957
+ arg.named = true;
8958
+ const doc = fieldMeta(field4, VGI_DOC_KEY);
8959
+ if (doc)
8960
+ arg.desc = doc;
8961
+ const rawDefault = fieldMeta(field4, VGI_DEFAULT_KEY);
8962
+ if (rawDefault !== undefined) {
8963
+ try {
8964
+ arg.default = JSON.stringify(JSON.parse(rawDefault));
8965
+ } catch {
8966
+ arg.default = rawDefault;
8967
+ }
8827
8968
  }
8828
- });
8829
- const handler = createHttpHandler(protocol, {
8830
- prefix,
8831
- serverId,
8832
- tokenKey: opts.signingKey,
8833
- tokenTtl,
8834
- stateSerializer: arrowStateSerializer
8835
- });
8836
- return async (req) => handler(req);
8969
+ args.push(arg);
8970
+ }
8971
+ return args;
8837
8972
  }
8973
+ function macroDisplayType(m) {
8974
+ return String(m.macro_type).toUpperCase() === "SCALAR" ? "scalar" : "table";
8975
+ }
8976
+ function macroDefaultJson(value) {
8977
+ if (typeof value === "bigint")
8978
+ return value.toString();
8979
+ try {
8980
+ return JSON.stringify(value);
8981
+ } catch {
8982
+ return String(value);
8983
+ }
8984
+ }
8985
+ function macroArgs(m) {
8986
+ const defaults = new Map;
8987
+ const defBytes = m.parameter_default_values;
8988
+ if (defBytes && defBytes.length > 0) {
8989
+ try {
8990
+ const batch = deserializeBatch(defBytes);
8991
+ for (const field4 of batch.schema.fields) {
8992
+ try {
8993
+ defaults.set(field4.name, batch.getChild(field4.name)?.get(0));
8994
+ } catch {}
8995
+ }
8996
+ } catch {}
8997
+ }
8998
+ const schema4 = readSchemaSafe(m.arguments_schema);
8999
+ const fields = schema4 ? schema4.fields : null;
9000
+ const fieldByName = new Map;
9001
+ if (fields)
9002
+ for (const f of fields)
9003
+ fieldByName.set(f.name, f);
9004
+ const names = fields ? fields.map((f) => f.name) : m.parameters;
9005
+ const args = [];
9006
+ for (const name of names) {
9007
+ const field4 = fieldByName.get(name);
9008
+ const arg = field4 !== undefined && !isNull(field4.type) ? { name, type: arrowTypeString(field4.type) } : { name, type: "ANY" };
9009
+ const doc = field4 !== undefined ? fieldMeta(field4, VGI_DOC_KEY) : undefined;
9010
+ if (doc)
9011
+ arg.desc = doc;
9012
+ if (defaults.has(name)) {
9013
+ arg.named = true;
9014
+ arg.default = macroDefaultJson(defaults.get(name));
9015
+ }
9016
+ args.push(arg);
9017
+ }
9018
+ return args;
9019
+ }
9020
+ function macroToObject(m) {
9021
+ return {
9022
+ name: m.name,
9023
+ type: macroDisplayType(m),
9024
+ doc: m.comment ?? "",
9025
+ args: macroArgs(m)
9026
+ };
9027
+ }
9028
+ async function schemaContents(iface, aod, name, kind) {
9029
+ try {
9030
+ if (kind === "TABLE") {
9031
+ return await iface.schemaContentsTables(aod, name);
9032
+ }
9033
+ return await iface.schemaContentsViews(aod, name);
9034
+ } catch {
9035
+ return [];
9036
+ }
9037
+ }
9038
+ async function schemaFunctions(iface, aod, name) {
9039
+ const out = [];
9040
+ for (const kind of ["SCALAR_FUNCTION", "TABLE_FUNCTION", "AGGREGATE_FUNCTION"]) {
9041
+ try {
9042
+ out.push(...await iface.schemaContentsFunctions(aod, name, kind));
9043
+ } catch {}
9044
+ }
9045
+ return out;
9046
+ }
9047
+ async function schemaMacros(iface, aod, name) {
9048
+ const out = [];
9049
+ for (const kind of ["SCALAR_MACRO", "TABLE_MACRO"]) {
9050
+ try {
9051
+ out.push(...await iface.schemaContentsMacros(aod, name, kind));
9052
+ } catch {}
9053
+ }
9054
+ return out;
9055
+ }
9056
+ async function buildSchemas(iface, aod) {
9057
+ let schemaInfos;
9058
+ try {
9059
+ schemaInfos = await iface.schemas(aod);
9060
+ } catch {
9061
+ return { schemas: [], counts: { schemas: 0, tables: 0, views: 0, functions: 0 } };
9062
+ }
9063
+ const schemas = [];
9064
+ const counts = { schemas: 0, tables: 0, views: 0, functions: 0 };
9065
+ for (const si of schemaInfos) {
9066
+ const tablesRaw = await schemaContents(iface, aod, si.name, "TABLE");
9067
+ const viewsRaw = await schemaContents(iface, aod, si.name, "VIEW");
9068
+ const funcsRaw = await schemaFunctions(iface, aod, si.name);
9069
+ const macrosRaw = await schemaMacros(iface, aod, si.name);
9070
+ const tables = tablesRaw.map((t) => {
9071
+ const schema4 = readSchemaSafe(t.columns);
9072
+ return { name: t.name, cols: schema4 ? schema4.fields.length : 0, comment: t.comment ?? "" };
9073
+ });
9074
+ const views = viewsRaw.map((v) => ({
9075
+ name: v.name,
9076
+ cols: Object.keys(v.column_comments ?? {}).length,
9077
+ comment: v.comment ?? "",
9078
+ def: v.definition
9079
+ }));
9080
+ const functions = funcsRaw.map((fn) => {
9081
+ const obj = {
9082
+ name: fn.name,
9083
+ type: functionDisplayType(fn),
9084
+ doc: fn.description ?? "",
9085
+ args: functionArgs(fn)
9086
+ };
9087
+ const ret = functionReturns(fn);
9088
+ if (ret)
9089
+ obj.returns = ret;
9090
+ return obj;
9091
+ });
9092
+ functions.push(...macrosRaw.map((m) => macroToObject(m)));
9093
+ functions.sort((a, b) => String(a.type).localeCompare(String(b.type)) || String(a.name).localeCompare(String(b.name)));
9094
+ const schemaObj = { name: si.name };
9095
+ if (si.comment)
9096
+ schemaObj.doc = si.comment;
9097
+ schemaObj.tables = tables;
9098
+ schemaObj.views = views;
9099
+ schemaObj.functions = functions;
9100
+ schemas.push(schemaObj);
9101
+ counts.schemas += 1;
9102
+ counts.tables += tables.length;
9103
+ counts.views += views.length;
9104
+ counts.functions += functions.length;
9105
+ }
9106
+ return { schemas, counts };
9107
+ }
9108
+ function catalogTags(result) {
9109
+ const tags = result?.tags;
9110
+ if (!tags)
9111
+ return {};
9112
+ const out = {};
9113
+ for (const [key, tag] of Object.entries(STRING_TAGS)) {
9114
+ const val = tags[tag];
9115
+ if (val)
9116
+ out[key] = val;
9117
+ }
9118
+ const kw = tags[KEYWORDS_TAG];
9119
+ if (kw) {
9120
+ try {
9121
+ const parsed = JSON.parse(kw);
9122
+ if (Array.isArray(parsed))
9123
+ out.keywords = parsed.map((k) => String(k));
9124
+ } catch {}
9125
+ }
9126
+ return out;
9127
+ }
9128
+ function decodeAttachOption(bytes2) {
9129
+ try {
9130
+ const batch = deserializeBatch(bytes2);
9131
+ if (batch.numRows === 0)
9132
+ return null;
9133
+ const name = String(batch.getChild("name")?.get(0) ?? "");
9134
+ const description = String(batch.getChild("description")?.get(0) ?? "");
9135
+ const typeBytes = batch.getChild("type")?.get(0);
9136
+ let type = "";
9137
+ const typeSchema = readSchemaSafe(typeBytes ?? null);
9138
+ if (typeSchema && typeSchema.fields.length > 0)
9139
+ type = typeToString(typeSchema.fields[0].type);
9140
+ let defaultStr = "";
9141
+ const defBytes = batch.getChild("default_value")?.get(0);
9142
+ if (defBytes) {
9143
+ try {
9144
+ const defBatch = deserializeBatch(defBytes);
9145
+ if (defBatch.numRows > 0) {
9146
+ const v = defBatch.getChild("value")?.get(0);
9147
+ defaultStr = v == null ? "" : String(v);
9148
+ }
9149
+ } catch {}
9150
+ }
9151
+ return { name, type, default: defaultStr, description };
9152
+ } catch {
9153
+ return null;
9154
+ }
9155
+ }
9156
+ async function attachCatalog(iface, name) {
9157
+ try {
9158
+ return await iface.attach(name, {}, null, null);
9159
+ } catch {
9160
+ return null;
9161
+ }
9162
+ }
9163
+ async function buildCatalog(iface, name, info) {
9164
+ const result = await attachCatalog(iface, name);
9165
+ const attachOptions = (info?.attach_option_specs ?? []).map((b) => decodeAttachOption(b)).filter((o) => o !== null);
9166
+ const dataVersions = (info?.releases ?? []).map((r) => r.summary ? { spec: r.version, label: r.summary } : { spec: r.version });
9167
+ let impl = info?.implementation_version ?? null;
9168
+ let dvs = info?.data_version_spec ?? null;
9169
+ if (result) {
9170
+ impl = result.resolved_implementation_version ?? impl;
9171
+ dvs = result.resolved_data_version ?? dvs;
9172
+ }
9173
+ let schemas = [];
9174
+ let counts = { schemas: 0, tables: 0, views: 0, functions: 0 };
9175
+ if (result) {
9176
+ const built = await buildSchemas(iface, result.attach_opaque_data);
9177
+ schemas = built.schemas;
9178
+ counts = built.counts;
9179
+ }
9180
+ return {
9181
+ name,
9182
+ implementation_version: impl,
9183
+ data_version_spec: dvs,
9184
+ data_versions: dataVersions,
9185
+ attach_options: attachOptions,
9186
+ tags: catalogTags(result),
9187
+ counts,
9188
+ schemas
9189
+ };
9190
+ }
9191
+ async function catalogInfoByName(iface) {
9192
+ const map4 = new Map;
9193
+ if (typeof iface.catalogsInfo === "function") {
9194
+ try {
9195
+ const infos = await iface.catalogsInfo();
9196
+ for (const info of infos)
9197
+ map4.set(info.name, info);
9198
+ } catch {}
9199
+ }
9200
+ return map4;
9201
+ }
9202
+ async function buildDescribeJson2(iface, worker, opts = {}) {
9203
+ const infos = await catalogInfoByName(iface);
9204
+ let names;
9205
+ try {
9206
+ names = iface.catalogs();
9207
+ } catch {
9208
+ names = [];
9209
+ }
9210
+ const catalogs = [];
9211
+ for (const name of names) {
9212
+ catalogs.push(await buildCatalog(iface, name, infos.get(name)));
9213
+ }
9214
+ return {
9215
+ landing_schema_version: LANDING_SCHEMA_VERSION2,
9216
+ worker: {
9217
+ name: worker.name,
9218
+ doc: worker.doc ?? "",
9219
+ version: worker.version ?? "unknown",
9220
+ lang: "typescript"
9221
+ },
9222
+ server_id: opts.serverId ?? "",
9223
+ oauth: opts.oauth ?? false,
9224
+ cupola_base: opts.cupolaBase ?? CUPOLA_BASE2,
9225
+ catalogs
9226
+ };
9227
+ }
9228
+ async function buildColumnsJson2(iface, catalog, schema4, table) {
9229
+ const result = await attachCatalog(iface, catalog);
9230
+ if (!result)
9231
+ return null;
9232
+ const aod = result.attach_opaque_data;
9233
+ const tables = await schemaContents(iface, aod, schema4, "TABLE");
9234
+ for (const t of tables) {
9235
+ if (t.name === table) {
9236
+ const arrow = readSchemaSafe(t.columns);
9237
+ return { columns: (arrow?.fields ?? []).map((f) => fieldToColumn(f)) };
9238
+ }
9239
+ }
9240
+ const views = await schemaContents(iface, aod, schema4, "VIEW");
9241
+ for (const v of views) {
9242
+ if (v.name === table) {
9243
+ return {
9244
+ columns: Object.entries(v.column_comments ?? {}).map(([name, comment]) => ({
9245
+ name,
9246
+ type: "",
9247
+ comment
9248
+ }))
9249
+ };
9250
+ }
9251
+ }
9252
+ return null;
9253
+ }
9254
+ function createLandingDescribe2(iface, worker, opts = {}) {
9255
+ return {
9256
+ describe: (ctx) => buildDescribeJson2(iface, worker, { ...ctx, cupolaBase: opts.cupolaBase }),
9257
+ columns: (catalog, schema4, table) => buildColumnsJson2(iface, catalog, schema4, table)
9258
+ };
9259
+ }
9260
+
9261
+ // src/worker-cf-entry.ts
9262
+ init_arrow();
9263
+ import { OutputCollector as OutputCollector2, AuthContext as AuthContext2 } from "@query-farm/vgi-rpc";
8838
9264
  export {
8839
9265
  utf82 as utf8,
8840
9266
  union2 as union,
@@ -8914,6 +9340,7 @@ export {
8914
9340
  dateDay2 as dateDay,
8915
9341
  date2 as date,
8916
9342
  createVgiFetch,
9343
+ createLandingDescribe2 as createLandingDescribe,
8917
9344
  columnFromArray,
8918
9345
  buildStatisticsBatch,
8919
9346
  bool2 as bool,
@@ -8942,4 +9369,4 @@ export {
8942
9369
  Arguments
8943
9370
  };
8944
9371
 
8945
- //# debugId=065F8224F5A26C2864756E2164756E21
9372
+ //# debugId=C67D053F70399BE264756E2164756E21