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