@malloy-publisher/server 0.9.4 → 0.9.5

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 (23) hide show
  1. package/dist/app/api-doc.yaml +104 -8
  2. package/dist/app/assets/{EnvironmentPage-uo3igcP9.js → EnvironmentPage-wGTml4WZ.js} +1 -1
  3. package/dist/app/assets/{HomePage-0OQVchl4.js → HomePage-BPFJHBxN.js} +1 -1
  4. package/dist/app/assets/{MainPage-D4SOACdm.js → MainPage-CNLgQje2.js} +1 -1
  5. package/dist/app/assets/{ModelPage-B5CpdEDl.js → ModelPage-Br6I_s4J.js} +2 -2
  6. package/dist/app/assets/{PackagePage-BzUfTQKy.js → PackagePage-B6lmG1Uq.js} +1 -1
  7. package/dist/app/assets/{RenderedResult-DwB0-9Yx.es-1MzhmBXH.js → RenderedResult-BUb2Xvr2.es-17Y63pbB.js} +14 -2
  8. package/dist/app/assets/{RouteError-BXcrPjvD.js → RouteError-B4yUUZFj.js} +1 -1
  9. package/dist/app/assets/{ThemeEditorPage-FpYg5NPt.js → ThemeEditorPage-CjK8EVnV.js} +1 -1
  10. package/dist/app/assets/{ToggleButtonGroup-Vkkjsbxx.js → ToggleButtonGroup-BKiI79mw.js} +1 -1
  11. package/dist/app/assets/{documentRoutes-BWHzvbNO.js → documentRoutes-D_78AAbq.js} +1 -1
  12. package/dist/app/assets/{index-DFvJYp4Q.js → index-B3woRPfQ.js} +1 -1
  13. package/dist/app/assets/{index-BZEvIUf-.js → index-BIqIsMFr.js} +100 -100
  14. package/dist/app/assets/{index-CprgMbE_.js → index-CfX148tj.js} +1 -1
  15. package/dist/app/assets/{index-NVPzfbUZ.js → index-dQ3jNgKw.js} +1 -1
  16. package/dist/app/assets/index.es-Bhhg6pWY.js +195 -0
  17. package/dist/app/index.html +1 -1
  18. package/dist/package_load_worker.mjs +128 -70
  19. package/dist/runtime/publisher.js +1 -1
  20. package/dist/server.mjs +3176 -2776
  21. package/dist/sshcrypto-cqb52edz.node +0 -0
  22. package/package.json +1 -1
  23. package/dist/app/assets/index.es-D2Ts8adM.js +0 -195
@@ -16,7 +16,7 @@ SPDX-License-Identifier: MIT
16
16
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
17
17
  />
18
18
  <title>Malloy Publisher</title>
19
- <script type="module" crossorigin src="/assets/index-BZEvIUf-.js"></script>
19
+ <script type="module" crossorigin src="/assets/index-BIqIsMFr.js"></script>
20
20
  <link rel="stylesheet" crossorigin href="/assets/index-DUqldpo0.css">
21
21
  </head>
22
22
  <body>
@@ -1108,10 +1108,14 @@ var require_recursive_readdir = __commonJS((exports, module) => {
1108
1108
 
1109
1109
  // src/constants.ts
1110
1110
  import os from "os";
1111
+ import path from "path";
1112
+ function installRecordPath(environmentPath, packageName) {
1113
+ return path.join(environmentPath, PACKAGE_INSTALL_RECORDS_DIR, `${packageName}.json`);
1114
+ }
1111
1115
  function normalizeModelPath(p) {
1112
1116
  return p.replace(/\\/g, "/").replace(/^\.\//, "");
1113
1117
  }
1114
- var API_PREFIX = "/api/v0", README_NAME = "README.md", PUBLISHER_CONFIG_NAME = "publisher.config.json", PACKAGE_MANIFEST_NAME = "publisher.json", MODEL_FILE_SUFFIX = ".malloy", NOTEBOOK_FILE_SUFFIX = ".malloynb", INDEX_MODEL_NAME = "index.malloy", DEFAULT_QUERY_ROW_LIMIT = 1000, DEFAULT_MAX_QUERY_ROWS = 1e5, DEFAULT_MAX_RESPONSE_BYTES = 50000000, DEFAULT_QUERY_TIMEOUT_MS = 300000, DEFAULT_MAX_CONCURRENT_QUERIES = 32, TEMP_DIR_PATH, PUBLISHER_DATA_DIR = "publisher_data";
1118
+ var API_PREFIX = "/api/v0", README_NAME = "README.md", PUBLISHER_CONFIG_NAME = "publisher.config.json", PACKAGE_MANIFEST_NAME = "publisher.json", PACKAGE_INSTALL_RECORDS_DIR = ".install-records", MODEL_FILE_SUFFIX = ".malloy", NOTEBOOK_FILE_SUFFIX = ".malloynb", INDEX_MODEL_NAME = "index.malloy", DEFAULT_QUERY_ROW_LIMIT = 1000, DEFAULT_MAX_QUERY_ROWS = 1e5, DEFAULT_MAX_RESPONSE_BYTES = 50000000, DEFAULT_QUERY_TIMEOUT_MS = 300000, DEFAULT_MAX_CONCURRENT_QUERIES = 32, TEMP_DIR_PATH, PUBLISHER_DATA_DIR = "publisher_data";
1115
1119
  var init_constants = __esm(() => {
1116
1120
  TEMP_DIR_PATH = os.tmpdir();
1117
1121
  });
@@ -11028,7 +11032,7 @@ var require_tail_file = __commonJS((exports, module) => {
11028
11032
  // ../../node_modules/winston/lib/winston/transports/file.js
11029
11033
  var require_file = __commonJS((exports, module) => {
11030
11034
  var fs = __require("fs");
11031
- var path = __require("path");
11035
+ var path2 = __require("path");
11032
11036
  var asyncSeries = require_series();
11033
11037
  var zlib = __require("zlib");
11034
11038
  var { MESSAGE } = require_triple_beam();
@@ -11053,14 +11057,14 @@ var require_file = __commonJS((exports, module) => {
11053
11057
  this._onError = this._onError.bind(this);
11054
11058
  if (options.filename || options.dirname) {
11055
11059
  throwIf("filename or dirname", "stream");
11056
- this._basename = this.filename = options.filename ? path.basename(options.filename) : "winston.log";
11057
- this.dirname = options.dirname || path.dirname(options.filename);
11060
+ this._basename = this.filename = options.filename ? path2.basename(options.filename) : "winston.log";
11061
+ this.dirname = options.dirname || path2.dirname(options.filename);
11058
11062
  this.options = options.options || { flags: "a" };
11059
11063
  } else if (options.stream) {
11060
11064
  console.warn("options.stream will be removed in winston@4. Use winston.transports.Stream");
11061
11065
  throwIf("stream", "filename", "maxsize");
11062
11066
  this._dest = this._stream.pipe(this._setupStream(options.stream));
11063
- this.dirname = path.dirname(this._dest.path);
11067
+ this.dirname = path2.dirname(this._dest.path);
11064
11068
  } else {
11065
11069
  throw new Error("Cannot log to file without filename or stream.");
11066
11070
  }
@@ -11190,7 +11194,7 @@ var require_file = __commonJS((exports, module) => {
11190
11194
  options = {};
11191
11195
  }
11192
11196
  options = normalizeQuery(options);
11193
- const file = path.join(this.dirname, this.filename);
11197
+ const file = path2.join(this.dirname, this.filename);
11194
11198
  let buff = "";
11195
11199
  let results = [];
11196
11200
  let row = 0;
@@ -11290,7 +11294,7 @@ var require_file = __commonJS((exports, module) => {
11290
11294
  }
11291
11295
  }
11292
11296
  stream(options = {}) {
11293
- const file = path.join(this.dirname, this.filename);
11297
+ const file = path2.join(this.dirname, this.filename);
11294
11298
  const stream = new Stream;
11295
11299
  const tail = {
11296
11300
  file,
@@ -11333,7 +11337,7 @@ var require_file = __commonJS((exports, module) => {
11333
11337
  }
11334
11338
  stat(callback) {
11335
11339
  const target = this._getFile();
11336
- const fullpath = path.join(this.dirname, target);
11340
+ const fullpath = path2.join(this.dirname, target);
11337
11341
  fs.stat(fullpath, (err, stat) => {
11338
11342
  if (err && err.code === "ENOENT") {
11339
11343
  debug("ENOENT ok", fullpath);
@@ -11394,7 +11398,7 @@ var require_file = __commonJS((exports, module) => {
11394
11398
  }
11395
11399
  }
11396
11400
  _createStream(source) {
11397
- const fullpath = path.join(this.dirname, this.filename);
11401
+ const fullpath = path2.join(this.dirname, this.filename);
11398
11402
  debug("create stream start", fullpath, this.options);
11399
11403
  const dest = fs.createWriteStream(fullpath, this.options).on("error", (err) => debug(err)).on("close", () => debug("close", dest.path, dest.bytesWritten)).on("open", () => {
11400
11404
  debug("file open ok", fullpath);
@@ -11414,13 +11418,13 @@ var require_file = __commonJS((exports, module) => {
11414
11418
  }
11415
11419
  _incFile(callback) {
11416
11420
  debug("_incFile", this.filename);
11417
- const ext = path.extname(this._basename);
11418
- const basename = path.basename(this._basename, ext);
11421
+ const ext = path2.extname(this._basename);
11422
+ const basename = path2.basename(this._basename, ext);
11419
11423
  const tasks = [];
11420
11424
  if (this.zippedArchive) {
11421
11425
  tasks.push(function(cb) {
11422
11426
  const num = this._created > 0 && !this.tailable ? this._created : "";
11423
- this._compressFile(path.join(this.dirname, `${basename}${num}${ext}`), path.join(this.dirname, `${basename}${num}${ext}.gz`), cb);
11427
+ this._compressFile(path2.join(this.dirname, `${basename}${num}${ext}`), path2.join(this.dirname, `${basename}${num}${ext}.gz`), cb);
11424
11428
  }.bind(this));
11425
11429
  }
11426
11430
  tasks.push(function(cb) {
@@ -11434,8 +11438,8 @@ var require_file = __commonJS((exports, module) => {
11434
11438
  asyncSeries(tasks, callback);
11435
11439
  }
11436
11440
  _getFile() {
11437
- const ext = path.extname(this._basename);
11438
- const basename = path.basename(this._basename, ext);
11441
+ const ext = path2.extname(this._basename);
11442
+ const basename = path2.basename(this._basename, ext);
11439
11443
  const isRotation = this.rotationFormat ? this.rotationFormat() : this._created;
11440
11444
  return !this.tailable && this._created ? `${basename}${isRotation}${ext}` : `${basename}${ext}`;
11441
11445
  }
@@ -11447,7 +11451,7 @@ var require_file = __commonJS((exports, module) => {
11447
11451
  const isOldest = oldest !== 0 ? oldest : "";
11448
11452
  const isZipped = this.zippedArchive ? ".gz" : "";
11449
11453
  const filePath = `${basename}${isOldest}${ext}${isZipped}`;
11450
- const target = path.join(this.dirname, filePath);
11454
+ const target = path2.join(this.dirname, filePath);
11451
11455
  fs.unlink(target, callback);
11452
11456
  }
11453
11457
  _checkMaxFilesTailable(ext, basename, callback) {
@@ -11459,18 +11463,18 @@ var require_file = __commonJS((exports, module) => {
11459
11463
  for (let x = this.maxFiles - 1;x > 1; x--) {
11460
11464
  tasks.push(function(i, cb) {
11461
11465
  let fileName = `${basename}${i - 1}${ext}${isZipped}`;
11462
- const tmppath = path.join(this.dirname, fileName);
11466
+ const tmppath = path2.join(this.dirname, fileName);
11463
11467
  fs.exists(tmppath, (exists) => {
11464
11468
  if (!exists) {
11465
11469
  return cb(null);
11466
11470
  }
11467
11471
  fileName = `${basename}${i}${ext}${isZipped}`;
11468
- fs.rename(tmppath, path.join(this.dirname, fileName), cb);
11472
+ fs.rename(tmppath, path2.join(this.dirname, fileName), cb);
11469
11473
  });
11470
11474
  }.bind(this, x));
11471
11475
  }
11472
11476
  asyncSeries(tasks, () => {
11473
- fs.rename(path.join(this.dirname, `${basename}${ext}${isZipped}`), path.join(this.dirname, `${basename}1${ext}${isZipped}`), callback);
11477
+ fs.rename(path2.join(this.dirname, `${basename}${ext}${isZipped}`), path2.join(this.dirname, `${basename}1${ext}${isZipped}`), callback);
11474
11478
  });
11475
11479
  }
11476
11480
  _compressFile(src, dest, callback) {
@@ -11552,9 +11556,9 @@ var require_http = __commonJS((exports, module) => {
11552
11556
  };
11553
11557
  const auth = options.params.auth || null;
11554
11558
  delete options.params.auth;
11555
- const path = options.params.path || null;
11559
+ const path2 = options.params.path || null;
11556
11560
  delete options.params.path;
11557
- this._request(options, auth, path, (err, res, body) => {
11561
+ this._request(options, auth, path2, (err, res, body) => {
11558
11562
  if (res && res.statusCode !== 200) {
11559
11563
  err = new Error(`Invalid HTTP Status Code: ${res.statusCode}`);
11560
11564
  }
@@ -11577,12 +11581,12 @@ var require_http = __commonJS((exports, module) => {
11577
11581
  method: "stream",
11578
11582
  params: options
11579
11583
  };
11580
- const path = options.params.path || null;
11584
+ const path2 = options.params.path || null;
11581
11585
  delete options.params.path;
11582
11586
  const auth = options.params.auth || null;
11583
11587
  delete options.params.auth;
11584
11588
  let buff = "";
11585
- const req = this._request(options, auth, path);
11589
+ const req = this._request(options, auth, path2);
11586
11590
  stream.destroy = () => req.destroy();
11587
11591
  req.on("data", (data) => {
11588
11592
  data = (buff + data).split(/\n+/);
@@ -11600,40 +11604,40 @@ var require_http = __commonJS((exports, module) => {
11600
11604
  req.on("error", (err) => stream.emit("error", err));
11601
11605
  return stream;
11602
11606
  }
11603
- _request(options, auth, path, callback) {
11607
+ _request(options, auth, path2, callback) {
11604
11608
  options = options || {};
11605
11609
  auth = auth || this.auth;
11606
- path = path || this.path || "";
11610
+ path2 = path2 || this.path || "";
11607
11611
  if (this.batch) {
11608
- this._doBatch(options, callback, auth, path);
11612
+ this._doBatch(options, callback, auth, path2);
11609
11613
  } else {
11610
- this._doRequest(options, callback, auth, path);
11614
+ this._doRequest(options, callback, auth, path2);
11611
11615
  }
11612
11616
  }
11613
- _doBatch(options, callback, auth, path) {
11617
+ _doBatch(options, callback, auth, path2) {
11614
11618
  this.batchOptions.push(options);
11615
11619
  if (this.batchOptions.length === 1) {
11616
11620
  const me = this;
11617
11621
  this.batchCallback = callback;
11618
11622
  this.batchTimeoutID = setTimeout(function() {
11619
11623
  me.batchTimeoutID = -1;
11620
- me._doBatchRequest(me.batchCallback, auth, path);
11624
+ me._doBatchRequest(me.batchCallback, auth, path2);
11621
11625
  }, this.batchInterval);
11622
11626
  }
11623
11627
  if (this.batchOptions.length === this.batchCount) {
11624
- this._doBatchRequest(this.batchCallback, auth, path);
11628
+ this._doBatchRequest(this.batchCallback, auth, path2);
11625
11629
  }
11626
11630
  }
11627
- _doBatchRequest(callback, auth, path) {
11631
+ _doBatchRequest(callback, auth, path2) {
11628
11632
  if (this.batchTimeoutID > 0) {
11629
11633
  clearTimeout(this.batchTimeoutID);
11630
11634
  this.batchTimeoutID = -1;
11631
11635
  }
11632
11636
  const batchOptionsCopy = this.batchOptions.slice();
11633
11637
  this.batchOptions = [];
11634
- this._doRequest(batchOptionsCopy, callback, auth, path);
11638
+ this._doRequest(batchOptionsCopy, callback, auth, path2);
11635
11639
  }
11636
- _doRequest(options, callback, auth, path) {
11640
+ _doRequest(options, callback, auth, path2) {
11637
11641
  const headers = Object.assign({}, this.headers);
11638
11642
  if (auth && auth.bearer) {
11639
11643
  headers.Authorization = `Bearer ${auth.bearer}`;
@@ -11643,7 +11647,7 @@ var require_http = __commonJS((exports, module) => {
11643
11647
  method: "POST",
11644
11648
  host: this.host,
11645
11649
  port: this.port,
11646
- path: `/${path.replace(/^\//, "")}`,
11650
+ path: `/${path2.replace(/^\//, "")}`,
11647
11651
  headers,
11648
11652
  auth: auth && auth.username && auth.password ? `${auth.username}:${auth.password}` : "",
11649
11653
  agent: this.agent
@@ -13082,13 +13086,13 @@ function messageWithFilesystemCause(error) {
13082
13086
  return `${message}: ${describeFilesystemAccessFailure(access)}`;
13083
13087
  }
13084
13088
  function errnoWireFields(error) {
13085
- const { code, syscall, path } = error;
13089
+ const { code, syscall, path: path2 } = error;
13086
13090
  if (typeof code !== "string")
13087
13091
  return;
13088
13092
  return {
13089
13093
  code,
13090
13094
  ...typeof syscall === "string" ? { syscall } : {},
13091
- ...typeof path === "string" ? { path } : {}
13095
+ ...typeof path2 === "string" ? { path: path2 } : {}
13092
13096
  };
13093
13097
  }
13094
13098
  function internalErrorToHttpError(error, { log = true } = {}) {
@@ -13195,7 +13199,7 @@ function toQueryTextProblem(problem) {
13195
13199
  ...problem.at ? { at: { range: problem.at.range } } : {}
13196
13200
  };
13197
13201
  }
13198
- var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", MAX_LOGGED_DETAIL_CHARS = 2000, FILESYSTEM_ACCESS_DESCRIPTIONS, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, RenderTagRefusedError, UnparseableTextError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, DestinationNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, PackageManifestError, MaterializationEligibilityError, PublisherConfigError, ServerConfigurationError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, WriteVerifyError, InvalidStateTransitionError, ServiceUnavailableError, PayloadTooLargeError, ResponseUnserializableError, QueryTimeoutError;
13202
+ var GENERIC_INTERNAL_MESSAGE = "Internal server error.", GENERIC_UPSTREAM_MESSAGE = "Upstream connection error.", MAX_LOGGED_DETAIL_CHARS = 2000, FILESYSTEM_ACCESS_DESCRIPTIONS, NotImplementedError, BadRequestError, InvalidArgumentError, CompileRefusedError, RenderTagRefusedError, UnparseableTextError, EnvironmentNotFoundError, PackageNotFoundError, ModelNotFoundError, DashboardNotFoundError, ConnectionNotFoundError, TableNotFoundError, ConnectionError, DestinationNotFoundError, ConnectionAuthError, UnsupportedCatalogFormatError, ModelCompilationError, PackageManifestError, MaterializationEligibilityError, ChainedUpstreamMissingError, ChainedShapeNotCarriedError, PublisherConfigError, ServerConfigurationError, FrozenConfigError, AccessDeniedError, QueryCompileError, NotQueryableError, OffSurfaceError, MaterializationNotFoundError, MaterializationConflictError, WriteConflictError, WriteRolledBackError, WriteVerifyError, InvalidStateTransitionError, ServiceUnavailableError, PackageAdmissionRefusedError, PayloadTooLargeError, ResponseUnserializableError, QueryTimeoutError;
13199
13203
  var init_errors = __esm(() => {
13200
13204
  init_constants();
13201
13205
  init_logger();
@@ -13298,6 +13302,20 @@ var init_errors = __esm(() => {
13298
13302
  this.reason = error.reason;
13299
13303
  }
13300
13304
  };
13305
+ ChainedUpstreamMissingError = class ChainedUpstreamMissingError extends Error {
13306
+ missing;
13307
+ constructor(missing, detail) {
13308
+ super(detail);
13309
+ this.name = "ChainedUpstreamMissingError";
13310
+ this.missing = missing;
13311
+ }
13312
+ };
13313
+ ChainedShapeNotCarriedError = class ChainedShapeNotCarriedError extends Error {
13314
+ constructor(detail) {
13315
+ super(detail);
13316
+ this.name = "ChainedShapeNotCarriedError";
13317
+ }
13318
+ };
13301
13319
  PublisherConfigError = class PublisherConfigError extends Error {
13302
13320
  constructor(configName, cause) {
13303
13321
  super(`Could not read ${configName}: ${cause instanceof Error ? cause.message : String(cause)}. Fix the file, or move it aside to fall back to the bundled default.`);
@@ -13378,6 +13396,8 @@ var init_errors = __esm(() => {
13378
13396
  super(message, options);
13379
13397
  }
13380
13398
  };
13399
+ PackageAdmissionRefusedError = class PackageAdmissionRefusedError extends ServiceUnavailableError {
13400
+ };
13381
13401
  PayloadTooLargeError = class PayloadTooLargeError extends Error {
13382
13402
  constructor(message) {
13383
13403
  super(message);
@@ -14006,6 +14026,32 @@ var init_error_wire = __esm(() => {
14006
14026
  init_errors();
14007
14027
  });
14008
14028
 
14029
+ // src/service/translator_error.ts
14030
+ import { MalloyError as MalloyError3 } from "@malloydata/malloy";
14031
+ function translatorInvariantProblem(error) {
14032
+ if (!(error instanceof Error) || error instanceof MalloyError3) {
14033
+ return;
14034
+ }
14035
+ const topFrame = (error.stack ?? "").split(`
14036
+ `).find((line) => line.trimStart().startsWith("at "));
14037
+ if (!topFrame || !TRANSLATOR_FRAME.test(topFrame))
14038
+ return;
14039
+ const hint = error.message === RANGE_COMPARISON_MESSAGE ? " This comes from comparing a date or timestamp to a date literal such as " + "@2025 with `~`, which Malloy cannot compile. Use `=` to match the whole " + "year, month or day (`order_date = @2025`), or an explicit range " + "(`order_date ? @2025-01-01 to @2026-01-01`)." : "";
14040
+ return {
14041
+ code: "translator-error",
14042
+ severity: "error",
14043
+ message: `Malloy could not compile this query: ${error.message}.` + hint
14044
+ };
14045
+ }
14046
+ function translatorMalloyError(error) {
14047
+ const problem = translatorInvariantProblem(error);
14048
+ return problem ? new MalloyError3(problem.message, [problem]) : undefined;
14049
+ }
14050
+ var TRANSLATOR_FRAME, RANGE_COMPARISON_MESSAGE = "mysterious error in range computation";
14051
+ var init_translator_error = __esm(() => {
14052
+ TRANSLATOR_FRAME = /[\\/]@malloydata[\\/]malloy[\\/]dist[\\/]lang[\\/]/;
14053
+ });
14054
+
14009
14055
  // src/service/annotations.ts
14010
14056
  import { Annotations } from "@malloydata/malloy";
14011
14057
  function isReservedRoute(route) {
@@ -14398,16 +14444,16 @@ import {
14398
14444
  isJoined,
14399
14445
  isSourceDef
14400
14446
  } from "@malloydata/malloy";
14401
- function resolveFieldUsagePath(struct, path) {
14447
+ function resolveFieldUsagePath(struct, path2) {
14402
14448
  let current = struct;
14403
- for (let i = 0;i < path.length - 1; i++) {
14404
- const seg = path[i];
14449
+ for (let i = 0;i < path2.length - 1; i++) {
14450
+ const seg = path2[i];
14405
14451
  const joinField = (current.fields ?? []).find((f) => (f.as || f.name) === seg && isJoined(f) && (isSourceDef(f) || f.type === "record" || f.type === "array"));
14406
14452
  if (!joinField)
14407
14453
  return;
14408
14454
  current = joinField;
14409
14455
  }
14410
- const leaf = path[path.length - 1];
14456
+ const leaf = path2[path2.length - 1];
14411
14457
  const field = (current.fields ?? []).find((f) => (f.as || f.name) === leaf);
14412
14458
  return field ? { struct: current, field } : undefined;
14413
14459
  }
@@ -14895,10 +14941,10 @@ function assertAuthorizeGrammarValid(modelDef, authorizeMap, authorizeOwnNotes,
14895
14941
  }
14896
14942
  }
14897
14943
  }
14898
- function fanoutSegment(struct, path) {
14944
+ function fanoutSegment(struct, path2) {
14899
14945
  let current = struct;
14900
- for (let i = 0;i < path.length - 1; i++) {
14901
- const seg = path[i];
14946
+ for (let i = 0;i < path2.length - 1; i++) {
14947
+ const seg = path2[i];
14902
14948
  const field = (current.fields ?? []).find((f) => (f.as ?? f.name) === seg);
14903
14949
  if (!field)
14904
14950
  return { segment: seg, reason: "unresolved" };
@@ -15863,16 +15909,16 @@ function parseMotly(texts) {
15863
15909
  const after = parseBounded(rescued);
15864
15910
  return { tag: after.tag, errors: [...envErrors, ...after.messages] };
15865
15911
  }
15866
- function tagText(tag, ...path) {
15912
+ function tagText(tag, ...path2) {
15867
15913
  try {
15868
- return tag?.text(...path);
15914
+ return tag?.text(...path2);
15869
15915
  } catch {
15870
15916
  return;
15871
15917
  }
15872
15918
  }
15873
- function tagNumeric(tag, ...path) {
15919
+ function tagNumeric(tag, ...path2) {
15874
15920
  try {
15875
- const raw = tagText(tag, ...path);
15921
+ const raw = tagText(tag, ...path2);
15876
15922
  if (raw === undefined)
15877
15923
  return;
15878
15924
  const DECIMAL = /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?$/;
@@ -23262,8 +23308,8 @@ var require_dist = __commonJS((exports) => {
23262
23308
  import {
23263
23309
  isSourceDef as isSourceDef4
23264
23310
  } from "@malloydata/malloy";
23265
- function presentText(tag, ...path) {
23266
- const raw = tagText(tag, ...path);
23311
+ function presentText(tag, ...path2) {
23312
+ const raw = tagText(tag, ...path2);
23267
23313
  return raw !== undefined && raw.trim() !== "" ? raw : undefined;
23268
23314
  }
23269
23315
  function readGivenControlSpec(annotationTexts2) {
@@ -23627,8 +23673,8 @@ function readDrillTag(annotations) {
23627
23673
  function isString(value) {
23628
23674
  return value !== undefined;
23629
23675
  }
23630
- function tagTextArray(tag, ...path) {
23631
- const items = tag?.array(...path);
23676
+ function tagTextArray(tag, ...path2) {
23677
+ const items = tag?.array(...path2);
23632
23678
  return items?.map((item) => tagText(item)).filter(isString);
23633
23679
  }
23634
23680
  function resolveTileGivens(tile, facts) {
@@ -24507,10 +24553,10 @@ var init_source_extraction = __esm(() => {
24507
24553
 
24508
24554
  // src/utils.ts
24509
24555
  import * as fs2 from "fs";
24510
- import * as path2 from "path";
24556
+ import * as path3 from "path";
24511
24557
  import { fileURLToPath } from "url";
24512
24558
  function ignoreDotfiles(file) {
24513
- return path2.basename(file).startsWith(".");
24559
+ return path3.basename(file).startsWith(".");
24514
24560
  }
24515
24561
  function errMessage(err) {
24516
24562
  return err instanceof Error ? err.message : String(err);
@@ -24519,11 +24565,11 @@ var URL_READER;
24519
24565
  var init_utils = __esm(() => {
24520
24566
  URL_READER = {
24521
24567
  readURL: (url) => {
24522
- let path3 = url.toString();
24568
+ let path4 = url.toString();
24523
24569
  if (url.protocol == "file:") {
24524
- path3 = fileURLToPath(url);
24570
+ path4 = fileURLToPath(url);
24525
24571
  }
24526
- return fs2.promises.readFile(path3, "utf8");
24572
+ return fs2.promises.readFile(path4, "utf8");
24527
24573
  }
24528
24574
  };
24529
24575
  });
@@ -24534,6 +24580,7 @@ init_authorize_metrics();
24534
24580
  init_data_styles();
24535
24581
  init_errors();
24536
24582
  init_error_wire();
24583
+ init_translator_error();
24537
24584
  init_authorize();
24538
24585
  init_gate_classification();
24539
24586
  init_gate_dimension();
@@ -24550,7 +24597,7 @@ import {
24550
24597
  MalloySQLStatementType
24551
24598
  } from "@malloydata/malloy-sql";
24552
24599
  import * as fs3 from "fs";
24553
- import * as path3 from "path";
24600
+ import * as path4 from "path";
24554
24601
  import { parentPort, threadId } from "node:worker_threads";
24555
24602
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
24556
24603
 
@@ -24741,7 +24788,7 @@ var QUERYABLE_SOURCES_DEPRECATION = `"queryableSources" in publisher.json does n
24741
24788
  init_errors();
24742
24789
  import { createHash } from "crypto";
24743
24790
  import * as fs from "fs";
24744
- import * as path from "path";
24791
+ import * as path2 from "path";
24745
24792
  var PACKAGE_REPRESENTATIONS = ["single", "facets"];
24746
24793
  var KEYPHRASE_MODES = ["auto", "never", "always"];
24747
24794
  var REFINE_LEVEL_NAMES = ["LOW", "MEDIUM", "HIGH"];
@@ -24797,17 +24844,17 @@ function describe(value) {
24797
24844
  return JSON.stringify(value) ?? "nothing";
24798
24845
  }
24799
24846
  function stepsOutside(within) {
24800
- return within === ".." || within.startsWith(`..${path.sep}`) || path.isAbsolute(within);
24847
+ return within === ".." || within.startsWith(`..${path2.sep}`) || path2.isAbsolute(within);
24801
24848
  }
24802
24849
  function resolvePromptPath(packageRoot, rel, promptKey = "keyphrase") {
24803
24850
  const key = `retrieval.prompts.${promptKey}`;
24804
24851
  const fix = `Fix: use a path inside the package, e.g. "prompts/${promptKey}.md".`;
24805
- if (rel.includes("\x00") || path.isAbsolute(rel) || /^[A-Za-z]:[\\/]/.test(rel) || rel.startsWith("\\")) {
24852
+ if (rel.includes("\x00") || path2.isAbsolute(rel) || /^[A-Za-z]:[\\/]/.test(rel) || rel.startsWith("\\")) {
24806
24853
  fail(`Invalid publisher.json ${key}: ${describe(rel)} is an absolute path. ${fix}`);
24807
24854
  }
24808
- const root = path.resolve(packageRoot);
24809
- const resolved = path.resolve(root, rel);
24810
- const within = path.relative(root, resolved);
24855
+ const root = path2.resolve(packageRoot);
24856
+ const resolved = path2.resolve(root, rel);
24857
+ const within = path2.relative(root, resolved);
24811
24858
  if (within === "" || stepsOutside(within)) {
24812
24859
  fail(`Invalid publisher.json ${key}: ${describe(rel)} resolves outside the package directory. ${fix}`);
24813
24860
  }
@@ -24932,7 +24979,7 @@ async function readPromptFile(packageRoot, key, rel) {
24932
24979
  fs.promises.realpath(packageRoot),
24933
24980
  fs.promises.realpath(file)
24934
24981
  ]);
24935
- const within = path.relative(realRoot, realFile);
24982
+ const within = path2.relative(realRoot, realFile);
24936
24983
  if (stepsOutside(within)) {
24937
24984
  fail(`Invalid publisher.json ${at}: ${describe(rel)} resolves outside the package directory through a link. ` + `Fix: copy the file into the package.`);
24938
24985
  }
@@ -25166,7 +25213,7 @@ function makeWorkerUrlReader(job) {
25166
25213
  readURL: async (url) => {
25167
25214
  if (url.protocol === "file:") {
25168
25215
  const filePath = fileURLToPath2(url);
25169
- if (job.replacement && path3.resolve(filePath) === path3.resolve(job.packagePath, job.replacement.modelPath)) {
25216
+ if (job.replacement && path4.resolve(filePath) === path4.resolve(job.packagePath, job.replacement.modelPath)) {
25170
25217
  return job.replacement.source;
25171
25218
  }
25172
25219
  return fs3.promises.readFile(filePath, "utf8");
@@ -25218,8 +25265,18 @@ function buildWorkerMalloyConfig(job) {
25218
25265
  }));
25219
25266
  return config;
25220
25267
  }
25268
+ async function readInstallRecord(packagePath) {
25269
+ try {
25270
+ const raw = await fs3.promises.readFile(installRecordPath(path4.dirname(packagePath), path4.basename(packagePath)), "utf8");
25271
+ const record = JSON.parse(raw);
25272
+ const location = typeof record === "object" && record !== null ? record.location : undefined;
25273
+ return typeof location === "string" && location !== "" ? location : undefined;
25274
+ } catch {
25275
+ return;
25276
+ }
25277
+ }
25221
25278
  async function readPackageMetadata(packagePath, modelPaths) {
25222
- const manifestPath = path3.join(packagePath, PACKAGE_MANIFEST_NAME);
25279
+ const manifestPath = path4.join(packagePath, PACKAGE_MANIFEST_NAME);
25223
25280
  const contents = await fs3.promises.readFile(manifestPath, "utf8");
25224
25281
  let parsed;
25225
25282
  try {
@@ -25246,6 +25303,7 @@ async function readPackageMetadata(packagePath, modelPaths) {
25246
25303
  return {
25247
25304
  name: parsed.name,
25248
25305
  description: parsed.description,
25306
+ location: await readInstallRecord(packagePath),
25249
25307
  explores: explores.explores,
25250
25308
  queryableSources: parsed.queryableSources === "all" ? "all" : "declared",
25251
25309
  manifestLocation: typeof parsed.manifestLocation === "string" ? parsed.manifestLocation : null,
@@ -25257,7 +25315,7 @@ async function readPackageMetadata(packagePath, modelPaths) {
25257
25315
  }
25258
25316
  async function listPackageFiles(packagePath) {
25259
25317
  const files = await import_recursive_readdir.default(packagePath, [ignoreDotfiles]);
25260
- return files.map((full) => path3.relative(packagePath, full).replace(/\\/g, "/")).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
25318
+ return files.map((full) => path4.relative(packagePath, full).replace(/\\/g, "/")).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
25261
25319
  }
25262
25320
  function filterModelPaths(allRelative) {
25263
25321
  return allRelative.filter((p) => p.endsWith(MODEL_FILE_SUFFIX) || p.endsWith(NOTEBOOK_FILE_SUFFIX));
@@ -25326,7 +25384,7 @@ function buildRuntimeForModel(job, malloyConfig) {
25326
25384
  }
25327
25385
  async function compileMalloyModel(job, malloyConfig, modelPath) {
25328
25386
  const compileStart = performance.now();
25329
- const fullPath = path3.join(job.packagePath, modelPath);
25387
+ const fullPath = path4.join(job.packagePath, modelPath);
25330
25388
  const modelURL = pathToFileURL(fullPath);
25331
25389
  const importBaseURL = new URL(".", modelURL);
25332
25390
  const { runtime, urlReader, textFor } = buildRuntimeForModel(job, malloyConfig);
@@ -25391,7 +25449,7 @@ async function compileMalloyModel(job, malloyConfig, modelPath) {
25391
25449
  }
25392
25450
  async function compileNotebookModel(job, malloyConfig, modelPath) {
25393
25451
  const compileStart = performance.now();
25394
- const fullPath = path3.join(job.packagePath, modelPath);
25452
+ const fullPath = path4.join(job.packagePath, modelPath);
25395
25453
  const modelURL = pathToFileURL(fullPath);
25396
25454
  const importBaseURL = new URL(".", modelURL);
25397
25455
  const { runtime, urlReader } = buildRuntimeForModel(job, malloyConfig);
@@ -25536,7 +25594,7 @@ async function compileOneModel(job, malloyConfig, modelPath) {
25536
25594
  return {
25537
25595
  modelPath,
25538
25596
  modelType,
25539
- compilationError: serializeError(error)
25597
+ compilationError: serializeError(translatorMalloyError(error) ?? error)
25540
25598
  };
25541
25599
  }
25542
25600
  }
@@ -11,7 +11,7 @@
11
11
  // opts: { environment?, package?, sourceName?, queryName?, filterParams?,
12
12
  // bypassFilters?, givens? }. givens is a name→value map bound as
13
13
  // Malloy given: runtime parameters for this query (safe parameterization,
14
- // not string interpolation) — see the malloy-html-data-app-runtime skill.
14
+ // not string interpolation) — see the malloy-html-data-apps skill (reference/runtime.md).
15
15
  // - Publisher.embed(selector, { src, height?, token? })
16
16
  // - Publisher.context ({ environment, package } inferred from URL)
17
17
  // - Publisher.setToken(token) (override Bearer token; default uses cookies)