@forzalabs/remora 2.0.2 → 2.0.3
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/CHANGELOG.md +15 -0
- package/index.js +457 -242
- package/package.json +2 -2
- package/workers/ExecutorWorker.js +385 -204
|
@@ -7807,15 +7807,15 @@ var require_index_cjs = __commonJS({
|
|
|
7807
7807
|
};
|
|
7808
7808
|
}
|
|
7809
7809
|
function wrapConversion(toModel, graph) {
|
|
7810
|
-
const
|
|
7810
|
+
const path21 = [graph[toModel].parent, toModel];
|
|
7811
7811
|
let fn = convert$1[graph[toModel].parent][toModel];
|
|
7812
7812
|
let cur = graph[toModel].parent;
|
|
7813
7813
|
while (graph[cur].parent) {
|
|
7814
|
-
|
|
7814
|
+
path21.unshift(graph[cur].parent);
|
|
7815
7815
|
fn = link(convert$1[graph[cur].parent][cur], fn);
|
|
7816
7816
|
cur = graph[cur].parent;
|
|
7817
7817
|
}
|
|
7818
|
-
fn.conversion =
|
|
7818
|
+
fn.conversion = path21;
|
|
7819
7819
|
return fn;
|
|
7820
7820
|
}
|
|
7821
7821
|
function route(fromModel) {
|
|
@@ -8445,7 +8445,7 @@ var require_node2 = __commonJS({
|
|
|
8445
8445
|
var require_tail_file = __commonJS({
|
|
8446
8446
|
"../../node_modules/winston/lib/winston/tail-file.js"(exports2, module2) {
|
|
8447
8447
|
"use strict";
|
|
8448
|
-
var
|
|
8448
|
+
var fs24 = require("fs");
|
|
8449
8449
|
var { StringDecoder } = require("string_decoder");
|
|
8450
8450
|
var { Stream } = require_readable();
|
|
8451
8451
|
function noop() {
|
|
@@ -8466,7 +8466,7 @@ var require_tail_file = __commonJS({
|
|
|
8466
8466
|
stream.emit("end");
|
|
8467
8467
|
stream.emit("close");
|
|
8468
8468
|
};
|
|
8469
|
-
|
|
8469
|
+
fs24.open(options.file, "a+", "0644", (err2, fd) => {
|
|
8470
8470
|
if (err2) {
|
|
8471
8471
|
if (!iter) {
|
|
8472
8472
|
stream.emit("error", err2);
|
|
@@ -8478,10 +8478,10 @@ var require_tail_file = __commonJS({
|
|
|
8478
8478
|
}
|
|
8479
8479
|
(function read() {
|
|
8480
8480
|
if (stream.destroyed) {
|
|
8481
|
-
|
|
8481
|
+
fs24.close(fd, noop);
|
|
8482
8482
|
return;
|
|
8483
8483
|
}
|
|
8484
|
-
return
|
|
8484
|
+
return fs24.read(fd, buffer, 0, buffer.length, pos, (error, bytes) => {
|
|
8485
8485
|
if (error) {
|
|
8486
8486
|
if (!iter) {
|
|
8487
8487
|
stream.emit("error", error);
|
|
@@ -8540,8 +8540,8 @@ var require_tail_file = __commonJS({
|
|
|
8540
8540
|
var require_file = __commonJS({
|
|
8541
8541
|
"../../node_modules/winston/lib/winston/transports/file.js"(exports2, module2) {
|
|
8542
8542
|
"use strict";
|
|
8543
|
-
var
|
|
8544
|
-
var
|
|
8543
|
+
var fs24 = require("fs");
|
|
8544
|
+
var path21 = require("path");
|
|
8545
8545
|
var asyncSeries = require_series();
|
|
8546
8546
|
var zlib3 = require("zlib");
|
|
8547
8547
|
var { MESSAGE } = require_triple_beam();
|
|
@@ -8571,14 +8571,14 @@ var require_file = __commonJS({
|
|
|
8571
8571
|
this._onError = this._onError.bind(this);
|
|
8572
8572
|
if (options.filename || options.dirname) {
|
|
8573
8573
|
throwIf("filename or dirname", "stream");
|
|
8574
|
-
this._basename = this.filename = options.filename ?
|
|
8575
|
-
this.dirname = options.dirname ||
|
|
8574
|
+
this._basename = this.filename = options.filename ? path21.basename(options.filename) : "winston.log";
|
|
8575
|
+
this.dirname = options.dirname || path21.dirname(options.filename);
|
|
8576
8576
|
this.options = options.options || { flags: "a" };
|
|
8577
8577
|
} else if (options.stream) {
|
|
8578
8578
|
console.warn("options.stream will be removed in winston@4. Use winston.transports.Stream");
|
|
8579
8579
|
throwIf("stream", "filename", "maxsize");
|
|
8580
8580
|
this._dest = this._stream.pipe(this._setupStream(options.stream));
|
|
8581
|
-
this.dirname =
|
|
8581
|
+
this.dirname = path21.dirname(this._dest.path);
|
|
8582
8582
|
} else {
|
|
8583
8583
|
throw new Error("Cannot log to file without filename or stream.");
|
|
8584
8584
|
}
|
|
@@ -8741,11 +8741,11 @@ var require_file = __commonJS({
|
|
|
8741
8741
|
options = {};
|
|
8742
8742
|
}
|
|
8743
8743
|
options = normalizeQuery(options);
|
|
8744
|
-
const file =
|
|
8744
|
+
const file = path21.join(this.dirname, this.filename);
|
|
8745
8745
|
let buff = "";
|
|
8746
8746
|
let results = [];
|
|
8747
8747
|
let row = 0;
|
|
8748
|
-
const stream =
|
|
8748
|
+
const stream = fs24.createReadStream(file, {
|
|
8749
8749
|
encoding: "utf8"
|
|
8750
8750
|
});
|
|
8751
8751
|
stream.on("error", (err2) => {
|
|
@@ -8846,7 +8846,7 @@ var require_file = __commonJS({
|
|
|
8846
8846
|
* TODO: Refactor me.
|
|
8847
8847
|
*/
|
|
8848
8848
|
stream(options = {}) {
|
|
8849
|
-
const file =
|
|
8849
|
+
const file = path21.join(this.dirname, this.filename);
|
|
8850
8850
|
const stream = new Stream();
|
|
8851
8851
|
const tail = {
|
|
8852
8852
|
file,
|
|
@@ -8896,8 +8896,8 @@ var require_file = __commonJS({
|
|
|
8896
8896
|
*/
|
|
8897
8897
|
stat(callback) {
|
|
8898
8898
|
const target = this._getFile();
|
|
8899
|
-
const fullpath =
|
|
8900
|
-
|
|
8899
|
+
const fullpath = path21.join(this.dirname, target);
|
|
8900
|
+
fs24.stat(fullpath, (err2, stat) => {
|
|
8901
8901
|
if (err2 && err2.code === "ENOENT") {
|
|
8902
8902
|
debug("ENOENT\xA0ok", fullpath);
|
|
8903
8903
|
this.filename = target;
|
|
@@ -9000,9 +9000,9 @@ var require_file = __commonJS({
|
|
|
9000
9000
|
* @returns {WritableStream} Stream that writes to disk for the active file.
|
|
9001
9001
|
*/
|
|
9002
9002
|
_createStream(source) {
|
|
9003
|
-
const fullpath =
|
|
9003
|
+
const fullpath = path21.join(this.dirname, this.filename);
|
|
9004
9004
|
debug("create stream start", fullpath, this.options);
|
|
9005
|
-
const dest =
|
|
9005
|
+
const dest = fs24.createWriteStream(fullpath, this.options).on("error", (err2) => debug(err2)).on("close", () => debug("close", dest.path, dest.bytesWritten)).on("open", () => {
|
|
9006
9006
|
debug("file open ok", fullpath);
|
|
9007
9007
|
this.emit("open", fullpath);
|
|
9008
9008
|
source.pipe(dest);
|
|
@@ -9025,16 +9025,16 @@ var require_file = __commonJS({
|
|
|
9025
9025
|
*/
|
|
9026
9026
|
_incFile(callback) {
|
|
9027
9027
|
debug("_incFile", this.filename);
|
|
9028
|
-
const ext =
|
|
9029
|
-
const basename =
|
|
9028
|
+
const ext = path21.extname(this._basename);
|
|
9029
|
+
const basename = path21.basename(this._basename, ext);
|
|
9030
9030
|
const tasks = [];
|
|
9031
9031
|
if (this.zippedArchive) {
|
|
9032
9032
|
tasks.push(
|
|
9033
9033
|
function(cb) {
|
|
9034
9034
|
const num = this._created > 0 && !this.tailable ? this._created : "";
|
|
9035
9035
|
this._compressFile(
|
|
9036
|
-
|
|
9037
|
-
|
|
9036
|
+
path21.join(this.dirname, `${basename}${num}${ext}`),
|
|
9037
|
+
path21.join(this.dirname, `${basename}${num}${ext}.gz`),
|
|
9038
9038
|
cb
|
|
9039
9039
|
);
|
|
9040
9040
|
}.bind(this)
|
|
@@ -9059,8 +9059,8 @@ var require_file = __commonJS({
|
|
|
9059
9059
|
* @private
|
|
9060
9060
|
*/
|
|
9061
9061
|
_getFile() {
|
|
9062
|
-
const ext =
|
|
9063
|
-
const basename =
|
|
9062
|
+
const ext = path21.extname(this._basename);
|
|
9063
|
+
const basename = path21.basename(this._basename, ext);
|
|
9064
9064
|
const isRotation = this.rotationFormat ? this.rotationFormat() : this._created;
|
|
9065
9065
|
return !this.tailable && this._created ? `${basename}${isRotation}${ext}` : `${basename}${ext}`;
|
|
9066
9066
|
}
|
|
@@ -9080,8 +9080,8 @@ var require_file = __commonJS({
|
|
|
9080
9080
|
const isOldest = oldest !== 0 ? oldest : "";
|
|
9081
9081
|
const isZipped = this.zippedArchive ? ".gz" : "";
|
|
9082
9082
|
const filePath = `${basename}${isOldest}${ext}${isZipped}`;
|
|
9083
|
-
const target =
|
|
9084
|
-
|
|
9083
|
+
const target = path21.join(this.dirname, filePath);
|
|
9084
|
+
fs24.unlink(target, callback);
|
|
9085
9085
|
}
|
|
9086
9086
|
/**
|
|
9087
9087
|
* Roll files forward based on integer, up to maxFiles. e.g. if base if
|
|
@@ -9103,20 +9103,20 @@ var require_file = __commonJS({
|
|
|
9103
9103
|
for (let x2 = this.maxFiles - 1; x2 > 1; x2--) {
|
|
9104
9104
|
tasks.push(function(i6, cb) {
|
|
9105
9105
|
let fileName = `${basename}${i6 - 1}${ext}${isZipped}`;
|
|
9106
|
-
const tmppath =
|
|
9107
|
-
|
|
9106
|
+
const tmppath = path21.join(this.dirname, fileName);
|
|
9107
|
+
fs24.exists(tmppath, (exists) => {
|
|
9108
9108
|
if (!exists) {
|
|
9109
9109
|
return cb(null);
|
|
9110
9110
|
}
|
|
9111
9111
|
fileName = `${basename}${i6}${ext}${isZipped}`;
|
|
9112
|
-
|
|
9112
|
+
fs24.rename(tmppath, path21.join(this.dirname, fileName), cb);
|
|
9113
9113
|
});
|
|
9114
9114
|
}.bind(this, x2));
|
|
9115
9115
|
}
|
|
9116
9116
|
asyncSeries(tasks, () => {
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9117
|
+
fs24.rename(
|
|
9118
|
+
path21.join(this.dirname, `${basename}${ext}${isZipped}`),
|
|
9119
|
+
path21.join(this.dirname, `${basename}1${ext}${isZipped}`),
|
|
9120
9120
|
callback
|
|
9121
9121
|
);
|
|
9122
9122
|
});
|
|
@@ -9130,22 +9130,22 @@ var require_file = __commonJS({
|
|
|
9130
9130
|
* @private
|
|
9131
9131
|
*/
|
|
9132
9132
|
_compressFile(src, dest, callback) {
|
|
9133
|
-
|
|
9133
|
+
fs24.access(src, fs24.F_OK, (err2) => {
|
|
9134
9134
|
if (err2) {
|
|
9135
9135
|
return callback();
|
|
9136
9136
|
}
|
|
9137
9137
|
var gzip = zlib3.createGzip();
|
|
9138
|
-
var inp =
|
|
9139
|
-
var out =
|
|
9138
|
+
var inp = fs24.createReadStream(src);
|
|
9139
|
+
var out = fs24.createWriteStream(dest);
|
|
9140
9140
|
out.on("finish", () => {
|
|
9141
|
-
|
|
9141
|
+
fs24.unlink(src, callback);
|
|
9142
9142
|
});
|
|
9143
9143
|
inp.pipe(gzip).pipe(out);
|
|
9144
9144
|
});
|
|
9145
9145
|
}
|
|
9146
9146
|
_createLogDirIfNotExist(dirPath) {
|
|
9147
|
-
if (!
|
|
9148
|
-
|
|
9147
|
+
if (!fs24.existsSync(dirPath)) {
|
|
9148
|
+
fs24.mkdirSync(dirPath, { recursive: true });
|
|
9149
9149
|
}
|
|
9150
9150
|
}
|
|
9151
9151
|
};
|
|
@@ -9229,9 +9229,9 @@ var require_http = __commonJS({
|
|
|
9229
9229
|
};
|
|
9230
9230
|
const auth = options.params.auth || null;
|
|
9231
9231
|
delete options.params.auth;
|
|
9232
|
-
const
|
|
9232
|
+
const path21 = options.params.path || null;
|
|
9233
9233
|
delete options.params.path;
|
|
9234
|
-
this._request(options, auth,
|
|
9234
|
+
this._request(options, auth, path21, (err2, res, body) => {
|
|
9235
9235
|
if (res && res.statusCode !== 200) {
|
|
9236
9236
|
err2 = new Error(`Invalid HTTP Status Code: ${res.statusCode}`);
|
|
9237
9237
|
}
|
|
@@ -9259,12 +9259,12 @@ var require_http = __commonJS({
|
|
|
9259
9259
|
method: "stream",
|
|
9260
9260
|
params: options
|
|
9261
9261
|
};
|
|
9262
|
-
const
|
|
9262
|
+
const path21 = options.params.path || null;
|
|
9263
9263
|
delete options.params.path;
|
|
9264
9264
|
const auth = options.params.auth || null;
|
|
9265
9265
|
delete options.params.auth;
|
|
9266
9266
|
let buff = "";
|
|
9267
|
-
const req = this._request(options, auth,
|
|
9267
|
+
const req = this._request(options, auth, path21);
|
|
9268
9268
|
stream.destroy = () => req.destroy();
|
|
9269
9269
|
req.on("data", (data) => {
|
|
9270
9270
|
data = (buff + data).split(/\n+/);
|
|
@@ -9290,14 +9290,14 @@ var require_http = __commonJS({
|
|
|
9290
9290
|
* @param {string} path - request path
|
|
9291
9291
|
* @param {function} callback - Continuation to respond to when complete.
|
|
9292
9292
|
*/
|
|
9293
|
-
_request(options, auth,
|
|
9293
|
+
_request(options, auth, path21, callback) {
|
|
9294
9294
|
options = options || {};
|
|
9295
9295
|
auth = auth || this.auth;
|
|
9296
|
-
|
|
9296
|
+
path21 = path21 || this.path || "";
|
|
9297
9297
|
if (this.batch) {
|
|
9298
|
-
this._doBatch(options, callback, auth,
|
|
9298
|
+
this._doBatch(options, callback, auth, path21);
|
|
9299
9299
|
} else {
|
|
9300
|
-
this._doRequest(options, callback, auth,
|
|
9300
|
+
this._doRequest(options, callback, auth, path21);
|
|
9301
9301
|
}
|
|
9302
9302
|
}
|
|
9303
9303
|
/**
|
|
@@ -9307,18 +9307,18 @@ var require_http = __commonJS({
|
|
|
9307
9307
|
* @param {Object?} auth - authentication options
|
|
9308
9308
|
* @param {string} path - request path
|
|
9309
9309
|
*/
|
|
9310
|
-
_doBatch(options, callback, auth,
|
|
9310
|
+
_doBatch(options, callback, auth, path21) {
|
|
9311
9311
|
this.batchOptions.push(options);
|
|
9312
9312
|
if (this.batchOptions.length === 1) {
|
|
9313
9313
|
const me3 = this;
|
|
9314
9314
|
this.batchCallback = callback;
|
|
9315
9315
|
this.batchTimeoutID = setTimeout(function() {
|
|
9316
9316
|
me3.batchTimeoutID = -1;
|
|
9317
|
-
me3._doBatchRequest(me3.batchCallback, auth,
|
|
9317
|
+
me3._doBatchRequest(me3.batchCallback, auth, path21);
|
|
9318
9318
|
}, this.batchInterval);
|
|
9319
9319
|
}
|
|
9320
9320
|
if (this.batchOptions.length === this.batchCount) {
|
|
9321
|
-
this._doBatchRequest(this.batchCallback, auth,
|
|
9321
|
+
this._doBatchRequest(this.batchCallback, auth, path21);
|
|
9322
9322
|
}
|
|
9323
9323
|
}
|
|
9324
9324
|
/**
|
|
@@ -9327,14 +9327,14 @@ var require_http = __commonJS({
|
|
|
9327
9327
|
* @param {Object?} auth - authentication options
|
|
9328
9328
|
* @param {string} path - request path
|
|
9329
9329
|
*/
|
|
9330
|
-
_doBatchRequest(callback, auth,
|
|
9330
|
+
_doBatchRequest(callback, auth, path21) {
|
|
9331
9331
|
if (this.batchTimeoutID > 0) {
|
|
9332
9332
|
clearTimeout(this.batchTimeoutID);
|
|
9333
9333
|
this.batchTimeoutID = -1;
|
|
9334
9334
|
}
|
|
9335
9335
|
const batchOptionsCopy = this.batchOptions.slice();
|
|
9336
9336
|
this.batchOptions = [];
|
|
9337
|
-
this._doRequest(batchOptionsCopy, callback, auth,
|
|
9337
|
+
this._doRequest(batchOptionsCopy, callback, auth, path21);
|
|
9338
9338
|
}
|
|
9339
9339
|
/**
|
|
9340
9340
|
* Make a request to a winstond server or any http server which can
|
|
@@ -9344,7 +9344,7 @@ var require_http = __commonJS({
|
|
|
9344
9344
|
* @param {Object?} auth - authentication options
|
|
9345
9345
|
* @param {string} path - request path
|
|
9346
9346
|
*/
|
|
9347
|
-
_doRequest(options, callback, auth,
|
|
9347
|
+
_doRequest(options, callback, auth, path21) {
|
|
9348
9348
|
const headers = Object.assign({}, this.headers);
|
|
9349
9349
|
if (auth && auth.bearer) {
|
|
9350
9350
|
headers.Authorization = `Bearer ${auth.bearer}`;
|
|
@@ -9354,7 +9354,7 @@ var require_http = __commonJS({
|
|
|
9354
9354
|
method: "POST",
|
|
9355
9355
|
host: this.host,
|
|
9356
9356
|
port: this.port,
|
|
9357
|
-
path: `/${
|
|
9357
|
+
path: `/${path21.replace(/^\//, "")}`,
|
|
9358
9358
|
headers,
|
|
9359
9359
|
auth: auth && auth.username && auth.password ? `${auth.username}:${auth.password}` : "",
|
|
9360
9360
|
agent: this.agent
|
|
@@ -11575,7 +11575,7 @@ var CONSTANTS, Constants_default;
|
|
|
11575
11575
|
var init_Constants = __esm({
|
|
11576
11576
|
"../../packages/constants/src/Constants.ts"() {
|
|
11577
11577
|
CONSTANTS = {
|
|
11578
|
-
cliVersion: "2.0.
|
|
11578
|
+
cliVersion: "2.0.3",
|
|
11579
11579
|
backendVersion: 1,
|
|
11580
11580
|
backendPort: 5088,
|
|
11581
11581
|
workerVersion: 2,
|
|
@@ -11632,7 +11632,12 @@ var init_Constants = __esm({
|
|
|
11632
11632
|
* whole run, so the entire work list is submitted at once and needs an upper bound. A queued
|
|
11633
11633
|
* task holds references, not copies, so this bounds the work list rather than memory.
|
|
11634
11634
|
*/
|
|
11635
|
-
MAX_WORKER_QUEUE_SIZE: 1e5
|
|
11635
|
+
MAX_WORKER_QUEUE_SIZE: 1e5,
|
|
11636
|
+
/**
|
|
11637
|
+
* Rows a sample may ask for out of the pipeline. A sample is a look at the data, never an
|
|
11638
|
+
* export of it — `remora sample -s` and the preview's Data tab are both held to this.
|
|
11639
|
+
*/
|
|
11640
|
+
MAX_SAMPLE_ROWS: 100
|
|
11636
11641
|
}
|
|
11637
11642
|
};
|
|
11638
11643
|
Constants_default = CONSTANTS;
|
|
@@ -12780,7 +12785,7 @@ var init_Validator = __esm({
|
|
|
12780
12785
|
*/
|
|
12781
12786
|
this.detectOnFinishRecursion = (consumer) => {
|
|
12782
12787
|
const errors = [];
|
|
12783
|
-
const
|
|
12788
|
+
const path21 = [];
|
|
12784
12789
|
const targetsOf = (cons) => {
|
|
12785
12790
|
const names = [];
|
|
12786
12791
|
for (const output of cons.outputs ?? []) {
|
|
@@ -12792,17 +12797,17 @@ var init_Validator = __esm({
|
|
|
12792
12797
|
return names;
|
|
12793
12798
|
};
|
|
12794
12799
|
const walk = (name) => {
|
|
12795
|
-
if (
|
|
12796
|
-
errors.push(`Consumer "${consumer.name}" has a cyclic run-consumer (onSuccess/onError) chain: ${[...
|
|
12800
|
+
if (path21.some((x2) => x2.toLowerCase() === name.toLowerCase())) {
|
|
12801
|
+
errors.push(`Consumer "${consumer.name}" has a cyclic run-consumer (onSuccess/onError) chain: ${[...path21, name].join(" -> ")}`);
|
|
12797
12802
|
return true;
|
|
12798
12803
|
}
|
|
12799
12804
|
const cons = Environment_default.getConsumer(name);
|
|
12800
12805
|
if (!cons) return false;
|
|
12801
|
-
|
|
12806
|
+
path21.push(name);
|
|
12802
12807
|
for (const target of targetsOf(cons)) {
|
|
12803
12808
|
if (walk(target)) return true;
|
|
12804
12809
|
}
|
|
12805
|
-
|
|
12810
|
+
path21.pop();
|
|
12806
12811
|
return false;
|
|
12807
12812
|
};
|
|
12808
12813
|
walk(consumer.name);
|
|
@@ -14852,14 +14857,14 @@ var init_readFile = __esm({
|
|
|
14852
14857
|
import_promises3 = require("fs/promises");
|
|
14853
14858
|
filePromises = {};
|
|
14854
14859
|
fileIntercept = {};
|
|
14855
|
-
readFile2 = (
|
|
14856
|
-
if (fileIntercept[
|
|
14857
|
-
return fileIntercept[
|
|
14860
|
+
readFile2 = (path21, options) => {
|
|
14861
|
+
if (fileIntercept[path21] !== void 0) {
|
|
14862
|
+
return fileIntercept[path21];
|
|
14858
14863
|
}
|
|
14859
|
-
if (!filePromises[
|
|
14860
|
-
filePromises[
|
|
14864
|
+
if (!filePromises[path21] || options?.ignoreCache) {
|
|
14865
|
+
filePromises[path21] = (0, import_promises3.readFile)(path21, "utf8");
|
|
14861
14866
|
}
|
|
14862
|
-
return filePromises[
|
|
14867
|
+
return filePromises[path21];
|
|
14863
14868
|
};
|
|
14864
14869
|
}
|
|
14865
14870
|
});
|
|
@@ -14971,8 +14976,8 @@ var init_externalDataInterceptor = __esm({
|
|
|
14971
14976
|
getFileRecord() {
|
|
14972
14977
|
return fileIntercept;
|
|
14973
14978
|
},
|
|
14974
|
-
interceptFile(
|
|
14975
|
-
fileIntercept[
|
|
14979
|
+
interceptFile(path21, contents) {
|
|
14980
|
+
fileIntercept[path21] = Promise.resolve(contents);
|
|
14976
14981
|
},
|
|
14977
14982
|
getTokenRecord() {
|
|
14978
14983
|
return tokenIntercept;
|
|
@@ -18052,8 +18057,8 @@ var init_createConfigValueProvider = __esm({
|
|
|
18052
18057
|
return endpoint.url.href;
|
|
18053
18058
|
}
|
|
18054
18059
|
if ("hostname" in endpoint) {
|
|
18055
|
-
const { protocol, hostname, port, path:
|
|
18056
|
-
return `${protocol}//${hostname}${port ? ":" + port : ""}${
|
|
18060
|
+
const { protocol, hostname, port, path: path21 } = endpoint;
|
|
18061
|
+
return `${protocol}//${hostname}${port ? ":" + port : ""}${path21}`;
|
|
18057
18062
|
}
|
|
18058
18063
|
}
|
|
18059
18064
|
return endpoint;
|
|
@@ -18428,18 +18433,18 @@ var getAttrPathList;
|
|
|
18428
18433
|
var init_getAttrPathList = __esm({
|
|
18429
18434
|
"../../node_modules/@smithy/core/dist-es/submodules/endpoints/util-endpoints/lib/getAttrPathList.js"() {
|
|
18430
18435
|
init_types2();
|
|
18431
|
-
getAttrPathList = (
|
|
18432
|
-
const parts =
|
|
18436
|
+
getAttrPathList = (path21) => {
|
|
18437
|
+
const parts = path21.split(".");
|
|
18433
18438
|
const pathList = [];
|
|
18434
18439
|
for (const part of parts) {
|
|
18435
18440
|
const squareBracketIndex = part.indexOf("[");
|
|
18436
18441
|
if (squareBracketIndex !== -1) {
|
|
18437
18442
|
if (part.indexOf("]") !== part.length - 1) {
|
|
18438
|
-
throw new EndpointError(`Path: '${
|
|
18443
|
+
throw new EndpointError(`Path: '${path21}' does not end with ']'`);
|
|
18439
18444
|
}
|
|
18440
18445
|
const arrayIndex = part.slice(squareBracketIndex + 1, -1);
|
|
18441
18446
|
if (Number.isNaN(parseInt(arrayIndex))) {
|
|
18442
|
-
throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${
|
|
18447
|
+
throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${path21}'`);
|
|
18443
18448
|
}
|
|
18444
18449
|
if (squareBracketIndex !== 0) {
|
|
18445
18450
|
pathList.push(part.slice(0, squareBracketIndex));
|
|
@@ -18460,9 +18465,9 @@ var init_getAttr = __esm({
|
|
|
18460
18465
|
"../../node_modules/@smithy/core/dist-es/submodules/endpoints/util-endpoints/lib/getAttr.js"() {
|
|
18461
18466
|
init_types2();
|
|
18462
18467
|
init_getAttrPathList();
|
|
18463
|
-
getAttr = (value,
|
|
18468
|
+
getAttr = (value, path21) => getAttrPathList(path21).reduce((acc, index) => {
|
|
18464
18469
|
if (typeof acc !== "object") {
|
|
18465
|
-
throw new EndpointError(`Index '${index}' in '${
|
|
18470
|
+
throw new EndpointError(`Index '${index}' in '${path21}' not found in '${JSON.stringify(value)}'`);
|
|
18466
18471
|
} else if (Array.isArray(acc)) {
|
|
18467
18472
|
const i6 = parseInt(index);
|
|
18468
18473
|
return acc[i6 < 0 ? acc.length + i6 : i6];
|
|
@@ -18523,8 +18528,8 @@ var init_parseURL = __esm({
|
|
|
18523
18528
|
return value;
|
|
18524
18529
|
}
|
|
18525
18530
|
if (typeof value === "object" && "hostname" in value) {
|
|
18526
|
-
const { hostname: hostname2, port, protocol: protocol2 = "", path:
|
|
18527
|
-
const url = new URL(`${protocol2}//${hostname2}${port ? `:${port}` : ""}${
|
|
18531
|
+
const { hostname: hostname2, port, protocol: protocol2 = "", path: path21 = "", query = {} } = value;
|
|
18532
|
+
const url = new URL(`${protocol2}//${hostname2}${port ? `:${port}` : ""}${path21}`);
|
|
18528
18533
|
url.search = Object.entries(query).map(([k7, v3]) => `${k7}=${v3}`).join("&");
|
|
18529
18534
|
return url;
|
|
18530
18535
|
}
|
|
@@ -20868,11 +20873,11 @@ var init_HttpBindingProtocol = __esm({
|
|
|
20868
20873
|
const opTraits = translateTraits(operationSchema.traits);
|
|
20869
20874
|
if (opTraits.http) {
|
|
20870
20875
|
request.method = opTraits.http[0];
|
|
20871
|
-
const [
|
|
20876
|
+
const [path21, search] = opTraits.http[1].split("?");
|
|
20872
20877
|
if (request.path == "/") {
|
|
20873
|
-
request.path =
|
|
20878
|
+
request.path = path21;
|
|
20874
20879
|
} else {
|
|
20875
|
-
request.path +=
|
|
20880
|
+
request.path += path21;
|
|
20876
20881
|
}
|
|
20877
20882
|
const traitSearchParams = new URLSearchParams(search ?? "");
|
|
20878
20883
|
for (const [key, value] of traitSearchParams) {
|
|
@@ -24585,12 +24590,12 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
24585
24590
|
const password = request.password ?? "";
|
|
24586
24591
|
auth = `${username}:${password}`;
|
|
24587
24592
|
}
|
|
24588
|
-
let
|
|
24593
|
+
let path21 = request.path;
|
|
24589
24594
|
if (queryString) {
|
|
24590
|
-
|
|
24595
|
+
path21 += `?${queryString}`;
|
|
24591
24596
|
}
|
|
24592
24597
|
if (request.fragment) {
|
|
24593
|
-
|
|
24598
|
+
path21 += `#${request.fragment}`;
|
|
24594
24599
|
}
|
|
24595
24600
|
let hostname = request.hostname ?? "";
|
|
24596
24601
|
if (hostname[0] === "[" && hostname.endsWith("]")) {
|
|
@@ -24602,7 +24607,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
24602
24607
|
headers: request.headers,
|
|
24603
24608
|
host: hostname,
|
|
24604
24609
|
method: request.method,
|
|
24605
|
-
path:
|
|
24610
|
+
path: path21,
|
|
24606
24611
|
port: request.port,
|
|
24607
24612
|
agent,
|
|
24608
24613
|
auth
|
|
@@ -25511,10 +25516,10 @@ ${longDate}
|
|
|
25511
25516
|
${credentialScope}
|
|
25512
25517
|
${toHex(hashedRequest)}`;
|
|
25513
25518
|
}
|
|
25514
|
-
getCanonicalPath({ path:
|
|
25519
|
+
getCanonicalPath({ path: path21 }) {
|
|
25515
25520
|
if (this.uriEscapePath) {
|
|
25516
25521
|
const normalizedPathSegments = [];
|
|
25517
|
-
for (const pathSegment of
|
|
25522
|
+
for (const pathSegment of path21.split("/")) {
|
|
25518
25523
|
if (pathSegment?.length === 0)
|
|
25519
25524
|
continue;
|
|
25520
25525
|
if (pathSegment === ".")
|
|
@@ -25525,11 +25530,11 @@ ${toHex(hashedRequest)}`;
|
|
|
25525
25530
|
normalizedPathSegments.push(pathSegment);
|
|
25526
25531
|
}
|
|
25527
25532
|
}
|
|
25528
|
-
const normalizedPath = `${
|
|
25533
|
+
const normalizedPath = `${path21?.startsWith("/") ? "/" : ""}${normalizedPathSegments.join("/")}${normalizedPathSegments.length > 0 && path21?.endsWith("/") ? "/" : ""}`;
|
|
25529
25534
|
const doubleEncoded = escapeUri(normalizedPath);
|
|
25530
25535
|
return doubleEncoded.replace(/%2F/g, "/");
|
|
25531
25536
|
}
|
|
25532
|
-
return
|
|
25537
|
+
return path21;
|
|
25533
25538
|
}
|
|
25534
25539
|
validateResolvedCredentials(credentials) {
|
|
25535
25540
|
if (typeof credentials !== "object" || typeof credentials.accessKeyId !== "string" || typeof credentials.secretAccessKey !== "string") {
|
|
@@ -42802,8 +42807,8 @@ var init_HttpClient = __esm({
|
|
|
42802
42807
|
throw new Error(err2.message ?? "An error occurred on GET.");
|
|
42803
42808
|
}
|
|
42804
42809
|
};
|
|
42805
|
-
this.getWorkerUrl = (
|
|
42806
|
-
const cleanPath =
|
|
42810
|
+
this.getWorkerUrl = (path21) => {
|
|
42811
|
+
const cleanPath = path21.startsWith("/") ? path21.substring(1) : path21;
|
|
42807
42812
|
return `${this.workerHost}/${cleanPath}`;
|
|
42808
42813
|
};
|
|
42809
42814
|
this.workerHost = ProcessENVManager_default.getEnvVariable("REMORA_WORKER_HOST") || "http://worker:5069";
|
|
@@ -42949,32 +42954,32 @@ var init_DriverHelper = __esm({
|
|
|
42949
42954
|
},
|
|
42950
42955
|
quickReadFile: async (filePath, lineCount) => {
|
|
42951
42956
|
const fileStream = (0, import_fs9.createReadStream)(filePath);
|
|
42952
|
-
const
|
|
42957
|
+
const rl8 = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
42953
42958
|
const lines = [];
|
|
42954
42959
|
let counter = 0;
|
|
42955
|
-
for await (const line of
|
|
42960
|
+
for await (const line of rl8) {
|
|
42956
42961
|
lines.push(line);
|
|
42957
42962
|
counter++;
|
|
42958
42963
|
if (counter >= lineCount) {
|
|
42959
42964
|
break;
|
|
42960
42965
|
}
|
|
42961
42966
|
}
|
|
42962
|
-
|
|
42967
|
+
rl8.close();
|
|
42963
42968
|
fileStream.close();
|
|
42964
42969
|
return lines;
|
|
42965
42970
|
},
|
|
42966
42971
|
quickReadStream: async (stream, lineCount) => {
|
|
42967
|
-
const
|
|
42972
|
+
const rl8 = (0, import_readline.createInterface)({ input: stream, crlfDelay: Infinity });
|
|
42968
42973
|
const lines = [];
|
|
42969
42974
|
let counter = 0;
|
|
42970
|
-
for await (const line of
|
|
42975
|
+
for await (const line of rl8) {
|
|
42971
42976
|
lines.push(line);
|
|
42972
42977
|
counter++;
|
|
42973
42978
|
if (counter >= lineCount) {
|
|
42974
42979
|
break;
|
|
42975
42980
|
}
|
|
42976
42981
|
}
|
|
42977
|
-
|
|
42982
|
+
rl8.close();
|
|
42978
42983
|
return lines;
|
|
42979
42984
|
}
|
|
42980
42985
|
};
|
|
@@ -43748,7 +43753,7 @@ var init_S3DestinationDriver = __esm({
|
|
|
43748
43753
|
});
|
|
43749
43754
|
|
|
43750
43755
|
// ../../packages/drivers/src/DriverFactory.ts
|
|
43751
|
-
var DriverFactoryClass, DriverFactory, DriverFactory_default;
|
|
43756
|
+
var STAGEABLE_ENGINES, DriverFactoryClass, DriverFactory, DriverFactory_default;
|
|
43752
43757
|
var init_DriverFactory = __esm({
|
|
43753
43758
|
"../../packages/drivers/src/DriverFactory.ts"() {
|
|
43754
43759
|
init_RedshiftDriver();
|
|
@@ -43758,8 +43763,11 @@ var init_DriverFactory = __esm({
|
|
|
43758
43763
|
init_LocalDestinationDriver();
|
|
43759
43764
|
init_S3SourceDriver();
|
|
43760
43765
|
init_S3DestinationDriver();
|
|
43766
|
+
STAGEABLE_ENGINES = ["local", "aws-s3", "delta-share"];
|
|
43761
43767
|
DriverFactoryClass = class {
|
|
43762
43768
|
constructor() {
|
|
43769
|
+
/** Whether a run can stage a producer from this engine — see `STAGEABLE_ENGINES`. */
|
|
43770
|
+
this.canStage = (engine) => STAGEABLE_ENGINES.includes(engine);
|
|
43763
43771
|
this.instantiateSource = async (source) => {
|
|
43764
43772
|
switch (source.engine) {
|
|
43765
43773
|
case "aws-redshift": {
|
|
@@ -43839,6 +43847,7 @@ var init_ProducerManager = __esm({
|
|
|
43839
43847
|
init_src4();
|
|
43840
43848
|
init_src3();
|
|
43841
43849
|
init_src5();
|
|
43850
|
+
init_CryptoEngine();
|
|
43842
43851
|
ProducerManagerClass = class {
|
|
43843
43852
|
constructor() {
|
|
43844
43853
|
this.getColumns = (producer) => {
|
|
@@ -43893,6 +43902,46 @@ var init_ProducerManager = __esm({
|
|
|
43893
43902
|
return true;
|
|
43894
43903
|
return FixedWidthParser_default.matchesSelector(line, resolved.selector, resolved.range);
|
|
43895
43904
|
};
|
|
43905
|
+
/**
|
|
43906
|
+
* The post-parse work a producer implies for every record it produces: which keys carry the
|
|
43907
|
+
* source file name, and which carry a mask.
|
|
43908
|
+
*
|
|
43909
|
+
* Resolved once per chunk, never per line — `getMask` resolves a secret and validates the value,
|
|
43910
|
+
* and neither depends on the record. Empty for almost every producer, which is the case worth
|
|
43911
|
+
* keeping fast.
|
|
43912
|
+
*/
|
|
43913
|
+
this.compileFills = (dimensions) => {
|
|
43914
|
+
Affirm_default(dimensions, "Invalid producer dimensions");
|
|
43915
|
+
const fills = [];
|
|
43916
|
+
for (const dimension of dimensions) {
|
|
43917
|
+
const { prodDimension } = dimension;
|
|
43918
|
+
const mask = this.getMask(prodDimension);
|
|
43919
|
+
const sourceFilename = prodDimension.sourceFilename === true;
|
|
43920
|
+
if (!sourceFilename && !Algo_default.hasVal(mask))
|
|
43921
|
+
continue;
|
|
43922
|
+
fills.push({ key: dimension.name, mask, sourceFilename, type: prodDimension.type });
|
|
43923
|
+
}
|
|
43924
|
+
return fills;
|
|
43925
|
+
};
|
|
43926
|
+
/**
|
|
43927
|
+
* Applies the compiled fills to one parsed record, in place.
|
|
43928
|
+
*
|
|
43929
|
+
* The one place a producer dimension's mask is ever applied, on purpose: a run reaches it through
|
|
43930
|
+
* `ProducerExecutor.processLine` and a sample through `ProducerEngine`, and a masked dimension
|
|
43931
|
+
* that came back in the clear from one of the two would be a `hash` the project declared and the
|
|
43932
|
+
* screen ignored — a disclosure, not a display bug.
|
|
43933
|
+
*/
|
|
43934
|
+
this.applyFills = (record, fills, sourceFilename) => {
|
|
43935
|
+
if (!fills?.length)
|
|
43936
|
+
return record;
|
|
43937
|
+
for (const fill2 of fills) {
|
|
43938
|
+
if (fill2.sourceFilename)
|
|
43939
|
+
record[fill2.key] = sourceFilename;
|
|
43940
|
+
if (Algo_default.hasVal(fill2.mask))
|
|
43941
|
+
record[fill2.key] = CryptoEngine_default.hashValue(fill2.mask, record[fill2.key]?.toString(), fill2.type);
|
|
43942
|
+
}
|
|
43943
|
+
return record;
|
|
43944
|
+
};
|
|
43896
43945
|
}
|
|
43897
43946
|
};
|
|
43898
43947
|
ProducerManager = new ProducerManagerClass();
|
|
@@ -44307,7 +44356,8 @@ var init_ProducerEngine = __esm({
|
|
|
44307
44356
|
}
|
|
44308
44357
|
};
|
|
44309
44358
|
}
|
|
44310
|
-
const
|
|
44359
|
+
const headerLines = ParseHelper_default.hasHeaderLine(effectiveProducer.settings.fileType, effectiveProducer.settings.hasHeaderRow) ? 1 : 0;
|
|
44360
|
+
const fileData = await this.readFile(effectiveProducer, { readmode: "lines", lines: { from: 0, to: sampleSize + headerLines } }, effectiveSource);
|
|
44311
44361
|
rawData = fileData.data;
|
|
44312
44362
|
} finally {
|
|
44313
44363
|
if (scope)
|
|
@@ -44326,13 +44376,15 @@ var init_ProducerEngine = __esm({
|
|
|
44326
44376
|
if (!rawData || rawData.length === 0) return [];
|
|
44327
44377
|
const firstItem = rawData[0];
|
|
44328
44378
|
const isLineData = typeof firstItem === "string";
|
|
44379
|
+
const fills = discover ? [] : ProducerManager_default.compileFills(this._fillDimensions(producer));
|
|
44380
|
+
const sourceFilename = import_path13.default.basename(producer.settings.fileKey ?? producer.settings.sqlTable ?? "");
|
|
44329
44381
|
if (isLineData) {
|
|
44330
44382
|
const lines = rawData;
|
|
44331
44383
|
const dimensions = this.deriveDimensions(lines[0], producer, discover);
|
|
44332
44384
|
const { fileType, hasHeaderRow } = producer.settings;
|
|
44333
44385
|
const dataLines = ParseHelper_default.hasHeaderLine(fileType, hasHeaderRow) ? lines.slice(1) : lines;
|
|
44334
44386
|
const recordSelector = ProducerManager_default.resolveRecordSelector(producer);
|
|
44335
|
-
return dataLines.filter((line) => line.trim().length > 0).filter((line) => ProducerManager_default.shouldReadLine(line, recordSelector)).flatMap((line) => LineParser_default.parseAll(line, producer, dimensions, noopTracker));
|
|
44387
|
+
return dataLines.filter((line) => line.trim().length > 0).filter((line) => ProducerManager_default.shouldReadLine(line, recordSelector)).flatMap((line) => LineParser_default.parseAll(line, producer, dimensions, noopTracker)).map((record) => ProducerManager_default.applyFills(record, fills, sourceFilename));
|
|
44336
44388
|
}
|
|
44337
44389
|
if (discover) {
|
|
44338
44390
|
return rawData.map((item) => ({ ...item }));
|
|
@@ -44343,9 +44395,15 @@ var init_ProducerEngine = __esm({
|
|
|
44343
44395
|
const key = dim.alias ?? dim.name;
|
|
44344
44396
|
record[dim.name] = TypeCaster_default.cast(item[key], dim.type, dim.format);
|
|
44345
44397
|
}
|
|
44346
|
-
return record;
|
|
44398
|
+
return ProducerManager_default.applyFills(record, fills, sourceFilename);
|
|
44347
44399
|
});
|
|
44348
44400
|
};
|
|
44401
|
+
/**
|
|
44402
|
+
* The producer's declared dimensions in the shape `compileFills` reads them in. Declaration
|
|
44403
|
+
* order, because a fill is addressed by key and never by position — unlike the executor
|
|
44404
|
+
* dimensions of a run, whose index is reconciled against the file's own header.
|
|
44405
|
+
*/
|
|
44406
|
+
this._fillDimensions = (producer) => producer.dimensions.map((prodDimension, index) => ({ index, name: prodDimension.name, prodDimension }));
|
|
44349
44407
|
/**
|
|
44350
44408
|
* Builds the executor dimensions of a producer. There are two shapes of source: a FIXED file has
|
|
44351
44409
|
* no header, so its layout comes from the positions declared on the dimensions; every other file
|
|
@@ -46813,9 +46871,10 @@ var init_MockDataFactory = __esm({
|
|
|
46813
46871
|
if (type === "number") {
|
|
46814
46872
|
const first = bounds?.min ?? 1;
|
|
46815
46873
|
const last = first + poolSize - 1;
|
|
46874
|
+
const ceiling = bounds?.max;
|
|
46816
46875
|
Affirm_default(
|
|
46817
|
-
|
|
46818
|
-
`Key "${norm}" has a synth range of ${first}-${
|
|
46876
|
+
ceiling === void 0 || ceiling >= last,
|
|
46877
|
+
`Key "${norm}" has a synth range of ${first}-${ceiling}, which holds fewer than the ${poolSize} distinct values it has to generate; widen it or generate fewer records`
|
|
46819
46878
|
);
|
|
46820
46879
|
for (let i6 = 0; i6 < poolSize; i6++) pool.push(first + i6);
|
|
46821
46880
|
return pool;
|
|
@@ -48155,23 +48214,23 @@ var init_Diagnostics = __esm({
|
|
|
48155
48214
|
return [.../* @__PURE__ */ new Set([...inputs, ...chained])];
|
|
48156
48215
|
};
|
|
48157
48216
|
this._walk = (start, next, onCycle) => {
|
|
48158
|
-
const
|
|
48217
|
+
const path21 = [];
|
|
48159
48218
|
const onPath = /* @__PURE__ */ new Set();
|
|
48160
48219
|
const stack = [{ name: start, done: false }];
|
|
48161
48220
|
const visited = /* @__PURE__ */ new Set();
|
|
48162
48221
|
while (stack.length > 0) {
|
|
48163
48222
|
const frame = stack.pop();
|
|
48164
48223
|
if (frame.done) {
|
|
48165
|
-
onPath.delete(
|
|
48224
|
+
onPath.delete(path21.pop());
|
|
48166
48225
|
continue;
|
|
48167
48226
|
}
|
|
48168
48227
|
if (onPath.has(frame.name)) {
|
|
48169
|
-
|
|
48228
|
+
path21.slice(path21.indexOf(frame.name)).forEach((name) => onCycle.add(name));
|
|
48170
48229
|
continue;
|
|
48171
48230
|
}
|
|
48172
48231
|
if (visited.has(frame.name)) continue;
|
|
48173
48232
|
visited.add(frame.name);
|
|
48174
|
-
|
|
48233
|
+
path21.push(frame.name);
|
|
48175
48234
|
onPath.add(frame.name);
|
|
48176
48235
|
stack.push({ name: frame.name, done: true });
|
|
48177
48236
|
const successors = next.get(frame.name) ?? [];
|
|
@@ -48848,8 +48907,8 @@ var init_ResourceView = __esm({
|
|
|
48848
48907
|
if (!source || origin.path.length < 2) return { value: "declared here", muted: true };
|
|
48849
48908
|
return { value: `${source.resource}.${source.field}`, link: source.node };
|
|
48850
48909
|
};
|
|
48851
|
-
this._pathText = (
|
|
48852
|
-
return
|
|
48910
|
+
this._pathText = (path21) => {
|
|
48911
|
+
return path21.map((step) => `${step.resource}.${step.field}`).join(" \u2192 ");
|
|
48853
48912
|
};
|
|
48854
48913
|
this._consumerOutputsTable = (env2, consumer) => {
|
|
48855
48914
|
const declared = new Set((env2.sources ?? []).map((x2) => x2.name));
|
|
@@ -49879,17 +49938,30 @@ var init_LocalUsageDB = __esm({
|
|
|
49879
49938
|
}
|
|
49880
49939
|
};
|
|
49881
49940
|
/**
|
|
49882
|
-
* The recorded runs, newest first
|
|
49941
|
+
* The recorded runs, newest first — the newest `limit` of the rows `keep` accepts.
|
|
49942
|
+
*
|
|
49943
|
+
* Decoded from the end and stopped as soon as that many are held: a reader wants the recent
|
|
49883
49944
|
* executions, and decoding ten thousand rows to show ten of them is work nobody asked for.
|
|
49884
49945
|
*
|
|
49946
|
+
* `keep` is applied BEFORE the limit, which is the only way "the newest N runs of this kind" can
|
|
49947
|
+
* mean it: filtering afterwards lets the rows a caller does not want displace the ones it does,
|
|
49948
|
+
* so one sample recorded here would silently push a real run out of a history someone is reading.
|
|
49949
|
+
*
|
|
49885
49950
|
* Never throws. A missing file reads as no history, and so does a half-written one — this store is
|
|
49886
49951
|
* appended to while it is being read, so failing on that would make it unreadable during a run.
|
|
49887
49952
|
*/
|
|
49888
|
-
this.list = (limit = MAX_LISTED_ROWS) => {
|
|
49953
|
+
this.list = (limit = MAX_LISTED_ROWS, keep) => {
|
|
49889
49954
|
try {
|
|
49890
49955
|
if (!(0, import_fs12.existsSync)(CLI_DB_PATH))
|
|
49891
49956
|
return [];
|
|
49892
|
-
|
|
49957
|
+
const rows = this._getRows();
|
|
49958
|
+
const wanted = Math.max(1, limit);
|
|
49959
|
+
const found = [];
|
|
49960
|
+
for (let index = rows.length - 1; index >= 0 && found.length < wanted; index--) {
|
|
49961
|
+
const usage = this._fromLine(rows[index]);
|
|
49962
|
+
if (!keep || keep(usage)) found.push(usage);
|
|
49963
|
+
}
|
|
49964
|
+
return found;
|
|
49893
49965
|
} catch (error) {
|
|
49894
49966
|
this._handleError("list", error);
|
|
49895
49967
|
return [];
|
|
@@ -50070,9 +50142,10 @@ var init_UsageManager = __esm({
|
|
|
50070
50142
|
});
|
|
50071
50143
|
|
|
50072
50144
|
// ../../packages/engines/src/ops/RunOverlay.ts
|
|
50073
|
-
var MAX_RUNS, MAX_OPERATIONS, RunOverlayClass, RunOverlay;
|
|
50145
|
+
var import_crypto4, MAX_RUNS, MAX_OPERATIONS, RunOverlayClass, RunOverlay;
|
|
50074
50146
|
var init_RunOverlay = __esm({
|
|
50075
50147
|
"../../packages/engines/src/ops/RunOverlay.ts"() {
|
|
50148
|
+
import_crypto4 = __toESM(require("crypto"), 1);
|
|
50076
50149
|
init_src();
|
|
50077
50150
|
init_LineageEngine();
|
|
50078
50151
|
init_LocalUsageDB();
|
|
@@ -50081,6 +50154,8 @@ var init_RunOverlay = __esm({
|
|
|
50081
50154
|
MAX_OPERATIONS = 40;
|
|
50082
50155
|
RunOverlayClass = class {
|
|
50083
50156
|
constructor() {
|
|
50157
|
+
/** The last store token read, and the overlay token it resolved to. */
|
|
50158
|
+
this._signed = { store: null, overlay: "" };
|
|
50084
50159
|
/**
|
|
50085
50160
|
* The recent executions and their aggregates. ONE read of the store answers both, so a page
|
|
50086
50161
|
* showing a graph, a run list and a timing breakdown costs one file read rather than three.
|
|
@@ -50091,20 +50166,40 @@ var init_RunOverlay = __esm({
|
|
|
50091
50166
|
this.read = (limit = MAX_RUNS) => {
|
|
50092
50167
|
Affirm_default(limit > 0, "Run overlay limit must be greater than zero");
|
|
50093
50168
|
if (!UsageManager_default.recordsLocally()) return { runs: [], metrics: {} };
|
|
50094
|
-
const stats = LocalUsageDB_default.list(limit
|
|
50169
|
+
const stats = LocalUsageDB_default.list(limit, (stat) => !!stat?.consumer && stat.invokedBy !== "SAMPLE");
|
|
50095
50170
|
return { runs: stats.map((stat) => this._run(stat)), metrics: this._metrics(stats) };
|
|
50096
50171
|
};
|
|
50097
50172
|
/**
|
|
50098
|
-
* A token that changes when the
|
|
50173
|
+
* A token that changes when the OVERLAY does. Empty when there is nothing to read.
|
|
50099
50174
|
*
|
|
50100
50175
|
* A run finishing changes no configuration file, so the config hash cannot notice it — this is
|
|
50101
|
-
* the second half of what the preview polls
|
|
50102
|
-
*
|
|
50176
|
+
* the second half of what the preview polls.
|
|
50177
|
+
*
|
|
50178
|
+
* It signs the painted runs rather than the store, because the two do not move together: a
|
|
50179
|
+
* sample is recorded like any other execution and then filtered out of `read`, so the store's
|
|
50180
|
+
* own token changes while the picture does not. Signing the store there announced a project
|
|
50181
|
+
* change for every sample — and a page told its resource changed drops the sample it is showing,
|
|
50182
|
+
* which is exactly the rows someone had just asked for.
|
|
50183
|
+
*
|
|
50184
|
+
* Still cheap to poll: the store's mtime/size gates the read, so the rows are decoded only after
|
|
50185
|
+
* something has actually been written, never once a second.
|
|
50103
50186
|
*/
|
|
50104
50187
|
this.signature = () => {
|
|
50105
50188
|
if (!UsageManager_default.recordsLocally()) return "";
|
|
50106
|
-
|
|
50189
|
+
const store = LocalUsageDB_default.signature();
|
|
50190
|
+
if (store === this._signed.store) return this._signed.overlay;
|
|
50191
|
+
const overlay = this._token(this.read());
|
|
50192
|
+
this._signed = { store, overlay };
|
|
50193
|
+
return overlay;
|
|
50107
50194
|
};
|
|
50195
|
+
/**
|
|
50196
|
+
* A token over the whole overlay, runs and metrics alike.
|
|
50197
|
+
*
|
|
50198
|
+
* Everything it carries, not the newest row and a count: `endUsage` updates a row in place and a
|
|
50199
|
+
* finish action writes runs of its own, so a narrower token would miss a transition the graph
|
|
50200
|
+
* exists to show.
|
|
50201
|
+
*/
|
|
50202
|
+
this._token = (overlay) => import_crypto4.default.createHash("sha256").update(JSON.stringify(overlay)).digest("hex");
|
|
50108
50203
|
this._run = (stat) => {
|
|
50109
50204
|
const startedAt = this._iso(stat.startedAt);
|
|
50110
50205
|
return {
|
|
@@ -50350,63 +50445,6 @@ var init_PushdownEngine = __esm({
|
|
|
50350
50445
|
}
|
|
50351
50446
|
});
|
|
50352
50447
|
|
|
50353
|
-
// ../../packages/engines/src/producer/SampleEngine.ts
|
|
50354
|
-
var MAX_CHAIN_DEPTH2, SampleEngineClass, SampleEngine;
|
|
50355
|
-
var init_SampleEngine = __esm({
|
|
50356
|
-
"../../packages/engines/src/producer/SampleEngine.ts"() {
|
|
50357
|
-
init_src();
|
|
50358
|
-
init_src4();
|
|
50359
|
-
init_ProducerEngine();
|
|
50360
|
-
MAX_CHAIN_DEPTH2 = 20;
|
|
50361
|
-
SampleEngineClass = class {
|
|
50362
|
-
constructor() {
|
|
50363
|
-
/**
|
|
50364
|
-
* @param resourceName a producer or consumer name, as declared.
|
|
50365
|
-
* @throws when the name is neither, or when the source cannot be read.
|
|
50366
|
-
*/
|
|
50367
|
-
this.read = async (resourceName, size = 10) => {
|
|
50368
|
-
Affirm_default(resourceName, "Missing resource name to sample");
|
|
50369
|
-
Affirm_default(size > 0, "Sample size must be greater than 0");
|
|
50370
|
-
const producer = Environment_default.getProducer(resourceName);
|
|
50371
|
-
if (producer)
|
|
50372
|
-
return { kind: "producer", name: resourceName, records: await ProducerEngine_default.readSampleData(producer, size, false) };
|
|
50373
|
-
const consumer = Environment_default.getConsumer(resourceName);
|
|
50374
|
-
Affirm_default(consumer, `Resource "${resourceName}" not found. Please check if it exists as a producer or consumer.`);
|
|
50375
|
-
return { kind: "consumer", name: resourceName, records: await this._readConsumer(consumer, size, []) };
|
|
50376
|
-
};
|
|
50377
|
-
/**
|
|
50378
|
-
* A consumer has no data of its own until it runs, so what it shows is its FIRST input, projected
|
|
50379
|
-
* through its field list — near enough to answer "what will come out of this" without a run.
|
|
50380
|
-
*/
|
|
50381
|
-
this._readConsumer = async (consumer, size, visited) => {
|
|
50382
|
-
Affirm_default(!visited.includes(consumer.name), `Consumer "${consumer.name}" reads itself through ${visited.join(" \u2192 ")}`);
|
|
50383
|
-
Affirm_default(visited.length < MAX_CHAIN_DEPTH2, `Consumer chain from "${visited[0]}" is more than ${MAX_CHAIN_DEPTH2} deep`);
|
|
50384
|
-
const input = consumer.producers[0];
|
|
50385
|
-
Affirm_default(input, `Consumer "${consumer.name}" has no producers configured`);
|
|
50386
|
-
const producer = Environment_default.getProducer(input.name);
|
|
50387
|
-
if (!producer) {
|
|
50388
|
-
const upstream = Environment_default.getConsumer(input.name);
|
|
50389
|
-
Affirm_default(upstream, `Producer or consumer "${input.name}" not found for consumer "${consumer.name}"`);
|
|
50390
|
-
return this._readConsumer(upstream, size, [...visited, consumer.name]);
|
|
50391
|
-
}
|
|
50392
|
-
const records = await ProducerEngine_default.readSampleData(producer, size, false);
|
|
50393
|
-
if (consumer.fields.some((field) => field.key === "*")) return records;
|
|
50394
|
-
return records.map((record) => this._project(consumer, record));
|
|
50395
|
-
};
|
|
50396
|
-
this._project = (consumer, record) => {
|
|
50397
|
-
const projected = {};
|
|
50398
|
-
for (const field of consumer.fields) {
|
|
50399
|
-
if (field.key === "*") continue;
|
|
50400
|
-
projected[field.alias || field.key] = record[field.key];
|
|
50401
|
-
}
|
|
50402
|
-
return projected;
|
|
50403
|
-
};
|
|
50404
|
-
}
|
|
50405
|
-
};
|
|
50406
|
-
SampleEngine = new SampleEngineClass();
|
|
50407
|
-
}
|
|
50408
|
-
});
|
|
50409
|
-
|
|
50410
50448
|
// ../../packages/engines/src/transform/LookupRegistry.ts
|
|
50411
50449
|
var LookupRegistryClass, LookupRegistry, LookupRegistry_default;
|
|
50412
50450
|
var init_LookupRegistry = __esm({
|
|
@@ -50443,12 +50481,12 @@ var init_LookupRegistry = __esm({
|
|
|
50443
50481
|
});
|
|
50444
50482
|
|
|
50445
50483
|
// ../../packages/engines/src/transform/LookupKey.ts
|
|
50446
|
-
var
|
|
50484
|
+
var import_crypto5, DELIMITER, idFor, LookupKey, LookupKey_default;
|
|
50447
50485
|
var init_LookupKey = __esm({
|
|
50448
50486
|
"../../packages/engines/src/transform/LookupKey.ts"() {
|
|
50449
|
-
|
|
50487
|
+
import_crypto5 = __toESM(require("crypto"), 1);
|
|
50450
50488
|
DELIMITER = String.fromCharCode(0);
|
|
50451
|
-
idFor = (ref) =>
|
|
50489
|
+
idFor = (ref) => import_crypto5.default.createHash("sha1").update([ref.consumer, ref.key, ref.value].join(DELIMITER)).digest("hex").slice(0, 16);
|
|
50452
50490
|
LookupKey = { idFor };
|
|
50453
50491
|
LookupKey_default = LookupKey;
|
|
50454
50492
|
}
|
|
@@ -51085,7 +51123,6 @@ var init_src10 = __esm({
|
|
|
51085
51123
|
init_ProducerEngine();
|
|
51086
51124
|
init_ProducerManager();
|
|
51087
51125
|
init_PushdownEngine();
|
|
51088
|
-
init_SampleEngine();
|
|
51089
51126
|
init_TransformationEngine();
|
|
51090
51127
|
init_TypeCaster();
|
|
51091
51128
|
init_LookupRegistry();
|
|
@@ -51255,14 +51292,14 @@ var init_OutputExecutor = __esm({
|
|
|
51255
51292
|
});
|
|
51256
51293
|
|
|
51257
51294
|
// ../../packages/executors/src/ConsumerExecutor.ts
|
|
51258
|
-
var import_path18, import_fs13, import_readline6, import_promises13,
|
|
51295
|
+
var import_path18, import_fs13, import_readline6, import_promises13, import_crypto6, LIMIT_SCAN_BYTES, NEWLINE_BYTE, ConsumerExecutorClass, ConsumerExecutor, ConsumerExecutor_default;
|
|
51259
51296
|
var init_ConsumerExecutor = __esm({
|
|
51260
51297
|
"../../packages/executors/src/ConsumerExecutor.ts"() {
|
|
51261
51298
|
import_path18 = __toESM(require("path"));
|
|
51262
51299
|
import_fs13 = __toESM(require("fs"));
|
|
51263
51300
|
import_readline6 = __toESM(require("readline"));
|
|
51264
51301
|
import_promises13 = __toESM(require("fs/promises"));
|
|
51265
|
-
|
|
51302
|
+
import_crypto6 = __toESM(require("crypto"));
|
|
51266
51303
|
init_src10();
|
|
51267
51304
|
init_src10();
|
|
51268
51305
|
init_src10();
|
|
@@ -51501,7 +51538,7 @@ var init_ConsumerExecutor = __esm({
|
|
|
51501
51538
|
let newLineCount = 0;
|
|
51502
51539
|
const seen = /* @__PURE__ */ new Set();
|
|
51503
51540
|
for await (const line of lineReader) {
|
|
51504
|
-
const hash =
|
|
51541
|
+
const hash = import_crypto6.default.createHash("sha1").update(line).digest("base64");
|
|
51505
51542
|
if (!seen.has(hash)) {
|
|
51506
51543
|
seen.add(hash);
|
|
51507
51544
|
if (!writer.write(line + "\n"))
|
|
@@ -51777,8 +51814,6 @@ var init_ProducerExecutor = __esm({
|
|
|
51777
51814
|
init_src8();
|
|
51778
51815
|
init_src4();
|
|
51779
51816
|
init_src10();
|
|
51780
|
-
init_src();
|
|
51781
|
-
init_src10();
|
|
51782
51817
|
init_src10();
|
|
51783
51818
|
import_path19 = __toESM(require("path"));
|
|
51784
51819
|
init_src2();
|
|
@@ -51809,20 +51844,14 @@ var init_ProducerExecutor = __esm({
|
|
|
51809
51844
|
* the source file name or a mask, and what that file name is. None of it depends on the line, so
|
|
51810
51845
|
* it is compiled once per chunk instead of rebuilt per line — including the mask's own
|
|
51811
51846
|
* validation, which used to run once per dimension per line.
|
|
51847
|
+
*
|
|
51848
|
+
* The fills themselves come from `ProducerManager`, which is also where the sample path gets
|
|
51849
|
+
* them: one producer stage, reached from two places.
|
|
51812
51850
|
*/
|
|
51813
51851
|
this.compileLine = (dimensions, chunk) => {
|
|
51814
51852
|
Affirm_default(dimensions, "Invalid producer dimensions");
|
|
51815
51853
|
Affirm_default(chunk, "Invalid chunk");
|
|
51816
|
-
|
|
51817
|
-
for (const dimension of dimensions) {
|
|
51818
|
-
const { prodDimension } = dimension;
|
|
51819
|
-
const mask = ProducerManager_default.getMask(prodDimension);
|
|
51820
|
-
const sourceFilename = prodDimension.sourceFilename === true;
|
|
51821
|
-
if (!sourceFilename && !Algo_default.hasVal(mask))
|
|
51822
|
-
continue;
|
|
51823
|
-
fills.push({ key: dimension.name, mask, sourceFilename, type: prodDimension.type });
|
|
51824
|
-
}
|
|
51825
|
-
return { fills, sourceFilename: import_path19.default.basename(chunk.fileUri) };
|
|
51854
|
+
return { fills: ProducerManager_default.compileFills(dimensions), sourceFilename: import_path19.default.basename(chunk.fileUri) };
|
|
51826
51855
|
};
|
|
51827
51856
|
/**
|
|
51828
51857
|
* The record(s) one source line produces. Almost always exactly one — a producer with a group
|
|
@@ -51843,14 +51872,8 @@ var init_ProducerExecutor = __esm({
|
|
|
51843
51872
|
if (plan.fills.length === 0)
|
|
51844
51873
|
return records;
|
|
51845
51874
|
counter = performance.now();
|
|
51846
|
-
for (const record of records)
|
|
51847
|
-
|
|
51848
|
-
if (fill2.sourceFilename)
|
|
51849
|
-
record[fill2.key] = plan.sourceFilename;
|
|
51850
|
-
if (Algo_default.hasVal(fill2.mask))
|
|
51851
|
-
record[fill2.key] = CryptoEngine_default.hashValue(fill2.mask, record[fill2.key]?.toString(), fill2.type);
|
|
51852
|
-
}
|
|
51853
|
-
}
|
|
51875
|
+
for (const record of records)
|
|
51876
|
+
ProducerManager_default.applyFills(record, plan.fills, plan.sourceFilename);
|
|
51854
51877
|
tracker.measure("process-line:dimensions-filename-mask", performance.now() - counter);
|
|
51855
51878
|
return records;
|
|
51856
51879
|
};
|
|
@@ -52618,7 +52641,8 @@ var init_ExecutorOrchestrator = __esm({
|
|
|
52618
52641
|
} catch (error) {
|
|
52619
52642
|
Logger_default.log(`[${usageId}] Consumer "${consumer.name}" failed: ${Helper_default.asError(error).message} | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
52620
52643
|
Logger_default.error(error);
|
|
52621
|
-
|
|
52644
|
+
if (!request.skipExport)
|
|
52645
|
+
await ConsumerOnFinishManager_default.onConsumerError(consumer, usageId, this.makeOnFinishRunner(consumer, request, usageId));
|
|
52622
52646
|
Logger_default.log(`[${usageId}] Running cleanup after failure`);
|
|
52623
52647
|
await this.performCleanupOperations(scope, tracker);
|
|
52624
52648
|
UsageManager_default.failUsage(usageId, Helper_default.asError(error).message);
|
|
@@ -53571,6 +53595,163 @@ init_src4();
|
|
|
53571
53595
|
init_OutputExecutor();
|
|
53572
53596
|
init_ProducerExecutor();
|
|
53573
53597
|
|
|
53598
|
+
// ../../packages/executors/src/SampleRunner.ts
|
|
53599
|
+
var import_fs18 = __toESM(require("fs"));
|
|
53600
|
+
var import_promises18 = __toESM(require("fs/promises"));
|
|
53601
|
+
var import_path24 = __toESM(require("path"));
|
|
53602
|
+
var import_readline11 = __toESM(require("readline"));
|
|
53603
|
+
init_src();
|
|
53604
|
+
init_src3();
|
|
53605
|
+
init_src4();
|
|
53606
|
+
init_src8();
|
|
53607
|
+
init_src10();
|
|
53608
|
+
init_src7();
|
|
53609
|
+
init_src2();
|
|
53610
|
+
init_ExecutorOrchestrator();
|
|
53611
|
+
var MAX_WALK_DEPTH = 20;
|
|
53612
|
+
var SAMPLE_USER = { user: { _id: "sample", name: "sample", type: "licence" } };
|
|
53613
|
+
var SampleRunnerClass = class {
|
|
53614
|
+
constructor() {
|
|
53615
|
+
/**
|
|
53616
|
+
* @param resourceName a producer or consumer name, as declared.
|
|
53617
|
+
* @param rows the most rows to return, capped at `MAX_SAMPLE_ROWS`.
|
|
53618
|
+
* @throws when the name is neither, when a source cannot be read, or when the pipeline itself
|
|
53619
|
+
* fails — a consumer whose transformation throws is a sample that reports the reason.
|
|
53620
|
+
*/
|
|
53621
|
+
this.read = async (resourceName, rows = 10, details) => {
|
|
53622
|
+
Affirm_default(resourceName, "Missing resource name to sample");
|
|
53623
|
+
Affirm_default(rows > 0, "Sample size must be greater than 0");
|
|
53624
|
+
const size = Math.min(rows, Constants_default.defaults.MAX_SAMPLE_ROWS);
|
|
53625
|
+
const producer = Environment_default.getProducer(resourceName);
|
|
53626
|
+
if (producer) {
|
|
53627
|
+
const records = await ProducerEngine_default.readSampleData(producer, size, false);
|
|
53628
|
+
return {
|
|
53629
|
+
kind: "producer",
|
|
53630
|
+
name: resourceName,
|
|
53631
|
+
records,
|
|
53632
|
+
note: `${records.length} row(s) read from the source now, with this producer's dimensions, types and masks applied.`
|
|
53633
|
+
};
|
|
53634
|
+
}
|
|
53635
|
+
const consumer = Environment_default.getConsumer(resourceName);
|
|
53636
|
+
Affirm_default(consumer, `Resource "${resourceName}" not found. Please check if it exists as a producer or consumer.`);
|
|
53637
|
+
return this._runConsumer(consumer, size, details);
|
|
53638
|
+
};
|
|
53639
|
+
/**
|
|
53640
|
+
* Runs the consumer for real and reads back what it produced.
|
|
53641
|
+
*
|
|
53642
|
+
* The output is captured instead of exported, so nothing reaches the consumer's destination and
|
|
53643
|
+
* no onSuccess action fires: looking at data must never be indistinguishable from publishing it.
|
|
53644
|
+
*/
|
|
53645
|
+
this._runConsumer = async (consumer, size, details) => {
|
|
53646
|
+
this._assertStageable(consumer);
|
|
53647
|
+
const capturePath = import_path24.default.resolve(import_path24.default.join(ExecutorScope_default.getBasePath(), `sample_${consumer.name}_${Helper_default.uuid()}.jsonl`));
|
|
53648
|
+
ExecutorScope_default.ensurePath(capturePath);
|
|
53649
|
+
try {
|
|
53650
|
+
const result = await ExecutorOrchestrator_default.launch({
|
|
53651
|
+
consumer,
|
|
53652
|
+
// `SAMPLE`, so the run it records is distinguishable from one the project did. The
|
|
53653
|
+
// executor treats it like any other invocation; only `RunOverlay` reads the marker.
|
|
53654
|
+
details: { ...details ?? SAMPLE_USER, invokedBy: "SAMPLE" },
|
|
53655
|
+
// The rows asked for, bounded the way `remora run -l` bounds them — pushed to the
|
|
53656
|
+
// source and stopped early per worker wherever nothing downstream can drop a record.
|
|
53657
|
+
options: { limit: size },
|
|
53658
|
+
// Nothing reaches the destination and no finish action fires; the merged dataset
|
|
53659
|
+
// comes back through the same capture the lookup and consumer-input runs use.
|
|
53660
|
+
skipExport: true,
|
|
53661
|
+
captureMainDatasetTo: capturePath,
|
|
53662
|
+
captureFormat: "JSONL"
|
|
53663
|
+
});
|
|
53664
|
+
const captured = await this._readCapture(capturePath, size);
|
|
53665
|
+
const records = captured.map((record) => this._inFieldOrder(consumer, record));
|
|
53666
|
+
Logger_default.log(`[sample] Consumer "${consumer.name}": ${records.length} row(s) from ${result.inputCount} input line(s)`);
|
|
53667
|
+
return {
|
|
53668
|
+
kind: "consumer",
|
|
53669
|
+
name: consumer.name,
|
|
53670
|
+
records,
|
|
53671
|
+
note: `${records.length} row(s) from the real pipeline \u2014 filters, transformations, masking and validation all applied, exactly as in a run. Nothing was written to the destination.`
|
|
53672
|
+
};
|
|
53673
|
+
} finally {
|
|
53674
|
+
await import_promises18.default.rm(capturePath, { force: true });
|
|
53675
|
+
}
|
|
53676
|
+
};
|
|
53677
|
+
/**
|
|
53678
|
+
* Refuses, naming the source, when a run could not read one of this consumer's producers.
|
|
53679
|
+
*
|
|
53680
|
+
* `RedshiftDriver.ready` and `HttpApiSourceDriver.ready` are unimplemented, so the pipeline
|
|
53681
|
+
* cannot reach those sources at all. Checked up front because the alternative is a run that
|
|
53682
|
+
* spins up a worker pool and then surfaces "Not implemented yet" from three layers down, which
|
|
53683
|
+
* names neither the producer nor the source that caused it.
|
|
53684
|
+
*/
|
|
53685
|
+
this._assertStageable = (consumer) => {
|
|
53686
|
+
for (const producer of this._inputProducers(consumer)) {
|
|
53687
|
+
const source = Environment_default.getSource(producer.source);
|
|
53688
|
+
Affirm_default(source, `Producer "${producer.name}" of consumer "${consumer.name}" has no source "${producer.source}"`);
|
|
53689
|
+
if (!DriverFactory_default.canStage(source.engine))
|
|
53690
|
+
throw new Error(`Cannot sample consumer "${consumer.name}": its producer "${producer.name}" reads source "${source.name}", and a "${source.engine}" source cannot be run through the pipeline yet. Sample the producer "${producer.name}" instead to see its rows.`);
|
|
53691
|
+
}
|
|
53692
|
+
};
|
|
53693
|
+
/**
|
|
53694
|
+
* Every producer a run of this consumer would stage — its own, plus those of the consumers it
|
|
53695
|
+
* reads as input or consults as a code_lookup table, since each of those is executed too.
|
|
53696
|
+
*/
|
|
53697
|
+
this._inputProducers = (consumer, visited = []) => {
|
|
53698
|
+
Affirm_default(!visited.includes(consumer.name), `Consumer "${consumer.name}" reads itself through ${visited.join(" \u2192 ")}`);
|
|
53699
|
+
Affirm_default(visited.length < MAX_WALK_DEPTH, `Consumer chain from "${visited[0]}" is more than ${MAX_WALK_DEPTH} deep`);
|
|
53700
|
+
const seen = [...visited, consumer.name];
|
|
53701
|
+
const upstream = [
|
|
53702
|
+
...consumer.producers.map((entry) => entry.name),
|
|
53703
|
+
...ConsumerManager_default.collectLookupRefs(ConsumerManager_default.getExpandedFields(consumer)).map((ref) => ref.consumer)
|
|
53704
|
+
];
|
|
53705
|
+
return upstream.flatMap((name) => {
|
|
53706
|
+
const producer = Environment_default.getProducer(name);
|
|
53707
|
+
if (producer) return [producer];
|
|
53708
|
+
const nested = Environment_default.getConsumer(name);
|
|
53709
|
+
Affirm_default(nested, `Producer or consumer "${name}" not found for consumer "${consumer.name}"`);
|
|
53710
|
+
return this._inputProducers(nested, seen);
|
|
53711
|
+
});
|
|
53712
|
+
};
|
|
53713
|
+
/**
|
|
53714
|
+
* One row's keys in the order the consumer DECLARES its fields.
|
|
53715
|
+
*
|
|
53716
|
+
* A record comes out of a worker keyed in the order the producer's dimensions were read, which is
|
|
53717
|
+
* the source's layout and not the consumer's — so a consumer declaring country, plan, is_active
|
|
53718
|
+
* over a producer that stores is_active first would be shown its own columns in someone else's
|
|
53719
|
+
* order. Invisible in an exported JSON object; the whole shape of the table here.
|
|
53720
|
+
*
|
|
53721
|
+
* Anything the record carries that the field list does not name is appended rather than dropped:
|
|
53722
|
+
* a column that turns up unexpectedly is exactly the one worth seeing.
|
|
53723
|
+
*/
|
|
53724
|
+
this._inFieldOrder = (consumer, record) => {
|
|
53725
|
+
const declared = ConsumerManager_default.getExpandedFields(consumer).filter((field) => !field.cField.hidden).map((field) => field.finalKey);
|
|
53726
|
+
const ordered = {};
|
|
53727
|
+
for (const key of declared) {
|
|
53728
|
+
if (key in record) ordered[key] = record[key];
|
|
53729
|
+
}
|
|
53730
|
+
for (const key of Object.keys(record)) {
|
|
53731
|
+
if (!(key in ordered)) ordered[key] = record[key];
|
|
53732
|
+
}
|
|
53733
|
+
return ordered;
|
|
53734
|
+
};
|
|
53735
|
+
/** The captured dataset, which `captureFormat: 'JSONL'` guarantees is one JSON object per line. */
|
|
53736
|
+
this._readCapture = async (capturePath, size) => {
|
|
53737
|
+
if (!import_fs18.default.existsSync(capturePath)) return [];
|
|
53738
|
+
const records = [];
|
|
53739
|
+
const lines = import_readline11.default.createInterface({ input: import_fs18.default.createReadStream(capturePath), crlfDelay: Infinity });
|
|
53740
|
+
try {
|
|
53741
|
+
for await (const line of lines) {
|
|
53742
|
+
if (!line.length) continue;
|
|
53743
|
+
records.push(JSON.parse(line));
|
|
53744
|
+
if (records.length >= size) break;
|
|
53745
|
+
}
|
|
53746
|
+
} finally {
|
|
53747
|
+
lines.close();
|
|
53748
|
+
}
|
|
53749
|
+
return records;
|
|
53750
|
+
};
|
|
53751
|
+
}
|
|
53752
|
+
};
|
|
53753
|
+
var SampleRunner = new SampleRunnerClass();
|
|
53754
|
+
|
|
53574
53755
|
// src/workers/ExecutorWorker.ts
|
|
53575
53756
|
registerExecutorWorker();
|
|
53576
53757
|
/*! Bundled license information:
|