@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
@@ -11,7 +11,7 @@
11
11
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
12
12
  />
13
13
  <title>Malloy Publisher</title>
14
- <script type="module" crossorigin src="/assets/index-BeNwIeYQ.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-DqiJ0bWp.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="/assets/index-5eLCcNmP.css">
16
16
  </head>
17
17
  <body>
@@ -11386,16 +11386,156 @@ var init_logger = __esm(() => {
11386
11386
  DISABLE_RESPONSE_LOGGING = process.env.DISABLE_RESPONSE_LOGGING === "true" || process.env.DISABLE_RESPONSE_LOGGING === "1";
11387
11387
  });
11388
11388
 
11389
+ // src/errors.ts
11390
+ import { MalloyError } from "@malloydata/malloy";
11391
+ function internalErrorToHttpError(error) {
11392
+ if (error instanceof BadRequestError) {
11393
+ return httpError(400, error.message);
11394
+ } else if (error instanceof FrozenConfigError) {
11395
+ return httpError(403, error.message);
11396
+ } else if (error instanceof AccessDeniedError) {
11397
+ return httpError(403, error.message);
11398
+ } else if (error instanceof EnvironmentNotFoundError) {
11399
+ return httpError(404, error.message);
11400
+ } else if (error instanceof PackageNotFoundError) {
11401
+ return httpError(404, error.message);
11402
+ } else if (error instanceof ModelNotFoundError) {
11403
+ return httpError(404, error.message);
11404
+ } else if (error instanceof MalloyError) {
11405
+ return httpError(400, error.message);
11406
+ } else if (error instanceof ConnectionNotFoundError) {
11407
+ return httpError(404, error.message);
11408
+ } else if (error instanceof ConnectionAuthError) {
11409
+ return httpError(422, error.message);
11410
+ } else if (error instanceof ModelCompilationError) {
11411
+ return httpError(424, error.message);
11412
+ } else if (error instanceof ConnectionError) {
11413
+ return httpError(502, error.message);
11414
+ } else if (error instanceof MaterializationNotFoundError) {
11415
+ return httpError(404, error.message);
11416
+ } else if (error instanceof MaterializationConflictError) {
11417
+ return httpError(409, error.message);
11418
+ } else if (error instanceof InvalidStateTransitionError) {
11419
+ return httpError(409, error.message);
11420
+ } else if (error instanceof ServiceUnavailableError) {
11421
+ return httpError(503, error.message);
11422
+ } else if (error instanceof PayloadTooLargeError) {
11423
+ return httpError(413, error.message);
11424
+ } else if (error instanceof QueryTimeoutError) {
11425
+ return httpError(504, error.message);
11426
+ } else {
11427
+ return httpError(500, error.message);
11428
+ }
11429
+ }
11430
+ function httpError(code, message) {
11431
+ return {
11432
+ status: code,
11433
+ json: {
11434
+ code,
11435
+ message
11436
+ }
11437
+ };
11438
+ }
11439
+ var NotImplementedError, BadRequestError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, ConnectionNotFoundError, ConnectionError, ConnectionAuthError, ModelCompilationError, FrozenConfigError, AccessDeniedError, MaterializationNotFoundError, MaterializationConflictError, InvalidStateTransitionError, ServiceUnavailableError, PayloadTooLargeError, QueryTimeoutError;
11440
+ var init_errors = __esm(() => {
11441
+ init_constants();
11442
+ NotImplementedError = class NotImplementedError extends Error {
11443
+ constructor(message) {
11444
+ super(message);
11445
+ }
11446
+ };
11447
+ BadRequestError = class BadRequestError extends Error {
11448
+ constructor(message) {
11449
+ super(message);
11450
+ }
11451
+ };
11452
+ EnvironmentNotFoundError = class EnvironmentNotFoundError extends Error {
11453
+ constructor(message) {
11454
+ super(message);
11455
+ }
11456
+ };
11457
+ PackageNotFoundError = class PackageNotFoundError extends Error {
11458
+ constructor(message) {
11459
+ super(message);
11460
+ }
11461
+ };
11462
+ ModelNotFoundError = class ModelNotFoundError extends Error {
11463
+ constructor(message) {
11464
+ super(message);
11465
+ }
11466
+ };
11467
+ ConnectionNotFoundError = class ConnectionNotFoundError extends Error {
11468
+ constructor(message) {
11469
+ super(message);
11470
+ }
11471
+ };
11472
+ ConnectionError = class ConnectionError extends Error {
11473
+ constructor(message) {
11474
+ super(message);
11475
+ }
11476
+ };
11477
+ ConnectionAuthError = class ConnectionAuthError extends Error {
11478
+ constructor(message) {
11479
+ super(message);
11480
+ }
11481
+ };
11482
+ ModelCompilationError = class ModelCompilationError extends Error {
11483
+ constructor(error) {
11484
+ super(error.message);
11485
+ }
11486
+ };
11487
+ FrozenConfigError = class FrozenConfigError extends Error {
11488
+ constructor(message = `Publisher config can't be updated when ${PUBLISHER_CONFIG_NAME} has { "frozenConfig": true }`) {
11489
+ super(message);
11490
+ }
11491
+ };
11492
+ AccessDeniedError = class AccessDeniedError extends Error {
11493
+ constructor(message) {
11494
+ super(message);
11495
+ this.name = "AccessDeniedError";
11496
+ }
11497
+ };
11498
+ MaterializationNotFoundError = class MaterializationNotFoundError extends Error {
11499
+ constructor(message) {
11500
+ super(message);
11501
+ }
11502
+ };
11503
+ MaterializationConflictError = class MaterializationConflictError extends Error {
11504
+ constructor(message) {
11505
+ super(message);
11506
+ }
11507
+ };
11508
+ InvalidStateTransitionError = class InvalidStateTransitionError extends Error {
11509
+ constructor(message) {
11510
+ super(message);
11511
+ }
11512
+ };
11513
+ ServiceUnavailableError = class ServiceUnavailableError extends Error {
11514
+ constructor(message) {
11515
+ super(message);
11516
+ }
11517
+ };
11518
+ PayloadTooLargeError = class PayloadTooLargeError extends Error {
11519
+ constructor(message) {
11520
+ super(message);
11521
+ }
11522
+ };
11523
+ QueryTimeoutError = class QueryTimeoutError extends Error {
11524
+ constructor(message) {
11525
+ super(message);
11526
+ }
11527
+ };
11528
+ });
11529
+
11389
11530
  // src/package_load/package_load_worker.ts
11390
11531
  init_constants();
11391
11532
  var import_recursive_readdir = __toESM(require_recursive_readdir(), 1);
11392
11533
  import {
11393
11534
  contextOverlay,
11394
11535
  MalloyConfig,
11395
- MalloyError,
11536
+ MalloyError as MalloyError2,
11396
11537
  modelDefToModelInfo,
11397
- Runtime,
11398
- isSourceDef
11538
+ Runtime
11399
11539
  } from "@malloydata/malloy";
11400
11540
  import {
11401
11541
  MalloySQLParser,
@@ -11454,6 +11594,157 @@ class HackyDataStylesAccumulator {
11454
11594
  }
11455
11595
  }
11456
11596
 
11597
+ // src/package_load/package_load_worker.ts
11598
+ init_errors();
11599
+
11600
+ // src/service/authorize.ts
11601
+ init_errors();
11602
+ var SOURCE_PREFIX = "#(authorize)";
11603
+ var FILE_PREFIX = "##(authorize)";
11604
+ function buildAuthorizeProbe(exprs) {
11605
+ const selects = exprs.map((expr, i) => `__auth_${i} is (${expr})`).join(`
11606
+ `);
11607
+ return `run: duckdb.sql("SELECT 1 AS __authorize_probe_row") -> {
11608
+ select:
11609
+ ${selects}
11610
+ limit: 1
11611
+ }`;
11612
+ }
11613
+ function isProbeTrue(cell) {
11614
+ return cell === true || cell === 1 || cell === "true";
11615
+ }
11616
+ async function evaluateAuthorize(executor, exprs, givens) {
11617
+ for (const expr of exprs) {
11618
+ try {
11619
+ const result = await executor.loadQuery(buildAuthorizeProbe([expr])).run({ rowLimit: 1, givens });
11620
+ const row = result?.data?.value?.[0];
11621
+ if (row && isProbeTrue(row.__auth_0)) {
11622
+ return true;
11623
+ }
11624
+ } catch {
11625
+ continue;
11626
+ }
11627
+ }
11628
+ return false;
11629
+ }
11630
+ async function validateAuthorizeProbes(compiler, sources) {
11631
+ for (const source of sources) {
11632
+ const exprs = source.authorize;
11633
+ if (!exprs || exprs.length === 0)
11634
+ continue;
11635
+ try {
11636
+ await compiler.loadQuery(buildAuthorizeProbe(exprs)).getPreparedQuery();
11637
+ } catch (err) {
11638
+ const detail = err instanceof Error ? err.message : String(err);
11639
+ throw new ModelCompilationError({
11640
+ message: `Invalid #(authorize) annotation on source "${source.name ?? "(unnamed)"}" [${exprs.join(" | ")}]: ${detail}`
11641
+ });
11642
+ }
11643
+ }
11644
+ }
11645
+ function parseAuthorizeAnnotation(annotation) {
11646
+ const trimmed = annotation.trim();
11647
+ let body;
11648
+ if (trimmed.startsWith(FILE_PREFIX)) {
11649
+ body = trimmed.slice(FILE_PREFIX.length).trim();
11650
+ } else if (trimmed.startsWith(SOURCE_PREFIX)) {
11651
+ body = trimmed.slice(SOURCE_PREFIX.length).trim();
11652
+ } else {
11653
+ return null;
11654
+ }
11655
+ return unwrapQuotedExpression(body);
11656
+ }
11657
+ function collectAuthorizeExprs(annotations) {
11658
+ const exprs = [];
11659
+ for (const annotation of annotations) {
11660
+ const expr = parseAuthorizeAnnotation(annotation);
11661
+ if (expr !== null) {
11662
+ exprs.push(expr);
11663
+ }
11664
+ }
11665
+ return exprs;
11666
+ }
11667
+ function unwrapQuotedExpression(body) {
11668
+ if (body.length < 2 || body[0] !== '"') {
11669
+ throw new Error(`authorize annotation expression must be a double-quoted string, got: ${body || "(empty)"}`);
11670
+ }
11671
+ let expr = "";
11672
+ let i = 1;
11673
+ let closed = false;
11674
+ for (;i < body.length; i++) {
11675
+ const ch = body[i];
11676
+ if (ch === "\\" && i + 1 < body.length) {
11677
+ const next = body[i + 1];
11678
+ if (next === '"' || next === "\\") {
11679
+ expr += next;
11680
+ i++;
11681
+ continue;
11682
+ }
11683
+ }
11684
+ if (ch === '"') {
11685
+ closed = true;
11686
+ i++;
11687
+ break;
11688
+ }
11689
+ expr += ch;
11690
+ }
11691
+ if (!closed) {
11692
+ throw new Error(`authorize annotation has mismatched quotes: ${body}`);
11693
+ }
11694
+ const rest = body.slice(i).trim();
11695
+ if (rest.length > 0) {
11696
+ throw new Error(`authorize annotation has unexpected content after the expression: ${rest}`);
11697
+ }
11698
+ if (expr.trim().length === 0) {
11699
+ throw new Error("authorize annotation has an empty expression body");
11700
+ }
11701
+ return expr;
11702
+ }
11703
+
11704
+ // src/service/source_extraction.ts
11705
+ import {
11706
+ isSourceDef
11707
+ } from "@malloydata/malloy";
11708
+
11709
+ // src/service/annotations.ts
11710
+ import { Annotations } from "@malloydata/malloy";
11711
+ function isReservedRoute(route) {
11712
+ return route === "" || !/[\p{L}\p{N}]/u.test(route);
11713
+ }
11714
+ function modelAnnotations(modelDef) {
11715
+ const registry = modelDef.modelAnnotations ?? {};
11716
+ const visited = new Set;
11717
+ const order = [];
11718
+ const visit = (id) => {
11719
+ if (visited.has(id))
11720
+ return;
11721
+ visited.add(id);
11722
+ const entry = registry[id];
11723
+ if (!entry)
11724
+ return;
11725
+ for (const dep of entry.inheritsFrom)
11726
+ visit(dep);
11727
+ order.push(id);
11728
+ };
11729
+ visit(modelDef.modelID);
11730
+ let folded;
11731
+ for (const id of order) {
11732
+ const own = registry[id].ownNotes;
11733
+ if (!own.notes?.length && !own.blockNotes?.length)
11734
+ continue;
11735
+ folded = {
11736
+ notes: own.notes,
11737
+ blockNotes: own.blockNotes,
11738
+ inherits: folded
11739
+ };
11740
+ }
11741
+ return folded ?? {};
11742
+ }
11743
+ function annotationTexts(annote) {
11744
+ const texts = new Annotations(annote).texts();
11745
+ return texts.length > 0 ? texts : undefined;
11746
+ }
11747
+
11457
11748
  // src/service/filter.ts
11458
11749
  var VALID_FILTER_TYPES = new Set([
11459
11750
  "equal",
@@ -11605,7 +11896,8 @@ function injectFilterRefinement(query, filterClause) {
11605
11896
  if (!filterClause) {
11606
11897
  return query;
11607
11898
  }
11608
- return `${query.trimEnd()} + {where: ${filterClause}}`;
11899
+ return `${query.trimEnd()}
11900
+ + {where: ${filterClause}}`;
11609
11901
  }
11610
11902
 
11611
11903
  class FilterValidationError extends Error {
@@ -11644,6 +11936,81 @@ function tokenize(input) {
11644
11936
  return tokens;
11645
11937
  }
11646
11938
 
11939
+ // src/service/source_extraction.ts
11940
+ function extractSourcesFromModelDef(modelDef, givens, onParseError) {
11941
+ const filterMap = new Map;
11942
+ const authorizeMap = new Map;
11943
+ const fileLevelAuthorize = collectAuthorizeExprs((modelAnnotations(modelDef).notes ?? []).map((note) => note.text));
11944
+ const sources = Object.values(modelDef.contents).filter((obj) => isSourceDef(obj)).map((sourceObj) => {
11945
+ const struct = sourceObj;
11946
+ const sourceName = struct.as || struct.name;
11947
+ const annotations = annotationTexts(struct.annotations);
11948
+ const collected = [];
11949
+ let cur = struct.annotations;
11950
+ while (cur) {
11951
+ if (cur.blockNotes) {
11952
+ collected.push(cur.blockNotes.map((note) => note.text));
11953
+ }
11954
+ cur = cur.inherits;
11955
+ }
11956
+ const allAnnotations = collected.reverse().flat();
11957
+ let filters;
11958
+ if (allAnnotations.length > 0) {
11959
+ try {
11960
+ const parsed = parseFilters(allAnnotations);
11961
+ if (parsed.length > 0) {
11962
+ filterMap.set(sourceName, parsed);
11963
+ const fields = struct.fields;
11964
+ filters = parsed.map((f) => {
11965
+ const field = fields.find((fd) => (fd.as || fd.name) === f.dimension);
11966
+ return {
11967
+ name: f.name,
11968
+ dimension: f.dimension,
11969
+ type: f.type,
11970
+ implicit: f.implicit,
11971
+ required: f.required,
11972
+ dimensionType: field?.type
11973
+ };
11974
+ });
11975
+ }
11976
+ } catch (err) {
11977
+ onParseError?.(sourceName, err);
11978
+ }
11979
+ }
11980
+ const ownNotes = (struct.annotations?.blockNotes ?? []).map((note) => note.text);
11981
+ const effective = [
11982
+ ...fileLevelAuthorize,
11983
+ ...collectAuthorizeExprs(ownNotes)
11984
+ ];
11985
+ let authorize;
11986
+ if (effective.length > 0) {
11987
+ authorizeMap.set(sourceName, effective);
11988
+ authorize = effective;
11989
+ }
11990
+ const views = struct.fields.filter((field) => field.type === "turtle").filter((turtle) => turtle.pipeline.map((stage) => stage.type).every((type) => type === "reduce")).map((turtle) => ({
11991
+ name: turtle.as || turtle.name,
11992
+ annotations: annotationTexts(turtle.annotations)
11993
+ }));
11994
+ return {
11995
+ name: sourceName,
11996
+ annotations,
11997
+ views,
11998
+ filters,
11999
+ givens,
12000
+ authorize
12001
+ };
12002
+ });
12003
+ return { sources, filterMap, authorizeMap };
12004
+ }
12005
+ function extractQueriesFromModelDef(modelDef) {
12006
+ const isNamedQuery = (obj) => obj.type === "query";
12007
+ return Object.values(modelDef.contents).filter(isNamedQuery).map((queryObj) => ({
12008
+ name: queryObj.as || queryObj.name,
12009
+ sourceName: typeof queryObj.structRef === "string" ? queryObj.structRef : undefined,
12010
+ annotations: annotationTexts(queryObj.annotations)
12011
+ }));
12012
+ }
12013
+
11647
12014
  // src/service/given.ts
11648
12015
  function malloyGivenToApi(given) {
11649
12016
  const type = given.type;
@@ -11651,7 +12018,8 @@ function malloyGivenToApi(given) {
11651
12018
  return {
11652
12019
  name: given.name,
11653
12020
  type: renderedType,
11654
- annotations: given.getTaglines(/^#\(/)
12021
+ annotations: given.annotations.forRoute(undefined).filter((note) => !isReservedRoute(note.route)).map((note) => note.text),
12022
+ default: given._internal?.defaultText
11655
12023
  };
11656
12024
  }
11657
12025
 
@@ -11788,9 +12156,6 @@ function serializeFetchOptions(options) {
11788
12156
  if (options.refreshTimestamp !== undefined) {
11789
12157
  out.refreshTimestamp = options.refreshTimestamp;
11790
12158
  }
11791
- if (options.modelAnnotation !== undefined) {
11792
- out.modelAnnotation = options.modelAnnotation;
11793
- }
11794
12159
  return out;
11795
12160
  }
11796
12161
  function makeWorkerUrlReader(jobId) {
@@ -11888,62 +12253,12 @@ function appendLocalSourceInfos(modelDef, target, importedNames) {
11888
12253
  target.push(source);
11889
12254
  }
11890
12255
  }
11891
- function extractSources(modelPath, modelDef, givens) {
11892
- const filterMap = new Map;
11893
- const sources = Object.values(modelDef.contents).filter((obj) => isSourceDef(obj)).map((sourceObj) => {
11894
- const sourceName = sourceObj.as || sourceObj.name;
11895
- const annotations = sourceObj.annotation?.blockNotes?.filter((note) => note.at.url.includes(modelPath)).map((note) => note.text);
11896
- const collected = [];
11897
- let cur = sourceObj.annotation;
11898
- while (cur) {
11899
- if (cur.blockNotes) {
11900
- collected.push(cur.blockNotes.map((note) => note.text));
11901
- }
11902
- cur = cur.inherits;
11903
- }
11904
- const allAnnotations = collected.reverse().flat();
11905
- let filters;
11906
- if (allAnnotations.length > 0) {
11907
- try {
11908
- const parsed = parseFilters(allAnnotations);
11909
- if (parsed.length > 0) {
11910
- filterMap.set(sourceName, parsed);
11911
- const fields = sourceObj.fields;
11912
- filters = parsed.map((f) => {
11913
- const field = fields.find((fd) => (fd.as || fd.name) === f.dimension);
11914
- return {
11915
- name: f.name,
11916
- dimension: f.dimension,
11917
- type: f.type,
11918
- implicit: f.implicit,
11919
- required: f.required,
11920
- dimensionType: field?.type
11921
- };
11922
- });
11923
- }
11924
- } catch {}
11925
- }
11926
- const views = sourceObj.fields.filter((f) => f.type === "turtle").filter((turtle) => turtle.pipeline.map((stage) => stage.type).every((type) => type === "reduce")).map((turtle) => ({
11927
- name: turtle.as || turtle.name,
11928
- annotations: turtle?.annotation?.blockNotes?.filter((note) => note.at.url.includes(modelPath)).map((note) => note.text)
11929
- }));
11930
- return {
11931
- name: sourceName,
11932
- annotations,
11933
- views,
11934
- filters,
11935
- givens
11936
- };
11937
- });
12256
+ function extractSources(modelDef, givens) {
12257
+ const { sources, filterMap } = extractSourcesFromModelDef(modelDef, givens);
11938
12258
  return { sources, filterMap };
11939
12259
  }
11940
- function extractQueries(modelPath, modelDef) {
11941
- const isNamedQuery = (obj) => obj.type === "query";
11942
- return Object.values(modelDef.contents).filter(isNamedQuery).map((q) => ({
11943
- name: q.as || q.name,
11944
- sourceName: typeof q.structRef === "string" ? q.structRef : undefined,
11945
- annotations: q?.annotation?.blockNotes?.filter((note) => note.at.url.includes(modelPath)).map((note) => note.text)
11946
- }));
12260
+ function extractQueries(modelDef) {
12261
+ return extractQueriesFromModelDef(modelDef);
11947
12262
  }
11948
12263
  function buildRuntimeForModel(job, malloyConfig, jobId) {
11949
12264
  const urlReader = new HackyDataStylesAccumulator(makeWorkerUrlReader(jobId));
@@ -11970,8 +12285,9 @@ async function compileMalloyModel(job, malloyConfig, modelPath) {
11970
12285
  const givens = malloyGivens.length > 0 ? malloyGivens.map((g) => malloyGivenToApi(g)) : undefined;
11971
12286
  const { sourceInfos, importedNames } = await collectImportedSourceInfos(modelDef, runtime, importBaseURL);
11972
12287
  appendLocalSourceInfos(modelDef, sourceInfos, importedNames);
11973
- const { sources, filterMap } = extractSources(modelPath, modelDef, givens);
11974
- const queries = extractQueries(modelPath, modelDef);
12288
+ const { sources, filterMap } = extractSources(modelDef, givens);
12289
+ const queries = extractQueries(modelDef);
12290
+ await validateAuthorizeProbes(mm, sources);
11975
12291
  return {
11976
12292
  modelPath,
11977
12293
  modelType: "model",
@@ -12076,10 +12392,11 @@ async function compileNotebookModel(job, malloyConfig, modelPath) {
12076
12392
  const collected = await collectImportedSourceInfos(finalModelDef, runtime, importBaseURL);
12077
12393
  appendLocalSourceInfos(finalModelDef, collected.sourceInfos, collected.importedNames);
12078
12394
  finalSourceInfos = collected.sourceInfos;
12079
- const extracted = extractSources(modelPath, finalModelDef, finalGivens);
12395
+ const extracted = extractSources(finalModelDef, finalGivens);
12080
12396
  finalSources = extracted.sources;
12081
12397
  finalFilterMap = extracted.filterMap;
12082
- finalQueries = extractQueries(modelPath, finalModelDef);
12398
+ finalQueries = extractQueries(finalModelDef);
12399
+ await validateAuthorizeProbes(mm, finalSources);
12083
12400
  }
12084
12401
  return {
12085
12402
  modelPath,
@@ -12137,7 +12454,7 @@ async function loadPackage(job) {
12137
12454
  };
12138
12455
  }
12139
12456
  function serializeError(error) {
12140
- if (error instanceof MalloyError) {
12457
+ if (error instanceof MalloyError2) {
12141
12458
  return {
12142
12459
  name: error.name,
12143
12460
  message: error.message,
@@ -12146,6 +12463,14 @@ function serializeError(error) {
12146
12463
  isCompilationError: true
12147
12464
  };
12148
12465
  }
12466
+ if (error instanceof ModelCompilationError) {
12467
+ return {
12468
+ name: error.name,
12469
+ message: error.message,
12470
+ stack: error.stack,
12471
+ isCompilationError: true
12472
+ };
12473
+ }
12149
12474
  if (error instanceof Error) {
12150
12475
  return {
12151
12476
  name: error.name,