@malloy-publisher/server 0.0.192 → 0.0.193

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 (34) hide show
  1. package/dist/app/api-doc.yaml +522 -1
  2. package/dist/app/assets/{HomePage-H1OH-VW5.js → HomePage-Di9MU3lS.js} +1 -1
  3. package/dist/app/assets/{MainPage-GL06aMke.js → MainPage-yZQo2HSL.js} +1 -1
  4. package/dist/app/assets/{ModelPage-Crau5hgZ.js → ModelPage-Dx2mHWeT.js} +1 -1
  5. package/dist/app/assets/{PackagePage-CbubRhgE.js → PackagePage-Q386Py9t.js} +1 -1
  6. package/dist/app/assets/{ProjectPage-DUlJkYJ4.js → ProjectPage-WR7wPQB-.js} +1 -1
  7. package/dist/app/assets/{RouteError-DrNXNihc.js → RouteError-stRGU4aW.js} +1 -1
  8. package/dist/app/assets/{WorkbookPage-CBBv7n5U.js → WorkbookPage-D3iX0djH.js} +1 -1
  9. package/dist/app/assets/{core-Dzx75uJR.es-DwnFZnyO.js → core-QH4HZQVz.es-CqlQLZdl.js} +1 -1
  10. package/dist/app/assets/{index-d5rvmoZ7.js → index-CVHzPJwN.js} +119 -119
  11. package/dist/app/assets/{index-CzjyS9cx.js → index-DavAceYD.js} +50 -50
  12. package/dist/app/assets/{index-HHdhLUpv.js → index-Y3Y-VRna.js} +1 -1
  13. package/dist/app/assets/{index.umd-CetYIBQY.js → index.umd-Bp8OIhfV.js} +46 -46
  14. package/dist/app/index.html +1 -1
  15. package/dist/server.mjs +1389 -984
  16. package/package.json +10 -10
  17. package/src/controller/connection.controller.ts +102 -27
  18. package/src/dto/connection.dto.spec.ts +4 -0
  19. package/src/dto/connection.dto.ts +46 -2
  20. package/src/server.ts +201 -2
  21. package/src/service/connection.spec.ts +250 -4
  22. package/src/service/connection.ts +326 -473
  23. package/src/service/connection_config.ts +514 -0
  24. package/src/service/connection_service.spec.ts +50 -0
  25. package/src/service/connection_service.ts +125 -32
  26. package/src/service/materialization_service.spec.ts +18 -12
  27. package/src/service/materialization_service.ts +54 -7
  28. package/src/service/model.ts +24 -27
  29. package/src/service/package.spec.ts +125 -1
  30. package/src/service/package.ts +86 -44
  31. package/src/service/project.ts +172 -94
  32. package/src/service/project_store.spec.ts +72 -0
  33. package/src/service/project_store.ts +98 -81
  34. package/tests/unit/duckdb/attached_databases.test.ts +1 -19
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,20 @@ 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 {
217109
+ contextOverlay,
217110
+ MalloyConfig
217111
+ } from "@malloydata/malloy";
217104
217112
 
217105
217113
  // ../../node_modules/axios/lib/helpers/bind.js
217106
217114
  function bind(fn, thisArg) {
@@ -220369,90 +220377,354 @@ var {
220369
220377
 
220370
220378
  // src/service/connection.ts
220371
220379
  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 };
220380
+ import path2 from "path";
220376
220381
 
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;
220382
+ // src/service/connection_config.ts
220383
+ import path from "path";
220384
+ var PUBLISHER_DUCKDB_API_FIELDS = new Set(["attachedDatabases"]);
220385
+ function normalizeSnowflakePrivateKey(privateKey) {
220386
+ let privateKeyContent = privateKey.trim();
220387
+ if (!privateKeyContent.includes(`
220388
+ `)) {
220389
+ const keyPatterns = [
220390
+ {
220391
+ beginRegex: /-----BEGIN\s+ENCRYPTED\s+PRIVATE\s+KEY-----/i,
220392
+ endRegex: /-----END\s+ENCRYPTED\s+PRIVATE\s+KEY-----/i,
220393
+ beginMarker: "-----BEGIN ENCRYPTED PRIVATE KEY-----",
220394
+ endMarker: "-----END ENCRYPTED PRIVATE KEY-----"
220395
+ },
220396
+ {
220397
+ beginRegex: /-----BEGIN\s+PRIVATE\s+KEY-----/i,
220398
+ endRegex: /-----END\s+PRIVATE\s+KEY-----/i,
220399
+ beginMarker: "-----BEGIN PRIVATE KEY-----",
220400
+ endMarker: "-----END PRIVATE KEY-----"
220401
+ }
220402
+ ];
220403
+ for (const pattern of keyPatterns) {
220404
+ const beginMatch = privateKeyContent.match(pattern.beginRegex);
220405
+ const endMatch = privateKeyContent.match(pattern.endRegex);
220406
+ if (beginMatch && endMatch) {
220407
+ const beginPos = beginMatch.index + beginMatch[0].length;
220408
+ const endPos = endMatch.index;
220409
+ const keyData = privateKeyContent.substring(beginPos, endPos).replace(/\s+/g, "");
220410
+ const lines = [];
220411
+ for (let i = 0;i < keyData.length; i += 64) {
220412
+ lines.push(keyData.slice(i, i + 64));
220413
+ }
220414
+ privateKeyContent = `${pattern.beginMarker}
220415
+ ${lines.join(`
220416
+ `)}
220417
+ ${pattern.endMarker}
220418
+ `;
220419
+ break;
220420
+ }
220421
+ }
220422
+ } else if (!privateKeyContent.endsWith(`
220423
+ `)) {
220424
+ privateKeyContent += `
220425
+ `;
220385
220426
  }
220386
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
220427
+ return privateKeyContent;
220387
220428
  }
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));
220429
+ function validateDuckdbApiSurface(connection) {
220430
+ if (connection.type !== "duckdb" || !connection.duckdbConnection)
220431
+ return;
220432
+ const unsupportedFields = Object.keys(connection.duckdbConnection).filter((field) => !PUBLISHER_DUCKDB_API_FIELDS.has(field) && connection.duckdbConnection[field] !== undefined);
220433
+ if (unsupportedFields.length > 0) {
220434
+ throw new Error(`Unsupported DuckDB connection field(s): ${unsupportedFields.join(", ")}. Publisher only supports attachedDatabases for project-authored DuckDB connections.`);
220435
+ }
220393
220436
  }
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();
220437
+ function cloneApiConnection(connection) {
220438
+ return { ...connection };
220396
220439
  }
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();
220440
+ function getStaticConnectionAttributes(type) {
220441
+ switch (type) {
220442
+ case "postgres":
220443
+ return {
220444
+ dialectName: "postgres",
220445
+ isPool: false,
220446
+ canPersist: true,
220447
+ canStream: true
220448
+ };
220449
+ case "bigquery":
220450
+ return {
220451
+ dialectName: "standardsql",
220452
+ isPool: false,
220453
+ canPersist: true,
220454
+ canStream: true
220455
+ };
220456
+ case "snowflake":
220457
+ return {
220458
+ dialectName: "snowflake",
220459
+ isPool: true,
220460
+ canPersist: true,
220461
+ canStream: true
220462
+ };
220463
+ case "trino":
220464
+ return {
220465
+ dialectName: "trino",
220466
+ isPool: false,
220467
+ canPersist: true,
220468
+ canStream: false
220469
+ };
220470
+ case "mysql":
220471
+ return {
220472
+ dialectName: "mysql",
220473
+ isPool: false,
220474
+ canPersist: true,
220475
+ canStream: false
220476
+ };
220477
+ case "duckdb":
220478
+ case "motherduck":
220479
+ case "ducklake":
220480
+ return {
220481
+ dialectName: "duckdb",
220482
+ isPool: false,
220483
+ canPersist: true,
220484
+ canStream: true
220485
+ };
220486
+ default:
220487
+ return;
220402
220488
  }
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");
220489
+ }
220490
+ function parseServiceAccountKey(json) {
220491
+ if (!json)
220492
+ return;
220493
+ const keyData = JSON.parse(json);
220494
+ const requiredFields = ["type", "project_id", "private_key", "client_email"];
220495
+ for (const field of requiredFields) {
220496
+ if (!keyData[field]) {
220497
+ throw new Error(`Invalid service account key: missing "${field}" field`);
220498
+ }
220499
+ }
220500
+ if (keyData.type !== "service_account") {
220501
+ throw new Error('Invalid service account key: incorrect "type" field');
220502
+ }
220503
+ return keyData;
220504
+ }
220505
+ function buildPostgresConnectionString(config) {
220506
+ if (config.connectionString || !process.env.PGSSLMODE) {
220507
+ return config.connectionString;
220407
220508
  }
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`);
220509
+ const params = new URLSearchParams;
220510
+ params.set("sslmode", process.env.PGSSLMODE);
220511
+ const auth = config.userName && config.password ? `${encodeURIComponent(config.userName)}:${encodeURIComponent(config.password)}@` : config.userName ? `${encodeURIComponent(config.userName)}@` : "";
220512
+ const host = config.host ?? "localhost";
220513
+ const port = config.port ? `:${config.port}` : "";
220514
+ const database = config.databaseName ? `/${encodeURIComponent(config.databaseName)}` : "";
220515
+ return `postgresql://${auth}${host}${port}${database}?${params.toString()}`;
220516
+ }
220517
+ function buildDuckdbEntry(name, projectPath, databaseFilename = `${name}.duckdb`) {
220518
+ return {
220519
+ is: "duckdb",
220520
+ databasePath: path.join(projectPath, databaseFilename)
220521
+ };
220522
+ }
220523
+ function validateConnectionShape(connection) {
220524
+ switch (connection.type) {
220525
+ case "postgres":
220526
+ case "mysql":
220527
+ case "bigquery":
220528
+ break;
220529
+ case "duckdb":
220530
+ if (!connection.duckdbConnection) {
220531
+ throw new Error("DuckDB connection configuration is missing.");
220532
+ }
220533
+ break;
220534
+ case "motherduck":
220535
+ if (!connection.motherduckConnection) {
220536
+ throw new Error("MotherDuck connection configuration is missing.");
220537
+ }
220538
+ if (!connection.motherduckConnection.accessToken) {
220539
+ throw new Error("MotherDuck access token is required.");
220540
+ }
220541
+ break;
220542
+ case "trino":
220543
+ if (!connection.trinoConnection) {
220544
+ throw new Error("Trino connection configuration is missing.");
220545
+ }
220546
+ break;
220547
+ case "snowflake": {
220548
+ const snowflakeConnection = connection.snowflakeConnection;
220549
+ if (!snowflakeConnection) {
220550
+ throw new Error("Snowflake connection configuration is missing.");
220551
+ }
220552
+ if (!snowflakeConnection.account) {
220553
+ throw new Error("Snowflake account is required.");
220554
+ }
220555
+ if (!snowflakeConnection.username) {
220556
+ throw new Error("Snowflake username is required.");
220557
+ }
220558
+ if (!snowflakeConnection.password && !snowflakeConnection.privateKey) {
220559
+ throw new Error("Snowflake password or private key or private key path is required.");
220560
+ }
220561
+ if (!snowflakeConnection.warehouse) {
220562
+ throw new Error("Snowflake warehouse is required.");
220563
+ }
220564
+ break;
220414
220565
  }
220415
- for (let i = 0;i < 16; ++i) {
220416
- buf[offset + i] = rnds[i];
220566
+ }
220567
+ }
220568
+ function assembleProjectConnections(connections = [], projectPath = "") {
220569
+ const pojo = { connections: {} };
220570
+ const metadata = new Map;
220571
+ const apiConnections = [];
220572
+ const processedConnections = new Set;
220573
+ for (const connection of connections) {
220574
+ if (!connection.name) {
220575
+ throw new Error("Invalid connection configuration. No name.");
220417
220576
  }
220418
- return buf;
220577
+ if (processedConnections.has(connection.name)) {
220578
+ continue;
220579
+ }
220580
+ if (connection.name === "duckdb") {
220581
+ throw new Error("DuckDB connection name cannot be 'duckdb'; it is reserved for Publisher package sandboxes.");
220582
+ }
220583
+ processedConnections.add(connection.name);
220584
+ validateDuckdbApiSurface(connection);
220585
+ validateConnectionShape(connection);
220586
+ const apiConnection = cloneApiConnection(connection);
220587
+ apiConnection.attributes = getStaticConnectionAttributes(connection.type);
220588
+ const attachedDatabases = connection.duckdbConnection?.attachedDatabases ?? [];
220589
+ const isDuckLake = connection.type === "ducklake";
220590
+ const isDuckdb = connection.type === "duckdb";
220591
+ const databasePath = isDuckLake ? path.join(projectPath, `${connection.name}_ducklake.duckdb`) : isDuckdb ? path.join(projectPath, `${connection.name}.duckdb`) : undefined;
220592
+ metadata.set(connection.name, {
220593
+ apiConnection,
220594
+ attachedDatabases,
220595
+ hasAzureAttachment: attachedDatabases.some((database) => database.type === "azure"),
220596
+ hasSnowflakePrivateKey: connection.type === "snowflake" && !!connection.snowflakeConnection?.privateKey,
220597
+ isDuckLake,
220598
+ databasePath,
220599
+ workingDirectory: projectPath
220600
+ });
220601
+ switch (connection.type) {
220602
+ case "postgres": {
220603
+ const postgresConnection = connection.postgresConnection;
220604
+ pojo.connections[connection.name] = {
220605
+ is: "postgres",
220606
+ host: postgresConnection?.host,
220607
+ port: postgresConnection?.port,
220608
+ username: postgresConnection?.userName,
220609
+ password: postgresConnection?.password,
220610
+ databaseName: postgresConnection?.databaseName,
220611
+ connectionString: postgresConnection ? buildPostgresConnectionString(postgresConnection) : undefined
220612
+ };
220613
+ break;
220614
+ }
220615
+ case "mysql": {
220616
+ pojo.connections[connection.name] = {
220617
+ is: "mysql",
220618
+ host: connection.mysqlConnection?.host,
220619
+ port: connection.mysqlConnection?.port,
220620
+ user: connection.mysqlConnection?.user,
220621
+ password: connection.mysqlConnection?.password,
220622
+ database: connection.mysqlConnection?.database
220623
+ };
220624
+ break;
220625
+ }
220626
+ case "bigquery": {
220627
+ const serviceAccountKey = parseServiceAccountKey(connection.bigqueryConnection?.serviceAccountKeyJson);
220628
+ pojo.connections[connection.name] = {
220629
+ is: "bigquery",
220630
+ projectId: connection.bigqueryConnection?.defaultProjectId ?? serviceAccountKey?.project_id,
220631
+ serviceAccountKey,
220632
+ location: connection.bigqueryConnection?.location,
220633
+ maximumBytesBilled: connection.bigqueryConnection?.maximumBytesBilled,
220634
+ timeoutMs: connection.bigqueryConnection?.queryTimeoutMilliseconds,
220635
+ billingProjectId: connection.bigqueryConnection?.billingProjectId
220636
+ };
220637
+ break;
220638
+ }
220639
+ case "snowflake": {
220640
+ pojo.connections[connection.name] = {
220641
+ is: "snowflake",
220642
+ account: connection.snowflakeConnection?.account,
220643
+ username: connection.snowflakeConnection?.username,
220644
+ password: connection.snowflakeConnection?.password,
220645
+ privateKey: connection.snowflakeConnection?.privateKey ? normalizeSnowflakePrivateKey(connection.snowflakeConnection.privateKey) : undefined,
220646
+ privateKeyPass: connection.snowflakeConnection?.privateKeyPass,
220647
+ warehouse: connection.snowflakeConnection?.warehouse,
220648
+ database: connection.snowflakeConnection?.database,
220649
+ schema: connection.snowflakeConnection?.schema,
220650
+ role: connection.snowflakeConnection?.role,
220651
+ timeoutMs: connection.snowflakeConnection?.responseTimeoutMilliseconds,
220652
+ poolMin: 1,
220653
+ poolMax: 20
220654
+ };
220655
+ break;
220656
+ }
220657
+ case "trino": {
220658
+ pojo.connections[connection.name] = {
220659
+ is: "trino",
220660
+ ...validateAndBuildTrinoCoreConfig(connection.trinoConnection)
220661
+ };
220662
+ break;
220663
+ }
220664
+ case "duckdb": {
220665
+ if (attachedDatabases.some((database) => database.name === connection.name)) {
220666
+ throw new Error(`DuckDB attached database names cannot conflict with connection name ${connection.name}`);
220667
+ }
220668
+ pojo.connections[connection.name] = buildDuckdbEntry(connection.name, projectPath, `${connection.name}.duckdb`);
220669
+ break;
220670
+ }
220671
+ case "motherduck": {
220672
+ if (!connection.motherduckConnection?.accessToken) {
220673
+ throw new Error("MotherDuck access token is required.");
220674
+ }
220675
+ pojo.connections[connection.name] = {
220676
+ is: "duckdb",
220677
+ databasePath: connection.motherduckConnection.database ? `md:${connection.motherduckConnection.database}?attach_mode=single` : "md:",
220678
+ motherDuckToken: connection.motherduckConnection.accessToken
220679
+ };
220680
+ break;
220681
+ }
220682
+ case "ducklake": {
220683
+ if (!connection.ducklakeConnection) {
220684
+ throw new Error("DuckLake connection configuration is missing.");
220685
+ }
220686
+ if (!connection.ducklakeConnection.catalog?.postgresConnection) {
220687
+ throw new Error(`PostgreSQL connection configuration is required for DuckLake catalog: ${connection.name}`);
220688
+ }
220689
+ pojo.connections[connection.name] = buildDuckdbEntry(connection.name, projectPath, `${connection.name}_ducklake.duckdb`);
220690
+ break;
220691
+ }
220692
+ default: {
220693
+ throw new Error(`Unsupported connection type: ${connection.type}`);
220694
+ }
220695
+ }
220696
+ apiConnections.push(apiConnection);
220419
220697
  }
220420
- return unsafeStringify(rnds);
220698
+ return { pojo, metadata, apiConnections };
220421
220699
  }
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}`;
220700
+ function validateAndBuildTrinoCoreConfig(trinoConfig) {
220701
+ if (!trinoConfig) {
220702
+ return {};
220427
220703
  }
220704
+ const server = trinoConfig.server && trinoConfig.port ? trinoConfig.server.includes(trinoConfig.port.toString()) ? trinoConfig.server : `${trinoConfig.server}:${trinoConfig.port}` : trinoConfig.server;
220428
220705
  const baseConfig = {
220429
- server: trinoConfig.server,
220706
+ server,
220430
220707
  port: trinoConfig.port,
220431
220708
  catalog: trinoConfig.catalog,
220432
220709
  schema: trinoConfig.schema,
220433
220710
  user: trinoConfig.user
220434
220711
  };
220435
220712
  if (trinoConfig.peakaKey) {
220436
- baseConfig.extraConfig = {
220437
- extraCredential: {
220438
- peakaKey: trinoConfig.peakaKey
220439
- }
220713
+ baseConfig.extraCredential = {
220714
+ peakaKey: trinoConfig.peakaKey
220440
220715
  };
220441
- delete baseConfig.password;
220442
- delete baseConfig.catalog;
220443
- delete baseConfig.schema;
220444
- } else if (trinoConfig.server?.startsWith("https://") && trinoConfig.password) {
220716
+ return baseConfig;
220717
+ }
220718
+ if (server?.startsWith("https://") && trinoConfig.password) {
220445
220719
  baseConfig.password = trinoConfig.password;
220446
220720
  }
220447
- if (trinoConfig.server?.startsWith("http://")) {
220448
- delete baseConfig.password;
220449
- return baseConfig;
220450
- } else if (trinoConfig.server?.startsWith("https://")) {
220721
+ if (server?.startsWith("http://") || server?.startsWith("https://")) {
220451
220722
  return baseConfig;
220452
- } else {
220453
- throw new Error(`Invalid Trino connection: expected "http://server:port" or "https://server:port".`);
220454
220723
  }
220724
+ throw new Error(`Invalid Trino connection: expected "http://server:port" or "https://server:port".`);
220455
220725
  }
220726
+
220727
+ // src/service/connection.ts
220456
220728
  async function installAndLoadExtension(connection, extensionName, fromCommunity = false) {
220457
220729
  try {
220458
220730
  const installCommand = fromCommunity ? `FORCE INSTALL '${extensionName}' FROM community;` : `INSTALL ${extensionName};`;
@@ -220488,52 +220760,6 @@ function handleAlreadyAttachedError(error, dbName) {
220488
220760
  throw error;
220489
220761
  }
220490
220762
  }
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
220763
  async function attachBigQuery(connection, attachedDb) {
220538
220764
  if (!attachedDb.bigqueryConnection) {
220539
220765
  throw new Error(`BigQuery connection configuration missing for: ${attachedDb.name}`);
@@ -220926,8 +221152,8 @@ function buildAzureFileUrl(azureConn, blobName) {
220926
221152
 
220927
221153
  class AzureDuckDBConnection extends DuckDBConnection {
220928
221154
  azureDatabases;
220929
- constructor(connectionName, databasePath, workingDirectory, azureDatabases) {
220930
- super(connectionName, databasePath, workingDirectory);
221155
+ constructor(options, azureDatabases) {
221156
+ super(options);
220931
221157
  this.azureDatabases = azureDatabases;
220932
221158
  }
220933
221159
  async fetchTableSchema(tableKey, tablePath) {
@@ -220959,12 +221185,12 @@ class AzureDuckDBConnection extends DuckDBConnection {
220959
221185
 
220960
221186
  class DuckLakeConnection extends DuckDBConnection {
220961
221187
  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}`);
221188
+ constructor(options) {
221189
+ super(options);
221190
+ if (!options.databasePath?.endsWith("_ducklake.duckdb")) {
221191
+ throw new Error(`DuckLakeConnection should only be used for DuckLake connections. ` + `Expected database path ending with '_ducklake.duckdb', got: ${options.databasePath}`);
220966
221192
  }
220967
- this.connectionName = connectionName;
221193
+ this.connectionName = options.name;
220968
221194
  }
220969
221195
  async fetchTableSchema(tableKey, tablePath) {
220970
221196
  const parts = tablePath.split(".");
@@ -220989,7 +221215,7 @@ class DuckLakeConnection extends DuckDBConnection {
220989
221215
  }
220990
221216
  }
220991
221217
  async function deleteDuckLakeConnectionFile(connectionName, projectPath) {
220992
- const ducklakePath = path.join(projectPath, `${connectionName}_ducklake.duckdb`);
221218
+ const ducklakePath = path2.join(projectPath, `${connectionName}_ducklake.duckdb`);
220993
221219
  try {
220994
221220
  await fs.access(ducklakePath);
220995
221221
  await fs.rm(ducklakePath);
@@ -221002,215 +221228,153 @@ async function deleteDuckLakeConnectionFile(connectionName, projectPath) {
221002
221228
  }
221003
221229
  }
221004
221230
  }
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.";
221231
+ function entryToDuckDBOptions(name, entry, workingDirectory) {
221232
+ const { is: _is, ...rest } = entry;
221233
+ if (workingDirectory !== undefined) {
221234
+ rest.workingDirectory = workingDirectory;
221235
+ }
221236
+ return { ...removeUndefined(rest), name };
221237
+ }
221238
+ function removeUndefined(value) {
221239
+ return Object.fromEntries(Object.entries(value).filter(([, fieldValue]) => fieldValue !== undefined));
221240
+ }
221241
+ function buildSnowflakePrivateKeyConnection(metadata) {
221242
+ const name = metadata.apiConnection.name;
221243
+ const snowflake = metadata.apiConnection.snowflakeConnection;
221244
+ if (!snowflake?.privateKey) {
221245
+ throw new Error(`Snowflake private key is required for connection ${name}`);
221246
+ }
221247
+ if (!snowflake.account) {
221248
+ throw new Error(`Snowflake account is required for connection ${name}`);
221249
+ }
221250
+ if (!snowflake.username) {
221251
+ throw new Error(`Snowflake username is required for connection ${name}`);
221252
+ }
221253
+ if (!snowflake.warehouse) {
221254
+ throw new Error(`Snowflake warehouse is required for connection ${name}`);
221255
+ }
221256
+ return new SnowflakeConnection(name, {
221257
+ connOptions: {
221258
+ account: snowflake.account,
221259
+ username: snowflake.username,
221260
+ privateKey: normalizeSnowflakePrivateKey(snowflake.privateKey),
221261
+ authenticator: "SNOWFLAKE_JWT",
221262
+ warehouse: snowflake.warehouse,
221263
+ ...removeUndefined({
221264
+ password: snowflake.password,
221265
+ privateKeyPass: snowflake.privateKeyPass,
221266
+ database: snowflake.database,
221267
+ schema: snowflake.schema,
221268
+ role: snowflake.role
221269
+ })
221270
+ },
221271
+ timeoutMs: snowflake.responseTimeoutMilliseconds,
221272
+ poolOptions: buildPoolOptions({ poolMin: 1, poolMax: 20 })
221273
+ });
221274
+ }
221275
+ function buildDuckLakeConnection(metadata, entry) {
221276
+ return new DuckLakeConnection(entryToDuckDBOptions(metadata.apiConnection.name, entry, metadata.workingDirectory));
221277
+ }
221278
+ function buildAzureDuckDBConnection(metadata, entry) {
221279
+ return new AzureDuckDBConnection(entryToDuckDBOptions(metadata.apiConnection.name, entry, metadata.workingDirectory), metadata.attachedDatabases);
221280
+ }
221281
+ function getMetadataForLookup(metadata, name) {
221282
+ return name ? metadata.get(name) : undefined;
221283
+ }
221284
+ function isDuckDBConnection(connection) {
221285
+ return connection instanceof DuckDBConnection;
221286
+ }
221287
+ function buildProjectMalloyConfig(connections = [], projectPath = "", isUpdateConnectionRequest = false) {
221288
+ const assembled = assembleProjectConnections(connections, projectPath);
221289
+ const duckLakeCache = new Map;
221290
+ const snowflakeJwtCache = new Map;
221291
+ const azureDuckDBCache = new Map;
221292
+ const attachPromises = new WeakMap;
221293
+ const malloyConfig = new MalloyConfig(assembled.pojo, {
221294
+ config: contextOverlay({ rootDirectory: projectPath })
221295
+ });
221296
+ async function attachOnce(connection, metadata) {
221297
+ if (metadata.attachedDatabases.length === 0 || !isDuckDBConnection(connection)) {
221298
+ return;
221018
221299
  }
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;
221300
+ let attachPromise = attachPromises.get(connection);
221301
+ if (!attachPromise) {
221302
+ attachPromise = attachDatabasesToDuckDB(connection, metadata.attachedDatabases);
221303
+ attachPromises.set(connection, attachPromise);
221304
+ }
221305
+ await attachPromise;
221306
+ }
221307
+ malloyConfig.wrapConnections((base) => ({
221308
+ lookupConnection: async (name) => {
221309
+ const metadata = getMetadataForLookup(assembled.metadata, name);
221310
+ if (metadata?.isDuckLake) {
221311
+ let connectionPromise = duckLakeCache.get(name);
221312
+ if (!connectionPromise) {
221313
+ const entry = assembled.pojo.connections[name];
221314
+ connectionPromise = Promise.resolve(buildDuckLakeConnection(metadata, entry));
221315
+ duckLakeCache.set(name, connectionPromise);
221316
+ }
221317
+ const connection2 = await connectionPromise;
221318
+ if (isUpdateConnectionRequest || !await isDatabaseAttached(connection2, name)) {
221319
+ await attachDuckLake(connection2, name, metadata.apiConnection.ducklakeConnection);
221320
+ }
221321
+ return connection2;
221322
+ }
221323
+ if (metadata?.hasSnowflakePrivateKey) {
221324
+ let connectionPromise = snowflakeJwtCache.get(name);
221325
+ if (!connectionPromise) {
221326
+ connectionPromise = Promise.resolve(buildSnowflakePrivateKeyConnection(metadata));
221327
+ snowflakeJwtCache.set(name, connectionPromise);
221328
+ }
221329
+ return connectionPromise;
221330
+ }
221331
+ if (metadata?.hasAzureAttachment) {
221332
+ let connectionPromise = azureDuckDBCache.get(name);
221333
+ if (!connectionPromise) {
221334
+ const entry = assembled.pojo.connections[name];
221335
+ connectionPromise = Promise.resolve(buildAzureDuckDBConnection(metadata, entry));
221336
+ azureDuckDBCache.set(name, connectionPromise);
221337
+ }
221338
+ const connection2 = await connectionPromise;
221339
+ await attachOnce(connection2, metadata);
221340
+ return connection2;
221341
+ }
221342
+ const connection = await base.lookupConnection(name);
221343
+ if (metadata) {
221344
+ await attachOnce(connection, metadata);
221159
221345
  }
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
221346
+ return connection;
221347
+ }
221348
+ }));
221349
+ return {
221350
+ malloyConfig,
221351
+ apiConnections: assembled.apiConnections,
221352
+ releaseConnections: async () => {
221353
+ const wrapperPromises = [
221354
+ ...duckLakeCache.values(),
221355
+ ...snowflakeJwtCache.values(),
221356
+ ...azureDuckDBCache.values()
221357
+ ];
221358
+ const closeResults = await Promise.allSettled([
221359
+ malloyConfig.releaseConnections(),
221360
+ ...wrapperPromises.map(async (promise) => {
221361
+ const connection = await promise;
221362
+ await connection.close();
221363
+ })
221364
+ ]);
221365
+ duckLakeCache.clear();
221366
+ snowflakeJwtCache.clear();
221367
+ azureDuckDBCache.clear();
221368
+ const failures = closeResults.filter((result) => result.status === "rejected");
221369
+ for (const failure of failures) {
221370
+ logger.error("Failed to release project connection", {
221371
+ error: failure.reason
221176
221372
  });
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
221373
  }
221193
- default: {
221194
- throw new Error(`Unsupported connection type: ${connection.type}`);
221374
+ if (failures.length > 0) {
221375
+ throw new AggregateError(failures.map((failure) => failure.reason), "Failed to release one or more project connections");
221195
221376
  }
221196
221377
  }
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
221378
  };
221215
221379
  }
221216
221380
  async function testDuckDBConnection(duckdbConnection, connectionConfig) {
@@ -221286,17 +221450,13 @@ ${failedAttachments.join(`
221286
221450
  }
221287
221451
  }
221288
221452
  async function testConnectionConfig(connectionConfig) {
221289
- let malloyConnections = null;
221453
+ let projectConfig = null;
221290
221454
  try {
221291
221455
  if (!connectionConfig.name) {
221292
221456
  throw new Error("Connection name is required");
221293
221457
  }
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
- }
221458
+ projectConfig = buildProjectMalloyConfig([connectionConfig]);
221459
+ const connection = await projectConfig.malloyConfig.connections.lookupConnection(connectionConfig.name);
221300
221460
  if (connectionConfig.type === "duckdb") {
221301
221461
  await testDuckDBConnection(connection, connectionConfig);
221302
221462
  } else if (connectionConfig.type === "ducklake") {
@@ -221325,25 +221485,41 @@ async function testConnectionConfig(connectionConfig) {
221325
221485
  errorMessage: error.message
221326
221486
  };
221327
221487
  } 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
- }
221488
+ if (projectConfig) {
221489
+ try {
221490
+ await projectConfig.releaseConnections();
221491
+ } catch (closeError) {
221492
+ logger.warn("Error releasing temporary connection test config", {
221493
+ error: closeError
221494
+ });
221341
221495
  }
221342
221496
  }
221497
+ if (connectionConfig.type === "ducklake" && connectionConfig.name) {
221498
+ await deleteDuckLakeConnectionFile(connectionConfig.name, process.cwd());
221499
+ }
221343
221500
  }
221344
221501
  }
221345
221502
 
221346
221503
  // src/service/connection_service.ts
221504
+ async function runProjectConnectionUpdate(project, fn) {
221505
+ if (project.runConnectionUpdateExclusive) {
221506
+ return project.runConnectionUpdateExclusive(fn);
221507
+ }
221508
+ return fn();
221509
+ }
221510
+ function updateProjectConnections(project, nextMalloyConfig, afterPreviousRelease) {
221511
+ project.updateConnections?.(nextMalloyConfig, nextMalloyConfig.apiConnections, afterPreviousRelease);
221512
+ }
221513
+ function buildDeletedConnectionCleanup(project, deletedConnection, connectionName) {
221514
+ if (deletedConnection.type === "duckdb" && typeof project.deleteDuckDBConnection === "function") {
221515
+ return () => project.deleteDuckDBConnection(connectionName);
221516
+ }
221517
+ if (deletedConnection.type === "ducklake" && typeof project.deleteDuckLakeConnection === "function") {
221518
+ return () => project.deleteDuckLakeConnection(connectionName);
221519
+ }
221520
+ return;
221521
+ }
221522
+
221347
221523
  class ConnectionService {
221348
221524
  projectStore;
221349
221525
  constructor(projectStore) {
@@ -221378,10 +221554,12 @@ class ConnectionService {
221378
221554
  throw new Error(`Connection "${connectionName}" already exists in project "${projectName}".`);
221379
221555
  }
221380
221556
  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);
221557
+ await runProjectConnectionUpdate(project, async () => {
221558
+ const existingConnections = project.listApiConnections();
221559
+ const nextMalloyConfig = buildProjectMalloyConfig([...existingConnections, connection], project.metadata.location || "");
221560
+ await this.projectStore.addConnection(connection, dbProject.id, repository);
221561
+ updateProjectConnections(project, nextMalloyConfig);
221562
+ });
221385
221563
  logger.info(`Successfully added connection "${connection.name}" to project "${projectName}"`);
221386
221564
  }
221387
221565
  async updateConnection(projectName, connectionName, connection) {
@@ -221392,16 +221570,18 @@ class ConnectionService {
221392
221570
  logger.info(`Updating connection "${connectionName}" in project "${projectName}"`);
221393
221571
  const { dbProject, dbConnection, repository } = await this.getConnection(projectName, connectionName);
221394
221572
  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);
221573
+ await runProjectConnectionUpdate(project, async () => {
221574
+ const existingConnections = project.listApiConnections();
221575
+ const updatedConnection = {
221576
+ ...dbConnection.config,
221577
+ ...connection,
221578
+ name: connectionName
221579
+ };
221580
+ const updatedConnections = existingConnections.map((conn) => conn.name === connectionName ? updatedConnection : conn);
221581
+ const nextMalloyConfig = buildProjectMalloyConfig(updatedConnections, project.metadata.location || "", true);
221582
+ await this.projectStore.updateConnection(updatedConnection, dbProject.id, repository);
221583
+ updateProjectConnections(project, nextMalloyConfig);
221584
+ });
221405
221585
  logger.info(`Successfully updated connection "${connectionName}" in project "${projectName}"`);
221406
221586
  }
221407
221587
  async deleteConnection(projectName, connectionName) {
@@ -221412,8 +221592,21 @@ class ConnectionService {
221412
221592
  logger.info(`Deleting connection "${connectionName}" from project "${projectName}"`);
221413
221593
  const { dbConnection, repository } = await this.getConnection(projectName, connectionName);
221414
221594
  const project = await this.projectStore.getProject(projectName, false);
221415
- await project.deleteConnection(connectionName);
221416
- await repository.deleteConnection(dbConnection.id);
221595
+ await runProjectConnectionUpdate(project, async () => {
221596
+ if (typeof project.listApiConnections !== "function") {
221597
+ if (typeof project.deleteConnection === "function") {
221598
+ await project.deleteConnection(connectionName);
221599
+ }
221600
+ await repository.deleteConnection(dbConnection.id);
221601
+ return;
221602
+ }
221603
+ const deletedConnection = "getApiConnection" in project && typeof project.getApiConnection === "function" ? project.getApiConnection(connectionName) : dbConnection.config;
221604
+ const updatedConnections = project.listApiConnections().filter((connection) => connection.name !== connectionName);
221605
+ const nextMalloyConfig = buildProjectMalloyConfig(updatedConnections, project.metadata.location || "");
221606
+ const deleteConnectionFilesAfterRelease = buildDeletedConnectionCleanup(project, deletedConnection, connectionName);
221607
+ await repository.deleteConnection(dbConnection.id);
221608
+ updateProjectConnections(project, nextMalloyConfig, deleteConnectionFilesAfterRelease);
221609
+ });
221417
221610
  logger.info(`Successfully deleted connection "${connectionName}" from project "${projectName}"`);
221418
221611
  }
221419
221612
  }
@@ -222426,6 +222619,16 @@ function validateAzureAttachedDatabases(connectionConfig) {
222426
222619
  }
222427
222620
  }
222428
222621
  }
222622
+ function validateAdminAuthoredConnection(connectionName, connectionConfig) {
222623
+ if (connectionName === "duckdb" || connectionConfig.name === "duckdb") {
222624
+ throw new BadRequestError("DuckDB connection name cannot be 'duckdb'; it is reserved for Publisher package sandboxes.");
222625
+ }
222626
+ try {
222627
+ validateDuckdbApiSurface(connectionConfig);
222628
+ } catch (error) {
222629
+ throw new BadRequestError(error.message);
222630
+ }
222631
+ }
222429
222632
 
222430
222633
  class ConnectionController {
222431
222634
  projectStore;
@@ -222434,22 +222637,42 @@ class ConnectionController {
222434
222637
  this.projectStore = projectStore;
222435
222638
  this.connectionService = new ConnectionService(projectStore);
222436
222639
  }
222437
- async getMalloyConnection(projectName, connectionName) {
222640
+ getApiConnectionForLookup(project, connectionName) {
222641
+ if (connectionName === "duckdb") {
222642
+ return {
222643
+ name: "duckdb",
222644
+ type: "duckdb",
222645
+ duckdbConnection: { attachedDatabases: [] }
222646
+ };
222647
+ }
222648
+ return project.getApiConnection(connectionName);
222649
+ }
222650
+ async getMalloyConnection(projectName, connectionName, packageName) {
222438
222651
  const project = await this.projectStore.getProject(projectName, false);
222439
- const connection = project.getApiConnection(connectionName);
222440
- if (connection.name === "duckdb" && connection.type === "duckdb") {
222652
+ if (connectionName === "duckdb") {
222441
222653
  const packages = await project.listPackages();
222442
222654
  if (packages.length === 0) {
222443
- return project.getMalloyConnection(connectionName);
222655
+ return await project.getMalloyConnection(connectionName);
222656
+ }
222657
+ if (packageName) {
222658
+ const known = packages.some((p) => p.name === packageName);
222659
+ if (!known) {
222660
+ throw new BadRequestError(`Package "${packageName}" not found in project "${projectName}"`);
222661
+ }
222662
+ const pkg = await project.getPackage(packageName);
222663
+ return await pkg.getMalloyConnection(connectionName);
222444
222664
  }
222445
- const packageName = packages[0].name;
222446
- if (!packageName) {
222447
- throw new ConnectionError("Package name is undefined");
222665
+ if (packages.length === 1) {
222666
+ const onlyPackage = packages[0].name;
222667
+ if (!onlyPackage) {
222668
+ throw new ConnectionError("Package name is undefined");
222669
+ }
222670
+ const pkg = await project.getPackage(onlyPackage);
222671
+ return await pkg.getMalloyConnection(connectionName);
222448
222672
  }
222449
- const pkg = await project.getPackage(packageName);
222450
- return pkg.getMalloyConnection(connectionName);
222673
+ throw new BadRequestError(`Ambiguous "duckdb" connection lookup: project "${projectName}" has multiple packages. ` + `Use /projects/${projectName}/packages/{packageName}/connections/duckdb/... to disambiguate.`);
222451
222674
  } else {
222452
- return project.getMalloyConnection(connectionName);
222675
+ return await project.getMalloyConnection(connectionName);
222453
222676
  }
222454
222677
  }
222455
222678
  async fetchTable(malloyConnection, tableKey, tablePath) {
@@ -222490,20 +222713,20 @@ class ConnectionController {
222490
222713
  const project = await this.projectStore.getProject(projectName, false);
222491
222714
  return project.listApiConnections();
222492
222715
  }
222493
- async listSchemas(projectName, connectionName) {
222716
+ async listSchemas(projectName, connectionName, packageName) {
222494
222717
  const project = await this.projectStore.getProject(projectName, false);
222495
- const connection = project.getApiConnection(connectionName);
222496
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222718
+ const connection = this.getApiConnectionForLookup(project, connectionName);
222719
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222497
222720
  return getSchemasForConnection(connection, malloyConnection);
222498
222721
  }
222499
- async listTables(projectName, connectionName, schemaName, tableNames) {
222722
+ async listTables(projectName, connectionName, schemaName, tableNames, packageName) {
222500
222723
  const project = await this.projectStore.getProject(projectName, false);
222501
- const connection = project.getApiConnection(connectionName);
222502
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222724
+ const connection = this.getApiConnectionForLookup(project, connectionName);
222725
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222503
222726
  return listTablesForSchema(connection, schemaName, malloyConnection, tableNames);
222504
222727
  }
222505
- async getConnectionSqlSource(projectName, connectionName, sqlStatement) {
222506
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222728
+ async getConnectionSqlSource(projectName, connectionName, sqlStatement, packageName) {
222729
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222507
222730
  try {
222508
222731
  const schema = await malloyConnection.fetchSelectSchema({
222509
222732
  connection: connectionName,
@@ -222519,10 +222742,10 @@ class ConnectionController {
222519
222742
  throw new ConnectionError(error.message);
222520
222743
  }
222521
222744
  }
222522
- async getTable(projectName, connectionName, schemaName, tablePath) {
222523
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222745
+ async getTable(projectName, connectionName, schemaName, tablePath, packageName) {
222746
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222524
222747
  const project = await this.projectStore.getProject(projectName, false);
222525
- const connection = project.getApiConnection(connectionName);
222748
+ const connection = this.getApiConnectionForLookup(project, connectionName);
222526
222749
  if (connection.type === "ducklake") {
222527
222750
  if (tablePath.split(".").length === 1) {
222528
222751
  tablePath = `${connectionName}.${schemaName}.${tablePath}`;
@@ -222554,8 +222777,8 @@ class ConnectionController {
222554
222777
  }
222555
222778
  return this.fetchTable(malloyConnection, tableKey, tablePath);
222556
222779
  }
222557
- async getConnectionQueryData(projectName, connectionName, sqlStatement, options) {
222558
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222780
+ async getConnectionQueryData(projectName, connectionName, sqlStatement, options, packageName) {
222781
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222559
222782
  let runSQLOptions = {};
222560
222783
  if (options) {
222561
222784
  runSQLOptions = JSON.parse(options);
@@ -222572,8 +222795,8 @@ class ConnectionController {
222572
222795
  throw new ConnectionError(error.message);
222573
222796
  }
222574
222797
  }
222575
- async getConnectionTemporaryTable(projectName, connectionName, sqlStatement) {
222576
- const malloyConnection = await this.getMalloyConnection(projectName, connectionName);
222798
+ async getConnectionTemporaryTable(projectName, connectionName, sqlStatement, packageName) {
222799
+ const malloyConnection = await this.getMalloyConnection(projectName, connectionName, packageName);
222577
222800
  try {
222578
222801
  return {
222579
222802
  table: JSON.stringify(await malloyConnection.manifestTemporaryTable(sqlStatement))
@@ -222582,10 +222805,8 @@ class ConnectionController {
222582
222805
  throw new ConnectionError(error.message);
222583
222806
  }
222584
222807
  }
222585
- async testConnectionConfiguration(connectionConfig) {
222586
- if (connectionConfig && "config" in connectionConfig && typeof connectionConfig.config === "object") {
222587
- connectionConfig = connectionConfig.config;
222588
- }
222808
+ async testConnectionConfiguration(input) {
222809
+ const connectionConfig = input.config && typeof input.config === "object" ? input.config : input;
222589
222810
  if (!connectionConfig || typeof connectionConfig !== "object" || Object.keys(connectionConfig).length === 0) {
222590
222811
  throw new BadRequestError("Connection configuration is required and cannot be empty");
222591
222812
  }
@@ -222612,6 +222833,7 @@ class ConnectionController {
222612
222833
  throw new BadRequestError("Connection type is required");
222613
222834
  }
222614
222835
  validateAzureAttachedDatabases(connectionConfig);
222836
+ validateAdminAuthoredConnection(connectionName, connectionConfig);
222615
222837
  logger.info(`Creating connection "${connectionName}" in project "${projectName}"`);
222616
222838
  await this.connectionService.addConnection(projectName, connectionName, connectionConfig);
222617
222839
  return {
@@ -222623,6 +222845,7 @@ class ConnectionController {
222623
222845
  throw new BadRequestError("Connection payload is required");
222624
222846
  }
222625
222847
  validateAzureAttachedDatabases(connection);
222848
+ validateAdminAuthoredConnection(connectionName, connection);
222626
222849
  logger.info(`Updating connection "${connectionName}" in project "${projectName}"`);
222627
222850
  await this.connectionService.updateConnection(projectName, connectionName, connection);
222628
222851
  return {
@@ -222713,7 +222936,7 @@ class ModelController {
222713
222936
  }
222714
222937
 
222715
222938
  // src/controller/package.controller.ts
222716
- import * as path2 from "path";
222939
+ import * as path3 from "path";
222717
222940
  class PackageController {
222718
222941
  projectStore;
222719
222942
  manifestService;
@@ -222797,7 +223020,7 @@ class PackageController {
222797
223020
  return result;
222798
223021
  }
222799
223022
  async downloadPackage(projectName, packageName, packageLocation) {
222800
- const absoluteTargetPath = path2.join(this.projectStore.serverRootPath, PUBLISHER_DATA_DIR, projectName, packageName);
223023
+ const absoluteTargetPath = path3.join(this.projectStore.serverRootPath, PUBLISHER_DATA_DIR, projectName, packageName);
222801
223024
  const isCompressedFile = packageLocation.endsWith(".zip");
222802
223025
  if (packageLocation.startsWith("https://") || packageLocation.startsWith("git@")) {
222803
223026
  await this.projectStore.downloadGitHubDirectory(packageLocation, absoluteTargetPath);
@@ -222921,7 +223144,7 @@ class ReaddirpStream extends Readable2 {
222921
223144
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
222922
223145
  const statMethod = opts.lstat ? lstat : stat;
222923
223146
  if (wantBigintFsStats) {
222924
- this._stat = (path3) => statMethod(path3, { bigint: true });
223147
+ this._stat = (path4) => statMethod(path4, { bigint: true });
222925
223148
  } else {
222926
223149
  this._stat = statMethod;
222927
223150
  }
@@ -222946,8 +223169,8 @@ class ReaddirpStream extends Readable2 {
222946
223169
  const par = this.parent;
222947
223170
  const fil = par && par.files;
222948
223171
  if (fil && fil.length > 0) {
222949
- const { path: path3, depth } = par;
222950
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path3));
223172
+ const { path: path4, depth } = par;
223173
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path4));
222951
223174
  const awaited = await Promise.all(slice);
222952
223175
  for (const entry of awaited) {
222953
223176
  if (!entry)
@@ -222987,20 +223210,20 @@ class ReaddirpStream extends Readable2 {
222987
223210
  this.reading = false;
222988
223211
  }
222989
223212
  }
222990
- async _exploreDir(path3, depth) {
223213
+ async _exploreDir(path4, depth) {
222991
223214
  let files;
222992
223215
  try {
222993
- files = await readdir(path3, this._rdOptions);
223216
+ files = await readdir(path4, this._rdOptions);
222994
223217
  } catch (error) {
222995
223218
  this._onError(error);
222996
223219
  }
222997
- return { files, depth, path: path3 };
223220
+ return { files, depth, path: path4 };
222998
223221
  }
222999
- async _formatEntry(dirent, path3) {
223222
+ async _formatEntry(dirent, path4) {
223000
223223
  let entry;
223001
223224
  const basename = this._isDirent ? dirent.name : dirent;
223002
223225
  try {
223003
- const fullPath = presolve(pjoin(path3, basename));
223226
+ const fullPath = presolve(pjoin(path4, basename));
223004
223227
  entry = { path: prelative(this._root, fullPath), fullPath, basename };
223005
223228
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
223006
223229
  } catch (err) {
@@ -223399,16 +223622,16 @@ var delFromSet = (main, prop, item) => {
223399
223622
  };
223400
223623
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
223401
223624
  var FsWatchInstances = new Map;
223402
- function createFsWatchInstance(path3, options, listener, errHandler, emitRaw) {
223625
+ function createFsWatchInstance(path4, options, listener, errHandler, emitRaw) {
223403
223626
  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));
223627
+ listener(path4);
223628
+ emitRaw(rawEvent, evPath, { watchedPath: path4 });
223629
+ if (evPath && path4 !== evPath) {
223630
+ fsWatchBroadcast(sysPath.resolve(path4, evPath), KEY_LISTENERS, sysPath.join(path4, evPath));
223408
223631
  }
223409
223632
  };
223410
223633
  try {
223411
- return fs_watch(path3, {
223634
+ return fs_watch(path4, {
223412
223635
  persistent: options.persistent
223413
223636
  }, handleEvent);
223414
223637
  } catch (error) {
@@ -223424,12 +223647,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
223424
223647
  listener(val1, val2, val3);
223425
223648
  });
223426
223649
  };
223427
- var setFsWatchListener = (path3, fullPath, options, handlers) => {
223650
+ var setFsWatchListener = (path4, fullPath, options, handlers) => {
223428
223651
  const { listener, errHandler, rawEmitter } = handlers;
223429
223652
  let cont = FsWatchInstances.get(fullPath);
223430
223653
  let watcher;
223431
223654
  if (!options.persistent) {
223432
- watcher = createFsWatchInstance(path3, options, listener, errHandler, rawEmitter);
223655
+ watcher = createFsWatchInstance(path4, options, listener, errHandler, rawEmitter);
223433
223656
  if (!watcher)
223434
223657
  return;
223435
223658
  return watcher.close.bind(watcher);
@@ -223439,7 +223662,7 @@ var setFsWatchListener = (path3, fullPath, options, handlers) => {
223439
223662
  addAndConvert(cont, KEY_ERR, errHandler);
223440
223663
  addAndConvert(cont, KEY_RAW, rawEmitter);
223441
223664
  } else {
223442
- watcher = createFsWatchInstance(path3, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
223665
+ watcher = createFsWatchInstance(path4, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
223443
223666
  if (!watcher)
223444
223667
  return;
223445
223668
  watcher.on(EV.ERROR, async (error) => {
@@ -223448,7 +223671,7 @@ var setFsWatchListener = (path3, fullPath, options, handlers) => {
223448
223671
  cont.watcherUnusable = true;
223449
223672
  if (isWindows && error.code === "EPERM") {
223450
223673
  try {
223451
- const fd = await open(path3, "r");
223674
+ const fd = await open(path4, "r");
223452
223675
  await fd.close();
223453
223676
  broadcastErr(error);
223454
223677
  } catch (err) {}
@@ -223478,7 +223701,7 @@ var setFsWatchListener = (path3, fullPath, options, handlers) => {
223478
223701
  };
223479
223702
  };
223480
223703
  var FsWatchFileInstances = new Map;
223481
- var setFsWatchFileListener = (path3, fullPath, options, handlers) => {
223704
+ var setFsWatchFileListener = (path4, fullPath, options, handlers) => {
223482
223705
  const { listener, rawEmitter } = handlers;
223483
223706
  let cont = FsWatchFileInstances.get(fullPath);
223484
223707
  const copts = cont && cont.options;
@@ -223500,7 +223723,7 @@ var setFsWatchFileListener = (path3, fullPath, options, handlers) => {
223500
223723
  });
223501
223724
  const currmtime = curr.mtimeMs;
223502
223725
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
223503
- foreach(cont.listeners, (listener2) => listener2(path3, curr));
223726
+ foreach(cont.listeners, (listener2) => listener2(path4, curr));
223504
223727
  }
223505
223728
  })
223506
223729
  };
@@ -223523,13 +223746,13 @@ class NodeFsHandler {
223523
223746
  this.fsw = fsW;
223524
223747
  this._boundHandleError = (error) => fsW._handleError(error);
223525
223748
  }
223526
- _watchWithNodeFs(path3, listener) {
223749
+ _watchWithNodeFs(path4, listener) {
223527
223750
  const opts = this.fsw.options;
223528
- const directory = sysPath.dirname(path3);
223529
- const basename2 = sysPath.basename(path3);
223751
+ const directory = sysPath.dirname(path4);
223752
+ const basename2 = sysPath.basename(path4);
223530
223753
  const parent = this.fsw._getWatchedDir(directory);
223531
223754
  parent.add(basename2);
223532
- const absolutePath = sysPath.resolve(path3);
223755
+ const absolutePath = sysPath.resolve(path4);
223533
223756
  const options = {
223534
223757
  persistent: opts.persistent
223535
223758
  };
@@ -223539,12 +223762,12 @@ class NodeFsHandler {
223539
223762
  if (opts.usePolling) {
223540
223763
  const enableBin = opts.interval !== opts.binaryInterval;
223541
223764
  options.interval = enableBin && isBinaryPath(basename2) ? opts.binaryInterval : opts.interval;
223542
- closer = setFsWatchFileListener(path3, absolutePath, options, {
223765
+ closer = setFsWatchFileListener(path4, absolutePath, options, {
223543
223766
  listener,
223544
223767
  rawEmitter: this.fsw._emitRaw
223545
223768
  });
223546
223769
  } else {
223547
- closer = setFsWatchListener(path3, absolutePath, options, {
223770
+ closer = setFsWatchListener(path4, absolutePath, options, {
223548
223771
  listener,
223549
223772
  errHandler: this._boundHandleError,
223550
223773
  rawEmitter: this.fsw._emitRaw
@@ -223562,7 +223785,7 @@ class NodeFsHandler {
223562
223785
  let prevStats = stats;
223563
223786
  if (parent.has(basename2))
223564
223787
  return;
223565
- const listener = async (path3, newStats) => {
223788
+ const listener = async (path4, newStats) => {
223566
223789
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
223567
223790
  return;
223568
223791
  if (!newStats || newStats.mtimeMs === 0) {
@@ -223576,11 +223799,11 @@ class NodeFsHandler {
223576
223799
  this.fsw._emit(EV.CHANGE, file, newStats2);
223577
223800
  }
223578
223801
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
223579
- this.fsw._closeFile(path3);
223802
+ this.fsw._closeFile(path4);
223580
223803
  prevStats = newStats2;
223581
223804
  const closer2 = this._watchWithNodeFs(file, listener);
223582
223805
  if (closer2)
223583
- this.fsw._addPathCloser(path3, closer2);
223806
+ this.fsw._addPathCloser(path4, closer2);
223584
223807
  } else {
223585
223808
  prevStats = newStats2;
223586
223809
  }
@@ -223604,7 +223827,7 @@ class NodeFsHandler {
223604
223827
  }
223605
223828
  return closer;
223606
223829
  }
223607
- async _handleSymlink(entry, directory, path3, item) {
223830
+ async _handleSymlink(entry, directory, path4, item) {
223608
223831
  if (this.fsw.closed) {
223609
223832
  return;
223610
223833
  }
@@ -223614,7 +223837,7 @@ class NodeFsHandler {
223614
223837
  this.fsw._incrReadyCount();
223615
223838
  let linkPath;
223616
223839
  try {
223617
- linkPath = await fsrealpath(path3);
223840
+ linkPath = await fsrealpath(path4);
223618
223841
  } catch (e) {
223619
223842
  this.fsw._emitReady();
223620
223843
  return true;
@@ -223624,12 +223847,12 @@ class NodeFsHandler {
223624
223847
  if (dir.has(item)) {
223625
223848
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
223626
223849
  this.fsw._symlinkPaths.set(full, linkPath);
223627
- this.fsw._emit(EV.CHANGE, path3, entry.stats);
223850
+ this.fsw._emit(EV.CHANGE, path4, entry.stats);
223628
223851
  }
223629
223852
  } else {
223630
223853
  dir.add(item);
223631
223854
  this.fsw._symlinkPaths.set(full, linkPath);
223632
- this.fsw._emit(EV.ADD, path3, entry.stats);
223855
+ this.fsw._emit(EV.ADD, path4, entry.stats);
223633
223856
  }
223634
223857
  this.fsw._emitReady();
223635
223858
  return true;
@@ -223658,9 +223881,9 @@ class NodeFsHandler {
223658
223881
  return;
223659
223882
  }
223660
223883
  const item = entry.path;
223661
- let path3 = sysPath.join(directory, item);
223884
+ let path4 = sysPath.join(directory, item);
223662
223885
  current.add(item);
223663
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path3, item)) {
223886
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path4, item)) {
223664
223887
  return;
223665
223888
  }
223666
223889
  if (this.fsw.closed) {
@@ -223669,8 +223892,8 @@ class NodeFsHandler {
223669
223892
  }
223670
223893
  if (item === target || !target && !previous.has(item)) {
223671
223894
  this.fsw._incrReadyCount();
223672
- path3 = sysPath.join(dir, sysPath.relative(dir, path3));
223673
- this._addToNodeFs(path3, initialAdd, wh, depth + 1);
223895
+ path4 = sysPath.join(dir, sysPath.relative(dir, path4));
223896
+ this._addToNodeFs(path4, initialAdd, wh, depth + 1);
223674
223897
  }
223675
223898
  }).on(EV.ERROR, this._boundHandleError);
223676
223899
  return new Promise((resolve2, reject) => {
@@ -223719,13 +223942,13 @@ class NodeFsHandler {
223719
223942
  }
223720
223943
  return closer;
223721
223944
  }
223722
- async _addToNodeFs(path3, initialAdd, priorWh, depth, target) {
223945
+ async _addToNodeFs(path4, initialAdd, priorWh, depth, target) {
223723
223946
  const ready = this.fsw._emitReady;
223724
- if (this.fsw._isIgnored(path3) || this.fsw.closed) {
223947
+ if (this.fsw._isIgnored(path4) || this.fsw.closed) {
223725
223948
  ready();
223726
223949
  return false;
223727
223950
  }
223728
- const wh = this.fsw._getWatchHelpers(path3);
223951
+ const wh = this.fsw._getWatchHelpers(path4);
223729
223952
  if (priorWh) {
223730
223953
  wh.filterPath = (entry) => priorWh.filterPath(entry);
223731
223954
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -223741,8 +223964,8 @@ class NodeFsHandler {
223741
223964
  const follow = this.fsw.options.followSymlinks;
223742
223965
  let closer;
223743
223966
  if (stats.isDirectory()) {
223744
- const absPath = sysPath.resolve(path3);
223745
- const targetPath = follow ? await fsrealpath(path3) : path3;
223967
+ const absPath = sysPath.resolve(path4);
223968
+ const targetPath = follow ? await fsrealpath(path4) : path4;
223746
223969
  if (this.fsw.closed)
223747
223970
  return;
223748
223971
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -223752,29 +223975,29 @@ class NodeFsHandler {
223752
223975
  this.fsw._symlinkPaths.set(absPath, targetPath);
223753
223976
  }
223754
223977
  } else if (stats.isSymbolicLink()) {
223755
- const targetPath = follow ? await fsrealpath(path3) : path3;
223978
+ const targetPath = follow ? await fsrealpath(path4) : path4;
223756
223979
  if (this.fsw.closed)
223757
223980
  return;
223758
223981
  const parent = sysPath.dirname(wh.watchPath);
223759
223982
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
223760
223983
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
223761
- closer = await this._handleDir(parent, stats, initialAdd, depth, path3, wh, targetPath);
223984
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path4, wh, targetPath);
223762
223985
  if (this.fsw.closed)
223763
223986
  return;
223764
223987
  if (targetPath !== undefined) {
223765
- this.fsw._symlinkPaths.set(sysPath.resolve(path3), targetPath);
223988
+ this.fsw._symlinkPaths.set(sysPath.resolve(path4), targetPath);
223766
223989
  }
223767
223990
  } else {
223768
223991
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
223769
223992
  }
223770
223993
  ready();
223771
223994
  if (closer)
223772
- this.fsw._addPathCloser(path3, closer);
223995
+ this.fsw._addPathCloser(path4, closer);
223773
223996
  return false;
223774
223997
  } catch (error) {
223775
223998
  if (this.fsw._handleError(error)) {
223776
223999
  ready();
223777
- return path3;
224000
+ return path4;
223778
224001
  }
223779
224002
  }
223780
224003
  }
@@ -223818,26 +224041,26 @@ function createPattern(matcher) {
223818
224041
  }
223819
224042
  return () => false;
223820
224043
  }
223821
- function normalizePath(path3) {
223822
- if (typeof path3 !== "string")
224044
+ function normalizePath(path4) {
224045
+ if (typeof path4 !== "string")
223823
224046
  throw new Error("string expected");
223824
- path3 = sysPath2.normalize(path3);
223825
- path3 = path3.replace(/\\/g, "/");
224047
+ path4 = sysPath2.normalize(path4);
224048
+ path4 = path4.replace(/\\/g, "/");
223826
224049
  let prepend = false;
223827
- if (path3.startsWith("//"))
224050
+ if (path4.startsWith("//"))
223828
224051
  prepend = true;
223829
224052
  const DOUBLE_SLASH_RE2 = /\/\//;
223830
- while (path3.match(DOUBLE_SLASH_RE2))
223831
- path3 = path3.replace(DOUBLE_SLASH_RE2, "/");
224053
+ while (path4.match(DOUBLE_SLASH_RE2))
224054
+ path4 = path4.replace(DOUBLE_SLASH_RE2, "/");
223832
224055
  if (prepend)
223833
- path3 = "/" + path3;
223834
- return path3;
224056
+ path4 = "/" + path4;
224057
+ return path4;
223835
224058
  }
223836
224059
  function matchPatterns(patterns, testString, stats) {
223837
- const path3 = normalizePath(testString);
224060
+ const path4 = normalizePath(testString);
223838
224061
  for (let index = 0;index < patterns.length; index++) {
223839
224062
  const pattern = patterns[index];
223840
- if (pattern(path3, stats)) {
224063
+ if (pattern(path4, stats)) {
223841
224064
  return true;
223842
224065
  }
223843
224066
  }
@@ -223877,19 +224100,19 @@ var toUnix = (string) => {
223877
224100
  }
223878
224101
  return str;
223879
224102
  };
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));
224103
+ var normalizePathToUnix = (path4) => toUnix(sysPath2.normalize(toUnix(path4)));
224104
+ var normalizeIgnored = (cwd = "") => (path4) => {
224105
+ if (typeof path4 === "string") {
224106
+ return normalizePathToUnix(sysPath2.isAbsolute(path4) ? path4 : sysPath2.join(cwd, path4));
223884
224107
  } else {
223885
- return path3;
224108
+ return path4;
223886
224109
  }
223887
224110
  };
223888
- var getAbsolutePath = (path3, cwd) => {
223889
- if (sysPath2.isAbsolute(path3)) {
223890
- return path3;
224111
+ var getAbsolutePath = (path4, cwd) => {
224112
+ if (sysPath2.isAbsolute(path4)) {
224113
+ return path4;
223891
224114
  }
223892
- return sysPath2.join(cwd, path3);
224115
+ return sysPath2.join(cwd, path4);
223893
224116
  };
223894
224117
  var EMPTY_SET = Object.freeze(new Set);
223895
224118
 
@@ -223946,10 +224169,10 @@ var STAT_METHOD_F = "stat";
223946
224169
  var STAT_METHOD_L = "lstat";
223947
224170
 
223948
224171
  class WatchHelper {
223949
- constructor(path3, follow, fsw) {
224172
+ constructor(path4, follow, fsw) {
223950
224173
  this.fsw = fsw;
223951
- const watchPath = path3;
223952
- this.path = path3 = path3.replace(REPLACER_RE, "");
224174
+ const watchPath = path4;
224175
+ this.path = path4 = path4.replace(REPLACER_RE, "");
223953
224176
  this.watchPath = watchPath;
223954
224177
  this.fullWatchPath = sysPath2.resolve(watchPath);
223955
224178
  this.dirParts = [];
@@ -224062,20 +224285,20 @@ class FSWatcher extends EventEmitter2 {
224062
224285
  this._closePromise = undefined;
224063
224286
  let paths = unifyPaths(paths_);
224064
224287
  if (cwd) {
224065
- paths = paths.map((path3) => {
224066
- const absPath = getAbsolutePath(path3, cwd);
224288
+ paths = paths.map((path4) => {
224289
+ const absPath = getAbsolutePath(path4, cwd);
224067
224290
  return absPath;
224068
224291
  });
224069
224292
  }
224070
- paths.forEach((path3) => {
224071
- this._removeIgnoredPath(path3);
224293
+ paths.forEach((path4) => {
224294
+ this._removeIgnoredPath(path4);
224072
224295
  });
224073
224296
  this._userIgnored = undefined;
224074
224297
  if (!this._readyCount)
224075
224298
  this._readyCount = 0;
224076
224299
  this._readyCount += paths.length;
224077
- Promise.all(paths.map(async (path3) => {
224078
- const res = await this._nodeFsHandler._addToNodeFs(path3, !_internal, undefined, 0, _origAdd);
224300
+ Promise.all(paths.map(async (path4) => {
224301
+ const res = await this._nodeFsHandler._addToNodeFs(path4, !_internal, undefined, 0, _origAdd);
224079
224302
  if (res)
224080
224303
  this._emitReady();
224081
224304
  return res;
@@ -224094,17 +224317,17 @@ class FSWatcher extends EventEmitter2 {
224094
224317
  return this;
224095
224318
  const paths = unifyPaths(paths_);
224096
224319
  const { cwd } = this.options;
224097
- paths.forEach((path3) => {
224098
- if (!sysPath2.isAbsolute(path3) && !this._closers.has(path3)) {
224320
+ paths.forEach((path4) => {
224321
+ if (!sysPath2.isAbsolute(path4) && !this._closers.has(path4)) {
224099
224322
  if (cwd)
224100
- path3 = sysPath2.join(cwd, path3);
224101
- path3 = sysPath2.resolve(path3);
224323
+ path4 = sysPath2.join(cwd, path4);
224324
+ path4 = sysPath2.resolve(path4);
224102
224325
  }
224103
- this._closePath(path3);
224104
- this._addIgnoredPath(path3);
224105
- if (this._watched.has(path3)) {
224326
+ this._closePath(path4);
224327
+ this._addIgnoredPath(path4);
224328
+ if (this._watched.has(path4)) {
224106
224329
  this._addIgnoredPath({
224107
- path: path3,
224330
+ path: path4,
224108
224331
  recursive: true
224109
224332
  });
224110
224333
  }
@@ -224153,38 +224376,38 @@ class FSWatcher extends EventEmitter2 {
224153
224376
  if (event !== EVENTS.ERROR)
224154
224377
  this.emit(EVENTS.ALL, event, ...args);
224155
224378
  }
224156
- async _emit(event, path3, stats) {
224379
+ async _emit(event, path4, stats) {
224157
224380
  if (this.closed)
224158
224381
  return;
224159
224382
  const opts = this.options;
224160
224383
  if (isWindows)
224161
- path3 = sysPath2.normalize(path3);
224384
+ path4 = sysPath2.normalize(path4);
224162
224385
  if (opts.cwd)
224163
- path3 = sysPath2.relative(opts.cwd, path3);
224164
- const args = [path3];
224386
+ path4 = sysPath2.relative(opts.cwd, path4);
224387
+ const args = [path4];
224165
224388
  if (stats != null)
224166
224389
  args.push(stats);
224167
224390
  const awf = opts.awaitWriteFinish;
224168
224391
  let pw;
224169
- if (awf && (pw = this._pendingWrites.get(path3))) {
224392
+ if (awf && (pw = this._pendingWrites.get(path4))) {
224170
224393
  pw.lastChange = new Date;
224171
224394
  return this;
224172
224395
  }
224173
224396
  if (opts.atomic) {
224174
224397
  if (event === EVENTS.UNLINK) {
224175
- this._pendingUnlinks.set(path3, [event, ...args]);
224398
+ this._pendingUnlinks.set(path4, [event, ...args]);
224176
224399
  setTimeout(() => {
224177
- this._pendingUnlinks.forEach((entry, path4) => {
224400
+ this._pendingUnlinks.forEach((entry, path5) => {
224178
224401
  this.emit(...entry);
224179
224402
  this.emit(EVENTS.ALL, ...entry);
224180
- this._pendingUnlinks.delete(path4);
224403
+ this._pendingUnlinks.delete(path5);
224181
224404
  });
224182
224405
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
224183
224406
  return this;
224184
224407
  }
224185
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path3)) {
224408
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path4)) {
224186
224409
  event = EVENTS.CHANGE;
224187
- this._pendingUnlinks.delete(path3);
224410
+ this._pendingUnlinks.delete(path4);
224188
224411
  }
224189
224412
  }
224190
224413
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -224202,16 +224425,16 @@ class FSWatcher extends EventEmitter2 {
224202
224425
  this.emitWithAll(event, args);
224203
224426
  }
224204
224427
  };
224205
- this._awaitWriteFinish(path3, awf.stabilityThreshold, event, awfEmit);
224428
+ this._awaitWriteFinish(path4, awf.stabilityThreshold, event, awfEmit);
224206
224429
  return this;
224207
224430
  }
224208
224431
  if (event === EVENTS.CHANGE) {
224209
- const isThrottled = !this._throttle(EVENTS.CHANGE, path3, 50);
224432
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path4, 50);
224210
224433
  if (isThrottled)
224211
224434
  return this;
224212
224435
  }
224213
224436
  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;
224437
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path4) : path4;
224215
224438
  let stats2;
224216
224439
  try {
224217
224440
  stats2 = await stat3(fullPath);
@@ -224230,23 +224453,23 @@ class FSWatcher extends EventEmitter2 {
224230
224453
  }
224231
224454
  return error || this.closed;
224232
224455
  }
224233
- _throttle(actionType, path3, timeout) {
224456
+ _throttle(actionType, path4, timeout) {
224234
224457
  if (!this._throttled.has(actionType)) {
224235
224458
  this._throttled.set(actionType, new Map);
224236
224459
  }
224237
224460
  const action = this._throttled.get(actionType);
224238
224461
  if (!action)
224239
224462
  throw new Error("invalid throttle");
224240
- const actionPath = action.get(path3);
224463
+ const actionPath = action.get(path4);
224241
224464
  if (actionPath) {
224242
224465
  actionPath.count++;
224243
224466
  return false;
224244
224467
  }
224245
224468
  let timeoutObject;
224246
224469
  const clear = () => {
224247
- const item = action.get(path3);
224470
+ const item = action.get(path4);
224248
224471
  const count = item ? item.count : 0;
224249
- action.delete(path3);
224472
+ action.delete(path4);
224250
224473
  clearTimeout(timeoutObject);
224251
224474
  if (item)
224252
224475
  clearTimeout(item.timeoutObject);
@@ -224254,50 +224477,50 @@ class FSWatcher extends EventEmitter2 {
224254
224477
  };
224255
224478
  timeoutObject = setTimeout(clear, timeout);
224256
224479
  const thr = { timeoutObject, clear, count: 0 };
224257
- action.set(path3, thr);
224480
+ action.set(path4, thr);
224258
224481
  return thr;
224259
224482
  }
224260
224483
  _incrReadyCount() {
224261
224484
  return this._readyCount++;
224262
224485
  }
224263
- _awaitWriteFinish(path3, threshold, event, awfEmit) {
224486
+ _awaitWriteFinish(path4, threshold, event, awfEmit) {
224264
224487
  const awf = this.options.awaitWriteFinish;
224265
224488
  if (typeof awf !== "object")
224266
224489
  return;
224267
224490
  const pollInterval = awf.pollInterval;
224268
224491
  let timeoutHandler;
224269
- let fullPath = path3;
224270
- if (this.options.cwd && !sysPath2.isAbsolute(path3)) {
224271
- fullPath = sysPath2.join(this.options.cwd, path3);
224492
+ let fullPath = path4;
224493
+ if (this.options.cwd && !sysPath2.isAbsolute(path4)) {
224494
+ fullPath = sysPath2.join(this.options.cwd, path4);
224272
224495
  }
224273
224496
  const now = new Date;
224274
224497
  const writes = this._pendingWrites;
224275
224498
  function awaitWriteFinishFn(prevStat) {
224276
224499
  statcb(fullPath, (err, curStat) => {
224277
- if (err || !writes.has(path3)) {
224500
+ if (err || !writes.has(path4)) {
224278
224501
  if (err && err.code !== "ENOENT")
224279
224502
  awfEmit(err);
224280
224503
  return;
224281
224504
  }
224282
224505
  const now2 = Number(new Date);
224283
224506
  if (prevStat && curStat.size !== prevStat.size) {
224284
- writes.get(path3).lastChange = now2;
224507
+ writes.get(path4).lastChange = now2;
224285
224508
  }
224286
- const pw = writes.get(path3);
224509
+ const pw = writes.get(path4);
224287
224510
  const df = now2 - pw.lastChange;
224288
224511
  if (df >= threshold) {
224289
- writes.delete(path3);
224512
+ writes.delete(path4);
224290
224513
  awfEmit(undefined, curStat);
224291
224514
  } else {
224292
224515
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
224293
224516
  }
224294
224517
  });
224295
224518
  }
224296
- if (!writes.has(path3)) {
224297
- writes.set(path3, {
224519
+ if (!writes.has(path4)) {
224520
+ writes.set(path4, {
224298
224521
  lastChange: now,
224299
224522
  cancelWait: () => {
224300
- writes.delete(path3);
224523
+ writes.delete(path4);
224301
224524
  clearTimeout(timeoutHandler);
224302
224525
  return event;
224303
224526
  }
@@ -224305,8 +224528,8 @@ class FSWatcher extends EventEmitter2 {
224305
224528
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
224306
224529
  }
224307
224530
  }
224308
- _isIgnored(path3, stats) {
224309
- if (this.options.atomic && DOT_RE.test(path3))
224531
+ _isIgnored(path4, stats) {
224532
+ if (this.options.atomic && DOT_RE.test(path4))
224310
224533
  return true;
224311
224534
  if (!this._userIgnored) {
224312
224535
  const { cwd } = this.options;
@@ -224316,13 +224539,13 @@ class FSWatcher extends EventEmitter2 {
224316
224539
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
224317
224540
  this._userIgnored = anymatch(list, undefined);
224318
224541
  }
224319
- return this._userIgnored(path3, stats);
224542
+ return this._userIgnored(path4, stats);
224320
224543
  }
224321
- _isntIgnored(path3, stat4) {
224322
- return !this._isIgnored(path3, stat4);
224544
+ _isntIgnored(path4, stat4) {
224545
+ return !this._isIgnored(path4, stat4);
224323
224546
  }
224324
- _getWatchHelpers(path3) {
224325
- return new WatchHelper(path3, this.options.followSymlinks, this);
224547
+ _getWatchHelpers(path4) {
224548
+ return new WatchHelper(path4, this.options.followSymlinks, this);
224326
224549
  }
224327
224550
  _getWatchedDir(directory) {
224328
224551
  const dir = sysPath2.resolve(directory);
@@ -224336,57 +224559,57 @@ class FSWatcher extends EventEmitter2 {
224336
224559
  return Boolean(Number(stats.mode) & 256);
224337
224560
  }
224338
224561
  _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))
224562
+ const path4 = sysPath2.join(directory, item);
224563
+ const fullPath = sysPath2.resolve(path4);
224564
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path4) || this._watched.has(fullPath);
224565
+ if (!this._throttle("remove", path4, 100))
224343
224566
  return;
224344
224567
  if (!isDirectory && this._watched.size === 1) {
224345
224568
  this.add(directory, item, true);
224346
224569
  }
224347
- const wp = this._getWatchedDir(path3);
224570
+ const wp = this._getWatchedDir(path4);
224348
224571
  const nestedDirectoryChildren = wp.getChildren();
224349
- nestedDirectoryChildren.forEach((nested) => this._remove(path3, nested));
224572
+ nestedDirectoryChildren.forEach((nested) => this._remove(path4, nested));
224350
224573
  const parent = this._getWatchedDir(directory);
224351
224574
  const wasTracked = parent.has(item);
224352
224575
  parent.remove(item);
224353
224576
  if (this._symlinkPaths.has(fullPath)) {
224354
224577
  this._symlinkPaths.delete(fullPath);
224355
224578
  }
224356
- let relPath = path3;
224579
+ let relPath = path4;
224357
224580
  if (this.options.cwd)
224358
- relPath = sysPath2.relative(this.options.cwd, path3);
224581
+ relPath = sysPath2.relative(this.options.cwd, path4);
224359
224582
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
224360
224583
  const event = this._pendingWrites.get(relPath).cancelWait();
224361
224584
  if (event === EVENTS.ADD)
224362
224585
  return;
224363
224586
  }
224364
- this._watched.delete(path3);
224587
+ this._watched.delete(path4);
224365
224588
  this._watched.delete(fullPath);
224366
224589
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
224367
- if (wasTracked && !this._isIgnored(path3))
224368
- this._emit(eventName, path3);
224369
- this._closePath(path3);
224590
+ if (wasTracked && !this._isIgnored(path4))
224591
+ this._emit(eventName, path4);
224592
+ this._closePath(path4);
224370
224593
  }
224371
- _closePath(path3) {
224372
- this._closeFile(path3);
224373
- const dir = sysPath2.dirname(path3);
224374
- this._getWatchedDir(dir).remove(sysPath2.basename(path3));
224594
+ _closePath(path4) {
224595
+ this._closeFile(path4);
224596
+ const dir = sysPath2.dirname(path4);
224597
+ this._getWatchedDir(dir).remove(sysPath2.basename(path4));
224375
224598
  }
224376
- _closeFile(path3) {
224377
- const closers = this._closers.get(path3);
224599
+ _closeFile(path4) {
224600
+ const closers = this._closers.get(path4);
224378
224601
  if (!closers)
224379
224602
  return;
224380
224603
  closers.forEach((closer) => closer());
224381
- this._closers.delete(path3);
224604
+ this._closers.delete(path4);
224382
224605
  }
224383
- _addPathCloser(path3, closer) {
224606
+ _addPathCloser(path4, closer) {
224384
224607
  if (!closer)
224385
224608
  return;
224386
- let list = this._closers.get(path3);
224609
+ let list = this._closers.get(path4);
224387
224610
  if (!list) {
224388
224611
  list = [];
224389
- this._closers.set(path3, list);
224612
+ this._closers.set(path4, list);
224390
224613
  }
224391
224614
  list.push(closer);
224392
224615
  }
@@ -224416,7 +224639,7 @@ function watch(paths, options = {}) {
224416
224639
  var esm_default = { watch, FSWatcher };
224417
224640
 
224418
224641
  // src/controller/watch-mode.controller.ts
224419
- import path9 from "path";
224642
+ import path10 from "path";
224420
224643
 
224421
224644
  // src/service/project_store.ts
224422
224645
  var import_client_s32 = __toESM(require_dist_cjs75(), 1);
@@ -224634,7 +224857,7 @@ class Mutex {
224634
224857
  // src/service/project_store.ts
224635
224858
  import crypto3 from "crypto";
224636
224859
  import * as fs7 from "fs";
224637
- import * as path8 from "path";
224860
+ import * as path9 from "path";
224638
224861
 
224639
224862
  // ../../node_modules/simple-git/dist/esm/index.js
224640
224863
  var import_file_exists = __toESM(require_dist11(), 1);
@@ -224672,8 +224895,8 @@ function pathspec(...paths) {
224672
224895
  cache.set(key, paths);
224673
224896
  return key;
224674
224897
  }
224675
- function isPathSpec(path3) {
224676
- return path3 instanceof String && cache.has(path3);
224898
+ function isPathSpec(path4) {
224899
+ return path4 instanceof String && cache.has(path4);
224677
224900
  }
224678
224901
  function toPaths(pathSpec) {
224679
224902
  return cache.get(pathSpec) || [];
@@ -224759,8 +224982,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = `
224759
224982
  function forEachLineWithContent(input, callback) {
224760
224983
  return toLinesWithContent(input, true).map((line) => callback(line));
224761
224984
  }
224762
- function folderExists(path3) {
224763
- return import_file_exists.exists(path3, import_file_exists.FOLDER);
224985
+ function folderExists(path4) {
224986
+ return import_file_exists.exists(path4, import_file_exists.FOLDER);
224764
224987
  }
224765
224988
  function append2(target, item) {
224766
224989
  if (Array.isArray(target)) {
@@ -225141,8 +225364,8 @@ function checkIsRepoRootTask() {
225141
225364
  commands,
225142
225365
  format: "utf-8",
225143
225366
  onError,
225144
- parser(path3) {
225145
- return /^\.(git)?$/.test(path3.trim());
225367
+ parser(path4) {
225368
+ return /^\.(git)?$/.test(path4.trim());
225146
225369
  }
225147
225370
  };
225148
225371
  }
@@ -225553,11 +225776,11 @@ function parseGrep(grep) {
225553
225776
  const paths = /* @__PURE__ */ new Set;
225554
225777
  const results = {};
225555
225778
  forEachLineWithContent(grep, (input) => {
225556
- const [path3, line, preview] = input.split(NULL);
225557
- paths.add(path3);
225558
- (results[path3] = results[path3] || []).push({
225779
+ const [path4, line, preview] = input.split(NULL);
225780
+ paths.add(path4);
225781
+ (results[path4] = results[path4] || []).push({
225559
225782
  line: asNumber(line),
225560
- path: path3,
225783
+ path: path4,
225561
225784
  preview
225562
225785
  });
225563
225786
  });
@@ -226219,14 +226442,14 @@ var init_hash_object = __esm({
226219
226442
  init_task();
226220
226443
  }
226221
226444
  });
226222
- function parseInit(bare, path3, text) {
226445
+ function parseInit(bare, path4, text) {
226223
226446
  const response = String(text).trim();
226224
226447
  let result;
226225
226448
  if (result = initResponseRegex.exec(response)) {
226226
- return new InitSummary(bare, path3, false, result[1]);
226449
+ return new InitSummary(bare, path4, false, result[1]);
226227
226450
  }
226228
226451
  if (result = reInitResponseRegex.exec(response)) {
226229
- return new InitSummary(bare, path3, true, result[1]);
226452
+ return new InitSummary(bare, path4, true, result[1]);
226230
226453
  }
226231
226454
  let gitDir = "";
226232
226455
  const tokens = response.split(" ");
@@ -226237,7 +226460,7 @@ function parseInit(bare, path3, text) {
226237
226460
  break;
226238
226461
  }
226239
226462
  }
226240
- return new InitSummary(bare, path3, /^re/i.test(response), gitDir);
226463
+ return new InitSummary(bare, path4, /^re/i.test(response), gitDir);
226241
226464
  }
226242
226465
  var InitSummary;
226243
226466
  var initResponseRegex;
@@ -226245,9 +226468,9 @@ var reInitResponseRegex;
226245
226468
  var init_InitSummary = __esm({
226246
226469
  "src/lib/responses/InitSummary.ts"() {
226247
226470
  InitSummary = class {
226248
- constructor(bare, path3, existing, gitDir) {
226471
+ constructor(bare, path4, existing, gitDir) {
226249
226472
  this.bare = bare;
226250
- this.path = path3;
226473
+ this.path = path4;
226251
226474
  this.existing = existing;
226252
226475
  this.gitDir = gitDir;
226253
226476
  }
@@ -226259,7 +226482,7 @@ var init_InitSummary = __esm({
226259
226482
  function hasBareCommand(command) {
226260
226483
  return command.includes(bareCommand);
226261
226484
  }
226262
- function initTask(bare = false, path3, customArgs) {
226485
+ function initTask(bare = false, path4, customArgs) {
226263
226486
  const commands = ["init", ...customArgs];
226264
226487
  if (bare && !hasBareCommand(commands)) {
226265
226488
  commands.splice(1, 0, bareCommand);
@@ -226268,7 +226491,7 @@ function initTask(bare = false, path3, customArgs) {
226268
226491
  commands,
226269
226492
  format: "utf-8",
226270
226493
  parser(text) {
226271
- return parseInit(commands.includes("--bare"), path3, text);
226494
+ return parseInit(commands.includes("--bare"), path4, text);
226272
226495
  }
226273
226496
  };
226274
226497
  }
@@ -226983,12 +227206,12 @@ var init_FileStatusSummary = __esm({
226983
227206
  "src/lib/responses/FileStatusSummary.ts"() {
226984
227207
  fromPathRegex = /^(.+)\0(.+)$/;
226985
227208
  FileStatusSummary = class {
226986
- constructor(path3, index, working_dir) {
226987
- this.path = path3;
227209
+ constructor(path4, index, working_dir) {
227210
+ this.path = path4;
226988
227211
  this.index = index;
226989
227212
  this.working_dir = working_dir;
226990
227213
  if (index === "R" || working_dir === "R") {
226991
- const detail = fromPathRegex.exec(path3) || [null, path3, path3];
227214
+ const detail = fromPathRegex.exec(path4) || [null, path4, path4];
226992
227215
  this.from = detail[2] || "";
226993
227216
  this.path = detail[1] || "";
226994
227217
  }
@@ -227019,14 +227242,14 @@ function splitLine(result, lineStr) {
227019
227242
  default:
227020
227243
  return;
227021
227244
  }
227022
- function data(index, workingDir, path3) {
227245
+ function data(index, workingDir, path4) {
227023
227246
  const raw = `${index}${workingDir}`;
227024
227247
  const handler = parsers6.get(raw);
227025
227248
  if (handler) {
227026
- handler(result, path3);
227249
+ handler(result, path4);
227027
227250
  }
227028
227251
  if (raw !== "##" && raw !== "!!") {
227029
- result.files.push(new FileStatusSummary(path3, index, workingDir));
227252
+ result.files.push(new FileStatusSummary(path4, index, workingDir));
227030
227253
  }
227031
227254
  }
227032
227255
  }
@@ -227257,8 +227480,8 @@ var init_simple_git_api = __esm({
227257
227480
  }
227258
227481
  return this._runTask(configurationErrorTask("Git.cwd: workingDirectory must be supplied as a string"), next);
227259
227482
  }
227260
- hashObject(path3, write) {
227261
- return this._runTask(hashObjectTask(path3, write === true), trailingFunctionArgument(arguments));
227483
+ hashObject(path4, write) {
227484
+ return this._runTask(hashObjectTask(path4, write === true), trailingFunctionArgument(arguments));
227262
227485
  }
227263
227486
  init(bare) {
227264
227487
  return this._runTask(initTask(bare === true, this._executor.cwd, getTrailingOptions(arguments)), trailingFunctionArgument(arguments));
@@ -227835,8 +228058,8 @@ __export2(sub_module_exports, {
227835
228058
  subModuleTask: () => subModuleTask,
227836
228059
  updateSubModuleTask: () => updateSubModuleTask
227837
228060
  });
227838
- function addSubModuleTask(repo, path3) {
227839
- return subModuleTask(["add", repo, path3]);
228061
+ function addSubModuleTask(repo, path4) {
228062
+ return subModuleTask(["add", repo, path4]);
227840
228063
  }
227841
228064
  function initSubModuleTask(customArgs) {
227842
228065
  return subModuleTask(["init", ...customArgs]);
@@ -228104,8 +228327,8 @@ var require_git = __commonJS2({
228104
228327
  }
228105
228328
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
228106
228329
  };
228107
- Git2.prototype.submoduleAdd = function(repo, path3, then) {
228108
- return this._runTask(addSubModuleTask2(repo, path3), trailingFunctionArgument2(arguments));
228330
+ Git2.prototype.submoduleAdd = function(repo, path4, then) {
228331
+ return this._runTask(addSubModuleTask2(repo, path4), trailingFunctionArgument2(arguments));
228109
228332
  };
228110
228333
  Git2.prototype.submoduleUpdate = function(args, then) {
228111
228334
  return this._runTask(updateSubModuleTask2(getTrailingOptions2(arguments, true)), trailingFunctionArgument2(arguments));
@@ -228621,7 +228844,7 @@ import { Writable } from "stream";
228621
228844
 
228622
228845
  // src/config.ts
228623
228846
  import fs2 from "fs";
228624
- import path3 from "path";
228847
+ import path4 from "path";
228625
228848
  function substituteEnvVars(value) {
228626
228849
  const envVarPattern = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
228627
228850
  return value.replace(envVarPattern, (_match, varName) => {
@@ -228649,7 +228872,7 @@ function processConfigValue(value) {
228649
228872
  return value;
228650
228873
  }
228651
228874
  var getPublisherConfig = (serverRoot) => {
228652
- const publisherConfigPath = path3.join(serverRoot, PUBLISHER_CONFIG_NAME);
228875
+ const publisherConfigPath = path4.join(serverRoot, PUBLISHER_CONFIG_NAME);
228653
228876
  if (!fs2.existsSync(publisherConfigPath)) {
228654
228877
  return {
228655
228878
  frozenConfig: false,
@@ -228871,7 +229094,7 @@ function registerHealthEndpoints(app) {
228871
229094
 
228872
229095
  // src/storage/duckdb/DuckDBConnection.ts
228873
229096
  import duckdb from "duckdb";
228874
- import * as path4 from "path";
229097
+ import * as path5 from "path";
228875
229098
 
228876
229099
  class DuckDBConnection2 {
228877
229100
  db = null;
@@ -228879,7 +229102,7 @@ class DuckDBConnection2 {
228879
229102
  dbPath;
228880
229103
  mutex = new Mutex;
228881
229104
  constructor(dbPath) {
228882
- this.dbPath = dbPath || path4.join(process.cwd(), "publisher.db");
229105
+ this.dbPath = dbPath || path5.join(process.cwd(), "publisher.db");
228883
229106
  }
228884
229107
  async initialize() {
228885
229108
  return new Promise((resolve3, reject) => {
@@ -229970,20 +230193,20 @@ class StorageManager {
229970
230193
  }
229971
230194
 
229972
230195
  // src/service/project.ts
229973
- import { FixedConnectionMap as FixedConnectionMap2, MalloyError as MalloyError3, Runtime as Runtime2 } from "@malloydata/malloy";
230196
+ import { MalloyError as MalloyError3, Runtime as Runtime2 } from "@malloydata/malloy";
229974
230197
  import * as fs6 from "fs";
229975
- import * as path7 from "path";
230198
+ import * as path8 from "path";
229976
230199
 
229977
230200
  // src/utils.ts
229978
230201
  import * as fs3 from "fs";
229979
230202
  import { fileURLToPath } from "url";
229980
230203
  var URL_READER = {
229981
230204
  readURL: (url2) => {
229982
- let path5 = url2.toString();
230205
+ let path6 = url2.toString();
229983
230206
  if (url2.protocol == "file:") {
229984
- path5 = fileURLToPath(url2);
230207
+ path6 = fileURLToPath(url2);
229985
230208
  }
229986
- return fs3.promises.readFile(path5, "utf8");
230209
+ return fs3.promises.readFile(path6, "utf8");
229987
230210
  }
229988
230211
  };
229989
230212
 
@@ -229991,11 +230214,15 @@ var URL_READER = {
229991
230214
  var import_api3 = __toESM(require_src(), 1);
229992
230215
  var import_recursive_readdir = __toESM(require_recursive_readdir(), 1);
229993
230216
  import * as fs5 from "fs/promises";
229994
- import * as path6 from "path";
230217
+ import * as path7 from "path";
229995
230218
  import { DuckDBConnection as DuckDBConnection3 } from "@malloydata/db-duckdb";
230219
+ import"@malloydata/db-duckdb/native";
229996
230220
  import {
229997
230221
  ConnectionRuntime,
229998
- EmptyURLReader
230222
+ EmptyURLReader,
230223
+ FixedConnectionMap as FixedConnectionMap2,
230224
+ contextOverlay as contextOverlay2,
230225
+ MalloyConfig as MalloyConfig3
229999
230226
  } from "@malloydata/malloy";
230000
230227
 
230001
230228
  // src/service/model.ts
@@ -230004,6 +230231,7 @@ import {
230004
230231
  API,
230005
230232
  FixedConnectionMap,
230006
230233
  isSourceDef,
230234
+ MalloyConfig as MalloyConfig2,
230007
230235
  MalloyError as MalloyError2,
230008
230236
  modelDefToModelInfo,
230009
230237
  Runtime
@@ -230014,8 +230242,7 @@ import {
230014
230242
  } from "@malloydata/malloy-sql";
230015
230243
  import { createRequire as createRequire2 } from "module";
230016
230244
  import * as fs4 from "fs/promises";
230017
- import * as path5 from "path";
230018
- import { fileURLToPath as fileURLToPath2 } from "url";
230245
+ import * as path6 from "path";
230019
230246
 
230020
230247
  // src/data_styles.ts
230021
230248
  function compileDataStyles(styles) {
@@ -230301,8 +230528,8 @@ class Model {
230301
230528
  const arrowMatch = query.match(/^\s*(\w+)\s*->/m);
230302
230529
  return runMatch?.[1] ?? arrowMatch?.[1];
230303
230530
  }
230304
- static async create(packageName, packagePath, modelPath, connections, options) {
230305
- const { runtime, modelURL, importBaseURL, dataStyles, modelType } = await Model.getModelRuntime(packagePath, modelPath, connections, options);
230531
+ static async create(packageName, packagePath, modelPath, malloyConfig, options) {
230532
+ const { runtime, modelURL, importBaseURL, dataStyles, modelType } = await Model.getModelRuntime(packagePath, modelPath, malloyConfig, options);
230306
230533
  try {
230307
230534
  const { modelMaterializer, runnableNotebookCells } = await Model.getModelMaterializer(runtime, importBaseURL, modelURL, modelPath);
230308
230535
  let modelDef = undefined;
@@ -230625,8 +230852,8 @@ run: ${sourceName ? sourceName + "->" : ""}${queryName}`;
230625
230852
  newSources: cell.newSources?.map((source) => JSON.stringify(source))
230626
230853
  };
230627
230854
  }
230628
- static async getModelRuntime(packagePath, modelPath, connections, options) {
230629
- const fullModelPath = path5.join(packagePath, modelPath);
230855
+ static async getModelRuntime(packagePath, modelPath, malloyConfig, options) {
230856
+ const fullModelPath = path6.join(packagePath, modelPath);
230630
230857
  try {
230631
230858
  if (!(await fs4.stat(fullModelPath)).isFile()) {
230632
230859
  throw new ModelNotFoundError(`${modelPath} is not a file.`);
@@ -230644,26 +230871,24 @@ run: ${sourceName ? sourceName + "->" : ""}${queryName}`;
230644
230871
  }
230645
230872
  const modelURL = new URL(`file://${fullModelPath}`);
230646
230873
  const baseUrl = new URL(".", modelURL);
230647
- const fileUrl = new URL(baseUrl.pathname, "file:");
230648
- const workingDirectory = fileURLToPath2(fileUrl);
230649
230874
  const importBaseURL = new URL(baseUrl.pathname + "/", "file:");
230650
230875
  const urlReader = new HackyDataStylesAccumulator(URL_READER);
230651
- const duckdbConnection = connections.get("duckdb");
230652
- await duckdbConnection.runSQL(`SET FILE_SEARCH_PATH='${workingDirectory}';`);
230653
- const runtimeOptions = {
230876
+ const runtime = new Runtime({
230654
230877
  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);
230878
+ config: Model.toMalloyConfig(malloyConfig),
230879
+ buildManifest: options?.buildManifest ? { entries: options.buildManifest, strict: false } : undefined
230880
+ });
230664
230881
  const dataStyles = urlReader.getHackyAccumulatedDataStyles();
230665
230882
  return { runtime, modelURL, importBaseURL, dataStyles, modelType };
230666
230883
  }
230884
+ static toMalloyConfig(input) {
230885
+ if (input instanceof MalloyConfig2) {
230886
+ return input;
230887
+ }
230888
+ const malloyConfig = new MalloyConfig2({ connections: {} });
230889
+ malloyConfig.wrapConnections(() => new FixedConnectionMap(input, "duckdb"));
230890
+ return malloyConfig;
230891
+ }
230667
230892
  static getQueries(modelPath, modelDef) {
230668
230893
  const isNamedQuery = (object) => object.type === "query";
230669
230894
  return Object.values(modelDef.contents).filter(isNamedQuery).map((queryObj) => ({
@@ -230841,7 +231066,7 @@ run: ${sourceName ? sourceName + "->" : ""}${queryName}`;
230841
231066
  return this.modelType;
230842
231067
  }
230843
231068
  async getFileText(packagePath) {
230844
- const fullPath = path5.join(packagePath, this.modelPath);
231069
+ const fullPath = path6.join(packagePath, this.modelPath);
230845
231070
  try {
230846
231071
  return await fs4.readFile(fullPath, "utf8");
230847
231072
  } catch {
@@ -230860,22 +231085,22 @@ class Package {
230860
231085
  databases;
230861
231086
  models = new Map;
230862
231087
  packagePath;
230863
- connections = new Map;
231088
+ malloyConfig;
230864
231089
  static meter = import_api3.metrics.getMeter("publisher");
230865
231090
  static packageLoadHistogram = this.meter.createHistogram("malloy_package_load_duration", {
230866
231091
  description: "Time taken to load a Malloy package",
230867
231092
  unit: "ms"
230868
231093
  });
230869
- constructor(projectName, packageName, packagePath, packageMetadata, databases, models, connections = new Map) {
231094
+ constructor(projectName, packageName, packagePath, packageMetadata, databases, models, malloyConfig = new MalloyConfig3({ connections: {} })) {
230870
231095
  this.projectName = projectName;
230871
231096
  this.packageName = packageName;
230872
231097
  this.packagePath = packagePath;
230873
231098
  this.packageMetadata = packageMetadata;
230874
231099
  this.databases = databases;
230875
231100
  this.models = models;
230876
- this.connections = connections;
231101
+ this.malloyConfig = malloyConfig;
230877
231102
  }
230878
- static async create(projectName, packageName, packagePath, projectConnections) {
231103
+ static async create(projectName, packageName, packagePath, projectMalloyConfig) {
230879
231104
  const startTime = performance.now();
230880
231105
  await Package.validatePackageManifestExistsOrThrowError(packagePath);
230881
231106
  const manifestValidationTime = performance.now();
@@ -230898,10 +231123,8 @@ class Package {
230898
231123
  databaseCount: databases.length,
230899
231124
  duration: formatDuration(databasesTime - packageConfigTime)
230900
231125
  });
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);
231126
+ const malloyConfig = Package.buildPackageMalloyConfig(packagePath, typeof projectMalloyConfig === "function" ? projectMalloyConfig : () => Package.toMalloyConfig(projectMalloyConfig));
231127
+ const models = await Package.loadModels(packageName, packagePath, malloyConfig);
230905
231128
  const modelsTime = performance.now();
230906
231129
  logger.info("Models loaded", {
230907
231130
  packageName,
@@ -230935,7 +231158,7 @@ class Package {
230935
231158
  packageName,
230936
231159
  duration: formatDuration(executionTime)
230937
231160
  });
230938
- return new Package(projectName, packageName, packagePath, packageConfig, databases, models, connections);
231161
+ return new Package(projectName, packageName, packagePath, packageConfig, databases, models, malloyConfig);
230939
231162
  } catch (error) {
230940
231163
  logger.error(`Error loading package ${packageName}`, { error });
230941
231164
  console.error(error);
@@ -230962,9 +231185,6 @@ class Package {
230962
231185
  getPackageName() {
230963
231186
  return this.packageName;
230964
231187
  }
230965
- getPackagePath() {
230966
- return this.packagePath;
230967
- }
230968
231188
  getPackageMetadata() {
230969
231189
  return this.packageMetadata;
230970
231190
  }
@@ -230974,6 +231194,15 @@ class Package {
230974
231194
  getModel(modelPath) {
230975
231195
  return this.models.get(modelPath);
230976
231196
  }
231197
+ async getMalloyConnection(connectionName) {
231198
+ return this.malloyConfig.connections.lookupConnection(connectionName);
231199
+ }
231200
+ getMalloyConfig() {
231201
+ return this.malloyConfig;
231202
+ }
231203
+ getPackagePath() {
231204
+ return this.packagePath;
231205
+ }
230977
231206
  getModelPaths() {
230978
231207
  return Array.from(this.models.keys());
230979
231208
  }
@@ -230984,23 +231213,13 @@ class Package {
230984
231213
  modelCount: modelPaths.length,
230985
231214
  manifestEntryCount: Object.keys(buildManifest).length
230986
231215
  });
230987
- const reloaded = await Promise.all(modelPaths.map((modelPath) => Model.create(this.packageName, this.packagePath, modelPath, this.connections, { buildManifest })));
231216
+ const reloaded = await Promise.all(modelPaths.map((modelPath) => Model.create(this.packageName, this.packagePath, modelPath, this.malloyConfig, { buildManifest })));
230988
231217
  const nextModels = new Map;
230989
231218
  for (const model of reloaded) {
230990
231219
  nextModels.set(model.getPath(), model);
230991
231220
  }
230992
231221
  this.models = nextModels;
230993
231222
  }
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
231223
  async getModelFileText(modelPath) {
231005
231224
  const model = this.getModel(modelPath);
231006
231225
  if (!model) {
@@ -231045,11 +231264,40 @@ class Package {
231045
231264
  };
231046
231265
  }));
231047
231266
  }
231048
- static async loadModels(packageName, packagePath, connections) {
231267
+ static async loadModels(packageName, packagePath, malloyConfig) {
231049
231268
  const modelPaths = await Package.getModelPaths(packagePath);
231050
- const models = await Promise.all(modelPaths.map((modelPath) => Model.create(packageName, packagePath, modelPath, connections)));
231269
+ const models = await Promise.all(modelPaths.map((modelPath) => Model.create(packageName, packagePath, modelPath, malloyConfig)));
231051
231270
  return new Map(models.map((model) => [model.getPath(), model]));
231052
231271
  }
231272
+ static buildPackageMalloyConfig(packagePath, getProjectMalloyConfig) {
231273
+ const malloyConfig = new MalloyConfig3({
231274
+ connections: {
231275
+ duckdb: {
231276
+ is: "duckdb",
231277
+ databasePath: ":memory:"
231278
+ }
231279
+ }
231280
+ }, {
231281
+ config: contextOverlay2({ rootDirectory: packagePath })
231282
+ });
231283
+ malloyConfig.wrapConnections((base) => ({
231284
+ lookupConnection: async (name) => {
231285
+ if (!name || name === "duckdb") {
231286
+ return base.lookupConnection(name);
231287
+ }
231288
+ return getProjectMalloyConfig().connections.lookupConnection(name);
231289
+ }
231290
+ }));
231291
+ return malloyConfig;
231292
+ }
231293
+ static toMalloyConfig(input) {
231294
+ if (input instanceof MalloyConfig3) {
231295
+ return input;
231296
+ }
231297
+ const malloyConfig = new MalloyConfig3({ connections: {} });
231298
+ malloyConfig.wrapConnections(() => new FixedConnectionMap2(input, "duckdb"));
231299
+ return malloyConfig;
231300
+ }
231053
231301
  static async getModelPaths(packagePath) {
231054
231302
  let files = undefined;
231055
231303
  try {
@@ -231059,11 +231307,11 @@ class Package {
231059
231307
  throw new PackageNotFoundError(`Package config for ${packagePath} does not exist.`);
231060
231308
  }
231061
231309
  return files.map((fullPath) => {
231062
- return path6.relative(packagePath, fullPath).replace(/\\/g, "/");
231310
+ return path7.relative(packagePath, fullPath).replace(/\\/g, "/");
231063
231311
  }).filter((modelPath) => modelPath.endsWith(MODEL_FILE_SUFFIX) || modelPath.endsWith(NOTEBOOK_FILE_SUFFIX));
231064
231312
  }
231065
231313
  static async validatePackageManifestExistsOrThrowError(packagePath) {
231066
- const packageConfigPath = path6.join(packagePath, PACKAGE_MANIFEST_NAME);
231314
+ const packageConfigPath = path7.join(packagePath, PACKAGE_MANIFEST_NAME);
231067
231315
  try {
231068
231316
  await fs5.stat(packageConfigPath);
231069
231317
  } catch {
@@ -231072,7 +231320,7 @@ class Package {
231072
231320
  }
231073
231321
  }
231074
231322
  static async readPackageConfig(packagePath) {
231075
- const packageConfigPath = path6.join(packagePath, PACKAGE_MANIFEST_NAME);
231323
+ const packageConfigPath = path7.join(packagePath, PACKAGE_MANIFEST_NAME);
231076
231324
  const packageConfigContents = await fs5.readFile(packageConfigPath);
231077
231325
  const packageManifest = JSON.parse(packageConfigContents.toString());
231078
231326
  return {
@@ -231094,11 +231342,11 @@ class Package {
231094
231342
  let files = undefined;
231095
231343
  files = await import_recursive_readdir.default(packagePath);
231096
231344
  return files.map((fullPath) => {
231097
- return path6.relative(packagePath, fullPath).replace(/\\/g, "/");
231345
+ return path7.relative(packagePath, fullPath).replace(/\\/g, "/");
231098
231346
  }).filter((modelPath) => modelPath.endsWith(".parquet") || modelPath.endsWith(".csv"));
231099
231347
  }
231100
231348
  static async getDatabaseInfo(packagePath, databasePath) {
231101
- const fullPath = path6.join(packagePath, databasePath);
231349
+ const fullPath = path7.join(packagePath, databasePath);
231102
231350
  const runtime = new ConnectionRuntime({
231103
231351
  urlReader: new EmptyURLReader,
231104
231352
  connections: [new DuckDBConnection3("duckdb")]
@@ -231127,19 +231375,23 @@ class Package {
231127
231375
  }
231128
231376
 
231129
231377
  // src/service/project.ts
231378
+ var RETIRED_CONNECTION_DRAIN_MS = 30000;
231379
+
231130
231380
  class Project {
231131
231381
  packages = new Map;
231132
231382
  packageMutexes = new Map;
231133
231383
  packageStatuses = new Map;
231134
- malloyConnections;
231384
+ malloyConfig;
231385
+ connectionMutex = new Mutex;
231386
+ retiredConnectionGenerations = new Set;
231135
231387
  apiConnections;
231136
231388
  projectPath;
231137
231389
  projectName;
231138
231390
  metadata;
231139
- constructor(projectName, projectPath, malloyConnections, apiConnections) {
231391
+ constructor(projectName, projectPath, malloyConfig, apiConnections) {
231140
231392
  this.projectName = projectName;
231141
231393
  this.projectPath = projectPath;
231142
- this.malloyConnections = malloyConnections;
231394
+ this.malloyConfig = malloyConfig;
231143
231395
  this.apiConnections = apiConnections;
231144
231396
  this.metadata = {
231145
231397
  resource: `${API_PREFIX}/projects/${this.projectName}`,
@@ -231151,7 +231403,7 @@ class Project {
231151
231403
  async writeProjectReadme(readme) {
231152
231404
  if (readme === undefined)
231153
231405
  return;
231154
- const readmePath = path7.join(this.projectPath, "README.md");
231406
+ const readmePath = path8.join(this.projectPath, "README.md");
231155
231407
  try {
231156
231408
  await fs6.promises.writeFile(readmePath, readme, "utf-8");
231157
231409
  logger.info(`Updated README.md for project ${this.projectName}`);
@@ -231166,15 +231418,16 @@ class Project {
231166
231418
  await this.writeProjectReadme(payload.readme);
231167
231419
  }
231168
231420
  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
231421
+ const payloadConnections = payload.connections;
231422
+ await this.runConnectionUpdateExclusive(async () => {
231423
+ logger.info(`Updating ${payloadConnections.length} connections for project ${this.projectName}`);
231424
+ const isUpdateConnectionRequest = true;
231425
+ const nextMalloyConfig = buildProjectMalloyConfig(payloadConnections, this.projectPath, isUpdateConnectionRequest);
231426
+ this.updateConnections(nextMalloyConfig);
231427
+ logger.info(`Successfully updated connections for project ${this.projectName}`, {
231428
+ apiConnections: this.apiConnections.length,
231429
+ internalConnections: this.apiConnections.length
231430
+ });
231178
231431
  });
231179
231432
  }
231180
231433
  return this;
@@ -231184,18 +231437,17 @@ class Project {
231184
231437
  throw new ProjectNotFoundError(`Project path ${projectPath} not found`);
231185
231438
  }
231186
231439
  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
231440
+ const malloyConfig = buildProjectMalloyConfig(connections, projectPath);
231441
+ logger.info(`Loaded ${malloyConfig.apiConnections.length} connections for project ${projectName}`, {
231442
+ apiConnections: malloyConfig.apiConnections
231191
231443
  });
231192
- const project = new Project(projectName, projectPath, malloyConnections, apiConnections);
231444
+ const project = new Project(projectName, projectPath, malloyConfig, malloyConfig.apiConnections);
231193
231445
  return project;
231194
231446
  }
231195
231447
  async reloadProjectMetadata() {
231196
231448
  let readme = "";
231197
231449
  try {
231198
- readme = (await fs6.promises.readFile(path7.join(this.projectPath, README_NAME))).toString();
231450
+ readme = (await fs6.promises.readFile(path8.join(this.projectPath, README_NAME))).toString();
231199
231451
  } catch {}
231200
231452
  this.metadata = {
231201
231453
  ...this.metadata,
@@ -231206,10 +231458,10 @@ class Project {
231206
231458
  return this.metadata;
231207
231459
  }
231208
231460
  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")}`;
231461
+ const modelDir = path8.dirname(path8.join(this.projectPath, packageName, modelName));
231462
+ const virtualUri = `file://${path8.join(modelDir, "__compile_check.malloy")}`;
231211
231463
  const virtualUrl = new URL(virtualUri);
231212
- const modelPath = path7.join(this.projectPath, packageName, modelName);
231464
+ const modelPath = path8.join(this.projectPath, packageName, modelName);
231213
231465
  let modelContent = "";
231214
231466
  try {
231215
231467
  modelContent = await fs6.promises.readFile(modelPath, "utf8");
@@ -231224,9 +231476,10 @@ ${source}` : source;
231224
231476
  return URL_READER.readURL(url2);
231225
231477
  }
231226
231478
  };
231479
+ const pkg = await this.getPackage(packageName);
231227
231480
  const runtime = new Runtime2({
231228
231481
  urlReader: interceptingReader,
231229
- connections: new FixedConnectionMap2(this.malloyConnections, "duckdb")
231482
+ config: pkg.getMalloyConfig()
231230
231483
  });
231231
231484
  try {
231232
231485
  const modelMaterializer = runtime.loadModel(virtualUrl);
@@ -231256,12 +231509,40 @@ ${source}` : source;
231256
231509
  }
231257
231510
  return connection;
231258
231511
  }
231259
- getMalloyConnection(connectionName) {
231260
- const connection = this.malloyConnections.get(connectionName);
231261
- if (!connection) {
231262
- throw new ConnectionNotFoundError(`Connection ${connectionName} not found`);
231512
+ async getMalloyConnection(connectionName) {
231513
+ return this.malloyConfig.malloyConfig.connections.lookupConnection(connectionName);
231514
+ }
231515
+ getProjectMalloyConfig() {
231516
+ return this.malloyConfig.malloyConfig;
231517
+ }
231518
+ async runConnectionUpdateExclusive(fn) {
231519
+ return this.connectionMutex.runExclusive(fn);
231520
+ }
231521
+ retireConnectionGeneration(label, releaseConnections) {
231522
+ const generation = {
231523
+ label,
231524
+ releaseConnections
231525
+ };
231526
+ generation.timer = setTimeout(() => {
231527
+ this.releaseRetiredConnectionGeneration(generation);
231528
+ }, RETIRED_CONNECTION_DRAIN_MS);
231529
+ generation.timer.unref?.();
231530
+ this.retiredConnectionGenerations.add(generation);
231531
+ }
231532
+ async releaseRetiredConnectionGeneration(generation) {
231533
+ if (!this.retiredConnectionGenerations.delete(generation))
231534
+ return;
231535
+ if (generation.timer) {
231536
+ clearTimeout(generation.timer);
231263
231537
  }
231264
- return connection;
231538
+ try {
231539
+ await generation.releaseConnections();
231540
+ } catch (error) {
231541
+ logger.error(`Error releasing retired connection generation ${generation.label}`, { error });
231542
+ }
231543
+ }
231544
+ async releaseAllRetiredConnectionGenerations() {
231545
+ await Promise.all([...this.retiredConnectionGenerations].map((generation) => this.releaseRetiredConnectionGeneration(generation)));
231265
231546
  }
231266
231547
  async listPackages() {
231267
231548
  logger.debug("Listing packages", { projectPath: this.projectPath });
@@ -231316,8 +231597,11 @@ ${source}` : source;
231316
231597
  this.setPackageStatus(packageName, "loading" /* LOADING */);
231317
231598
  try {
231318
231599
  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);
231600
+ const packagePath = path8.join(this.projectPath, packageName);
231601
+ const _package2 = await Package.create(this.projectName, packageName, packagePath, () => this.malloyConfig.malloyConfig);
231602
+ if (existingPackage !== undefined && reload) {
231603
+ this.retireConnectionGeneration(`package ${packageName}`, () => existingPackage.getMalloyConfig().releaseConnections());
231604
+ }
231321
231605
  this.packages.set(packageName, _package2);
231322
231606
  this.setPackageStatus(packageName, "serving" /* SERVING */);
231323
231607
  logger.debug(`Successfully loaded package ${packageName}`);
@@ -231331,17 +231615,17 @@ ${source}` : source;
231331
231615
  });
231332
231616
  }
231333
231617
  async addPackage(packageName) {
231334
- const packagePath = path7.join(this.projectPath, packageName);
231618
+ const packagePath = path8.join(this.projectPath, packageName);
231335
231619
  if (!await fs6.promises.access(packagePath).then(() => true).catch(() => false) || !(await fs6.promises.stat(packagePath))?.isDirectory()) {
231336
231620
  throw new PackageNotFoundError(`Package ${packageName} not found`);
231337
231621
  }
231338
231622
  logger.info(`Adding package ${packageName} to project ${this.projectName}`, {
231339
231623
  packagePath,
231340
- malloyConnections: this.malloyConnections
231624
+ malloyConfig: this.malloyConfig.malloyConfig
231341
231625
  });
231342
231626
  this.setPackageStatus(packageName, "loading" /* LOADING */);
231343
231627
  try {
231344
- this.packages.set(packageName, await Package.create(this.projectName, packageName, packagePath, this.malloyConnections));
231628
+ this.packages.set(packageName, await Package.create(this.projectName, packageName, packagePath, () => this.malloyConfig.malloyConfig));
231345
231629
  } catch (error) {
231346
231630
  logger.error("Error adding package", { error });
231347
231631
  this.deletePackageStatus(packageName);
@@ -231351,8 +231635,8 @@ ${source}` : source;
231351
231635
  return this.packages.get(packageName);
231352
231636
  }
231353
231637
  async writePackageManifest(packageName, metadata) {
231354
- const packagePath = path7.join(this.projectPath, packageName);
231355
- const manifestPath = path7.join(packagePath, "publisher.json");
231638
+ const packagePath = path8.join(this.projectPath, packageName);
231639
+ const manifestPath = path8.join(packagePath, "publisher.json");
231356
231640
  try {
231357
231641
  let existingManifest = {};
231358
231642
  try {
@@ -231422,8 +231706,9 @@ ${source}` : source;
231422
231706
  } else if (packageStatus?.status === "serving" /* SERVING */) {
231423
231707
  this.setPackageStatus(packageName, "unloading" /* UNLOADING */);
231424
231708
  }
231709
+ await _package.getMalloyConfig().releaseConnections();
231425
231710
  try {
231426
- await fs6.promises.rm(path7.join(this.projectPath, packageName), {
231711
+ await fs6.promises.rm(path8.join(this.projectPath, packageName), {
231427
231712
  recursive: true,
231428
231713
  force: true
231429
231714
  });
@@ -231433,39 +231718,45 @@ ${source}` : source;
231433
231718
  this.packages.delete(packageName);
231434
231719
  this.packageStatuses.delete(packageName);
231435
231720
  }
231436
- updateConnections(malloyConnections, apiConnections) {
231437
- this.malloyConnections = malloyConnections;
231438
- this.apiConnections = apiConnections;
231721
+ updateConnections(malloyConfig, _apiConnections, afterPreviousRelease) {
231722
+ const previousMalloyConfig = this.malloyConfig;
231723
+ this.malloyConfig = malloyConfig;
231724
+ this.apiConnections = malloyConfig.apiConnections;
231725
+ if (previousMalloyConfig !== malloyConfig) {
231726
+ this.retireConnectionGeneration(`project ${this.projectName}`, async () => {
231727
+ await previousMalloyConfig.releaseConnections();
231728
+ await afterPreviousRelease?.();
231729
+ });
231730
+ } else {
231731
+ afterPreviousRelease?.();
231732
+ }
231439
231733
  }
231440
231734
  async deleteConnection(connectionName) {
231441
- this.malloyConnections.get(connectionName)?.close();
231442
- const isDeleted = this.malloyConnections.delete(connectionName);
231443
231735
  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
231736
  if (index !== -1) {
231451
231737
  this.apiConnections.splice(index, 1);
231452
231738
  }
231453
- if (isDeleted || index !== -1) {
231739
+ if (index !== -1) {
231454
231740
  logger.info(`Removed connection ${connectionName} from project ${this.projectName}`);
231455
231741
  } else {
231456
231742
  logger.warn(`Connection ${connectionName} not found in project ${this.projectName}`);
231457
231743
  }
231458
231744
  }
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 });
231745
+ async closeAllConnections() {
231746
+ const packageReleases = await Promise.allSettled(Array.from(this.packages.values(), (pkg) => pkg.getMalloyConfig().releaseConnections()));
231747
+ for (const result of packageReleases) {
231748
+ if (result.status === "rejected") {
231749
+ logger.error(`Error closing package connections for project ${this.projectName}`, { error: result.reason });
231466
231750
  }
231467
231751
  }
231468
- this.malloyConnections.clear();
231752
+ this.packages.clear();
231753
+ this.packageStatuses.clear();
231754
+ try {
231755
+ await this.malloyConfig.releaseConnections();
231756
+ } catch (error) {
231757
+ logger.error(`Error closing connections for project ${this.projectName}`, { error });
231758
+ }
231759
+ await this.releaseAllRetiredConnectionGenerations();
231469
231760
  this.apiConnections = [];
231470
231761
  logger.info(`Closed all connections for project ${this.projectName}`);
231471
231762
  }
@@ -231477,16 +231768,13 @@ ${source}` : source;
231477
231768
  };
231478
231769
  }
231479
231770
  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) => {
231771
+ const duckdbPath = path8.join(this.projectPath, `${connectionName}.duckdb`);
231772
+ try {
231773
+ await fs6.promises.rm(duckdbPath, { force: true });
231774
+ logger.info(`Removed DuckDB connection file ${connectionName} from project ${this.projectName}`);
231775
+ } catch (error) {
231488
231776
  logger.error(`Failed to remove DuckDB connection file ${connectionName} from project ${this.projectName}`, { error });
231489
- });
231777
+ }
231490
231778
  }
231491
231779
  async deleteDuckLakeConnection(connectionName) {
231492
231780
  await deleteDuckLakeConnectionFile(connectionName, this.projectPath);
@@ -231560,12 +231848,28 @@ class ProjectStore {
231560
231848
  const storageConfig = {
231561
231849
  type: "duckdb",
231562
231850
  duckdb: {
231563
- path: path8.join(serverRootPath, "publisher.db")
231851
+ path: path9.join(serverRootPath, "publisher.db")
231564
231852
  }
231565
231853
  };
231566
231854
  this.storageManager = new StorageManager(storageConfig);
231567
231855
  this.finishedInitialization = this.initialize();
231568
231856
  }
231857
+ async addConfiguredProject(project) {
231858
+ try {
231859
+ await this.addProject({
231860
+ name: project.name,
231861
+ resource: `${API_PREFIX}/projects/${project.name}`,
231862
+ connections: project.connections,
231863
+ packages: project.packages
231864
+ }, true);
231865
+ } catch (error) {
231866
+ this.logProjectInitializationError(project.name, error);
231867
+ }
231868
+ }
231869
+ logProjectInitializationError(projectName, error) {
231870
+ const label = projectName ? ` "${projectName}"` : "";
231871
+ logger.error(`Error initializing project${label}; skipping project`, this.extractErrorDataFromError(error));
231872
+ }
231569
231873
  async initialize() {
231570
231874
  const reInit = process.env.INITIALIZE_STORAGE === "true";
231571
231875
  const initialTime = performance.now();
@@ -231577,58 +231881,52 @@ class ProjectStore {
231577
231881
  const repository = this.storageManager.getRepository();
231578
231882
  if (reInit) {
231579
231883
  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);
231884
+ await this.addConfiguredProject(project);
231586
231885
  }));
231587
231886
  } else {
231588
231887
  const existingProjects = await repository.listProjects();
231589
231888
  if (existingProjects.length > 0) {
231590
231889
  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;
231890
+ try {
231891
+ const projectExists = await fs7.promises.access(dbProject.path).then(() => true).catch(() => false);
231892
+ if (!projectExists) {
231893
+ const projectConfig = projectManifest.projects.find((p) => p.name === dbProject.name);
231894
+ if (projectConfig) {
231895
+ const projectInstance2 = await this.addProject({
231896
+ name: projectConfig.name,
231897
+ resource: `${API_PREFIX}/projects/${projectConfig.name}`,
231898
+ connections: projectConfig.connections,
231899
+ packages: projectConfig.packages
231900
+ }, true);
231901
+ await repository.updateProject(dbProject.id, {
231902
+ path: projectInstance2.metadata.location
231903
+ });
231904
+ return projectInstance2.listPackages();
231905
+ } else {
231906
+ logger.error(`Project "${dbProject.name}" not found in config and files missing`);
231907
+ return;
231908
+ }
231608
231909
  }
231910
+ const connections = await repository.listConnections(dbProject.id);
231911
+ const projectInstance = await Project.create(dbProject.name, dbProject.path, connections.map((conn) => ({
231912
+ name: conn.name,
231913
+ type: conn.type,
231914
+ resource: `${API_PREFIX}/connections/${conn.name}`,
231915
+ ...conn.config
231916
+ })));
231917
+ const packages = await repository.listPackages(dbProject.id);
231918
+ packages.forEach((pkg) => {
231919
+ projectInstance.setPackageStatus(pkg.name, "serving" /* SERVING */);
231920
+ });
231921
+ this.projects.set(dbProject.name, projectInstance);
231922
+ return projectInstance.listPackages();
231923
+ } catch (error) {
231924
+ this.logProjectInitializationError(dbProject.name, error);
231609
231925
  }
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
231926
  }));
231624
231927
  } else {
231625
231928
  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);
231929
+ await this.addConfiguredProject(project);
231632
231930
  }));
231633
231931
  }
231634
231932
  }
@@ -231640,7 +231938,6 @@ class ProjectStore {
231640
231938
  markNotReady();
231641
231939
  const errorData = this.extractErrorDataFromError(error);
231642
231940
  logger.error("Error initializing project store", errorData);
231643
- process.exit(1);
231644
231941
  }
231645
231942
  }
231646
231943
  async addProjectToDatabase(project) {
@@ -231838,7 +232135,7 @@ class ProjectStore {
231838
232135
  const reInit = process.env.INITIALIZE_STORAGE === "true";
231839
232136
  await fs7.promises.mkdir(this.serverRootPath, { recursive: true });
231840
232137
  if (reInit) {
231841
- const uploadDocsPath2 = path8.join(this.serverRootPath, PUBLISHER_DATA_DIR);
232138
+ const uploadDocsPath2 = path9.join(this.serverRootPath, PUBLISHER_DATA_DIR);
231842
232139
  logger.info(`Reinitialization mode: Cleaning up upload documents path ${uploadDocsPath2}`);
231843
232140
  try {
231844
232141
  await fs7.promises.rm(uploadDocsPath2, {
@@ -231855,7 +232152,7 @@ class ProjectStore {
231855
232152
  } else {
231856
232153
  logger.info(`Using existing publisher path`);
231857
232154
  }
231858
- const uploadDocsPath = path8.join(this.serverRootPath, PUBLISHER_DATA_DIR);
232155
+ const uploadDocsPath = path9.join(this.serverRootPath, PUBLISHER_DATA_DIR);
231859
232156
  await fs7.promises.mkdir(uploadDocsPath, { recursive: true });
231860
232157
  }
231861
232158
  async listProjects(skipInitializationCheck = false) {
@@ -232021,7 +232318,7 @@ class ProjectStore {
232021
232318
  return;
232022
232319
  }
232023
232320
  const projectPath = project.metadata?.location;
232024
- project.closeAllConnections();
232321
+ await project.closeAllConnections();
232025
232322
  this.projects.delete(projectName);
232026
232323
  await this.deleteProjectFromDatabase(projectName);
232027
232324
  if (projectPath) {
@@ -232079,12 +232376,12 @@ class ProjectStore {
232079
232376
  const absoluteProjectPath = `${this.serverRootPath}/${PUBLISHER_DATA_DIR}/${projectName}`;
232080
232377
  await fs7.promises.mkdir(absoluteProjectPath, { recursive: true });
232081
232378
  if (project.readme) {
232082
- await fs7.promises.writeFile(path8.join(absoluteProjectPath, "README.md"), project.readme);
232379
+ await fs7.promises.writeFile(path9.join(absoluteProjectPath, "README.md"), project.readme);
232083
232380
  }
232084
232381
  return absoluteProjectPath;
232085
232382
  }
232086
232383
  isLocalPath(location) {
232087
- return location.startsWith("./") || location.startsWith("../") || location.startsWith("~/") || location.startsWith("/") || path8.isAbsolute(location);
232384
+ return location.startsWith("./") || location.startsWith("../") || location.startsWith("~/") || location.startsWith("/") || path9.isAbsolute(location);
232088
232385
  }
232089
232386
  isGitHubURL(location) {
232090
232387
  return location.startsWith("https://github.com/") || location.startsWith("git@github.com:");
@@ -232140,7 +232437,7 @@ class ProjectStore {
232140
232437
  if (githubInfo && githubInfo.packagePath) {
232141
232438
  const subPathMatch = _package.location.match(/\/tree\/[^/]+\/(.+)$/);
232142
232439
  if (subPathMatch) {
232143
- sourcePath = path8.join(tempDownloadPath, subPathMatch[1]);
232440
+ sourcePath = path9.join(tempDownloadPath, subPathMatch[1]);
232144
232441
  } else {
232145
232442
  sourcePath = tempDownloadPath;
232146
232443
  }
@@ -232151,7 +232448,7 @@ class ProjectStore {
232151
232448
  if (this.isLocalPath(_package.location)) {
232152
232449
  sourcePath = _package.location;
232153
232450
  } else {
232154
- sourcePath = path8.join(tempDownloadPath, groupedLocation);
232451
+ sourcePath = path9.join(tempDownloadPath, groupedLocation);
232155
232452
  }
232156
232453
  }
232157
232454
  const sourceExists = await fs7.promises.access(sourcePath).then(() => true).catch(() => false);
@@ -232227,7 +232524,7 @@ class ProjectStore {
232227
232524
  }
232228
232525
  }
232229
232526
  if (this.isLocalPath(location)) {
232230
- const packagePath = path8.isAbsolute(location) ? location : path8.join(this.serverRootPath, location);
232527
+ const packagePath = path9.isAbsolute(location) ? location : path9.join(this.serverRootPath, location);
232231
232528
  try {
232232
232529
  logger.info(`Mounting local directory at "${packagePath}" to "${targetPath}"`);
232233
232530
  await this.mountLocalDirectory(packagePath, targetPath, projectName, packageName);
@@ -232281,11 +232578,11 @@ class ProjectStore {
232281
232578
  }
232282
232579
  await Promise.all(files.map(async (file) => {
232283
232580
  const relativeFilePath = file.name.replace(prefix, "");
232284
- const absoluteFilePath = isCompressedFile ? absoluteDirPath : path8.join(absoluteDirPath, relativeFilePath);
232581
+ const absoluteFilePath = isCompressedFile ? absoluteDirPath : path9.join(absoluteDirPath, relativeFilePath);
232285
232582
  if (file.name.endsWith("/")) {
232286
232583
  return;
232287
232584
  }
232288
- await fs7.promises.mkdir(path8.dirname(absoluteFilePath), {
232585
+ await fs7.promises.mkdir(path9.dirname(absoluteFilePath), {
232289
232586
  recursive: true
232290
232587
  });
232291
232588
  return fs7.promises.writeFile(absoluteFilePath, await file.download());
@@ -232301,7 +232598,7 @@ class ProjectStore {
232301
232598
  const prefix = prefixParts.join("/");
232302
232599
  if (isCompressedFile) {
232303
232600
  const zipFilePath = `${absoluteDirPath}.zip`;
232304
- await fs7.promises.mkdir(path8.dirname(zipFilePath), {
232601
+ await fs7.promises.mkdir(path9.dirname(zipFilePath), {
232305
232602
  recursive: true
232306
232603
  });
232307
232604
  const command = new import_client_s32.GetObjectCommand({
@@ -232340,8 +232637,8 @@ class ProjectStore {
232340
232637
  if (!relativeFilePath || relativeFilePath.endsWith("/")) {
232341
232638
  return;
232342
232639
  }
232343
- const absoluteFilePath = path8.join(absoluteDirPath, relativeFilePath);
232344
- await fs7.promises.mkdir(path8.dirname(absoluteFilePath), {
232640
+ const absoluteFilePath = path9.join(absoluteDirPath, relativeFilePath);
232641
+ await fs7.promises.mkdir(path9.dirname(absoluteFilePath), {
232345
232642
  recursive: true
232346
232643
  });
232347
232644
  const command = new import_client_s32.GetObjectCommand({
@@ -232403,7 +232700,7 @@ class ProjectStore {
232403
232700
  logger.info(`Successfully cloned entire repository to: ${absoluteDirPath}`);
232404
232701
  return;
232405
232702
  }
232406
- const packageFullPath = path8.join(absoluteDirPath, cleanPackagePath);
232703
+ const packageFullPath = path9.join(absoluteDirPath, cleanPackagePath);
232407
232704
  const packageExists = await fs7.promises.access(packageFullPath).then(() => true).catch(() => false);
232408
232705
  if (!packageExists) {
232409
232706
  throw new Error(`Package path "${cleanPackagePath}" does not exist in the cloned repository.`);
@@ -232411,7 +232708,7 @@ class ProjectStore {
232411
232708
  const dirContents = await fs7.promises.readdir(absoluteDirPath);
232412
232709
  for (const entry of dirContents) {
232413
232710
  if (entry !== cleanPackagePath.replace(/^\/+/, "").split("/")[0]) {
232414
- await fs7.promises.rm(path8.join(absoluteDirPath, entry), {
232711
+ await fs7.promises.rm(path9.join(absoluteDirPath, entry), {
232415
232712
  recursive: true,
232416
232713
  force: true
232417
232714
  });
@@ -232419,7 +232716,7 @@ class ProjectStore {
232419
232716
  }
232420
232717
  const packageContents = await fs7.promises.readdir(packageFullPath);
232421
232718
  for (const entry of packageContents) {
232422
- await fs7.promises.rename(path8.join(packageFullPath, entry), path8.join(absoluteDirPath, entry));
232719
+ await fs7.promises.rename(path9.join(packageFullPath, entry), path9.join(absoluteDirPath, entry));
232423
232720
  }
232424
232721
  await fs7.promises.rm(packageFullPath, { recursive: true, force: true });
232425
232722
  }
@@ -232466,9 +232763,9 @@ class WatchModeController {
232466
232763
  });
232467
232764
  return;
232468
232765
  }
232469
- this.watchingPath = path9.join(this.projectStore.serverRootPath, req.body.projectName);
232766
+ this.watchingPath = path10.join(this.projectStore.serverRootPath, req.body.projectName);
232470
232767
  this.watcher = esm_default.watch(this.watchingPath, {
232471
- ignored: (path10, stats) => !!stats?.isFile() && !path10.endsWith(".malloy") && !path10.endsWith(".md"),
232768
+ ignored: (path11, stats) => !!stats?.isFile() && !path11.endsWith(".malloy") && !path11.endsWith(".md"),
232472
232769
  ignoreInitial: true
232473
232770
  });
232474
232771
  const reloadProject = async () => {
@@ -232476,16 +232773,16 @@ class WatchModeController {
232476
232773
  await this.projectStore.addProject(project2.metadata);
232477
232774
  logger.info(`Reloaded ${req.body.projectName}`);
232478
232775
  };
232479
- this.watcher.on("add", async (path10) => {
232480
- logger.info(`Detected new file ${path10}, reloading ${req.body.projectName}`);
232776
+ this.watcher.on("add", async (path11) => {
232777
+ logger.info(`Detected new file ${path11}, reloading ${req.body.projectName}`);
232481
232778
  await reloadProject();
232482
232779
  });
232483
- this.watcher.on("unlink", async (path10) => {
232484
- logger.info(`Detected deletion of ${path10}, reloading ${req.body.projectName}`);
232780
+ this.watcher.on("unlink", async (path11) => {
232781
+ logger.info(`Detected deletion of ${path11}, reloading ${req.body.projectName}`);
232485
232782
  await reloadProject();
232486
232783
  });
232487
- this.watcher.on("change", async (path10) => {
232488
- logger.info(`Detected change on ${path10}, reloading ${req.body.projectName}`);
232784
+ this.watcher.on("change", async (path11) => {
232785
+ logger.info(`Detected change on ${path11}, reloading ${req.body.projectName}`);
232489
232786
  await reloadProject();
232490
232787
  });
232491
232788
  res.json();
@@ -235576,25 +235873,25 @@ async function getModelForQuery(projectStore, projectName, packageName, modelPat
235576
235873
  }
235577
235874
  }
235578
235875
  function buildMalloyUri(components, fragment) {
235579
- let path10 = "/project/";
235876
+ let path11 = "/project/";
235580
235877
  if (components.project) {
235581
- path10 += encodeURIComponent(components.project);
235878
+ path11 += encodeURIComponent(components.project);
235582
235879
  } else {
235583
- path10 += "home";
235880
+ path11 += "home";
235584
235881
  }
235585
235882
  if (components.package) {
235586
- path10 += "/package/" + encodeURIComponent(components.package);
235883
+ path11 += "/package/" + encodeURIComponent(components.package);
235587
235884
  }
235588
235885
  if (components.resourceType) {
235589
- path10 += "/" + components.resourceType;
235886
+ path11 += "/" + components.resourceType;
235590
235887
  if (components.resourceName) {
235591
- path10 += "/" + encodeURIComponent(components.resourceName);
235888
+ path11 += "/" + encodeURIComponent(components.resourceName);
235592
235889
  if (components.subResourceType && components.subResourceName) {
235593
- path10 += "/" + components.subResourceType + "/" + encodeURIComponent(components.subResourceName);
235890
+ path11 += "/" + components.subResourceType + "/" + encodeURIComponent(components.subResourceName);
235594
235891
  }
235595
235892
  }
235596
235893
  }
235597
- let uriString = "malloy:/" + path10;
235894
+ let uriString = "malloy:/" + path11;
235598
235895
  if (fragment) {
235599
235896
  uriString += "#" + fragment;
235600
235897
  }
@@ -236530,8 +236827,8 @@ import {
236530
236827
  } from "@malloydata/malloy";
236531
236828
 
236532
236829
  // src/service/quoting.ts
236533
- function quoteTablePath(path10, dialect) {
236534
- return path10.split(".").map((seg) => dialect.quoteTablePath(seg)).join(".");
236830
+ function quoteTablePath(path11, dialect) {
236831
+ return path11.split(".").map((seg) => dialect.quoteTablePath(seg)).join(".");
236535
236832
  }
236536
236833
  function splitTablePath(tableName) {
236537
236834
  const lastDot = tableName.lastIndexOf(".");
@@ -236695,6 +236992,23 @@ var STAGING_BUILD_ID_LEN = 12;
236695
236992
  function stagingSuffix(buildId) {
236696
236993
  return `_${buildId.substring(0, STAGING_BUILD_ID_LEN)}`;
236697
236994
  }
236995
+ async function resolvePackageConnections(pkg, names) {
236996
+ const map2 = new Map;
236997
+ const seen = new Set;
236998
+ for (const name of names) {
236999
+ if (!name || seen.has(name))
237000
+ continue;
237001
+ seen.add(name);
237002
+ try {
237003
+ map2.set(name, await pkg.getMalloyConnection(name));
237004
+ } catch (err) {
237005
+ logger.warn(`Failed to resolve connection ${name}`, {
237006
+ error: err instanceof Error ? err.message : String(err)
237007
+ });
237008
+ }
237009
+ }
237010
+ return map2;
237011
+ }
236698
237012
  function manifestTableKey(connectionName, tableName) {
236699
237013
  return `${connectionName}::${tableName}`;
236700
237014
  }
@@ -236875,8 +237189,8 @@ class MaterializationService {
236875
237189
  }
236876
237190
  const project = await this.projectStore.getProject(projectName, false);
236877
237191
  const pkg = await project.getPackage(packageName, false);
236878
- const connections = pkg.getConnections();
236879
237192
  const entries = await this.manifestService.listEntries(projectId, packageName);
237193
+ const connections = await resolvePackageConnections(pkg, entries.map((e) => e.connectionName));
236880
237194
  return dropManifestEntries(entries, {
236881
237195
  connections,
236882
237196
  manifestService: this.manifestService,
@@ -236897,12 +237211,11 @@ class MaterializationService {
236897
237211
  manifest.loadText(JSON.stringify(existingManifest));
236898
237212
  const existingEntries = await this.manifestService.listEntries(projectId, packageName);
236899
237213
  const knownMaterializedTables = new Set(existingEntries.map((e) => manifestTableKey(e.connectionName, e.tableName)));
236900
- const { graphs, sources, connectionDigests } = await this.compilePackageBuildPlan(pkg, signal);
237214
+ const { graphs, sources, connectionDigests, connections } = await this.compilePackageBuildPlan(pkg, signal);
236901
237215
  if (graphs.length === 0) {
236902
237216
  logger.info("No persist sources to build");
236903
237217
  return { sourcesBuilt: 0, sourcesSkipped: 0 };
236904
237218
  }
236905
- const connections = pkg.getConnections();
236906
237219
  let sourcesBuilt = 0;
236907
237220
  let sourcesSkipped = 0;
236908
237221
  const sourceResults = [];
@@ -236951,7 +237264,7 @@ class MaterializationService {
236951
237264
  for (const modelPath of modelPaths) {
236952
237265
  if (signal.aborted)
236953
237266
  throw new Error("Build cancelled");
236954
- const { runtime, modelURL, importBaseURL } = await Model.getModelRuntime(pkg.getPackagePath(), modelPath, pkg.getConnections());
237267
+ const { runtime, modelURL, importBaseURL } = await Model.getModelRuntime(pkg.getPackagePath(), modelPath, pkg.getMalloyConfig());
236955
237268
  const modelMaterializer = runtime.loadModel(modelURL, {
236956
237269
  importBaseURL
236957
237270
  });
@@ -236994,7 +237307,7 @@ class MaterializationService {
236994
237307
  }
236995
237308
  tableOwners.set(key, sourceID);
236996
237309
  }
236997
- const connections = pkg.getConnections();
237310
+ const connections = await resolvePackageConnections(pkg, allGraphs.map((g) => g.connectionName));
236998
237311
  const connectionDigests = {};
236999
237312
  for (const graph of allGraphs) {
237000
237313
  const conn = connections.get(graph.connectionName);
@@ -237002,7 +237315,12 @@ class MaterializationService {
237002
237315
  connectionDigests[graph.connectionName] = await conn.getDigest();
237003
237316
  }
237004
237317
  }
237005
- return { graphs: allGraphs, sources: allSources, connectionDigests };
237318
+ return {
237319
+ graphs: allGraphs,
237320
+ sources: allSources,
237321
+ connectionDigests,
237322
+ connections
237323
+ };
237006
237324
  }
237007
237325
  async buildOneSource(persistSource, manifest, connection, connectionDigests, forceRefresh, projectId, packageName, knownMaterializedTables) {
237008
237326
  const buildIdSQL = persistSource.getSQL();
@@ -237155,9 +237473,9 @@ var MCP_PORT = Number(process.env.MCP_PORT || 4040);
237155
237473
  var MCP_ENDPOINT = "/mcp";
237156
237474
  var SHUTDOWN_DRAIN_DURATION_SECONDS = Number(process.env.SHUTDOWN_DRAIN_DURATION_SECONDS || 0);
237157
237475
  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 || ".");
237476
+ var __filename_esm = fileURLToPath2(import.meta.url);
237477
+ var ROOT = path11.join(path11.dirname(__filename_esm), "app");
237478
+ var SERVER_ROOT = path11.resolve(process.cwd(), process.env.SERVER_ROOT || ".");
237161
237479
  var API_PREFIX2 = "/api/v0";
237162
237480
  var isDevelopment = process.env["NODE_ENV"] === "development";
237163
237481
  var app = import_express.default();
@@ -237238,14 +237556,14 @@ mcpApp.all(MCP_ENDPOINT, async (req, res) => {
237238
237556
  });
237239
237557
  if (!isDevelopment) {
237240
237558
  app.use("/", import_express.default.static(ROOT));
237241
- app.use("/api-doc.html", import_express.default.static(path10.join(ROOT, "api-doc.html")));
237559
+ app.use("/api-doc.html", import_express.default.static(path11.join(ROOT, "api-doc.html")));
237242
237560
  } else {
237243
237561
  app.use(`${API_PREFIX2}`, loggerMiddleware);
237244
237562
  app.use(import_http_proxy_middleware.createProxyMiddleware({
237245
237563
  target: "http://localhost:5173",
237246
237564
  changeOrigin: true,
237247
237565
  ws: true,
237248
- pathFilter: (path11) => !path11.startsWith("/api/") && !path11.startsWith("/metrics") && !path11.startsWith("/health")
237566
+ pathFilter: (path12) => !path12.startsWith("/api/") && !path12.startsWith("/metrics") && !path12.startsWith("/health")
237249
237567
  }));
237250
237568
  }
237251
237569
  var setVersionIdError = (res) => {
@@ -237418,6 +237736,33 @@ app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/schema
237418
237736
  res.status(status).json(json);
237419
237737
  }
237420
237738
  });
237739
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/schemas`, async (req, res) => {
237740
+ try {
237741
+ res.status(200).json(await connectionController.listSchemas(req.params.projectName, req.params.connectionName, req.params.packageName));
237742
+ } catch (error) {
237743
+ logger.error(error);
237744
+ const { json, status } = internalErrorToHttpError(error);
237745
+ res.status(status).json(json);
237746
+ }
237747
+ });
237748
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/schemas/:schemaName/tables`, async (req, res) => {
237749
+ try {
237750
+ res.status(200).json(await connectionController.listTables(req.params.projectName, req.params.connectionName, req.params.schemaName, normalizeQueryArray(req.query.tableNames), req.params.packageName));
237751
+ } catch (error) {
237752
+ logger.error(error);
237753
+ const { json, status } = internalErrorToHttpError(error);
237754
+ res.status(status).json(json);
237755
+ }
237756
+ });
237757
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/schemas/:schemaName/tables/:tablePath`, async (req, res) => {
237758
+ try {
237759
+ res.status(200).json(await connectionController.getTable(req.params.projectName, req.params.connectionName, req.params.schemaName, req.params.tablePath, req.params.packageName));
237760
+ } catch (error) {
237761
+ logger.error(error);
237762
+ const { json, status } = internalErrorToHttpError(error);
237763
+ res.status(status).json(json);
237764
+ }
237765
+ });
237421
237766
  app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlSource`, async (req, res) => {
237422
237767
  try {
237423
237768
  res.status(200).json(await connectionController.getConnectionSqlSource(req.params.projectName, req.params.connectionName, req.query.sqlStatement));
@@ -237436,6 +237781,24 @@ app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlSo
237436
237781
  res.status(status).json(json);
237437
237782
  }
237438
237783
  });
237784
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlSource`, async (req, res) => {
237785
+ try {
237786
+ res.status(200).json(await connectionController.getConnectionSqlSource(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.params.packageName));
237787
+ } catch (error) {
237788
+ logger.error(error);
237789
+ const { json, status } = internalErrorToHttpError(error);
237790
+ res.status(status).json(json);
237791
+ }
237792
+ });
237793
+ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlSource`, async (req, res) => {
237794
+ try {
237795
+ res.status(200).json(await connectionController.getConnectionSqlSource(req.params.projectName, req.params.connectionName, req.body.sqlStatement, req.params.packageName));
237796
+ } catch (error) {
237797
+ logger.error(error);
237798
+ const { json, status } = internalErrorToHttpError(error);
237799
+ res.status(status).json(json);
237800
+ }
237801
+ });
237439
237802
  app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/queryData`, async (req, res) => {
237440
237803
  try {
237441
237804
  res.status(200).json(await connectionController.getConnectionQueryData(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.query.options));
@@ -237445,6 +237808,15 @@ app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/queryD
237445
237808
  res.status(status).json(json);
237446
237809
  }
237447
237810
  });
237811
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/queryData`, async (req, res) => {
237812
+ try {
237813
+ res.status(200).json(await connectionController.getConnectionQueryData(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.query.options, req.params.packageName));
237814
+ } catch (error) {
237815
+ logger.error(error);
237816
+ const { json, status } = internalErrorToHttpError(error);
237817
+ res.status(status).json(json);
237818
+ }
237819
+ });
237448
237820
  app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlQuery`, async (req, res) => {
237449
237821
  try {
237450
237822
  let options;
@@ -237460,6 +237832,21 @@ app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlQu
237460
237832
  res.status(status).json(json);
237461
237833
  }
237462
237834
  });
237835
+ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlQuery`, async (req, res) => {
237836
+ try {
237837
+ let options;
237838
+ if (req.body?.options) {
237839
+ options = req.body.options;
237840
+ } else {
237841
+ options = req.query.options;
237842
+ }
237843
+ res.status(200).json(await connectionController.getConnectionQueryData(req.params.projectName, req.params.connectionName, req.body.sqlStatement, options, req.params.packageName));
237844
+ } catch (error) {
237845
+ logger.error(error);
237846
+ const { json, status } = internalErrorToHttpError(error);
237847
+ res.status(status).json(json);
237848
+ }
237849
+ });
237463
237850
  app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/temporaryTable`, async (req, res) => {
237464
237851
  try {
237465
237852
  res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.query.sqlStatement));
@@ -237469,6 +237856,15 @@ app.get(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/tempor
237469
237856
  res.status(status).json(json);
237470
237857
  }
237471
237858
  });
237859
+ app.get(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/temporaryTable`, async (req, res) => {
237860
+ try {
237861
+ res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.query.sqlStatement, req.params.packageName));
237862
+ } catch (error) {
237863
+ logger.error(error);
237864
+ const { json, status } = internalErrorToHttpError(error);
237865
+ res.status(status).json(json);
237866
+ }
237867
+ });
237472
237868
  app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlTemporaryTable`, async (req, res) => {
237473
237869
  try {
237474
237870
  res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.body.sqlStatement));
@@ -237478,6 +237874,15 @@ app.post(`${API_PREFIX2}/projects/:projectName/connections/:connectionName/sqlTe
237478
237874
  res.status(status).json(json);
237479
237875
  }
237480
237876
  });
237877
+ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/connections/:connectionName/sqlTemporaryTable`, async (req, res) => {
237878
+ try {
237879
+ res.status(200).json(await connectionController.getConnectionTemporaryTable(req.params.projectName, req.params.connectionName, req.body.sqlStatement, req.params.packageName));
237880
+ } catch (error) {
237881
+ logger.error(error);
237882
+ const { json, status } = internalErrorToHttpError(error);
237883
+ res.status(status).json(json);
237884
+ }
237885
+ });
237481
237886
  app.get(`${API_PREFIX2}/projects/:projectName/packages`, async (req, res) => {
237482
237887
  if (req.query.versionId) {
237483
237888
  setVersionIdError(res);
@@ -237747,7 +238152,7 @@ app.post(`${API_PREFIX2}/projects/:projectName/packages/:packageName/manifest`,
237747
238152
  }
237748
238153
  });
237749
238154
  if (!isDevelopment) {
237750
- app.get("*", (_req, res) => res.sendFile(path10.resolve(ROOT, "index.html")));
238155
+ app.get("*", (_req, res) => res.sendFile(path11.resolve(ROOT, "index.html")));
237751
238156
  }
237752
238157
  app.use((err, _req, res, _next) => {
237753
238158
  logger.error("Unhandled error:", err);