@malloy-publisher/server 0.0.192 → 0.0.194

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 (44) hide show
  1. package/build.ts +1 -0
  2. package/dist/app/api-doc.yaml +558 -1
  3. package/dist/app/assets/{HomePage-H1OH-VW5.js → HomePage-DbZS0N7G.js} +1 -1
  4. package/dist/app/assets/MainPage-CBuWkbmr.js +2 -0
  5. package/dist/app/assets/{ModelPage-Crau5hgZ.js → ModelPage-Bt37smot.js} +1 -1
  6. package/dist/app/assets/{PackagePage-CbubRhgE.js → PackagePage-DLZe50WG.js} +1 -1
  7. package/dist/app/assets/{ProjectPage-DUlJkYJ4.js → ProjectPage-FQTEPXP4.js} +1 -1
  8. package/dist/app/assets/{RouteError-DrNXNihc.js → RouteError-DefbDO7F.js} +1 -1
  9. package/dist/app/assets/{WorkbookPage-CBBv7n5U.js → WorkbookPage-CkAo16ar.js} +1 -1
  10. package/dist/app/assets/{core-Dzx75uJR.es-DwnFZnyO.js → core-BrfQApxh.es-DnvCX4oH.js} +14 -14
  11. package/dist/app/assets/index-5eLCcNmP.css +1 -0
  12. package/dist/app/assets/{index-d5rvmoZ7.js → index-Bu0ub036.js} +119 -119
  13. package/dist/app/assets/index-CkzK3JIl.js +40 -0
  14. package/dist/app/assets/index-CoA6HIGS.js +1742 -0
  15. package/dist/app/assets/{index.umd-CetYIBQY.js → index.umd-B6Ms2PpL.js} +46 -46
  16. package/dist/app/index.html +2 -2
  17. package/dist/server.mjs +1529 -985
  18. package/package.json +11 -10
  19. package/src/config.ts +7 -2
  20. package/src/controller/connection.controller.ts +102 -27
  21. package/src/dto/connection.dto.spec.ts +55 -0
  22. package/src/dto/connection.dto.ts +87 -2
  23. package/src/server.ts +201 -2
  24. package/src/service/connection.spec.ts +250 -4
  25. package/src/service/connection.ts +328 -473
  26. package/src/service/connection_config.spec.ts +123 -0
  27. package/src/service/connection_config.ts +562 -0
  28. package/src/service/connection_service.spec.ts +50 -0
  29. package/src/service/connection_service.ts +125 -32
  30. package/src/service/db_utils.spec.ts +161 -0
  31. package/src/service/db_utils.ts +131 -0
  32. package/src/service/materialization_service.spec.ts +18 -12
  33. package/src/service/materialization_service.ts +54 -7
  34. package/src/service/model.ts +24 -27
  35. package/src/service/package.spec.ts +125 -1
  36. package/src/service/package.ts +86 -44
  37. package/src/service/project.ts +172 -94
  38. package/src/service/project_store.spec.ts +72 -0
  39. package/src/service/project_store.ts +98 -81
  40. package/tests/unit/duckdb/attached_databases.test.ts +1 -19
  41. package/dist/app/assets/MainPage-GL06aMke.js +0 -2
  42. package/dist/app/assets/index-CMlGQMcl.css +0 -1
  43. package/dist/app/assets/index-CzjyS9cx.js +0 -1276
  44. package/dist/app/assets/index-HHdhLUpv.js +0 -676
package/dist/server.mjs CHANGED
@@ -150546,7 +150546,7 @@ var require_src113 = __commonJS((exports) => {
150546
150546
  var fs2 = __require("fs");
150547
150547
  var gaxios_1 = require_src53();
150548
150548
  var jws = require_jws();
150549
- var path2 = __require("path");
150549
+ var path3 = __require("path");
150550
150550
  var util_1 = __require("util");
150551
150551
  var readFile = fs2.readFile ? (0, util_1.promisify)(fs2.readFile) : async () => {
150552
150552
  throw new ErrorWithCode("use key rather than keyFile.", "MISSING_CREDENTIALS");
@@ -150616,7 +150616,7 @@ var require_src113 = __commonJS((exports) => {
150616
150616
  return __classPrivateFieldGet(this, _GoogleToken_instances, "m", _GoogleToken_getTokenAsync).call(this, opts);
150617
150617
  }
150618
150618
  async getCredentials(keyFile) {
150619
- const ext = path2.extname(keyFile);
150619
+ const ext = path3.extname(keyFile);
150620
150620
  switch (ext) {
150621
150621
  case ".json": {
150622
150622
  const key = await readFile(keyFile, "utf8");
@@ -152721,7 +152721,7 @@ var require_googleauth = __commonJS((exports) => {
152721
152721
  var fs2 = __require("fs");
152722
152722
  var gcpMetadata = require_src55();
152723
152723
  var os2 = __require("os");
152724
- var path2 = __require("path");
152724
+ var path3 = __require("path");
152725
152725
  var crypto_1 = require_crypto3();
152726
152726
  var transporters_1 = require_transporters();
152727
152727
  var computeclient_1 = require_computeclient();
@@ -152917,11 +152917,11 @@ var require_googleauth = __commonJS((exports) => {
152917
152917
  } else {
152918
152918
  const home = process.env["HOME"];
152919
152919
  if (home) {
152920
- location = path2.join(home, ".config");
152920
+ location = path3.join(home, ".config");
152921
152921
  }
152922
152922
  }
152923
152923
  if (location) {
152924
- location = path2.join(location, "gcloud", "application_default_credentials.json");
152924
+ location = path3.join(location, "gcloud", "application_default_credentials.json");
152925
152925
  if (!fs2.existsSync(location)) {
152926
152926
  location = null;
152927
152927
  }
@@ -153238,7 +153238,7 @@ var require_googleauth = __commonJS((exports) => {
153238
153238
  if (this.jsonContent) {
153239
153239
  return this._cacheClientFromJSON(this.jsonContent, this.clientOptions);
153240
153240
  } else if (this.keyFilename) {
153241
- const filePath = path2.resolve(this.keyFilename);
153241
+ const filePath = path3.resolve(this.keyFilename);
153242
153242
  const stream4 = fs2.createReadStream(filePath);
153243
153243
  return await this.fromStreamAsync(stream4, this.clientOptions);
153244
153244
  } else if (this.apiKey) {
@@ -153729,19 +153729,19 @@ var require_rng2 = __commonJS((exports) => {
153729
153729
  Object.defineProperty(exports, "__esModule", {
153730
153730
  value: true
153731
153731
  });
153732
- exports.default = rng2;
153732
+ exports.default = rng;
153733
153733
  var _crypto = _interopRequireDefault(__require("crypto"));
153734
153734
  function _interopRequireDefault(obj) {
153735
153735
  return obj && obj.__esModule ? obj : { default: obj };
153736
153736
  }
153737
- var rnds8Pool2 = new Uint8Array(256);
153738
- var poolPtr2 = rnds8Pool2.length;
153739
- function rng2() {
153740
- if (poolPtr2 > rnds8Pool2.length - 16) {
153741
- _crypto.default.randomFillSync(rnds8Pool2);
153742
- poolPtr2 = 0;
153737
+ var rnds8Pool = new Uint8Array(256);
153738
+ var poolPtr = rnds8Pool.length;
153739
+ function rng() {
153740
+ if (poolPtr > rnds8Pool.length - 16) {
153741
+ _crypto.default.randomFillSync(rnds8Pool);
153742
+ poolPtr = 0;
153743
153743
  }
153744
- return rnds8Pool2.slice(poolPtr2, poolPtr2 += 16);
153744
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
153745
153745
  }
153746
153746
  });
153747
153747
 
@@ -153778,20 +153778,20 @@ var require_stringify5 = __commonJS((exports) => {
153778
153778
  value: true
153779
153779
  });
153780
153780
  exports.default = undefined;
153781
- exports.unsafeStringify = unsafeStringify2;
153781
+ exports.unsafeStringify = unsafeStringify;
153782
153782
  var _validate = _interopRequireDefault(require_validate2());
153783
153783
  function _interopRequireDefault(obj) {
153784
153784
  return obj && obj.__esModule ? obj : { default: obj };
153785
153785
  }
153786
- var byteToHex2 = [];
153786
+ var byteToHex = [];
153787
153787
  for (let i = 0;i < 256; ++i) {
153788
- byteToHex2.push((i + 256).toString(16).slice(1));
153788
+ byteToHex.push((i + 256).toString(16).slice(1));
153789
153789
  }
153790
- function unsafeStringify2(arr, offset = 0) {
153791
- return byteToHex2[arr[offset + 0]] + byteToHex2[arr[offset + 1]] + byteToHex2[arr[offset + 2]] + byteToHex2[arr[offset + 3]] + "-" + byteToHex2[arr[offset + 4]] + byteToHex2[arr[offset + 5]] + "-" + byteToHex2[arr[offset + 6]] + byteToHex2[arr[offset + 7]] + "-" + byteToHex2[arr[offset + 8]] + byteToHex2[arr[offset + 9]] + "-" + byteToHex2[arr[offset + 10]] + byteToHex2[arr[offset + 11]] + byteToHex2[arr[offset + 12]] + byteToHex2[arr[offset + 13]] + byteToHex2[arr[offset + 14]] + byteToHex2[arr[offset + 15]];
153790
+ function unsafeStringify(arr, offset = 0) {
153791
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
153792
153792
  }
153793
153793
  function stringify(arr, offset = 0) {
153794
- const uuid = unsafeStringify2(arr, offset);
153794
+ const uuid = unsafeStringify(arr, offset);
153795
153795
  if (!(0, _validate.default)(uuid)) {
153796
153796
  throw TypeError("Stringified UUID is invalid");
153797
153797
  }
@@ -154032,7 +154032,7 @@ var require_v42 = __commonJS((exports) => {
154032
154032
  function _interopRequireDefault(obj) {
154033
154033
  return obj && obj.__esModule ? obj : { default: obj };
154034
154034
  }
154035
- function v42(options, buf, offset) {
154035
+ function v4(options, buf, offset) {
154036
154036
  if (_native.default.randomUUID && !buf && !options) {
154037
154037
  return _native.default.randomUUID();
154038
154038
  }
@@ -154049,7 +154049,7 @@ var require_v42 = __commonJS((exports) => {
154049
154049
  }
154050
154050
  return (0, _stringify.unsafeStringify)(rnds);
154051
154051
  }
154052
- var _default = v42;
154052
+ var _default = v4;
154053
154053
  exports.default = _default;
154054
154054
  });
154055
154055
 
@@ -160310,19 +160310,19 @@ var require_rng3 = __commonJS((exports) => {
160310
160310
  Object.defineProperty(exports, "__esModule", {
160311
160311
  value: true
160312
160312
  });
160313
- exports.default = rng2;
160313
+ exports.default = rng;
160314
160314
  var _crypto = _interopRequireDefault(__require("crypto"));
160315
160315
  function _interopRequireDefault(obj) {
160316
160316
  return obj && obj.__esModule ? obj : { default: obj };
160317
160317
  }
160318
- var rnds8Pool2 = new Uint8Array(256);
160319
- var poolPtr2 = rnds8Pool2.length;
160320
- function rng2() {
160321
- if (poolPtr2 > rnds8Pool2.length - 16) {
160322
- _crypto.default.randomFillSync(rnds8Pool2);
160323
- poolPtr2 = 0;
160318
+ var rnds8Pool = new Uint8Array(256);
160319
+ var poolPtr = rnds8Pool.length;
160320
+ function rng() {
160321
+ if (poolPtr > rnds8Pool.length - 16) {
160322
+ _crypto.default.randomFillSync(rnds8Pool);
160323
+ poolPtr = 0;
160324
160324
  }
160325
- return rnds8Pool2.slice(poolPtr2, poolPtr2 += 16);
160325
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
160326
160326
  }
160327
160327
  });
160328
160328
 
@@ -160359,20 +160359,20 @@ var require_stringify6 = __commonJS((exports) => {
160359
160359
  value: true
160360
160360
  });
160361
160361
  exports.default = undefined;
160362
- exports.unsafeStringify = unsafeStringify2;
160362
+ exports.unsafeStringify = unsafeStringify;
160363
160363
  var _validate = _interopRequireDefault(require_validate3());
160364
160364
  function _interopRequireDefault(obj) {
160365
160365
  return obj && obj.__esModule ? obj : { default: obj };
160366
160366
  }
160367
- var byteToHex2 = [];
160367
+ var byteToHex = [];
160368
160368
  for (let i = 0;i < 256; ++i) {
160369
- byteToHex2.push((i + 256).toString(16).slice(1));
160369
+ byteToHex.push((i + 256).toString(16).slice(1));
160370
160370
  }
160371
- function unsafeStringify2(arr, offset = 0) {
160372
- return byteToHex2[arr[offset + 0]] + byteToHex2[arr[offset + 1]] + byteToHex2[arr[offset + 2]] + byteToHex2[arr[offset + 3]] + "-" + byteToHex2[arr[offset + 4]] + byteToHex2[arr[offset + 5]] + "-" + byteToHex2[arr[offset + 6]] + byteToHex2[arr[offset + 7]] + "-" + byteToHex2[arr[offset + 8]] + byteToHex2[arr[offset + 9]] + "-" + byteToHex2[arr[offset + 10]] + byteToHex2[arr[offset + 11]] + byteToHex2[arr[offset + 12]] + byteToHex2[arr[offset + 13]] + byteToHex2[arr[offset + 14]] + byteToHex2[arr[offset + 15]];
160371
+ function unsafeStringify(arr, offset = 0) {
160372
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
160373
160373
  }
160374
160374
  function stringify(arr, offset = 0) {
160375
- const uuid = unsafeStringify2(arr, offset);
160375
+ const uuid = unsafeStringify(arr, offset);
160376
160376
  if (!(0, _validate.default)(uuid)) {
160377
160377
  throw TypeError("Stringified UUID is invalid");
160378
160378
  }
@@ -160613,7 +160613,7 @@ var require_v43 = __commonJS((exports) => {
160613
160613
  function _interopRequireDefault(obj) {
160614
160614
  return obj && obj.__esModule ? obj : { default: obj };
160615
160615
  }
160616
- function v42(options, buf, offset) {
160616
+ function v4(options, buf, offset) {
160617
160617
  if (_native.default.randomUUID && !buf && !options) {
160618
160618
  return _native.default.randomUUID();
160619
160619
  }
@@ -160630,7 +160630,7 @@ var require_v43 = __commonJS((exports) => {
160630
160630
  }
160631
160631
  return (0, _stringify.unsafeStringify)(rnds);
160632
160632
  }
160633
- var _default = v42;
160633
+ var _default = v4;
160634
160634
  exports.default = _default;
160635
160635
  });
160636
160636
 
@@ -160995,7 +160995,7 @@ var require_table = __commonJS((exports) => {
160995
160995
  var events_1 = __require("events");
160996
160996
  var fs2 = __require("fs");
160997
160997
  var is = require_is();
160998
- var path2 = __require("path");
160998
+ var path3 = __require("path");
160999
160999
  var streamEvents = require_stream_events();
161000
161000
  var uuid = require_dist9();
161001
161001
  var _1 = require_src121();
@@ -161241,7 +161241,7 @@ var require_table = __commonJS((exports) => {
161241
161241
  if (!common_1.util.isCustomType(dest, "storage/file")) {
161242
161242
  throw new Error("Destination must be a File object.");
161243
161243
  }
161244
- const format = path2.extname(dest.name).substr(1).toLowerCase();
161244
+ const format = path3.extname(dest.name).substr(1).toLowerCase();
161245
161245
  if (!options.destinationFormat && !options.format && FORMATS[format]) {
161246
161246
  options.destinationFormat = FORMATS[format];
161247
161247
  }
@@ -161299,7 +161299,7 @@ var require_table = __commonJS((exports) => {
161299
161299
  metadata.location = this.location;
161300
161300
  }
161301
161301
  if (typeof source === "string") {
161302
- const detectedFormat = FORMATS[path2.extname(source).substr(1).toLowerCase()];
161302
+ const detectedFormat = FORMATS[path3.extname(source).substr(1).toLowerCase()];
161303
161303
  if (!metadata.sourceFormat && detectedFormat) {
161304
161304
  metadata.sourceFormat = detectedFormat;
161305
161305
  }
@@ -161335,7 +161335,7 @@ var require_table = __commonJS((exports) => {
161335
161335
  if (!common_1.util.isCustomType(src, "storage/file")) {
161336
161336
  throw new Error("Source must be a File object.");
161337
161337
  }
161338
- const format = FORMATS[path2.extname(src.name).substr(1).toLowerCase()];
161338
+ const format = FORMATS[path3.extname(src.name).substr(1).toLowerCase()];
161339
161339
  if (!metadata.sourceFormat && format) {
161340
161340
  body.configuration.load.sourceFormat = format;
161341
161341
  }
@@ -164969,12 +164969,12 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
164969
164969
  const password = request.password ?? "";
164970
164970
  auth = `${username}:${password}`;
164971
164971
  }
164972
- let path2 = request.path;
164972
+ let path3 = request.path;
164973
164973
  if (queryString) {
164974
- path2 += `?${queryString}`;
164974
+ path3 += `?${queryString}`;
164975
164975
  }
164976
164976
  if (request.fragment) {
164977
- path2 += `#${request.fragment}`;
164977
+ path3 += `#${request.fragment}`;
164978
164978
  }
164979
164979
  let hostname = request.hostname ?? "";
164980
164980
  if (hostname[0] === "[" && hostname.endsWith("]")) {
@@ -164986,7 +164986,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
164986
164986
  headers: request.headers,
164987
164987
  host: hostname,
164988
164988
  method: request.method,
164989
- path: path2,
164989
+ path: path3,
164990
164990
  port: request.port,
164991
164991
  agent,
164992
164992
  auth
@@ -165244,16 +165244,16 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
165244
165244
  reject(err);
165245
165245
  };
165246
165246
  const queryString = querystringBuilder.buildQueryString(query || {});
165247
- let path2 = request.path;
165247
+ let path3 = request.path;
165248
165248
  if (queryString) {
165249
- path2 += `?${queryString}`;
165249
+ path3 += `?${queryString}`;
165250
165250
  }
165251
165251
  if (request.fragment) {
165252
- path2 += `#${request.fragment}`;
165252
+ path3 += `#${request.fragment}`;
165253
165253
  }
165254
165254
  const req = session.request({
165255
165255
  ...request.headers,
165256
- [http22.constants.HTTP2_HEADER_PATH]: path2,
165256
+ [http22.constants.HTTP2_HEADER_PATH]: path3,
165257
165257
  [http22.constants.HTTP2_HEADER_METHOD]: method
165258
165258
  });
165259
165259
  session.ref();
@@ -165440,13 +165440,13 @@ var require_dist_cjs13 = __commonJS((exports) => {
165440
165440
  abortError.name = "AbortError";
165441
165441
  return Promise.reject(abortError);
165442
165442
  }
165443
- let path2 = request.path;
165443
+ let path3 = request.path;
165444
165444
  const queryString = querystringBuilder.buildQueryString(request.query || {});
165445
165445
  if (queryString) {
165446
- path2 += `?${queryString}`;
165446
+ path3 += `?${queryString}`;
165447
165447
  }
165448
165448
  if (request.fragment) {
165449
- path2 += `#${request.fragment}`;
165449
+ path3 += `#${request.fragment}`;
165450
165450
  }
165451
165451
  let auth = "";
165452
165452
  if (request.username != null || request.password != null) {
@@ -165455,7 +165455,7 @@ var require_dist_cjs13 = __commonJS((exports) => {
165455
165455
  auth = `${username}:${password}@`;
165456
165456
  }
165457
165457
  const { port, method } = request;
165458
- const url2 = `${request.protocol}//${auth}${request.hostname}${port ? `:${port}` : ""}${path2}`;
165458
+ const url2 = `${request.protocol}//${auth}${request.hostname}${port ? `:${port}` : ""}${path3}`;
165459
165459
  const body = method === "GET" || method === "HEAD" ? undefined : request.body;
165460
165460
  const requestOptions = {
165461
165461
  body,
@@ -167049,13 +167049,13 @@ var require_tslib = __commonJS((exports, module) => {
167049
167049
  }
167050
167050
  return next();
167051
167051
  };
167052
- __rewriteRelativeImportExtension = function(path2, preserveJsx) {
167053
- if (typeof path2 === "string" && /^\.\.?\//.test(path2)) {
167054
- return path2.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
167052
+ __rewriteRelativeImportExtension = function(path3, preserveJsx) {
167053
+ if (typeof path3 === "string" && /^\.\.?\//.test(path3)) {
167054
+ return path3.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
167055
167055
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
167056
167056
  });
167057
167057
  }
167058
- return path2;
167058
+ return path3;
167059
167059
  };
167060
167060
  exporter("__extends", __extends);
167061
167061
  exporter("__assign", __assign);
@@ -167103,11 +167103,11 @@ var require_randomUUID = __commonJS((exports) => {
167103
167103
 
167104
167104
  // ../../node_modules/@smithy/uuid/dist-cjs/index.js
167105
167105
  var require_dist_cjs16 = __commonJS((exports) => {
167106
- var randomUUID3 = require_randomUUID();
167106
+ var randomUUID2 = require_randomUUID();
167107
167107
  var decimalToHex = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
167108
- var v42 = () => {
167109
- if (randomUUID3.randomUUID) {
167110
- return randomUUID3.randomUUID();
167108
+ var v4 = () => {
167109
+ if (randomUUID2.randomUUID) {
167110
+ return randomUUID2.randomUUID();
167111
167111
  }
167112
167112
  const rnds = new Uint8Array(16);
167113
167113
  crypto.getRandomValues(rnds);
@@ -167115,7 +167115,7 @@ var require_dist_cjs16 = __commonJS((exports) => {
167115
167115
  rnds[8] = rnds[8] & 63 | 128;
167116
167116
  return decimalToHex[rnds[0]] + decimalToHex[rnds[1]] + decimalToHex[rnds[2]] + decimalToHex[rnds[3]] + "-" + decimalToHex[rnds[4]] + decimalToHex[rnds[5]] + "-" + decimalToHex[rnds[6]] + decimalToHex[rnds[7]] + "-" + decimalToHex[rnds[8]] + decimalToHex[rnds[9]] + "-" + decimalToHex[rnds[10]] + decimalToHex[rnds[11]] + decimalToHex[rnds[12]] + decimalToHex[rnds[13]] + decimalToHex[rnds[14]] + decimalToHex[rnds[15]];
167117
167117
  };
167118
- exports.v4 = v42;
167118
+ exports.v4 = v4;
167119
167119
  });
167120
167120
 
167121
167121
  // ../../node_modules/@smithy/core/dist-cjs/submodules/serde/index.js
@@ -168203,11 +168203,11 @@ var require_protocols = __commonJS((exports) => {
168203
168203
  const opTraits = schema.translateTraits(operationSchema.traits);
168204
168204
  if (opTraits.http) {
168205
168205
  request.method = opTraits.http[0];
168206
- const [path2, search] = opTraits.http[1].split("?");
168206
+ const [path3, search] = opTraits.http[1].split("?");
168207
168207
  if (request.path == "/") {
168208
- request.path = path2;
168208
+ request.path = path3;
168209
168209
  } else {
168210
- request.path += path2;
168210
+ request.path += path3;
168211
168211
  }
168212
168212
  const traitSearchParams = new URLSearchParams(search ?? "");
168213
168213
  Object.assign(query, Object.fromEntries(traitSearchParams));
@@ -168559,8 +168559,8 @@ var require_protocols = __commonJS((exports) => {
168559
168559
  return this;
168560
168560
  }
168561
168561
  p(memberName, labelValueProvider, uriLabel, isGreedyLabel) {
168562
- this.resolvePathStack.push((path2) => {
168563
- this.path = resolvedPath(path2, this.input, memberName, labelValueProvider, uriLabel, isGreedyLabel);
168562
+ this.resolvePathStack.push((path3) => {
168563
+ this.path = resolvedPath(path3, this.input, memberName, labelValueProvider, uriLabel, isGreedyLabel);
168564
168564
  });
168565
168565
  return this;
168566
168566
  }
@@ -168995,9 +168995,9 @@ var require_dist_cjs17 = __commonJS((exports) => {
168995
168995
  return;
168996
168996
  };
168997
168997
  }
168998
- var get = (fromObject, path2) => {
168998
+ var get = (fromObject, path3) => {
168999
168999
  let cursor = fromObject;
169000
- const pathComponents = path2.split(".");
169000
+ const pathComponents = path3.split(".");
169001
169001
  for (const step of pathComponents) {
169002
169002
  if (!cursor || typeof cursor !== "object") {
169003
169003
  return;
@@ -169641,10 +169641,10 @@ ${longDate}
169641
169641
  ${credentialScope}
169642
169642
  ${utilHexEncoding.toHex(hashedRequest)}`;
169643
169643
  }
169644
- getCanonicalPath({ path: path2 }) {
169644
+ getCanonicalPath({ path: path3 }) {
169645
169645
  if (this.uriEscapePath) {
169646
169646
  const normalizedPathSegments = [];
169647
- for (const pathSegment of path2.split("/")) {
169647
+ for (const pathSegment of path3.split("/")) {
169648
169648
  if (pathSegment?.length === 0)
169649
169649
  continue;
169650
169650
  if (pathSegment === ".")
@@ -169655,11 +169655,11 @@ ${utilHexEncoding.toHex(hashedRequest)}`;
169655
169655
  normalizedPathSegments.push(pathSegment);
169656
169656
  }
169657
169657
  }
169658
- const normalizedPath = `${path2?.startsWith("/") ? "/" : ""}${normalizedPathSegments.join("/")}${normalizedPathSegments.length > 0 && path2?.endsWith("/") ? "/" : ""}`;
169658
+ const normalizedPath = `${path3?.startsWith("/") ? "/" : ""}${normalizedPathSegments.join("/")}${normalizedPathSegments.length > 0 && path3?.endsWith("/") ? "/" : ""}`;
169659
169659
  const doubleEncoded = utilUriEscape.escapeUri(normalizedPath);
169660
169660
  return doubleEncoded.replace(/%2F/g, "/");
169661
169661
  }
169662
- return path2;
169662
+ return path3;
169663
169663
  }
169664
169664
  validateResolvedCredentials(credentials) {
169665
169665
  if (typeof credentials !== "object" || typeof credentials.accessKeyId !== "string" || typeof credentials.secretAccessKey !== "string") {
@@ -170571,14 +170571,14 @@ var require_cbor = __commonJS((exports) => {
170571
170571
  throw new Error("Malformed RPCv2 CBOR response, status: " + response.statusCode);
170572
170572
  }
170573
170573
  };
170574
- var buildHttpRpcRequest = async (context, headers, path2, resolvedHostname, body) => {
170574
+ var buildHttpRpcRequest = async (context, headers, path3, resolvedHostname, body) => {
170575
170575
  const { hostname, protocol = "https", port, path: basePath } = await context.endpoint();
170576
170576
  const contents = {
170577
170577
  protocol,
170578
170578
  hostname,
170579
170579
  port,
170580
170580
  method: "POST",
170581
- path: basePath.endsWith("/") ? basePath.slice(0, -1) + path2 : basePath + path2,
170581
+ path: basePath.endsWith("/") ? basePath.slice(0, -1) + path3 : basePath + path3,
170582
170582
  headers: {
170583
170583
  ...headers
170584
170584
  }
@@ -170806,11 +170806,11 @@ var require_cbor = __commonJS((exports) => {
170806
170806
  } catch (e) {}
170807
170807
  }
170808
170808
  const { service, operation } = utilMiddleware.getSmithyContext(context);
170809
- const path2 = `/service/${service}/operation/${operation}`;
170809
+ const path3 = `/service/${service}/operation/${operation}`;
170810
170810
  if (request.path.endsWith("/")) {
170811
- request.path += path2.slice(1);
170811
+ request.path += path3.slice(1);
170812
170812
  } else {
170813
- request.path += path2;
170813
+ request.path += path3;
170814
170814
  }
170815
170815
  return request;
170816
170816
  }
@@ -177273,18 +177273,18 @@ var require_dist_cjs36 = __commonJS((exports) => {
177273
177273
  }
177274
177274
  }
177275
177275
  var booleanEquals = (value1, value2) => value1 === value2;
177276
- var getAttrPathList = (path2) => {
177277
- const parts = path2.split(".");
177276
+ var getAttrPathList = (path3) => {
177277
+ const parts = path3.split(".");
177278
177278
  const pathList = [];
177279
177279
  for (const part of parts) {
177280
177280
  const squareBracketIndex = part.indexOf("[");
177281
177281
  if (squareBracketIndex !== -1) {
177282
177282
  if (part.indexOf("]") !== part.length - 1) {
177283
- throw new EndpointError(`Path: '${path2}' does not end with ']'`);
177283
+ throw new EndpointError(`Path: '${path3}' does not end with ']'`);
177284
177284
  }
177285
177285
  const arrayIndex = part.slice(squareBracketIndex + 1, -1);
177286
177286
  if (Number.isNaN(parseInt(arrayIndex))) {
177287
- throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${path2}'`);
177287
+ throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${path3}'`);
177288
177288
  }
177289
177289
  if (squareBracketIndex !== 0) {
177290
177290
  pathList.push(part.slice(0, squareBracketIndex));
@@ -177296,9 +177296,9 @@ var require_dist_cjs36 = __commonJS((exports) => {
177296
177296
  }
177297
177297
  return pathList;
177298
177298
  };
177299
- var getAttr = (value, path2) => getAttrPathList(path2).reduce((acc, index) => {
177299
+ var getAttr = (value, path3) => getAttrPathList(path3).reduce((acc, index) => {
177300
177300
  if (typeof acc !== "object") {
177301
- throw new EndpointError(`Index '${index}' in '${path2}' not found in '${JSON.stringify(value)}'`);
177301
+ throw new EndpointError(`Index '${index}' in '${path3}' not found in '${JSON.stringify(value)}'`);
177302
177302
  } else if (Array.isArray(acc)) {
177303
177303
  return acc[parseInt(index)];
177304
177304
  }
@@ -177317,8 +177317,8 @@ var require_dist_cjs36 = __commonJS((exports) => {
177317
177317
  return value;
177318
177318
  }
177319
177319
  if (typeof value === "object" && "hostname" in value) {
177320
- const { hostname: hostname2, port, protocol: protocol2 = "", path: path2 = "", query = {} } = value;
177321
- const url2 = new URL(`${protocol2}//${hostname2}${port ? `:${port}` : ""}${path2}`);
177320
+ const { hostname: hostname2, port, protocol: protocol2 = "", path: path3 = "", query = {} } = value;
177321
+ const url2 = new URL(`${protocol2}//${hostname2}${port ? `:${port}` : ""}${path3}`);
177322
177322
  url2.search = Object.entries(query).map(([k, v]) => `${k}=${v}`).join("&");
177323
177323
  return url2;
177324
177324
  }
@@ -178526,14 +178526,14 @@ var require_readFile = __commonJS((exports) => {
178526
178526
  var promises_1 = __require("node:fs/promises");
178527
178527
  exports.filePromises = {};
178528
178528
  exports.fileIntercept = {};
178529
- var readFile = (path2, options) => {
178530
- if (exports.fileIntercept[path2] !== undefined) {
178531
- return exports.fileIntercept[path2];
178529
+ var readFile = (path3, options) => {
178530
+ if (exports.fileIntercept[path3] !== undefined) {
178531
+ return exports.fileIntercept[path3];
178532
178532
  }
178533
- if (!exports.filePromises[path2] || options?.ignoreCache) {
178534
- exports.filePromises[path2] = (0, promises_1.readFile)(path2, "utf8");
178533
+ if (!exports.filePromises[path3] || options?.ignoreCache) {
178534
+ exports.filePromises[path3] = (0, promises_1.readFile)(path3, "utf8");
178535
178535
  }
178536
- return exports.filePromises[path2];
178536
+ return exports.filePromises[path3];
178537
178537
  };
178538
178538
  exports.readFile = readFile;
178539
178539
  });
@@ -178543,7 +178543,7 @@ var require_dist_cjs44 = __commonJS((exports) => {
178543
178543
  var getHomeDir = require_getHomeDir();
178544
178544
  var getSSOTokenFilepath = require_getSSOTokenFilepath();
178545
178545
  var getSSOTokenFromFile = require_getSSOTokenFromFile();
178546
- var path2 = __require("path");
178546
+ var path3 = __require("path");
178547
178547
  var types2 = require_dist_cjs();
178548
178548
  var readFile = require_readFile();
178549
178549
  var ENV_PROFILE = "AWS_PROFILE";
@@ -178565,9 +178565,9 @@ var require_dist_cjs44 = __commonJS((exports) => {
178565
178565
  ...data.default && { default: data.default }
178566
178566
  });
178567
178567
  var ENV_CONFIG_PATH = "AWS_CONFIG_FILE";
178568
- var getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || path2.join(getHomeDir.getHomeDir(), ".aws", "config");
178568
+ var getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || path3.join(getHomeDir.getHomeDir(), ".aws", "config");
178569
178569
  var ENV_CREDENTIALS_PATH = "AWS_SHARED_CREDENTIALS_FILE";
178570
- var getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || path2.join(getHomeDir.getHomeDir(), ".aws", "credentials");
178570
+ var getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || path3.join(getHomeDir.getHomeDir(), ".aws", "credentials");
178571
178571
  var prefixKeyRegex = /^([\w-]+)\s(["'])?([\w-@\+\.%:/]+)\2$/;
178572
178572
  var profileNameBlockList = ["__proto__", "profile __proto__"];
178573
178573
  var parseIni = (iniData) => {
@@ -178622,11 +178622,11 @@ var require_dist_cjs44 = __commonJS((exports) => {
178622
178622
  const relativeHomeDirPrefix = "~/";
178623
178623
  let resolvedFilepath = filepath;
178624
178624
  if (filepath.startsWith(relativeHomeDirPrefix)) {
178625
- resolvedFilepath = path2.join(homeDir, filepath.slice(2));
178625
+ resolvedFilepath = path3.join(homeDir, filepath.slice(2));
178626
178626
  }
178627
178627
  let resolvedConfigFilepath = configFilepath;
178628
178628
  if (configFilepath.startsWith(relativeHomeDirPrefix)) {
178629
- resolvedConfigFilepath = path2.join(homeDir, configFilepath.slice(2));
178629
+ resolvedConfigFilepath = path3.join(homeDir, configFilepath.slice(2));
178630
178630
  }
178631
178631
  const parsedFiles = await Promise.all([
178632
178632
  readFile.readFile(resolvedConfigFilepath, {
@@ -178665,8 +178665,8 @@ var require_dist_cjs44 = __commonJS((exports) => {
178665
178665
  getFileRecord() {
178666
178666
  return readFile.fileIntercept;
178667
178667
  },
178668
- interceptFile(path3, contents) {
178669
- readFile.fileIntercept[path3] = Promise.resolve(contents);
178668
+ interceptFile(path4, contents) {
178669
+ readFile.fileIntercept[path4] = Promise.resolve(contents);
178670
178670
  },
178671
178671
  getTokenRecord() {
178672
178672
  return getSSOTokenFromFile.tokenIntercept;
@@ -178894,8 +178894,8 @@ var require_dist_cjs46 = __commonJS((exports) => {
178894
178894
  return endpoint.url.href;
178895
178895
  }
178896
178896
  if ("hostname" in endpoint) {
178897
- const { protocol, hostname, port, path: path2 } = endpoint;
178898
- return `${protocol}//${hostname}${port ? ":" + port : ""}${path2}`;
178897
+ const { protocol, hostname, port, path: path3 } = endpoint;
178898
+ return `${protocol}//${hostname}${port ? ":" + port : ""}${path3}`;
178899
178899
  }
178900
178900
  }
178901
178901
  return endpoint;
@@ -196989,26 +196989,26 @@ var require_utils74 = __commonJS((exports, module) => {
196989
196989
  }
196990
196990
  mkdirSync(folder);
196991
196991
  };
196992
- Utils.prototype.writeFileTo = function(path3, content, overwrite, attr) {
196992
+ Utils.prototype.writeFileTo = function(path4, content, overwrite, attr) {
196993
196993
  const self2 = this;
196994
- if (self2.fs.existsSync(path3)) {
196994
+ if (self2.fs.existsSync(path4)) {
196995
196995
  if (!overwrite)
196996
196996
  return false;
196997
- var stat4 = self2.fs.statSync(path3);
196997
+ var stat4 = self2.fs.statSync(path4);
196998
196998
  if (stat4.isDirectory()) {
196999
196999
  return false;
197000
197000
  }
197001
197001
  }
197002
- var folder = pth.dirname(path3);
197002
+ var folder = pth.dirname(path4);
197003
197003
  if (!self2.fs.existsSync(folder)) {
197004
197004
  self2.makeDir(folder);
197005
197005
  }
197006
197006
  var fd;
197007
197007
  try {
197008
- fd = self2.fs.openSync(path3, "w", 438);
197008
+ fd = self2.fs.openSync(path4, "w", 438);
197009
197009
  } catch (e) {
197010
- self2.fs.chmodSync(path3, 438);
197011
- fd = self2.fs.openSync(path3, "w", 438);
197010
+ self2.fs.chmodSync(path4, 438);
197011
+ fd = self2.fs.openSync(path4, "w", 438);
197012
197012
  }
197013
197013
  if (fd) {
197014
197014
  try {
@@ -197017,33 +197017,33 @@ var require_utils74 = __commonJS((exports, module) => {
197017
197017
  self2.fs.closeSync(fd);
197018
197018
  }
197019
197019
  }
197020
- self2.fs.chmodSync(path3, attr || 438);
197020
+ self2.fs.chmodSync(path4, attr || 438);
197021
197021
  return true;
197022
197022
  };
197023
- Utils.prototype.writeFileToAsync = function(path3, content, overwrite, attr, callback) {
197023
+ Utils.prototype.writeFileToAsync = function(path4, content, overwrite, attr, callback) {
197024
197024
  if (typeof attr === "function") {
197025
197025
  callback = attr;
197026
197026
  attr = undefined;
197027
197027
  }
197028
197028
  const self2 = this;
197029
- self2.fs.exists(path3, function(exist) {
197029
+ self2.fs.exists(path4, function(exist) {
197030
197030
  if (exist && !overwrite)
197031
197031
  return callback(false);
197032
- self2.fs.stat(path3, function(err, stat4) {
197032
+ self2.fs.stat(path4, function(err, stat4) {
197033
197033
  if (exist && stat4.isDirectory()) {
197034
197034
  return callback(false);
197035
197035
  }
197036
- var folder = pth.dirname(path3);
197036
+ var folder = pth.dirname(path4);
197037
197037
  self2.fs.exists(folder, function(exists) {
197038
197038
  if (!exists)
197039
197039
  self2.makeDir(folder);
197040
- self2.fs.open(path3, "w", 438, function(err2, fd) {
197040
+ self2.fs.open(path4, "w", 438, function(err2, fd) {
197041
197041
  if (err2) {
197042
- self2.fs.chmod(path3, 438, function() {
197043
- self2.fs.open(path3, "w", 438, function(err3, fd2) {
197042
+ self2.fs.chmod(path4, 438, function() {
197043
+ self2.fs.open(path4, "w", 438, function(err3, fd2) {
197044
197044
  self2.fs.write(fd2, content, 0, content.length, 0, function() {
197045
197045
  self2.fs.close(fd2, function() {
197046
- self2.fs.chmod(path3, attr || 438, function() {
197046
+ self2.fs.chmod(path4, attr || 438, function() {
197047
197047
  callback(true);
197048
197048
  });
197049
197049
  });
@@ -197053,13 +197053,13 @@ var require_utils74 = __commonJS((exports, module) => {
197053
197053
  } else if (fd) {
197054
197054
  self2.fs.write(fd, content, 0, content.length, 0, function() {
197055
197055
  self2.fs.close(fd, function() {
197056
- self2.fs.chmod(path3, attr || 438, function() {
197056
+ self2.fs.chmod(path4, attr || 438, function() {
197057
197057
  callback(true);
197058
197058
  });
197059
197059
  });
197060
197060
  });
197061
197061
  } else {
197062
- self2.fs.chmod(path3, attr || 438, function() {
197062
+ self2.fs.chmod(path4, attr || 438, function() {
197063
197063
  callback(true);
197064
197064
  });
197065
197065
  }
@@ -197068,7 +197068,7 @@ var require_utils74 = __commonJS((exports, module) => {
197068
197068
  });
197069
197069
  });
197070
197070
  };
197071
- Utils.prototype.findFiles = function(path3) {
197071
+ Utils.prototype.findFiles = function(path4) {
197072
197072
  const self2 = this;
197073
197073
  function findSync(dir, pattern, recursive) {
197074
197074
  if (typeof pattern === "boolean") {
@@ -197077,17 +197077,17 @@ var require_utils74 = __commonJS((exports, module) => {
197077
197077
  }
197078
197078
  let files = [];
197079
197079
  self2.fs.readdirSync(dir).forEach(function(file) {
197080
- const path4 = pth.join(dir, file);
197081
- const stat4 = self2.fs.statSync(path4);
197082
- if (!pattern || pattern.test(path4)) {
197083
- files.push(pth.normalize(path4) + (stat4.isDirectory() ? self2.sep : ""));
197080
+ const path5 = pth.join(dir, file);
197081
+ const stat4 = self2.fs.statSync(path5);
197082
+ if (!pattern || pattern.test(path5)) {
197083
+ files.push(pth.normalize(path5) + (stat4.isDirectory() ? self2.sep : ""));
197084
197084
  }
197085
197085
  if (stat4.isDirectory() && recursive)
197086
- files = files.concat(findSync(path4, pattern, recursive));
197086
+ files = files.concat(findSync(path5, pattern, recursive));
197087
197087
  });
197088
197088
  return files;
197089
197089
  }
197090
- return findSync(path3, undefined, true);
197090
+ return findSync(path4, undefined, true);
197091
197091
  };
197092
197092
  Utils.prototype.findFilesAsync = function(dir, cb) {
197093
197093
  const self2 = this;
@@ -197147,16 +197147,16 @@ var require_utils74 = __commonJS((exports, module) => {
197147
197147
  return "UNSUPPORTED (" + method + ")";
197148
197148
  }
197149
197149
  };
197150
- Utils.canonical = function(path3) {
197151
- if (!path3)
197150
+ Utils.canonical = function(path4) {
197151
+ if (!path4)
197152
197152
  return "";
197153
- const safeSuffix = pth.posix.normalize("/" + path3.split("\\").join("/"));
197153
+ const safeSuffix = pth.posix.normalize("/" + path4.split("\\").join("/"));
197154
197154
  return pth.join(".", safeSuffix);
197155
197155
  };
197156
- Utils.zipnamefix = function(path3) {
197157
- if (!path3)
197156
+ Utils.zipnamefix = function(path4) {
197157
+ if (!path4)
197158
197158
  return "";
197159
- const safeSuffix = pth.posix.normalize("/" + path3.split("\\").join("/"));
197159
+ const safeSuffix = pth.posix.normalize("/" + path4.split("\\").join("/"));
197160
197160
  return pth.posix.join(".", safeSuffix);
197161
197161
  };
197162
197162
  Utils.findLast = function(arr, callback) {
@@ -197174,9 +197174,9 @@ var require_utils74 = __commonJS((exports, module) => {
197174
197174
  prefix = pth.resolve(pth.normalize(prefix));
197175
197175
  var parts = name.split("/");
197176
197176
  for (var i = 0, l = parts.length;i < l; i++) {
197177
- var path3 = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep)));
197178
- if (path3.indexOf(prefix) === 0) {
197179
- return path3;
197177
+ var path4 = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep)));
197178
+ if (path4.indexOf(prefix) === 0) {
197179
+ return path4;
197180
197180
  }
197181
197181
  }
197182
197182
  return pth.normalize(pth.join(prefix, pth.basename(name)));
@@ -197214,8 +197214,8 @@ var require_utils74 = __commonJS((exports, module) => {
197214
197214
  // ../../node_modules/adm-zip/util/fattr.js
197215
197215
  var require_fattr = __commonJS((exports, module) => {
197216
197216
  var pth = __require("path");
197217
- module.exports = function(path3, { fs: fs2 }) {
197218
- var _path = path3 || "", _obj = newAttr(), _stat = null;
197217
+ module.exports = function(path4, { fs: fs2 }) {
197218
+ var _path = path4 || "", _obj = newAttr(), _stat = null;
197219
197219
  function newAttr() {
197220
197220
  return {
197221
197221
  directory: false,
@@ -197722,7 +197722,7 @@ var require_inflater = __commonJS((exports, module) => {
197722
197722
 
197723
197723
  // ../../node_modules/adm-zip/methods/zipcrypto.js
197724
197724
  var require_zipcrypto = __commonJS((exports, module) => {
197725
- var { randomFillSync: randomFillSync2 } = __require("crypto");
197725
+ var { randomFillSync } = __require("crypto");
197726
197726
  var Errors = require_errors6();
197727
197727
  var crctable = new Uint32Array(256).map((t, crc) => {
197728
197728
  for (let j = 0;j < 8; j++) {
@@ -197739,8 +197739,8 @@ var require_zipcrypto = __commonJS((exports, module) => {
197739
197739
  return crctable[(pCrc32 ^ bval) & 255] ^ pCrc32 >>> 8;
197740
197740
  };
197741
197741
  var genSalt = () => {
197742
- if (typeof randomFillSync2 === "function") {
197743
- return randomFillSync2(Buffer.alloc(12));
197742
+ if (typeof randomFillSync === "function") {
197743
+ return randomFillSync(Buffer.alloc(12));
197744
197744
  } else {
197745
197745
  return genSalt.node();
197746
197746
  }
@@ -199074,10 +199074,10 @@ var require_src122 = __commonJS((exports) => {
199074
199074
  var fs_1 = __require("fs");
199075
199075
  var debug_1 = __importDefault(require_src5());
199076
199076
  var log = debug_1.default("@kwsites/file-exists");
199077
- function check(path3, isFile2, isDirectory) {
199078
- log(`checking %s`, path3);
199077
+ function check(path4, isFile2, isDirectory) {
199078
+ log(`checking %s`, path4);
199079
199079
  try {
199080
- const stat4 = fs_1.statSync(path3);
199080
+ const stat4 = fs_1.statSync(path4);
199081
199081
  if (stat4.isFile() && isFile2) {
199082
199082
  log(`[OK] path represents a file`);
199083
199083
  return true;
@@ -199097,8 +199097,8 @@ var require_src122 = __commonJS((exports) => {
199097
199097
  throw e;
199098
199098
  }
199099
199099
  }
199100
- function exists(path3, type = exports.READABLE) {
199101
- return check(path3, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
199100
+ function exists(path4, type = exports.READABLE) {
199101
+ return check(path4, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
199102
199102
  }
199103
199103
  exports.exists = exists;
199104
199104
  exports.FILE = 1;
@@ -199378,14 +199378,14 @@ var require_brace_expansion = __commonJS((exports, module) => {
199378
199378
  var require_minimatch = __commonJS((exports, module) => {
199379
199379
  module.exports = minimatch;
199380
199380
  minimatch.Minimatch = Minimatch;
199381
- var path5 = function() {
199381
+ var path6 = function() {
199382
199382
  try {
199383
199383
  return __require("path");
199384
199384
  } catch (e) {}
199385
199385
  }() || {
199386
199386
  sep: "/"
199387
199387
  };
199388
- minimatch.sep = path5.sep;
199388
+ minimatch.sep = path6.sep;
199389
199389
  var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {};
199390
199390
  var expand = require_brace_expansion();
199391
199391
  var plTypes = {
@@ -199476,8 +199476,8 @@ var require_minimatch = __commonJS((exports, module) => {
199476
199476
  if (!options)
199477
199477
  options = {};
199478
199478
  pattern = pattern.trim();
199479
- if (!options.allowWindowsEscape && path5.sep !== "/") {
199480
- pattern = pattern.split(path5.sep).join("/");
199479
+ if (!options.allowWindowsEscape && path6.sep !== "/") {
199480
+ pattern = pattern.split(path6.sep).join("/");
199481
199481
  }
199482
199482
  this.options = options;
199483
199483
  this.set = [];
@@ -199854,8 +199854,8 @@ var require_minimatch = __commonJS((exports, module) => {
199854
199854
  if (f === "/" && partial)
199855
199855
  return true;
199856
199856
  var options = this.options;
199857
- if (path5.sep !== "/") {
199858
- f = f.split(path5.sep).join("/");
199857
+ if (path6.sep !== "/") {
199858
+ f = f.split(path6.sep).join("/");
199859
199859
  }
199860
199860
  f = f.split(slashSplit);
199861
199861
  this.debug(this.pattern, "split", f);
@@ -199966,9 +199966,9 @@ var require_recursive_readdir = __commonJS((exports, module) => {
199966
199966
  var p = __require("path");
199967
199967
  var minimatch = require_minimatch();
199968
199968
  function patternMatcher(pattern) {
199969
- return function(path5, stats) {
199969
+ return function(path6, stats) {
199970
199970
  var minimatcher = new minimatch.Minimatch(pattern, { matchBase: true });
199971
- return (!minimatcher.negate || stats.isFile()) && minimatcher.match(path5);
199971
+ return (!minimatcher.negate || stats.isFile()) && minimatcher.match(path6);
199972
199972
  };
199973
199973
  }
199974
199974
  function toMatcherFunction(ignoreEntry) {
@@ -199978,14 +199978,14 @@ var require_recursive_readdir = __commonJS((exports, module) => {
199978
199978
  return patternMatcher(ignoreEntry);
199979
199979
  }
199980
199980
  }
199981
- function readdir3(path5, ignores, callback) {
199981
+ function readdir3(path6, ignores, callback) {
199982
199982
  if (typeof ignores == "function") {
199983
199983
  callback = ignores;
199984
199984
  ignores = [];
199985
199985
  }
199986
199986
  if (!callback) {
199987
199987
  return new Promise(function(resolve3, reject) {
199988
- readdir3(path5, ignores || [], function(err, data) {
199988
+ readdir3(path6, ignores || [], function(err, data) {
199989
199989
  if (err) {
199990
199990
  reject(err);
199991
199991
  } else {
@@ -199996,7 +199996,7 @@ var require_recursive_readdir = __commonJS((exports, module) => {
199996
199996
  }
199997
199997
  ignores = ignores.map(toMatcherFunction);
199998
199998
  var list = [];
199999
- fs4.readdir(path5, function(err, files) {
199999
+ fs4.readdir(path6, function(err, files) {
200000
200000
  if (err) {
200001
200001
  return callback(err);
200002
200002
  }
@@ -200005,7 +200005,7 @@ var require_recursive_readdir = __commonJS((exports, module) => {
200005
200005
  return callback(null, list);
200006
200006
  }
200007
200007
  files.forEach(function(file) {
200008
- var filePath = p.join(path5, file);
200008
+ var filePath = p.join(path6, file);
200009
200009
  fs4.stat(filePath, function(_err, stats) {
200010
200010
  if (_err) {
200011
200011
  return callback(_err);
@@ -200851,8 +200851,8 @@ var require_uri_all = __commonJS((exports, module) => {
200851
200851
  wsComponents.secure = undefined;
200852
200852
  }
200853
200853
  if (wsComponents.resourceName) {
200854
- var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path10 = _wsComponents$resourc2[0], query = _wsComponents$resourc2[1];
200855
- wsComponents.path = path10 && path10 !== "/" ? path10 : undefined;
200854
+ var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path11 = _wsComponents$resourc2[0], query = _wsComponents$resourc2[1];
200855
+ wsComponents.path = path11 && path11 !== "/" ? path11 : undefined;
200856
200856
  wsComponents.query = query;
200857
200857
  wsComponents.resourceName = undefined;
200858
200858
  }
@@ -201245,12 +201245,12 @@ var require_util13 = __commonJS((exports, module) => {
201245
201245
  return "'" + escapeQuotes(str) + "'";
201246
201246
  }
201247
201247
  function getPathExpr(currentPath, expr, jsonPointers, isNumber2) {
201248
- var path10 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'";
201249
- return joinPaths(currentPath, path10);
201248
+ var path11 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'";
201249
+ return joinPaths(currentPath, path11);
201250
201250
  }
201251
201251
  function getPath(currentPath, prop, jsonPointers) {
201252
- var path10 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop));
201253
- return joinPaths(currentPath, path10);
201252
+ var path11 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop));
201253
+ return joinPaths(currentPath, path11);
201254
201254
  }
201255
201255
  var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
201256
201256
  var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
@@ -207304,11 +207304,11 @@ var require_ast = __commonJS((exports, module) => {
207304
207304
  helperExpression: function helperExpression(node) {
207305
207305
  return node.type === "SubExpression" || (node.type === "MustacheStatement" || node.type === "BlockStatement") && !!(node.params && node.params.length || node.hash);
207306
207306
  },
207307
- scopedId: function scopedId(path10) {
207308
- return /^\.|this\b/.test(path10.original);
207307
+ scopedId: function scopedId(path11) {
207308
+ return /^\.|this\b/.test(path11.original);
207309
207309
  },
207310
- simpleId: function simpleId(path10) {
207311
- return path10.parts.length === 1 && !AST.helpers.scopedId(path10) && !path10.depth;
207310
+ simpleId: function simpleId(path11) {
207311
+ return path11.parts.length === 1 && !AST.helpers.scopedId(path11) && !path11.depth;
207312
207312
  }
207313
207313
  }
207314
207314
  };
@@ -208368,12 +208368,12 @@ var require_helpers3 = __commonJS((exports) => {
208368
208368
  loc
208369
208369
  };
208370
208370
  }
208371
- function prepareMustache(path10, params, hash, open2, strip, locInfo) {
208371
+ function prepareMustache(path11, params, hash, open2, strip, locInfo) {
208372
208372
  var escapeFlag = open2.charAt(3) || open2.charAt(2), escaped = escapeFlag !== "{" && escapeFlag !== "&";
208373
208373
  var decorator = /\*/.test(open2);
208374
208374
  return {
208375
208375
  type: decorator ? "Decorator" : "MustacheStatement",
208376
- path: path10,
208376
+ path: path11,
208377
208377
  params,
208378
208378
  hash,
208379
208379
  escaped,
@@ -208637,9 +208637,9 @@ var require_compiler = __commonJS((exports) => {
208637
208637
  },
208638
208638
  DecoratorBlock: function DecoratorBlock(decorator) {
208639
208639
  var program = decorator.program && this.compileProgram(decorator.program);
208640
- var params = this.setupFullMustacheParams(decorator, program, undefined), path10 = decorator.path;
208640
+ var params = this.setupFullMustacheParams(decorator, program, undefined), path11 = decorator.path;
208641
208641
  this.useDecorators = true;
208642
- this.opcode("registerDecorator", params.length, path10.original);
208642
+ this.opcode("registerDecorator", params.length, path11.original);
208643
208643
  },
208644
208644
  PartialStatement: function PartialStatement(partial) {
208645
208645
  this.usePartial = true;
@@ -208702,46 +208702,46 @@ var require_compiler = __commonJS((exports) => {
208702
208702
  }
208703
208703
  },
208704
208704
  ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) {
208705
- var path10 = sexpr.path, name = path10.parts[0], isBlock = program != null || inverse != null;
208706
- this.opcode("getContext", path10.depth);
208705
+ var path11 = sexpr.path, name = path11.parts[0], isBlock = program != null || inverse != null;
208706
+ this.opcode("getContext", path11.depth);
208707
208707
  this.opcode("pushProgram", program);
208708
208708
  this.opcode("pushProgram", inverse);
208709
- path10.strict = true;
208710
- this.accept(path10);
208709
+ path11.strict = true;
208710
+ this.accept(path11);
208711
208711
  this.opcode("invokeAmbiguous", name, isBlock);
208712
208712
  },
208713
208713
  simpleSexpr: function simpleSexpr(sexpr) {
208714
- var path10 = sexpr.path;
208715
- path10.strict = true;
208716
- this.accept(path10);
208714
+ var path11 = sexpr.path;
208715
+ path11.strict = true;
208716
+ this.accept(path11);
208717
208717
  this.opcode("resolvePossibleLambda");
208718
208718
  },
208719
208719
  helperSexpr: function helperSexpr(sexpr, program, inverse) {
208720
- var params = this.setupFullMustacheParams(sexpr, program, inverse), path10 = sexpr.path, name = path10.parts[0];
208720
+ var params = this.setupFullMustacheParams(sexpr, program, inverse), path11 = sexpr.path, name = path11.parts[0];
208721
208721
  if (this.options.knownHelpers[name]) {
208722
208722
  this.opcode("invokeKnownHelper", params.length, name);
208723
208723
  } else if (this.options.knownHelpersOnly) {
208724
208724
  throw new _exception2["default"]("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
208725
208725
  } else {
208726
- path10.strict = true;
208727
- path10.falsy = true;
208728
- this.accept(path10);
208729
- this.opcode("invokeHelper", params.length, path10.original, _ast2["default"].helpers.simpleId(path10));
208726
+ path11.strict = true;
208727
+ path11.falsy = true;
208728
+ this.accept(path11);
208729
+ this.opcode("invokeHelper", params.length, path11.original, _ast2["default"].helpers.simpleId(path11));
208730
208730
  }
208731
208731
  },
208732
- PathExpression: function PathExpression(path10) {
208733
- this.addDepth(path10.depth);
208734
- this.opcode("getContext", path10.depth);
208735
- var name = path10.parts[0], scoped = _ast2["default"].helpers.scopedId(path10), blockParamId = !path10.depth && !scoped && this.blockParamIndex(name);
208732
+ PathExpression: function PathExpression(path11) {
208733
+ this.addDepth(path11.depth);
208734
+ this.opcode("getContext", path11.depth);
208735
+ var name = path11.parts[0], scoped = _ast2["default"].helpers.scopedId(path11), blockParamId = !path11.depth && !scoped && this.blockParamIndex(name);
208736
208736
  if (blockParamId) {
208737
- this.opcode("lookupBlockParam", blockParamId, path10.parts);
208737
+ this.opcode("lookupBlockParam", blockParamId, path11.parts);
208738
208738
  } else if (!name) {
208739
208739
  this.opcode("pushContext");
208740
- } else if (path10.data) {
208740
+ } else if (path11.data) {
208741
208741
  this.options.data = true;
208742
- this.opcode("lookupData", path10.depth, path10.parts, path10.strict);
208742
+ this.opcode("lookupData", path11.depth, path11.parts, path11.strict);
208743
208743
  } else {
208744
- this.opcode("lookupOnContext", path10.parts, path10.falsy, path10.strict, scoped);
208744
+ this.opcode("lookupOnContext", path11.parts, path11.falsy, path11.strict, scoped);
208745
208745
  }
208746
208746
  },
208747
208747
  StringLiteral: function StringLiteral(string2) {
@@ -209085,16 +209085,16 @@ var require_util14 = __commonJS((exports) => {
209085
209085
  }
209086
209086
  exports.urlGenerate = urlGenerate;
209087
209087
  function normalize2(aPath) {
209088
- var path10 = aPath;
209088
+ var path11 = aPath;
209089
209089
  var url2 = urlParse(aPath);
209090
209090
  if (url2) {
209091
209091
  if (!url2.path) {
209092
209092
  return aPath;
209093
209093
  }
209094
- path10 = url2.path;
209094
+ path11 = url2.path;
209095
209095
  }
209096
- var isAbsolute3 = exports.isAbsolute(path10);
209097
- var parts = path10.split(/\/+/);
209096
+ var isAbsolute3 = exports.isAbsolute(path11);
209097
+ var parts = path11.split(/\/+/);
209098
209098
  for (var part, up = 0, i = parts.length - 1;i >= 0; i--) {
209099
209099
  part = parts[i];
209100
209100
  if (part === ".") {
@@ -209111,15 +209111,15 @@ var require_util14 = __commonJS((exports) => {
209111
209111
  }
209112
209112
  }
209113
209113
  }
209114
- path10 = parts.join("/");
209115
- if (path10 === "") {
209116
- path10 = isAbsolute3 ? "/" : ".";
209114
+ path11 = parts.join("/");
209115
+ if (path11 === "") {
209116
+ path11 = isAbsolute3 ? "/" : ".";
209117
209117
  }
209118
209118
  if (url2) {
209119
- url2.path = path10;
209119
+ url2.path = path11;
209120
209120
  return urlGenerate(url2);
209121
209121
  }
209122
- return path10;
209122
+ return path11;
209123
209123
  }
209124
209124
  exports.normalize = normalize2;
209125
209125
  function join9(aRoot, aPath) {
@@ -211676,8 +211676,8 @@ var require_printer = __commonJS((exports) => {
211676
211676
  return this.accept(sexpr.path) + " " + params + hash;
211677
211677
  };
211678
211678
  PrintVisitor.prototype.PathExpression = function(id) {
211679
- var path10 = id.parts.join("/");
211680
- return (id.data ? "@" : "") + "PATH:" + path10;
211679
+ var path11 = id.parts.join("/");
211680
+ return (id.data ? "@" : "") + "PATH:" + path11;
211681
211681
  };
211682
211682
  PrintVisitor.prototype.StringLiteral = function(string2) {
211683
211683
  return '"' + string2.value + '"';
@@ -216946,8 +216946,8 @@ var import_cors = __toESM(require_lib7(), 1);
216946
216946
  var import_express = __toESM(require_express(), 1);
216947
216947
  var import_http_proxy_middleware = __toESM(require_dist4(), 1);
216948
216948
  import * as http2 from "http";
216949
- import * as path10 from "path";
216950
- import { fileURLToPath as fileURLToPath3 } from "url";
216949
+ import * as path11 from "path";
216950
+ import { fileURLToPath as fileURLToPath2 } from "url";
216951
216951
 
216952
216952
  // src/controller/compile.controller.ts
216953
216953
  class CompileController {
@@ -217095,12 +217095,21 @@ class InvalidStateTransitionError extends Error {
217095
217095
  }
217096
217096
 
217097
217097
  // src/service/connection.ts
217098
- import { BigQueryConnection } from "@malloydata/db-bigquery";
217098
+ import"@malloydata/db-bigquery";
217099
217099
  import { DuckDBConnection } from "@malloydata/db-duckdb";
217100
- import { MySQLConnection } from "@malloydata/db-mysql";
217101
- import { PostgresConnection } from "@malloydata/db-postgres";
217102
- import { SnowflakeConnection } from "@malloydata/db-snowflake";
217103
- import { TrinoConnection } from "@malloydata/db-trino";
217100
+ import"@malloydata/db-duckdb/native";
217101
+ import"@malloydata/db-mysql";
217102
+ import"@malloydata/db-postgres";
217103
+ import {
217104
+ buildPoolOptions,
217105
+ SnowflakeConnection
217106
+ } from "@malloydata/db-snowflake";
217107
+ import"@malloydata/db-trino";
217108
+ import"@malloydata/db-databricks";
217109
+ import {
217110
+ contextOverlay,
217111
+ MalloyConfig
217112
+ } from "@malloydata/malloy";
217104
217113
 
217105
217114
  // ../../node_modules/axios/lib/helpers/bind.js
217106
217115
  function bind(fn, thisArg) {
@@ -220369,90 +220378,398 @@ var {
220369
220378
 
220370
220379
  // src/service/connection.ts
220371
220380
  import fs from "fs/promises";
220372
- import path from "path";
220373
- // ../../node_modules/uuid/dist/esm/native.js
220374
- import { randomUUID as randomUUID2 } from "crypto";
220375
- var native_default = { randomUUID: randomUUID2 };
220381
+ import path2 from "path";
220376
220382
 
220377
- // ../../node_modules/uuid/dist/esm/rng.js
220378
- import { randomFillSync } from "crypto";
220379
- var rnds8Pool = new Uint8Array(256);
220380
- var poolPtr = rnds8Pool.length;
220381
- function rng() {
220382
- if (poolPtr > rnds8Pool.length - 16) {
220383
- randomFillSync(rnds8Pool);
220384
- poolPtr = 0;
220383
+ // src/service/connection_config.ts
220384
+ import path from "path";
220385
+ var PUBLISHER_DUCKDB_API_FIELDS = new Set(["attachedDatabases"]);
220386
+ function normalizeSnowflakePrivateKey(privateKey) {
220387
+ let privateKeyContent = privateKey.trim();
220388
+ if (!privateKeyContent.includes(`
220389
+ `)) {
220390
+ const keyPatterns = [
220391
+ {
220392
+ beginRegex: /-----BEGIN\s+ENCRYPTED\s+PRIVATE\s+KEY-----/i,
220393
+ endRegex: /-----END\s+ENCRYPTED\s+PRIVATE\s+KEY-----/i,
220394
+ beginMarker: "-----BEGIN ENCRYPTED PRIVATE KEY-----",
220395
+ endMarker: "-----END ENCRYPTED PRIVATE KEY-----"
220396
+ },
220397
+ {
220398
+ beginRegex: /-----BEGIN\s+PRIVATE\s+KEY-----/i,
220399
+ endRegex: /-----END\s+PRIVATE\s+KEY-----/i,
220400
+ beginMarker: "-----BEGIN PRIVATE KEY-----",
220401
+ endMarker: "-----END PRIVATE KEY-----"
220402
+ }
220403
+ ];
220404
+ for (const pattern of keyPatterns) {
220405
+ const beginMatch = privateKeyContent.match(pattern.beginRegex);
220406
+ const endMatch = privateKeyContent.match(pattern.endRegex);
220407
+ if (beginMatch && endMatch) {
220408
+ const beginPos = beginMatch.index + beginMatch[0].length;
220409
+ const endPos = endMatch.index;
220410
+ const keyData = privateKeyContent.substring(beginPos, endPos).replace(/\s+/g, "");
220411
+ const lines = [];
220412
+ for (let i = 0;i < keyData.length; i += 64) {
220413
+ lines.push(keyData.slice(i, i + 64));
220414
+ }
220415
+ privateKeyContent = `${pattern.beginMarker}
220416
+ ${lines.join(`
220417
+ `)}
220418
+ ${pattern.endMarker}
220419
+ `;
220420
+ break;
220421
+ }
220422
+ }
220423
+ } else if (!privateKeyContent.endsWith(`
220424
+ `)) {
220425
+ privateKeyContent += `
220426
+ `;
220385
220427
  }
220386
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
220428
+ return privateKeyContent;
220387
220429
  }
220388
-
220389
- // ../../node_modules/uuid/dist/esm/stringify.js
220390
- var byteToHex = [];
220391
- for (let i = 0;i < 256; ++i) {
220392
- byteToHex.push((i + 256).toString(16).slice(1));
220430
+ function validateDuckdbApiSurface(connection) {
220431
+ if (connection.type !== "duckdb" || !connection.duckdbConnection)
220432
+ return;
220433
+ const unsupportedFields = Object.keys(connection.duckdbConnection).filter((field) => !PUBLISHER_DUCKDB_API_FIELDS.has(field) && connection.duckdbConnection[field] !== undefined);
220434
+ if (unsupportedFields.length > 0) {
220435
+ throw new Error(`Unsupported DuckDB connection field(s): ${unsupportedFields.join(", ")}. Publisher only supports attachedDatabases for project-authored DuckDB connections.`);
220436
+ }
220393
220437
  }
220394
- function unsafeStringify(arr, offset = 0) {
220395
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
220438
+ function cloneApiConnection(connection) {
220439
+ return { ...connection };
220396
220440
  }
220397
-
220398
- // ../../node_modules/uuid/dist/esm/v4.js
220399
- function v4(options, buf, offset) {
220400
- if (native_default.randomUUID && !buf && !options) {
220401
- return native_default.randomUUID();
220441
+ function getStaticConnectionAttributes(type) {
220442
+ switch (type) {
220443
+ case "postgres":
220444
+ return {
220445
+ dialectName: "postgres",
220446
+ isPool: false,
220447
+ canPersist: true,
220448
+ canStream: true
220449
+ };
220450
+ case "bigquery":
220451
+ return {
220452
+ dialectName: "standardsql",
220453
+ isPool: false,
220454
+ canPersist: true,
220455
+ canStream: true
220456
+ };
220457
+ case "snowflake":
220458
+ return {
220459
+ dialectName: "snowflake",
220460
+ isPool: true,
220461
+ canPersist: true,
220462
+ canStream: true
220463
+ };
220464
+ case "trino":
220465
+ return {
220466
+ dialectName: "trino",
220467
+ isPool: false,
220468
+ canPersist: true,
220469
+ canStream: false
220470
+ };
220471
+ case "databricks":
220472
+ return {
220473
+ dialectName: "databricks",
220474
+ isPool: false,
220475
+ canPersist: true,
220476
+ canStream: false
220477
+ };
220478
+ case "mysql":
220479
+ return {
220480
+ dialectName: "mysql",
220481
+ isPool: false,
220482
+ canPersist: true,
220483
+ canStream: false
220484
+ };
220485
+ case "duckdb":
220486
+ case "motherduck":
220487
+ case "ducklake":
220488
+ return {
220489
+ dialectName: "duckdb",
220490
+ isPool: false,
220491
+ canPersist: true,
220492
+ canStream: true
220493
+ };
220494
+ default:
220495
+ return;
220496
+ }
220497
+ }
220498
+ function parseServiceAccountKey(json) {
220499
+ if (!json)
220500
+ return;
220501
+ const keyData = JSON.parse(json);
220502
+ const requiredFields = ["type", "project_id", "private_key", "client_email"];
220503
+ for (const field of requiredFields) {
220504
+ if (!keyData[field]) {
220505
+ throw new Error(`Invalid service account key: missing "${field}" field`);
220506
+ }
220507
+ }
220508
+ if (keyData.type !== "service_account") {
220509
+ throw new Error('Invalid service account key: incorrect "type" field');
220402
220510
  }
220403
- options = options || {};
220404
- const rnds = options.random ?? options.rng?.() ?? rng();
220405
- if (rnds.length < 16) {
220406
- throw new Error("Random bytes length must be >= 16");
220511
+ return keyData;
220512
+ }
220513
+ function buildPostgresConnectionString(config) {
220514
+ if (config.connectionString || !process.env.PGSSLMODE) {
220515
+ return config.connectionString;
220516
+ }
220517
+ const params = new URLSearchParams;
220518
+ params.set("sslmode", process.env.PGSSLMODE);
220519
+ const auth = config.userName && config.password ? `${encodeURIComponent(config.userName)}:${encodeURIComponent(config.password)}@` : config.userName ? `${encodeURIComponent(config.userName)}@` : "";
220520
+ const host = config.host ?? "localhost";
220521
+ const port = config.port ? `:${config.port}` : "";
220522
+ const database = config.databaseName ? `/${encodeURIComponent(config.databaseName)}` : "";
220523
+ return `postgresql://${auth}${host}${port}${database}?${params.toString()}`;
220524
+ }
220525
+ function buildDuckdbEntry(name, projectPath, databaseFilename = `${name}.duckdb`) {
220526
+ return {
220527
+ is: "duckdb",
220528
+ databasePath: path.join(projectPath, databaseFilename)
220529
+ };
220530
+ }
220531
+ function validateConnectionShape(connection) {
220532
+ switch (connection.type) {
220533
+ case "postgres":
220534
+ case "mysql":
220535
+ case "bigquery":
220536
+ break;
220537
+ case "duckdb":
220538
+ if (!connection.duckdbConnection) {
220539
+ throw new Error("DuckDB connection configuration is missing.");
220540
+ }
220541
+ break;
220542
+ case "motherduck":
220543
+ if (!connection.motherduckConnection) {
220544
+ throw new Error("MotherDuck connection configuration is missing.");
220545
+ }
220546
+ if (!connection.motherduckConnection.accessToken) {
220547
+ throw new Error("MotherDuck access token is required.");
220548
+ }
220549
+ break;
220550
+ case "trino":
220551
+ if (!connection.trinoConnection) {
220552
+ throw new Error("Trino connection configuration is missing.");
220553
+ }
220554
+ break;
220555
+ case "databricks": {
220556
+ const databricks = connection.databricksConnection;
220557
+ if (!databricks) {
220558
+ throw new Error("Databricks connection configuration is missing.");
220559
+ }
220560
+ if (!databricks.host) {
220561
+ throw new Error("Databricks host is required.");
220562
+ }
220563
+ if (!databricks.path) {
220564
+ throw new Error("Databricks SQL warehouse HTTP path is required.");
220565
+ }
220566
+ const hasToken = !!databricks.token;
220567
+ const hasOAuth = !!databricks.oauthClientId && !!databricks.oauthClientSecret;
220568
+ if (!hasToken && !hasOAuth) {
220569
+ throw new Error("Databricks requires either a personal access token or OAuth M2M client ID and secret.");
220570
+ }
220571
+ const hasDefaultCatalog = !!databricks.defaultCatalog;
220572
+ if (!hasDefaultCatalog) {
220573
+ throw new Error("Databricks default catalog is required.");
220574
+ }
220575
+ break;
220576
+ }
220577
+ case "snowflake": {
220578
+ const snowflakeConnection = connection.snowflakeConnection;
220579
+ if (!snowflakeConnection) {
220580
+ throw new Error("Snowflake connection configuration is missing.");
220581
+ }
220582
+ if (!snowflakeConnection.account) {
220583
+ throw new Error("Snowflake account is required.");
220584
+ }
220585
+ if (!snowflakeConnection.username) {
220586
+ throw new Error("Snowflake username is required.");
220587
+ }
220588
+ if (!snowflakeConnection.password && !snowflakeConnection.privateKey) {
220589
+ throw new Error("Snowflake password or private key or private key path is required.");
220590
+ }
220591
+ if (!snowflakeConnection.warehouse) {
220592
+ throw new Error("Snowflake warehouse is required.");
220593
+ }
220594
+ break;
220595
+ }
220407
220596
  }
220408
- rnds[6] = rnds[6] & 15 | 64;
220409
- rnds[8] = rnds[8] & 63 | 128;
220410
- if (buf) {
220411
- offset = offset || 0;
220412
- if (offset < 0 || offset + 16 > buf.length) {
220413
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
220597
+ }
220598
+ function assembleProjectConnections(connections = [], projectPath = "") {
220599
+ const pojo = { connections: {} };
220600
+ const metadata = new Map;
220601
+ const apiConnections = [];
220602
+ const processedConnections = new Set;
220603
+ for (const connection of connections) {
220604
+ if (!connection.name) {
220605
+ throw new Error("Invalid connection configuration. No name.");
220606
+ }
220607
+ if (processedConnections.has(connection.name)) {
220608
+ continue;
220414
220609
  }
220415
- for (let i = 0;i < 16; ++i) {
220416
- buf[offset + i] = rnds[i];
220610
+ if (connection.name === "duckdb") {
220611
+ throw new Error("DuckDB connection name cannot be 'duckdb'; it is reserved for Publisher package sandboxes.");
220417
220612
  }
220418
- return buf;
220613
+ processedConnections.add(connection.name);
220614
+ validateDuckdbApiSurface(connection);
220615
+ validateConnectionShape(connection);
220616
+ const apiConnection = cloneApiConnection(connection);
220617
+ apiConnection.attributes = getStaticConnectionAttributes(connection.type);
220618
+ const attachedDatabases = connection.duckdbConnection?.attachedDatabases ?? [];
220619
+ const isDuckLake = connection.type === "ducklake";
220620
+ const isDuckdb = connection.type === "duckdb";
220621
+ const databasePath = isDuckLake ? path.join(projectPath, `${connection.name}_ducklake.duckdb`) : isDuckdb ? path.join(projectPath, `${connection.name}.duckdb`) : undefined;
220622
+ metadata.set(connection.name, {
220623
+ apiConnection,
220624
+ attachedDatabases,
220625
+ hasAzureAttachment: attachedDatabases.some((database) => database.type === "azure"),
220626
+ hasSnowflakePrivateKey: connection.type === "snowflake" && !!connection.snowflakeConnection?.privateKey,
220627
+ isDuckLake,
220628
+ databasePath,
220629
+ workingDirectory: projectPath
220630
+ });
220631
+ switch (connection.type) {
220632
+ case "postgres": {
220633
+ const postgresConnection = connection.postgresConnection;
220634
+ pojo.connections[connection.name] = {
220635
+ is: "postgres",
220636
+ host: postgresConnection?.host,
220637
+ port: postgresConnection?.port,
220638
+ username: postgresConnection?.userName,
220639
+ password: postgresConnection?.password,
220640
+ databaseName: postgresConnection?.databaseName,
220641
+ connectionString: postgresConnection ? buildPostgresConnectionString(postgresConnection) : undefined
220642
+ };
220643
+ break;
220644
+ }
220645
+ case "mysql": {
220646
+ pojo.connections[connection.name] = {
220647
+ is: "mysql",
220648
+ host: connection.mysqlConnection?.host,
220649
+ port: connection.mysqlConnection?.port,
220650
+ user: connection.mysqlConnection?.user,
220651
+ password: connection.mysqlConnection?.password,
220652
+ database: connection.mysqlConnection?.database
220653
+ };
220654
+ break;
220655
+ }
220656
+ case "bigquery": {
220657
+ const serviceAccountKey = parseServiceAccountKey(connection.bigqueryConnection?.serviceAccountKeyJson);
220658
+ pojo.connections[connection.name] = {
220659
+ is: "bigquery",
220660
+ projectId: connection.bigqueryConnection?.defaultProjectId ?? serviceAccountKey?.project_id,
220661
+ serviceAccountKey,
220662
+ location: connection.bigqueryConnection?.location,
220663
+ maximumBytesBilled: connection.bigqueryConnection?.maximumBytesBilled,
220664
+ timeoutMs: connection.bigqueryConnection?.queryTimeoutMilliseconds,
220665
+ billingProjectId: connection.bigqueryConnection?.billingProjectId
220666
+ };
220667
+ break;
220668
+ }
220669
+ case "snowflake": {
220670
+ pojo.connections[connection.name] = {
220671
+ is: "snowflake",
220672
+ account: connection.snowflakeConnection?.account,
220673
+ username: connection.snowflakeConnection?.username,
220674
+ password: connection.snowflakeConnection?.password,
220675
+ privateKey: connection.snowflakeConnection?.privateKey ? normalizeSnowflakePrivateKey(connection.snowflakeConnection.privateKey) : undefined,
220676
+ privateKeyPass: connection.snowflakeConnection?.privateKeyPass,
220677
+ warehouse: connection.snowflakeConnection?.warehouse,
220678
+ database: connection.snowflakeConnection?.database,
220679
+ schema: connection.snowflakeConnection?.schema,
220680
+ role: connection.snowflakeConnection?.role,
220681
+ timeoutMs: connection.snowflakeConnection?.responseTimeoutMilliseconds,
220682
+ poolMin: 1,
220683
+ poolMax: 20
220684
+ };
220685
+ break;
220686
+ }
220687
+ case "trino": {
220688
+ pojo.connections[connection.name] = {
220689
+ is: "trino",
220690
+ ...validateAndBuildTrinoCoreConfig(connection.trinoConnection)
220691
+ };
220692
+ break;
220693
+ }
220694
+ case "databricks": {
220695
+ const databricks = connection.databricksConnection;
220696
+ pojo.connections[connection.name] = {
220697
+ is: "databricks",
220698
+ host: databricks?.host,
220699
+ path: databricks?.path,
220700
+ token: databricks?.token,
220701
+ oauthClientId: databricks?.oauthClientId,
220702
+ oauthClientSecret: databricks?.oauthClientSecret,
220703
+ defaultCatalog: databricks?.defaultCatalog,
220704
+ defaultSchema: databricks?.defaultSchema,
220705
+ setupSQL: databricks?.setupSQL
220706
+ };
220707
+ break;
220708
+ }
220709
+ case "duckdb": {
220710
+ if (attachedDatabases.some((database) => database.name === connection.name)) {
220711
+ throw new Error(`DuckDB attached database names cannot conflict with connection name ${connection.name}`);
220712
+ }
220713
+ pojo.connections[connection.name] = buildDuckdbEntry(connection.name, projectPath, `${connection.name}.duckdb`);
220714
+ break;
220715
+ }
220716
+ case "motherduck": {
220717
+ if (!connection.motherduckConnection?.accessToken) {
220718
+ throw new Error("MotherDuck access token is required.");
220719
+ }
220720
+ pojo.connections[connection.name] = {
220721
+ is: "duckdb",
220722
+ databasePath: connection.motherduckConnection.database ? `md:${connection.motherduckConnection.database}?attach_mode=single` : "md:",
220723
+ motherDuckToken: connection.motherduckConnection.accessToken
220724
+ };
220725
+ break;
220726
+ }
220727
+ case "ducklake": {
220728
+ if (!connection.ducklakeConnection) {
220729
+ throw new Error("DuckLake connection configuration is missing.");
220730
+ }
220731
+ if (!connection.ducklakeConnection.catalog?.postgresConnection) {
220732
+ throw new Error(`PostgreSQL connection configuration is required for DuckLake catalog: ${connection.name}`);
220733
+ }
220734
+ pojo.connections[connection.name] = buildDuckdbEntry(connection.name, projectPath, `${connection.name}_ducklake.duckdb`);
220735
+ break;
220736
+ }
220737
+ default: {
220738
+ throw new Error(`Unsupported connection type: ${connection.type}`);
220739
+ }
220740
+ }
220741
+ apiConnections.push(apiConnection);
220419
220742
  }
220420
- return unsafeStringify(rnds);
220743
+ return { pojo, metadata, apiConnections };
220421
220744
  }
220422
- var v4_default = v4;
220423
- // src/service/connection.ts
220424
- function validateAndBuildTrinoConfig(trinoConfig) {
220425
- if (!trinoConfig.server?.includes(trinoConfig.port?.toString() || "")) {
220426
- trinoConfig.server = `${trinoConfig.server}:${trinoConfig.port}`;
220745
+ function validateAndBuildTrinoCoreConfig(trinoConfig) {
220746
+ if (!trinoConfig) {
220747
+ return {};
220427
220748
  }
220749
+ const server = trinoConfig.server && trinoConfig.port ? trinoConfig.server.includes(trinoConfig.port.toString()) ? trinoConfig.server : `${trinoConfig.server}:${trinoConfig.port}` : trinoConfig.server;
220428
220750
  const baseConfig = {
220429
- server: trinoConfig.server,
220751
+ server,
220430
220752
  port: trinoConfig.port,
220431
220753
  catalog: trinoConfig.catalog,
220432
220754
  schema: trinoConfig.schema,
220433
220755
  user: trinoConfig.user
220434
220756
  };
220435
220757
  if (trinoConfig.peakaKey) {
220436
- baseConfig.extraConfig = {
220437
- extraCredential: {
220438
- peakaKey: trinoConfig.peakaKey
220439
- }
220758
+ baseConfig.extraCredential = {
220759
+ peakaKey: trinoConfig.peakaKey
220440
220760
  };
220441
- delete baseConfig.password;
220442
- delete baseConfig.catalog;
220443
- delete baseConfig.schema;
220444
- } else if (trinoConfig.server?.startsWith("https://") && trinoConfig.password) {
220761
+ return baseConfig;
220762
+ }
220763
+ if (server?.startsWith("https://") && trinoConfig.password) {
220445
220764
  baseConfig.password = trinoConfig.password;
220446
220765
  }
220447
- if (trinoConfig.server?.startsWith("http://")) {
220448
- delete baseConfig.password;
220766
+ if (server?.startsWith("http://") || server?.startsWith("https://")) {
220449
220767
  return baseConfig;
220450
- } else if (trinoConfig.server?.startsWith("https://")) {
220451
- return baseConfig;
220452
- } else {
220453
- throw new Error(`Invalid Trino connection: expected "http://server:port" or "https://server:port".`);
220454
220768
  }
220769
+ throw new Error(`Invalid Trino connection: expected "http://server:port" or "https://server:port".`);
220455
220770
  }
220771
+
220772
+ // src/service/connection.ts
220456
220773
  async function installAndLoadExtension(connection, extensionName, fromCommunity = false) {
220457
220774
  try {
220458
220775
  const installCommand = fromCommunity ? `FORCE INSTALL '${extensionName}' FROM community;` : `INSTALL ${extensionName};`;
@@ -220488,52 +220805,6 @@ function handleAlreadyAttachedError(error, dbName) {
220488
220805
  throw error;
220489
220806
  }
220490
220807
  }
220491
- function normalizePrivateKey(privateKey) {
220492
- let privateKeyContent = privateKey.trim();
220493
- if (!privateKeyContent.includes(`
220494
- `)) {
220495
- const keyPatterns = [
220496
- {
220497
- beginRegex: /-----BEGIN\s+ENCRYPTED\s+PRIVATE\s+KEY-----/i,
220498
- endRegex: /-----END\s+ENCRYPTED\s+PRIVATE\s+KEY-----/i,
220499
- beginMarker: "-----BEGIN ENCRYPTED PRIVATE KEY-----",
220500
- endMarker: "-----END ENCRYPTED PRIVATE KEY-----"
220501
- },
220502
- {
220503
- beginRegex: /-----BEGIN\s+PRIVATE\s+KEY-----/i,
220504
- endRegex: /-----END\s+PRIVATE\s+KEY-----/i,
220505
- beginMarker: "-----BEGIN PRIVATE KEY-----",
220506
- endMarker: "-----END PRIVATE KEY-----"
220507
- }
220508
- ];
220509
- for (const pattern of keyPatterns) {
220510
- const beginMatch = privateKeyContent.match(pattern.beginRegex);
220511
- const endMatch = privateKeyContent.match(pattern.endRegex);
220512
- if (beginMatch && endMatch) {
220513
- const beginPos = beginMatch.index + beginMatch[0].length;
220514
- const endPos = endMatch.index;
220515
- const keyData = privateKeyContent.substring(beginPos, endPos).replace(/\s+/g, "");
220516
- const lines = [];
220517
- for (let i = 0;i < keyData.length; i += 64) {
220518
- lines.push(keyData.slice(i, i + 64));
220519
- }
220520
- privateKeyContent = `${pattern.beginMarker}
220521
- ${lines.join(`
220522
- `)}
220523
- ${pattern.endMarker}
220524
- `;
220525
- break;
220526
- }
220527
- }
220528
- } else {
220529
- if (!privateKeyContent.endsWith(`
220530
- `)) {
220531
- privateKeyContent += `
220532
- `;
220533
- }
220534
- }
220535
- return privateKeyContent;
220536
- }
220537
220808
  async function attachBigQuery(connection, attachedDb) {
220538
220809
  if (!attachedDb.bigqueryConnection) {
220539
220810
  throw new Error(`BigQuery connection configuration missing for: ${attachedDb.name}`);
@@ -220926,8 +221197,8 @@ function buildAzureFileUrl(azureConn, blobName) {
220926
221197
 
220927
221198
  class AzureDuckDBConnection extends DuckDBConnection {
220928
221199
  azureDatabases;
220929
- constructor(connectionName, databasePath, workingDirectory, azureDatabases) {
220930
- super(connectionName, databasePath, workingDirectory);
221200
+ constructor(options, azureDatabases) {
221201
+ super(options);
220931
221202
  this.azureDatabases = azureDatabases;
220932
221203
  }
220933
221204
  async fetchTableSchema(tableKey, tablePath) {
@@ -220959,12 +221230,12 @@ class AzureDuckDBConnection extends DuckDBConnection {
220959
221230
 
220960
221231
  class DuckLakeConnection extends DuckDBConnection {
220961
221232
  connectionName;
220962
- constructor(connectionName, databasePath, workingDirectory) {
220963
- super(connectionName, databasePath, workingDirectory);
220964
- if (!databasePath.endsWith("_ducklake.duckdb")) {
220965
- throw new Error(`DuckLakeConnection should only be used for DuckLake connections. ` + `Expected database path ending with '_ducklake.duckdb', got: ${databasePath}`);
221233
+ constructor(options) {
221234
+ super(options);
221235
+ if (!options.databasePath?.endsWith("_ducklake.duckdb")) {
221236
+ throw new Error(`DuckLakeConnection should only be used for DuckLake connections. ` + `Expected database path ending with '_ducklake.duckdb', got: ${options.databasePath}`);
220966
221237
  }
220967
- this.connectionName = connectionName;
221238
+ this.connectionName = options.name;
220968
221239
  }
220969
221240
  async fetchTableSchema(tableKey, tablePath) {
220970
221241
  const parts = tablePath.split(".");
@@ -220989,7 +221260,7 @@ class DuckLakeConnection extends DuckDBConnection {
220989
221260
  }
220990
221261
  }
220991
221262
  async function deleteDuckLakeConnectionFile(connectionName, projectPath) {
220992
- const ducklakePath = path.join(projectPath, `${connectionName}_ducklake.duckdb`);
221263
+ const ducklakePath = path2.join(projectPath, `${connectionName}_ducklake.duckdb`);
220993
221264
  try {
220994
221265
  await fs.access(ducklakePath);
220995
221266
  await fs.rm(ducklakePath);
@@ -221002,215 +221273,153 @@ async function deleteDuckLakeConnectionFile(connectionName, projectPath) {
221002
221273
  }
221003
221274
  }
221004
221275
  }
221005
- async function createProjectConnections(connections = [], projectPath = "", isUpdateConnectionRequest = false) {
221006
- const connectionMap = new Map;
221007
- const processedConnections = new Set;
221008
- const apiConnections = [];
221009
- for (const connection of connections) {
221010
- if (connection.name && processedConnections.has(connection.name)) {
221011
- continue;
221012
- }
221013
- logger.info(`Adding connection ${connection.name}`, {
221014
- connection
221015
- });
221016
- if (!connection.name) {
221017
- throw "Invalid connection configuration. No name.";
221276
+ function entryToDuckDBOptions(name, entry, workingDirectory) {
221277
+ const { is: _is, ...rest } = entry;
221278
+ if (workingDirectory !== undefined) {
221279
+ rest.workingDirectory = workingDirectory;
221280
+ }
221281
+ return { ...removeUndefined(rest), name };
221282
+ }
221283
+ function removeUndefined(value) {
221284
+ return Object.fromEntries(Object.entries(value).filter(([, fieldValue]) => fieldValue !== undefined));
221285
+ }
221286
+ function buildSnowflakePrivateKeyConnection(metadata) {
221287
+ const name = metadata.apiConnection.name;
221288
+ const snowflake = metadata.apiConnection.snowflakeConnection;
221289
+ if (!snowflake?.privateKey) {
221290
+ throw new Error(`Snowflake private key is required for connection ${name}`);
221291
+ }
221292
+ if (!snowflake.account) {
221293
+ throw new Error(`Snowflake account is required for connection ${name}`);
221294
+ }
221295
+ if (!snowflake.username) {
221296
+ throw new Error(`Snowflake username is required for connection ${name}`);
221297
+ }
221298
+ if (!snowflake.warehouse) {
221299
+ throw new Error(`Snowflake warehouse is required for connection ${name}`);
221300
+ }
221301
+ return new SnowflakeConnection(name, {
221302
+ connOptions: {
221303
+ account: snowflake.account,
221304
+ username: snowflake.username,
221305
+ privateKey: normalizeSnowflakePrivateKey(snowflake.privateKey),
221306
+ authenticator: "SNOWFLAKE_JWT",
221307
+ warehouse: snowflake.warehouse,
221308
+ ...removeUndefined({
221309
+ password: snowflake.password,
221310
+ privateKeyPass: snowflake.privateKeyPass,
221311
+ database: snowflake.database,
221312
+ schema: snowflake.schema,
221313
+ role: snowflake.role
221314
+ })
221315
+ },
221316
+ timeoutMs: snowflake.responseTimeoutMilliseconds,
221317
+ poolOptions: buildPoolOptions({ poolMin: 1, poolMax: 20 })
221318
+ });
221319
+ }
221320
+ function buildDuckLakeConnection(metadata, entry) {
221321
+ return new DuckLakeConnection(entryToDuckDBOptions(metadata.apiConnection.name, entry, metadata.workingDirectory));
221322
+ }
221323
+ function buildAzureDuckDBConnection(metadata, entry) {
221324
+ return new AzureDuckDBConnection(entryToDuckDBOptions(metadata.apiConnection.name, entry, metadata.workingDirectory), metadata.attachedDatabases);
221325
+ }
221326
+ function getMetadataForLookup(metadata, name) {
221327
+ return name ? metadata.get(name) : undefined;
221328
+ }
221329
+ function isDuckDBConnection(connection) {
221330
+ return connection instanceof DuckDBConnection;
221331
+ }
221332
+ function buildProjectMalloyConfig(connections = [], projectPath = "", isUpdateConnectionRequest = false) {
221333
+ const assembled = assembleProjectConnections(connections, projectPath);
221334
+ const duckLakeCache = new Map;
221335
+ const snowflakeJwtCache = new Map;
221336
+ const azureDuckDBCache = new Map;
221337
+ const attachPromises = new WeakMap;
221338
+ const malloyConfig = new MalloyConfig(assembled.pojo, {
221339
+ config: contextOverlay({ rootDirectory: projectPath })
221340
+ });
221341
+ async function attachOnce(connection, metadata) {
221342
+ if (metadata.attachedDatabases.length === 0 || !isDuckDBConnection(connection)) {
221343
+ return;
221018
221344
  }
221019
- processedConnections.add(connection.name);
221020
- switch (connection.type) {
221021
- case "postgres": {
221022
- const configReader = async () => {
221023
- if (!connection.postgresConnection) {
221024
- throw "Invalid connection configuration. No postgres connection.";
221025
- }
221026
- return {
221027
- host: connection.postgresConnection.host,
221028
- port: connection.postgresConnection.port,
221029
- username: connection.postgresConnection.userName,
221030
- password: connection.postgresConnection.password,
221031
- databaseName: connection.postgresConnection.databaseName,
221032
- connectionString: connection.postgresConnection.connectionString
221033
- };
221034
- };
221035
- const postgresConnection = new PostgresConnection(connection.name, () => ({}), configReader);
221036
- connectionMap.set(connection.name, postgresConnection);
221037
- connection.attributes = getConnectionAttributes(postgresConnection);
221038
- break;
221039
- }
221040
- case "mysql": {
221041
- if (!connection.mysqlConnection) {
221042
- throw "Invalid connection configuration. No mysql connection.";
221043
- }
221044
- const config = {
221045
- host: connection.mysqlConnection.host,
221046
- port: connection.mysqlConnection.port,
221047
- user: connection.mysqlConnection.user,
221048
- password: connection.mysqlConnection.password,
221049
- database: connection.mysqlConnection.database
221050
- };
221051
- const mysqlConnection = new MySQLConnection(connection.name, config);
221052
- connectionMap.set(connection.name, mysqlConnection);
221053
- connection.attributes = getConnectionAttributes(mysqlConnection);
221054
- break;
221055
- }
221056
- case "bigquery": {
221057
- if (!connection.bigqueryConnection) {
221058
- throw "Invalid connection configuration. No bigquery connection.";
221059
- }
221060
- let serviceAccountKeyPath = undefined;
221061
- if (connection.bigqueryConnection.serviceAccountKeyJson) {
221062
- serviceAccountKeyPath = path.join(TEMP_DIR_PATH, `${connection.name}-${v4_default()}-service-account-key.json`);
221063
- await fs.writeFile(serviceAccountKeyPath, connection.bigqueryConnection.serviceAccountKeyJson);
221064
- }
221065
- const bigqueryConnectionOptions = {
221066
- projectId: connection.bigqueryConnection.defaultProjectId,
221067
- serviceAccountKeyPath,
221068
- location: connection.bigqueryConnection.location,
221069
- maximumBytesBilled: connection.bigqueryConnection.maximumBytesBilled,
221070
- timeoutMs: connection.bigqueryConnection.queryTimeoutMilliseconds,
221071
- billingProjectId: connection.bigqueryConnection.billingProjectId
221072
- };
221073
- const bigqueryConnection = new BigQueryConnection(connection.name, () => ({}), bigqueryConnectionOptions);
221074
- connectionMap.set(connection.name, bigqueryConnection);
221075
- connection.attributes = getConnectionAttributes(bigqueryConnection);
221076
- break;
221077
- }
221078
- case "snowflake": {
221079
- if (!connection.snowflakeConnection) {
221080
- throw new Error("Snowflake connection configuration is missing.");
221081
- }
221082
- if (!connection.snowflakeConnection.account) {
221083
- throw new Error("Snowflake account is required.");
221084
- }
221085
- if (!connection.snowflakeConnection.username) {
221086
- throw new Error("Snowflake username is required.");
221087
- }
221088
- if (!connection.snowflakeConnection.password && !connection.snowflakeConnection.privateKey) {
221089
- throw new Error("Snowflake password or private key or private key path is required.");
221090
- }
221091
- if (!connection.snowflakeConnection.warehouse) {
221092
- throw new Error("Snowflake warehouse is required.");
221093
- }
221094
- let privateKeyPath = undefined;
221095
- if (connection.snowflakeConnection.privateKey) {
221096
- privateKeyPath = path.join(TEMP_DIR_PATH, `${connection.name}-${v4_default()}-private-key.pem`);
221097
- const normalizedKey = normalizePrivateKey(connection.snowflakeConnection.privateKey);
221098
- await fs.writeFile(privateKeyPath, normalizedKey);
221099
- }
221100
- const snowflakeConnectionOptions = {
221101
- connOptions: {
221102
- account: connection.snowflakeConnection.account,
221103
- username: connection.snowflakeConnection.username,
221104
- warehouse: connection.snowflakeConnection.warehouse,
221105
- database: connection.snowflakeConnection.database,
221106
- schema: connection.snowflakeConnection.schema,
221107
- role: connection.snowflakeConnection.role,
221108
- ...connection.snowflakeConnection.privateKey ? {
221109
- privateKeyPath,
221110
- authenticator: "SNOWFLAKE_JWT",
221111
- privateKeyPass: connection.snowflakeConnection.privateKeyPass || undefined
221112
- } : {
221113
- password: connection.snowflakeConnection.password || undefined
221114
- },
221115
- timeout: connection.snowflakeConnection.responseTimeoutMilliseconds
221116
- },
221117
- poolOptions: {
221118
- min: 1,
221119
- max: 20
221120
- }
221121
- };
221122
- const snowflakeConnection = new SnowflakeConnection(connection.name, snowflakeConnectionOptions);
221123
- connectionMap.set(connection.name, snowflakeConnection);
221124
- connection.attributes = getConnectionAttributes(snowflakeConnection);
221125
- break;
221126
- }
221127
- case "trino": {
221128
- if (!connection.trinoConnection) {
221129
- throw new Error("Trino connection configuration is missing.");
221130
- }
221131
- const trinoConnectionOptions = validateAndBuildTrinoConfig(connection.trinoConnection);
221132
- const trinoConnection = new TrinoConnection(connection.name, {}, trinoConnectionOptions);
221133
- connectionMap.set(connection.name, trinoConnection);
221134
- connection.attributes = getConnectionAttributes(trinoConnection);
221135
- break;
221136
- }
221137
- case "duckdb": {
221138
- if (!connection.duckdbConnection) {
221139
- throw new Error("DuckDB connection configuration is missing.");
221140
- }
221141
- if (connection.duckdbConnection.attachedDatabases?.some((database) => database.name === connection.name)) {
221142
- throw new Error(`DuckDB attached databases names cannot conflict with connection name ${connection.name}`);
221143
- }
221144
- if (connection.name === "duckdb") {
221145
- throw new Error("DuckDB connection name cannot be 'duckdb'");
221146
- }
221147
- if (connection.duckdbConnection?.attachedDatabases?.length == 0) {
221148
- throw new Error("DuckDB connection must have at least one attached database");
221149
- }
221150
- const attachedDatabases = connection.duckdbConnection.attachedDatabases ?? [];
221151
- const hasAzureAttached = attachedDatabases.some((db) => db.type === "azure");
221152
- const duckdbConnection = hasAzureAttached ? new AzureDuckDBConnection(connection.name, path.join(projectPath, `${connection.name}.duckdb`), projectPath, attachedDatabases) : new DuckDBConnection(connection.name, path.join(projectPath, `${connection.name}.duckdb`), projectPath);
221153
- if (attachedDatabases.length > 0) {
221154
- await attachDatabasesToDuckDB(duckdbConnection, attachedDatabases);
221155
- }
221156
- connectionMap.set(connection.name, duckdbConnection);
221157
- connection.attributes = getConnectionAttributes(duckdbConnection);
221158
- break;
221345
+ let attachPromise = attachPromises.get(connection);
221346
+ if (!attachPromise) {
221347
+ attachPromise = attachDatabasesToDuckDB(connection, metadata.attachedDatabases);
221348
+ attachPromises.set(connection, attachPromise);
221349
+ }
221350
+ await attachPromise;
221351
+ }
221352
+ malloyConfig.wrapConnections((base) => ({
221353
+ lookupConnection: async (name) => {
221354
+ const metadata = getMetadataForLookup(assembled.metadata, name);
221355
+ if (metadata?.isDuckLake) {
221356
+ let connectionPromise = duckLakeCache.get(name);
221357
+ if (!connectionPromise) {
221358
+ const entry = assembled.pojo.connections[name];
221359
+ connectionPromise = Promise.resolve(buildDuckLakeConnection(metadata, entry));
221360
+ duckLakeCache.set(name, connectionPromise);
221361
+ }
221362
+ const connection2 = await connectionPromise;
221363
+ if (isUpdateConnectionRequest || !await isDatabaseAttached(connection2, name)) {
221364
+ await attachDuckLake(connection2, name, metadata.apiConnection.ducklakeConnection);
221365
+ }
221366
+ return connection2;
221367
+ }
221368
+ if (metadata?.hasSnowflakePrivateKey) {
221369
+ let connectionPromise = snowflakeJwtCache.get(name);
221370
+ if (!connectionPromise) {
221371
+ connectionPromise = Promise.resolve(buildSnowflakePrivateKeyConnection(metadata));
221372
+ snowflakeJwtCache.set(name, connectionPromise);
221373
+ }
221374
+ return connectionPromise;
221375
+ }
221376
+ if (metadata?.hasAzureAttachment) {
221377
+ let connectionPromise = azureDuckDBCache.get(name);
221378
+ if (!connectionPromise) {
221379
+ const entry = assembled.pojo.connections[name];
221380
+ connectionPromise = Promise.resolve(buildAzureDuckDBConnection(metadata, entry));
221381
+ azureDuckDBCache.set(name, connectionPromise);
221382
+ }
221383
+ const connection2 = await connectionPromise;
221384
+ await attachOnce(connection2, metadata);
221385
+ return connection2;
221386
+ }
221387
+ const connection = await base.lookupConnection(name);
221388
+ if (metadata) {
221389
+ await attachOnce(connection, metadata);
221159
221390
  }
221160
- case "motherduck": {
221161
- if (!connection.motherduckConnection) {
221162
- throw new Error("MotherDuck connection configuration is missing.");
221163
- }
221164
- if (!connection.motherduckConnection.accessToken) {
221165
- throw new Error("MotherDuck access token is required.");
221166
- }
221167
- let databasePath = `md:`;
221168
- if (connection.motherduckConnection.database) {
221169
- databasePath = `md:${connection.motherduckConnection.database}?attach_mode=single`;
221170
- }
221171
- const motherduckConnection = new DuckDBConnection({
221172
- name: connection.name,
221173
- databasePath,
221174
- motherDuckToken: connection.motherduckConnection.accessToken,
221175
- workingDirectory: projectPath
221391
+ return connection;
221392
+ }
221393
+ }));
221394
+ return {
221395
+ malloyConfig,
221396
+ apiConnections: assembled.apiConnections,
221397
+ releaseConnections: async () => {
221398
+ const wrapperPromises = [
221399
+ ...duckLakeCache.values(),
221400
+ ...snowflakeJwtCache.values(),
221401
+ ...azureDuckDBCache.values()
221402
+ ];
221403
+ const closeResults = await Promise.allSettled([
221404
+ malloyConfig.releaseConnections(),
221405
+ ...wrapperPromises.map(async (promise) => {
221406
+ const connection = await promise;
221407
+ await connection.close();
221408
+ })
221409
+ ]);
221410
+ duckLakeCache.clear();
221411
+ snowflakeJwtCache.clear();
221412
+ azureDuckDBCache.clear();
221413
+ const failures = closeResults.filter((result) => result.status === "rejected");
221414
+ for (const failure of failures) {
221415
+ logger.error("Failed to release project connection", {
221416
+ error: failure.reason
221176
221417
  });
221177
- connectionMap.set(connection.name, motherduckConnection);
221178
- connection.attributes = getConnectionAttributes(motherduckConnection);
221179
- break;
221180
- }
221181
- case "ducklake": {
221182
- if (!connection.ducklakeConnection) {
221183
- throw new Error("DuckLake connection configuration is missing.");
221184
- }
221185
- const ducklakeDuckdbConnection = new DuckLakeConnection(connection.name, path.join(projectPath, `${connection.name}_ducklake.duckdb`), projectPath);
221186
- if (isUpdateConnectionRequest || !await isDatabaseAttached(ducklakeDuckdbConnection, connection.name)) {
221187
- await attachDuckLake(ducklakeDuckdbConnection, connection.name, connection.ducklakeConnection);
221188
- }
221189
- connectionMap.set(connection.name, ducklakeDuckdbConnection);
221190
- connection.attributes = getConnectionAttributes(ducklakeDuckdbConnection);
221191
- break;
221192
221418
  }
221193
- default: {
221194
- throw new Error(`Unsupported connection type: ${connection.type}`);
221419
+ if (failures.length > 0) {
221420
+ throw new AggregateError(failures.map((failure) => failure.reason), "Failed to release one or more project connections");
221195
221421
  }
221196
221422
  }
221197
- apiConnections.push(connection);
221198
- }
221199
- return {
221200
- malloyConnections: connectionMap,
221201
- apiConnections
221202
- };
221203
- }
221204
- function getConnectionAttributes(connection) {
221205
- let canStream = false;
221206
- try {
221207
- canStream = connection.canStream();
221208
- } catch {}
221209
- return {
221210
- dialectName: connection.dialectName,
221211
- isPool: connection.isPool(),
221212
- canPersist: connection.canPersist(),
221213
- canStream
221214
221423
  };
221215
221424
  }
221216
221425
  async function testDuckDBConnection(duckdbConnection, connectionConfig) {
@@ -221286,17 +221495,13 @@ ${failedAttachments.join(`
221286
221495
  }
221287
221496
  }
221288
221497
  async function testConnectionConfig(connectionConfig) {
221289
- let malloyConnections = null;
221498
+ let projectConfig = null;
221290
221499
  try {
221291
221500
  if (!connectionConfig.name) {
221292
221501
  throw new Error("Connection name is required");
221293
221502
  }
221294
- const result = await createProjectConnections([connectionConfig]);
221295
- malloyConnections = result.malloyConnections;
221296
- const connection = malloyConnections.get(connectionConfig.name);
221297
- if (!connection) {
221298
- throw new Error(`Failed to create connection: ${connectionConfig.name}`);
221299
- }
221503
+ projectConfig = buildProjectMalloyConfig([connectionConfig]);
221504
+ const connection = await projectConfig.malloyConfig.connections.lookupConnection(connectionConfig.name);
221300
221505
  if (connectionConfig.type === "duckdb") {
221301
221506
  await testDuckDBConnection(connection, connectionConfig);
221302
221507
  } else if (connectionConfig.type === "ducklake") {
@@ -221325,25 +221530,41 @@ async function testConnectionConfig(connectionConfig) {
221325
221530
  errorMessage: error.message
221326
221531
  };
221327
221532
  } finally {
221328
- if (malloyConnections) {
221329
- for (const [connName, conn] of malloyConnections) {
221330
- try {
221331
- if (conn && typeof conn.close === "function") {
221332
- await conn.close();
221333
- }
221334
- } catch (closeError) {
221335
- logger.warn(`Error closing connection ${connName} during test cleanup`, { error: closeError });
221336
- } finally {
221337
- if (connectionConfig.type === "ducklake") {
221338
- await deleteDuckLakeConnectionFile(connName, process.cwd());
221339
- }
221340
- }
221533
+ if (projectConfig) {
221534
+ try {
221535
+ await projectConfig.releaseConnections();
221536
+ } catch (closeError) {
221537
+ logger.warn("Error releasing temporary connection test config", {
221538
+ error: closeError
221539
+ });
221341
221540
  }
221342
221541
  }
221542
+ if (connectionConfig.type === "ducklake" && connectionConfig.name) {
221543
+ await deleteDuckLakeConnectionFile(connectionConfig.name, process.cwd());
221544
+ }
221343
221545
  }
221344
221546
  }
221345
221547
 
221346
221548
  // src/service/connection_service.ts
221549
+ async function runProjectConnectionUpdate(project, fn) {
221550
+ if (project.runConnectionUpdateExclusive) {
221551
+ return project.runConnectionUpdateExclusive(fn);
221552
+ }
221553
+ return fn();
221554
+ }
221555
+ function updateProjectConnections(project, nextMalloyConfig, afterPreviousRelease) {
221556
+ project.updateConnections?.(nextMalloyConfig, nextMalloyConfig.apiConnections, afterPreviousRelease);
221557
+ }
221558
+ function buildDeletedConnectionCleanup(project, deletedConnection, connectionName) {
221559
+ if (deletedConnection.type === "duckdb" && typeof project.deleteDuckDBConnection === "function") {
221560
+ return () => project.deleteDuckDBConnection(connectionName);
221561
+ }
221562
+ if (deletedConnection.type === "ducklake" && typeof project.deleteDuckLakeConnection === "function") {
221563
+ return () => project.deleteDuckLakeConnection(connectionName);
221564
+ }
221565
+ return;
221566
+ }
221567
+
221347
221568
  class ConnectionService {
221348
221569
  projectStore;
221349
221570
  constructor(projectStore) {
@@ -221378,10 +221599,12 @@ class ConnectionService {
221378
221599
  throw new Error(`Connection "${connectionName}" already exists in project "${projectName}".`);
221379
221600
  }
221380
221601
  const project = await this.projectStore.getProject(projectName, false);
221381
- const existingConnections = project.listApiConnections();
221382
- const { malloyConnections, apiConnections } = await createProjectConnections([...existingConnections, connection], project.metadata.location || "");
221383
- project.updateConnections(malloyConnections, apiConnections);
221384
- await this.projectStore.addConnection(connection, dbProject.id, repository);
221602
+ await runProjectConnectionUpdate(project, async () => {
221603
+ const existingConnections = project.listApiConnections();
221604
+ const nextMalloyConfig = buildProjectMalloyConfig([...existingConnections, connection], project.metadata.location || "");
221605
+ await this.projectStore.addConnection(connection, dbProject.id, repository);
221606
+ updateProjectConnections(project, nextMalloyConfig);
221607
+ });
221385
221608
  logger.info(`Successfully added connection "${connection.name}" to project "${projectName}"`);
221386
221609
  }
221387
221610
  async updateConnection(projectName, connectionName, connection) {
@@ -221392,16 +221615,18 @@ class ConnectionService {
221392
221615
  logger.info(`Updating connection "${connectionName}" in project "${projectName}"`);
221393
221616
  const { dbProject, dbConnection, repository } = await this.getConnection(projectName, connectionName);
221394
221617
  const project = await this.projectStore.getProject(projectName, false);
221395
- const existingConnections = project.listApiConnections();
221396
- const updatedConnection = {
221397
- ...dbConnection.config,
221398
- ...connection,
221399
- name: connectionName
221400
- };
221401
- const updatedConnections = existingConnections.map((conn) => conn.name === connectionName ? updatedConnection : conn);
221402
- const { malloyConnections, apiConnections } = await createProjectConnections(updatedConnections, project.metadata.location || "");
221403
- project.updateConnections(malloyConnections, apiConnections);
221404
- await this.projectStore.updateConnection(updatedConnection, dbProject.id, repository);
221618
+ await runProjectConnectionUpdate(project, async () => {
221619
+ const existingConnections = project.listApiConnections();
221620
+ const updatedConnection = {
221621
+ ...dbConnection.config,
221622
+ ...connection,
221623
+ name: connectionName
221624
+ };
221625
+ const updatedConnections = existingConnections.map((conn) => conn.name === connectionName ? updatedConnection : conn);
221626
+ const nextMalloyConfig = buildProjectMalloyConfig(updatedConnections, project.metadata.location || "", true);
221627
+ await this.projectStore.updateConnection(updatedConnection, dbProject.id, repository);
221628
+ updateProjectConnections(project, nextMalloyConfig);
221629
+ });
221405
221630
  logger.info(`Successfully updated connection "${connectionName}" in project "${projectName}"`);
221406
221631
  }
221407
221632
  async deleteConnection(projectName, connectionName) {
@@ -221412,8 +221637,21 @@ class ConnectionService {
221412
221637
  logger.info(`Deleting connection "${connectionName}" from project "${projectName}"`);
221413
221638
  const { dbConnection, repository } = await this.getConnection(projectName, connectionName);
221414
221639
  const project = await this.projectStore.getProject(projectName, false);
221415
- await project.deleteConnection(connectionName);
221416
- await repository.deleteConnection(dbConnection.id);
221640
+ await runProjectConnectionUpdate(project, async () => {
221641
+ if (typeof project.listApiConnections !== "function") {
221642
+ if (typeof project.deleteConnection === "function") {
221643
+ await project.deleteConnection(connectionName);
221644
+ }
221645
+ await repository.deleteConnection(dbConnection.id);
221646
+ return;
221647
+ }
221648
+ const deletedConnection = "getApiConnection" in project && typeof project.getApiConnection === "function" ? project.getApiConnection(connectionName) : dbConnection.config;
221649
+ const updatedConnections = project.listApiConnections().filter((connection) => connection.name !== connectionName);
221650
+ const nextMalloyConfig = buildProjectMalloyConfig(updatedConnections, project.metadata.location || "");
221651
+ const deleteConnectionFilesAfterRelease = buildDeletedConnectionCleanup(project, deletedConnection, connectionName);
221652
+ await repository.deleteConnection(dbConnection.id);
221653
+ updateProjectConnections(project, nextMalloyConfig, deleteConnectionFilesAfterRelease);
221654
+ });
221417
221655
  logger.info(`Successfully deleted connection "${connectionName}" from project "${projectName}"`);
221418
221656
  }
221419
221657
  }
@@ -221873,6 +222111,60 @@ async function getSchemasForTrino(connection, malloyConnection) {
221873
222111
  throw new Error(`Failed to get schemas for Trino connection ${connection.name}: ${error.message}`);
221874
222112
  }
221875
222113
  }
222114
+ async function getSchemasForDatabricks(connection, malloyConnection) {
222115
+ if (!connection.databricksConnection) {
222116
+ throw new Error("Databricks connection is required");
222117
+ }
222118
+ try {
222119
+ const configuredSchema = connection.databricksConnection.defaultSchema;
222120
+ let allRows = [];
222121
+ if (connection.databricksConnection.defaultCatalog) {
222122
+ const catalog = connection.databricksConnection.defaultCatalog;
222123
+ const result = await malloyConnection.runSQL(`SELECT schema_name FROM ${catalog}.information_schema.schemata ORDER BY schema_name`);
222124
+ const rows = standardizeRunSQLResult2(result);
222125
+ allRows = rows.map((row) => {
222126
+ const r = row;
222127
+ return {
222128
+ catalog,
222129
+ schema: String(r.schema_name ?? r.Schema ?? "")
222130
+ };
222131
+ });
222132
+ } else {
222133
+ const catalogsResult = await malloyConnection.runSQL(`SHOW CATALOGS`);
222134
+ const catalogNames = standardizeRunSQLResult2(catalogsResult).map((row) => {
222135
+ const r = row;
222136
+ return String(r.catalog ?? r.Catalog ?? r.catalog_name ?? "");
222137
+ });
222138
+ for (const catalog of catalogNames) {
222139
+ try {
222140
+ const result = await malloyConnection.runSQL(`SELECT schema_name FROM ${catalog}.information_schema.schemata ORDER BY schema_name`);
222141
+ const rows = standardizeRunSQLResult2(result);
222142
+ for (const row of rows) {
222143
+ const r = row;
222144
+ allRows.push({
222145
+ catalog,
222146
+ schema: String(r.schema_name ?? r.Schema ?? "")
222147
+ });
222148
+ }
222149
+ } catch (catalogError) {
222150
+ logger.warn(`Failed to list schemas for Databricks catalog ${catalog}`, { error: catalogError });
222151
+ }
222152
+ }
222153
+ }
222154
+ logger.info("allRows for Schemas for Databricks", { allRows });
222155
+ return allRows.map(({ catalog, schema }) => {
222156
+ const name = connection.databricksConnection?.defaultCatalog ? schema : `${catalog}.${schema}`;
222157
+ return {
222158
+ name,
222159
+ isHidden: ["information_schema"].includes(schema),
222160
+ isDefault: configuredSchema ? schema === configuredSchema : false
222161
+ };
222162
+ });
222163
+ } catch (error) {
222164
+ logger.error(`Error getting schemas for Databricks connection ${connection.name}`, { error });
222165
+ throw new Error(`Failed to get schemas for Databricks connection ${connection.name}: ${error.message}`);
222166
+ }
222167
+ }
221876
222168
  async function getSchemasForDuckDB(connection, malloyConnection) {
221877
222169
  if (!connection.duckdbConnection) {
221878
222170
  throw new Error("DuckDB connection is required");
@@ -221983,6 +222275,8 @@ async function getSchemasForConnection(connection, malloyConnection) {
221983
222275
  return getSchemasForSnowflake(connection, malloyConnection);
221984
222276
  case "trino":
221985
222277
  return getSchemasForTrino(connection, malloyConnection);
222278
+ case "databricks":
222279
+ return getSchemasForDatabricks(connection, malloyConnection);
221986
222280
  case "duckdb":
221987
222281
  return getSchemasForDuckDB(connection, malloyConnection);
221988
222282
  case "motherduck":
@@ -222165,6 +222459,8 @@ async function listTablesForSchema(connection, schemaName, malloyConnection, tab
222165
222459
  return listTablesForSnowflake(connection, schemaName, malloyConnection, tableNames);
222166
222460
  case "trino":
222167
222461
  return listTablesForTrino(connection, schemaName, malloyConnection, tableNames);
222462
+ case "databricks":
222463
+ return listTablesForDatabricks(connection, schemaName, malloyConnection, tableNames);
222168
222464
  case "duckdb":
222169
222465
  return listTablesForDuckDB(connection, schemaName, malloyConnection, tableNames);
222170
222466
  case "motherduck":
@@ -222293,6 +222589,37 @@ async function listTablesForTrino(connection, schemaName, malloyConnection, tabl
222293
222589
  throw new Error(`Failed to get tables for Trino schema ${schemaName} in connection ${connection.name}: ${error.message}`);
222294
222590
  }
222295
222591
  }
222592
+ async function listTablesForDatabricks(connection, schemaName, malloyConnection, tableNames) {
222593
+ if (!connection.databricksConnection) {
222594
+ throw new Error("Databricks connection is required");
222595
+ }
222596
+ try {
222597
+ let catalogPrefix;
222598
+ let schemaOnly;
222599
+ let resourcePrefix;
222600
+ if (connection.databricksConnection.defaultCatalog) {
222601
+ catalogPrefix = `${connection.databricksConnection.defaultCatalog}.`;
222602
+ schemaOnly = schemaName;
222603
+ resourcePrefix = `${connection.databricksConnection.defaultCatalog}.${schemaName}`;
222604
+ } else {
222605
+ const dotIdx = schemaName.indexOf(".");
222606
+ if (dotIdx > 0) {
222607
+ catalogPrefix = `${schemaName.substring(0, dotIdx)}.`;
222608
+ schemaOnly = schemaName.substring(dotIdx + 1);
222609
+ } else {
222610
+ catalogPrefix = "";
222611
+ schemaOnly = schemaName;
222612
+ }
222613
+ resourcePrefix = schemaName;
222614
+ }
222615
+ const result = await malloyConnection.runSQL(`SELECT table_name, column_name, data_type FROM ${catalogPrefix}information_schema.columns WHERE table_schema = '${schemaOnly}' ${sqlInFilter("table_name", tableNames)} ORDER BY table_name, ordinal_position`);
222616
+ const rows = standardizeRunSQLResult2(result);
222617
+ return groupColumnRowsIntoTables(rows, (t) => `${resourcePrefix}.${t}`);
222618
+ } catch (error) {
222619
+ logger.error(`Error getting tables for Databricks schema ${schemaName} in connection ${connection.name}`, { error });
222620
+ throw new Error(`Failed to get tables for Databricks schema ${schemaName} in connection ${connection.name}: ${error.message}`);
222621
+ }
222622
+ }
222296
222623
  async function listTablesForDuckDB(connection, schemaName, malloyConnection, tableNames) {
222297
222624
  if (!connection.duckdbConnection) {
222298
222625
  throw new Error("DuckDB connection is required");
@@ -222426,6 +222753,16 @@ function validateAzureAttachedDatabases(connectionConfig) {
222426
222753
  }
222427
222754
  }
222428
222755
  }
222756
+ function validateAdminAuthoredConnection(connectionName, connectionConfig) {
222757
+ if (connectionName === "duckdb" || connectionConfig.name === "duckdb") {
222758
+ throw new BadRequestError("DuckDB connection name cannot be 'duckdb'; it is reserved for Publisher package sandboxes.");
222759
+ }
222760
+ try {
222761
+ validateDuckdbApiSurface(connectionConfig);
222762
+ } catch (error) {
222763
+ throw new BadRequestError(error.message);
222764
+ }
222765
+ }
222429
222766
 
222430
222767
  class ConnectionController {
222431
222768
  projectStore;
@@ -222434,22 +222771,42 @@ class ConnectionController {
222434
222771
  this.projectStore = projectStore;
222435
222772
  this.connectionService = new ConnectionService(projectStore);
222436
222773
  }
222437
- async getMalloyConnection(projectName, connectionName) {
222774
+ getApiConnectionForLookup(project, connectionName) {
222775
+ if (connectionName === "duckdb") {
222776
+ return {
222777
+ name: "duckdb",
222778
+ type: "duckdb",
222779
+ duckdbConnection: { attachedDatabases: [] }
222780
+ };
222781
+ }
222782
+ return project.getApiConnection(connectionName);
222783
+ }
222784
+ async getMalloyConnection(projectName, connectionName, packageName) {
222438
222785
  const project = await this.projectStore.getProject(projectName, false);
222439
- const connection = project.getApiConnection(connectionName);
222440
- if (connection.name === "duckdb" && connection.type === "duckdb") {
222786
+ if (connectionName === "duckdb") {
222441
222787
  const packages = await project.listPackages();
222442
222788
  if (packages.length === 0) {
222443
- return project.getMalloyConnection(connectionName);
222789
+ return await project.getMalloyConnection(connectionName);
222790
+ }
222791
+ if (packageName) {
222792
+ const known = packages.some((p) => p.name === packageName);
222793
+ if (!known) {
222794
+ throw new BadRequestError(`Package "${packageName}" not found in project "${projectName}"`);
222795
+ }
222796
+ const pkg = await project.getPackage(packageName);
222797
+ return await pkg.getMalloyConnection(connectionName);
222444
222798
  }
222445
- const packageName = packages[0].name;
222446
- if (!packageName) {
222447
- throw new ConnectionError("Package name is undefined");
222799
+ if (packages.length === 1) {
222800
+ const onlyPackage = packages[0].name;
222801
+ if (!onlyPackage) {
222802
+ throw new ConnectionError("Package name is undefined");
222803
+ }
222804
+ const pkg = await project.getPackage(onlyPackage);
222805
+ return await pkg.getMalloyConnection(connectionName);
222448
222806
  }
222449
- const pkg = await project.getPackage(packageName);
222450
- return pkg.getMalloyConnection(connectionName);
222807
+ throw new BadRequestError(`Ambiguous "duckdb" connection lookup: project "${projectName}" has multiple packages. ` + `Use /projects/${projectName}/packages/{packageName}/connections/duckdb/... to disambiguate.`);
222451
222808
  } else {
222452
- return project.getMalloyConnection(connectionName);
222809
+ return await project.getMalloyConnection(connectionName);
222453
222810
  }
222454
222811
  }
222455
222812
  async fetchTable(malloyConnection, tableKey, tablePath) {
@@ -222490,20 +222847,20 @@ class ConnectionController {
222490
222847
  const project = await this.projectStore.getProject(projectName, false);
222491
222848
  return project.listApiConnections();
222492
222849
  }
222493
- async listSchemas(projectName, connectionName) {
222850
+ async listSchemas(projectName, connectionName, packageName) {
222494
222851
  const project = await this.projectStore.getProject(projectName, false);
222495
- const connection = project.getApiConnection(connectionName);
222496
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222852
+ const connection = this.getApiConnectionForLookup(project, connectionName);
222853
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222497
222854
  return getSchemasForConnection(connection, malloyConnection);
222498
222855
  }
222499
- async listTables(projectName, connectionName, schemaName, tableNames) {
222856
+ async listTables(projectName, connectionName, schemaName, tableNames, packageName) {
222500
222857
  const project = await this.projectStore.getProject(projectName, false);
222501
- const connection = project.getApiConnection(connectionName);
222502
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222858
+ const connection = this.getApiConnectionForLookup(project, connectionName);
222859
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222503
222860
  return listTablesForSchema(connection, schemaName, malloyConnection, tableNames);
222504
222861
  }
222505
- async getConnectionSqlSource(projectName, connectionName, sqlStatement) {
222506
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222862
+ async getConnectionSqlSource(projectName, connectionName, sqlStatement, packageName) {
222863
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222507
222864
  try {
222508
222865
  const schema = await malloyConnection.fetchSelectSchema({
222509
222866
  connection: connectionName,
@@ -222519,10 +222876,10 @@ class ConnectionController {
222519
222876
  throw new ConnectionError(error.message);
222520
222877
  }
222521
222878
  }
222522
- async getTable(projectName, connectionName, schemaName, tablePath) {
222523
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222879
+ async getTable(projectName, connectionName, schemaName, tablePath, packageName) {
222880
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222524
222881
  const project = await this.projectStore.getProject(projectName, false);
222525
- const connection = project.getApiConnection(connectionName);
222882
+ const connection = this.getApiConnectionForLookup(project, connectionName);
222526
222883
  if (connection.type === "ducklake") {
222527
222884
  if (tablePath.split(".").length === 1) {
222528
222885
  tablePath = `${connectionName}.${schemaName}.${tablePath}`;
@@ -222554,8 +222911,8 @@ class ConnectionController {
222554
222911
  }
222555
222912
  return this.fetchTable(malloyConnection, tableKey, tablePath);
222556
222913
  }
222557
- async getConnectionQueryData(projectName, connectionName, sqlStatement, options) {
222558
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222914
+ async getConnectionQueryData(projectName, connectionName, sqlStatement, options, packageName) {
222915
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222559
222916
  let runSQLOptions = {};
222560
222917
  if (options) {
222561
222918
  runSQLOptions = JSON.parse(options);
@@ -222572,8 +222929,8 @@ class ConnectionController {
222572
222929
  throw new ConnectionError(error.message);
222573
222930
  }
222574
222931
  }
222575
- async getConnectionTemporaryTable(projectName, connectionName, sqlStatement) {
222576
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222932
+ async getConnectionTemporaryTable(projectName, connectionName, sqlStatement, packageName) {
222933
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222577
222934
  try {
222578
222935
  return {
222579
222936
  table: JSON.stringify(await malloyConnection.manifestTemporaryTable(sqlStatement))
@@ -222582,10 +222939,8 @@ class ConnectionController {
222582
222939
  throw new ConnectionError(error.message);
222583
222940
  }
222584
222941
  }
222585
- async testConnectionConfiguration(connectionConfig) {
222586
- if (connectionConfig && "config" in connectionConfig && typeof connectionConfig.config === "object") {
222587
- connectionConfig = connectionConfig.config;
222588
- }
222942
+ async testConnectionConfiguration(input) {
222943
+ const connectionConfig = input.config && typeof input.config === "object" ? input.config : input;
222589
222944
  if (!connectionConfig || typeof connectionConfig !== "object" || Object.keys(connectionConfig).length === 0) {
222590
222945
  throw new BadRequestError("Connection configuration is required and cannot be empty");
222591
222946
  }
@@ -222612,6 +222967,7 @@ class ConnectionController {
222612
222967
  throw new BadRequestError("Connection type is required");
222613
222968
  }
222614
222969
  validateAzureAttachedDatabases(connectionConfig);
222970
+ validateAdminAuthoredConnection(connectionName, connectionConfig);
222615
222971
  logger.info(`Creating connection "${connectionName}" in project "${projectName}"`);
222616
222972
  await this.connectionService.addConnection(projectName, connectionName, connectionConfig);
222617
222973
  return {
@@ -222623,6 +222979,7 @@ class ConnectionController {
222623
222979
  throw new BadRequestError("Connection payload is required");
222624
222980
  }
222625
222981
  validateAzureAttachedDatabases(connection);
222982
+ validateAdminAuthoredConnection(connectionName, connection);
222626
222983
  logger.info(`Updating connection "${connectionName}" in project "${projectName}"`);
222627
222984
  await this.connectionService.updateConnection(projectName, connectionName, connection);
222628
222985
  return {
@@ -222713,7 +223070,7 @@ class ModelController {
222713
223070
  }
222714
223071
 
222715
223072
  // src/controller/package.controller.ts
222716
- import * as path2 from "path";
223073
+ import * as path3 from "path";
222717
223074
  class PackageController {
222718
223075
  projectStore;
222719
223076
  manifestService;
@@ -222797,7 +223154,7 @@ class PackageController {
222797
223154
  return result;
222798
223155
  }
222799
223156
  async downloadPackage(projectName, packageName, packageLocation) {
222800
- const absoluteTargetPath = path2.join(this.projectStore.serverRootPath, PUBLISHER_DATA_DIR, projectName, packageName);
223157
+ const absoluteTargetPath = path3.join(this.projectStore.serverRootPath, PUBLISHER_DATA_DIR, projectName, packageName);
222801
223158
  const isCompressedFile = packageLocation.endsWith(".zip");
222802
223159
  if (packageLocation.startsWith("https://") || packageLocation.startsWith("git@")) {
222803
223160
  await this.projectStore.downloadGitHubDirectory(packageLocation, absoluteTargetPath);
@@ -222921,7 +223278,7 @@ class ReaddirpStream extends Readable2 {
222921
223278
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
222922
223279
  const statMethod = opts.lstat ? lstat : stat;
222923
223280
  if (wantBigintFsStats) {
222924
- this._stat = (path3) => statMethod(path3, { bigint: true });
223281
+ this._stat = (path4) => statMethod(path4, { bigint: true });
222925
223282
  } else {
222926
223283
  this._stat = statMethod;
222927
223284
  }
@@ -222946,8 +223303,8 @@ class ReaddirpStream extends Readable2 {
222946
223303
  const par = this.parent;
222947
223304
  const fil = par && par.files;
222948
223305
  if (fil && fil.length > 0) {
222949
- const { path: path3, depth } = par;
222950
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path3));
223306
+ const { path: path4, depth } = par;
223307
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path4));
222951
223308
  const awaited = await Promise.all(slice);
222952
223309
  for (const entry of awaited) {
222953
223310
  if (!entry)
@@ -222987,20 +223344,20 @@ class ReaddirpStream extends Readable2 {
222987
223344
  this.reading = false;
222988
223345
  }
222989
223346
  }
222990
- async _exploreDir(path3, depth) {
223347
+ async _exploreDir(path4, depth) {
222991
223348
  let files;
222992
223349
  try {
222993
- files = await readdir(path3, this._rdOptions);
223350
+ files = await readdir(path4, this._rdOptions);
222994
223351
  } catch (error) {
222995
223352
  this._onError(error);
222996
223353
  }
222997
- return { files, depth, path: path3 };
223354
+ return { files, depth, path: path4 };
222998
223355
  }
222999
- async _formatEntry(dirent, path3) {
223356
+ async _formatEntry(dirent, path4) {
223000
223357
  let entry;
223001
223358
  const basename = this._isDirent ? dirent.name : dirent;
223002
223359
  try {
223003
- const fullPath = presolve(pjoin(path3, basename));
223360
+ const fullPath = presolve(pjoin(path4, basename));
223004
223361
  entry = { path: prelative(this._root, fullPath), fullPath, basename };
223005
223362
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
223006
223363
  } catch (err) {
@@ -223399,16 +223756,16 @@ var delFromSet = (main, prop, item) => {
223399
223756
  };
223400
223757
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
223401
223758
  var FsWatchInstances = new Map;
223402
- function createFsWatchInstance(path3, options, listener, errHandler, emitRaw) {
223759
+ function createFsWatchInstance(path4, options, listener, errHandler, emitRaw) {
223403
223760
  const handleEvent = (rawEvent, evPath) => {
223404
- listener(path3);
223405
- emitRaw(rawEvent, evPath, { watchedPath: path3 });
223406
- if (evPath && path3 !== evPath) {
223407
- fsWatchBroadcast(sysPath.resolve(path3, evPath), KEY_LISTENERS, sysPath.join(path3, evPath));
223761
+ listener(path4);
223762
+ emitRaw(rawEvent, evPath, { watchedPath: path4 });
223763
+ if (evPath && path4 !== evPath) {
223764
+ fsWatchBroadcast(sysPath.resolve(path4, evPath), KEY_LISTENERS, sysPath.join(path4, evPath));
223408
223765
  }
223409
223766
  };
223410
223767
  try {
223411
- return fs_watch(path3, {
223768
+ return fs_watch(path4, {
223412
223769
  persistent: options.persistent
223413
223770
  }, handleEvent);
223414
223771
  } catch (error) {
@@ -223424,12 +223781,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
223424
223781
  listener(val1, val2, val3);
223425
223782
  });
223426
223783
  };
223427
- var setFsWatchListener = (path3, fullPath, options, handlers) => {
223784
+ var setFsWatchListener = (path4, fullPath, options, handlers) => {
223428
223785
  const { listener, errHandler, rawEmitter } = handlers;
223429
223786
  let cont = FsWatchInstances.get(fullPath);
223430
223787
  let watcher;
223431
223788
  if (!options.persistent) {
223432
- watcher = createFsWatchInstance(path3, options, listener, errHandler, rawEmitter);
223789
+ watcher = createFsWatchInstance(path4, options, listener, errHandler, rawEmitter);
223433
223790
  if (!watcher)
223434
223791
  return;
223435
223792
  return watcher.close.bind(watcher);
@@ -223439,7 +223796,7 @@ var setFsWatchListener = (path3, fullPath, options, handlers) => {
223439
223796
  addAndConvert(cont, KEY_ERR, errHandler);
223440
223797
  addAndConvert(cont, KEY_RAW, rawEmitter);
223441
223798
  } else {
223442
- watcher = createFsWatchInstance(path3, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
223799
+ watcher = createFsWatchInstance(path4, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
223443
223800
  if (!watcher)
223444
223801
  return;
223445
223802
  watcher.on(EV.ERROR, async (error) => {
@@ -223448,7 +223805,7 @@ var setFsWatchListener = (path3, fullPath, options, handlers) => {
223448
223805
  cont.watcherUnusable = true;
223449
223806
  if (isWindows && error.code === "EPERM") {
223450
223807
  try {
223451
- const fd = await open(path3, "r");
223808
+ const fd = await open(path4, "r");
223452
223809
  await fd.close();
223453
223810
  broadcastErr(error);
223454
223811
  } catch (err) {}
@@ -223478,7 +223835,7 @@ var setFsWatchListener = (path3, fullPath, options, handlers) => {
223478
223835
  };
223479
223836
  };
223480
223837
  var FsWatchFileInstances = new Map;
223481
- var setFsWatchFileListener = (path3, fullPath, options, handlers) => {
223838
+ var setFsWatchFileListener = (path4, fullPath, options, handlers) => {
223482
223839
  const { listener, rawEmitter } = handlers;
223483
223840
  let cont = FsWatchFileInstances.get(fullPath);
223484
223841
  const copts = cont && cont.options;
@@ -223500,7 +223857,7 @@ var setFsWatchFileListener = (path3, fullPath, options, handlers) => {
223500
223857
  });
223501
223858
  const currmtime = curr.mtimeMs;
223502
223859
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
223503
- foreach(cont.listeners, (listener2) => listener2(path3, curr));
223860
+ foreach(cont.listeners, (listener2) => listener2(path4, curr));
223504
223861
  }
223505
223862
  })
223506
223863
  };
@@ -223523,13 +223880,13 @@ class NodeFsHandler {
223523
223880
  this.fsw = fsW;
223524
223881
  this._boundHandleError = (error) => fsW._handleError(error);
223525
223882
  }
223526
- _watchWithNodeFs(path3, listener) {
223883
+ _watchWithNodeFs(path4, listener) {
223527
223884
  const opts = this.fsw.options;
223528
- const directory = sysPath.dirname(path3);
223529
- const basename2 = sysPath.basename(path3);
223885
+ const directory = sysPath.dirname(path4);
223886
+ const basename2 = sysPath.basename(path4);
223530
223887
  const parent = this.fsw._getWatchedDir(directory);
223531
223888
  parent.add(basename2);
223532
- const absolutePath = sysPath.resolve(path3);
223889
+ const absolutePath = sysPath.resolve(path4);
223533
223890
  const options = {
223534
223891
  persistent: opts.persistent
223535
223892
  };
@@ -223539,12 +223896,12 @@ class NodeFsHandler {
223539
223896
  if (opts.usePolling) {
223540
223897
  const enableBin = opts.interval !== opts.binaryInterval;
223541
223898
  options.interval = enableBin && isBinaryPath(basename2) ? opts.binaryInterval : opts.interval;
223542
- closer = setFsWatchFileListener(path3, absolutePath, options, {
223899
+ closer = setFsWatchFileListener(path4, absolutePath, options, {
223543
223900
  listener,
223544
223901
  rawEmitter: this.fsw._emitRaw
223545
223902
  });
223546
223903
  } else {
223547
- closer = setFsWatchListener(path3, absolutePath, options, {
223904
+ closer = setFsWatchListener(path4, absolutePath, options, {
223548
223905
  listener,
223549
223906
  errHandler: this._boundHandleError,
223550
223907
  rawEmitter: this.fsw._emitRaw
@@ -223562,7 +223919,7 @@ class NodeFsHandler {
223562
223919
  let prevStats = stats;
223563
223920
  if (parent.has(basename2))
223564
223921
  return;
223565
- const listener = async (path3, newStats) => {
223922
+ const listener = async (path4, newStats) => {
223566
223923
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
223567
223924
  return;
223568
223925
  if (!newStats || newStats.mtimeMs === 0) {
@@ -223576,11 +223933,11 @@ class NodeFsHandler {
223576
223933
  this.fsw._emit(EV.CHANGE, file, newStats2);
223577
223934
  }
223578
223935
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
223579
- this.fsw._closeFile(path3);
223936
+ this.fsw._closeFile(path4);
223580
223937
  prevStats = newStats2;
223581
223938
  const closer2 = this._watchWithNodeFs(file, listener);
223582
223939
  if (closer2)
223583
- this.fsw._addPathCloser(path3, closer2);
223940
+ this.fsw._addPathCloser(path4, closer2);
223584
223941
  } else {
223585
223942
  prevStats = newStats2;
223586
223943
  }
@@ -223604,7 +223961,7 @@ class NodeFsHandler {
223604
223961
  }
223605
223962
  return closer;
223606
223963
  }
223607
- async _handleSymlink(entry, directory, path3, item) {
223964
+ async _handleSymlink(entry, directory, path4, item) {
223608
223965
  if (this.fsw.closed) {
223609
223966
  return;
223610
223967
  }
@@ -223614,7 +223971,7 @@ class NodeFsHandler {
223614
223971
  this.fsw._incrReadyCount();
223615
223972
  let linkPath;
223616
223973
  try {
223617
- linkPath = await fsrealpath(path3);
223974
+ linkPath = await fsrealpath(path4);
223618
223975
  } catch (e) {
223619
223976
  this.fsw._emitReady();
223620
223977
  return true;
@@ -223624,12 +223981,12 @@ class NodeFsHandler {
223624
223981
  if (dir.has(item)) {
223625
223982
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
223626
223983
  this.fsw._symlinkPaths.set(full, linkPath);
223627
- this.fsw._emit(EV.CHANGE, path3, entry.stats);
223984
+ this.fsw._emit(EV.CHANGE, path4, entry.stats);
223628
223985
  }
223629
223986
  } else {
223630
223987
  dir.add(item);
223631
223988
  this.fsw._symlinkPaths.set(full, linkPath);
223632
- this.fsw._emit(EV.ADD, path3, entry.stats);
223989
+ this.fsw._emit(EV.ADD, path4, entry.stats);
223633
223990
  }
223634
223991
  this.fsw._emitReady();
223635
223992
  return true;
@@ -223658,9 +224015,9 @@ class NodeFsHandler {
223658
224015
  return;
223659
224016
  }
223660
224017
  const item = entry.path;
223661
- let path3 = sysPath.join(directory, item);
224018
+ let path4 = sysPath.join(directory, item);
223662
224019
  current.add(item);
223663
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path3, item)) {
224020
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path4, item)) {
223664
224021
  return;
223665
224022
  }
223666
224023
  if (this.fsw.closed) {
@@ -223669,8 +224026,8 @@ class NodeFsHandler {
223669
224026
  }
223670
224027
  if (item === target || !target && !previous.has(item)) {
223671
224028
  this.fsw._incrReadyCount();
223672
- path3 = sysPath.join(dir, sysPath.relative(dir, path3));
223673
- this._addToNodeFs(path3, initialAdd, wh, depth + 1);
224029
+ path4 = sysPath.join(dir, sysPath.relative(dir, path4));
224030
+ this._addToNodeFs(path4, initialAdd, wh, depth + 1);
223674
224031
  }
223675
224032
  }).on(EV.ERROR, this._boundHandleError);
223676
224033
  return new Promise((resolve2, reject) => {
@@ -223719,13 +224076,13 @@ class NodeFsHandler {
223719
224076
  }
223720
224077
  return closer;
223721
224078
  }
223722
- async _addToNodeFs(path3, initialAdd, priorWh, depth, target) {
224079
+ async _addToNodeFs(path4, initialAdd, priorWh, depth, target) {
223723
224080
  const ready = this.fsw._emitReady;
223724
- if (this.fsw._isIgnored(path3) || this.fsw.closed) {
224081
+ if (this.fsw._isIgnored(path4) || this.fsw.closed) {
223725
224082
  ready();
223726
224083
  return false;
223727
224084
  }
223728
- const wh = this.fsw._getWatchHelpers(path3);
224085
+ const wh = this.fsw._getWatchHelpers(path4);
223729
224086
  if (priorWh) {
223730
224087
  wh.filterPath = (entry) => priorWh.filterPath(entry);
223731
224088
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -223741,8 +224098,8 @@ class NodeFsHandler {
223741
224098
  const follow = this.fsw.options.followSymlinks;
223742
224099
  let closer;
223743
224100
  if (stats.isDirectory()) {
223744
- const absPath = sysPath.resolve(path3);
223745
- const targetPath = follow ? await fsrealpath(path3) : path3;
224101
+ const absPath = sysPath.resolve(path4);
224102
+ const targetPath = follow ? await fsrealpath(path4) : path4;
223746
224103
  if (this.fsw.closed)
223747
224104
  return;
223748
224105
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -223752,29 +224109,29 @@ class NodeFsHandler {
223752
224109
  this.fsw._symlinkPaths.set(absPath, targetPath);
223753
224110
  }
223754
224111
  } else if (stats.isSymbolicLink()) {
223755
- const targetPath = follow ? await fsrealpath(path3) : path3;
224112
+ const targetPath = follow ? await fsrealpath(path4) : path4;
223756
224113
  if (this.fsw.closed)
223757
224114
  return;
223758
224115
  const parent = sysPath.dirname(wh.watchPath);
223759
224116
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
223760
224117
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
223761
- closer = await this._handleDir(parent, stats, initialAdd, depth, path3, wh, targetPath);
224118
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path4, wh, targetPath);
223762
224119
  if (this.fsw.closed)
223763
224120
  return;
223764
224121
  if (targetPath !== undefined) {
223765
- this.fsw._symlinkPaths.set(sysPath.resolve(path3), targetPath);
224122
+ this.fsw._symlinkPaths.set(sysPath.resolve(path4), targetPath);
223766
224123
  }
223767
224124
  } else {
223768
224125
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
223769
224126
  }
223770
224127
  ready();
223771
224128
  if (closer)
223772
- this.fsw._addPathCloser(path3, closer);
224129
+ this.fsw._addPathCloser(path4, closer);
223773
224130
  return false;
223774
224131
  } catch (error) {
223775
224132
  if (this.fsw._handleError(error)) {
223776
224133
  ready();
223777
- return path3;
224134
+ return path4;
223778
224135
  }
223779
224136
  }
223780
224137
  }
@@ -223818,26 +224175,26 @@ function createPattern(matcher) {
223818
224175
  }
223819
224176
  return () => false;
223820
224177
  }
223821
- function normalizePath(path3) {
223822
- if (typeof path3 !== "string")
224178
+ function normalizePath(path4) {
224179
+ if (typeof path4 !== "string")
223823
224180
  throw new Error("string expected");
223824
- path3 = sysPath2.normalize(path3);
223825
- path3 = path3.replace(/\\/g, "/");
224181
+ path4 = sysPath2.normalize(path4);
224182
+ path4 = path4.replace(/\\/g, "/");
223826
224183
  let prepend = false;
223827
- if (path3.startsWith("//"))
224184
+ if (path4.startsWith("//"))
223828
224185
  prepend = true;
223829
224186
  const DOUBLE_SLASH_RE2 = /\/\//;
223830
- while (path3.match(DOUBLE_SLASH_RE2))
223831
- path3 = path3.replace(DOUBLE_SLASH_RE2, "/");
224187
+ while (path4.match(DOUBLE_SLASH_RE2))
224188
+ path4 = path4.replace(DOUBLE_SLASH_RE2, "/");
223832
224189
  if (prepend)
223833
- path3 = "/" + path3;
223834
- return path3;
224190
+ path4 = "/" + path4;
224191
+ return path4;
223835
224192
  }
223836
224193
  function matchPatterns(patterns, testString, stats) {
223837
- const path3 = normalizePath(testString);
224194
+ const path4 = normalizePath(testString);
223838
224195
  for (let index = 0;index < patterns.length; index++) {
223839
224196
  const pattern = patterns[index];
223840
- if (pattern(path3, stats)) {
224197
+ if (pattern(path4, stats)) {
223841
224198
  return true;
223842
224199
  }
223843
224200
  }
@@ -223877,19 +224234,19 @@ var toUnix = (string) => {
223877
224234
  }
223878
224235
  return str;
223879
224236
  };
223880
- var normalizePathToUnix = (path3) => toUnix(sysPath2.normalize(toUnix(path3)));
223881
- var normalizeIgnored = (cwd = "") => (path3) => {
223882
- if (typeof path3 === "string") {
223883
- return normalizePathToUnix(sysPath2.isAbsolute(path3) ? path3 : sysPath2.join(cwd, path3));
224237
+ var normalizePathToUnix = (path4) => toUnix(sysPath2.normalize(toUnix(path4)));
224238
+ var normalizeIgnored = (cwd = "") => (path4) => {
224239
+ if (typeof path4 === "string") {
224240
+ return normalizePathToUnix(sysPath2.isAbsolute(path4) ? path4 : sysPath2.join(cwd, path4));
223884
224241
  } else {
223885
- return path3;
224242
+ return path4;
223886
224243
  }
223887
224244
  };
223888
- var getAbsolutePath = (path3, cwd) => {
223889
- if (sysPath2.isAbsolute(path3)) {
223890
- return path3;
224245
+ var getAbsolutePath = (path4, cwd) => {
224246
+ if (sysPath2.isAbsolute(path4)) {
224247
+ return path4;
223891
224248
  }
223892
- return sysPath2.join(cwd, path3);
224249
+ return sysPath2.join(cwd, path4);
223893
224250
  };
223894
224251
  var EMPTY_SET = Object.freeze(new Set);
223895
224252
 
@@ -223946,10 +224303,10 @@ var STAT_METHOD_F = "stat";
223946
224303
  var STAT_METHOD_L = "lstat";
223947
224304
 
223948
224305
  class WatchHelper {
223949
- constructor(path3, follow, fsw) {
224306
+ constructor(path4, follow, fsw) {
223950
224307
  this.fsw = fsw;
223951
- const watchPath = path3;
223952
- this.path = path3 = path3.replace(REPLACER_RE, "");
224308
+ const watchPath = path4;
224309
+ this.path = path4 = path4.replace(REPLACER_RE, "");
223953
224310
  this.watchPath = watchPath;
223954
224311
  this.fullWatchPath = sysPath2.resolve(watchPath);
223955
224312
  this.dirParts = [];
@@ -224062,20 +224419,20 @@ class FSWatcher extends EventEmitter2 {
224062
224419
  this._closePromise = undefined;
224063
224420
  let paths = unifyPaths(paths_);
224064
224421
  if (cwd) {
224065
- paths = paths.map((path3) => {
224066
- const absPath = getAbsolutePath(path3, cwd);
224422
+ paths = paths.map((path4) => {
224423
+ const absPath = getAbsolutePath(path4, cwd);
224067
224424
  return absPath;
224068
224425
  });
224069
224426
  }
224070
- paths.forEach((path3) => {
224071
- this._removeIgnoredPath(path3);
224427
+ paths.forEach((path4) => {
224428
+ this._removeIgnoredPath(path4);
224072
224429
  });
224073
224430
  this._userIgnored = undefined;
224074
224431
  if (!this._readyCount)
224075
224432
  this._readyCount = 0;
224076
224433
  this._readyCount += paths.length;
224077
- Promise.all(paths.map(async (path3) => {
224078
- const res = await this._nodeFsHandler._addToNodeFs(path3, !_internal, undefined, 0, _origAdd);
224434
+ Promise.all(paths.map(async (path4) => {
224435
+ const res = await this._nodeFsHandler._addToNodeFs(path4, !_internal, undefined, 0, _origAdd);
224079
224436
  if (res)
224080
224437
  this._emitReady();
224081
224438
  return res;
@@ -224094,17 +224451,17 @@ class FSWatcher extends EventEmitter2 {
224094
224451
  return this;
224095
224452
  const paths = unifyPaths(paths_);
224096
224453
  const { cwd } = this.options;
224097
- paths.forEach((path3) => {
224098
- if (!sysPath2.isAbsolute(path3) && !this._closers.has(path3)) {
224454
+ paths.forEach((path4) => {
224455
+ if (!sysPath2.isAbsolute(path4) && !this._closers.has(path4)) {
224099
224456
  if (cwd)
224100
- path3 = sysPath2.join(cwd, path3);
224101
- path3 = sysPath2.resolve(path3);
224457
+ path4 = sysPath2.join(cwd, path4);
224458
+ path4 = sysPath2.resolve(path4);
224102
224459
  }
224103
- this._closePath(path3);
224104
- this._addIgnoredPath(path3);
224105
- if (this._watched.has(path3)) {
224460
+ this._closePath(path4);
224461
+ this._addIgnoredPath(path4);
224462
+ if (this._watched.has(path4)) {
224106
224463
  this._addIgnoredPath({
224107
- path: path3,
224464
+ path: path4,
224108
224465
  recursive: true
224109
224466
  });
224110
224467
  }
@@ -224153,38 +224510,38 @@ class FSWatcher extends EventEmitter2 {
224153
224510
  if (event !== EVENTS.ERROR)
224154
224511
  this.emit(EVENTS.ALL, event, ...args);
224155
224512
  }
224156
- async _emit(event, path3, stats) {
224513
+ async _emit(event, path4, stats) {
224157
224514
  if (this.closed)
224158
224515
  return;
224159
224516
  const opts = this.options;
224160
224517
  if (isWindows)
224161
- path3 = sysPath2.normalize(path3);
224518
+ path4 = sysPath2.normalize(path4);
224162
224519
  if (opts.cwd)
224163
- path3 = sysPath2.relative(opts.cwd, path3);
224164
- const args = [path3];
224520
+ path4 = sysPath2.relative(opts.cwd, path4);
224521
+ const args = [path4];
224165
224522
  if (stats != null)
224166
224523
  args.push(stats);
224167
224524
  const awf = opts.awaitWriteFinish;
224168
224525
  let pw;
224169
- if (awf && (pw = this._pendingWrites.get(path3))) {
224526
+ if (awf && (pw = this._pendingWrites.get(path4))) {
224170
224527
  pw.lastChange = new Date;
224171
224528
  return this;
224172
224529
  }
224173
224530
  if (opts.atomic) {
224174
224531
  if (event === EVENTS.UNLINK) {
224175
- this._pendingUnlinks.set(path3, [event, ...args]);
224532
+ this._pendingUnlinks.set(path4, [event, ...args]);
224176
224533
  setTimeout(() => {
224177
- this._pendingUnlinks.forEach((entry, path4) => {
224534
+ this._pendingUnlinks.forEach((entry, path5) => {
224178
224535
  this.emit(...entry);
224179
224536
  this.emit(EVENTS.ALL, ...entry);
224180
- this._pendingUnlinks.delete(path4);
224537
+ this._pendingUnlinks.delete(path5);
224181
224538
  });
224182
224539
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
224183
224540
  return this;
224184
224541
  }
224185
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path3)) {
224542
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path4)) {
224186
224543
  event = EVENTS.CHANGE;
224187
- this._pendingUnlinks.delete(path3);
224544
+ this._pendingUnlinks.delete(path4);
224188
224545
  }
224189
224546
  }
224190
224547
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -224202,16 +224559,16 @@ class FSWatcher extends EventEmitter2 {
224202
224559
  this.emitWithAll(event, args);
224203
224560
  }
224204
224561
  };
224205
- this._awaitWriteFinish(path3, awf.stabilityThreshold, event, awfEmit);
224562
+ this._awaitWriteFinish(path4, awf.stabilityThreshold, event, awfEmit);
224206
224563
  return this;
224207
224564
  }
224208
224565
  if (event === EVENTS.CHANGE) {
224209
- const isThrottled = !this._throttle(EVENTS.CHANGE, path3, 50);
224566
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path4, 50);
224210
224567
  if (isThrottled)
224211
224568
  return this;
224212
224569
  }
224213
224570
  if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
224214
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path3) : path3;
224571
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path4) : path4;
224215
224572
  let stats2;
224216
224573
  try {
224217
224574
  stats2 = await stat3(fullPath);
@@ -224230,23 +224587,23 @@ class FSWatcher extends EventEmitter2 {
224230
224587
  }
224231
224588
  return error || this.closed;
224232
224589
  }
224233
- _throttle(actionType, path3, timeout) {
224590
+ _throttle(actionType, path4, timeout) {
224234
224591
  if (!this._throttled.has(actionType)) {
224235
224592
  this._throttled.set(actionType, new Map);
224236
224593
  }
224237
224594
  const action = this._throttled.get(actionType);
224238
224595
  if (!action)
224239
224596
  throw new Error("invalid throttle");
224240
- const actionPath = action.get(path3);
224597
+ const actionPath = action.get(path4);
224241
224598
  if (actionPath) {
224242
224599
  actionPath.count++;
224243
224600
  return false;
224244
224601
  }
224245
224602
  let timeoutObject;
224246
224603
  const clear = () => {
224247
- const item = action.get(path3);
224604
+ const item = action.get(path4);
224248
224605
  const count = item ? item.count : 0;
224249
- action.delete(path3);
224606
+ action.delete(path4);
224250
224607
  clearTimeout(timeoutObject);
224251
224608
  if (item)
224252
224609
  clearTimeout(item.timeoutObject);
@@ -224254,50 +224611,50 @@ class FSWatcher extends EventEmitter2 {
224254
224611
  };
224255
224612
  timeoutObject = setTimeout(clear, timeout);
224256
224613
  const thr = { timeoutObject, clear, count: 0 };
224257
- action.set(path3, thr);
224614
+ action.set(path4, thr);
224258
224615
  return thr;
224259
224616
  }
224260
224617
  _incrReadyCount() {
224261
224618
  return this._readyCount++;
224262
224619
  }
224263
- _awaitWriteFinish(path3, threshold, event, awfEmit) {
224620
+ _awaitWriteFinish(path4, threshold, event, awfEmit) {
224264
224621
  const awf = this.options.awaitWriteFinish;
224265
224622
  if (typeof awf !== "object")
224266
224623
  return;
224267
224624
  const pollInterval = awf.pollInterval;
224268
224625
  let timeoutHandler;
224269
- let fullPath = path3;
224270
- if (this.options.cwd && !sysPath2.isAbsolute(path3)) {
224271
- fullPath = sysPath2.join(this.options.cwd, path3);
224626
+ let fullPath = path4;
224627
+ if (this.options.cwd && !sysPath2.isAbsolute(path4)) {
224628
+ fullPath = sysPath2.join(this.options.cwd, path4);
224272
224629
  }
224273
224630
  const now = new Date;
224274
224631
  const writes = this._pendingWrites;
224275
224632
  function awaitWriteFinishFn(prevStat) {
224276
224633
  statcb(fullPath, (err, curStat) => {
224277
- if (err || !writes.has(path3)) {
224634
+ if (err || !writes.has(path4)) {
224278
224635
  if (err && err.code !== "ENOENT")
224279
224636
  awfEmit(err);
224280
224637
  return;
224281
224638
  }
224282
224639
  const now2 = Number(new Date);
224283
224640
  if (prevStat && curStat.size !== prevStat.size) {
224284
- writes.get(path3).lastChange = now2;
224641
+ writes.get(path4).lastChange = now2;
224285
224642
  }
224286
- const pw = writes.get(path3);
224643
+ const pw = writes.get(path4);
224287
224644
  const df = now2 - pw.lastChange;
224288
224645
  if (df >= threshold) {
224289
- writes.delete(path3);
224646
+ writes.delete(path4);
224290
224647
  awfEmit(undefined, curStat);
224291
224648
  } else {
224292
224649
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
224293
224650
  }
224294
224651
  });
224295
224652
  }
224296
- if (!writes.has(path3)) {
224297
- writes.set(path3, {
224653
+ if (!writes.has(path4)) {
224654
+ writes.set(path4, {
224298
224655
  lastChange: now,
224299
224656
  cancelWait: () => {
224300
- writes.delete(path3);
224657
+ writes.delete(path4);
224301
224658
  clearTimeout(timeoutHandler);
224302
224659
  return event;
224303
224660
  }
@@ -224305,8 +224662,8 @@ class FSWatcher extends EventEmitter2 {
224305
224662
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
224306
224663
  }
224307
224664
  }
224308
- _isIgnored(path3, stats) {
224309
- if (this.options.atomic && DOT_RE.test(path3))
224665
+ _isIgnored(path4, stats) {
224666
+ if (this.options.atomic && DOT_RE.test(path4))
224310
224667
  return true;
224311
224668
  if (!this._userIgnored) {
224312
224669
  const { cwd } = this.options;
@@ -224316,13 +224673,13 @@ class FSWatcher extends EventEmitter2 {
224316
224673
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
224317
224674
  this._userIgnored = anymatch(list, undefined);
224318
224675
  }
224319
- return this._userIgnored(path3, stats);
224676
+ return this._userIgnored(path4, stats);
224320
224677
  }
224321
- _isntIgnored(path3, stat4) {
224322
- return !this._isIgnored(path3, stat4);
224678
+ _isntIgnored(path4, stat4) {
224679
+ return !this._isIgnored(path4, stat4);
224323
224680
  }
224324
- _getWatchHelpers(path3) {
224325
- return new WatchHelper(path3, this.options.followSymlinks, this);
224681
+ _getWatchHelpers(path4) {
224682
+ return new WatchHelper(path4, this.options.followSymlinks, this);
224326
224683
  }
224327
224684
  _getWatchedDir(directory) {
224328
224685
  const dir = sysPath2.resolve(directory);
@@ -224336,57 +224693,57 @@ class FSWatcher extends EventEmitter2 {
224336
224693
  return Boolean(Number(stats.mode) & 256);
224337
224694
  }
224338
224695
  _remove(directory, item, isDirectory) {
224339
- const path3 = sysPath2.join(directory, item);
224340
- const fullPath = sysPath2.resolve(path3);
224341
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path3) || this._watched.has(fullPath);
224342
- if (!this._throttle("remove", path3, 100))
224696
+ const path4 = sysPath2.join(directory, item);
224697
+ const fullPath = sysPath2.resolve(path4);
224698
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path4) || this._watched.has(fullPath);
224699
+ if (!this._throttle("remove", path4, 100))
224343
224700
  return;
224344
224701
  if (!isDirectory && this._watched.size === 1) {
224345
224702
  this.add(directory, item, true);
224346
224703
  }
224347
- const wp = this._getWatchedDir(path3);
224704
+ const wp = this._getWatchedDir(path4);
224348
224705
  const nestedDirectoryChildren = wp.getChildren();
224349
- nestedDirectoryChildren.forEach((nested) => this._remove(path3, nested));
224706
+ nestedDirectoryChildren.forEach((nested) => this._remove(path4, nested));
224350
224707
  const parent = this._getWatchedDir(directory);
224351
224708
  const wasTracked = parent.has(item);
224352
224709
  parent.remove(item);
224353
224710
  if (this._symlinkPaths.has(fullPath)) {
224354
224711
  this._symlinkPaths.delete(fullPath);
224355
224712
  }
224356
- let relPath = path3;
224713
+ let relPath = path4;
224357
224714
  if (this.options.cwd)
224358
- relPath = sysPath2.relative(this.options.cwd, path3);
224715
+ relPath = sysPath2.relative(this.options.cwd, path4);
224359
224716
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
224360
224717
  const event = this._pendingWrites.get(relPath).cancelWait();
224361
224718
  if (event === EVENTS.ADD)
224362
224719
  return;
224363
224720
  }
224364
- this._watched.delete(path3);
224721
+ this._watched.delete(path4);
224365
224722
  this._watched.delete(fullPath);
224366
224723
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
224367
- if (wasTracked && !this._isIgnored(path3))
224368
- this._emit(eventName, path3);
224369
- this._closePath(path3);
224724
+ if (wasTracked && !this._isIgnored(path4))
224725
+ this._emit(eventName, path4);
224726
+ this._closePath(path4);
224370
224727
  }
224371
- _closePath(path3) {
224372
- this._closeFile(path3);
224373
- const dir = sysPath2.dirname(path3);
224374
- this._getWatchedDir(dir).remove(sysPath2.basename(path3));
224728
+ _closePath(path4) {
224729
+ this._closeFile(path4);
224730
+ const dir = sysPath2.dirname(path4);
224731
+ this._getWatchedDir(dir).remove(sysPath2.basename(path4));
224375
224732
  }
224376
- _closeFile(path3) {
224377
- const closers = this._closers.get(path3);
224733
+ _closeFile(path4) {
224734
+ const closers = this._closers.get(path4);
224378
224735
  if (!closers)
224379
224736
  return;
224380
224737
  closers.forEach((closer) => closer());
224381
- this._closers.delete(path3);
224738
+ this._closers.delete(path4);
224382
224739
  }
224383
- _addPathCloser(path3, closer) {
224740
+ _addPathCloser(path4, closer) {
224384
224741
  if (!closer)
224385
224742
  return;
224386
- let list = this._closers.get(path3);
224743
+ let list = this._closers.get(path4);
224387
224744
  if (!list) {
224388
224745
  list = [];
224389
- this._closers.set(path3, list);
224746
+ this._closers.set(path4, list);
224390
224747
  }
224391
224748
  list.push(closer);
224392
224749
  }
@@ -224416,7 +224773,7 @@ function watch(paths, options = {}) {
224416
224773
  var esm_default = { watch, FSWatcher };
224417
224774
 
224418
224775
  // src/controller/watch-mode.controller.ts
224419
- import path9 from "path";
224776
+ import path10 from "path";
224420
224777
 
224421
224778
  // src/service/project_store.ts
224422
224779
  var import_client_s32 = __toESM(require_dist_cjs75(), 1);
@@ -224634,7 +224991,7 @@ class Mutex {
224634
224991
  // src/service/project_store.ts
224635
224992
  import crypto3 from "crypto";
224636
224993
  import * as fs7 from "fs";
224637
- import * as path8 from "path";
224994
+ import * as path9 from "path";
224638
224995
 
224639
224996
  // ../../node_modules/simple-git/dist/esm/index.js
224640
224997
  var import_file_exists = __toESM(require_dist11(), 1);
@@ -224672,8 +225029,8 @@ function pathspec(...paths) {
224672
225029
  cache.set(key, paths);
224673
225030
  return key;
224674
225031
  }
224675
- function isPathSpec(path3) {
224676
- return path3 instanceof String && cache.has(path3);
225032
+ function isPathSpec(path4) {
225033
+ return path4 instanceof String && cache.has(path4);
224677
225034
  }
224678
225035
  function toPaths(pathSpec) {
224679
225036
  return cache.get(pathSpec) || [];
@@ -224759,8 +225116,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = `
224759
225116
  function forEachLineWithContent(input, callback) {
224760
225117
  return toLinesWithContent(input, true).map((line) => callback(line));
224761
225118
  }
224762
- function folderExists(path3) {
224763
- return import_file_exists.exists(path3, import_file_exists.FOLDER);
225119
+ function folderExists(path4) {
225120
+ return import_file_exists.exists(path4, import_file_exists.FOLDER);
224764
225121
  }
224765
225122
  function append2(target, item) {
224766
225123
  if (Array.isArray(target)) {
@@ -225141,8 +225498,8 @@ function checkIsRepoRootTask() {
225141
225498
  commands,
225142
225499
  format: "utf-8",
225143
225500
  onError,
225144
- parser(path3) {
225145
- return /^\.(git)?$/.test(path3.trim());
225501
+ parser(path4) {
225502
+ return /^\.(git)?$/.test(path4.trim());
225146
225503
  }
225147
225504
  };
225148
225505
  }
@@ -225553,11 +225910,11 @@ function parseGrep(grep) {
225553
225910
  const paths = /* @__PURE__ */ new Set;
225554
225911
  const results = {};
225555
225912
  forEachLineWithContent(grep, (input) => {
225556
- const [path3, line, preview] = input.split(NULL);
225557
- paths.add(path3);
225558
- (results[path3] = results[path3] || []).push({
225913
+ const [path4, line, preview] = input.split(NULL);
225914
+ paths.add(path4);
225915
+ (results[path4] = results[path4] || []).push({
225559
225916
  line: asNumber(line),
225560
- path: path3,
225917
+ path: path4,
225561
225918
  preview
225562
225919
  });
225563
225920
  });
@@ -226219,14 +226576,14 @@ var init_hash_object = __esm({
226219
226576
  init_task();
226220
226577
  }
226221
226578
  });
226222
- function parseInit(bare, path3, text) {
226579
+ function parseInit(bare, path4, text) {
226223
226580
  const response = String(text).trim();
226224
226581
  let result;
226225
226582
  if (result = initResponseRegex.exec(response)) {
226226
- return new InitSummary(bare, path3, false, result[1]);
226583
+ return new InitSummary(bare, path4, false, result[1]);
226227
226584
  }
226228
226585
  if (result = reInitResponseRegex.exec(response)) {
226229
- return new InitSummary(bare, path3, true, result[1]);
226586
+ return new InitSummary(bare, path4, true, result[1]);
226230
226587
  }
226231
226588
  let gitDir = "";
226232
226589
  const tokens = response.split(" ");
@@ -226237,7 +226594,7 @@ function parseInit(bare, path3, text) {
226237
226594
  break;
226238
226595
  }
226239
226596
  }
226240
- return new InitSummary(bare, path3, /^re/i.test(response), gitDir);
226597
+ return new InitSummary(bare, path4, /^re/i.test(response), gitDir);
226241
226598
  }
226242
226599
  var InitSummary;
226243
226600
  var initResponseRegex;
@@ -226245,9 +226602,9 @@ var reInitResponseRegex;
226245
226602
  var init_InitSummary = __esm({
226246
226603
  "src/lib/responses/InitSummary.ts"() {
226247
226604
  InitSummary = class {
226248
- constructor(bare, path3, existing, gitDir) {
226605
+ constructor(bare, path4, existing, gitDir) {
226249
226606
  this.bare = bare;
226250
- this.path = path3;
226607
+ this.path = path4;
226251
226608
  this.existing = existing;
226252
226609
  this.gitDir = gitDir;
226253
226610
  }
@@ -226259,7 +226616,7 @@ var init_InitSummary = __esm({
226259
226616
  function hasBareCommand(command) {
226260
226617
  return command.includes(bareCommand);
226261
226618
  }
226262
- function initTask(bare = false, path3, customArgs) {
226619
+ function initTask(bare = false, path4, customArgs) {
226263
226620
  const commands = ["init", ...customArgs];
226264
226621
  if (bare && !hasBareCommand(commands)) {
226265
226622
  commands.splice(1, 0, bareCommand);
@@ -226268,7 +226625,7 @@ function initTask(bare = false, path3, customArgs) {
226268
226625
  commands,
226269
226626
  format: "utf-8",
226270
226627
  parser(text) {
226271
- return parseInit(commands.includes("--bare"), path3, text);
226628
+ return parseInit(commands.includes("--bare"), path4, text);
226272
226629
  }
226273
226630
  };
226274
226631
  }
@@ -226983,12 +227340,12 @@ var init_FileStatusSummary = __esm({
226983
227340
  "src/lib/responses/FileStatusSummary.ts"() {
226984
227341
  fromPathRegex = /^(.+)\0(.+)$/;
226985
227342
  FileStatusSummary = class {
226986
- constructor(path3, index, working_dir) {
226987
- this.path = path3;
227343
+ constructor(path4, index, working_dir) {
227344
+ this.path = path4;
226988
227345
  this.index = index;
226989
227346
  this.working_dir = working_dir;
226990
227347
  if (index === "R" || working_dir === "R") {
226991
- const detail = fromPathRegex.exec(path3) || [null, path3, path3];
227348
+ const detail = fromPathRegex.exec(path4) || [null, path4, path4];
226992
227349
  this.from = detail[2] || "";
226993
227350
  this.path = detail[1] || "";
226994
227351
  }
@@ -227019,14 +227376,14 @@ function splitLine(result, lineStr) {
227019
227376
  default:
227020
227377
  return;
227021
227378
  }
227022
- function data(index, workingDir, path3) {
227379
+ function data(index, workingDir, path4) {
227023
227380
  const raw = `${index}${workingDir}`;
227024
227381
  const handler = parsers6.get(raw);
227025
227382
  if (handler) {
227026
- handler(result, path3);
227383
+ handler(result, path4);
227027
227384
  }
227028
227385
  if (raw !== "##" && raw !== "!!") {
227029
- result.files.push(new FileStatusSummary(path3, index, workingDir));
227386
+ result.files.push(new FileStatusSummary(path4, index, workingDir));
227030
227387
  }
227031
227388
  }
227032
227389
  }
@@ -227257,8 +227614,8 @@ var init_simple_git_api = __esm({
227257
227614
  }
227258
227615
  return this._runTask(configurationErrorTask("Git.cwd: workingDirectory must be supplied as a string"), next);
227259
227616
  }
227260
- hashObject(path3, write) {
227261
- return this._runTask(hashObjectTask(path3, write === true), trailingFunctionArgument(arguments));
227617
+ hashObject(path4, write) {
227618
+ return this._runTask(hashObjectTask(path4, write === true), trailingFunctionArgument(arguments));
227262
227619
  }
227263
227620
  init(bare) {
227264
227621
  return this._runTask(initTask(bare === true, this._executor.cwd, getTrailingOptions(arguments)), trailingFunctionArgument(arguments));
@@ -227835,8 +228192,8 @@ __export2(sub_module_exports, {
227835
228192
  subModuleTask: () => subModuleTask,
227836
228193
  updateSubModuleTask: () => updateSubModuleTask
227837
228194
  });
227838
- function addSubModuleTask(repo, path3) {
227839
- return subModuleTask(["add", repo, path3]);
228195
+ function addSubModuleTask(repo, path4) {
228196
+ return subModuleTask(["add", repo, path4]);
227840
228197
  }
227841
228198
  function initSubModuleTask(customArgs) {
227842
228199
  return subModuleTask(["init", ...customArgs]);
@@ -228104,8 +228461,8 @@ var require_git = __commonJS2({
228104
228461
  }
228105
228462
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
228106
228463
  };
228107
- Git2.prototype.submoduleAdd = function(repo, path3, then) {
228108
- return this._runTask(addSubModuleTask2(repo, path3), trailingFunctionArgument2(arguments));
228464
+ Git2.prototype.submoduleAdd = function(repo, path4, then) {
228465
+ return this._runTask(addSubModuleTask2(repo, path4), trailingFunctionArgument2(arguments));
228109
228466
  };
228110
228467
  Git2.prototype.submoduleUpdate = function(args, then) {
228111
228468
  return this._runTask(updateSubModuleTask2(getTrailingOptions2(arguments, true)), trailingFunctionArgument2(arguments));
@@ -228621,7 +228978,7 @@ import { Writable } from "stream";
228621
228978
 
228622
228979
  // src/config.ts
228623
228980
  import fs2 from "fs";
228624
- import path3 from "path";
228981
+ import path4 from "path";
228625
228982
  function substituteEnvVars(value) {
228626
228983
  const envVarPattern = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
228627
228984
  return value.replace(envVarPattern, (_match, varName) => {
@@ -228649,7 +229006,7 @@ function processConfigValue(value) {
228649
229006
  return value;
228650
229007
  }
228651
229008
  var getPublisherConfig = (serverRoot) => {
228652
- const publisherConfigPath = path3.join(serverRoot, PUBLISHER_CONFIG_NAME);
229009
+ const publisherConfigPath = path4.join(serverRoot, PUBLISHER_CONFIG_NAME);
228653
229010
  if (!fs2.existsSync(publisherConfigPath)) {
228654
229011
  return {
228655
229012
  frozenConfig: false,
@@ -228661,7 +229018,12 @@ var getPublisherConfig = (serverRoot) => {
228661
229018
  const fileContent = fs2.readFileSync(publisherConfigPath, "utf8");
228662
229019
  rawConfig = JSON.parse(fileContent);
228663
229020
  } catch (error) {
228664
- logger.error(`Failed to parse ${PUBLISHER_CONFIG_NAME}. Using default empty config.`, { error });
229021
+ const message = error instanceof Error ? error.message : String(error);
229022
+ logger.error(`Failed to parse ${publisherConfigPath}: ${message}. Using default empty config.`, {
229023
+ path: publisherConfigPath,
229024
+ error: message,
229025
+ stack: error instanceof Error ? error.stack : undefined
229026
+ });
228665
229027
  return {
228666
229028
  frozenConfig: false,
228667
229029
  projects: []
@@ -228871,7 +229233,7 @@ function registerHealthEndpoints(app) {
228871
229233
 
228872
229234
  // src/storage/duckdb/DuckDBConnection.ts
228873
229235
  import duckdb from "duckdb";
228874
- import * as path4 from "path";
229236
+ import * as path5 from "path";
228875
229237
 
228876
229238
  class DuckDBConnection2 {
228877
229239
  db = null;
@@ -228879,7 +229241,7 @@ class DuckDBConnection2 {
228879
229241
  dbPath;
228880
229242
  mutex = new Mutex;
228881
229243
  constructor(dbPath) {
228882
- this.dbPath = dbPath || path4.join(process.cwd(), "publisher.db");
229244
+ this.dbPath = dbPath || path5.join(process.cwd(), "publisher.db");
228883
229245
  }
228884
229246
  async initialize() {
228885
229247
  return new Promise((resolve3, reject) => {
@@ -229970,20 +230332,20 @@ class StorageManager {
229970
230332
  }
229971
230333
 
229972
230334
  // src/service/project.ts
229973
- import { FixedConnectionMap as FixedConnectionMap2, MalloyError as MalloyError3, Runtime as Runtime2 } from "@malloydata/malloy";
230335
+ import { MalloyError as MalloyError3, Runtime as Runtime2 } from "@malloydata/malloy";
229974
230336
  import * as fs6 from "fs";
229975
- import * as path7 from "path";
230337
+ import * as path8 from "path";
229976
230338
 
229977
230339
  // src/utils.ts
229978
230340
  import * as fs3 from "fs";
229979
230341
  import { fileURLToPath } from "url";
229980
230342
  var URL_READER = {
229981
230343
  readURL: (url2) => {
229982
- let path5 = url2.toString();
230344
+ let path6 = url2.toString();
229983
230345
  if (url2.protocol == "file:") {
229984
- path5 = fileURLToPath(url2);
230346
+ path6 = fileURLToPath(url2);
229985
230347
  }
229986
- return fs3.promises.readFile(path5, "utf8");
230348
+ return fs3.promises.readFile(path6, "utf8");
229987
230349
  }
229988
230350
  };
229989
230351
 
@@ -229991,11 +230353,15 @@ var URL_READER = {
229991
230353
  var import_api3 = __toESM(require_src(), 1);
229992
230354
  var import_recursive_readdir = __toESM(require_recursive_readdir(), 1);
229993
230355
  import * as fs5 from "fs/promises";
229994
- import * as path6 from "path";
230356
+ import * as path7 from "path";
229995
230357
  import { DuckDBConnection as DuckDBConnection3 } from "@malloydata/db-duckdb";
230358
+ import"@malloydata/db-duckdb/native";
229996
230359
  import {
229997
230360
  ConnectionRuntime,
229998
- EmptyURLReader
230361
+ EmptyURLReader,
230362
+ FixedConnectionMap as FixedConnectionMap2,
230363
+ contextOverlay as contextOverlay2,
230364
+ MalloyConfig as MalloyConfig3
229999
230365
  } from "@malloydata/malloy";
230000
230366
 
230001
230367
  // src/service/model.ts
@@ -230004,6 +230370,7 @@ import {
230004
230370
  API,
230005
230371
  FixedConnectionMap,
230006
230372
  isSourceDef,
230373
+ MalloyConfig as MalloyConfig2,
230007
230374
  MalloyError as MalloyError2,
230008
230375
  modelDefToModelInfo,
230009
230376
  Runtime
@@ -230014,8 +230381,7 @@ import {
230014
230381
  } from "@malloydata/malloy-sql";
230015
230382
  import { createRequire as createRequire2 } from "module";
230016
230383
  import * as fs4 from "fs/promises";
230017
- import * as path5 from "path";
230018
- import { fileURLToPath as fileURLToPath2 } from "url";
230384
+ import * as path6 from "path";
230019
230385
 
230020
230386
  // src/data_styles.ts
230021
230387
  function compileDataStyles(styles) {
@@ -230301,8 +230667,8 @@ class Model {
230301
230667
  const arrowMatch = query.match(/^\s*(\w+)\s*->/m);
230302
230668
  return runMatch?.[1] ?? arrowMatch?.[1];
230303
230669
  }
230304
- static async create(packageName, packagePath, modelPath, connections, options) {
230305
- const { runtime, modelURL, importBaseURL, dataStyles, modelType } = await Model.getModelRuntime(packagePath, modelPath, connections, options);
230670
+ static async create(packageName, packagePath, modelPath, malloyConfig, options) {
230671
+ const { runtime, modelURL, importBaseURL, dataStyles, modelType } = await Model.getModelRuntime(packagePath, modelPath, malloyConfig, options);
230306
230672
  try {
230307
230673
  const { modelMaterializer, runnableNotebookCells } = await Model.getModelMaterializer(runtime, importBaseURL, modelURL, modelPath);
230308
230674
  let modelDef = undefined;
@@ -230625,8 +230991,8 @@ run: ${sourceName ? sourceName + "->" : ""}${queryName}`;
230625
230991
  newSources: cell.newSources?.map((source) => JSON.stringify(source))
230626
230992
  };
230627
230993
  }
230628
- static async getModelRuntime(packagePath, modelPath, connections, options) {
230629
- const fullModelPath = path5.join(packagePath, modelPath);
230994
+ static async getModelRuntime(packagePath, modelPath, malloyConfig, options) {
230995
+ const fullModelPath = path6.join(packagePath, modelPath);
230630
230996
  try {
230631
230997
  if (!(await fs4.stat(fullModelPath)).isFile()) {
230632
230998
  throw new ModelNotFoundError(`${modelPath} is not a file.`);
@@ -230644,26 +231010,24 @@ run: ${sourceName ? sourceName + "->" : ""}${queryName}`;
230644
231010
  }
230645
231011
  const modelURL = new URL(`file://${fullModelPath}`);
230646
231012
  const baseUrl = new URL(".", modelURL);
230647
- const fileUrl = new URL(baseUrl.pathname, "file:");
230648
- const workingDirectory = fileURLToPath2(fileUrl);
230649
231013
  const importBaseURL = new URL(baseUrl.pathname + "/", "file:");
230650
231014
  const urlReader = new HackyDataStylesAccumulator(URL_READER);
230651
- const duckdbConnection = connections.get("duckdb");
230652
- await duckdbConnection.runSQL(`SET FILE_SEARCH_PATH='${workingDirectory}';`);
230653
- const runtimeOptions = {
231015
+ const runtime = new Runtime({
230654
231016
  urlReader,
230655
- connections: new FixedConnectionMap(connections, "duckdb")
230656
- };
230657
- if (options?.buildManifest) {
230658
- runtimeOptions.buildManifest = {
230659
- entries: options.buildManifest,
230660
- strict: false
230661
- };
230662
- }
230663
- const runtime = new Runtime(runtimeOptions);
231017
+ config: Model.toMalloyConfig(malloyConfig),
231018
+ buildManifest: options?.buildManifest ? { entries: options.buildManifest, strict: false } : undefined
231019
+ });
230664
231020
  const dataStyles = urlReader.getHackyAccumulatedDataStyles();
230665
231021
  return { runtime, modelURL, importBaseURL, dataStyles, modelType };
230666
231022
  }
231023
+ static toMalloyConfig(input) {
231024
+ if (input instanceof MalloyConfig2) {
231025
+ return input;
231026
+ }
231027
+ const malloyConfig = new MalloyConfig2({ connections: {} });
231028
+ malloyConfig.wrapConnections(() => new FixedConnectionMap(input, "duckdb"));
231029
+ return malloyConfig;
231030
+ }
230667
231031
  static getQueries(modelPath, modelDef) {
230668
231032
  const isNamedQuery = (object) => object.type === "query";
230669
231033
  return Object.values(modelDef.contents).filter(isNamedQuery).map((queryObj) => ({
@@ -230841,7 +231205,7 @@ run: ${sourceName ? sourceName + "->" : ""}${queryName}`;
230841
231205
  return this.modelType;
230842
231206
  }
230843
231207
  async getFileText(packagePath) {
230844
- const fullPath = path5.join(packagePath, this.modelPath);
231208
+ const fullPath = path6.join(packagePath, this.modelPath);
230845
231209
  try {
230846
231210
  return await fs4.readFile(fullPath, "utf8");
230847
231211
  } catch {
@@ -230860,22 +231224,22 @@ class Package {
230860
231224
  databases;
230861
231225
  models = new Map;
230862
231226
  packagePath;
230863
- connections = new Map;
231227
+ malloyConfig;
230864
231228
  static meter = import_api3.metrics.getMeter("publisher");
230865
231229
  static packageLoadHistogram = this.meter.createHistogram("malloy_package_load_duration", {
230866
231230
  description: "Time taken to load a Malloy package",
230867
231231
  unit: "ms"
230868
231232
  });
230869
- constructor(projectName, packageName, packagePath, packageMetadata, databases, models, connections = new Map) {
231233
+ constructor(projectName, packageName, packagePath, packageMetadata, databases, models, malloyConfig = new MalloyConfig3({ connections: {} })) {
230870
231234
  this.projectName = projectName;
230871
231235
  this.packageName = packageName;
230872
231236
  this.packagePath = packagePath;
230873
231237
  this.packageMetadata = packageMetadata;
230874
231238
  this.databases = databases;
230875
231239
  this.models = models;
230876
- this.connections = connections;
231240
+ this.malloyConfig = malloyConfig;
230877
231241
  }
230878
- static async create(projectName, packageName, packagePath, projectConnections) {
231242
+ static async create(projectName, packageName, packagePath, projectMalloyConfig) {
230879
231243
  const startTime = performance.now();
230880
231244
  await Package.validatePackageManifestExistsOrThrowError(packagePath);
230881
231245
  const manifestValidationTime = performance.now();
@@ -230898,10 +231262,8 @@ class Package {
230898
231262
  databaseCount: databases.length,
230899
231263
  duration: formatDuration(databasesTime - packageConfigTime)
230900
231264
  });
230901
- const connections = new Map(projectConnections);
230902
- const duckdbConnection = new DuckDBConnection3("duckdb", ":memory:", packagePath);
230903
- connections.set("duckdb", duckdbConnection);
230904
- const models = await Package.loadModels(packageName, packagePath, connections);
231265
+ const malloyConfig = Package.buildPackageMalloyConfig(packagePath, typeof projectMalloyConfig === "function" ? projectMalloyConfig : () => Package.toMalloyConfig(projectMalloyConfig));
231266
+ const models = await Package.loadModels(packageName, packagePath, malloyConfig);
230905
231267
  const modelsTime = performance.now();
230906
231268
  logger.info("Models loaded", {
230907
231269
  packageName,
@@ -230935,7 +231297,7 @@ class Package {
230935
231297
  packageName,
230936
231298
  duration: formatDuration(executionTime)
230937
231299
  });
230938
- return new Package(projectName, packageName, packagePath, packageConfig, databases, models, connections);
231300
+ return new Package(projectName, packageName, packagePath, packageConfig, databases, models, malloyConfig);
230939
231301
  } catch (error) {
230940
231302
  logger.error(`Error loading package ${packageName}`, { error });
230941
231303
  console.error(error);
@@ -230962,9 +231324,6 @@ class Package {
230962
231324
  getPackageName() {
230963
231325
  return this.packageName;
230964
231326
  }
230965
- getPackagePath() {
230966
- return this.packagePath;
230967
- }
230968
231327
  getPackageMetadata() {
230969
231328
  return this.packageMetadata;
230970
231329
  }
@@ -230974,6 +231333,15 @@ class Package {
230974
231333
  getModel(modelPath) {
230975
231334
  return this.models.get(modelPath);
230976
231335
  }
231336
+ async getMalloyConnection(connectionName) {
231337
+ return this.malloyConfig.connections.lookupConnection(connectionName);
231338
+ }
231339
+ getMalloyConfig() {
231340
+ return this.malloyConfig;
231341
+ }
231342
+ getPackagePath() {
231343
+ return this.packagePath;
231344
+ }
230977
231345
  getModelPaths() {
230978
231346
  return Array.from(this.models.keys());
230979
231347
  }
@@ -230984,23 +231352,13 @@ class Package {
230984
231352
  modelCount: modelPaths.length,
230985
231353
  manifestEntryCount: Object.keys(buildManifest).length
230986
231354
  });
230987
- const reloaded = await Promise.all(modelPaths.map((modelPath) => Model.create(this.packageName, this.packagePath, modelPath, this.connections, { buildManifest })));
231355
+ const reloaded = await Promise.all(modelPaths.map((modelPath) => Model.create(this.packageName, this.packagePath, modelPath, this.malloyConfig, { buildManifest })));
230988
231356
  const nextModels = new Map;
230989
231357
  for (const model of reloaded) {
230990
231358
  nextModels.set(model.getPath(), model);
230991
231359
  }
230992
231360
  this.models = nextModels;
230993
231361
  }
230994
- getConnections() {
230995
- return this.connections;
230996
- }
230997
- getMalloyConnection(connectionName) {
230998
- const connection = this.connections.get(connectionName);
230999
- if (!connection) {
231000
- throw new Error(`Connection ${connectionName} not found in package ${this.packageName}`);
231001
- }
231002
- return connection;
231003
- }
231004
231362
  async getModelFileText(modelPath) {
231005
231363
  const model = this.getModel(modelPath);
231006
231364
  if (!model) {
@@ -231045,11 +231403,40 @@ class Package {
231045
231403
  };
231046
231404
  }));
231047
231405
  }
231048
- static async loadModels(packageName, packagePath, connections) {
231406
+ static async loadModels(packageName, packagePath, malloyConfig) {
231049
231407
  const modelPaths = await Package.getModelPaths(packagePath);
231050
- const models = await Promise.all(modelPaths.map((modelPath) => Model.create(packageName, packagePath, modelPath, connections)));
231408
+ const models = await Promise.all(modelPaths.map((modelPath) => Model.create(packageName, packagePath, modelPath, malloyConfig)));
231051
231409
  return new Map(models.map((model) => [model.getPath(), model]));
231052
231410
  }
231411
+ static buildPackageMalloyConfig(packagePath, getProjectMalloyConfig) {
231412
+ const malloyConfig = new MalloyConfig3({
231413
+ connections: {
231414
+ duckdb: {
231415
+ is: "duckdb",
231416
+ databasePath: ":memory:"
231417
+ }
231418
+ }
231419
+ }, {
231420
+ config: contextOverlay2({ rootDirectory: packagePath })
231421
+ });
231422
+ malloyConfig.wrapConnections((base) => ({
231423
+ lookupConnection: async (name) => {
231424
+ if (!name || name === "duckdb") {
231425
+ return base.lookupConnection(name);
231426
+ }
231427
+ return getProjectMalloyConfig().connections.lookupConnection(name);
231428
+ }
231429
+ }));
231430
+ return malloyConfig;
231431
+ }
231432
+ static toMalloyConfig(input) {
231433
+ if (input instanceof MalloyConfig3) {
231434
+ return input;
231435
+ }
231436
+ const malloyConfig = new MalloyConfig3({ connections: {} });
231437
+ malloyConfig.wrapConnections(() => new FixedConnectionMap2(input, "duckdb"));
231438
+ return malloyConfig;
231439
+ }
231053
231440
  static async getModelPaths(packagePath) {
231054
231441
  let files = undefined;
231055
231442
  try {
@@ -231059,11 +231446,11 @@ class Package {
231059
231446
  throw new PackageNotFoundError(`Package config for ${packagePath} does not exist.`);
231060
231447
  }
231061
231448
  return files.map((fullPath) => {
231062
- return path6.relative(packagePath, fullPath).replace(/\\/g, "/");
231449
+ return path7.relative(packagePath, fullPath).replace(/\\/g, "/");
231063
231450
  }).filter((modelPath) => modelPath.endsWith(MODEL_FILE_SUFFIX) || modelPath.endsWith(NOTEBOOK_FILE_SUFFIX));
231064
231451
  }
231065
231452
  static async validatePackageManifestExistsOrThrowError(packagePath) {
231066
- const packageConfigPath = path6.join(packagePath, PACKAGE_MANIFEST_NAME);
231453
+ const packageConfigPath = path7.join(packagePath, PACKAGE_MANIFEST_NAME);
231067
231454
  try {
231068
231455
  await fs5.stat(packageConfigPath);
231069
231456
  } catch {
@@ -231072,7 +231459,7 @@ class Package {
231072
231459
  }
231073
231460
  }
231074
231461
  static async readPackageConfig(packagePath) {
231075
- const packageConfigPath = path6.join(packagePath, PACKAGE_MANIFEST_NAME);
231462
+ const packageConfigPath = path7.join(packagePath, PACKAGE_MANIFEST_NAME);
231076
231463
  const packageConfigContents = await fs5.readFile(packageConfigPath);
231077
231464
  const packageManifest = JSON.parse(packageConfigContents.toString());
231078
231465
  return {
@@ -231094,11 +231481,11 @@ class Package {
231094
231481
  let files = undefined;
231095
231482
  files = await import_recursive_readdir.default(packagePath);
231096
231483
  return files.map((fullPath) => {
231097
- return path6.relative(packagePath, fullPath).replace(/\\/g, "/");
231484
+ return path7.relative(packagePath, fullPath).replace(/\\/g, "/");
231098
231485
  }).filter((modelPath) => modelPath.endsWith(".parquet") || modelPath.endsWith(".csv"));
231099
231486
  }
231100
231487
  static async getDatabaseInfo(packagePath, databasePath) {
231101
- const fullPath = path6.join(packagePath, databasePath);
231488
+ const fullPath = path7.join(packagePath, databasePath);
231102
231489
  const runtime = new ConnectionRuntime({
231103
231490
  urlReader: new EmptyURLReader,
231104
231491
  connections: [new DuckDBConnection3("duckdb")]
@@ -231127,19 +231514,23 @@ class Package {
231127
231514
  }
231128
231515
 
231129
231516
  // src/service/project.ts
231517
+ var RETIRED_CONNECTION_DRAIN_MS = 30000;
231518
+
231130
231519
  class Project {
231131
231520
  packages = new Map;
231132
231521
  packageMutexes = new Map;
231133
231522
  packageStatuses = new Map;
231134
- malloyConnections;
231523
+ malloyConfig;
231524
+ connectionMutex = new Mutex;
231525
+ retiredConnectionGenerations = new Set;
231135
231526
  apiConnections;
231136
231527
  projectPath;
231137
231528
  projectName;
231138
231529
  metadata;
231139
- constructor(projectName, projectPath, malloyConnections, apiConnections) {
231530
+ constructor(projectName, projectPath, malloyConfig, apiConnections) {
231140
231531
  this.projectName = projectName;
231141
231532
  this.projectPath = projectPath;
231142
- this.malloyConnections = malloyConnections;
231533
+ this.malloyConfig = malloyConfig;
231143
231534
  this.apiConnections = apiConnections;
231144
231535
  this.metadata = {
231145
231536
  resource: `${API_PREFIX}/projects/${this.projectName}`,
@@ -231151,7 +231542,7 @@ class Project {
231151
231542
  async writeProjectReadme(readme) {
231152
231543
  if (readme === undefined)
231153
231544
  return;
231154
- const readmePath = path7.join(this.projectPath, "README.md");
231545
+ const readmePath = path8.join(this.projectPath, "README.md");
231155
231546
  try {
231156
231547
  await fs6.promises.writeFile(readmePath, readme, "utf-8");
231157
231548
  logger.info(`Updated README.md for project ${this.projectName}`);
@@ -231166,15 +231557,16 @@ class Project {
231166
231557
  await this.writeProjectReadme(payload.readme);
231167
231558
  }
231168
231559
  if (payload.connections) {
231169
- logger.info(`Updating ${payload.connections.length} connections for project ${this.projectName}`);
231170
- const isUpdateConnectionRequest = true;
231171
- const { malloyConnections, apiConnections } = await createProjectConnections(payload.connections, this.projectPath, isUpdateConnectionRequest);
231172
- this.malloyConnections = malloyConnections;
231173
- this.apiConnections = apiConnections;
231174
- logger.info(`Successfully updated connections for project ${this.projectName}`, {
231175
- malloyConnections: malloyConnections.size,
231176
- apiConnections: apiConnections.length,
231177
- internalConnections: apiConnections.length
231560
+ const payloadConnections = payload.connections;
231561
+ await this.runConnectionUpdateExclusive(async () => {
231562
+ logger.info(`Updating ${payloadConnections.length} connections for project ${this.projectName}`);
231563
+ const isUpdateConnectionRequest = true;
231564
+ const nextMalloyConfig = buildProjectMalloyConfig(payloadConnections, this.projectPath, isUpdateConnectionRequest);
231565
+ this.updateConnections(nextMalloyConfig);
231566
+ logger.info(`Successfully updated connections for project ${this.projectName}`, {
231567
+ apiConnections: this.apiConnections.length,
231568
+ internalConnections: this.apiConnections.length
231569
+ });
231178
231570
  });
231179
231571
  }
231180
231572
  return this;
@@ -231184,18 +231576,17 @@ class Project {
231184
231576
  throw new ProjectNotFoundError(`Project path ${projectPath} not found`);
231185
231577
  }
231186
231578
  logger.info(`Creating project with connection configuration`);
231187
- const { malloyConnections, apiConnections } = await createProjectConnections(connections, projectPath);
231188
- logger.info(`Loaded ${malloyConnections.size + apiConnections.length} connections for project ${projectName}`, {
231189
- malloyConnections,
231190
- apiConnections
231579
+ const malloyConfig = buildProjectMalloyConfig(connections, projectPath);
231580
+ logger.info(`Loaded ${malloyConfig.apiConnections.length} connections for project ${projectName}`, {
231581
+ apiConnections: malloyConfig.apiConnections
231191
231582
  });
231192
- const project = new Project(projectName, projectPath, malloyConnections, apiConnections);
231583
+ const project = new Project(projectName, projectPath, malloyConfig, malloyConfig.apiConnections);
231193
231584
  return project;
231194
231585
  }
231195
231586
  async reloadProjectMetadata() {
231196
231587
  let readme = "";
231197
231588
  try {
231198
- readme = (await fs6.promises.readFile(path7.join(this.projectPath, README_NAME))).toString();
231589
+ readme = (await fs6.promises.readFile(path8.join(this.projectPath, README_NAME))).toString();
231199
231590
  } catch {}
231200
231591
  this.metadata = {
231201
231592
  ...this.metadata,
@@ -231206,10 +231597,10 @@ class Project {
231206
231597
  return this.metadata;
231207
231598
  }
231208
231599
  async compileSource(packageName, modelName, source, includeSql = false) {
231209
- const modelDir = path7.dirname(path7.join(this.projectPath, packageName, modelName));
231210
- const virtualUri = `file://${path7.join(modelDir, "__compile_check.malloy")}`;
231600
+ const modelDir = path8.dirname(path8.join(this.projectPath, packageName, modelName));
231601
+ const virtualUri = `file://${path8.join(modelDir, "__compile_check.malloy")}`;
231211
231602
  const virtualUrl = new URL(virtualUri);
231212
- const modelPath = path7.join(this.projectPath, packageName, modelName);
231603
+ const modelPath = path8.join(this.projectPath, packageName, modelName);
231213
231604
  let modelContent = "";
231214
231605
  try {
231215
231606
  modelContent = await fs6.promises.readFile(modelPath, "utf8");
@@ -231224,9 +231615,10 @@ ${source}` : source;
231224
231615
  return URL_READER.readURL(url2);
231225
231616
  }
231226
231617
  };
231618
+ const pkg = await this.getPackage(packageName);
231227
231619
  const runtime = new Runtime2({
231228
231620
  urlReader: interceptingReader,
231229
- connections: new FixedConnectionMap2(this.malloyConnections, "duckdb")
231621
+ config: pkg.getMalloyConfig()
231230
231622
  });
231231
231623
  try {
231232
231624
  const modelMaterializer = runtime.loadModel(virtualUrl);
@@ -231256,12 +231648,40 @@ ${source}` : source;
231256
231648
  }
231257
231649
  return connection;
231258
231650
  }
231259
- getMalloyConnection(connectionName) {
231260
- const connection = this.malloyConnections.get(connectionName);
231261
- if (!connection) {
231262
- throw new ConnectionNotFoundError(`Connection ${connectionName} not found`);
231651
+ async getMalloyConnection(connectionName) {
231652
+ return this.malloyConfig.malloyConfig.connections.lookupConnection(connectionName);
231653
+ }
231654
+ getProjectMalloyConfig() {
231655
+ return this.malloyConfig.malloyConfig;
231656
+ }
231657
+ async runConnectionUpdateExclusive(fn) {
231658
+ return this.connectionMutex.runExclusive(fn);
231659
+ }
231660
+ retireConnectionGeneration(label, releaseConnections) {
231661
+ const generation = {
231662
+ label,
231663
+ releaseConnections
231664
+ };
231665
+ generation.timer = setTimeout(() => {
231666
+ this.releaseRetiredConnectionGeneration(generation);
231667
+ }, RETIRED_CONNECTION_DRAIN_MS);
231668
+ generation.timer.unref?.();
231669
+ this.retiredConnectionGenerations.add(generation);
231670
+ }
231671
+ async releaseRetiredConnectionGeneration(generation) {
231672
+ if (!this.retiredConnectionGenerations.delete(generation))
231673
+ return;
231674
+ if (generation.timer) {
231675
+ clearTimeout(generation.timer);
231263
231676
  }
231264
- return connection;
231677
+ try {
231678
+ await generation.releaseConnections();
231679
+ } catch (error) {
231680
+ logger.error(`Error releasing retired connection generation ${generation.label}`, { error });
231681
+ }
231682
+ }
231683
+ async releaseAllRetiredConnectionGenerations() {
231684
+ await Promise.all([...this.retiredConnectionGenerations].map((generation) => this.releaseRetiredConnectionGeneration(generation)));
231265
231685
  }
231266
231686
  async listPackages() {
231267
231687
  logger.debug("Listing packages", { projectPath: this.projectPath });
@@ -231316,8 +231736,11 @@ ${source}` : source;
231316
231736
  this.setPackageStatus(packageName, "loading" /* LOADING */);
231317
231737
  try {
231318
231738
  logger.debug(`Loading package ${packageName}...`);
231319
- const packagePath = path7.join(this.projectPath, packageName);
231320
- const _package2 = await Package.create(this.projectName, packageName, packagePath, this.malloyConnections);
231739
+ const packagePath = path8.join(this.projectPath, packageName);
231740
+ const _package2 = await Package.create(this.projectName, packageName, packagePath, () => this.malloyConfig.malloyConfig);
231741
+ if (existingPackage !== undefined && reload) {
231742
+ this.retireConnectionGeneration(`package ${packageName}`, () => existingPackage.getMalloyConfig().releaseConnections());
231743
+ }
231321
231744
  this.packages.set(packageName, _package2);
231322
231745
  this.setPackageStatus(packageName, "serving" /* SERVING */);
231323
231746
  logger.debug(`Successfully loaded package ${packageName}`);
@@ -231331,17 +231754,17 @@ ${source}` : source;
231331
231754
  });
231332
231755
  }
231333
231756
  async addPackage(packageName) {
231334
- const packagePath = path7.join(this.projectPath, packageName);
231757
+ const packagePath = path8.join(this.projectPath, packageName);
231335
231758
  if (!await fs6.promises.access(packagePath).then(() => true).catch(() => false) || !(await fs6.promises.stat(packagePath))?.isDirectory()) {
231336
231759
  throw new PackageNotFoundError(`Package ${packageName} not found`);
231337
231760
  }
231338
231761
  logger.info(`Adding package ${packageName} to project ${this.projectName}`, {
231339
231762
  packagePath,
231340
- malloyConnections: this.malloyConnections
231763
+ malloyConfig: this.malloyConfig.malloyConfig
231341
231764
  });
231342
231765
  this.setPackageStatus(packageName, "loading" /* LOADING */);
231343
231766
  try {
231344
- this.packages.set(packageName, await Package.create(this.projectName, packageName, packagePath, this.malloyConnections));
231767
+ this.packages.set(packageName, await Package.create(this.projectName, packageName, packagePath, () => this.malloyConfig.malloyConfig));
231345
231768
  } catch (error) {
231346
231769
  logger.error("Error adding package", { error });
231347
231770
  this.deletePackageStatus(packageName);
@@ -231351,8 +231774,8 @@ ${source}` : source;
231351
231774
  return this.packages.get(packageName);
231352
231775
  }
231353
231776
  async writePackageManifest(packageName, metadata) {
231354
- const packagePath = path7.join(this.projectPath, packageName);
231355
- const manifestPath = path7.join(packagePath, "publisher.json");
231777
+ const packagePath = path8.join(this.projectPath, packageName);
231778
+ const manifestPath = path8.join(packagePath, "publisher.json");
231356
231779
  try {
231357
231780
  let existingManifest = {};
231358
231781
  try {
@@ -231422,8 +231845,9 @@ ${source}` : source;
231422
231845
  } else if (packageStatus?.status === "serving" /* SERVING */) {
231423
231846
  this.setPackageStatus(packageName, "unloading" /* UNLOADING */);
231424
231847
  }
231848
+ await _package.getMalloyConfig().releaseConnections();
231425
231849
  try {
231426
- await fs6.promises.rm(path7.join(this.projectPath, packageName), {
231850
+ await fs6.promises.rm(path8.join(this.projectPath, packageName), {
231427
231851
  recursive: true,
231428
231852
  force: true
231429
231853
  });
@@ -231433,39 +231857,45 @@ ${source}` : source;
231433
231857
  this.packages.delete(packageName);
231434
231858
  this.packageStatuses.delete(packageName);
231435
231859
  }
231436
- updateConnections(malloyConnections, apiConnections) {
231437
- this.malloyConnections = malloyConnections;
231438
- this.apiConnections = apiConnections;
231860
+ updateConnections(malloyConfig, _apiConnections, afterPreviousRelease) {
231861
+ const previousMalloyConfig = this.malloyConfig;
231862
+ this.malloyConfig = malloyConfig;
231863
+ this.apiConnections = malloyConfig.apiConnections;
231864
+ if (previousMalloyConfig !== malloyConfig) {
231865
+ this.retireConnectionGeneration(`project ${this.projectName}`, async () => {
231866
+ await previousMalloyConfig.releaseConnections();
231867
+ await afterPreviousRelease?.();
231868
+ });
231869
+ } else {
231870
+ afterPreviousRelease?.();
231871
+ }
231439
231872
  }
231440
231873
  async deleteConnection(connectionName) {
231441
- this.malloyConnections.get(connectionName)?.close();
231442
- const isDeleted = this.malloyConnections.delete(connectionName);
231443
231874
  const index = this.apiConnections.findIndex((conn) => conn.name === connectionName);
231444
- const connectionType = this.apiConnections[index]?.type;
231445
- if (connectionType === "duckdb") {
231446
- await this.deleteDuckDBConnection(connectionName);
231447
- } else if (connectionType === "ducklake") {
231448
- await this.deleteDuckLakeConnection(connectionName);
231449
- }
231450
231875
  if (index !== -1) {
231451
231876
  this.apiConnections.splice(index, 1);
231452
231877
  }
231453
- if (isDeleted || index !== -1) {
231878
+ if (index !== -1) {
231454
231879
  logger.info(`Removed connection ${connectionName} from project ${this.projectName}`);
231455
231880
  } else {
231456
231881
  logger.warn(`Connection ${connectionName} not found in project ${this.projectName}`);
231457
231882
  }
231458
231883
  }
231459
- closeAllConnections() {
231460
- for (const [connectionName, connection] of this.malloyConnections) {
231461
- try {
231462
- connection.close();
231463
- logger.info(`Closed connection ${connectionName} for project ${this.projectName}`);
231464
- } catch (error) {
231465
- logger.error(`Error closing connection ${connectionName} for project ${this.projectName}`, { error });
231884
+ async closeAllConnections() {
231885
+ const packageReleases = await Promise.allSettled(Array.from(this.packages.values(), (pkg) => pkg.getMalloyConfig().releaseConnections()));
231886
+ for (const result of packageReleases) {
231887
+ if (result.status === "rejected") {
231888
+ logger.error(`Error closing package connections for project ${this.projectName}`, { error: result.reason });
231466
231889
  }
231467
231890
  }
231468
- this.malloyConnections.clear();
231891
+ this.packages.clear();
231892
+ this.packageStatuses.clear();
231893
+ try {
231894
+ await this.malloyConfig.releaseConnections();
231895
+ } catch (error) {
231896
+ logger.error(`Error closing connections for project ${this.projectName}`, { error });
231897
+ }
231898
+ await this.releaseAllRetiredConnectionGenerations();
231469
231899
  this.apiConnections = [];
231470
231900
  logger.info(`Closed all connections for project ${this.projectName}`);
231471
231901
  }
@@ -231477,16 +231907,13 @@ ${source}` : source;
231477
231907
  };
231478
231908
  }
231479
231909
  async deleteDuckDBConnection(connectionName) {
231480
- const duckdbPath = path7.join(this.projectPath, `${connectionName}.duckdb`);
231481
- fs6.promises.access(duckdbPath).then(() => {
231482
- fs6.promises.rm(duckdbPath).then(() => {
231483
- logger.info(`Removed DuckDB connection file ${connectionName} from project ${this.projectName}`);
231484
- }).catch((error) => {
231485
- logger.error(`Failed to remove DuckDB connection file ${connectionName} from project ${this.projectName}`, { error });
231486
- });
231487
- }).catch((error) => {
231910
+ const duckdbPath = path8.join(this.projectPath, `${connectionName}.duckdb`);
231911
+ try {
231912
+ await fs6.promises.rm(duckdbPath, { force: true });
231913
+ logger.info(`Removed DuckDB connection file ${connectionName} from project ${this.projectName}`);
231914
+ } catch (error) {
231488
231915
  logger.error(`Failed to remove DuckDB connection file ${connectionName} from project ${this.projectName}`, { error });
231489
- });
231916
+ }
231490
231917
  }
231491
231918
  async deleteDuckLakeConnection(connectionName) {
231492
231919
  await deleteDuckLakeConnectionFile(connectionName, this.projectPath);
@@ -231560,12 +231987,28 @@ class ProjectStore {
231560
231987
  const storageConfig = {
231561
231988
  type: "duckdb",
231562
231989
  duckdb: {
231563
- path: path8.join(serverRootPath, "publisher.db")
231990
+ path: path9.join(serverRootPath, "publisher.db")
231564
231991
  }
231565
231992
  };
231566
231993
  this.storageManager = new StorageManager(storageConfig);
231567
231994
  this.finishedInitialization = this.initialize();
231568
231995
  }
231996
+ async addConfiguredProject(project) {
231997
+ try {
231998
+ await this.addProject({
231999
+ name: project.name,
232000
+ resource: `${API_PREFIX}/projects/${project.name}`,
232001
+ connections: project.connections,
232002
+ packages: project.packages
232003
+ }, true);
232004
+ } catch (error) {
232005
+ this.logProjectInitializationError(project.name, error);
232006
+ }
232007
+ }
232008
+ logProjectInitializationError(projectName, error) {
232009
+ const label = projectName ? ` "${projectName}"` : "";
232010
+ logger.error(`Error initializing project${label}; skipping project`, this.extractErrorDataFromError(error));
232011
+ }
231569
232012
  async initialize() {
231570
232013
  const reInit = process.env.INITIALIZE_STORAGE === "true";
231571
232014
  const initialTime = performance.now();
@@ -231577,58 +232020,52 @@ class ProjectStore {
231577
232020
  const repository = this.storageManager.getRepository();
231578
232021
  if (reInit) {
231579
232022
  await Promise.all(projectManifest.projects.map(async (project) => {
231580
- await this.addProject({
231581
- name: project.name,
231582
- resource: `${API_PREFIX}/projects/${project.name}`,
231583
- connections: project.connections,
231584
- packages: project.packages
231585
- }, true);
232023
+ await this.addConfiguredProject(project);
231586
232024
  }));
231587
232025
  } else {
231588
232026
  const existingProjects = await repository.listProjects();
231589
232027
  if (existingProjects.length > 0) {
231590
232028
  await Promise.all(existingProjects.map(async (dbProject) => {
231591
- const projectExists = await fs7.promises.access(dbProject.path).then(() => true).catch(() => false);
231592
- if (!projectExists) {
231593
- const projectConfig = projectManifest.projects.find((p) => p.name === dbProject.name);
231594
- if (projectConfig) {
231595
- const projectInstance2 = await this.addProject({
231596
- name: projectConfig.name,
231597
- resource: `${API_PREFIX}/projects/${projectConfig.name}`,
231598
- connections: projectConfig.connections,
231599
- packages: projectConfig.packages
231600
- }, true);
231601
- await repository.updateProject(dbProject.id, {
231602
- path: projectInstance2.metadata.location
231603
- });
231604
- return projectInstance2.listPackages();
231605
- } else {
231606
- logger.error(`Project "${dbProject.name}" not found in config and files missing`);
231607
- return;
232029
+ try {
232030
+ const projectExists = await fs7.promises.access(dbProject.path).then(() => true).catch(() => false);
232031
+ if (!projectExists) {
232032
+ const projectConfig = projectManifest.projects.find((p) => p.name === dbProject.name);
232033
+ if (projectConfig) {
232034
+ const projectInstance2 = await this.addProject({
232035
+ name: projectConfig.name,
232036
+ resource: `${API_PREFIX}/projects/${projectConfig.name}`,
232037
+ connections: projectConfig.connections,
232038
+ packages: projectConfig.packages
232039
+ }, true);
232040
+ await repository.updateProject(dbProject.id, {
232041
+ path: projectInstance2.metadata.location
232042
+ });
232043
+ return projectInstance2.listPackages();
232044
+ } else {
232045
+ logger.error(`Project "${dbProject.name}" not found in config and files missing`);
232046
+ return;
232047
+ }
231608
232048
  }
232049
+ const connections = await repository.listConnections(dbProject.id);
232050
+ const projectInstance = await Project.create(dbProject.name, dbProject.path, connections.map((conn) => ({
232051
+ name: conn.name,
232052
+ type: conn.type,
232053
+ resource: `${API_PREFIX}/connections/${conn.name}`,
232054
+ ...conn.config
232055
+ })));
232056
+ const packages = await repository.listPackages(dbProject.id);
232057
+ packages.forEach((pkg) => {
232058
+ projectInstance.setPackageStatus(pkg.name, "serving" /* SERVING */);
232059
+ });
232060
+ this.projects.set(dbProject.name, projectInstance);
232061
+ return projectInstance.listPackages();
232062
+ } catch (error) {
232063
+ this.logProjectInitializationError(dbProject.name, error);
231609
232064
  }
231610
- const connections = await repository.listConnections(dbProject.id);
231611
- const projectInstance = await Project.create(dbProject.name, dbProject.path, connections.map((conn) => ({
231612
- name: conn.name,
231613
- type: conn.type,
231614
- resource: `${API_PREFIX}/connections/${conn.name}`,
231615
- ...conn.config
231616
- })));
231617
- this.projects.set(dbProject.name, projectInstance);
231618
- const packages = await repository.listPackages(dbProject.id);
231619
- packages.forEach((pkg) => {
231620
- projectInstance.setPackageStatus(pkg.name, "serving" /* SERVING */);
231621
- });
231622
- return projectInstance.listPackages();
231623
232065
  }));
231624
232066
  } else {
231625
232067
  await Promise.all(projectManifest.projects.map(async (project) => {
231626
- await this.addProject({
231627
- name: project.name,
231628
- resource: `${API_PREFIX}/projects/${project.name}`,
231629
- connections: project.connections,
231630
- packages: project.packages
231631
- }, true);
232068
+ await this.addConfiguredProject(project);
231632
232069
  }));
231633
232070
  }
231634
232071
  }
@@ -231640,7 +232077,6 @@ class ProjectStore {
231640
232077
  markNotReady();
231641
232078
  const errorData = this.extractErrorDataFromError(error);
231642
232079
  logger.error("Error initializing project store", errorData);
231643
- process.exit(1);
231644
232080
  }
231645
232081
  }
231646
232082
  async addProjectToDatabase(project) {
@@ -231838,7 +232274,7 @@ class ProjectStore {
231838
232274
  const reInit = process.env.INITIALIZE_STORAGE === "true";
231839
232275
  await fs7.promises.mkdir(this.serverRootPath, { recursive: true });
231840
232276
  if (reInit) {
231841
- const uploadDocsPath2 = path8.join(this.serverRootPath, PUBLISHER_DATA_DIR);
232277
+ const uploadDocsPath2 = path9.join(this.serverRootPath, PUBLISHER_DATA_DIR);
231842
232278
  logger.info(`Reinitialization mode: Cleaning up upload documents path ${uploadDocsPath2}`);
231843
232279
  try {
231844
232280
  await fs7.promises.rm(uploadDocsPath2, {
@@ -231855,7 +232291,7 @@ class ProjectStore {
231855
232291
  } else {
231856
232292
  logger.info(`Using existing publisher path`);
231857
232293
  }
231858
- const uploadDocsPath = path8.join(this.serverRootPath, PUBLISHER_DATA_DIR);
232294
+ const uploadDocsPath = path9.join(this.serverRootPath, PUBLISHER_DATA_DIR);
231859
232295
  await fs7.promises.mkdir(uploadDocsPath, { recursive: true });
231860
232296
  }
231861
232297
  async listProjects(skipInitializationCheck = false) {
@@ -232021,7 +232457,7 @@ class ProjectStore {
232021
232457
  return;
232022
232458
  }
232023
232459
  const projectPath = project.metadata?.location;
232024
- project.closeAllConnections();
232460
+ await project.closeAllConnections();
232025
232461
  this.projects.delete(projectName);
232026
232462
  await this.deleteProjectFromDatabase(projectName);
232027
232463
  if (projectPath) {
@@ -232079,12 +232515,12 @@ class ProjectStore {
232079
232515
  const absoluteProjectPath = `${this.serverRootPath}/${PUBLISHER_DATA_DIR}/${projectName}`;
232080
232516
  await fs7.promises.mkdir(absoluteProjectPath, { recursive: true });
232081
232517
  if (project.readme) {
232082
- await fs7.promises.writeFile(path8.join(absoluteProjectPath, "README.md"), project.readme);
232518
+ await fs7.promises.writeFile(path9.join(absoluteProjectPath, "README.md"), project.readme);
232083
232519
  }
232084
232520
  return absoluteProjectPath;
232085
232521
  }
232086
232522
  isLocalPath(location) {
232087
- return location.startsWith("./") || location.startsWith("../") || location.startsWith("~/") || location.startsWith("/") || path8.isAbsolute(location);
232523
+ return location.startsWith("./") || location.startsWith("../") || location.startsWith("~/") || location.startsWith("/") || path9.isAbsolute(location);
232088
232524
  }
232089
232525
  isGitHubURL(location) {
232090
232526
  return location.startsWith("https://github.com/") || location.startsWith("git@github.com:");
@@ -232140,7 +232576,7 @@ class ProjectStore {
232140
232576
  if (githubInfo && githubInfo.packagePath) {
232141
232577
  const subPathMatch = _package.location.match(/\/tree\/[^/]+\/(.+)$/);
232142
232578
  if (subPathMatch) {
232143
- sourcePath = path8.join(tempDownloadPath, subPathMatch[1]);
232579
+ sourcePath = path9.join(tempDownloadPath, subPathMatch[1]);
232144
232580
  } else {
232145
232581
  sourcePath = tempDownloadPath;
232146
232582
  }
@@ -232151,7 +232587,7 @@ class ProjectStore {
232151
232587
  if (this.isLocalPath(_package.location)) {
232152
232588
  sourcePath = _package.location;
232153
232589
  } else {
232154
- sourcePath = path8.join(tempDownloadPath, groupedLocation);
232590
+ sourcePath = path9.join(tempDownloadPath, groupedLocation);
232155
232591
  }
232156
232592
  }
232157
232593
  const sourceExists = await fs7.promises.access(sourcePath).then(() => true).catch(() => false);
@@ -232227,7 +232663,7 @@ class ProjectStore {
232227
232663
  }
232228
232664
  }
232229
232665
  if (this.isLocalPath(location)) {
232230
- const packagePath = path8.isAbsolute(location) ? location : path8.join(this.serverRootPath, location);
232666
+ const packagePath = path9.isAbsolute(location) ? location : path9.join(this.serverRootPath, location);
232231
232667
  try {
232232
232668
  logger.info(`Mounting local directory at "${packagePath}" to "${targetPath}"`);
232233
232669
  await this.mountLocalDirectory(packagePath, targetPath, projectName, packageName);
@@ -232281,11 +232717,11 @@ class ProjectStore {
232281
232717
  }
232282
232718
  await Promise.all(files.map(async (file) => {
232283
232719
  const relativeFilePath = file.name.replace(prefix, "");
232284
- const absoluteFilePath = isCompressedFile ? absoluteDirPath : path8.join(absoluteDirPath, relativeFilePath);
232720
+ const absoluteFilePath = isCompressedFile ? absoluteDirPath : path9.join(absoluteDirPath, relativeFilePath);
232285
232721
  if (file.name.endsWith("/")) {
232286
232722
  return;
232287
232723
  }
232288
- await fs7.promises.mkdir(path8.dirname(absoluteFilePath), {
232724
+ await fs7.promises.mkdir(path9.dirname(absoluteFilePath), {
232289
232725
  recursive: true
232290
232726
  });
232291
232727
  return fs7.promises.writeFile(absoluteFilePath, await file.download());
@@ -232301,7 +232737,7 @@ class ProjectStore {
232301
232737
  const prefix = prefixParts.join("/");
232302
232738
  if (isCompressedFile) {
232303
232739
  const zipFilePath = `${absoluteDirPath}.zip`;
232304
- await fs7.promises.mkdir(path8.dirname(zipFilePath), {
232740
+ await fs7.promises.mkdir(path9.dirname(zipFilePath), {
232305
232741
  recursive: true
232306
232742
  });
232307
232743
  const command = new import_client_s32.GetObjectCommand({
@@ -232340,8 +232776,8 @@ class ProjectStore {
232340
232776
  if (!relativeFilePath || relativeFilePath.endsWith("/")) {
232341
232777
  return;
232342
232778
  }
232343
- const absoluteFilePath = path8.join(absoluteDirPath, relativeFilePath);
232344
- await fs7.promises.mkdir(path8.dirname(absoluteFilePath), {
232779
+ const absoluteFilePath = path9.join(absoluteDirPath, relativeFilePath);
232780
+ await fs7.promises.mkdir(path9.dirname(absoluteFilePath), {
232345
232781
  recursive: true
232346
232782
  });
232347
232783
  const command = new import_client_s32.GetObjectCommand({
@@ -232403,7 +232839,7 @@ class ProjectStore {
232403
232839
  logger.info(`Successfully cloned entire repository to: ${absoluteDirPath}`);
232404
232840
  return;
232405
232841
  }
232406
- const packageFullPath = path8.join(absoluteDirPath, cleanPackagePath);
232842
+ const packageFullPath = path9.join(absoluteDirPath, cleanPackagePath);
232407
232843
  const packageExists = await fs7.promises.access(packageFullPath).then(() => true).catch(() => false);
232408
232844
  if (!packageExists) {
232409
232845
  throw new Error(`Package path "${cleanPackagePath}" does not exist in the cloned repository.`);
@@ -232411,7 +232847,7 @@ class ProjectStore {
232411
232847
  const dirContents = await fs7.promises.readdir(absoluteDirPath);
232412
232848
  for (const entry of dirContents) {
232413
232849
  if (entry !== cleanPackagePath.replace(/^\/+/, "").split("/")[0]) {
232414
- await fs7.promises.rm(path8.join(absoluteDirPath, entry), {
232850
+ await fs7.promises.rm(path9.join(absoluteDirPath, entry), {
232415
232851
  recursive: true,
232416
232852
  force: true
232417
232853
  });
@@ -232419,7 +232855,7 @@ class ProjectStore {
232419
232855
  }
232420
232856
  const packageContents = await fs7.promises.readdir(packageFullPath);
232421
232857
  for (const entry of packageContents) {
232422
- await fs7.promises.rename(path8.join(packageFullPath, entry), path8.join(absoluteDirPath, entry));
232858
+ await fs7.promises.rename(path9.join(packageFullPath, entry), path9.join(absoluteDirPath, entry));
232423
232859
  }
232424
232860
  await fs7.promises.rm(packageFullPath, { recursive: true, force: true });
232425
232861
  }
@@ -232466,9 +232902,9 @@ class WatchModeController {
232466
232902
  });
232467
232903
  return;
232468
232904
  }
232469
- this.watchingPath = path9.join(this.projectStore.serverRootPath, req.body.projectName);
232905
+ this.watchingPath = path10.join(this.projectStore.serverRootPath, req.body.projectName);
232470
232906
  this.watcher = esm_default.watch(this.watchingPath, {
232471
- ignored: (path10, stats) => !!stats?.isFile() && !path10.endsWith(".malloy") && !path10.endsWith(".md"),
232907
+ ignored: (path11, stats) => !!stats?.isFile() && !path11.endsWith(".malloy") && !path11.endsWith(".md"),
232472
232908
  ignoreInitial: true
232473
232909
  });
232474
232910
  const reloadProject = async () => {
@@ -232476,16 +232912,16 @@ class WatchModeController {
232476
232912
  await this.projectStore.addProject(project2.metadata);
232477
232913
  logger.info(`Reloaded ${req.body.projectName}`);
232478
232914
  };
232479
- this.watcher.on("add", async (path10) => {
232480
- logger.info(`Detected new file ${path10}, reloading ${req.body.projectName}`);
232915
+ this.watcher.on("add", async (path11) => {
232916
+ logger.info(`Detected new file ${path11}, reloading ${req.body.projectName}`);
232481
232917
  await reloadProject();
232482
232918
  });
232483
- this.watcher.on("unlink", async (path10) => {
232484
- logger.info(`Detected deletion of ${path10}, reloading ${req.body.projectName}`);
232919
+ this.watcher.on("unlink", async (path11) => {
232920
+ logger.info(`Detected deletion of ${path11}, reloading ${req.body.projectName}`);
232485
232921
  await reloadProject();
232486
232922
  });
232487
- this.watcher.on("change", async (path10) => {
232488
- logger.info(`Detected change on ${path10}, reloading ${req.body.projectName}`);
232923
+ this.watcher.on("change", async (path11) => {
232924
+ logger.info(`Detected change on ${path11}, reloading ${req.body.projectName}`);
232489
232925
  await reloadProject();
232490
232926
  });
232491
232927
  res.json();
@@ -235576,25 +236012,25 @@ async function getModelForQuery(projectStore, projectName, packageName, modelPat
235576
236012
  }
235577
236013
  }
235578
236014
  function buildMalloyUri(components, fragment) {
235579
- let path10 = "/project/";
236015
+ let path11 = "/project/";
235580
236016
  if (components.project) {
235581
- path10 += encodeURIComponent(components.project);
236017
+ path11 += encodeURIComponent(components.project);
235582
236018
  } else {
235583
- path10 += "home";
236019
+ path11 += "home";
235584
236020
  }
235585
236021
  if (components.package) {
235586
- path10 += "/package/" + encodeURIComponent(components.package);
236022
+ path11 += "/package/" + encodeURIComponent(components.package);
235587
236023
  }
235588
236024
  if (components.resourceType) {
235589
- path10 += "/" + components.resourceType;
236025
+ path11 += "/" + components.resourceType;
235590
236026
  if (components.resourceName) {
235591
- path10 += "/" + encodeURIComponent(components.resourceName);
236027
+ path11 += "/" + encodeURIComponent(components.resourceName);
235592
236028
  if (components.subResourceType && components.subResourceName) {
235593
- path10 += "/" + components.subResourceType + "/" + encodeURIComponent(components.subResourceName);
236029
+ path11 += "/" + components.subResourceType + "/" + encodeURIComponent(components.subResourceName);
235594
236030
  }
235595
236031
  }
235596
236032
  }
235597
- let uriString = "malloy:/" + path10;
236033
+ let uriString = "malloy:/" + path11;
235598
236034
  if (fragment) {
235599
236035
  uriString += "#" + fragment;
235600
236036
  }
@@ -236530,8 +236966,8 @@ import {
236530
236966
  } from "@malloydata/malloy";
236531
236967
 
236532
236968
  // src/service/quoting.ts
236533
- function quoteTablePath(path10, dialect) {
236534
- return path10.split(".").map((seg) => dialect.quoteTablePath(seg)).join(".");
236969
+ function quoteTablePath(path11, dialect) {
236970
+ return path11.split(".").map((seg) => dialect.quoteTablePath(seg)).join(".");
236535
236971
  }
236536
236972
  function splitTablePath(tableName) {
236537
236973
  const lastDot = tableName.lastIndexOf(".");
@@ -236695,6 +237131,23 @@ var STAGING_BUILD_ID_LEN = 12;
236695
237131
  function stagingSuffix(buildId) {
236696
237132
  return `_${buildId.substring(0, STAGING_BUILD_ID_LEN)}`;
236697
237133
  }
237134
+ async function resolvePackageConnections(pkg, names) {
237135
+ const map2 = new Map;
237136
+ const seen = new Set;
237137
+ for (const name of names) {
237138
+ if (!name || seen.has(name))
237139
+ continue;
237140
+ seen.add(name);
237141
+ try {
237142
+ map2.set(name, await pkg.getMalloyConnection(name));
237143
+ } catch (err) {
237144
+ logger.warn(`Failed to resolve connection ${name}`, {
237145
+ error: err instanceof Error ? err.message : String(err)
237146
+ });
237147
+ }
237148
+ }
237149
+ return map2;
237150
+ }
236698
237151
  function manifestTableKey(connectionName, tableName) {
236699
237152
  return `${connectionName}::${tableName}`;
236700
237153
  }
@@ -236875,8 +237328,8 @@ class MaterializationService {
236875
237328
  }
236876
237329
  const project = await this.projectStore.getProject(projectName, false);
236877
237330
  const pkg = await project.getPackage(packageName, false);
236878
- const connections = pkg.getConnections();
236879
237331
  const entries = await this.manifestService.listEntries(projectId, packageName);
237332
+ const connections = await resolvePackageConnections(pkg, entries.map((e) => e.connectionName));
236880
237333
  return dropManifestEntries(entries, {
236881
237334
  connections,
236882
237335
  manifestService: this.manifestService,
@@ -236897,12 +237350,11 @@ class MaterializationService {
236897
237350
  manifest.loadText(JSON.stringify(existingManifest));
236898
237351
  const existingEntries = await this.manifestService.listEntries(projectId, packageName);
236899
237352
  const knownMaterializedTables = new Set(existingEntries.map((e) => manifestTableKey(e.connectionName, e.tableName)));
236900
- const { graphs, sources, connectionDigests } = await this.compilePackageBuildPlan(pkg, signal);
237353
+ const { graphs, sources, connectionDigests, connections } = await this.compilePackageBuildPlan(pkg, signal);
236901
237354
  if (graphs.length === 0) {
236902
237355
  logger.info("No persist sources to build");
236903
237356
  return { sourcesBuilt: 0, sourcesSkipped: 0 };
236904
237357
  }
236905
- const connections = pkg.getConnections();
236906
237358
  let sourcesBuilt = 0;
236907
237359
  let sourcesSkipped = 0;
236908
237360
  const sourceResults = [];
@@ -236951,7 +237403,7 @@ class MaterializationService {
236951
237403
  for (const modelPath of modelPaths) {
236952
237404
  if (signal.aborted)
236953
237405
  throw new Error("Build cancelled");
236954
- const { runtime, modelURL, importBaseURL } = await Model.getModelRuntime(pkg.getPackagePath(), modelPath, pkg.getConnections());
237406
+ const { runtime, modelURL, importBaseURL } = await Model.getModelRuntime(pkg.getPackagePath(), modelPath, pkg.getMalloyConfig());
236955
237407
  const modelMaterializer = runtime.loadModel(modelURL, {
236956
237408
  importBaseURL
236957
237409
  });
@@ -236994,7 +237446,7 @@ class MaterializationService {
236994
237446
  }
236995
237447
  tableOwners.set(key, sourceID);
236996
237448
  }
236997
- const connections = pkg.getConnections();
237449
+ const connections = await resolvePackageConnections(pkg, allGraphs.map((g) => g.connectionName));
236998
237450
  const connectionDigests = {};
236999
237451
  for (const graph of allGraphs) {
237000
237452
  const conn = connections.get(graph.connectionName);
@@ -237002,7 +237454,12 @@ class MaterializationService {
237002
237454
  connectionDigests[graph.connectionName] = await conn.getDigest();
237003
237455
  }
237004
237456
  }
237005
- return { graphs: allGraphs, sources: allSources, connectionDigests };
237457
+ return {
237458
+ graphs: allGraphs,
237459
+ sources: allSources,
237460
+ connectionDigests,
237461
+ connections
237462
+ };
237006
237463
  }
237007
237464
  async buildOneSource(persistSource, manifest, connection, connectionDigests, forceRefresh, projectId, packageName, knownMaterializedTables) {
237008
237465
  const buildIdSQL = persistSource.getSQL();
@@ -237155,9 +237612,9 @@ var MCP_PORT = Number(process.env.MCP_PORT || 4040);
237155
237612
  var MCP_ENDPOINT = "/mcp";
237156
237613
  var SHUTDOWN_DRAIN_DURATION_SECONDS = Number(process.env.SHUTDOWN_DRAIN_DURATION_SECONDS || 0);
237157
237614
  var SHUTDOWN_GRACEFUL_CLOSE_TIMEOUT_SECONDS = Number(process.env.SHUTDOWN_GRACEFUL_CLOSE_TIMEOUT_SECONDS || 0);
237158
- var __filename_esm = fileURLToPath3(import.meta.url);
237159
- var ROOT = path10.join(path10.dirname(__filename_esm), "app");
237160
- var SERVER_ROOT = path10.resolve(process.cwd(), process.env.SERVER_ROOT || ".");
237615
+ var __filename_esm = fileURLToPath2(import.meta.url);
237616
+ var ROOT = path11.join(path11.dirname(__filename_esm), "app");
237617
+ var SERVER_ROOT = path11.resolve(process.cwd(), process.env.SERVER_ROOT || ".");
237161
237618
  var API_PREFIX2 = "/api/v0";
237162
237619
  var isDevelopment = process.env["NODE_ENV"] === "development";
237163
237620
  var app = import_express.default();
@@ -237238,14 +237695,14 @@ mcpApp.all(MCP_ENDPOINT, async (req, res) => {
237238
237695
  });
237239
237696
  if (!isDevelopment) {
237240
237697
  app.use("/", import_express.default.static(ROOT));
237241
- app.use("/api-doc.html", import_express.default.static(path10.join(ROOT, "api-doc.html")));
237698
+ app.use("/api-doc.html", import_express.default.static(path11.join(ROOT, "api-doc.html")));
237242
237699
  } else {
237243
237700
  app.use(`${API_PREFIX2}`, loggerMiddleware);
237244
237701
  app.use(import_http_proxy_middleware.createProxyMiddleware({
237245
237702
  target: "http://localhost:5173",
237246
237703
  changeOrigin: true,
237247
237704
  ws: true,
237248
- pathFilter: (path11) => !path11.startsWith("/api/") && !path11.startsWith("/metrics") && !path11.startsWith("/health")
237705
+ pathFilter: (path12) => !path12.startsWith("/api/") && !path12.startsWith("/metrics") && !path12.startsWith("/health")
237249
237706
  }));
237250
237707
  }
237251
237708
  var setVersionIdError = (res) => {
@@ -237418,6 +237875,33 @@ app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/schema
237418
237875
  res.status(status).json(json);
237419
237876
  }
237420
237877
  });
237878
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/schemas`, async (req, res) => {
237879
+ try {
237880
+ res.status(200).json(await connectionController.listSchemas(req.params.projectName, req.params.connectionName, req.params.packageName));
237881
+ } catch (error) {
237882
+ logger.error(error);
237883
+ const { json, status } = internalErrorToHttpError(error);
237884
+ res.status(status).json(json);
237885
+ }
237886
+ });
237887
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/schemas/:schemaName/tables`, async (req, res) => {
237888
+ try {
237889
+ res.status(200).json(await connectionController.listTables(req.params.projectName, req.params.connectionName, req.params.schemaName, normalizeQueryArray(req.query.tableNames), req.params.packageName));
237890
+ } catch (error) {
237891
+ logger.error(error);
237892
+ const { json, status } = internalErrorToHttpError(error);
237893
+ res.status(status).json(json);
237894
+ }
237895
+ });
237896
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/schemas/:schemaName/tables/:tablePath`, async (req, res) => {
237897
+ try {
237898
+ res.status(200).json(await connectionController.getTable(req.params.projectName, req.params.connectionName, req.params.schemaName, req.params.tablePath, req.params.packageName));
237899
+ } catch (error) {
237900
+ logger.error(error);
237901
+ const { json, status } = internalErrorToHttpError(error);
237902
+ res.status(status).json(json);
237903
+ }
237904
+ });
237421
237905
  app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlSource`, async (req, res) => {
237422
237906
  try {
237423
237907
  res.status(200).json(await connectionController.getConnectionSqlSource(req.params.projectName, req.params.connectionName, req.query.sqlStatement));
@@ -237436,6 +237920,24 @@ app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlSo
237436
237920
  res.status(status).json(json);
237437
237921
  }
237438
237922
  });
237923
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlSource`, async (req, res) => {
237924
+ try {
237925
+ res.status(200).json(await connectionController.getConnectionSqlSource(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.params.packageName));
237926
+ } catch (error) {
237927
+ logger.error(error);
237928
+ const { json, status } = internalErrorToHttpError(error);
237929
+ res.status(status).json(json);
237930
+ }
237931
+ });
237932
+ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlSource`, async (req, res) => {
237933
+ try {
237934
+ res.status(200).json(await connectionController.getConnectionSqlSource(req.params.projectName, req.params.connectionName, req.body.sqlStatement, req.params.packageName));
237935
+ } catch (error) {
237936
+ logger.error(error);
237937
+ const { json, status } = internalErrorToHttpError(error);
237938
+ res.status(status).json(json);
237939
+ }
237940
+ });
237439
237941
  app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/queryData`, async (req, res) => {
237440
237942
  try {
237441
237943
  res.status(200).json(await connectionController.getConnectionQueryData(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.query.options));
@@ -237445,6 +237947,15 @@ app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/queryD
237445
237947
  res.status(status).json(json);
237446
237948
  }
237447
237949
  });
237950
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/queryData`, async (req, res) => {
237951
+ try {
237952
+ res.status(200).json(await connectionController.getConnectionQueryData(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.query.options, req.params.packageName));
237953
+ } catch (error) {
237954
+ logger.error(error);
237955
+ const { json, status } = internalErrorToHttpError(error);
237956
+ res.status(status).json(json);
237957
+ }
237958
+ });
237448
237959
  app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlQuery`, async (req, res) => {
237449
237960
  try {
237450
237961
  let options;
@@ -237460,6 +237971,21 @@ app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlQu
237460
237971
  res.status(status).json(json);
237461
237972
  }
237462
237973
  });
237974
+ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlQuery`, async (req, res) => {
237975
+ try {
237976
+ let options;
237977
+ if (req.body?.options) {
237978
+ options = req.body.options;
237979
+ } else {
237980
+ options = req.query.options;
237981
+ }
237982
+ res.status(200).json(await connectionController.getConnectionQueryData(req.params.projectName, req.params.connectionName, req.body.sqlStatement, options, req.params.packageName));
237983
+ } catch (error) {
237984
+ logger.error(error);
237985
+ const { json, status } = internalErrorToHttpError(error);
237986
+ res.status(status).json(json);
237987
+ }
237988
+ });
237463
237989
  app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/temporaryTable`, async (req, res) => {
237464
237990
  try {
237465
237991
  res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.query.sqlStatement));
@@ -237469,6 +237995,15 @@ app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/tempor
237469
237995
  res.status(status).json(json);
237470
237996
  }
237471
237997
  });
237998
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/temporaryTable`, async (req, res) => {
237999
+ try {
238000
+ res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.params.packageName));
238001
+ } catch (error) {
238002
+ logger.error(error);
238003
+ const { json, status } = internalErrorToHttpError(error);
238004
+ res.status(status).json(json);
238005
+ }
238006
+ });
237472
238007
  app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlTemporaryTable`, async (req, res) => {
237473
238008
  try {
237474
238009
  res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.body.sqlStatement));
@@ -237478,6 +238013,15 @@ app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlTe
237478
238013
  res.status(status).json(json);
237479
238014
  }
237480
238015
  });
238016
+ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlTemporaryTable`, async (req, res) => {
238017
+ try {
238018
+ res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.body.sqlStatement, req.params.packageName));
238019
+ } catch (error) {
238020
+ logger.error(error);
238021
+ const { json, status } = internalErrorToHttpError(error);
238022
+ res.status(status).json(json);
238023
+ }
238024
+ });
237481
238025
  app.get(`${API_PREFIX2}/projects/:projectName/packages`, async (req, res) => {
237482
238026
  if (req.query.versionId) {
237483
238027
  setVersionIdError(res);
@@ -237747,7 +238291,7 @@ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/manifest`,
237747
238291
  }
237748
238292
  });
237749
238293
  if (!isDevelopment) {
237750
- app.get("*", (_req, res) => res.sendFile(path10.resolve(ROOT, "index.html")));
238294
+ app.get("*", (_req, res) => res.sendFile(path11.resolve(ROOT, "index.html")));
237751
238295
  }
237752
238296
  app.use((err, _req, res, _next) => {
237753
238297
  logger.error("Unhandled error:", err);