@malloy-publisher/server 0.0.203 → 0.0.204

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/app/api-doc.yaml +17 -0
  2. package/dist/app/assets/{EnvironmentPage-BVQ7glKP.js → EnvironmentPage-CX06cjOF.js} +1 -1
  3. package/dist/app/assets/HomePage-CNFt_eUU.js +1 -0
  4. package/dist/app/assets/{MainPage-bYOWcgDP.js → MainPage-nUJ9YatG.js} +1 -1
  5. package/dist/app/assets/{PackagePage-N1ZBNJul.js → MaterializationsPage-B5goxVXW.js} +1 -1
  6. package/dist/app/assets/{ModelPage-DT0gjNy1.js → ModelPage-Ba7Xh4lL.js} +1 -1
  7. package/dist/app/assets/PackagePage-BaEVdEAG.js +1 -0
  8. package/dist/app/assets/{RouteError-_J-EBz7W.js → RouteError-BShQjZio.js} +1 -1
  9. package/dist/app/assets/{WorkbookPage-Bjs9Nm-_.js → WorkbookPage-CBn6ZjJW.js} +1 -1
  10. package/dist/app/assets/{core-BPLlx5VM.es-C2ARtwWI.js → core-DECXYL4E.es-OaRfXwuQ.js} +1 -1
  11. package/dist/app/assets/{index-CqUWJELr.js → index-BLfPC1gy.js} +2 -2
  12. package/dist/app/assets/index-DqiJ0bWp.js +455 -0
  13. package/dist/app/assets/index-Dy3YhAZQ.js +1812 -0
  14. package/dist/app/assets/index.umd-DAN9K8yC.js +2469 -0
  15. package/dist/app/index.html +1 -1
  16. package/dist/package_load_worker.mjs +392 -67
  17. package/dist/server.mjs +415 -152
  18. package/package.json +11 -11
  19. package/src/ducklake_version.spec.ts +43 -0
  20. package/src/ducklake_version.ts +26 -0
  21. package/src/errors.ts +18 -1
  22. package/src/package_load/package_load_pool.ts +0 -5
  23. package/src/package_load/package_load_worker.ts +41 -99
  24. package/src/package_load/protocol.ts +1 -7
  25. package/src/service/annotations.spec.ts +118 -0
  26. package/src/service/annotations.ts +91 -0
  27. package/src/service/authorize.spec.ts +132 -0
  28. package/src/service/authorize.ts +241 -0
  29. package/src/service/authorize_integration.spec.ts +838 -0
  30. package/src/service/connection.ts +1 -1
  31. package/src/service/environment.ts +4 -4
  32. package/src/service/filter.spec.ts +14 -3
  33. package/src/service/filter.ts +5 -1
  34. package/src/service/filter_bypass.spec.ts +418 -0
  35. package/src/service/given.ts +37 -12
  36. package/src/service/givens_integration.spec.ts +34 -7
  37. package/src/service/materialization_service.ts +25 -20
  38. package/src/service/materialized_table_gc.spec.ts +6 -5
  39. package/src/service/materialized_table_gc.ts +2 -50
  40. package/src/service/model.spec.ts +203 -8
  41. package/src/service/model.ts +305 -155
  42. package/src/service/package_worker_path.spec.ts +113 -0
  43. package/src/service/quoting.ts +0 -20
  44. package/src/service/restricted_mode.spec.ts +299 -0
  45. package/src/service/source_extraction.ts +226 -0
  46. package/src/storage/StorageManager.ts +73 -0
  47. package/dist/app/assets/HomePage-D9drXoZX.js +0 -1
  48. package/dist/app/assets/index-BeNwIeYQ.js +0 -454
  49. package/dist/app/assets/index-Dx7qi2LO.js +0 -1803
  50. package/dist/app/assets/index.umd-BXm2lnUO.js +0 -1145
@@ -1,5 +1,9 @@
1
1
  import { Mutex } from "async-mutex";
2
2
  import * as crypto from "crypto";
3
+ import {
4
+ isCatalogVersionSupported,
5
+ SUPPORTED_CATALOG_VERSIONS,
6
+ } from "../ducklake_version";
3
7
  import { ConnectionAuthError } from "../errors";
4
8
  import { logger } from "../logger";
5
9
  import {
@@ -64,6 +68,53 @@ function catalogNameForConfig(c: DuckLakeManifestConfig): string {
64
68
  return `manifest_lake_${hash}`;
65
69
  }
66
70
 
71
+ // Read the catalog's recorded DuckLake format version from its
72
+ // `ducklake_metadata` table via a plain postgres ATTACH (does NOT invoke
73
+ // the DuckLake extension on the catalog). Returns the version string on
74
+ // success, or `undefined` on any failure (missing table, query timeout,
75
+ // connect failure) so the main ATTACH path stays the source of truth for
76
+ // unrelated errors. Only meaningful for postgres-backed catalogs; the
77
+ // caller must guard with `isPostgres`.
78
+ async function readDuckLakeCatalogVersion(
79
+ connection: DuckDBConnection,
80
+ catalogUrl: string,
81
+ catalogName: string,
82
+ ): Promise<string | undefined> {
83
+ if (!catalogUrl.startsWith("postgres:")) {
84
+ return undefined;
85
+ }
86
+ const pgConnString = catalogUrl.slice("postgres:".length);
87
+ const tempDb = `${catalogName}_preflight`;
88
+ const escaped = escapeSQL(pgConnString);
89
+ try {
90
+ await connection.run(
91
+ `ATTACH '${escaped}' AS ${tempDb} (TYPE postgres, READ_ONLY);`,
92
+ );
93
+ const rows = await connection.all<{ value: string }>(
94
+ `SELECT value FROM ${tempDb}.ducklake_metadata WHERE key = 'version' LIMIT 1;`,
95
+ );
96
+ const value = rows[0]?.value;
97
+ return typeof value === "string" ? value : undefined;
98
+ } catch (error) {
99
+ logger.warn(
100
+ "DuckLake catalog version preflight failed; falling back to ATTACH",
101
+ {
102
+ catalogName,
103
+ error: redactPgSecrets(
104
+ error instanceof Error ? error.message : String(error),
105
+ ),
106
+ },
107
+ );
108
+ return undefined;
109
+ } finally {
110
+ try {
111
+ await connection.run(`DETACH ${tempDb};`);
112
+ } catch {
113
+ // ATTACH may have failed, so DETACH may have nothing to do.
114
+ }
115
+ }
116
+ }
117
+
67
118
  /**
68
119
  * Manages the storage backend (DuckDB, Postgres, etc.) and per-environment
69
120
  * manifest stores. Environments without `materializationStorage` config use
@@ -222,6 +273,28 @@ export class StorageManager {
222
273
  await connection.run("INSTALL httpfs; LOAD httpfs;");
223
274
  }
224
275
 
276
+ // Preflight: read the catalog's recorded format version via the
277
+ // postgres extension (not DuckLake) and fail fast with a non-retryable
278
+ // 422 if the baked DuckLake extension can't read it. Without this,
279
+ // an unsupported catalog would surface as a generic DuckDB error
280
+ // from the ATTACH below, which retry loops misclassify as transient.
281
+ if (isPostgres) {
282
+ const catalogVersion = await readDuckLakeCatalogVersion(
283
+ connection,
284
+ catalogUrl,
285
+ catalogName,
286
+ );
287
+ if (catalogVersion && !isCatalogVersionSupported(catalogVersion)) {
288
+ const supportedMax =
289
+ SUPPORTED_CATALOG_VERSIONS[
290
+ SUPPORTED_CATALOG_VERSIONS.length - 1
291
+ ];
292
+ throw new ConnectionAuthError(
293
+ `DuckLake catalog version ${catalogVersion} is newer than this Publisher's extension supports (max ${supportedMax}). Upgrade the Publisher image or downgrade the catalog.`,
294
+ );
295
+ }
296
+ }
297
+
225
298
  let attachCmd = `ATTACH 'ducklake:${escapedCatalogUrl}' AS ${catalogName}`;
226
299
  const attachOpts: string[] = [
227
300
  `DATA_PATH '${escapedDataPath}'`,
@@ -1 +0,0 @@
1
- import{T as t,j as o,A as a}from"./index-BeNwIeYQ.js";function s(){const n=t();return o.jsx(a,{onClickEnvironment:n})}export{s as default};