@malloy-publisher/server 0.0.246 → 0.0.247

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.
@@ -11887,11 +11887,19 @@ import { Annotations } from "@malloydata/malloy";
11887
11887
  function isReservedRoute(route) {
11888
11888
  return route === "" || !/[\p{L}\p{N}]/u.test(route);
11889
11889
  }
11890
+ function ownModelAnnotations(modelDef) {
11891
+ return foldModelAnnotations(modelDef, (id) => id === modelDef.modelID || id.startsWith("internal://"));
11892
+ }
11890
11893
  function modelAnnotations(modelDef) {
11894
+ return foldModelAnnotations(modelDef, () => true);
11895
+ }
11896
+ function foldModelAnnotations(modelDef, admits) {
11891
11897
  const registry = modelDef.modelAnnotations ?? {};
11892
11898
  const visited = new Set;
11893
11899
  const order = [];
11894
11900
  const visit = (id) => {
11901
+ if (!admits(id))
11902
+ return;
11895
11903
  if (visited.has(id))
11896
11904
  return;
11897
11905
  visited.add(id);
@@ -12328,6 +12336,48 @@ function resolvePackageScope(rootRaw, materializationRaw) {
12328
12336
  return { scope: envelopeScope, warnings: [] };
12329
12337
  }
12330
12338
  var SCOPE_ROOT_DEPRECATION = `"scope" at the manifest root is deprecated: declare it as ` + `"materialization": { "scope": ... } alongside the other build knobs. The ` + `root form still works and will be removed in a future release; until then ` + `the server keeps both homes in sync when it writes the manifest, so an ` + `older publisher still reads the right value.`;
12339
+ function resolvePackageQueryMetadata(rootRaw, materializationRaw) {
12340
+ const envelopeRaw = materializationRaw && typeof materializationRaw === "object" ? materializationRaw.queryMetadata : undefined;
12341
+ const rootDeclared = rootRaw !== undefined && rootRaw !== null;
12342
+ const envelopeDeclared = envelopeRaw !== undefined && envelopeRaw !== null;
12343
+ if (rootDeclared && envelopeDeclared) {
12344
+ if (sameQueryMetadataBag(rootRaw, envelopeRaw)) {
12345
+ return { queryMetadata: rootRaw, home: "root", warnings: [] };
12346
+ }
12347
+ return {
12348
+ queryMetadata: rootRaw,
12349
+ home: "root",
12350
+ warnings: [QUERY_METADATA_CONFLICT]
12351
+ };
12352
+ }
12353
+ if (envelopeDeclared) {
12354
+ return {
12355
+ queryMetadata: envelopeRaw,
12356
+ home: "envelope",
12357
+ warnings: [QUERY_METADATA_ENVELOPE_DEPRECATION]
12358
+ };
12359
+ }
12360
+ return { queryMetadata: rootRaw, home: "root", warnings: [] };
12361
+ }
12362
+ function sameQueryMetadataBag(a, b) {
12363
+ return keySortedJson(a) === keySortedJson(b);
12364
+ }
12365
+ function keySortedJson(value) {
12366
+ if (value === null || typeof value !== "object") {
12367
+ return JSON.stringify(value) ?? "undefined";
12368
+ }
12369
+ if (Array.isArray(value)) {
12370
+ return `[${value.map(keySortedJson).join(",")}]`;
12371
+ }
12372
+ const entries = Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
12373
+ return `{${entries.map(([name, nested]) => `${JSON.stringify(name)}:${keySortedJson(nested)}`).join(",")}}`;
12374
+ }
12375
+ var QUERY_METADATA_HOME_LABELS = {
12376
+ root: "queryMetadata",
12377
+ envelope: "materialization.queryMetadata"
12378
+ };
12379
+ var QUERY_METADATA_ENVELOPE_DEPRECATION = `"queryMetadata" inside "materialization" is deprecated: declare it at the ` + `manifest root instead. It is not a build setting — the properties ride ` + `every statement the package's sources issue, including served queries. The ` + `enveloped form still works and will be removed in a future release; until ` + `then the server keeps both homes in sync when it writes the manifest, so an ` + `older publisher still reads the right value.`;
12380
+ var QUERY_METADATA_CONFLICT = `Conflicting "queryMetadata" in publisher.json: the manifest root and ` + `"materialization.queryMetadata" declare different bags, and the root wins. ` + `Delete "materialization": { "queryMetadata": ... } — the server rewrites ` + `both homes on its next manifest write, so an older publisher still reads ` + `the right value.`;
12331
12381
  function parseFreshness(raw) {
12332
12382
  if (!raw || typeof raw !== "object") {
12333
12383
  return null;
@@ -12342,7 +12392,7 @@ function parseFreshness(raw) {
12342
12392
  }
12343
12393
  return freshness;
12344
12394
  }
12345
- function parseQueryMetadata(raw) {
12395
+ function parseQueryMetadata(raw, label = QUERY_METADATA_HOME_LABELS.envelope) {
12346
12396
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
12347
12397
  return { metadata: null, warnings: [] };
12348
12398
  }
@@ -12352,7 +12402,7 @@ function parseQueryMetadata(raw) {
12352
12402
  if (typeof value === "string") {
12353
12403
  out[name] = value;
12354
12404
  } else {
12355
- warnings.push(`materialization.queryMetadata: property '${name}' must be a ` + `string (got ${value === null ? "null" : typeof value}); it is ` + `not attached to any statement`);
12405
+ warnings.push(`${label}: property '${name}' must be a ` + `string (got ${value === null ? "null" : typeof value}); it is ` + `not attached to any statement`);
12356
12406
  }
12357
12407
  }
12358
12408
  return {
@@ -12371,12 +12421,18 @@ function parsePackageMaterialization(raw) {
12371
12421
  queryMetadata: parseQueryMetadata(queryMetadata).metadata
12372
12422
  };
12373
12423
  }
12374
- function packageMaterializationWarnings(raw) {
12375
- if (!raw || typeof raw !== "object") {
12376
- return [];
12377
- }
12378
- const { queryMetadata } = raw;
12379
- return parseQueryMetadata(queryMetadata).warnings;
12424
+ function materializationWithQueryMetadata(parsed, queryMetadataRaw) {
12425
+ const queryMetadata = parseQueryMetadata(queryMetadataRaw).metadata;
12426
+ if (!parsed && !queryMetadata)
12427
+ return null;
12428
+ return {
12429
+ schedule: parsed?.schedule ?? null,
12430
+ freshness: parsed?.freshness ?? null,
12431
+ queryMetadata
12432
+ };
12433
+ }
12434
+ function queryMetadataParseWarnings(raw, home = "root") {
12435
+ return parseQueryMetadata(raw, QUERY_METADATA_HOME_LABELS[home]).warnings;
12380
12436
  }
12381
12437
 
12382
12438
  // src/package_load/package_load_worker.ts
@@ -12438,9 +12494,9 @@ function newRpcId() {
12438
12494
  }
12439
12495
  function callMain(send) {
12440
12496
  const requestId = newRpcId();
12441
- return new Promise((resolve, reject) => {
12497
+ return new Promise((resolve2, reject) => {
12442
12498
  pendingRpc.set(requestId, {
12443
- resolve: (value) => resolve(value),
12499
+ resolve: (value) => resolve2(value),
12444
12500
  reject
12445
12501
  });
12446
12502
  send(requestId);
@@ -12555,18 +12611,21 @@ function serializeFetchOptions(options) {
12555
12611
  }
12556
12612
  return out;
12557
12613
  }
12558
- function makeWorkerUrlReader(jobId) {
12614
+ function makeWorkerUrlReader(job) {
12559
12615
  return {
12560
12616
  readURL: async (url) => {
12561
12617
  if (url.protocol === "file:") {
12562
12618
  const filePath = fileURLToPath2(url);
12619
+ if (job.replacement && path2.resolve(filePath) === path2.resolve(job.packagePath, job.replacement.modelPath)) {
12620
+ return job.replacement.source;
12621
+ }
12563
12622
  return fs2.promises.readFile(filePath, "utf8");
12564
12623
  }
12565
12624
  const response = await callMain((requestId) => {
12566
12625
  const req = {
12567
12626
  type: "read-url",
12568
12627
  requestId,
12569
- jobId,
12628
+ jobId: job.requestId,
12570
12629
  url: url.toString()
12571
12630
  };
12572
12631
  port.postMessage(req);
@@ -12614,9 +12673,11 @@ async function readPackageMetadata(packagePath) {
12614
12673
  const contents = await fs2.promises.readFile(manifestPath, "utf8");
12615
12674
  const parsed = JSON.parse(contents);
12616
12675
  const scope = resolvePackageScope(parsed.scope, parsed.materialization);
12676
+ const queryMetadata = resolvePackageQueryMetadata(parsed.queryMetadata, parsed.materialization);
12617
12677
  const manifestWarnings = [
12618
12678
  ...scope.warnings,
12619
- ...packageMaterializationWarnings(parsed.materialization)
12679
+ ...queryMetadata.warnings,
12680
+ ...queryMetadataParseWarnings(queryMetadata.queryMetadata, queryMetadata.home)
12620
12681
  ];
12621
12682
  return {
12622
12683
  name: parsed.name,
@@ -12624,7 +12685,7 @@ async function readPackageMetadata(packagePath) {
12624
12685
  explores: Array.isArray(parsed.explores) ? parsed.explores.map(normalizeModelPath) : undefined,
12625
12686
  queryableSources: parsed.queryableSources === "all" ? "all" : "declared",
12626
12687
  manifestLocation: typeof parsed.manifestLocation === "string" ? parsed.manifestLocation : null,
12627
- materialization: parsePackageMaterialization(parsed.materialization),
12688
+ materialization: materializationWithQueryMetadata(parsePackageMaterialization(parsed.materialization), queryMetadata.queryMetadata),
12628
12689
  scope: scope.scope,
12629
12690
  manifestWarnings: manifestWarnings.length > 0 ? manifestWarnings : undefined
12630
12691
  };
@@ -12675,8 +12736,8 @@ function extractSources(modelDef, givens) {
12675
12736
  function extractQueries(modelDef) {
12676
12737
  return extractQueriesFromModelDef(modelDef);
12677
12738
  }
12678
- function buildRuntimeForModel(job, malloyConfig, jobId) {
12679
- const urlReader = new HackyDataStylesAccumulator(makeWorkerUrlReader(jobId));
12739
+ function buildRuntimeForModel(job, malloyConfig) {
12740
+ const urlReader = new HackyDataStylesAccumulator(makeWorkerUrlReader(job));
12680
12741
  const runtime = new Runtime({
12681
12742
  urlReader,
12682
12743
  config: malloyConfig,
@@ -12692,7 +12753,7 @@ async function compileMalloyModel(job, malloyConfig, modelPath) {
12692
12753
  const fullPath = path2.join(job.packagePath, modelPath);
12693
12754
  const modelURL = pathToFileURL(fullPath);
12694
12755
  const importBaseURL = new URL(".", modelURL);
12695
- const { runtime, urlReader } = buildRuntimeForModel(job, malloyConfig, job.requestId);
12756
+ const { runtime, urlReader } = buildRuntimeForModel(job, malloyConfig);
12696
12757
  const mm = runtime.loadModel(modelURL, { importBaseURL });
12697
12758
  const compiled = await mm.getModel();
12698
12759
  const modelDef = compiled._modelDef;
@@ -12714,7 +12775,8 @@ async function compileMalloyModel(job, malloyConfig, modelPath) {
12714
12775
  filterMap: Array.from(filterMap.entries()),
12715
12776
  givens,
12716
12777
  dataStyles: urlReader.getHackyAccumulatedDataStyles(),
12717
- compileDurationMs: performance.now() - compileStart
12778
+ compileDurationMs: performance.now() - compileStart,
12779
+ problems: job.collectProblems ? compiled.problems : undefined
12718
12780
  };
12719
12781
  }
12720
12782
  async function compileNotebookModel(job, malloyConfig, modelPath) {
@@ -12722,7 +12784,7 @@ async function compileNotebookModel(job, malloyConfig, modelPath) {
12722
12784
  const fullPath = path2.join(job.packagePath, modelPath);
12723
12785
  const modelURL = pathToFileURL(fullPath);
12724
12786
  const importBaseURL = new URL(".", modelURL);
12725
- const { runtime, urlReader } = buildRuntimeForModel(job, malloyConfig, job.requestId);
12787
+ const { runtime, urlReader } = buildRuntimeForModel(job, malloyConfig);
12726
12788
  const fileContents = await fs2.promises.readFile(modelURL, "utf8");
12727
12789
  const parse = MalloySQLParser.parse(fileContents, modelPath);
12728
12790
  let mm;
@@ -12799,8 +12861,10 @@ async function compileNotebookModel(job, malloyConfig, modelPath) {
12799
12861
  let finalSourceInfos;
12800
12862
  let finalFilterMap;
12801
12863
  let finalGivens;
12864
+ let finalProblems;
12802
12865
  if (mm) {
12803
12866
  const compiled = await mm.getModel();
12867
+ finalProblems = compiled.problems;
12804
12868
  finalModelDef = compiled._modelDef;
12805
12869
  const malloyGivens = Array.from(compiled.givens.values());
12806
12870
  finalGivens = malloyGivens.length > 0 ? malloyGivens.map((g) => malloyGivenToApi(g)) : undefined;
@@ -12825,7 +12889,8 @@ async function compileNotebookModel(job, malloyConfig, modelPath) {
12825
12889
  givens: finalGivens,
12826
12890
  notebookCells,
12827
12891
  dataStyles: urlReader.getHackyAccumulatedDataStyles(),
12828
- compileDurationMs: performance.now() - compileStart
12892
+ compileDurationMs: performance.now() - compileStart,
12893
+ problems: job.collectProblems ? finalProblems : undefined
12829
12894
  };
12830
12895
  }
12831
12896
  async function compileOneModel(job, malloyConfig, modelPath) {
@@ -12859,6 +12924,10 @@ async function loadPackage(job) {
12859
12924
  const malloyConfig = buildWorkerMalloyConfig(job);
12860
12925
  const allFiles = await listPackageFiles(job.packagePath);
12861
12926
  const modelPaths = filterModelPaths(allFiles);
12927
+ const replacementMatchedExisting = job.replacement ? modelPaths.includes(job.replacement.modelPath) : undefined;
12928
+ if (job.replacement && !replacementMatchedExisting) {
12929
+ modelPaths.push(job.replacement.modelPath);
12930
+ }
12862
12931
  const compileRegionStart = performance.now();
12863
12932
  schemaWait.begin(job.requestId);
12864
12933
  const models = await Promise.all(modelPaths.map((modelPath) => compileOneModel(job, malloyConfig, modelPath)));
@@ -12869,6 +12938,7 @@ async function loadPackage(job) {
12869
12938
  requestId: job.requestId,
12870
12939
  packageMetadata,
12871
12940
  models,
12941
+ replacementMatchedExisting,
12872
12942
  loadDurationMs: loadEnd - loadStart,
12873
12943
  timings: {
12874
12944
  compileDurationMs: Math.max(0, loadEnd - compileRegionStart - schemaFetchDurationMs),