@caelo-cms/provisioning 0.11.10 → 0.11.12
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/adapter.d.ts +6 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adopt-existing.d.ts +6 -2
- package/dist/adopt-existing.d.ts.map +1 -1
- package/dist/adopt-existing.js +57 -0
- package/dist/adopt-existing.js.map +1 -1
- package/dist/agent/command.d.ts +5 -2
- package/dist/agent/command.d.ts.map +1 -1
- package/dist/agent/command.js +1 -1
- package/dist/agent/command.js.map +1 -1
- package/dist/agent-db.js +196 -23
- package/dist/cli-routing.js +1 -1
- package/dist/cli-routing.js.map +1 -1
- package/dist/cli.js +59 -7
- package/dist/cli.js.map +1 -1
- package/dist/cloudsql-tls.d.ts +30 -0
- package/dist/cloudsql-tls.d.ts.map +1 -1
- package/dist/cloudsql-tls.js +7 -1
- package/dist/cloudsql-tls.js.map +1 -1
- package/dist/compose.d.ts +14 -0
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +54 -1
- package/dist/compose.js.map +1 -1
- package/dist/converge-db-trust.d.ts +44 -0
- package/dist/converge-db-trust.d.ts.map +1 -0
- package/dist/converge-db-trust.js +158 -0
- package/dist/converge-db-trust.js.map +1 -0
- package/dist/converge-job-gcp.d.ts +12 -2
- package/dist/converge-job-gcp.d.ts.map +1 -1
- package/dist/converge-job-gcp.js +42 -3
- package/dist/converge-job-gcp.js.map +1 -1
- package/dist/converge-job-preflight.d.ts +34 -2
- package/dist/converge-job-preflight.d.ts.map +1 -1
- package/dist/converge-job-preflight.js +76 -1
- package/dist/converge-job-preflight.js.map +1 -1
- package/dist/converge-job-setup.d.ts.map +1 -1
- package/dist/converge-job-setup.js +4 -1
- package/dist/converge-job-setup.js.map +1 -1
- package/dist/converge-job.d.ts +44 -3
- package/dist/converge-job.d.ts.map +1 -1
- package/dist/converge-job.js +105 -11
- package/dist/converge-job.js.map +1 -1
- package/dist/gcp-names.d.ts +13 -0
- package/dist/gcp-names.d.ts.map +1 -1
- package/dist/gcp-names.js +21 -0
- package/dist/gcp-names.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/infra-contract.d.ts +1 -1
- package/dist/infra-contract.d.ts.map +1 -1
- package/dist/infra-contract.js +22 -1
- package/dist/infra-contract.js.map +1 -1
- package/dist/install-job.d.ts +10 -2
- package/dist/install-job.d.ts.map +1 -1
- package/dist/install-job.js +10 -1
- package/dist/install-job.js.map +1 -1
- package/dist/install-state.d.ts +7 -0
- package/dist/install-state.d.ts.map +1 -1
- package/dist/install-state.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +3 -0
- package/dist/lifecycle.js.map +1 -1
- package/dist/mcp-auth-proxy-setup.d.ts +3 -1
- package/dist/mcp-auth-proxy-setup.d.ts.map +1 -1
- package/dist/mcp-auth-proxy-setup.js +9 -4
- package/dist/mcp-auth-proxy-setup.js.map +1 -1
- package/dist/migration-runner.d.ts.map +1 -1
- package/dist/migration-runner.js +8 -3
- package/dist/migration-runner.js.map +1 -1
- package/dist/migration-targets.d.ts +11 -0
- package/dist/migration-targets.d.ts.map +1 -0
- package/dist/migration-targets.js +12 -0
- package/dist/migration-targets.js.map +1 -0
- package/dist/operator-access.d.ts +10 -0
- package/dist/operator-access.d.ts.map +1 -1
- package/dist/operator-access.js +5 -0
- package/dist/operator-access.js.map +1 -1
- package/dist/pool-budget-stack.d.ts +13 -1
- package/dist/pool-budget-stack.d.ts.map +1 -1
- package/dist/pool-budget-stack.js +11 -1
- package/dist/pool-budget-stack.js.map +1 -1
- package/dist/public-role-isolation.d.ts +7 -3
- package/dist/public-role-isolation.d.ts.map +1 -1
- package/dist/public-role-isolation.js +25 -13
- package/dist/public-role-isolation.js.map +1 -1
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +3 -0
- package/dist/release-contract.js.map +1 -1
- package/dist/runtime-secrets.d.ts +2 -0
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +19 -15
- package/dist/runtime-secrets.js.map +1 -1
- package/dist/scheduler-setup.d.ts +75 -0
- package/dist/scheduler-setup.d.ts.map +1 -0
- package/dist/scheduler-setup.js +331 -0
- package/dist/scheduler-setup.js.map +1 -0
- package/dist/self-hosted-roles.d.ts +16 -9
- package/dist/self-hosted-roles.d.ts.map +1 -1
- package/dist/self-hosted-roles.js +49 -15
- package/dist/self-hosted-roles.js.map +1 -1
- package/dist/self-hosted-scheduler-interval.d.ts +21 -0
- package/dist/self-hosted-scheduler-interval.d.ts.map +1 -0
- package/dist/self-hosted-scheduler-interval.js +68 -0
- package/dist/self-hosted-scheduler-interval.js.map +1 -0
- package/dist/self-hosted-upgrade.d.ts +7 -4
- package/dist/self-hosted-upgrade.d.ts.map +1 -1
- package/dist/self-hosted-upgrade.js +9 -5
- package/dist/self-hosted-upgrade.js.map +1 -1
- package/dist/stack-contract.d.ts +67 -6
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +87 -6
- package/dist/stack-contract.js.map +1 -1
- package/dist/staging-database.d.ts +22 -0
- package/dist/staging-database.d.ts.map +1 -0
- package/dist/staging-database.js +117 -0
- package/dist/staging-database.js.map +1 -0
- package/dist/upgrade/converge.d.ts +5 -0
- package/dist/upgrade/converge.d.ts.map +1 -1
- package/dist/upgrade/converge.js +110 -10
- package/dist/upgrade/converge.js.map +1 -1
- package/dist/upgrade/upgrade.d.ts +6 -0
- package/dist/upgrade/upgrade.d.ts.map +1 -1
- package/dist/upgrade/upgrade.js +3 -0
- package/dist/upgrade/upgrade.js.map +1 -1
- package/dist/upgrader-gcp.d.ts +5 -4
- package/dist/upgrader-gcp.d.ts.map +1 -1
- package/dist/upgrader-gcp.js +5 -4
- package/dist/upgrader-gcp.js.map +1 -1
- package/dist/upgrader-iam-preflight.d.ts +8 -6
- package/dist/upgrader-iam-preflight.d.ts.map +1 -1
- package/dist/upgrader-iam-preflight.js +5 -1
- package/dist/upgrader-iam-preflight.js.map +1 -1
- package/dist/wizard.d.ts +7 -0
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +11 -0
- package/dist/wizard.js.map +1 -1
- package/dist/wizards/gcp-cost.d.ts +31 -0
- package/dist/wizards/gcp-cost.d.ts.map +1 -1
- package/dist/wizards/gcp-cost.js +82 -12
- package/dist/wizards/gcp-cost.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +87 -11
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter.ts +6 -0
- package/src/admin-memory.test.ts +1 -1
- package/src/adopt-existing.test.ts +46 -0
- package/src/adopt-existing.ts +58 -2
- package/src/agent/command.ts +6 -3
- package/src/caddy-redirects.test.ts +1 -1
- package/src/cli-routing.test.ts +1 -1
- package/src/cli-routing.ts +1 -1
- package/src/cli.ts +63 -8
- package/src/cloudsql-tls.test.ts +30 -0
- package/src/cloudsql-tls.ts +10 -3
- package/src/compose.ts +68 -0
- package/src/converge-db-trust.test.ts +237 -0
- package/src/converge-db-trust.ts +212 -0
- package/src/converge-job-gcp.ts +42 -2
- package/src/converge-job-preflight.test.ts +106 -0
- package/src/converge-job-preflight.ts +97 -3
- package/src/converge-job-setup.ts +4 -1
- package/src/converge-job.test.ts +213 -0
- package/src/converge-job.ts +175 -19
- package/src/database-tls-builders.test.ts +3 -2
- package/src/deployed-release.test.ts +3 -0
- package/src/gateway-env-isolation.test.ts +40 -7
- package/src/gcp-names.ts +25 -0
- package/src/index.test.ts +3 -3
- package/src/index.ts +6 -0
- package/src/infra-contract.test.ts +5 -3
- package/src/infra-contract.ts +22 -1
- package/src/install-job.ts +10 -1
- package/src/install-state.ts +7 -0
- package/src/lifecycle.ts +3 -0
- package/src/mcp-auth-proxy-setup.test.ts +33 -1
- package/src/mcp-auth-proxy-setup.ts +11 -4
- package/src/migration-runner.ts +14 -9
- package/src/migration-targets.ts +12 -0
- package/src/operator-access.test.ts +15 -0
- package/src/operator-access.ts +14 -0
- package/src/pool-budget-stack.ts +15 -0
- package/src/pool-budget-stacks.test.ts +38 -13
- package/src/public-role-isolation.test.ts +18 -8
- package/src/public-role-isolation.ts +31 -17
- package/src/release-contract.ts +3 -0
- package/src/runtime-secrets.test.ts +18 -8
- package/src/runtime-secrets.ts +37 -18
- package/src/scheduler-setup.test.ts +201 -0
- package/src/scheduler-setup.ts +375 -0
- package/src/self-hosted-backup.test.ts +1 -0
- package/src/self-hosted-compose.test.ts +72 -1
- package/src/self-hosted-roles.integration.test.ts +2 -0
- package/src/self-hosted-roles.test.ts +49 -19
- package/src/self-hosted-roles.ts +60 -20
- package/src/self-hosted-scheduler-interval.test.ts +66 -0
- package/src/self-hosted-scheduler-interval.ts +79 -0
- package/src/self-hosted-start.test.ts +1 -0
- package/src/self-hosted-upgrade.test.ts +2 -1
- package/src/self-hosted-upgrade.ts +14 -8
- package/src/stack-contract.test.ts +31 -3
- package/src/stack-contract.ts +113 -6
- package/src/stack-converge-secrets.test.ts +2 -0
- package/src/stack-converge.test.ts +6 -4
- package/src/staging-database.test.ts +114 -0
- package/src/staging-database.ts +148 -0
- package/src/upgrade/converge.ts +130 -9
- package/src/upgrade/upgrade.test.ts +85 -2
- package/src/upgrade/upgrade.ts +9 -0
- package/src/upgrader-gcp.ts +5 -4
- package/src/upgrader-iam-preflight.ts +15 -10
- package/src/wizard.ts +19 -0
- package/src/wizards/gcp-cost.test.ts +54 -1
- package/src/wizards/gcp-cost.ts +102 -12
- package/src/wizards/gcp.ts +109 -8
- package/stacks/aws/Pulumi.yaml +1 -1
- package/stacks/aws/index.ts +41 -1
- package/stacks/azure/index.ts +51 -3
- package/stacks/gcp/Pulumi.yaml +1 -1
- package/stacks/gcp/README.md +1 -0
- package/stacks/gcp/index.ts +50 -1
- package/stacks/gcp-firebase/Pulumi.yaml +1 -1
- package/stacks/gcp-firebase/index.ts +50 -1
- package/stacks/self-hosted/Pulumi.yaml +3 -0
- package/stacks/self-hosted/README.md +4 -0
- package/stacks/self-hosted/index.ts +29 -4
package/dist/agent-db.js
CHANGED
|
@@ -18856,6 +18856,7 @@ async function recordAudit(tx, opts) {
|
|
|
18856
18856
|
var SYSTEM_ACTOR_ID = "00000000-0000-0000-0000-00000000ffff";
|
|
18857
18857
|
|
|
18858
18858
|
// ../query-api/src/branch-access.ts
|
|
18859
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
18859
18860
|
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
18860
18861
|
function namedBranches(ctx, input) {
|
|
18861
18862
|
const out = new Set;
|
|
@@ -18879,12 +18880,71 @@ function branchNotFound(operation, chatBranchId) {
|
|
|
18879
18880
|
function firstMalformedBranch(branches) {
|
|
18880
18881
|
return branches.find((b) => !UUID_RE2.test(b)) ?? null;
|
|
18881
18882
|
}
|
|
18882
|
-
|
|
18883
|
+
var VERDICT_MAX_AGE_MS = 30000;
|
|
18884
|
+
var visibilityScope = new AsyncLocalStorage;
|
|
18885
|
+
function verdictKey(ctx, branch) {
|
|
18886
|
+
return `${ctx.actorKind}|${ctx.actorId}|${ctx.chatTaskId ?? ""}|${branch}`;
|
|
18887
|
+
}
|
|
18888
|
+
function rememberedVerdict(ctx, branch) {
|
|
18889
|
+
const scope = visibilityScope.getStore();
|
|
18890
|
+
if (!scope)
|
|
18891
|
+
return;
|
|
18892
|
+
const key = verdictKey(ctx, branch);
|
|
18893
|
+
const hit = scope.verdicts.get(key);
|
|
18894
|
+
if (!hit)
|
|
18895
|
+
return;
|
|
18896
|
+
if (Date.now() - hit.at > VERDICT_MAX_AGE_MS) {
|
|
18897
|
+
scope.verdicts.delete(key);
|
|
18898
|
+
return;
|
|
18899
|
+
}
|
|
18900
|
+
return hit.visible;
|
|
18901
|
+
}
|
|
18902
|
+
function rememberVerdict(ctx, branch, visible) {
|
|
18903
|
+
const scope = visibilityScope.getStore();
|
|
18904
|
+
if (!scope)
|
|
18905
|
+
return;
|
|
18906
|
+
const key = verdictKey(ctx, branch);
|
|
18907
|
+
const entry = { visible, at: Date.now() };
|
|
18908
|
+
scope.verdicts.set(key, entry);
|
|
18909
|
+
visible.catch(() => {
|
|
18910
|
+
if (scope.verdicts.get(key) === entry)
|
|
18911
|
+
scope.verdicts.delete(key);
|
|
18912
|
+
});
|
|
18913
|
+
}
|
|
18914
|
+
async function rememberedFirstInvisible(ctx, branches) {
|
|
18915
|
+
const pending = [];
|
|
18883
18916
|
for (const branch of branches) {
|
|
18884
18917
|
if (!UUID_RE2.test(branch))
|
|
18885
18918
|
return branch;
|
|
18886
|
-
const
|
|
18887
|
-
if (
|
|
18919
|
+
const visible = rememberedVerdict(ctx, branch);
|
|
18920
|
+
if (!visible)
|
|
18921
|
+
return;
|
|
18922
|
+
pending.push({ branch, visible });
|
|
18923
|
+
}
|
|
18924
|
+
for (const p of pending) {
|
|
18925
|
+
try {
|
|
18926
|
+
if (!await p.visible)
|
|
18927
|
+
return p.branch;
|
|
18928
|
+
} catch {
|
|
18929
|
+
return;
|
|
18930
|
+
}
|
|
18931
|
+
}
|
|
18932
|
+
return null;
|
|
18933
|
+
}
|
|
18934
|
+
async function firstInvisibleBranch(tx, branches, ctx) {
|
|
18935
|
+
for (const branch of branches) {
|
|
18936
|
+
if (!UUID_RE2.test(branch))
|
|
18937
|
+
return branch;
|
|
18938
|
+
let visible = ctx ? rememberedVerdict(ctx, branch) : undefined;
|
|
18939
|
+
if (!visible) {
|
|
18940
|
+
visible = (async () => {
|
|
18941
|
+
const rows = await tx.execute(sql`SELECT caelo_branch_visible(${branch}::uuid) AS visible`);
|
|
18942
|
+
return rows[0]?.visible === true;
|
|
18943
|
+
})();
|
|
18944
|
+
if (ctx)
|
|
18945
|
+
rememberVerdict(ctx, branch, visible);
|
|
18946
|
+
}
|
|
18947
|
+
if (!await visible)
|
|
18888
18948
|
return branch;
|
|
18889
18949
|
}
|
|
18890
18950
|
return null;
|
|
@@ -19106,7 +19166,7 @@ async function provisionPluginSchemaInTx(tx, caller, opts) {
|
|
|
19106
19166
|
}
|
|
19107
19167
|
|
|
19108
19168
|
// ../query-api/src/pool-guard.ts
|
|
19109
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
19169
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
19110
19170
|
var POOL_ACQUIRE_TIMEOUT_MS = 1e4;
|
|
19111
19171
|
var LONG_TRANSACTIONS = [
|
|
19112
19172
|
{
|
|
@@ -19146,13 +19206,14 @@ class PoolAcquireTimeoutError extends Error {
|
|
|
19146
19206
|
timeoutMs;
|
|
19147
19207
|
name = "PoolAcquireTimeoutError";
|
|
19148
19208
|
constructor(pool, requester, timeoutMs) {
|
|
19149
|
-
super(`the ${pool} database pool had no free connection for ${requester} within ${timeoutMs} ms: every connection is busy. ` +
|
|
19209
|
+
super(`the ${pool} database pool had no free connection for ${requester} within ${timeoutMs} ms: every connection is busy. ` + `Nothing was changed. Retry in a few seconds (wait about ${Math.round(POOL_BUSY_RETRY_AFTER_MS / 1000)} s, then send the same call again unchanged); ` + "if it keeps happening the admin is overloaded or a request holds its connections \u2014 the server log names it.");
|
|
19150
19210
|
this.pool = pool;
|
|
19151
19211
|
this.requester = requester;
|
|
19152
19212
|
this.timeoutMs = timeoutMs;
|
|
19153
19213
|
}
|
|
19154
19214
|
}
|
|
19155
|
-
var
|
|
19215
|
+
var POOL_BUSY_RETRY_AFTER_MS = 5000;
|
|
19216
|
+
var joining = new AsyncLocalStorage2;
|
|
19156
19217
|
function newMarker(holder, root) {
|
|
19157
19218
|
return {
|
|
19158
19219
|
holder,
|
|
@@ -19168,8 +19229,8 @@ function newMarker(holder, root) {
|
|
|
19168
19229
|
|
|
19169
19230
|
class PoolGuard {
|
|
19170
19231
|
#stores = {
|
|
19171
|
-
admin: new
|
|
19172
|
-
public: new
|
|
19232
|
+
admin: new AsyncLocalStorage2,
|
|
19233
|
+
public: new AsyncLocalStorage2
|
|
19173
19234
|
};
|
|
19174
19235
|
plan(pool, holder) {
|
|
19175
19236
|
const outer = this.held(pool);
|
|
@@ -19231,6 +19292,50 @@ function detachedRunner(operation, open) {
|
|
|
19231
19292
|
});
|
|
19232
19293
|
}
|
|
19233
19294
|
|
|
19295
|
+
// ../query-api/src/pool-pressure.ts
|
|
19296
|
+
var BUN_DEFAULT_POOL_MAX = 10;
|
|
19297
|
+
|
|
19298
|
+
class PoolDemand {
|
|
19299
|
+
#pool;
|
|
19300
|
+
#max;
|
|
19301
|
+
#now;
|
|
19302
|
+
#next = 0;
|
|
19303
|
+
#waiting = new Map;
|
|
19304
|
+
#holding = new Map;
|
|
19305
|
+
constructor(pool, max, now = Date.now) {
|
|
19306
|
+
this.#pool = pool;
|
|
19307
|
+
this.#max = max;
|
|
19308
|
+
this.#now = now;
|
|
19309
|
+
}
|
|
19310
|
+
beginWait() {
|
|
19311
|
+
const id = this.#next++;
|
|
19312
|
+
this.#waiting.set(id, this.#now());
|
|
19313
|
+
return () => {
|
|
19314
|
+
this.#waiting.delete(id);
|
|
19315
|
+
};
|
|
19316
|
+
}
|
|
19317
|
+
beginHold(holder) {
|
|
19318
|
+
const id = this.#next++;
|
|
19319
|
+
this.#holding.set(id, { holder, since: this.#now() });
|
|
19320
|
+
return () => {
|
|
19321
|
+
this.#holding.delete(id);
|
|
19322
|
+
};
|
|
19323
|
+
}
|
|
19324
|
+
snapshot() {
|
|
19325
|
+
const now = this.#now();
|
|
19326
|
+
const firstWait = this.#waiting.values().next();
|
|
19327
|
+
const holders = [...this.#holding.values()].map((h) => ({ holder: h.holder, heldMs: now - h.since })).sort((a, b) => b.heldMs - a.heldMs);
|
|
19328
|
+
return {
|
|
19329
|
+
pool: this.#pool,
|
|
19330
|
+
max: this.#max,
|
|
19331
|
+
inUse: this.#holding.size,
|
|
19332
|
+
waiting: this.#waiting.size,
|
|
19333
|
+
oldestWaitMs: firstWait.done ? 0 : now - firstWait.value,
|
|
19334
|
+
holders
|
|
19335
|
+
};
|
|
19336
|
+
}
|
|
19337
|
+
}
|
|
19338
|
+
|
|
19234
19339
|
// ../query-api/src/post-commit.ts
|
|
19235
19340
|
var pendingByTx = new WeakMap;
|
|
19236
19341
|
function collectPostCommitEffects(tx) {
|
|
@@ -19367,20 +19472,24 @@ class DatabaseAdapter {
|
|
|
19367
19472
|
#adminRaw;
|
|
19368
19473
|
#publicRaw;
|
|
19369
19474
|
#adminUrl;
|
|
19475
|
+
#tls;
|
|
19370
19476
|
#publicUrl;
|
|
19371
19477
|
#listeners = new Map;
|
|
19372
19478
|
#listenLost = new Map;
|
|
19373
19479
|
#listenersClosing = false;
|
|
19374
19480
|
#skipVerify;
|
|
19375
19481
|
#roles;
|
|
19482
|
+
#publicDatabase;
|
|
19376
19483
|
#acquireTimeoutMs;
|
|
19377
19484
|
#guard = new PoolGuard;
|
|
19485
|
+
#demand;
|
|
19378
19486
|
#verifyPromise = null;
|
|
19379
19487
|
#projectionPublisher = null;
|
|
19380
19488
|
#onStatement;
|
|
19381
19489
|
#drizzleOptions;
|
|
19382
19490
|
constructor(config) {
|
|
19383
19491
|
this.#roles = config.expectedRoles ?? DEFAULT_ROLES;
|
|
19492
|
+
this.#publicDatabase = config.publicDatabase ?? "cms_public";
|
|
19384
19493
|
if (config.adminDatabaseUrl === null !== (this.#roles.admin === null)) {
|
|
19385
19494
|
throw new Error("DatabaseAdapter: a public-only adapter (adminDatabaseUrl: null) must expect no admin role, and an adapter with an admin URL must expect one");
|
|
19386
19495
|
}
|
|
@@ -19388,7 +19497,9 @@ class DatabaseAdapter {
|
|
|
19388
19497
|
const poolMax = resolvePoolMax(config.poolMax);
|
|
19389
19498
|
const publicPoolMax = resolvePublicPoolMax(config.publicPoolMax, config.poolMax);
|
|
19390
19499
|
const idleTimeout = config.poolIdleTimeoutSeconds ?? POOL_IDLE_TIMEOUT_SECONDS;
|
|
19391
|
-
|
|
19500
|
+
this.#tls = config.tls ?? null;
|
|
19501
|
+
const tls = this.#tls ? { tls: this.#tls } : {};
|
|
19502
|
+
const open = (url, max) => new SQL3(url, max === undefined ? { idleTimeout, ...tls } : { max, idleTimeout, ...tls });
|
|
19392
19503
|
this.#adminRaw = config.adminDatabaseUrl === null ? null : open(config.adminDatabaseUrl, poolMax);
|
|
19393
19504
|
this.#publicRaw = open(config.publicDatabaseUrl, publicPoolMax);
|
|
19394
19505
|
this.#adminUrl = config.adminDatabaseUrl;
|
|
@@ -19400,6 +19511,13 @@ class DatabaseAdapter {
|
|
|
19400
19511
|
this.#public = drizzle(this.#publicRaw, this.#drizzleOptions);
|
|
19401
19512
|
this.#skipVerify = config.skipRoleVerification === true;
|
|
19402
19513
|
this.#acquireTimeoutMs = config.poolAcquireTimeoutMs ?? POOL_ACQUIRE_TIMEOUT_MS;
|
|
19514
|
+
this.#demand = {
|
|
19515
|
+
admin: new PoolDemand("admin", poolMax ?? BUN_DEFAULT_POOL_MAX),
|
|
19516
|
+
public: new PoolDemand("public", publicPoolMax ?? BUN_DEFAULT_POOL_MAX)
|
|
19517
|
+
};
|
|
19518
|
+
}
|
|
19519
|
+
poolPressure(pool) {
|
|
19520
|
+
return this.#demand[pool].snapshot();
|
|
19403
19521
|
}
|
|
19404
19522
|
async#transaction(pool, holder, fn) {
|
|
19405
19523
|
const raw = pool === "admin" ? this.#adminRaw : this.#publicRaw;
|
|
@@ -19410,6 +19528,7 @@ class DatabaseAdapter {
|
|
|
19410
19528
|
return this.#joinHeld(pool, plan.outer, plan.marker, fn);
|
|
19411
19529
|
const marker = plan.marker;
|
|
19412
19530
|
const reserved = await this.#reserve(pool, raw, holder);
|
|
19531
|
+
const endHold = this.#demand[pool].beginHold(holder);
|
|
19413
19532
|
try {
|
|
19414
19533
|
const db = drizzle({ client: reserved, ...this.#drizzleOptions });
|
|
19415
19534
|
this.#onStatement?.("BEGIN");
|
|
@@ -19423,6 +19542,7 @@ class DatabaseAdapter {
|
|
|
19423
19542
|
return out;
|
|
19424
19543
|
} finally {
|
|
19425
19544
|
reserved.release();
|
|
19545
|
+
endHold();
|
|
19426
19546
|
await this.#runAfterEnd(marker);
|
|
19427
19547
|
}
|
|
19428
19548
|
}
|
|
@@ -19466,6 +19586,7 @@ class DatabaseAdapter {
|
|
|
19466
19586
|
async#reserve(pool, raw, requester) {
|
|
19467
19587
|
const deadline = new AbortController;
|
|
19468
19588
|
const timer = setTimeout(() => deadline.abort(), this.#acquireTimeoutMs);
|
|
19589
|
+
const endWait = this.#demand[pool].beginWait();
|
|
19469
19590
|
try {
|
|
19470
19591
|
return await raw.reserve({ signal: deadline.signal });
|
|
19471
19592
|
} catch (e) {
|
|
@@ -19474,6 +19595,7 @@ class DatabaseAdapter {
|
|
|
19474
19595
|
}
|
|
19475
19596
|
throw e;
|
|
19476
19597
|
} finally {
|
|
19598
|
+
endWait();
|
|
19477
19599
|
clearTimeout(timer);
|
|
19478
19600
|
}
|
|
19479
19601
|
}
|
|
@@ -19520,8 +19642,8 @@ class DatabaseAdapter {
|
|
|
19520
19642
|
}
|
|
19521
19643
|
return;
|
|
19522
19644
|
}
|
|
19523
|
-
if (id.database !==
|
|
19524
|
-
throw new Error(`DatabaseAdapter public pool expected database
|
|
19645
|
+
if (id.database !== this.#publicDatabase) {
|
|
19646
|
+
throw new Error(`DatabaseAdapter public pool expected database ${this.#publicDatabase} but connected to ${id.database}. Check ${this.#publicDatabase === "cms_public" ? "PUBLIC_DATABASE_URL / PUBLIC_ADMIN_DATABASE_URL" : "PUBLIC_DATABASE_URL / PUBLIC_STAGING_ADMIN_DATABASE_URL"}.`);
|
|
19525
19647
|
}
|
|
19526
19648
|
if (!this.#roles.public.includes(id.user)) {
|
|
19527
19649
|
throw new Error(`DatabaseAdapter public pool expected user ${this.#roles.public.join(" or ")}, got ${id.user}.`);
|
|
@@ -19585,7 +19707,7 @@ class DatabaseAdapter {
|
|
|
19585
19707
|
postCommit = collectPostCommitEffects(tx);
|
|
19586
19708
|
await this.#setIdentity(tx, ctx, op.name);
|
|
19587
19709
|
if (op.database === "cms_admin") {
|
|
19588
|
-
const denied = await firstInvisibleBranch(tx, namedBranches(ctx, validatedInput));
|
|
19710
|
+
const denied = await firstInvisibleBranch(tx, namedBranches(ctx, validatedInput), ctx);
|
|
19589
19711
|
if (denied !== null)
|
|
19590
19712
|
return err(branchNotFound(op.name, denied));
|
|
19591
19713
|
}
|
|
@@ -19642,9 +19764,10 @@ class DatabaseAdapter {
|
|
|
19642
19764
|
try {
|
|
19643
19765
|
const branches = op.database === "cms_admin" ? namedBranches(ctx, validatedInput) : [];
|
|
19644
19766
|
if (branches.length > 0) {
|
|
19645
|
-
const
|
|
19767
|
+
const remembered = await rememberedFirstInvisible(ctx, branches);
|
|
19768
|
+
const denied = remembered !== undefined ? remembered : await this.#transaction("admin", op.name, async (tx) => {
|
|
19646
19769
|
await this.#setIdentity(tx, ctx);
|
|
19647
|
-
return firstInvisibleBranch(tx, branches);
|
|
19770
|
+
return firstInvisibleBranch(tx, branches, ctx);
|
|
19648
19771
|
});
|
|
19649
19772
|
if (denied !== null)
|
|
19650
19773
|
return err(branchNotFound(op.name, denied));
|
|
@@ -19710,6 +19833,7 @@ class DatabaseAdapter {
|
|
|
19710
19833
|
if (!conn) {
|
|
19711
19834
|
conn = new SQL3(url, {
|
|
19712
19835
|
max: LISTEN_CONNECTIONS_PER_INSTANCE,
|
|
19836
|
+
...this.#tls ? { tls: this.#tls } : {},
|
|
19713
19837
|
onclose: (cause) => {
|
|
19714
19838
|
if (this.#listenersClosing)
|
|
19715
19839
|
return;
|
|
@@ -19743,7 +19867,8 @@ class DatabaseAdapter {
|
|
|
19743
19867
|
try {
|
|
19744
19868
|
const branches = namedBranches(ctx, validatedInput);
|
|
19745
19869
|
if (branches.length > 0) {
|
|
19746
|
-
const
|
|
19870
|
+
const remembered = await rememberedFirstInvisible(ctx, branches);
|
|
19871
|
+
const denied = remembered !== undefined ? remembered : await this.#shortRead(ctx, op.name, (tx) => firstInvisibleBranch(tx, branches, ctx));
|
|
19747
19872
|
if (denied !== null)
|
|
19748
19873
|
return err(branchNotFound(op.name, denied));
|
|
19749
19874
|
}
|
|
@@ -19823,7 +19948,7 @@ class DatabaseAdapter {
|
|
|
19823
19948
|
if (!joined)
|
|
19824
19949
|
postCommit = collectPostCommitEffects(tx);
|
|
19825
19950
|
await this.#setIdentity(tx, ctx, options.holder ?? null);
|
|
19826
|
-
const denied = await firstInvisibleBranch(tx, namedBranches(ctx, undefined));
|
|
19951
|
+
const denied = await firstInvisibleBranch(tx, namedBranches(ctx, undefined), ctx);
|
|
19827
19952
|
if (denied !== null) {
|
|
19828
19953
|
throw new OperationAbortError(branchNotFound("withAdminTransaction", denied));
|
|
19829
19954
|
}
|
|
@@ -19860,11 +19985,40 @@ class DatabaseAdapter {
|
|
|
19860
19985
|
if (this.#adminRaw === null)
|
|
19861
19986
|
throw new AdminDatabaseUnavailableError("rawAdmin");
|
|
19862
19987
|
this.#guard.assertNoHeldTransaction("admin", "rawAdmin()");
|
|
19863
|
-
return this.#adminRaw;
|
|
19988
|
+
return this.#trackedRaw("admin", this.#adminRaw);
|
|
19864
19989
|
}
|
|
19865
19990
|
rawPublic() {
|
|
19866
19991
|
this.#guard.assertNoHeldTransaction("public", "rawPublic()");
|
|
19867
|
-
return this.#publicRaw;
|
|
19992
|
+
return this.#trackedRaw("public", this.#publicRaw);
|
|
19993
|
+
}
|
|
19994
|
+
#trackedRaw(pool, raw) {
|
|
19995
|
+
const demand = this.#demand[pool];
|
|
19996
|
+
return new Proxy(raw, {
|
|
19997
|
+
get(target, property, receiver) {
|
|
19998
|
+
const value = Reflect.get(target, property, receiver);
|
|
19999
|
+
if (property !== "begin" || typeof value !== "function") {
|
|
20000
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
20001
|
+
}
|
|
20002
|
+
return (...args) => {
|
|
20003
|
+
const last = args.length - 1;
|
|
20004
|
+
const fn = args[last];
|
|
20005
|
+
if (typeof fn !== "function")
|
|
20006
|
+
return value.apply(target, args);
|
|
20007
|
+
const endWait = demand.beginWait();
|
|
20008
|
+
const counted = async (tx) => {
|
|
20009
|
+
endWait();
|
|
20010
|
+
const endHold = demand.beginHold("raw.begin");
|
|
20011
|
+
try {
|
|
20012
|
+
return await fn(tx);
|
|
20013
|
+
} finally {
|
|
20014
|
+
endHold();
|
|
20015
|
+
}
|
|
20016
|
+
};
|
|
20017
|
+
const out = value.apply(target, [...args.slice(0, last), counted]);
|
|
20018
|
+
return out.finally(endWait);
|
|
20019
|
+
};
|
|
20020
|
+
}
|
|
20021
|
+
});
|
|
19868
20022
|
}
|
|
19869
20023
|
async provisionPluginPublicSchema(opts) {
|
|
19870
20024
|
if (!/^[0-9a-f-]{36}$/i.test(opts.pluginId)) {
|
|
@@ -19875,12 +20029,23 @@ class DatabaseAdapter {
|
|
|
19875
20029
|
const outcome = await this.#transaction("public", "provisionPluginPublicSchema", async (tx) => {
|
|
19876
20030
|
return provisionPluginSchemaInTx(tx, "provisionPluginPublicSchema", opts);
|
|
19877
20031
|
});
|
|
19878
|
-
|
|
19879
|
-
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
|
|
20032
|
+
const result = {
|
|
20033
|
+
database: this.#publicDatabase,
|
|
20034
|
+
schemaName: outcome.schemaName,
|
|
20035
|
+
droppedColumns: outcome.droppedColumns
|
|
20036
|
+
};
|
|
20037
|
+
if (outcome.droppedColumns.length > 0 && this.#adminRaw !== null) {
|
|
20038
|
+
await this.auditPluginSchemaDrop(opts.pluginId, result);
|
|
19883
20039
|
}
|
|
20040
|
+
return result;
|
|
20041
|
+
}
|
|
20042
|
+
async auditPluginSchemaDrop(pluginId, outcome) {
|
|
20043
|
+
if (outcome.droppedColumns.length === 0)
|
|
20044
|
+
return;
|
|
20045
|
+
await this.#transaction("admin", "provisionPluginPublicSchema", async (tx) => {
|
|
20046
|
+
await tx.execute(sql.raw("SELECT set_config('caelo.actor_kind', 'system', true)"));
|
|
20047
|
+
await auditDroppedColumns(tx, outcome.database, pluginId, outcome);
|
|
20048
|
+
});
|
|
19884
20049
|
}
|
|
19885
20050
|
async provisionPluginAdminSchema(opts) {
|
|
19886
20051
|
if (!/^[0-9a-f-]{36}$/i.test(opts.pluginId)) {
|
|
@@ -19946,6 +20111,14 @@ async function auditDroppedColumns(tx, database, pluginId, outcome) {
|
|
|
19946
20111
|
}
|
|
19947
20112
|
function thrownToQueryError(operation, thrown, access) {
|
|
19948
20113
|
const raw = thrown instanceof Error ? thrown.message : String(thrown);
|
|
20114
|
+
if (thrown instanceof PoolAcquireTimeoutError) {
|
|
20115
|
+
return {
|
|
20116
|
+
kind: "HandlerError",
|
|
20117
|
+
operation,
|
|
20118
|
+
message: raw,
|
|
20119
|
+
busy: { retryAfterMs: POOL_BUSY_RETRY_AFTER_MS }
|
|
20120
|
+
};
|
|
20121
|
+
}
|
|
19949
20122
|
if (isRlsDenial(thrown)) {
|
|
19950
20123
|
console.warn(`[query-api] ${operation}: RLS denied the ${access}: ${raw}`);
|
|
19951
20124
|
return { kind: "RLSDenied", operation, detail: rlsDenialMessage(operation, access) };
|
package/dist/cli-routing.js
CHANGED
|
@@ -136,7 +136,7 @@ export const CLI_COMMANDS = [
|
|
|
136
136
|
];
|
|
137
137
|
/** The text `cms-provision --help` prints, built from {@link CLI_COMMANDS}. */
|
|
138
138
|
export function cliUsage() {
|
|
139
|
-
return (`Usage: cms-provision [wizard] [--provider <name> --domain <d> [--staging-domain <host>] --owner-email <e> --region <r>] [--local|--install-job] | <${CLI_COMMANDS.map((c) => c.name).join("|")}> [options]\n` +
|
|
139
|
+
return (`Usage: cms-provision [wizard] [--provider <name> --domain <d> [--staging-domain <host>] --owner-email <e> --region <r> [--scheduler-interval-minutes 1-15]] [--local|--install-job] | <${CLI_COMMANDS.map((c) => c.name).join("|")}> [options]\n` +
|
|
140
140
|
"With several installs on this machine, pick one with --install <install-id or domain> (status, upgrade and backup also take --install all); in a terminal you are asked otherwise.\n" +
|
|
141
141
|
"Pass --no-wizard with no sub-command to print this usage instead of the wizard.");
|
|
142
142
|
}
|
package/dist/cli-routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-routing.js","sourceRoot":"","sources":["../src/cli-routing.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cli-routing.js","sourceRoot":"","sources":["../src/cli-routing.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -47,7 +47,8 @@ import { selfCommand } from "./self-command.js";
|
|
|
47
47
|
import { ensureSelfHostedDbTls, selfHostedDbTlsServerCertSha256 } from "./self-hosted-db-tls.js";
|
|
48
48
|
import { ensureInternalSecret, writeInternalSecret } from "./self-hosted-internal-secret.js";
|
|
49
49
|
import { bunHostRunner, readRelease, recordRelease, releaseImages, resolveVerifiedRelease, } from "./self-hosted-release.js";
|
|
50
|
-
import {
|
|
50
|
+
import { applyPreMigrationRoles, convergeSelfHostedRoles, decideUp, selfHostedBootstrapScript, } from "./self-hosted-roles.js";
|
|
51
|
+
import { parseSchedulerIntervalMinutes } from "./stack-contract.js";
|
|
51
52
|
const REPO_ROOT = resolve(import.meta.dir, "../../..");
|
|
52
53
|
/**
|
|
53
54
|
* Whether this CLI runs from a Caelo source checkout (contributor) rather
|
|
@@ -139,6 +140,15 @@ function loadConfig() {
|
|
|
139
140
|
cfg.composeProject ??= "caelo";
|
|
140
141
|
saveConfig(cfg);
|
|
141
142
|
}
|
|
143
|
+
// #1329 — the staging gateway's login came with the staging database. An
|
|
144
|
+
// install from before gets its own password now; the next `up` or
|
|
145
|
+
// upgrade creates the role with it (self-hosted-roles.ts) before anything
|
|
146
|
+
// uses it, so the roles count as not converged until then.
|
|
147
|
+
if (cfg.rolePasswords && !cfg.rolePasswords.publicStaging) {
|
|
148
|
+
cfg.rolePasswords = { ...cfg.rolePasswords, publicStaging: randomSecret(32) };
|
|
149
|
+
cfg.rolesConverged = false;
|
|
150
|
+
saveConfig(cfg);
|
|
151
|
+
}
|
|
142
152
|
return cfg;
|
|
143
153
|
}
|
|
144
154
|
function saveConfig(c) {
|
|
@@ -152,9 +162,9 @@ function arg(name) {
|
|
|
152
162
|
return undefined;
|
|
153
163
|
return process.argv[idx + 1];
|
|
154
164
|
}
|
|
155
|
-
/** Fresh passwords for the
|
|
165
|
+
/** Fresh passwords for the application roles. */
|
|
156
166
|
function newRolePasswords() {
|
|
157
|
-
return { admin: randomSecret(32), public: randomSecret(32) };
|
|
167
|
+
return { admin: randomSecret(32), public: randomSecret(32), publicStaging: randomSecret(32) };
|
|
158
168
|
}
|
|
159
169
|
function emitConfig(cfg, extraDomains = []) {
|
|
160
170
|
// Back-fill caeloSecretKek for installs created before P18. Persists
|
|
@@ -246,6 +256,9 @@ function renderCompose(cfg, images) {
|
|
|
246
256
|
images,
|
|
247
257
|
ports: cfg.ports,
|
|
248
258
|
project: cfg.composeProject,
|
|
259
|
+
...(cfg.schedulerIntervalMinutes !== undefined
|
|
260
|
+
? { schedulerIntervalMinutes: cfg.schedulerIntervalMinutes }
|
|
261
|
+
: {}),
|
|
249
262
|
...(activeAgent(cfg) ? { agent: activeAgent(cfg) } : {}),
|
|
250
263
|
});
|
|
251
264
|
}
|
|
@@ -282,7 +295,20 @@ function agentContext(cfg) {
|
|
|
282
295
|
...(activeAgent(cfg) ? { agentPassword: activeAgent(cfg)?.dbPassword } : {}),
|
|
283
296
|
});
|
|
284
297
|
},
|
|
285
|
-
|
|
298
|
+
applyPreMigrationRoles: () => {
|
|
299
|
+
if (!cfg.rolePasswords) {
|
|
300
|
+
return Promise.resolve({
|
|
301
|
+
ok: false,
|
|
302
|
+
reachable: true,
|
|
303
|
+
error: "config.json has no role passwords — run `cms-provision up` first",
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return applyPreMigrationRoles({
|
|
307
|
+
probe: postgresIsUp,
|
|
308
|
+
psql: superuserPsql,
|
|
309
|
+
stagingPassword: cfg.rolePasswords.publicStaging,
|
|
310
|
+
});
|
|
311
|
+
},
|
|
286
312
|
renderCompose: (images) => renderCompose(cfg, images),
|
|
287
313
|
refreshCaddy: () => refreshCaddyfile(cfg),
|
|
288
314
|
randomSecret: () => randomSecret(32),
|
|
@@ -421,7 +447,7 @@ async function init() {
|
|
|
421
447
|
return;
|
|
422
448
|
}
|
|
423
449
|
if (!domain || !ownerEmail) {
|
|
424
|
-
console.error("Usage: cms-provision init [--provider self-hosted] --domain example.com [--staging-domain staging.example.com] --owner-email me@example.com [--version x.y.z] [--skip-verify] [--dev] [--tls acme|internal] [--http-port 80] [--https-port 443]\n" +
|
|
450
|
+
console.error("Usage: cms-provision init [--provider self-hosted] --domain example.com [--staging-domain staging.example.com] --owner-email me@example.com [--version x.y.z] [--skip-verify] [--dev] [--tls acme|internal] [--http-port 80] [--https-port 443] [--scheduler-interval-minutes 5]\n" +
|
|
425
451
|
"Cloud providers (gcp | gcp-firebase | aws | azure) run the wizard: cms-provision --provider <name>");
|
|
426
452
|
process.exit(2);
|
|
427
453
|
}
|
|
@@ -435,6 +461,18 @@ async function init() {
|
|
|
435
461
|
console.error("--http-port and --https-port must differ");
|
|
436
462
|
process.exit(2);
|
|
437
463
|
}
|
|
464
|
+
const schedulerArg = arg("scheduler-interval-minutes");
|
|
465
|
+
let schedulerIntervalMinutes;
|
|
466
|
+
try {
|
|
467
|
+
schedulerIntervalMinutes =
|
|
468
|
+
schedulerArg === undefined
|
|
469
|
+
? undefined
|
|
470
|
+
: parseSchedulerIntervalMinutes(schedulerArg, "--scheduler-interval-minutes");
|
|
471
|
+
}
|
|
472
|
+
catch (e) {
|
|
473
|
+
console.error(e.message);
|
|
474
|
+
process.exit(2);
|
|
475
|
+
}
|
|
438
476
|
const stagingArg = arg("staging-domain");
|
|
439
477
|
const stagingProblem = stagingArg
|
|
440
478
|
? stagingHostProblem(stagingArg, {
|
|
@@ -502,6 +540,7 @@ async function init() {
|
|
|
502
540
|
tls,
|
|
503
541
|
ports,
|
|
504
542
|
composeProject: composeProjectName(domain),
|
|
543
|
+
...(schedulerIntervalMinutes !== undefined ? { schedulerIntervalMinutes } : {}),
|
|
505
544
|
};
|
|
506
545
|
saveConfig(cfg);
|
|
507
546
|
// P15.1 — the shared HMAC secret for /api/internal/* endpoints, read by
|
|
@@ -859,7 +898,7 @@ async function upgradeSelfHostedCommand(opts) {
|
|
|
859
898
|
runner: bunHostRunner,
|
|
860
899
|
renderCompose: (images) => renderCompose(cfg, images),
|
|
861
900
|
convergeRoles: agentContext(cfg).convergeRoles,
|
|
862
|
-
|
|
901
|
+
applyPreMigrationRoles: agentContext(cfg).applyPreMigrationRoles,
|
|
863
902
|
refreshCaddy: () => refreshCaddyfile(cfg),
|
|
864
903
|
log: {
|
|
865
904
|
step: (m) => console.log(`\n==> ${m}`),
|
|
@@ -1356,13 +1395,26 @@ async function waitForDomainMappingCert(target) {
|
|
|
1356
1395
|
* §11.C — interactive wizard. Loaded lazily so the bare-CLI startup
|
|
1357
1396
|
* cost stays small (clack + kleur are pulled in only when needed).
|
|
1358
1397
|
* Reads `--provider`, `--domain`, `--owner-email`, `--project-id`, `--region`,
|
|
1359
|
-
* `--non-interactive` and the run mode (`--local` / `--install-job`, default:
|
|
1398
|
+
* `--scheduler-interval-minutes` (#1140), `--non-interactive` and the run mode (`--local` / `--install-job`, default:
|
|
1360
1399
|
* the install job in Cloud Shell, local elsewhere — run-mode.ts) from argv.
|
|
1361
1400
|
*/
|
|
1362
1401
|
async function wizardCommand() {
|
|
1363
1402
|
const { runWizard } = await import("./wizard.js");
|
|
1364
1403
|
const { chooseRunMode } = await import("./run-mode.js");
|
|
1404
|
+
const schedulerArg = arg("scheduler-interval-minutes");
|
|
1405
|
+
let schedulerIntervalMinutes;
|
|
1406
|
+
try {
|
|
1407
|
+
schedulerIntervalMinutes =
|
|
1408
|
+
schedulerArg === undefined
|
|
1409
|
+
? undefined
|
|
1410
|
+
: parseSchedulerIntervalMinutes(schedulerArg, "--scheduler-interval-minutes");
|
|
1411
|
+
}
|
|
1412
|
+
catch (e) {
|
|
1413
|
+
console.error(e.message);
|
|
1414
|
+
process.exit(2);
|
|
1415
|
+
}
|
|
1365
1416
|
await runWizard({
|
|
1417
|
+
...(schedulerIntervalMinutes !== undefined ? { schedulerIntervalMinutes } : {}),
|
|
1366
1418
|
runMode: chooseRunMode(process.argv, process.env),
|
|
1367
1419
|
nonInteractive: process.argv.includes("--non-interactive"),
|
|
1368
1420
|
provider: arg("provider"),
|