@nmakarov/cli-toolkit 0.25.0 → 0.29.0
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/dist/cli-runner.cjs +118 -36
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +118 -36
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +114 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +114 -36
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +94 -31
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +94 -31
- package/dist/init.js.map +1 -1
- package/dist/params.cjs +69 -28
- package/dist/params.cjs.map +1 -1
- package/dist/params.js +69 -28
- package/dist/params.js.map +1 -1
- package/dist/s3.cjs +1 -0
- package/dist/s3.cjs.map +1 -1
- package/dist/s3.js +1 -0
- package/dist/s3.js.map +1 -1
- package/dist/tasks.cjs +25 -7
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +25 -7
- package/dist/tasks.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1689,46 +1689,87 @@ var Params = class _Params {
|
|
|
1689
1689
|
paramGetters = [];
|
|
1690
1690
|
trackedParams = [];
|
|
1691
1691
|
_currentModule = "script";
|
|
1692
|
-
/**
|
|
1693
|
-
|
|
1692
|
+
/**
|
|
1693
|
+
* Resolved early in constructor so cleanup does not read params lazily.
|
|
1694
|
+
* One of: false (off) | "end" (print at exit) | "top" (print after init,
|
|
1695
|
+
* via context.showUsedParamsIfNeeded()) | "stop" (print after init, then
|
|
1696
|
+
* exit the process — also via context.showUsedParamsIfNeeded()).
|
|
1697
|
+
*/
|
|
1698
|
+
_showUsedParamsMode = false;
|
|
1699
|
+
/** Guard so the dump prints at most once (top OR end, never both). */
|
|
1700
|
+
_usedParamsPrinted = false;
|
|
1694
1701
|
constructor(context, options = {}) {
|
|
1695
1702
|
this.context = context;
|
|
1696
1703
|
this.args = context.args;
|
|
1697
1704
|
if (Object.keys(options).length > 0) {
|
|
1698
1705
|
this.configure(options);
|
|
1699
1706
|
}
|
|
1700
|
-
this.
|
|
1707
|
+
this._resolveShowUsedParams();
|
|
1701
1708
|
if (context && typeof context.registerCleanup === "function") {
|
|
1702
1709
|
context.registerCleanup((ctx) => {
|
|
1703
|
-
if (!ctx.params.
|
|
1704
|
-
|
|
1705
|
-
const modules = Object.keys(byModule).sort();
|
|
1706
|
-
if (modules.length === 0) return;
|
|
1707
|
-
const logger = ctx.logger;
|
|
1708
|
-
logger.debug("[Params]: list of used params:");
|
|
1709
|
-
if (typeof logger.highlight !== "function") {
|
|
1710
|
-
for (const mod of modules) {
|
|
1711
|
-
logger.debug(` [${mod}]`);
|
|
1712
|
-
for (const [key, entry] of Object.entries(byModule[mod])) {
|
|
1713
|
-
logger.debug(` ${key}: ${JSON.stringify(entry.value)} (${entry.source})`);
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
return;
|
|
1717
|
-
}
|
|
1718
|
-
for (const mod of modules) {
|
|
1719
|
-
logger.debug(` [${mod}]`);
|
|
1720
|
-
for (const [key, entry] of Object.entries(byModule[mod])) {
|
|
1721
|
-
const valueStr = JSON.stringify(entry.value);
|
|
1722
|
-
const display = entry.source === "default" ? valueStr : logger.highlight(valueStr);
|
|
1723
|
-
logger.debug(` ${key}: ${display} (${entry.source})`);
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1710
|
+
if (!ctx.params.getShowUsedParamsMode()) return;
|
|
1711
|
+
ctx.params.printUsedParams(ctx.logger);
|
|
1726
1712
|
});
|
|
1727
1713
|
}
|
|
1728
1714
|
}
|
|
1729
|
-
/**
|
|
1715
|
+
/**
|
|
1716
|
+
* Resolve the --showUsedParams mode. The flag is intentionally dual-typed:
|
|
1717
|
+
* (absent) / --no-showUsedParams / =false -> false (off)
|
|
1718
|
+
* --showUsedParams / =true -> "end" (print at exit)
|
|
1719
|
+
* --showUsedParams=top -> "top" (print after init)
|
|
1720
|
+
* --showUsedParams=stop -> "stop" (print after init, then exit)
|
|
1721
|
+
* Read raw (uncoerced) from args so the string "top"/"stop" isn't forced to
|
|
1722
|
+
* a boolean, then track it under the "script" module for the dump itself.
|
|
1723
|
+
*/
|
|
1724
|
+
_resolveShowUsedParams() {
|
|
1725
|
+
const raw = this.args.get("showUsedParams");
|
|
1726
|
+
const source = this.args.getSource?.("showUsedParams") ?? "default";
|
|
1727
|
+
let mode = false;
|
|
1728
|
+
if (raw === void 0 || raw === null) {
|
|
1729
|
+
mode = false;
|
|
1730
|
+
} else if (typeof raw === "string" && raw.trim().toLowerCase() === "top") {
|
|
1731
|
+
mode = "top";
|
|
1732
|
+
} else if (typeof raw === "string" && raw.trim().toLowerCase() === "stop") {
|
|
1733
|
+
mode = "stop";
|
|
1734
|
+
} else {
|
|
1735
|
+
const s = typeof raw === "string" ? raw.trim().toLowerCase() : raw;
|
|
1736
|
+
const falsey = s === false || s === "false" || s === "0" || s === "no" || s === "off";
|
|
1737
|
+
mode = falsey ? false : "end";
|
|
1738
|
+
}
|
|
1739
|
+
this._showUsedParamsMode = mode;
|
|
1740
|
+
this.trackParam("showUsedParams", "string", mode, raw === void 0 ? "default" : source, "script");
|
|
1741
|
+
return mode;
|
|
1742
|
+
}
|
|
1743
|
+
/** Whether --showUsedParams was requested in any mode (truthy = on). */
|
|
1730
1744
|
getShowUsedParams() {
|
|
1731
|
-
return this.
|
|
1745
|
+
return this._showUsedParamsMode !== false;
|
|
1746
|
+
}
|
|
1747
|
+
/** Resolved mode: false | "end" | "top" | "stop". */
|
|
1748
|
+
getShowUsedParamsMode() {
|
|
1749
|
+
return this._showUsedParamsMode;
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* Print the module-grouped list of figured params (the --showUsedParams
|
|
1753
|
+
* dump). Idempotent: only the first call prints, so callers can invoke it
|
|
1754
|
+
* at the top (long-running services) without double-printing at exit.
|
|
1755
|
+
*/
|
|
1756
|
+
printUsedParams(logger) {
|
|
1757
|
+
if (this._usedParamsPrinted) return;
|
|
1758
|
+
const byModule = this.getFiguredByModule();
|
|
1759
|
+
const modules = Object.keys(byModule).sort();
|
|
1760
|
+
if (modules.length === 0) return;
|
|
1761
|
+
this._usedParamsPrinted = true;
|
|
1762
|
+
logger = logger ?? this.context?.logger ?? console;
|
|
1763
|
+
const hasHighlight = typeof logger.highlight === "function";
|
|
1764
|
+
logger.debug("[Params]: list of used params:");
|
|
1765
|
+
for (const mod of modules) {
|
|
1766
|
+
logger.debug(` [${mod}]`);
|
|
1767
|
+
for (const [key, entry] of Object.entries(byModule[mod])) {
|
|
1768
|
+
const valueStr = JSON.stringify(entry.value);
|
|
1769
|
+
const display = hasHighlight && entry.source !== "default" ? logger.highlight(valueStr) : valueStr;
|
|
1770
|
+
logger.debug(` ${key}: ${display} (${entry.source})`);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1732
1773
|
}
|
|
1733
1774
|
/**
|
|
1734
1775
|
* Configure parameters
|
|
@@ -3749,6 +3790,7 @@ var S3 = class _S3 {
|
|
|
3749
3790
|
secretAccessKey: config2.secretAccessKey
|
|
3750
3791
|
};
|
|
3751
3792
|
}
|
|
3793
|
+
process.env.AWS_SDK_JS_NODE_VERSION_SUPPORT_WARNING_DISABLED ??= "true";
|
|
3752
3794
|
this.client = new S3Client(clientConfig);
|
|
3753
3795
|
}
|
|
3754
3796
|
// ── info ────────────────────────────────────────────────────────────────
|
|
@@ -4275,7 +4317,25 @@ function setup(opts = {}) {
|
|
|
4275
4317
|
emitter: partialContext.emitter,
|
|
4276
4318
|
isStop: partialContext.isStop,
|
|
4277
4319
|
cleanupFunctions: partialContext.cleanupFunctions,
|
|
4278
|
-
registerCleanup: partialContext.registerCleanup
|
|
4320
|
+
registerCleanup: partialContext.registerCleanup,
|
|
4321
|
+
// For long-running scripts (servers): with --showUsedParams=top, print
|
|
4322
|
+
// the used-params list now (after the script has initialized all its
|
|
4323
|
+
// own components), instead of at exit. No-op for the default mode,
|
|
4324
|
+
// which prints at exit via the cleanup registered by Params.
|
|
4325
|
+
//
|
|
4326
|
+
// --showUsedParams=stop behaves like "top" but then exits immediately —
|
|
4327
|
+
// a quick "show me the figured params and quit" that skips the flow's
|
|
4328
|
+
// actual work. Like --stopAfter=init, this is a hard exit(0) (registered
|
|
4329
|
+
// cleanups are skipped); call it once components/params are resolved.
|
|
4330
|
+
showUsedParamsIfNeeded: () => {
|
|
4331
|
+
const mode = params.getShowUsedParamsMode?.();
|
|
4332
|
+
if (mode !== "top" && mode !== "stop") return;
|
|
4333
|
+
params.printUsedParams(logger);
|
|
4334
|
+
if (mode === "stop") {
|
|
4335
|
+
logger.debug?.("[showUsedParams=stop] params printed \u2014 exiting");
|
|
4336
|
+
process.exit(0);
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4279
4339
|
};
|
|
4280
4340
|
logger.debug("[setup] completed successfully");
|
|
4281
4341
|
return context;
|
|
@@ -4397,7 +4457,7 @@ function defineTasksTable(t, db, tableNameForIndex) {
|
|
|
4397
4457
|
t.timestamp("past_due").defaultTo(null);
|
|
4398
4458
|
t.text("name").notNullable();
|
|
4399
4459
|
t.text("opid");
|
|
4400
|
-
t.
|
|
4460
|
+
t.jsonb("params");
|
|
4401
4461
|
t.text("service_group");
|
|
4402
4462
|
t.integer("instance_number");
|
|
4403
4463
|
t.text("service_name");
|
|
@@ -4406,7 +4466,7 @@ function defineTasksTable(t, db, tableNameForIndex) {
|
|
|
4406
4466
|
t.timestamp("status_changed_at").defaultTo(null);
|
|
4407
4467
|
t.text("progress");
|
|
4408
4468
|
t.boolean("success");
|
|
4409
|
-
t.
|
|
4469
|
+
t.jsonb("results");
|
|
4410
4470
|
t.index(["service_group", "status", "priority", "created_at"], `${tableNameForIndex}_claim_idx`);
|
|
4411
4471
|
t.index(["service_group", "name"], `${tableNameForIndex}_group_name_idx`);
|
|
4412
4472
|
}
|
|
@@ -4421,11 +4481,29 @@ function taskHistoryInsertFromQueueRow(row, overrides) {
|
|
|
4421
4481
|
async function ensureTaskTables(context, options = {}) {
|
|
4422
4482
|
const queueName = options.queueName ?? "tasks";
|
|
4423
4483
|
const recreate = options.recreate ?? false;
|
|
4484
|
+
const dryRun = options.dryRun ?? false;
|
|
4424
4485
|
const db = getDb(context);
|
|
4486
|
+
const log = context.logger ?? console;
|
|
4425
4487
|
const { tasksTable, historyTable, registryTable } = queueToTableNames(queueName);
|
|
4426
4488
|
const needsTasks = recreate ? true : !await db.tableExists(tasksTable);
|
|
4427
4489
|
const needsHistory = recreate ? true : !await db.tableExists(historyTable);
|
|
4428
4490
|
const needsRegistry = recreate ? true : !await db.tableExists(registryTable);
|
|
4491
|
+
if (dryRun) {
|
|
4492
|
+
const plan = [];
|
|
4493
|
+
if (recreate) {
|
|
4494
|
+
plan.push(`DROP TABLE IF EXISTS ${historyTable}, ${tasksTable}, ${registryTable}`);
|
|
4495
|
+
}
|
|
4496
|
+
if (needsTasks) plan.push(`CREATE TABLE ${tasksTable} (tasks queue)`);
|
|
4497
|
+
if (needsHistory) plan.push(`CREATE TABLE ${historyTable} (history mirror)`);
|
|
4498
|
+
if (needsRegistry) plan.push(`CREATE TABLE ${registryTable} (services registry)`);
|
|
4499
|
+
if (plan.length === 0) {
|
|
4500
|
+
log.info?.(`[tasks-schema] dryRun \u2014 queue "${queueName}" already up to date; no DDL`);
|
|
4501
|
+
} else {
|
|
4502
|
+
log.info?.(`[tasks-schema] dryRun \u2014 would run ${plan.length} statement(s) for queue "${queueName}":`);
|
|
4503
|
+
for (const s of plan) log.info?.(` - ${s}`);
|
|
4504
|
+
}
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4429
4507
|
if (recreate) {
|
|
4430
4508
|
await db.schema.dropTableIfExists(historyTable);
|
|
4431
4509
|
await db.schema.dropTableIfExists(tasksTable);
|
|
@@ -5868,8 +5946,7 @@ function forwardChildLogToParent(context, prefix, message) {
|
|
|
5868
5946
|
}
|
|
5869
5947
|
function buildNodeArgs(scriptPath, cliArgs) {
|
|
5870
5948
|
const inheritedExecArgs = Array.isArray(process.execArgv) ? [...process.execArgv] : [];
|
|
5871
|
-
|
|
5872
|
-
return hasTsRuntimeInParent ? [...inheritedExecArgs, scriptPath, ...cliArgs] : ["--import", "tsx", scriptPath, ...cliArgs];
|
|
5949
|
+
return [...inheritedExecArgs, scriptPath, ...cliArgs];
|
|
5873
5950
|
}
|
|
5874
5951
|
function resolveTasksTableName(context) {
|
|
5875
5952
|
return context.tasksQueueName || context.params?.get?.("table") || "tasks";
|
|
@@ -6109,9 +6186,8 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
6109
6186
|
const dbName = String(context?.params?.get?.("dbName") || "local");
|
|
6110
6187
|
const tableName = String(context?.params?.get?.("table") || "tasks");
|
|
6111
6188
|
const fallbackRecoverCommand = [
|
|
6112
|
-
"
|
|
6113
|
-
"
|
|
6114
|
-
"examples/tasks/recover-task.ts",
|
|
6189
|
+
"node",
|
|
6190
|
+
"examples/tasks/recover-task.js",
|
|
6115
6191
|
`--dbName='${dbName.replace(/'/g, `'\\''`)}'`,
|
|
6116
6192
|
`--table='${tableName.replace(/'/g, `'\\''`)}'`,
|
|
6117
6193
|
`--id='${String(row.id).replace(/'/g, `'\\''`)}'`
|
|
@@ -6177,6 +6253,8 @@ async function claimNextRunnableTask(context, tasksTable, serviceGroup, registry
|
|
|
6177
6253
|
const db = getDb3(context);
|
|
6178
6254
|
let query = db(tasksTable).where({ status: "idle" }).where(function() {
|
|
6179
6255
|
this.whereNull("service_group").orWhere({ service_group: serviceGroup });
|
|
6256
|
+
}).where(function() {
|
|
6257
|
+
this.whereNull("next_run_at").orWhere("next_run_at", "<=", db.fn.now());
|
|
6180
6258
|
}).orderByRaw("CASE WHEN past_due IS NULL THEN 1 ELSE 0 END ASC").orderBy([{ column: "priority", order: "asc" }]).orderByRaw("CASE WHEN completed_at IS NULL THEN 0 ELSE 1 END ASC").orderBy([{ column: "completed_at", order: "asc" }, { column: "created_at", order: "asc" }]).limit(scanLimit);
|
|
6181
6259
|
if (taskNames && taskNames.length > 0) {
|
|
6182
6260
|
query = query.whereIn("name", taskNames);
|