ignitify 1.2.0 → 1.2.2
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/ignitify-NOTICE.txt +2 -2
- package/ignitify.cjs +508 -459
- package/package.json +1 -1
package/ignitify.cjs
CHANGED
|
@@ -942,10 +942,25 @@ function bareValueFlag(args, valueFlags2) {
|
|
|
942
942
|
function needsValueMessage(flag) {
|
|
943
943
|
return `--${flag} needs a value`;
|
|
944
944
|
}
|
|
945
|
+
function strOpt(args, key) {
|
|
946
|
+
let bare = bareValueFlag(args, [key]);
|
|
947
|
+
if (bare !== void 0) throw new Error(needsValueMessage(bare));
|
|
948
|
+
let v = args.options[key];
|
|
949
|
+
return typeof v == "string" ? v : void 0;
|
|
950
|
+
}
|
|
951
|
+
function flagParams(args, map2) {
|
|
952
|
+
return Object.fromEntries(Object.entries(map2).flatMap(([flag, param]) => {
|
|
953
|
+
let v = strOpt(args, flag);
|
|
954
|
+
return v === void 0 ? [] : [[param, v]];
|
|
955
|
+
}));
|
|
956
|
+
}
|
|
945
957
|
var init_args = __esm({ "../../packages/http-client/args.ts"() {
|
|
946
958
|
"use strict";
|
|
947
959
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
948
960
|
} });
|
|
961
|
+
function boolFlagSpec(flags) {
|
|
962
|
+
return { boolFlags: new Set(Object.keys(flags).filter((flag) => flags[flag] === "bool")) };
|
|
963
|
+
}
|
|
949
964
|
function unknownFlagText(flag, command) {
|
|
950
965
|
return `unknown flag ${flag} for ${command}`;
|
|
951
966
|
}
|
|
@@ -978,13 +993,49 @@ function shapeRefusal(command, args, flags, maxPositionals) {
|
|
|
978
993
|
function isHelpRequest(args) {
|
|
979
994
|
return HELP_TOKENS.includes(args.command) || args.options.help === true;
|
|
980
995
|
}
|
|
981
|
-
var didYouMean, itsFlags, flagTakesNoValue, tooManyArgs, HELP_TOKENS, init_invocation = __esm({ "../../packages/http-client/invocation.ts"() {
|
|
996
|
+
var looksShort, didYouMean, itsFlags, flagTakesNoValue, tooManyArgs, HELP_TOKENS, init_invocation = __esm({ "../../packages/http-client/invocation.ts"() {
|
|
982
997
|
"use strict";
|
|
983
998
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
984
999
|
init_args();
|
|
1000
|
+
looksShort = (tok) => tok.length > 1 && tok.startsWith("-") && !tok.startsWith("--");
|
|
985
1001
|
didYouMean = (flag) => `Did you mean --${flag}?`, itsFlags = (own, global) => `Its flags: ${own.length === 0 ? "(none)" : own.map((f) => `--${f}`).join(" ")}. Global: ${global.map((f) => `--${f}`).join(" ")}.`, flagTakesNoValue = (flag) => `--${flag} takes no value`, tooManyArgs = (command, max, extra, got) => `${command} takes ${max} argument${max === 1 ? "" : "s"}; got ${got} (${extra.map((e) => JSON.stringify(e)).join(", ")} ${extra.length === 1 ? "is" : "are"} extra)`;
|
|
986
1002
|
HELP_TOKENS = ["", "help", "--help", "-h"];
|
|
987
1003
|
} });
|
|
1004
|
+
function isLoopbackHost(hostname) {
|
|
1005
|
+
return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(hostname);
|
|
1006
|
+
}
|
|
1007
|
+
function keyUrlRefusal(url) {
|
|
1008
|
+
let u;
|
|
1009
|
+
try {
|
|
1010
|
+
u = new URL(url);
|
|
1011
|
+
} catch {
|
|
1012
|
+
return "not-url";
|
|
1013
|
+
}
|
|
1014
|
+
return u.protocol === "https:" || u.protocol === "http:" && isLoopbackHost(u.hostname) ? null : "insecure";
|
|
1015
|
+
}
|
|
1016
|
+
var init_key_url = __esm({ "../../packages/http-client/key-url.ts"() {
|
|
1017
|
+
"use strict";
|
|
1018
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1019
|
+
} });
|
|
1020
|
+
function scale(n, units) {
|
|
1021
|
+
let step = (v, i) => v >= 1024 && i < units.length - 1 ? step(v / 1024, i + 1) : i === 0 ? `${n} ${units[0]}` : `${v.toFixed(1)} ${units[i]}`;
|
|
1022
|
+
return step(n, 0);
|
|
1023
|
+
}
|
|
1024
|
+
function duration(ms) {
|
|
1025
|
+
if (ms < 1e3) return `${ms} ms`;
|
|
1026
|
+
let s = Math.round(ms / 1e3);
|
|
1027
|
+
if (s < 60) return `${s} s`;
|
|
1028
|
+
let m = Math.floor(s / 60);
|
|
1029
|
+
return m < 60 ? `${m}m ${s % 60}s` : `${Math.floor(m / 60)}h ${m % 60}m`;
|
|
1030
|
+
}
|
|
1031
|
+
function formatUsageQuantity(n, unit) {
|
|
1032
|
+
return unit === "bytes" ? scale(n, BYTE_UNITS) : unit === "ms" ? duration(n) : unit === "byte-hours" ? scale(n, BYTE_HOUR_UNITS) : `${n}`;
|
|
1033
|
+
}
|
|
1034
|
+
var BYTE_UNITS, BYTE_HOUR_UNITS, init_usage_format = __esm({ "../../packages/http-client/usage-format.ts"() {
|
|
1035
|
+
"use strict";
|
|
1036
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1037
|
+
BYTE_UNITS = ["B", "KiB", "MiB", "GiB", "TiB"], BYTE_HOUR_UNITS = ["B\xB7h", "KiB\xB7h", "MiB\xB7h", "GiB\xB7h", "TiB\xB7h", "PiB\xB7h"];
|
|
1038
|
+
} });
|
|
988
1039
|
function csvRow(values) {
|
|
989
1040
|
return values.map((v) => `"${v.replace(/"/g, '""')}"`).join(",");
|
|
990
1041
|
}
|
|
@@ -1027,6 +1078,16 @@ var PAGE_CURSOR_FLAG, PAGE_FLAG_PARAMS, init_page = __esm({ "../../packages/http
|
|
|
1027
1078
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1028
1079
|
PAGE_CURSOR_FLAG = "after-id", PAGE_FLAG_PARAMS = { limit: "limit", after: "after", "after-id": "after_id" };
|
|
1029
1080
|
} });
|
|
1081
|
+
function httpErrorJson(e) {
|
|
1082
|
+
if (!(e instanceof HttpError)) return null;
|
|
1083
|
+
let body;
|
|
1084
|
+
try {
|
|
1085
|
+
body = JSON.parse(e.body);
|
|
1086
|
+
} catch {
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
return typeof body != "object" || body === null || Array.isArray(body) ? null : { status: e.status, body };
|
|
1090
|
+
}
|
|
1030
1091
|
async function parseJson(res) {
|
|
1031
1092
|
let text = await res.text();
|
|
1032
1093
|
if (!res.ok) throw new HttpError(res.status, text, res.statusText, res.headers.get(TRACE_HEADER));
|
|
@@ -1052,6 +1113,8 @@ var DEFAULT_REQUEST_TIMEOUT_MS, TRACE_HEADER, HttpError, init_http_client = __es
|
|
|
1052
1113
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1053
1114
|
init_args();
|
|
1054
1115
|
init_invocation();
|
|
1116
|
+
init_key_url();
|
|
1117
|
+
init_usage_format();
|
|
1055
1118
|
init_csv();
|
|
1056
1119
|
init_page();
|
|
1057
1120
|
DEFAULT_REQUEST_TIMEOUT_MS = 12e4, TRACE_HEADER = "x-correlation-id", HttpError = class extends Error {
|
|
@@ -1073,11 +1136,14 @@ function fill(pattern, ...params) {
|
|
|
1073
1136
|
if (i !== params.length) throw new Error(`route ${pattern}: takes ${i} parameter(s), given ${params.length}`);
|
|
1074
1137
|
return out2;
|
|
1075
1138
|
}
|
|
1076
|
-
|
|
1139
|
+
function isTerminalRunStatus(status) {
|
|
1140
|
+
return TERMINAL_RUN_STATUSES.includes(status);
|
|
1141
|
+
}
|
|
1142
|
+
var DOT_SEGMENTS, TENANT_ROUTES, KEY_EXPIRED_ERROR, TENANT_PATHS, API_VERSION, API_VERSION_HEADER, CLIENT_FLOOR_HEADER, CLI_VERSION_HEADER, TERMINAL_RUN_STATUSES, init_api_routes = __esm({ "../../packages/contract/api-routes.ts"() {
|
|
1077
1143
|
"use strict";
|
|
1078
1144
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1079
1145
|
DOT_SEGMENTS = /* @__PURE__ */ new Set([".", ".."]);
|
|
1080
|
-
TENANT_ROUTES = { TASKS: "/tasks", TASK_BY_ID: "/tasks/:id", TASK_DELETION_PREVIEW: "/tasks/:id/deletion-preview", DEPLOYMENTS: "/deployments", DEPLOYMENT_BY_ID: "/deployments/:id", RUNS: "/runs", RUN_BY_ID: "/runs/:id", RUN_CANCEL: "/runs/:id/cancel", WHOAMI: "/whoami", PACKAGE_ADVICE: "/packages/advice", VMS: "/vms", VM_BY_ID: "/vms/:id", HOOKS: "/hooks", TRIGGER: "/hooks/trigger", TRIGGER_HOOK: "/hooks/trigger/:hookId", SECRETS: "/secrets", SECRET_BY_NAME: "/secrets/:name", SCHEDULES: "/schedules", SCHEDULE_BY_ID: "/schedules/:id", USAGE: "/usage", RUN_LOGS: "/runs/:id/logs", DEPLOYMENT_LOGS: "/deployments/:id/logs", DEPLOYMENT_HOOKS: "/deployments/:id/hooks", DEPLOYMENT_NOTIFY: "/deployments/:id/notify", HOOK_BY_ID: "/hooks/:id", READYZ: "/readyz", LIVEZ: "/livez", AUTH_DEVICE: "/auth/device", AUTH_DEVICE_TOKEN: "/auth/device/token", AUTH_KEY: "/auth/key" }, KEY_EXPIRED_ERROR = "API key has expired", TENANT_PATHS = { TASKS: TENANT_ROUTES.TASKS, TASK_BY_ID: (id) => fill(TENANT_ROUTES.TASK_BY_ID, id), TASK_DELETION_PREVIEW: (id) => fill(TENANT_ROUTES.TASK_DELETION_PREVIEW, id), DEPLOYMENTS: TENANT_ROUTES.DEPLOYMENTS, DEPLOYMENT_BY_ID: (id) => fill(TENANT_ROUTES.DEPLOYMENT_BY_ID, id), DEPLOYMENT_LOGS: (id) => fill(TENANT_ROUTES.DEPLOYMENT_LOGS, id), RUNS: TENANT_ROUTES.RUNS, RUN_BY_ID: (id) => fill(TENANT_ROUTES.RUN_BY_ID, id), RUN_CANCEL: (id) => fill(TENANT_ROUTES.RUN_CANCEL, id), RUN_LOGS: (id) => fill(TENANT_ROUTES.RUN_LOGS, id), WHOAMI: TENANT_ROUTES.WHOAMI, PACKAGE_ADVICE: TENANT_ROUTES.PACKAGE_ADVICE, VMS: TENANT_ROUTES.VMS, VM_BY_ID: (id) => fill(TENANT_ROUTES.VM_BY_ID, id), HOOKS: TENANT_ROUTES.HOOKS, TRIGGER: TENANT_ROUTES.TRIGGER, TRIGGER_HOOK: (hookId) => fill(TENANT_ROUTES.TRIGGER_HOOK, hookId), SECRETS: TENANT_ROUTES.SECRETS, SECRET_BY_NAME: (name) => fill(TENANT_ROUTES.SECRET_BY_NAME, name), SCHEDULES: TENANT_ROUTES.SCHEDULES, SCHEDULE_BY_ID: (id) => fill(TENANT_ROUTES.SCHEDULE_BY_ID, id), USAGE: TENANT_ROUTES.USAGE, DEPLOYMENT_HOOKS: (id) => fill(TENANT_ROUTES.DEPLOYMENT_HOOKS, id), DEPLOYMENT_NOTIFY: (id) => fill(TENANT_ROUTES.DEPLOYMENT_NOTIFY, id), HOOK_BY_ID: (id) => fill(TENANT_ROUTES.HOOK_BY_ID, id), READYZ: TENANT_ROUTES.READYZ, LIVEZ: TENANT_ROUTES.LIVEZ, AUTH_DEVICE: TENANT_ROUTES.AUTH_DEVICE, AUTH_DEVICE_TOKEN: TENANT_ROUTES.AUTH_DEVICE_TOKEN, AUTH_KEY: TENANT_ROUTES.AUTH_KEY }, API_VERSION = "1", API_VERSION_HEADER = "X-Api-Version", CLIENT_FLOOR_HEADER = "X-Client-Floor", CLI_VERSION_HEADER = "X-Ignitify-Cli";
|
|
1146
|
+
TENANT_ROUTES = { TASKS: "/tasks", TASK_BY_ID: "/tasks/:id", TASK_DELETION_PREVIEW: "/tasks/:id/deletion-preview", DEPLOYMENTS: "/deployments", DEPLOYMENT_BY_ID: "/deployments/:id", RUNS: "/runs", RUN_BY_ID: "/runs/:id", RUN_CANCEL: "/runs/:id/cancel", WHOAMI: "/whoami", PACKAGE_ADVICE: "/packages/advice", VMS: "/vms", VM_BY_ID: "/vms/:id", HOOKS: "/hooks", TRIGGER: "/hooks/trigger", TRIGGER_HOOK: "/hooks/trigger/:hookId", SECRETS: "/secrets", SECRET_BY_NAME: "/secrets/:name", SCHEDULES: "/schedules", SCHEDULE_BY_ID: "/schedules/:id", USAGE: "/usage", RUN_LOGS: "/runs/:id/logs", DEPLOYMENT_LOGS: "/deployments/:id/logs", DEPLOYMENT_HOOKS: "/deployments/:id/hooks", DEPLOYMENT_NOTIFY: "/deployments/:id/notify", HOOK_BY_ID: "/hooks/:id", READYZ: "/readyz", LIVEZ: "/livez", AUTH_DEVICE: "/auth/device", AUTH_DEVICE_TOKEN: "/auth/device/token", AUTH_KEY: "/auth/key" }, KEY_EXPIRED_ERROR = "API key has expired", TENANT_PATHS = { TASKS: TENANT_ROUTES.TASKS, TASK_BY_ID: (id) => fill(TENANT_ROUTES.TASK_BY_ID, id), TASK_DELETION_PREVIEW: (id) => fill(TENANT_ROUTES.TASK_DELETION_PREVIEW, id), DEPLOYMENTS: TENANT_ROUTES.DEPLOYMENTS, DEPLOYMENT_BY_ID: (id) => fill(TENANT_ROUTES.DEPLOYMENT_BY_ID, id), DEPLOYMENT_LOGS: (id) => fill(TENANT_ROUTES.DEPLOYMENT_LOGS, id), RUNS: TENANT_ROUTES.RUNS, RUN_BY_ID: (id) => fill(TENANT_ROUTES.RUN_BY_ID, id), RUN_CANCEL: (id) => fill(TENANT_ROUTES.RUN_CANCEL, id), RUN_LOGS: (id) => fill(TENANT_ROUTES.RUN_LOGS, id), WHOAMI: TENANT_ROUTES.WHOAMI, PACKAGE_ADVICE: TENANT_ROUTES.PACKAGE_ADVICE, VMS: TENANT_ROUTES.VMS, VM_BY_ID: (id) => fill(TENANT_ROUTES.VM_BY_ID, id), HOOKS: TENANT_ROUTES.HOOKS, TRIGGER: TENANT_ROUTES.TRIGGER, TRIGGER_HOOK: (hookId) => fill(TENANT_ROUTES.TRIGGER_HOOK, hookId), SECRETS: TENANT_ROUTES.SECRETS, SECRET_BY_NAME: (name) => fill(TENANT_ROUTES.SECRET_BY_NAME, name), SCHEDULES: TENANT_ROUTES.SCHEDULES, SCHEDULE_BY_ID: (id) => fill(TENANT_ROUTES.SCHEDULE_BY_ID, id), USAGE: TENANT_ROUTES.USAGE, DEPLOYMENT_HOOKS: (id) => fill(TENANT_ROUTES.DEPLOYMENT_HOOKS, id), DEPLOYMENT_NOTIFY: (id) => fill(TENANT_ROUTES.DEPLOYMENT_NOTIFY, id), HOOK_BY_ID: (id) => fill(TENANT_ROUTES.HOOK_BY_ID, id), READYZ: TENANT_ROUTES.READYZ, LIVEZ: TENANT_ROUTES.LIVEZ, AUTH_DEVICE: TENANT_ROUTES.AUTH_DEVICE, AUTH_DEVICE_TOKEN: TENANT_ROUTES.AUTH_DEVICE_TOKEN, AUTH_KEY: TENANT_ROUTES.AUTH_KEY }, API_VERSION = "1", API_VERSION_HEADER = "X-Api-Version", CLIENT_FLOOR_HEADER = "X-Client-Floor", CLI_VERSION_HEADER = "X-Ignitify-Cli", TERMINAL_RUN_STATUSES = ["COMPLETED", "FAILED", "CANCELLED"];
|
|
1081
1147
|
} });
|
|
1082
1148
|
var CALLBACK_PATH_PREFIX, init_callback_path = __esm({ "../../packages/contract/callback-path.ts"() {
|
|
1083
1149
|
"use strict";
|
|
@@ -1097,14 +1163,49 @@ var TASK_CONFIG_FILENAMES, RUNTIME_REGISTRY, RUNTIME_IDS, LIVE_RUNTIME_IDS, isRu
|
|
|
1097
1163
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1098
1164
|
TASK_CONFIG_FILENAMES = ["task.yaml", "task.yml", "task.json"], RUNTIME_REGISTRY = Object.freeze({ node: Object.freeze({ entryFile: "index.ts", depManifest: "package.json", lockfile: "package-lock.json", wireRuntime: "node22", status: "live" }), python: Object.freeze({ entryFile: "main.py", depManifest: "requirements.txt", lockfile: "requirements.txt", wireRuntime: "python3.11", status: "live" }), go: Object.freeze({ entryFile: "main.go", depManifest: "go.mod", lockfile: "go.sum", wireRuntime: "go", status: "live" }), rust: Object.freeze({ entryFile: "src/main.rs", depManifest: "Cargo.toml", lockfile: "Cargo.lock", wireRuntime: "rust", status: "live" }) }), RUNTIME_IDS = Object.keys(RUNTIME_REGISTRY), LIVE_RUNTIME_IDS = RUNTIME_IDS.filter((id) => RUNTIME_REGISTRY[id].status === "live"), isRuntimeId = (v) => typeof v == "string" && Object.prototype.hasOwnProperty.call(RUNTIME_REGISTRY, v), TASK_CONFIG_AJV_OPTIONS = Object.freeze({ allErrors: true, strict: true, useDefaults: false }), TASK_CONFIG_SCHEMA = Object.freeze({ $schema: "https://json-schema.org/draft/2020-12/schema", $id: "https://ignitify.dev/schemas/task-config/v1.json", title: "Ignitify task configuration", type: "object", required: ["schema_version", "slug", "runtime"], additionalProperties: false, properties: { schema_version: { const: 1 }, slug: { type: "string", minLength: 1 }, runtime: { enum: [...RUNTIME_IDS] }, entry: { type: "string", minLength: 1 }, execution: { type: "object" }, secrets: { type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true }, run: { type: "object", additionalProperties: false, properties: { payload: { type: "object" }, preset: { type: "string", minLength: 1 }, timeout_sec: { type: "integer", exclusiveMinimum: 0 } } }, build: { type: "object", additionalProperties: false, properties: { allowed_hosts: { type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true }, ship: { type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true }, system_packages: { type: "array", items: { type: "string", minLength: 1 } } } } } }), BUILD_REFUSAL_STAGES = ["read", "fetch", "build", "smoke"], BUILD_STAGES = ["done", ...BUILD_REFUSAL_STAGES, "builder", "image", "cap"];
|
|
1099
1165
|
} });
|
|
1166
|
+
function parseJsonText(text) {
|
|
1167
|
+
try {
|
|
1168
|
+
return { ok: true, value: JSON.parse(text) };
|
|
1169
|
+
} catch {
|
|
1170
|
+
return { ok: false };
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
var isRecord, init_wire_json = __esm({ "../../packages/contract/wire-json.ts"() {
|
|
1174
|
+
"use strict";
|
|
1175
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1176
|
+
isRecord = (v) => typeof v == "object" && v !== null && !Array.isArray(v);
|
|
1177
|
+
} });
|
|
1178
|
+
function errText(err2) {
|
|
1179
|
+
if (err2 instanceof Error) return err2.message;
|
|
1180
|
+
try {
|
|
1181
|
+
return String(err2);
|
|
1182
|
+
} catch {
|
|
1183
|
+
return "unprintable error";
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
function errCode(err2) {
|
|
1187
|
+
let code = isRecord(err2) ? err2.code : void 0;
|
|
1188
|
+
return typeof code == "string" ? code : "error";
|
|
1189
|
+
}
|
|
1190
|
+
var isMissing, init_err_text = __esm({ "../../packages/contract/err-text.ts"() {
|
|
1191
|
+
"use strict";
|
|
1192
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1193
|
+
init_wire_json();
|
|
1194
|
+
isMissing = (err2) => errCode(err2) === "ENOENT";
|
|
1195
|
+
} });
|
|
1196
|
+
var SHA256_HEX, SHA256_PREFIX, isSha256Hex, stripSha256Prefix, init_digest = __esm({ "../../packages/contract/digest.ts"() {
|
|
1197
|
+
"use strict";
|
|
1198
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1199
|
+
SHA256_HEX = /^[0-9a-f]{64}$/, SHA256_PREFIX = "sha256:", isSha256Hex = (v) => typeof v == "string" && SHA256_HEX.test(v), stripSha256Prefix = (s) => s.startsWith(SHA256_PREFIX) ? s.slice(SHA256_PREFIX.length) : s;
|
|
1200
|
+
} });
|
|
1100
1201
|
function rootConfigName(paths) {
|
|
1101
1202
|
return TASK_CONFIG_FILENAMES.find((n) => paths.includes(n)) ?? null;
|
|
1102
1203
|
}
|
|
1103
1204
|
function configKeyText(value) {
|
|
1104
|
-
let top = value !== null && typeof value == "object" && !Array.isArray(value) ? Object.fromEntries(Object.entries(value).filter(([k]) => !RUN_ONLY_CONFIG_KEYS.includes(k))) : value, parts = [],
|
|
1205
|
+
let top = value !== null && typeof value == "object" && !Array.isArray(value) ? Object.fromEntries(Object.entries(value).filter(([k]) => !RUN_ONLY_CONFIG_KEYS.includes(k))) : value, parts = [], bytes = 0, over = () => {
|
|
1105
1206
|
throw new Error(`its build settings are over ${CONFIG_KEY_TEXT_MAX_BYTES / 1024} KiB as canonical JSON (a YAML alias is expanded each time it is used)`);
|
|
1106
1207
|
}, emit2 = (s) => {
|
|
1107
|
-
|
|
1208
|
+
bytes += utf8Bytes(s), bytes > CONFIG_KEY_TEXT_MAX_BYTES && over(), parts.push(s);
|
|
1108
1209
|
}, walk = (v, depth) => {
|
|
1109
1210
|
if (depth > CONFIG_KEY_MAX_DEPTH) throw new Error(`it is nested deeper than ${CONFIG_KEY_MAX_DEPTH} levels`);
|
|
1110
1211
|
if (v === null || typeof v == "boolean") return emit2(String(v));
|
|
@@ -1150,39 +1251,39 @@ function privateKeyFileWarning(relPath) {
|
|
|
1150
1251
|
let base = relPath.slice(relPath.lastIndexOf("/") + 1).toLowerCase();
|
|
1151
1252
|
return base.endsWith(".pem") || base.endsWith(".key") || base.startsWith("id_rsa") && !base.endsWith(".pub") ? `${relPath} looks like a private key and is uploaded with the task, then stored in the image. If it is a secret, remove it (secrets go through \`secret:set\`); to keep a harmless file out, list it in \`.ignitifyignore\`` : null;
|
|
1152
1253
|
}
|
|
1153
|
-
function
|
|
1254
|
+
function checkSourceManifest(entries, config) {
|
|
1154
1255
|
let expected = rootConfigName(entries.map((e) => e.path));
|
|
1155
|
-
if ((config?.name ?? null) !== expected)
|
|
1256
|
+
if ((config?.name ?? null) !== expected) return refused(`the task config in the key must be ${expected ?? "none"}, not ${config?.name ?? "none"}`);
|
|
1156
1257
|
let configLine = [];
|
|
1157
1258
|
if (config !== null) try {
|
|
1158
1259
|
configLine = [`config ${config.name} ${configKeyText(config.value)}`];
|
|
1159
1260
|
} catch (e) {
|
|
1160
|
-
|
|
1261
|
+
return refused(`${config.name}: ${errText(e)}`);
|
|
1161
1262
|
}
|
|
1162
1263
|
let seen = /* @__PURE__ */ new Set();
|
|
1163
1264
|
for (let e of entries) {
|
|
1164
|
-
|
|
1165
|
-
if (
|
|
1166
|
-
if (e.path.startsWith("/")) throw new Error(`source manifest: absolute path: ${e.path}`);
|
|
1167
|
-
if (!isCanonicalRelativePath(e.path)) throw new Error(`source manifest: non-canonical path: ${e.path}`);
|
|
1168
|
-
if (e.path.includes(`
|
|
1169
|
-
`) || e.path.includes(" ")) throw new Error(`source manifest: path contains a tab or newline: ${JSON.stringify(e.path)}`);
|
|
1170
|
-
if (!Number.isSafeInteger(e.size) || e.size < 0) throw new Error(`source manifest: bad size for ${e.path}: ${String(e.size)}`);
|
|
1171
|
-
if (!HEX64.test(e.sha256)) throw new Error(`source manifest: sha256 for ${e.path} must be 64 lowercase hex chars`);
|
|
1172
|
-
if (seen.has(e.path)) throw new Error(`source manifest: duplicate path: ${e.path}`);
|
|
1265
|
+
let bad = entryRefusal(e, seen);
|
|
1266
|
+
if (bad !== null) return refused(bad);
|
|
1173
1267
|
seen.add(e.path);
|
|
1174
1268
|
}
|
|
1175
1269
|
let lines = entries.filter((e) => e.path !== config?.name).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0).map((e) => `${e.exec ? "755" : "644"} ${e.size} ${e.sha256} ${e.path}`);
|
|
1176
|
-
return [`ignitify-source/${SOURCE_MANIFEST_VERSION}`, ...configLine, ...lines, ""].join(`
|
|
1177
|
-
`);
|
|
1270
|
+
return { ok: true, text: [`ignitify-source/${SOURCE_MANIFEST_VERSION}`, ...configLine, ...lines, ""].join(`
|
|
1271
|
+
`) };
|
|
1178
1272
|
}
|
|
1179
|
-
|
|
1273
|
+
function entryRefusal(e, seen) {
|
|
1274
|
+
return typeof e.path != "string" || e.path === "" ? "empty path" : e.path.includes("\\") ? `path contains a backslash: ${JSON.stringify(e.path)}. Separators must be normalised to "/" before hashing, or the same tree hashes differently per platform.` : e.path.startsWith("/") ? `absolute path: ${e.path}` : isCanonicalRelativePath(e.path) ? e.path.includes(`
|
|
1275
|
+
`) || e.path.includes(" ") ? `path contains a tab or newline: ${JSON.stringify(e.path)}` : !Number.isSafeInteger(e.size) || e.size < 0 ? `bad size for ${e.path}: ${String(e.size)}` : isSha256Hex(e.sha256) ? seen.has(e.path) ? `duplicate path: ${e.path}` : null : `sha256 for ${e.path} must be 64 lowercase hex chars` : `non-canonical path: ${e.path}`;
|
|
1276
|
+
}
|
|
1277
|
+
var SOURCE_MANIFEST_VERSION, RUN_ONLY_CONFIG_KEYS, CONFIG_KEY_TEXT_MAX_BYTES, UPLOAD_MAX_BYTES, CONFIG_KEY_MAX_DEPTH, SOURCE_EXCLUDED_DIRS, SOURCE_EXCLUDED_ROOT_DIRS, SOURCE_EXCLUDED_FILE_PREFIXES, CREDENTIAL_KEYS, CREDENTIAL_CHECKED_FILES, isCanonicalRelativePath, refused, init_source_manifest = __esm({ "../../packages/contract/source-manifest.ts"() {
|
|
1180
1278
|
"use strict";
|
|
1181
1279
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1182
1280
|
init_task_config();
|
|
1281
|
+
init_err_text();
|
|
1282
|
+
init_digest();
|
|
1183
1283
|
SOURCE_MANIFEST_VERSION = "v2", RUN_ONLY_CONFIG_KEYS = Object.freeze(["execution", "secrets", "run"]), CONFIG_KEY_TEXT_MAX_BYTES = 64 * 1024, UPLOAD_MAX_BYTES = 64 * 1024 * 1024, CONFIG_KEY_MAX_DEPTH = 64;
|
|
1184
1284
|
SOURCE_EXCLUDED_DIRS = Object.freeze([".git", ".ignitify", "node_modules", "__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]), SOURCE_EXCLUDED_ROOT_DIRS = Object.freeze(["target", "dist"]), SOURCE_EXCLUDED_FILE_PREFIXES = Object.freeze([".env"]), CREDENTIAL_KEYS = Object.freeze({ ".npmrc": /^[ \t]*(?![#;])[^=\n]*_(?:authToken|auth|password)[ \t]*=[ \t]*(?!\$\{\w+\}[ \t]*$)\S/m, ".yarnrc.yml": /^[ \t]*npmAuth(?:Token|Ident)[ \t]*:[ \t]*(?!["']?\$\{\w+\}["']?[ \t]*$)\S/m }), CREDENTIAL_CHECKED_FILES = Object.freeze(Object.keys(CREDENTIAL_KEYS));
|
|
1185
|
-
|
|
1285
|
+
isCanonicalRelativePath = (p) => !p.startsWith("/") && !p.includes("\\") && p.split("/").every((seg) => seg !== "" && seg !== "." && seg !== "..");
|
|
1286
|
+
refused = (reason) => ({ ok: false, reason });
|
|
1186
1287
|
} });
|
|
1187
1288
|
function normaliseSystemPackages(declared) {
|
|
1188
1289
|
return [...new Set(declared)].sort();
|
|
@@ -1206,6 +1307,23 @@ var USAGE_AXES, USAGE_DETAIL_COMMAND, RESETS_AT_NEXT_RENEWAL, init_usage = __esm
|
|
|
1206
1307
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1207
1308
|
USAGE_AXES = ["compute", "network", "network_in", "disk", "scratch", "runs", "pin", "build"], USAGE_DETAIL_COMMAND = "ignitify quota", RESETS_AT_NEXT_RENEWAL = "your next paid renewal";
|
|
1208
1309
|
} });
|
|
1310
|
+
function formatUserCode(code) {
|
|
1311
|
+
if (code.length !== 8) return code;
|
|
1312
|
+
let half = 8 / 2;
|
|
1313
|
+
return `${code.slice(0, half)}-${code.slice(half)}`;
|
|
1314
|
+
}
|
|
1315
|
+
var init_device_code = __esm({ "../../packages/contract/device-code.ts"() {
|
|
1316
|
+
"use strict";
|
|
1317
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1318
|
+
} });
|
|
1319
|
+
function cappedExponentialMs(step, baseMs, maxMs) {
|
|
1320
|
+
let n = Number.isNaN(step) ? 0 : Math.min(Math.max(0, Math.floor(step)), 32);
|
|
1321
|
+
return Math.min(baseMs * 2 ** n, maxMs);
|
|
1322
|
+
}
|
|
1323
|
+
var init_backoff = __esm({ "../../packages/contract/backoff.ts"() {
|
|
1324
|
+
"use strict";
|
|
1325
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
1326
|
+
} });
|
|
1209
1327
|
var init_tenant = __esm({ "../../packages/contract/tenant/index.ts"() {
|
|
1210
1328
|
"use strict";
|
|
1211
1329
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
@@ -1217,23 +1335,26 @@ var init_tenant = __esm({ "../../packages/contract/tenant/index.ts"() {
|
|
|
1217
1335
|
init_system_packages();
|
|
1218
1336
|
init_package_advice();
|
|
1219
1337
|
init_usage();
|
|
1338
|
+
init_wire_json();
|
|
1339
|
+
init_err_text();
|
|
1340
|
+
init_digest();
|
|
1341
|
+
init_device_code();
|
|
1342
|
+
init_backoff();
|
|
1220
1343
|
} });
|
|
1221
1344
|
function valueFlags(map2) {
|
|
1222
1345
|
return Object.fromEntries(Object.keys(map2).map((flag) => [flag, "value"]));
|
|
1223
1346
|
}
|
|
1224
|
-
|
|
1225
|
-
return TERMINAL_RUN_STATUSES.includes(status);
|
|
1226
|
-
}
|
|
1227
|
-
var COMMANDS, IGNORE_FILE, STATE, CREDENTIALS, LOGIN, LOGIN_VIEW, NETWORK, ENV, DEFAULT_TASKS_DIR, DEFAULTS, UPGRADE_COMMAND, PAYLOAD_LIMIT_FALLBACK_BYTES, RESULT_LIMIT_FALLBACK_BYTES, RUN_LIST_FLAG_PARAMS, VM_LIST_FLAG_PARAMS, GLOBAL_FLAGS, SERVER_FLAGS, HIDDEN_FLAGS, SHORT_FLAGS, VERSION_TOKENS, VALIDATE, ADVICE, INTEGRATION, NO_FLAGS, DIR, PAGE, YES, RAW, USAGE_FILTERS, COMMAND_META, VERSION_META, MESSAGES, RUN_STATUS, TERMINAL_RUN_STATUSES, ACTIVE_RUN_STATUSES, DEPLOYMENT_STATUS, POLL, WAIT, init_constants = __esm({ "src/constants/index.ts"() {
|
|
1347
|
+
var COMMANDS, IGNORE_FILE, STATE, CREDENTIALS, LOGIN, LOGIN_VIEW, NETWORK, ENV, DEFAULT_TASKS_DIR, DEFAULTS, UPGRADE_COMMAND, PAYLOAD_LIMIT_FALLBACK_BYTES, RESULT_LIMIT_FALLBACK_BYTES, RUN_LIST_FLAG_PARAMS, VM_LIST_FLAG_PARAMS, GLOBAL_FLAGS, SERVER_FLAGS, HIDDEN_FLAGS, SHORT_FLAGS, VERSION_TOKENS, VALIDATE, ADVICE, INTEGRATION, NO_FLAGS, DIR, PAGE, YES, RAW, USAGE_FLAG_PARAMS, USAGE_FILTERS, COMMAND_META, VERSION_META, MESSAGES, RUN_STATUS, ACTIVE_RUN_STATUSES, DEPLOYMENT_STATUS, POLL, WAIT, init_constants = __esm({ "src/constants/index.ts"() {
|
|
1228
1348
|
"use strict";
|
|
1229
1349
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1230
1350
|
init_http_client();
|
|
1231
1351
|
init_tenant();
|
|
1232
1352
|
init_tenant();
|
|
1353
|
+
init_tenant();
|
|
1233
1354
|
COMMANDS = { HELP: "help", LOGIN: "login", LOGOUT: "logout", WHOAMI: "whoami", QUOTA: "quota", TASK_CREATE: "task:create", TASK_LIST: "task:list", TASK_GET: "task:get", TASK_DELETE: "task:delete", TASK_VALIDATE: "task:validate", TASK_PACK: "task:pack", TASK_DEPLOY: "task:deploy", TASK_RUN: "task:run", DEPLOYMENT_LIST: "deployment:list", DEPLOYMENT_GET: "deployment:get", DEPLOYMENT_LOGS: "deployment:logs", DEPLOYMENT_DELETE: "deployment:delete", RUN_LIST: "run:list", RUN_GET: "run:get", RUN_LOGS: "run:logs", RUN_DELETE: "run:delete", RUN_CANCEL: "run:cancel", VM_LIST: "vm:list", VM_GET: "vm:get", VM_DELETE: "vm:delete", SECRET_SET: "secret:set", SECRET_LIST: "secret:list", SECRET_DELETE: "secret:delete", SCHEDULE_LIST: "schedule:list", SCHEDULE_CANCEL: "schedule:cancel", HOOK_CREATE: "hook:create", HOOK_LIST: "hook:list", HOOK_DELETE: "hook:delete", NOTIFY_SET: "notify:set", INTEGRATION_ADD: "integration:add", USAGE: "usage", USAGE_EXPORT: "usage:export" }, IGNORE_FILE = ".ignitifyignore", STATE = { DIR: ".ignitify", FILE: "state.json", GITIGNORE_FILE: ".gitignore", GITIGNORE_TEXT: `# written by ignitify: local state, never commit
|
|
1234
1355
|
*
|
|
1235
1356
|
` }, CREDENTIALS = { DIR_NAME: "ignitify", FILE_NAME: "credentials.json", DIR_MODE: 448, FILE_MODE: 384 }, LOGIN = { MAX_RETRIES: 3, KEY_TTL_DAYS: 90, MIN_POLL_INTERVAL_SEC: 5, BROWSER_SCHEMES: ["https:", "http:"] }, LOGIN_VIEW = { TITLE: "Sign in to Ignitify", OPEN_PAGE: "Open this page:", ASK_OPERATOR: "Give this code to your operator, who approves it:", CHECK_CODE: "Check this code", SAME_CODE: "The page must show the same code.", WAITING_STATIC: (minutes) => `Waiting for approval. The code expires in ${minutes} minutes.`, WAITING_LIVE: (left) => `Waiting for approval... code expires in ${left}`, CANCELLED: "Sign-in cancelled. Nothing was saved.", SIGNED_IN: "Signed in", SIGNED_OUT: "Signed out", KEY_EXPIRES: (days) => `${days} days after last use; each use renews it`, YES: "yes", ROWS: { ACCOUNT: "Account", ACCOUNT_ID: "Account id", KEY_LABEL: "Key label", KEY_EXPIRES: "Key expires", SAVED_TO: "Saved to", REVOKED: "Revoked", DELETED: "Deleted" } }, NETWORK = { REASONS: { ECONNREFUSED: "nothing accepts connections there", ENOTFOUND: "the host name is unknown", EAI_AGAIN: "the host name lookup failed", ETIMEDOUT: "the connection timed out", UND_ERR_CONNECT_TIMEOUT: "the connection timed out", ECONNRESET: "the connection was reset" }, TLS_WORDS: "the TLS certificate was not accepted", TLS_CODES: ["CERT_HAS_EXPIRED", "CERT_NOT_YET_VALID", "DEPTH_ZERO_SELF_SIGNED_CERT", "SELF_SIGNED_CERT_IN_CHAIN", "UNABLE_TO_VERIFY_LEAF_SIGNATURE", "UNABLE_TO_GET_ISSUER_CERT_LOCALLY"], TLS_CODE_PREFIXES: ["ERR_TLS_", "ERR_SSL_"], CODE_PATTERN: /^[A-Z][A-Z0-9_]*$/, DETAIL_MAX_CHARS: 80 }, ENV = { TASKS_DIR: "IGNITIFY_TASKS_DIR", KEY: "IGNITIFY_API_KEY" }, DEFAULT_TASKS_DIR = "tasks", DEFAULTS = { API_URL: "https://api.ignitify.dev" }, UPGRADE_COMMAND = "npm install --global ignitify@latest", PAYLOAD_LIMIT_FALLBACK_BYTES = 10240, RESULT_LIMIT_FALLBACK_BYTES = 10240, RUN_LIST_FLAG_PARAMS = { status: "status", "deployment-id": "deployment_id", "task-name": "task_name", preset: "preset", "correlation-id": "correlation_id", "vm-id": "vm_id", ...PAGE_FLAG_PARAMS }, VM_LIST_FLAG_PARAMS = { "deployment-id": "deployment_id", "task-name": "task_name", preset: "preset", "older-than": "older_than", ...PAGE_FLAG_PARAMS }, GLOBAL_FLAGS = { json: "bool", help: "bool" }, SERVER_FLAGS = { api: "value" }, HIDDEN_FLAGS = ["api"], SHORT_FLAGS = { h: "help", y: "yes" }, VERSION_TOKENS = ["--version", "-v"];
|
|
1236
|
-
VALIDATE = { VALID: "task config valid" }, ADVICE = { FLAG: "review-packages", TIMEOUT_MS: 6e4, FAULT_STATUSES: [400, 401, 403], SECONDS_ONLY_BELOW: 60, SECONDS_PER_MINUTE: 60, NO_PACKAGES: "this task lists no build.system_packages", SKIPPED: (reason) => `AI check skipped: ${reason}`, RATE_LIMITED: (retryAfterS) => `rate limited, try again in ${retryAfterS} s`, UNAVAILABLE: (reason) => `the review is unavailable (${reason})`, NO_ANSWER: (status, message) => status === null ? message : `server answered ${status}`, FAULT: (status, body) => `AI check failed (HTTP ${status}): ${body}`, BAD_NAMES: (bad) => `not valid package names: ${bad.join(", ")}`, TOO_MANY: (count, max) => `${count} packages listed, the most is ${max}`, BASIS: { measured: "measured", model: "model estimate" }, NO_FIT: (driveMib, capMib) => `does not fit: ${driveMib} MiB of packages against the ${capMib} MiB image store of your tier`, TITLE: "Package review", NOTE: "AI advice only. A suggestion is not checked against Debian.", COLUMNS: { PACKAGE: "Package", VERDICT: "Verdict", SIZE: "Size", NOTE: "Note", SUGGEST: "Suggest" }, NOT_DOUBLE_CHECKED: "not double-checked by the second model", RESULT_CLEAN: (total) => `No concerns found in ${total} package${total === 1 ? "" : "s"}.`, RESULT_FLAGGED: (total, flagged) => `${total} package${total === 1 ? "" : "s"} checked, ${flagged} to look at.`, NOT_ANSWERED: (names) => `No AI answer for: ${names.join(", ")}. The review could not judge ${names.length === 1 ? "it" : "them"}.`, BUILD_TITLE: "Build time", BUILD_LABELS: { ADDED: "Added", APPLIES: "Applies to", SIZE: "Packages size", LEFT_OUT: "Left out" }, BUILD_NONE: "nothing: your tenant already holds the drive for this list", BUILD_ADDED: (range, basis) => `about ${range} (${basis})`, BUILD_APPLIES: "the first deploy of this list. A later code-only redeploy reuses the drive.", BUILD_SIZE: (mib, capMib) => capMib === null ? `${mib} MiB` : `${mib} MiB of ${capMib} MiB (the image store of your tier)`, BUILD_LEFT_OUT: (names) => `${names.join(", ")} (unusable, or size unknown)` }, INTEGRATION = { PACKAGE_JSON: "package.json", NODE_MODULES: "node_modules", RUNTIME: "node", NPM: "npm", TARBALL_EXT: ".tgz", PACKED_ROOT: "package", PACK_TMP_PREFIX: "ignitify-integration-pack-", PACK_ARGS: (pkg, destDir, taskDir) => ["pack", pkg, "--pack-destination", destDir, "--prefix", taskDir], INSTALL_ARGS: (spec, taskDir) => ["install", spec, "--save-prod", "--ignore-scripts", "--prefix", taskDir], PACKED_MAX_BYTES: 8 * 1024 * 1024, ZLIB_TOO_BIG: "ERR_BUFFER_TOO_LARGE", VERSION_PATTERN: /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/, QUESTION: "Apply?", REGISTRY_URL: "https://registry.npmjs.org", REGISTRY_ACCEPT: "application/vnd.npm.install-v1+json", REGISTRY_TIMEOUT_MS: 5e3, NOTED_FIELDS: ["execution.network.type", "run.preset"], USAGE: "usage: ignitify integration:add <name> --task <slug> [--yes | --dry-run] [--dir <base-dir>]", TASK_REQUIRED: "--task <slug> is required: the task folder to add the integration to", YES_WITH_DRY_RUN: "--yes and --dry-run cannot be used together", BAD_NAME: (name, pattern) => `integration name ${JSON.stringify(name)} must match ${pattern}`, NOT_NODE: (runtime) => `integrations work with Node tasks only; this task has runtime "${runtime}"`, NO_PACKAGE_JSON: (taskDir) => `${taskDir} has no package.json: run npm init in the task folder first; nothing was changed`, NOT_INTERACTIVE: "Refusing to proceed: not a TTY. Re-run with --yes to apply the plan, or with --dry-run to see it.", PACK_FAILED: (pkg, code) => `npm pack ${pkg} failed${code === null ? "" : ` (exit ${code})`}; nothing in the task was changed`, INSTALL_FAILED: (spec, code) => `npm install ${spec} failed${code === null ? "" : ` (exit ${code})`}; task.yaml was not changed`, INSTALLED: (spec) => `${spec} installed`, BAD_VERSION: (pkg, version2) => `${pkg}: its package.json version ${JSON.stringify(version2)} is not a plain x.y.z version; nothing in the task was changed`, PACKED_TOO_BIG: (file, max) => `${file} unpacks to more than ${max} bytes: refused, nothing in the task was changed`, INSTALL_ONLY: (spec) => `installs ${spec}; task.yaml unchanged`, NOT_AN_INTEGRATION: (pkg, file) => `${pkg} has no ${file}: it is not an integration package`, BAD_MANIFEST: (pkg, issue) => `${pkg} integration.yaml: ${issue}`, UNREADABLE: (file, reason) => `cannot read ${file}: ${reason}`, WRITE_MISMATCH: (file) => `the edited ${file} does not read back as the plan; nothing was written`, YOU_ADD: "you add:", NO_CHANGES: "task.yaml already has every setting this integration needs; nothing to write", DRY_RUN: "dry run: task.yaml was not changed", WRITTEN: (file) => `${file} updated`, NOT_INSTALLED: (pkgs) => `${pkgs.join(", ")} ${pkgs.length === 1 ? "is" : "are"} in package.json but not in node_modules: run npm install, then task:validate again`, OBSOLETE: (pkg, version2, latest) => `${pkg}@${version2} is obsolete: use ${latest}`, OBSOLETE_SKIPPED: (reason) => `obsolete-version check skipped: ${reason}`, REGISTRY_UNREACHABLE: "the npm registry did not answer (offline?)", REGISTRY_NOT_FOUND: (pkg) => `${pkg} is not on the npm registry` }, NO_FLAGS = {}, DIR = { dir: "value" }, PAGE = valueFlags(PAGE_FLAG_PARAMS), YES = { yes: "bool" }, RAW = { raw: "bool" }, USAGE_FILTERS = { period: "value", axis: "value", vm: "value", run: "value" }, COMMAND_META = { [COMMANDS.HELP]: { flags: NO_FLAGS, positionals: 1, confirms: false }, [COMMANDS.LOGIN]: { flags: { ...SERVER_FLAGS, "no-browser": "bool", name: "value" }, positionals: 0, confirms: false }, [COMMANDS.LOGOUT]: { flags: NO_FLAGS, positionals: 0, confirms: false }, [COMMANDS.WHOAMI]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.QUOTA]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.TASK_CREATE]: { flags: { ...SERVER_FLAGS, ...DIR, lang: "value", local: "bool", "no-init": "bool", "no-scaffold": "bool" }, positionals: 1, confirms: false }, [COMMANDS.TASK_LIST]: { flags: { ...SERVER_FLAGS, ...PAGE }, positionals: 0, confirms: false }, [COMMANDS.TASK_GET]: { flags: { ...SERVER_FLAGS, ...DIR }, positionals: 1, confirms: false }, [COMMANDS.TASK_DELETE]: { flags: { ...SERVER_FLAGS, ...DIR, ...YES }, positionals: 1, confirms: true }, [COMMANDS.TASK_VALIDATE]: { flags: { ...SERVER_FLAGS, ...DIR, [ADVICE.FLAG]: "bool" }, positionals: 1, confirms: false }, [COMMANDS.TASK_PACK]: { flags: DIR, positionals: 1, confirms: false }, [COMMANDS.TASK_DEPLOY]: { flags: { ...SERVER_FLAGS, ...DIR, check: "bool" }, positionals: 1, confirms: false }, [COMMANDS.TASK_RUN]: { flags: { deployment: "value", payload: "value", "timeout-sec": "value", "on-busy": "value", at: "value", wait: "bool", ...DIR, ...SERVER_FLAGS }, positionals: 1, confirms: false }, [COMMANDS.DEPLOYMENT_LIST]: { flags: { ...SERVER_FLAGS, ...PAGE }, positionals: 0, confirms: false }, [COMMANDS.DEPLOYMENT_GET]: { flags: SERVER_FLAGS, positionals: 1, confirms: false }, [COMMANDS.DEPLOYMENT_LOGS]: { flags: { ...SERVER_FLAGS, ...RAW }, positionals: 1, confirms: false }, [COMMANDS.DEPLOYMENT_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.RUN_LIST]: { flags: { ...SERVER_FLAGS, ...valueFlags(RUN_LIST_FLAG_PARAMS) }, positionals: 0, confirms: false }, [COMMANDS.RUN_GET]: { flags: { ...SERVER_FLAGS, full: "bool" }, positionals: 1, confirms: false }, [COMMANDS.RUN_LOGS]: { flags: { ...SERVER_FLAGS, ...RAW }, positionals: 1, confirms: false }, [COMMANDS.RUN_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.RUN_CANCEL]: { flags: { ...SERVER_FLAGS, ...YES, force: "bool", grace: "value" }, positionals: 1, confirms: true }, [COMMANDS.VM_LIST]: { flags: { ...SERVER_FLAGS, ...valueFlags(VM_LIST_FLAG_PARAMS), pinned: "bool" }, positionals: 0, confirms: false }, [COMMANDS.VM_GET]: { flags: SERVER_FLAGS, positionals: 1, confirms: false }, [COMMANDS.VM_DELETE]: { flags: { ...SERVER_FLAGS, ...YES, force: "bool" }, positionals: 1, confirms: true }, [COMMANDS.SECRET_SET]: { flags: { ...SERVER_FLAGS, stdin: "bool", value: "value" }, positionals: 1, confirms: false, secretArgv: true }, [COMMANDS.SECRET_LIST]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.SECRET_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.SCHEDULE_LIST]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.SCHEDULE_CANCEL]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.HOOK_CREATE]: { flags: { ...SERVER_FLAGS, "task-name": "value" }, positionals: 1, confirms: false }, [COMMANDS.HOOK_LIST]: { flags: { ...SERVER_FLAGS, ...PAGE }, positionals: 1, confirms: false }, [COMMANDS.HOOK_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.NOTIFY_SET]: { flags: { ...SERVER_FLAGS, url: "value", clear: "bool", "secret-stdin": "bool", secret: "value" }, positionals: 1, confirms: false, secretArgv: true }, [COMMANDS.INTEGRATION_ADD]: { flags: { ...DIR, ...YES, task: "value", "dry-run": "bool" }, positionals: 1, confirms: true }, [COMMANDS.USAGE]: { flags: { ...SERVER_FLAGS, ...USAGE_FILTERS, runs: "bool", vms: "bool" }, positionals: 0, confirms: false }, [COMMANDS.USAGE_EXPORT]: { flags: { ...SERVER_FLAGS, ...USAGE_FILTERS, csv: "bool" }, positionals: 0, confirms: false } }, VERSION_META = { flags: SERVER_FLAGS, positionals: 0, confirms: false }, MESSAGES = { NOT_SIGNED_IN: "Not signed in. Run 'ignitify login', or set the IGNITIFY_API_KEY environment variable.", CREDENTIALS_SYMLINK: (file) => `${file} is a symbolic link. Remove it and run 'ignitify login' again.`, CREDENTIALS_NOT_FILE: (file) => `${file} is not a regular file. Remove it and run 'ignitify login' again.`, CREDENTIALS_NOT_OWNED: (file) => `${file} belongs to another user. Remove it and run 'ignitify login' again.`, CREDENTIALS_TOO_OPEN: (file, mode) => `${file} can be read by other users (mode 0${mode}). Run: chmod 600 ${file}`, CREDENTIALS_UNREADABLE: (file) => `${file} is not a valid credentials file. Remove it and run 'ignitify login' again.`, CREDENTIALS_OTHER_URL: (fileUrl, url) => `The saved key is for ${fileUrl}, not ${url}. Run 'ignitify login --api ${url}'.`, CREDENTIALS_DIR_NOT_DIR: (dir) => `${dir} is not a folder. Remove it and run 'ignitify login' again.`, API_URL_NOT_URL: (url) => `The API address "${url}" is not a URL.`, API_URL_NOT_HTTPS: (url) => `The API address ${url} is not https. The CLI sends your key only over https, or over plain http to this machine (localhost, 127.0.0.1, ::1).`, LOGIN_REPLACED: (label) => `Note: replaced the key "${label}" of another machine. Use 'ignitify login --name <other-label>' to keep both.`, LOGIN_EXPIRED: (code) => `The code ${code} expired before it was approved. Run 'ignitify login' again.`, LOGIN_REFUSED: (reason) => `The sign-in was refused: ${reason}.`, LOGIN_UNKNOWN: "The sign-in code is unknown or was already used. Run 'ignitify login' again.", LOGIN_BAD_ANSWER: "The server sent a sign-in answer with no usable key. Nothing was saved.", LOGIN_BAD_START: "The server sent a sign-in start that the CLI cannot use (no code, or no wait times). Nothing was started.", ENV_KEY_OVERRIDES_LOGIN: "Note: the IGNITIFY_API_KEY environment variable is set, so it is used instead of your saved login.", KEY_EXPIRED_HINT: "Run 'ignitify login' to sign in again.", LOGIN_TOO_MANY: "Too many sign-in attempts from this network. Try again later.", LOGIN_CAP: (limit) => `This account already has the most API keys its plan allows${limit === null ? "" : ` (${limit})`}. Remove one, or approve with "replace", then run 'ignitify login' again.`, CANNOT_REACH: (url, detail) => `Cannot reach ${url}${detail === null ? "" : ` (${detail})`}. Check your network and run 'ignitify login' again.`, UNREACHABLE: (origin, detail) => `Cannot reach ${origin}${detail === null ? "" : ` (${detail})`}.`, LOGOUT_NOTHING: "Not signed in. There are no saved credentials.", LOGOUT_ENV_NOTE: "Note: the IGNITIFY_API_KEY environment variable is still set. Logout does not change it.", LOGOUT_NOT_REVOKED: (label) => `Warning: the server did not revoke the key, so it may still work. The saved credentials were deleted. Ask your operator to revoke the key "${label}".`, SLUG_MISSING: (source) => `'slug' is required in ${source}`, SLUG_INVALID: (source, reason) => `${source}: 'slug' ${reason}`, PRESET_INVALID: "run.preset must be a non-empty string", PRESET_UNKNOWN: (source, name, valid) => `${source}: unknown run.preset "${name}" (valid: ${valid.join(", ")}). An unrecognised preset would silently fall back to the platform default, giving you a different instance class than you declared.`, TIMEOUT_INVALID: "run.timeout_sec must be a positive number", TASK_ID_REQUIRED: "a <task-id> is required", TASK_ID_INVALID: (id, reason) => `task id ${JSON.stringify(id)} ${reason}`, ERROR: (message) => `Error: ${message}`, ERROR_PREFIX: "Error:", SERVER_TRACE_ID: (id) => `server trace id: ${id}`, ARG_REQUIRED: (label) => `${label} is required`, UNKNOWN_COMMAND: "unknown command", SEE_HELP: "Run 'ignitify help' to see every command.", UNKNOWN_SHORT_FLAG: (short, long, command) => `unknown flag ${short} (--${long}) for ${command}`, GRACE_INVALID: (got) => `--grace must be a whole number of milliseconds, 0 or more (got ${JSON.stringify(got)})`, GRACE_WITH_FORCE: "--grace has no effect with --force (force stops the run now)", TASK_LIMITS: (payload, result) => `payload max ${payload}, result max ${result}; over the limit the run fails`, PAYLOAD_OVER_LIMIT: (bytes2, limit) => `payload is ${bytes2} bytes; the limit is ${limit} bytes`, PAYLOAD_REFUSED_BY_SERVER: (limit) => `the server refused the payload as too large; the limit is ${limit} bytes`, DEFAULT_PAYLOAD_OVER_LIMIT: (source, bytes2, limit) => `${source}: run.payload is ${bytes2} bytes; the offline limit is ${limit} bytes (the server may allow more)`, IGNORED_BY_FILE: `ignored by ${IGNORE_FILE}`, IGNORED_COUNT: (n) => `${n} path(s) left out by ${IGNORE_FILE}`, TASK_DELETED: "task deleted", TASK_LINK_REMOVED: "Removed local link", TASK_LINK_NOT_REMOVED: (link, reason) => `Warning: the task is deleted, but its local link was not removed (${reason}). Remove ${link} by hand.`, DEPLOY_DELETED: "deployment deleted", RUN_DELETED: "run deleted", ABORTED: "Aborted.", CONFIRM_PROCEED: "Proceed?", SECRET_SET_USAGE: "usage: ignitify secret:set <NAME> --stdin (the value is read from stdin)", SECRET_VALUE_EMPTY: "secret:set read an empty value from stdin \u2014 nothing was stored (pipe the value in: `--stdin < value-file`)", SECRET_VALUE_ON_ARGV: `secret:set takes no value on argv: it is visible in \`ps\` and is written to your shell history. Pipe it on stdin, e.g.
|
|
1357
|
+
VALIDATE = { VALID: "task config valid" }, ADVICE = { FLAG: "review-packages", TIMEOUT_MS: 6e4, FAULT_STATUSES: [400, 401, 403], SECONDS_ONLY_BELOW: 60, SECONDS_PER_MINUTE: 60, NO_PACKAGES: "this task lists no build.system_packages", SKIPPED: (reason) => `AI check skipped: ${reason}`, RATE_LIMITED: (retryAfterS) => `rate limited, try again in ${retryAfterS} s`, UNAVAILABLE: (reason) => `the review is unavailable (${reason})`, NO_ANSWER: (status, message) => status === null ? message : `server answered ${status}`, FAULT: (status, body) => `AI check failed (HTTP ${status}): ${body}`, BAD_NAMES: (bad) => `not valid package names: ${bad.join(", ")}`, TOO_MANY: (count, max) => `${count} packages listed, the most is ${max}`, BASIS: { measured: "measured", model: "model estimate" }, NO_FIT: (driveMib, capMib) => `does not fit: ${driveMib} MiB of packages against the ${capMib} MiB image store of your tier`, TITLE: "Package review", NOTE: "AI advice only. A suggestion is not checked against Debian.", COLUMNS: { PACKAGE: "Package", VERDICT: "Verdict", SIZE: "Size", NOTE: "Note", SUGGEST: "Suggest" }, NOT_DOUBLE_CHECKED: "not double-checked by the second model", RESULT_CLEAN: (total) => `No concerns found in ${total} package${total === 1 ? "" : "s"}.`, RESULT_FLAGGED: (total, flagged) => `${total} package${total === 1 ? "" : "s"} checked, ${flagged} to look at.`, NOT_ANSWERED: (names) => `No AI answer for: ${names.join(", ")}. The review could not judge ${names.length === 1 ? "it" : "them"}.`, BUILD_TITLE: "Build time", BUILD_LABELS: { ADDED: "Added", APPLIES: "Applies to", SIZE: "Packages size", LEFT_OUT: "Left out" }, BUILD_NONE: "nothing: your tenant already holds the drive for this list", BUILD_ADDED: (range, basis) => `about ${range} (${basis})`, BUILD_APPLIES: "the first deploy of this list. A later code-only redeploy reuses the drive.", BUILD_SIZE: (mib, capMib) => capMib === null ? `${mib} MiB` : `${mib} MiB of ${capMib} MiB (the image store of your tier)`, BUILD_LEFT_OUT: (names) => `${names.join(", ")} (unusable, or size unknown)` }, INTEGRATION = { PACKAGE_JSON: "package.json", NODE_MODULES: "node_modules", RUNTIME: "node", NPM: "npm", TARBALL_EXT: ".tgz", PACKED_ROOT: "package", PACK_TMP_PREFIX: "ignitify-integration-pack-", PACK_ARGS: (pkg, destDir, taskDir) => ["pack", pkg, "--pack-destination", destDir, "--prefix", taskDir], INSTALL_ARGS: (spec, taskDir) => ["install", spec, "--save-prod", "--ignore-scripts", "--prefix", taskDir], PACKED_MAX_BYTES: 8 * 1024 * 1024, ZLIB_TOO_BIG: "ERR_BUFFER_TOO_LARGE", VERSION_PATTERN: /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/, QUESTION: "Apply?", REGISTRY_URL: "https://registry.npmjs.org", REGISTRY_ACCEPT: "application/vnd.npm.install-v1+json", REGISTRY_TIMEOUT_MS: 5e3, NOTED_FIELDS: ["execution.network.type", "run.preset"], USAGE: "usage: ignitify integration:add <name> --task <slug> [--yes | --dry-run] [--dir <base-dir>]", TASK_REQUIRED: "--task <slug> is required: the task folder to add the integration to", YES_WITH_DRY_RUN: "--yes and --dry-run cannot be used together", BAD_NAME: (name, pattern) => `integration name ${JSON.stringify(name)} must match ${pattern}`, NOT_NODE: (runtime) => `integrations work with Node tasks only; this task has runtime "${runtime}"`, NO_PACKAGE_JSON: (taskDir) => `${taskDir} has no package.json: run npm init in the task folder first; nothing was changed`, NOT_INTERACTIVE: "Refusing to proceed: not a TTY. Re-run with --yes to apply the plan, or with --dry-run to see it.", PACK_FAILED: (pkg, code) => `npm pack ${pkg} failed${code === null ? "" : ` (exit ${code})`}; nothing in the task was changed`, INSTALL_FAILED: (spec, code) => `npm install ${spec} failed${code === null ? "" : ` (exit ${code})`}; task.yaml was not changed`, INSTALLED: (spec) => `${spec} installed`, BAD_VERSION: (pkg, version2) => `${pkg}: its package.json version ${JSON.stringify(version2)} is not a plain x.y.z version; nothing in the task was changed`, PACKED_TOO_BIG: (file, max) => `${file} unpacks to more than ${max} bytes: refused, nothing in the task was changed`, INSTALL_ONLY: (spec) => `installs ${spec}; task.yaml unchanged`, NOT_AN_INTEGRATION: (pkg, file) => `${pkg} has no ${file}: it is not an integration package`, BAD_MANIFEST: (pkg, issue) => `${pkg} integration.yaml: ${issue}`, UNREADABLE: (file, reason) => `cannot read ${file}: ${reason}`, WRITE_MISMATCH: (file) => `the edited ${file} does not read back as the plan; nothing was written`, YOU_ADD: "you add:", NO_CHANGES: "task.yaml already has every setting this integration needs; nothing to write", DRY_RUN: "dry run: task.yaml was not changed", WRITTEN: (file) => `${file} updated`, NOT_INSTALLED: (pkgs) => `${pkgs.join(", ")} ${pkgs.length === 1 ? "is" : "are"} in package.json but not in node_modules: run npm install, then task:validate again`, OBSOLETE: (pkg, version2, latest) => `${pkg}@${version2} is obsolete: use ${latest}`, OBSOLETE_SKIPPED: (reason) => `obsolete-version check skipped: ${reason}`, REGISTRY_UNREACHABLE: "the npm registry did not answer (offline?)", REGISTRY_NOT_FOUND: (pkg) => `${pkg} is not on the npm registry` }, NO_FLAGS = {}, DIR = { dir: "value" }, PAGE = valueFlags(PAGE_FLAG_PARAMS), YES = { yes: "bool" }, RAW = { raw: "bool" }, USAGE_FLAG_PARAMS = { period: "period", axis: "axis", vm: "vm", run: "run" }, USAGE_FILTERS = valueFlags(USAGE_FLAG_PARAMS), COMMAND_META = { [COMMANDS.HELP]: { flags: NO_FLAGS, positionals: 1, confirms: false }, [COMMANDS.LOGIN]: { flags: { ...SERVER_FLAGS, "no-browser": "bool", name: "value" }, positionals: 0, confirms: false }, [COMMANDS.LOGOUT]: { flags: NO_FLAGS, positionals: 0, confirms: false }, [COMMANDS.WHOAMI]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.QUOTA]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.TASK_CREATE]: { flags: { ...SERVER_FLAGS, ...DIR, lang: "value", local: "bool", "no-init": "bool", "no-scaffold": "bool" }, positionals: 1, confirms: false }, [COMMANDS.TASK_LIST]: { flags: { ...SERVER_FLAGS, ...PAGE }, positionals: 0, confirms: false }, [COMMANDS.TASK_GET]: { flags: { ...SERVER_FLAGS, ...DIR }, positionals: 1, confirms: false }, [COMMANDS.TASK_DELETE]: { flags: { ...SERVER_FLAGS, ...DIR, ...YES }, positionals: 1, confirms: true }, [COMMANDS.TASK_VALIDATE]: { flags: { ...SERVER_FLAGS, ...DIR, [ADVICE.FLAG]: "bool" }, positionals: 1, confirms: false }, [COMMANDS.TASK_PACK]: { flags: DIR, positionals: 1, confirms: false }, [COMMANDS.TASK_DEPLOY]: { flags: { ...SERVER_FLAGS, ...DIR, check: "bool" }, positionals: 1, confirms: false }, [COMMANDS.TASK_RUN]: { flags: { deployment: "value", payload: "value", "timeout-sec": "value", "on-busy": "value", at: "value", wait: "bool", ...DIR, ...SERVER_FLAGS }, positionals: 1, confirms: false }, [COMMANDS.DEPLOYMENT_LIST]: { flags: { ...SERVER_FLAGS, ...PAGE }, positionals: 0, confirms: false }, [COMMANDS.DEPLOYMENT_GET]: { flags: SERVER_FLAGS, positionals: 1, confirms: false }, [COMMANDS.DEPLOYMENT_LOGS]: { flags: { ...SERVER_FLAGS, ...RAW }, positionals: 1, confirms: false }, [COMMANDS.DEPLOYMENT_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.RUN_LIST]: { flags: { ...SERVER_FLAGS, ...valueFlags(RUN_LIST_FLAG_PARAMS) }, positionals: 0, confirms: false }, [COMMANDS.RUN_GET]: { flags: { ...SERVER_FLAGS, full: "bool" }, positionals: 1, confirms: false }, [COMMANDS.RUN_LOGS]: { flags: { ...SERVER_FLAGS, ...RAW }, positionals: 1, confirms: false }, [COMMANDS.RUN_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.RUN_CANCEL]: { flags: { ...SERVER_FLAGS, ...YES, force: "bool", grace: "value" }, positionals: 1, confirms: true }, [COMMANDS.VM_LIST]: { flags: { ...SERVER_FLAGS, ...valueFlags(VM_LIST_FLAG_PARAMS), pinned: "bool" }, positionals: 0, confirms: false }, [COMMANDS.VM_GET]: { flags: SERVER_FLAGS, positionals: 1, confirms: false }, [COMMANDS.VM_DELETE]: { flags: { ...SERVER_FLAGS, ...YES, force: "bool" }, positionals: 1, confirms: true }, [COMMANDS.SECRET_SET]: { flags: { ...SERVER_FLAGS, stdin: "bool", value: "value" }, positionals: 1, confirms: false, secretArgv: true }, [COMMANDS.SECRET_LIST]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.SECRET_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.SCHEDULE_LIST]: { flags: SERVER_FLAGS, positionals: 0, confirms: false }, [COMMANDS.SCHEDULE_CANCEL]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.HOOK_CREATE]: { flags: { ...SERVER_FLAGS, "task-name": "value" }, positionals: 1, confirms: false }, [COMMANDS.HOOK_LIST]: { flags: { ...SERVER_FLAGS, ...PAGE }, positionals: 1, confirms: false }, [COMMANDS.HOOK_DELETE]: { flags: { ...SERVER_FLAGS, ...YES }, positionals: 1, confirms: true }, [COMMANDS.NOTIFY_SET]: { flags: { ...SERVER_FLAGS, url: "value", clear: "bool", "secret-stdin": "bool", secret: "value" }, positionals: 1, confirms: false, secretArgv: true }, [COMMANDS.INTEGRATION_ADD]: { flags: { ...DIR, ...YES, task: "value", "dry-run": "bool" }, positionals: 1, confirms: true }, [COMMANDS.USAGE]: { flags: { ...SERVER_FLAGS, ...USAGE_FILTERS, runs: "bool", vms: "bool" }, positionals: 0, confirms: false }, [COMMANDS.USAGE_EXPORT]: { flags: { ...SERVER_FLAGS, ...USAGE_FILTERS, csv: "bool" }, positionals: 0, confirms: false } }, VERSION_META = { flags: SERVER_FLAGS, positionals: 0, confirms: false }, MESSAGES = { NOT_SIGNED_IN: "Not signed in. Run 'ignitify login', or set the IGNITIFY_API_KEY environment variable.", CREDENTIALS_SYMLINK: (file) => `${file} is a symbolic link. Remove it and run 'ignitify login' again.`, CREDENTIALS_NOT_FILE: (file) => `${file} is not a regular file. Remove it and run 'ignitify login' again.`, CREDENTIALS_NOT_OWNED: (file) => `${file} belongs to another user. Remove it and run 'ignitify login' again.`, CREDENTIALS_TOO_OPEN: (file, mode) => `${file} can be read by other users (mode 0${mode}). Run: chmod 600 ${file}`, CREDENTIALS_UNREADABLE: (file) => `${file} is not a valid credentials file. Remove it and run 'ignitify login' again.`, CREDENTIALS_OTHER_URL: (fileUrl, url) => `The saved key is for ${fileUrl}, not ${url}. Run 'ignitify login --api ${url}'.`, CREDENTIALS_DIR_NOT_DIR: (dir) => `${dir} is not a folder. Remove it and run 'ignitify login' again.`, API_URL_NOT_URL: (url) => `The API address "${url}" is not a URL.`, API_URL_NOT_HTTPS: (url) => `The API address ${url} is not https. The CLI sends your key only over https, or over plain http to this machine (localhost, 127.0.0.1, ::1).`, LOGIN_REPLACED: (label) => `Note: replaced the key "${label}" of another machine. Use 'ignitify login --name <other-label>' to keep both.`, LOGIN_EXPIRED: (code) => `The code ${code} expired before it was approved. Run 'ignitify login' again.`, LOGIN_REFUSED: (reason) => `The sign-in was refused: ${reason}.`, LOGIN_UNKNOWN: "The sign-in code is unknown or was already used. Run 'ignitify login' again.", LOGIN_BAD_ANSWER: "The server sent a sign-in answer with no usable key. Nothing was saved.", LOGIN_BAD_START: "The server sent a sign-in start that the CLI cannot use (no code, or no wait times). Nothing was started.", ENV_KEY_OVERRIDES_LOGIN: "Note: the IGNITIFY_API_KEY environment variable is set, so it is used instead of your saved login.", KEY_EXPIRED_HINT: "Run 'ignitify login' to sign in again.", LOGIN_TOO_MANY: "Too many sign-in attempts from this network. Try again later.", LOGIN_CAP: (limit) => `This account already has the most API keys its plan allows${limit === null ? "" : ` (${limit})`}. Remove one, or approve with "replace", then run 'ignitify login' again.`, CANNOT_REACH: (url, detail) => `Cannot reach ${url}${detail === null ? "" : ` (${detail})`}. Check your network and run 'ignitify login' again.`, UNREACHABLE: (origin, detail) => `Cannot reach ${origin}${detail === null ? "" : ` (${detail})`}.`, LOGOUT_NOTHING: "Not signed in. There are no saved credentials.", LOGOUT_ENV_NOTE: "Note: the IGNITIFY_API_KEY environment variable is still set. Logout does not change it.", LOGOUT_NOT_REVOKED: (label) => `Warning: the server did not revoke the key, so it may still work. The saved credentials were deleted. Ask your operator to revoke the key "${label}".`, SLUG_MISSING: (source) => `'slug' is required in ${source}`, SLUG_INVALID: (source, reason) => `${source}: 'slug' ${reason}`, PRESET_INVALID: "run.preset must be a non-empty string", PRESET_UNKNOWN: (source, name, valid) => `${source}: unknown run.preset "${name}" (valid: ${valid.join(", ")}). An unrecognised preset would silently fall back to the platform default, giving you a different instance class than you declared.`, TIMEOUT_INVALID: "run.timeout_sec must be a positive number", TASK_ID_REQUIRED: "a <task-id> is required", TASK_ID_INVALID: (id, reason) => `task id ${JSON.stringify(id)} ${reason}`, ERROR: (message) => `Error: ${message}`, ERROR_PREFIX: "Error:", SERVER_TRACE_ID: (id) => `server trace id: ${id}`, ARG_REQUIRED: (label) => `${label} is required`, UNKNOWN_COMMAND: "unknown command", SEE_HELP: "Run 'ignitify help' to see every command.", UNKNOWN_SHORT_FLAG: (short, long, command) => `unknown flag ${short} (--${long}) for ${command}`, GRACE_INVALID: (got) => `--grace must be a whole number of milliseconds, 0 or more (got ${JSON.stringify(got)})`, GRACE_WITH_FORCE: "--grace has no effect with --force (force stops the run now)", TASK_LIMITS: (payload, result) => `payload max ${payload}, result max ${result}; over the limit the run fails`, PAYLOAD_OVER_LIMIT: (bytes, limit) => `payload is ${bytes} bytes; the limit is ${limit} bytes`, PAYLOAD_REFUSED_BY_SERVER: (limit) => `the server refused the payload as too large; the limit is ${limit} bytes`, DEFAULT_PAYLOAD_OVER_LIMIT: (source, bytes, limit) => `${source}: run.payload is ${bytes} bytes; the offline limit is ${limit} bytes (the server may allow more)`, IGNORED_BY_FILE: `ignored by ${IGNORE_FILE}`, IGNORED_COUNT: (n) => `${n} path(s) left out by ${IGNORE_FILE}`, TASK_DELETED: "task deleted", TASK_LINK_REMOVED: "Removed local link", TASK_LINK_NOT_REMOVED: (link, reason) => `Warning: the task is deleted, but its local link was not removed (${reason}). Remove ${link} by hand.`, DEPLOY_DELETED: "deployment deleted", RUN_DELETED: "run deleted", ABORTED: "Aborted.", CONFIRM_PROCEED: "Proceed?", SECRET_SET_USAGE: "usage: ignitify secret:set <NAME> --stdin (the value is read from stdin)", SECRET_VALUE_EMPTY: "secret:set read an empty value from stdin \u2014 nothing was stored (pipe the value in: `--stdin < value-file`)", SECRET_VALUE_ON_ARGV: `secret:set takes no value on argv: it is visible in \`ps\` and is written to your shell history. Pipe it on stdin, e.g.
|
|
1237
1358
|
ignitify secret:set <NAME> --stdin < value-file
|
|
1238
1359
|
printf %s "$VALUE" | ignitify secret:set <NAME> --stdin
|
|
1239
1360
|
\u26A0\uFE0F The value you just typed is already in your history \u2014 rotate it.`, NOTIFY_SECRET_ON_ARGV: '--secret is not accepted: a value on argv is visible in `ps` and is written to your shell history. Use --secret-stdin, e.g.\n printf %s "$SECRET" | ignitify notify:set <deployment-id> --url <https://\u2026> --secret-stdin\n\u26A0\uFE0F The value you just typed is already in your history \u2014 rotate it.', HOOK_CREATE_USAGE: "usage: ignitify hook:create <deployment-id> --task-name <name>", HOOK_TASK_NAME_REQUIRED: `--task-name <name> is required: a hook starts a run of ONE task in the deployment, and a run without a task name fails.
|
|
@@ -1241,15 +1362,14 @@ usage: ignitify hook:create <deployment-id> --task-name <name>`, HOOK_LIST_USAGE
|
|
|
1241
1362
|
ignitify notify:set <deployment-id> --clear
|
|
1242
1363
|
--secret-stdin reads the signing secret (at least ${32} characters) from stdin; it is
|
|
1243
1364
|
required with --url. There is no --secret flag: a value on argv is visible in \`ps\`
|
|
1244
|
-
and lands in your shell history.`, NOTIFY_URL_NEEDS_SECRET: "--url needs --secret-stdin: the server refuses a notify target with no signing secret.", NOTIFY_SECRET_EMPTY: "--secret-stdin read an empty value from stdin.", NOTIFY_URL_WITH_CLEAR: "--url and --clear cannot be used together.", NOTIFY_SECRET_STDIN_VALUE: "--secret-stdin takes no value: pipe the secret on stdin.", HOOK_SECRET_SHOWN_ONCE: "\u26A0\uFE0F The secret below is shown ONCE and cannot be read back \u2014 hook:list never returns it. Store it now; if it is lost, delete the hook and create a new one.", HOOK_PAYLOAD_LIMIT: (limit) => `A webhook body over ${limit} is refused with 413 before the signature is checked.`, SECRET_DELETE_USAGE: "usage: ignitify secret:delete <NAME>", USAGE_EXPORT_USAGE: "usage: ignitify usage:export [--period YYYY-MM] (--json|--csv) (name exactly one format)", LATEST_DEPLOY_BUILDING: (task, deploymentId) => `the latest deploy of ${task} is still building (${deploymentId}). Wait for it ('ignitify deployment:get ${deploymentId}'), or pass --deployment <id> to run an older one.`, LATEST_DEPLOY_FAILED: (task, reason) => `the latest deploy of ${task} failed: ${reason ?? "no reason recorded"}. Fix the task and run 'ignitify task:deploy ${task}' again, or pass --deployment <id> to run an older one.`, RUN_AT_WITH_WAIT: "--wait cannot be used with --at: a scheduled run has no run id until it fires. Drop --wait; follow it later with 'ignitify schedule:list' and 'ignitify run:list'.", SECRET_STORED: (name) => `secret ${name} stored`, SECRET_REMOVED: (name) => `secret ${name} removed` }, RUN_STATUS = { PENDING: "PENDING", PROVISIONING: "PROVISIONING", RUNNING: "RUNNING", RETRYING: "RETRYING", COMPLETED: "COMPLETED", FAILED: "FAILED", CANCELLED: "CANCELLED" },
|
|
1245
|
-
ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set([RUN_STATUS.PENDING, RUN_STATUS.PROVISIONING, RUN_STATUS.RUNNING, RUN_STATUS.RETRYING]), DEPLOYMENT_STATUS = { BUILDING: "BUILDING", READY: "READY", FAILED: "FAILED", ARCHIVED: "ARCHIVED" }, POLL = { DEPLOY: { BASE_MS: 500, MAX_MS: 1e3, TIMEOUT_MS: 900 * 1e3 }, RUN: { BASE_MS: 500, MAX_MS: 3e3, TIMEOUT_MS: 1800 * 1e3 }, ERROR: { MIN_TRIES: 3, GRACE_MS: 6e4 } }, WAIT = { UPLOADING: (slug2, size) => `Uploading ${slug2}${size ? ` (${size})` : ""}`, UPLOAD_FAILED: "Upload failed", BUILDING: (deploymentId) => `Building image ${deploymentId}`, BUILT: "Image built", REUSED: "Image already built \u2014 reused", BUILD_FAILED: "Build failed", BUILD_FAILED_DETAIL: (deploymentId, reason) => `deployment ${deploymentId} failed to build \u2014 ${reason}`, BUILD_TIMEOUT: "Still building after 15 minutes \u2014 stopped waiting", BUILD_TIMEOUT_DETAIL: (deploymentId) => `deployment ${deploymentId} is still building after 15 minutes. The build has NOT been cancelled \u2014 check it with 'ignitify deployment:get ${deploymentId}'.`, RUN: (runId, status) => `Run ${runId} ${status}`, RUN_SUBMITTED: (runId) => `Run ${runId} submitted`, RUN_ENDED: (status) => `Run ${status}`, RUN_TIMEOUT: (status) => `Run is still ${status} after 30 minutes \u2014 stopped waiting`, RUN_TIMEOUT_DETAIL: (runId) => `The run has NOT been cancelled \u2014 check it with 'ignitify run:get ${runId}'.`, HINT_RETRYING: "lost contact with the server \u2014 retrying", LOST: "Lost contact with the server \u2014 stopped waiting", LOST_BUILD_DETAIL: (deploymentId, cause) => `stopped waiting for deployment ${deploymentId}: ${cause}. The build has NOT been cancelled \u2014 check it with 'ignitify deployment:get ${deploymentId}'.`, LOST_RUN_DETAIL: (runId, cause) => `stopped waiting for run ${runId}: ${cause}. The run has NOT been cancelled \u2014 check it with 'ignitify run:get ${runId}'.`, HINT_BUILD: "Ctrl+C stops waiting, not the build", HINT_RUN: "Ctrl+C stops waiting, not the run", INTERRUPTED_BUILD: (deploymentId, started) => `Stopped waiting. The build ${started ? "keeps running" : "is queued"} on the server \u2014 nothing was cancelled.
|
|
1365
|
+
and lands in your shell history.`, NOTIFY_URL_NEEDS_SECRET: "--url needs --secret-stdin: the server refuses a notify target with no signing secret.", NOTIFY_SECRET_EMPTY: "--secret-stdin read an empty value from stdin.", NOTIFY_URL_WITH_CLEAR: "--url and --clear cannot be used together.", NOTIFY_SECRET_STDIN_VALUE: "--secret-stdin takes no value: pipe the secret on stdin.", HOOK_SECRET_SHOWN_ONCE: "\u26A0\uFE0F The secret below is shown ONCE and cannot be read back \u2014 hook:list never returns it. Store it now; if it is lost, delete the hook and create a new one.", HOOK_PAYLOAD_LIMIT: (limit) => `A webhook body over ${limit} is refused with 413 before the signature is checked.`, SECRET_DELETE_USAGE: "usage: ignitify secret:delete <NAME>", USAGE_EXPORT_USAGE: "usage: ignitify usage:export [--period YYYY-MM] (--json|--csv) (name exactly one format)", LATEST_DEPLOY_BUILDING: (task, deploymentId) => `the latest deploy of ${task} is still building (${deploymentId}). Wait for it ('ignitify deployment:get ${deploymentId}'), or pass --deployment <id> to run an older one.`, LATEST_DEPLOY_FAILED: (task, reason) => `the latest deploy of ${task} failed: ${reason ?? "no reason recorded"}. Fix the task and run 'ignitify task:deploy ${task}' again, or pass --deployment <id> to run an older one.`, RUN_AT_WITH_WAIT: "--wait cannot be used with --at: a scheduled run has no run id until it fires. Drop --wait; follow it later with 'ignitify schedule:list' and 'ignitify run:list'.", SECRET_STORED: (name) => `secret ${name} stored`, SECRET_REMOVED: (name) => `secret ${name} removed` }, RUN_STATUS = { PENDING: "PENDING", PROVISIONING: "PROVISIONING", RUNNING: "RUNNING", RETRYING: "RETRYING", COMPLETED: "COMPLETED", FAILED: "FAILED", CANCELLED: "CANCELLED" }, ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set([RUN_STATUS.PENDING, RUN_STATUS.PROVISIONING, RUN_STATUS.RUNNING, RUN_STATUS.RETRYING]), DEPLOYMENT_STATUS = { BUILDING: "BUILDING", READY: "READY", FAILED: "FAILED", ARCHIVED: "ARCHIVED" }, POLL = { DEPLOY: { BASE_MS: 500, MAX_MS: 1e3, TIMEOUT_MS: 900 * 1e3 }, RUN: { BASE_MS: 500, MAX_MS: 3e3, TIMEOUT_MS: 1800 * 1e3 }, ERROR: { MIN_TRIES: 3, GRACE_MS: 6e4 } }, WAIT = { UPLOADING: (slug2, size) => `Uploading ${slug2}${size ? ` (${size})` : ""}`, UPLOAD_FAILED: "Upload failed", BUILDING: (deploymentId) => `Building image ${deploymentId}`, BUILT: "Image built", REUSED: "Image already built \u2014 reused", BUILD_FAILED: "Build failed", BUILD_FAILED_DETAIL: (deploymentId, reason) => `deployment ${deploymentId} failed to build \u2014 ${reason}`, BUILD_TIMEOUT: "Still building after 15 minutes \u2014 stopped waiting", BUILD_TIMEOUT_DETAIL: (deploymentId) => `deployment ${deploymentId} is still building after 15 minutes. The build has NOT been cancelled \u2014 check it with 'ignitify deployment:get ${deploymentId}'.`, RUN: (runId, status) => `Run ${runId} ${status}`, RUN_SUBMITTED: (runId) => `Run ${runId} submitted`, RUN_ENDED: (status) => `Run ${status}`, RUN_TIMEOUT: (status) => `Run is still ${status} after 30 minutes \u2014 stopped waiting`, RUN_TIMEOUT_DETAIL: (runId) => `The run has NOT been cancelled \u2014 check it with 'ignitify run:get ${runId}'.`, HINT_RETRYING: "lost contact with the server \u2014 retrying", LOST: "Lost contact with the server \u2014 stopped waiting", LOST_BUILD_DETAIL: (deploymentId, cause) => `stopped waiting for deployment ${deploymentId}: ${cause}. The build has NOT been cancelled \u2014 check it with 'ignitify deployment:get ${deploymentId}'.`, LOST_RUN_DETAIL: (runId, cause) => `stopped waiting for run ${runId}: ${cause}. The run has NOT been cancelled \u2014 check it with 'ignitify run:get ${runId}'.`, HINT_BUILD: "Ctrl+C stops waiting, not the build", HINT_RUN: "Ctrl+C stops waiting, not the run", INTERRUPTED_BUILD: (deploymentId, started) => `Stopped waiting. The build ${started ? "keeps running" : "is queued"} on the server \u2014 nothing was cancelled.
|
|
1246
1366
|
Check it with: ignitify deployment:get ${deploymentId}`, INTERRUPTED_RUN: (runId) => `Stopped waiting. The run keeps going on the server \u2014 nothing was cancelled.
|
|
1247
1367
|
Check it with: ignitify run:get ${runId}` };
|
|
1248
1368
|
} });
|
|
1249
1369
|
var ANSI, GLYPHS, LAYOUT, LABELS, EMPTY_LISTS, DISPLAY_CAPS, TITLES, PER_BRAIN_MARKER, PER_BRAIN_FOOTNOTE, POLICY_UNIT_NOTES, HIDDEN_FIELDS, RESULT_MESSAGES, RUN_CANCEL_OUTCOME, init_constants2 = __esm({ "src/output/constants.ts"() {
|
|
1250
1370
|
"use strict";
|
|
1251
1371
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1252
|
-
ANSI = { reset: "\x1B[0m", bold: "\x1B[1m", dim: "\x1B[2m", underline: "\x1B[4m", red: "\x1B[31m", green: "\x1B[32m", yellow: "\x1B[33m", cyan: "\x1B[36m", clearLine: "\r\x1B[2K", hideCursor: "\x1B[?25l", showCursor: "\x1B[?25h" }, GLYPHS = { unicode: { ok: "\u2713", err: "\u2717", warn: "\u26A0", bullet: "\u2022", ellipsis: "\u2026", dash: "\u2014", rule: "\u2500", box: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u2500", v: "\u2502" }, frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"] }, ascii: { ok: "OK", err: "x", warn: "!", bullet: "*", ellipsis: "...", dash: "-", rule: "-", box: { tl: "+", tr: "+", bl: "+", br: "+", h: "-", v: "|" }, frames: ["-", "\\", "|", "/"] } }, LAYOUT = { MAX_WIDTH: 80, INDENT: " ", GAP: " ", MIN_COLUMN: 8, SPINNER_MS: 100, NO_UNICODE_TERMS: ["dumb", "linux"] }, LABELS = { NEXT_STEP: "Next Step:", SYSTEM_RESOURCES: "System Resources:", RESULT: "Result:", MORE_LINES: (n) => `\u2026 ${n} more lines (run:get --full shows all)`, BUILD_LOG: "Build log:", PLATFORM_BUILT_IMAGE: "Image: built and stored by the platform; there is nothing for you to download.", EARLIER_LINES: (n) => `\u2026 ${n} earlier lines (deployment:get <id> shows all)`, NO_RESULTS: "(No results)", EMPTY: "(empty)" }, EMPTY_LISTS = { ANY: { message: "(No results)" }, TASKS: { message: "No tasks yet.", next: "Create one with: ignitify task:create <task-id>" }, DEPLOYMENTS: { message: "No deployments yet.", next: "Build one with: ignitify task:deploy <task-id>" }, RUNS: { message: "No runs yet.", next: "Start one with: ignitify task:run <task-id>" }, VMS: { message: "No live VMs." }, SCHEDULES: { message: "No scheduled runs.", next: "Schedule one with: ignitify task:run <task-id> --at <iso>" }, HOOKS: { message: "No webhooks yet.", next: "Create one with: ignitify hook:create <deployment-id> --task-name <name>" } }, DISPLAY_CAPS = { RESULT_MAX_LINES: 40, BUILD_LOG_TAIL_LINES: 30, ERROR_MAX_CHARS: 2e3 }, TITLES = { TENANT_PROFILE: "Tenant Profile", TASK_REGISTERED: "Task Registered", SOURCE_PACK: "Source Upload (nothing built, nothing sent)", DEPLOYMENT_CREATED: "Deployment Created", RUN_SUBMITTED: "Run Submitted", RUN_DETAILS: "Run Details", DEPLOYMENT_DETAILS: "Deployment Details", VM_DETAILS: "VM Details", USAGE: "Usage & Limits", UNIT_WEIGHTS: "Units per run (by preset)", ENTITLEMENTS: "Entitlements (tier policy)", ENFORCED: "Enforced Limits (what this server applies)" }, PER_BRAIN_MARKER = "(per server)", PER_BRAIN_FOOTNOTE = " (per server) \u2014 each server applies this limit on its own, so the limit across all servers is at least this.", POLICY_UNIT_NOTES = { max_compute_seconds_month: "(run seconds, not the VM time `usage` shows as compute)" }, HIDDEN_FIELDS = { SCALAR: ["payload", "result", "slug"], LIST: ["payload", "result", "execution"] }, RESULT_MESSAGES = { TASK_GET_OFFLINE: (reason) => `Note: ${reason.replace(/\.$/, "")}. The server sections show UNKNOWN.`, TASK_CREATED_LOCAL: (lang, taskId, dir) => `Created ${lang} task ${taskId} at ${dir} (local only \u2014 not registered)`, HOOK_CREATED_TITLE: "Webhook Created", HOOK_SECRET_KEY: "secret (shown ONCE)", HOOK_DELETED: (id) => `Webhook deleted: ${id}`, NOTIFY_SET: (deploymentId, url) => `Notify URL for ${deploymentId} set to ${url}`, NOTIFY_CLEARED: (deploymentId) => `Notify URL for ${deploymentId} cleared`, SCHEDULE_CANCELLED: (id) => `Schedule cancelled: ${id}`, NO_SECRETS: "(no secrets)", NO_SECRETS_NEXT: "Store one with: ignitify secret:set <NAME> --stdin" }, RUN_CANCEL_OUTCOME = { ALREADY_TERMINAL: "already-terminal", DRAINING: "draining", CANCELLED: "cancelled" };
|
|
1372
|
+
ANSI = { reset: "\x1B[0m", bold: "\x1B[1m", dim: "\x1B[2m", underline: "\x1B[4m", red: "\x1B[31m", green: "\x1B[32m", yellow: "\x1B[33m", cyan: "\x1B[36m", clearLine: "\r\x1B[2K", hideCursor: "\x1B[?25l", showCursor: "\x1B[?25h" }, GLYPHS = { unicode: { ok: "\u2713", err: "\u2717", warn: "\u26A0", bullet: "\u2022", ellipsis: "\u2026", dash: "\u2014", rule: "\u2500", box: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u2500", v: "\u2502" }, frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"] }, ascii: { ok: "OK", err: "x", warn: "!", bullet: "*", ellipsis: "...", dash: "-", rule: "-", box: { tl: "+", tr: "+", bl: "+", br: "+", h: "-", v: "|" }, frames: ["-", "\\", "|", "/"] } }, LAYOUT = { MAX_WIDTH: 80, INDENT: " ", GAP: " ", MIN_COLUMN: 8, SPINNER_MS: 100, NO_UNICODE_TERMS: ["dumb", "linux"] }, LABELS = { NEXT_STEP: "Next Step:", SYSTEM_RESOURCES: "System Resources:", RESULT: "Result:", MORE_LINES: (n) => `\u2026 ${n} more lines (run:get --full shows all)`, BUILD_LOG: "Build log:", PLATFORM_BUILT_IMAGE: "Image: built and stored by the platform; there is nothing for you to download.", EARLIER_LINES: (n) => `\u2026 ${n} earlier lines (deployment:get <id> shows all)`, NO_RESULTS: "(No results)", EMPTY: "(empty)" }, EMPTY_LISTS = { ANY: { message: "(No results)" }, TASKS: { message: "No tasks yet.", next: "Create one with: ignitify task:create <task-id>" }, DEPLOYMENTS: { message: "No deployments yet.", next: "Build one with: ignitify task:deploy <task-id>" }, RUNS: { message: "No runs yet.", next: "Start one with: ignitify task:run <task-id>" }, VMS: { message: "No live VMs." }, SCHEDULES: { message: "No scheduled runs.", next: "Schedule one with: ignitify task:run <task-id> --at <iso>" }, HOOKS: { message: "No webhooks yet.", next: "Create one with: ignitify hook:create <deployment-id> --task-name <name>" } }, DISPLAY_CAPS = { RESULT_MAX_LINES: 40, BUILD_LOG_TAIL_LINES: 30, ERROR_MAX_CHARS: 2e3 }, TITLES = { TENANT_PROFILE: "Tenant Profile", TASK_REGISTERED: "Task Registered", SOURCE_PACK: "Source Upload (nothing built, nothing sent)", DEPLOYMENT_CREATED: "Deployment Created", RUN_SUBMITTED: "Run Submitted", RUN_DETAILS: "Run Details", DEPLOYMENT_DETAILS: "Deployment Details", VM_DETAILS: "VM Details", USAGE: "Usage & Limits", UNIT_WEIGHTS: "Units per run (by preset)", ENTITLEMENTS: "Entitlements (tier policy)", ENFORCED: "Enforced Limits (what this server applies)" }, PER_BRAIN_MARKER = "(per server)", PER_BRAIN_FOOTNOTE = " (per server) \u2014 each server applies this limit on its own, so the limit across all servers is at least this.", POLICY_UNIT_NOTES = { max_compute_seconds_month: "(run seconds, not the VM time `usage` shows as compute)" }, HIDDEN_FIELDS = { SCALAR: ["payload", "result", "slug"], LIST: ["payload", "result", "execution"] }, RESULT_MESSAGES = { TASK_GET_OFFLINE: (reason) => `Note: ${reason.replace(/\.$/, "")}. The server sections show UNKNOWN.`, TASK_CREATED_LOCAL: (lang, taskId, dir) => `Created ${lang} task ${taskId} at ${dir} (local only \u2014 not registered)`, HOOK_CREATED_TITLE: "Webhook Created", HOOK_SECRET_KEY: "secret (shown ONCE)", HOOK_DELETED: (id) => `Webhook deleted: ${id}`, NOTIFY_SET: (deploymentId, url) => `Notify URL for ${deploymentId} set to ${url}`, NOTIFY_CLEARED: (deploymentId) => `Notify URL for ${deploymentId} cleared`, SCHEDULE_CANCELLED: (id) => `Schedule cancelled: ${id}`, SCHEDULE_CANCEL_PREVIEW: (id) => `Will cancel schedule ${id} \u2014 it will never fire.`, SCHEDULE_NOT_CANCELLED: (id) => `Schedule ${id} was NOT cancelled: not found, already fired, or currently firing.`, HOOK_DELETE_PREVIEW: (id) => `Will delete webhook ${id}. A sender that posts to it is refused from then on.`, SECRET_DELETE_PREVIEW: (name) => `Will delete secret ${name}. Its value cannot be read back.`, DEPLOYMENT_DELETE_PREVIEW: (id) => `Will soft-delete deployment ${id} and all its runs (cascade).`, RUN_DELETE_PREVIEW: (id) => `Will soft-delete run ${id}.`, RUN_ALREADY_OVER: (id, status) => `Run ${id} is already ${status} \u2014 nothing to cancel.`, RUN_CANCEL_PREVIEW: (id, force) => force ? `Will cancel run ${id} immediately (force: destroys the VM even if it is pinned).` : `Will ask run ${id} to stop gracefully; it is killed if it does not finish in time.`, RUN_STOPPING: (id, grace, was) => `Run ${id} is stopping${grace}${was} \u2014 still RUNNING until it finishes or the grace expires.`, RUN_CANCELLED: (id, was) => `Run cancelled: ${id}${was}`, LOG_TRUNCATED: (lines) => `truncated \u2014 ${lines} line(s) shown; the log was cut at the size cap.`, NO_SECRETS: "(no secrets)", NO_SECRETS_NEXT: "Store one with: ignitify secret:set <NAME> --stdin" }, RUN_CANCEL_OUTCOME = { ALREADY_TERMINAL: "already-terminal", DRAINING: "draining", CANCELLED: "cancelled" };
|
|
1253
1373
|
} });
|
|
1254
1374
|
function makeStyle(o) {
|
|
1255
1375
|
let p = (...codes) => paint(o.colour, ...codes), columns = Math.max(o.width, 1);
|
|
@@ -1509,7 +1629,7 @@ var init_execution = __esm({ "../../packages/execution/index.ts"() {
|
|
|
1509
1629
|
init_egress_match();
|
|
1510
1630
|
init_ingress_hostname();
|
|
1511
1631
|
} });
|
|
1512
|
-
var sectionHeader, layout, filterScalars, filterDisplayKeys,
|
|
1632
|
+
var sectionHeader, layout, filterScalars, filterDisplayKeys, BYTE_UNITS2, formatBytes, quotaLine, storeLine, renderWhoami, hasUnits, renderUnitWeights, showEnforced, renderEnforcedBlock, renderPolicyValue, renderPolicyBlock, renderUsageBlocks, renderUsage, renderTaskCreate, renderPack, renderDeploy, renderRunSubmit, renderRunNotices, isStorageClamped, renderCapacity, capacityBlock, renderRunGet, renderList, imageSize, renderDeploymentList, packagesLine, renderDeploymentGet, formatDuration, renderVmList, pinLines, renderVmRows, renderVmGet, nextStepBanner, init_formatters = __esm({ "src/output/formatters.ts"() {
|
|
1513
1633
|
"use strict";
|
|
1514
1634
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1515
1635
|
init_constants();
|
|
@@ -1523,17 +1643,13 @@ var sectionHeader, layout, filterScalars, filterDisplayKeys, BYTE_UNITS, formatB
|
|
|
1523
1643
|
${heading(st, title, success)}
|
|
1524
1644
|
`, layout = (header, content, footer = "") => `${header}${content}${footer ? `
|
|
1525
1645
|
` + footer : `
|
|
1526
|
-
`}`, filterScalars = (data) => {
|
|
1527
|
-
let filtered = {};
|
|
1528
|
-
for (let [k, v] of Object.entries(data)) typeof v != "object" && !HIDDEN_FIELDS.SCALAR.includes(k) && (filtered[k] = v);
|
|
1529
|
-
return filtered;
|
|
1530
|
-
}, filterDisplayKeys = (data) => {
|
|
1646
|
+
`}`, filterScalars = (data) => Object.fromEntries(Object.entries(data).filter(([k, v]) => typeof v != "object" && !HIDDEN_FIELDS.SCALAR.includes(k))), filterDisplayKeys = (data) => {
|
|
1531
1647
|
let { slug: _slug, ...rest } = data;
|
|
1532
1648
|
return rest;
|
|
1533
|
-
},
|
|
1534
|
-
if (!Number.isFinite(
|
|
1535
|
-
let exp = Math.min(Math.floor(Math.log2(
|
|
1536
|
-
return `${exp === 0 ? value : value.toFixed(1)} ${
|
|
1649
|
+
}, BYTE_UNITS2 = ["B", "KiB", "MiB", "GiB", "TiB"], formatBytes = (bytes) => {
|
|
1650
|
+
if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
1651
|
+
let exp = Math.min(Math.floor(Math.log2(bytes) / 10), BYTE_UNITS2.length - 1), value = bytes / 2 ** (10 * exp);
|
|
1652
|
+
return `${exp === 0 ? value : value.toFixed(1)} ${BYTE_UNITS2[exp]}`;
|
|
1537
1653
|
}, quotaLine = (used, max) => `${used} / ${max ?? "unlimited"}`, storeLine = (used, max) => max === void 0 ? formatBytes(used) : `${formatBytes(used)} / ${max === null ? "unlimited" : formatBytes(max)}`, renderWhoami = (data, st = PLAIN) => {
|
|
1538
1654
|
if (!data) return "";
|
|
1539
1655
|
let { limits, usage, tier, policy, bound_by, status_reason, policy_scope, enforced, unit_weights, capacity, ...identity } = data, identityRows = { ...identity };
|
|
@@ -1541,20 +1657,16 @@ ${heading(st, title, success)}
|
|
|
1541
1657
|
let out2 = layout(sectionHeader(st, TITLES.TENANT_PROFILE), renderFields(st, filterDisplayKeys(identityRows)));
|
|
1542
1658
|
return (limits || usage) && (out2 += renderUsageBlocks(st, limits, usage)), out2 += capacityBlock(st, capacity), hasUnits(limits) && unit_weights && (out2 += renderUnitWeights(st, unit_weights)), policy && (out2 += renderPolicyBlock(st, policy, policy_scope?.per_brain ?? [])), enforced && enforced.length > 0 && (out2 += renderEnforcedBlock(st, enforced)), out2;
|
|
1543
1659
|
}, hasUnits = (limits) => typeof limits?.max_units == "number", renderUnitWeights = (st, weights) => layout(sectionHeader(st, TITLES.UNIT_WEIGHTS), renderFields(st, Object.fromEntries(Object.entries(weights).map(([p, w]) => [p, String(w)])))), showEnforced = (v) => v === null ? "\u2014" : String(v), renderEnforcedBlock = (st, rows) => {
|
|
1544
|
-
let
|
|
1545
|
-
for (let r of rows) {
|
|
1660
|
+
let enforcedText = (r) => {
|
|
1546
1661
|
let value = showEnforced(r.enforced);
|
|
1547
|
-
|
|
1548
|
-
}
|
|
1662
|
+
return r.winner === "host-clamp" ? `${value} (platform cap; tier asked ${showEnforced(r.tier)})` : r.winner === "host-default" ? `${value} (platform default)` : value;
|
|
1663
|
+
}, out2 = Object.fromEntries(rows.map((r) => [r.column, enforcedText(r)]));
|
|
1549
1664
|
return layout(sectionHeader(st, TITLES.ENFORCED), renderFields(st, out2));
|
|
1550
1665
|
}, renderPolicyValue = (key, v) => key === "allowed_presets" ? Array.isArray(v) ? v.join(", ") : "all" : v == null ? "unlimited" : typeof v == "boolean" ? v ? "yes" : "no" : String(v), renderPolicyBlock = (st, policy, perBrain = []) => {
|
|
1551
|
-
let scoped = new Set(perBrain),
|
|
1552
|
-
for (let [k, v] of Object.entries(policy)) {
|
|
1553
|
-
if (k === "tier_id" || k === "tier_name" || k === "tier_version") continue;
|
|
1666
|
+
let scoped = new Set(perBrain), policyText = (k, v) => {
|
|
1554
1667
|
let value = POLICY_UNIT_NOTES[k] ? `${renderPolicyValue(k, v)} ${POLICY_UNIT_NOTES[k]}` : renderPolicyValue(k, v);
|
|
1555
|
-
|
|
1556
|
-
}
|
|
1557
|
-
let block = layout(sectionHeader(st, TITLES.ENTITLEMENTS), renderFields(st, rows));
|
|
1668
|
+
return scoped.has(k) ? `${value} ${PER_BRAIN_MARKER}` : value;
|
|
1669
|
+
}, rows = Object.fromEntries(Object.entries(policy).filter(([k]) => k !== "tier_id" && k !== "tier_name" && k !== "tier_version").map(([k, v]) => [k, policyText(k, v)])), block = layout(sectionHeader(st, TITLES.ENTITLEMENTS), renderFields(st, rows));
|
|
1558
1670
|
return scoped.size === 0 ? block : `${block}
|
|
1559
1671
|
${st.dim(PER_BRAIN_FOOTNOTE)}
|
|
1560
1672
|
`;
|
|
@@ -1581,12 +1693,13 @@ ${bullets(st, [LABELS.PLATFORM_BUILT_IMAGE])}
|
|
|
1581
1693
|
return layout(sectionHeader(st, TITLES.RUN_SUBMITTED, true), renderFields(st, filterDisplayKeys(rest))) + (noticeText ? `
|
|
1582
1694
|
${st.yellow(noticeText)}
|
|
1583
1695
|
` : "") + capacityBlock(st, capacity);
|
|
1584
|
-
}, renderRunNotices = (notices) => Array.isArray(notices) ? notices.map((n) =>
|
|
1585
|
-
`) : "", renderCapacity = (capacity, st = PLAIN) => {
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1696
|
+
}, renderRunNotices = (notices) => Array.isArray(notices) ? notices.filter(isStorageClamped).map((n) => STORAGE_MESSAGES.clamped(n.requested, n.preset, n.effective)).join(`
|
|
1697
|
+
`) : "", isStorageClamped = (n) => isRecord(n) && n.code === "storage-clamped" && typeof n.preset == "string" && typeof n.requested == "number" && typeof n.effective == "number", renderCapacity = (capacity, st = PLAIN) => {
|
|
1698
|
+
if (!isRecord(capacity) || !Array.isArray(capacity.limits)) return "";
|
|
1699
|
+
let texts = capacity.limits.flatMap((l) => isRecord(l) && typeof l.text == "string" ? [l.text] : []);
|
|
1700
|
+
if (texts.length === 0) return "";
|
|
1701
|
+
let { period_start: periodStart, resets_at: resetsAt, usage_command: usageCommand } = capacity, since = typeof periodStart == "string" ? `Since ${periodStart} \xB7 ` : "", resets = typeof resetsAt == "string" ? resetsAt : `at ${RESETS_AT_NEXT_RENEWAL}`, details = typeof usageCommand == "string" ? usageCommand : USAGE_DETAIL_COMMAND;
|
|
1702
|
+
return [...texts.map((t) => `Monthly ${t}`), st.dim(`${since}Resets ${resets} \xB7 details: ${details}`)].join(`
|
|
1590
1703
|
`);
|
|
1591
1704
|
}, capacityBlock = (st, capacity) => {
|
|
1592
1705
|
let text = renderCapacity(capacity, st);
|
|
@@ -1608,7 +1721,7 @@ ${emptyState(st, empty.message, empty.next)}
|
|
|
1608
1721
|
return `
|
|
1609
1722
|
${renderTable(st, columns, rows)}
|
|
1610
1723
|
`;
|
|
1611
|
-
}, imageSize = (
|
|
1724
|
+
}, imageSize = (bytes, present) => present === false ? "(missing)" : bytes === null ? "unknown" : formatBytes(Number(bytes)), renderDeploymentList = (data, st = PLAIN) => {
|
|
1612
1725
|
let rows = data.deployments ?? [], total = data.tenant_total_bytes, limit = data.tenant_limit_bytes, display = rows.map(({ image_bytes, image_present, ...rest }) => ({ ...rest, ...image_bytes !== void 0 ? { size: imageSize(image_bytes, image_present) } : {} })), out2 = renderList(display, st, EMPTY_LISTS.DEPLOYMENTS);
|
|
1613
1726
|
if (total !== void 0 && rows.length > 0) {
|
|
1614
1727
|
let of = typeof limit == "number" ? ` of ${formatBytes(limit)}` : "";
|
|
@@ -1617,10 +1730,10 @@ ${renderTable(st, columns, rows)}
|
|
|
1617
1730
|
}
|
|
1618
1731
|
return out2;
|
|
1619
1732
|
}, packagesLine = (v) => {
|
|
1620
|
-
if (
|
|
1733
|
+
if (!isRecord(v)) return;
|
|
1621
1734
|
let { names, drive } = v;
|
|
1622
1735
|
if (!Array.isArray(names) || names.length === 0) return;
|
|
1623
|
-
let
|
|
1736
|
+
let size = isRecord(drive) && typeof drive.bytes == "number" ? `drive ${formatBytes(drive.bytes)} (snapshot ${String(drive.snapshot)})` : "drive not built yet";
|
|
1624
1737
|
return `${names.join(", ")} \xB7 ${size}`;
|
|
1625
1738
|
}, renderDeploymentGet = (data, st = PLAIN) => {
|
|
1626
1739
|
if (!data) return "";
|
|
@@ -1647,10 +1760,11 @@ ${st.dim("Command template for next step:")} ${st.bold(LABELS.NEXT_STEP)} ${temp
|
|
|
1647
1760
|
${st.dim("Full command:")} ${st.cyan(actual)}
|
|
1648
1761
|
`;
|
|
1649
1762
|
} });
|
|
1650
|
-
var str, slug, WORKFLOW,
|
|
1763
|
+
var str, slug, WORKFLOW, resolveNextStep, init_next_step = __esm({ "src/output/next-step.ts"() {
|
|
1651
1764
|
"use strict";
|
|
1652
1765
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1653
|
-
|
|
1766
|
+
init_tenant();
|
|
1767
|
+
str = (v) => typeof v == "string" && v !== "" ? v : void 0, slug = (data) => str(data.slug) ?? str(data.task_id) ?? "<task_id>", WORKFLOW = { "task:create": { template: "ignitify task:deploy <task_id>", resolve: (d) => `ignitify task:deploy ${slug(d)}` }, "task:pack": { template: "ignitify task:deploy <task_id>", resolve: (d) => `ignitify task:deploy ${slug(d)}` }, "task:deploy": { template: "ignitify task:run <task_id>", resolve: (d) => `ignitify task:run ${slug(d)}` }, "task:run": { template: "ignitify run:get <run_id>", resolve: (d) => `ignitify run:get ${str(d.resource_id) ?? str(d.run_id) ?? "<run_id>"}` } }, resolveNextStep = (command, data) => {
|
|
1654
1768
|
let step = WORKFLOW[command];
|
|
1655
1769
|
return step ? { template: step.template, actual: step.resolve(isRecord(data) ? data : {}) } : null;
|
|
1656
1770
|
};
|
|
@@ -1696,8 +1810,8 @@ var RENDERERS, jsonMode, sayStream, outStyle, errStyle, writeRaw, out, sayOk, wa
|
|
|
1696
1810
|
RENDERERS = { whoami: renderWhoami, quota: renderUsage, "task:create": renderTaskCreate, "task:pack": renderPack, "task:deploy": renderDeploy, "task:run": renderRunSubmit, "run:get": renderRunGet, "task:list": (d, st) => renderList(d, st, EMPTY_LISTS.TASKS), "deployment:list": renderDeploymentList, "deployment:get": renderDeploymentGet, "run:list": (d, st) => renderList(d, st, EMPTY_LISTS.RUNS), "vm:list": renderVmList, "vm:get": renderVmGet, "schedule:list": (d, st) => renderList(d, st, EMPTY_LISTS.SCHEDULES) }, jsonMode = false;
|
|
1697
1811
|
sayStream = () => jsonMode ? process.stderr : process.stdout;
|
|
1698
1812
|
outStyle = () => streamStyle(process.stdout), errStyle = () => streamStyle(process.stderr);
|
|
1699
|
-
writeRaw = (
|
|
1700
|
-
process.stdout.write(
|
|
1813
|
+
writeRaw = (bytes) => {
|
|
1814
|
+
process.stdout.write(bytes);
|
|
1701
1815
|
}, out = (text) => console.log(text), sayOk = (text) => say(successLine(screenStyle(), text));
|
|
1702
1816
|
warn = (text) => console.error(noteLine(errStyle(), text)), tell = (text) => console.error(text), printWarnings = (ws) => ws.forEach((w) => console.error(warnMark(errStyle(), w))), printErrors = (es) => es.forEach((e) => console.error(errorMark(errStyle(), e)));
|
|
1703
1817
|
CliOutputManager = { render(command, data) {
|
|
@@ -1936,66 +2050,38 @@ var FATE_TEXT, printDeletionPlan, init_deletion_plan = __esm({ "src/output/delet
|
|
|
1936
2050
|
FATE_TEXT = { "cancelled-via-vm-teardown": "its VM is destroyed and the run is recorded as CANCELLED", "deleted-while-pending": "never dispatched \u2014 deleted before it could start", "unknown-status": "unrecognised status; this CLI cannot say what happens to it" };
|
|
1937
2051
|
printDeletionPlan = (plan) => say(renderDeletionPlan(screenStyle(), plan));
|
|
1938
2052
|
} });
|
|
1939
|
-
function explainRunRefusal(
|
|
1940
|
-
let body =
|
|
2053
|
+
function explainRunRefusal(e) {
|
|
2054
|
+
let body = httpErrorJson(e)?.body, message = errText(e), pinned = body?.reason === "bidirectional-busy" ? body.pinned === true : message.includes("bidirectional deployment runs one VM at a time") ? message.includes("PINNED") : null;
|
|
1941
2055
|
if (pinned === null) return null;
|
|
1942
2056
|
let lines = ["\u2717 Run refused \u2014 this bidirectional deployment already has a live VM.", "", " Concurrent VMs for bidirectional-network tasks are not supported", " (one VM at a time)."];
|
|
1943
2057
|
if (pinned) {
|
|
1944
|
-
let
|
|
2058
|
+
let vmField = body?.vm_id, vmId = typeof vmField == "string" && vmField !== "" ? vmField : "<vm-id>";
|
|
1945
2059
|
lines.push("", " Why it was not queued, even if you asked for --on-busy=queue:", " A PINNED VM has no idle timeout \u2014 it stays up until it is explicitly", " removed, so queueing behind it could wait forever.", "", " What you can do now:", " \u2022 Reuse the pinned VM \u2014 submit the run against it instead", ' \u2022 Use network.type "egress" if this task needs no inbound traffic', ` \u2022 Remove it yourself: ignitify vm:delete ${vmId} --force`);
|
|
1946
2060
|
} else lines.push("", " Retry when the live VM finishes, or omit --on-busy=reject to queue instead.");
|
|
1947
2061
|
return lines.join(`
|
|
1948
2062
|
`);
|
|
1949
2063
|
}
|
|
1950
|
-
function explainLimitRefusal(
|
|
1951
|
-
let
|
|
1952
|
-
if (!
|
|
1953
|
-
let
|
|
1954
|
-
return typeof
|
|
2064
|
+
function explainLimitRefusal(e) {
|
|
2065
|
+
let refused2 = httpErrorJson(e);
|
|
2066
|
+
if (!refused2 || refused2.status !== 429) return null;
|
|
2067
|
+
let { summary, reason } = refused2.body;
|
|
2068
|
+
return typeof summary != "string" || summary === "" ? null : [`\u2717 Run refused \u2014 a monthly limit is reached (${typeof reason == "string" ? reason : "429"}).`, ` ${summary}`].join(`
|
|
1955
2069
|
`);
|
|
1956
2070
|
}
|
|
1957
|
-
function apiErrorBody(message) {
|
|
1958
|
-
let m = /^API (\d{3}): (\{[\s\S]*\})$/.exec(message.trim());
|
|
1959
|
-
if (!m) return null;
|
|
1960
|
-
try {
|
|
1961
|
-
let body = JSON.parse(m[2]);
|
|
1962
|
-
return typeof body != "object" || body === null || Array.isArray(body) ? null : { status: Number(m[1]), body };
|
|
1963
|
-
} catch {
|
|
1964
|
-
return null;
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
2071
|
var isPayloadTooLarge, init_run_refusal = __esm({ "src/output/run-refusal.ts"() {
|
|
1968
2072
|
"use strict";
|
|
1969
2073
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
1970
|
-
|
|
2074
|
+
init_http_client();
|
|
2075
|
+
init_tenant();
|
|
2076
|
+
isPayloadTooLarge = (e) => e instanceof HttpError && e.status === 413;
|
|
1971
2077
|
} });
|
|
1972
|
-
function quantity(n, unit) {
|
|
1973
|
-
return unit === "bytes" ? bytes(n) : unit === "ms" ? duration(n) : unit === "byte-hours" ? byteHours(n) : `${n}`;
|
|
1974
|
-
}
|
|
1975
|
-
function byteHours(n) {
|
|
1976
|
-
let u = ["B\xB7h", "KiB\xB7h", "MiB\xB7h", "GiB\xB7h", "TiB\xB7h", "PiB\xB7h"], i = 0, v = n;
|
|
1977
|
-
for (; v >= 1024 && i < u.length - 1; ) v /= 1024, i += 1;
|
|
1978
|
-
return i === 0 ? `${n} B\xB7h` : `${v.toFixed(1)} ${u[i]}`;
|
|
1979
|
-
}
|
|
1980
|
-
function bytes(n) {
|
|
1981
|
-
let u = ["B", "KB", "MB", "GB", "TB"], i = 0, v = n;
|
|
1982
|
-
for (; v >= 1024 && i < u.length - 1; ) v /= 1024, i += 1;
|
|
1983
|
-
return i === 0 ? `${n} B` : `${v.toFixed(1)} ${u[i]}`;
|
|
1984
|
-
}
|
|
1985
|
-
function duration(ms) {
|
|
1986
|
-
if (ms < 1e3) return `${ms} ms`;
|
|
1987
|
-
let s = Math.round(ms / 1e3);
|
|
1988
|
-
if (s < 60) return `${s} s`;
|
|
1989
|
-
let m = Math.floor(s / 60);
|
|
1990
|
-
return m < 60 ? `${m}m ${s % 60}s` : `${Math.floor(m / 60)}h ${m % 60}m`;
|
|
1991
|
-
}
|
|
1992
2078
|
function renderUsageReport(st, r, opts = { lines: false }) {
|
|
1993
2079
|
let I2 = LAYOUT.INDENT, out2 = [`${heading(st, `usage for ${r.period}`)}${r.filtered ? st.dim(" (filtered)") : ""}`, ""];
|
|
1994
|
-
return out2.push(renderTable(st, [{ header: "AXIS", keep: true }, { header: "QUANTITY", keep: true }, { header: "LINES", keep: true }, { header: "RECONCILIATION" }], r.totals.map((t) => [t.axis,
|
|
2080
|
+
return out2.push(renderTable(st, [{ header: "AXIS", keep: true }, { header: "QUANTITY", keep: true }, { header: "LINES", keep: true }, { header: "RECONCILIATION" }], r.totals.map((t) => [t.axis, formatUsageQuantity(t.quantity, t.unit), t.lines, reconcileNote(t)]), { indent: I2 })), r.totals.some((t) => t.axis === "disk" || t.axis === "scratch") && (out2.push("", st.dim(`${I2}note: \`disk\` = your build images \xD7 the hours each was held this month (still-held images included);`)), out2.push(st.dim(`${I2} \`scratch\` = each VM's scratch drive \xD7 the hours the VM ran. 1 GiB\xB7h = 1 GiB for one hour.`))), r.totals.some((t) => t.axis === "compute") && out2.push("", st.dim(`${I2}note: \`compute\` = VM time (boot to teardown). Your monthly compute limit counts run seconds instead.`)), out2.push("", `${I2}runs started ${r.counters.runs_started} deployments created ${r.counters.deployments_created} API requests ${r.counters.api_requests_approx} (approx)`), opts.lines && out2.push("", renderTable(st, [{ header: "AXIS", keep: true }, { header: "QUANTITY", keep: true }, { header: "VM / RUN", keep: true }, { header: "DETAIL" }], r.lines.map((l) => [l.axis, formatUsageQuantity(l.quantity, l.unit), l.run_id ?? l.vm_id ?? l.deployment_id ?? st.glyphs.dash, l.detail ?? ""]), { indent: I2 })), out2.join(`
|
|
1995
2081
|
`);
|
|
1996
2082
|
}
|
|
1997
2083
|
function reconcileNote(t) {
|
|
1998
|
-
return !t.reconcilable || t.counter === null || t.drift === null ? t.reconciliation === "none" ? "\u2014" : "not checked (filtered)" : t.drift === 0 ? "agrees with the meter" : t.reconciliation === "inequality" && t.drift > 0 ? `${t.drift} still in flight` : `meter differs by ${
|
|
2084
|
+
return !t.reconcilable || t.counter === null || t.drift === null ? t.reconciliation === "none" ? "\u2014" : "not checked (filtered)" : t.drift === 0 ? "agrees with the meter" : t.reconciliation === "inequality" && t.drift > 0 ? `${t.drift} still in flight` : `meter differs by ${formatUsageQuantity(Math.abs(t.drift), t.unit)}`;
|
|
1999
2085
|
}
|
|
2000
2086
|
function toCsv(r) {
|
|
2001
2087
|
let head = "axis,vm_id,run_id,deployment_id,window_start,window_end,quantity,unit,detail", rows = r.lines.map((l) => csvRow([l.axis, l.vm_id ?? "", l.run_id ?? "", l.deployment_id ?? "", l.window_start ?? "", l.window_end ?? "", String(l.quantity), l.unit, l.detail ?? ""]));
|
|
@@ -2034,50 +2120,27 @@ function planAdvice(config) {
|
|
|
2034
2120
|
let checked = checkSystemPackages(declared);
|
|
2035
2121
|
return checked.ok ? { kind: "call", request: { names: checked.names, runtime: config.runtime } } : { kind: "skip", reason: checked.reason === "bad-names" ? ADVICE.BAD_NAMES(checked.bad) : ADVICE.TOO_MANY(checked.count, 64) };
|
|
2036
2122
|
}
|
|
2037
|
-
function
|
|
2038
|
-
|
|
2039
|
-
let v = JSON.parse(body);
|
|
2040
|
-
return typeof v == "object" && v !== null ? v : {};
|
|
2041
|
-
} catch {
|
|
2042
|
-
return {};
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
function adviceFailure(status, body) {
|
|
2046
|
-
let parsed = jsonBody(body);
|
|
2123
|
+
function adviceFailure(e) {
|
|
2124
|
+
let { status, body } = e, parsed = httpErrorJson(e)?.body ?? {};
|
|
2047
2125
|
return status === 429 && typeof parsed.retry_after_s == "number" ? { kind: "rate-limited", retryAfterS: parsed.retry_after_s } : status === 503 && typeof parsed.reason == "string" ? { kind: "unavailable", reason: parsed.reason } : { kind: "error", status, message: body };
|
|
2048
2126
|
}
|
|
2049
2127
|
var init_package_advice3 = __esm({ "src/core/package-advice.ts"() {
|
|
2050
2128
|
"use strict";
|
|
2051
2129
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2130
|
+
init_http_client();
|
|
2052
2131
|
init_tenant();
|
|
2053
2132
|
init_constants();
|
|
2054
2133
|
} });
|
|
2055
2134
|
var version, init_package = __esm({ "package.json"() {
|
|
2056
|
-
version = "1.2.
|
|
2135
|
+
version = "1.2.2";
|
|
2057
2136
|
} });
|
|
2058
2137
|
var byCreatedAtDesc, init_sort = __esm({ "src/utils/sort.ts"() {
|
|
2059
2138
|
"use strict";
|
|
2060
2139
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2061
2140
|
byCreatedAtDesc = (rows) => [...rows].sort((a, b) => (b.created_at ?? "").localeCompare(a.created_at ?? ""));
|
|
2062
2141
|
} });
|
|
2063
|
-
|
|
2064
|
-
"
|
|
2065
|
-
init_define_IGNITIFY_CLIENT_FILES();
|
|
2066
|
-
normalizeContentHash = (hash) => hash.replace(/^sha256:/, "");
|
|
2067
|
-
} });
|
|
2068
|
-
function strOpt(args, key) {
|
|
2069
|
-
let bare = bareValueFlag(args, [key]);
|
|
2070
|
-
if (bare !== void 0) throw new Error(needsValueMessage(bare));
|
|
2071
|
-
let v = args.options[key];
|
|
2072
|
-
return typeof v == "string" ? v : void 0;
|
|
2073
|
-
}
|
|
2074
|
-
function flagParams(args, map2) {
|
|
2075
|
-
let params = {};
|
|
2076
|
-
for (let [flag, param] of Object.entries(map2)) {
|
|
2077
|
-
let v = strOpt(args, flag);
|
|
2078
|
-
v !== void 0 && (params[param] = v);
|
|
2079
|
-
}
|
|
2080
|
-
return params;
|
|
2142
|
+
function apiUrlOf(args) {
|
|
2143
|
+
return strOpt(args, "api") ?? DEFAULTS.API_URL;
|
|
2081
2144
|
}
|
|
2082
2145
|
function boolFlag(args, key) {
|
|
2083
2146
|
return args.options[key] === true;
|
|
@@ -2092,33 +2155,23 @@ function requireArg(args, label) {
|
|
|
2092
2155
|
var init_args2 = __esm({ "src/utils/args.ts"() {
|
|
2093
2156
|
"use strict";
|
|
2094
2157
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2095
|
-
init_http_client();
|
|
2096
2158
|
init_constants();
|
|
2097
2159
|
init_output();
|
|
2160
|
+
init_http_client();
|
|
2161
|
+
init_http_client();
|
|
2098
2162
|
} });
|
|
2099
|
-
function errorMessage(e) {
|
|
2100
|
-
return e instanceof Error ? e.message : String(e);
|
|
2101
|
-
}
|
|
2102
2163
|
function traceLine(e) {
|
|
2103
2164
|
return e instanceof HttpError && e.traceId ? MESSAGES.SERVER_TRACE_ID(e.traceId) : null;
|
|
2104
2165
|
}
|
|
2105
2166
|
function keyExpiredHint(e) {
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
return JSON.parse(e.body)?.error === KEY_EXPIRED_ERROR ? MESSAGES.KEY_EXPIRED_HINT : null;
|
|
2109
|
-
} catch {
|
|
2110
|
-
return null;
|
|
2111
|
-
}
|
|
2167
|
+
let refused2 = httpErrorJson(e);
|
|
2168
|
+
return refused2?.status === 401 && refused2.body.error === KEY_EXPIRED_ERROR ? MESSAGES.KEY_EXPIRED_HINT : null;
|
|
2112
2169
|
}
|
|
2113
2170
|
function printError(e) {
|
|
2114
|
-
fail(
|
|
2171
|
+
fail(errText(e), { hint: keyExpiredHint(e), trace: traceLine(e) });
|
|
2115
2172
|
}
|
|
2116
2173
|
async function guard(body) {
|
|
2117
|
-
|
|
2118
|
-
return await body();
|
|
2119
|
-
} catch (e) {
|
|
2120
|
-
return printError(e), 1;
|
|
2121
|
-
}
|
|
2174
|
+
return await guardValue(body) ?? 1;
|
|
2122
2175
|
}
|
|
2123
2176
|
async function guardValue(body) {
|
|
2124
2177
|
try {
|
|
@@ -2194,7 +2247,6 @@ var init_utils = __esm({ "src/utils/index.ts"() {
|
|
|
2194
2247
|
"use strict";
|
|
2195
2248
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2196
2249
|
init_sort();
|
|
2197
|
-
init_hash();
|
|
2198
2250
|
init_args2();
|
|
2199
2251
|
init_guard();
|
|
2200
2252
|
init_prompt_flow();
|
|
@@ -2229,7 +2281,7 @@ async function describeServer(baseUrl, fetchImpl = fetch, check = noteServerVers
|
|
|
2229
2281
|
return `API: ${api} at ${baseUrl}${floor ? ` (minimum client ${floor})` : ""}`;
|
|
2230
2282
|
}
|
|
2231
2283
|
async function runVersion(args, fetchImpl = fetch) {
|
|
2232
|
-
let baseUrl =
|
|
2284
|
+
let baseUrl = apiUrlOf(args), st = outStyle();
|
|
2233
2285
|
return out(`${st.bold(`ignitify ${CLIENT_VERSION}`)} ${st.dim(`(built for API ${API_VERSION})`)}`), out(st.dim(await describeServer(baseUrl, fetchImpl))), 0;
|
|
2234
2286
|
}
|
|
2235
2287
|
var CLIENT_VERSION, PROBE_TIMEOUT_MS, noteServerVersion, init_version = __esm({ "src/io/version.ts"() {
|
|
@@ -2249,7 +2301,7 @@ function openNoFollow(file, fsx = import_node_fs.default) {
|
|
|
2249
2301
|
try {
|
|
2250
2302
|
fd = fsx.openSync(file, NO_FOLLOW_READ_FLAGS);
|
|
2251
2303
|
} catch (e) {
|
|
2252
|
-
let code = e
|
|
2304
|
+
let code = errCode(e);
|
|
2253
2305
|
if (code === "ENOENT") return { kind: "missing" };
|
|
2254
2306
|
if (code === "ELOOP") return { kind: "symlink" };
|
|
2255
2307
|
throw e;
|
|
@@ -2263,7 +2315,9 @@ function openNoFollow(file, fsx = import_node_fs.default) {
|
|
|
2263
2315
|
var import_node_fs, NO_FOLLOW_READ_FLAGS, init_no_follow = __esm({ "src/io/no-follow.ts"() {
|
|
2264
2316
|
"use strict";
|
|
2265
2317
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2266
|
-
import_node_fs = __toESM(require("node:fs"), 1)
|
|
2318
|
+
import_node_fs = __toESM(require("node:fs"), 1);
|
|
2319
|
+
init_tenant();
|
|
2320
|
+
NO_FOLLOW_READ_FLAGS = import_node_fs.default.constants.O_RDONLY | (import_node_fs.default.constants.O_NOFOLLOW ?? 0) | (import_node_fs.default.constants.O_NONBLOCK ?? 0);
|
|
2267
2321
|
} });
|
|
2268
2322
|
function credentialsPath(env = process.env, home = import_node_os.default.homedir()) {
|
|
2269
2323
|
let xdg = env.XDG_CONFIG_HOME, base = xdg && import_node_path.default.isAbsolute(xdg) ? xdg : import_node_path.default.join(home, ".config");
|
|
@@ -2288,10 +2342,9 @@ function parseCredentials(text) {
|
|
|
2288
2342
|
} catch {
|
|
2289
2343
|
return null;
|
|
2290
2344
|
}
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
return d;
|
|
2345
|
+
if (!isRecord(doc) || doc.version !== 1) return null;
|
|
2346
|
+
let { api_url, api_key, key_id, label, saved_at } = doc;
|
|
2347
|
+
return !isFilled(api_url) || !isFilled(api_key) || !isFilled(key_id) || !isFilled(label) || !isFilled(saved_at) ? null : { version: 1, api_url, api_key, key_id, label, saved_at };
|
|
2295
2348
|
}
|
|
2296
2349
|
function readCredentials(file = credentialsPath(), fsx = import_node_fs2.default) {
|
|
2297
2350
|
let opened = openNoFollow(file, fsx);
|
|
@@ -2331,13 +2384,15 @@ function deleteCredentials(file = credentialsPath(), fsx = import_node_fs2.defau
|
|
|
2331
2384
|
throw e;
|
|
2332
2385
|
}
|
|
2333
2386
|
}
|
|
2334
|
-
var import_node_fs2, import_node_os, import_node_path, import_node_crypto,
|
|
2387
|
+
var import_node_fs2, import_node_os, import_node_path, import_node_crypto, isFilled, myUid, init_credentials = __esm({ "src/io/credentials.ts"() {
|
|
2335
2388
|
"use strict";
|
|
2336
2389
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2337
2390
|
import_node_fs2 = __toESM(require("node:fs"), 1), import_node_os = __toESM(require("node:os"), 1), import_node_path = __toESM(require("node:path"), 1), import_node_crypto = require("node:crypto");
|
|
2391
|
+
init_tenant();
|
|
2338
2392
|
init_constants();
|
|
2339
2393
|
init_no_follow();
|
|
2340
|
-
|
|
2394
|
+
isFilled = (v) => typeof v == "string" && v !== "";
|
|
2395
|
+
myUid = () => typeof process.getuid == "function" ? process.getuid() : null;
|
|
2341
2396
|
} });
|
|
2342
2397
|
function codeOf(cause) {
|
|
2343
2398
|
let code = cause?.code;
|
|
@@ -2385,17 +2440,15 @@ var UnreachableError, init_unreachable = __esm({ "src/core/unreachable.ts"() {
|
|
|
2385
2440
|
}
|
|
2386
2441
|
};
|
|
2387
2442
|
} });
|
|
2388
|
-
function isLoopbackHost(hostname) {
|
|
2389
|
-
return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(hostname);
|
|
2390
|
-
}
|
|
2391
2443
|
function apiUrlRefusal(url) {
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2444
|
+
switch (keyUrlRefusal(url)) {
|
|
2445
|
+
case "not-url":
|
|
2446
|
+
return MESSAGES.API_URL_NOT_URL(url);
|
|
2447
|
+
case "insecure":
|
|
2448
|
+
return MESSAGES.API_URL_NOT_HTTPS(url);
|
|
2449
|
+
case null:
|
|
2450
|
+
return null;
|
|
2397
2451
|
}
|
|
2398
|
-
return u.protocol === "https:" || u.protocol === "http:" && isLoopbackHost(u.hostname) ? null : MESSAGES.API_URL_NOT_HTTPS(url);
|
|
2399
2452
|
}
|
|
2400
2453
|
function assertApiUrl(url) {
|
|
2401
2454
|
let refusal = apiUrlRefusal(url);
|
|
@@ -2405,6 +2458,7 @@ function assertApiUrl(url) {
|
|
|
2405
2458
|
var init_api_url = __esm({ "src/core/api-url.ts"() {
|
|
2406
2459
|
"use strict";
|
|
2407
2460
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2461
|
+
init_http_client();
|
|
2408
2462
|
init_constants();
|
|
2409
2463
|
} });
|
|
2410
2464
|
function resolveApiConfig(apiOverride, env = process.env, read = () => readCredentials(), note = noteEnvOverride) {
|
|
@@ -2456,7 +2510,7 @@ async function pollDeviceLogin(cfg, deviceCode, fetchImpl) {
|
|
|
2456
2510
|
try {
|
|
2457
2511
|
body = await request(`${cfg.baseUrl}${TENANT_PATHS.AUTH_DEVICE_TOKEN}`, { method: "POST", headers: { "content-type": "application/json", ...versionHeader }, body: { device_code: deviceCode }, fetchImpl: viaApi(fetchImpl), ...readHeaders });
|
|
2458
2512
|
} catch (e) {
|
|
2459
|
-
let wait =
|
|
2513
|
+
let wait = slowDownOf(e);
|
|
2460
2514
|
if (wait === null) throw e;
|
|
2461
2515
|
return { kind: "wait", interval: wait };
|
|
2462
2516
|
}
|
|
@@ -2466,13 +2520,11 @@ async function pollDeviceLogin(cfg, deviceCode, fetchImpl) {
|
|
|
2466
2520
|
if (!key || typeof key.api_key != "string" || key.api_key === "" || typeof key.key_id != "string" || typeof key.label != "string" || typeof key.tenant?.resource_id != "string") throw new BadAnswerError(MESSAGES.LOGIN_BAD_ANSWER);
|
|
2467
2521
|
return { kind: "key", key };
|
|
2468
2522
|
}
|
|
2469
|
-
function slowDownOf(
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
return null;
|
|
2475
|
-
}
|
|
2523
|
+
function slowDownOf(e) {
|
|
2524
|
+
let refused2 = httpErrorJson(e);
|
|
2525
|
+
if (refused2?.status !== 429 || refused2.body.status !== "slow_down") return null;
|
|
2526
|
+
let interval = refused2.body.interval;
|
|
2527
|
+
return typeof interval == "number" ? interval : null;
|
|
2476
2528
|
}
|
|
2477
2529
|
function revokeOwnKey(cfg, fetchImpl) {
|
|
2478
2530
|
return apiDelete(cfg, TENANT_PATHS.AUTH_KEY, fetchImpl);
|
|
@@ -2484,8 +2536,9 @@ async function postDeployment(cfg, taskId, manifest, tar, fetchImpl) {
|
|
|
2484
2536
|
let form = new FormData();
|
|
2485
2537
|
return form.set("task_id", taskId), form.set("manifest", JSON.stringify(manifest)), form.set("bundle", new Blob([new Uint8Array(tar)], { type: "application/x-tar" }), "bundle.tar"), await request(`${cfg.baseUrl}${TENANT_PATHS.DEPLOYMENTS}`, { method: "POST", headers: authHeaders(cfg), body: form, fetchImpl: viaApi(fetchImpl), timeoutMs: 3e5, ...readHeaders });
|
|
2486
2538
|
}
|
|
2487
|
-
|
|
2488
|
-
|
|
2539
|
+
function postRun(cfg, run2, fetchImpl) {
|
|
2540
|
+
let body = { deployment_id: run2.deploymentId, task_name: run2.taskName, payload: run2.payload, preset: run2.preset, timeout_sec: run2.timeoutSec, execution: run2.execution, at: run2.at };
|
|
2541
|
+
return apiPost(cfg, TENANT_PATHS.RUNS, body, fetchImpl);
|
|
2489
2542
|
}
|
|
2490
2543
|
async function listSchedules(cfg, fetchImpl) {
|
|
2491
2544
|
return apiGet(cfg, TENANT_PATHS.SCHEDULES, fetchImpl);
|
|
@@ -2536,7 +2589,7 @@ async function postPackageAdvice(cfg, body, fetchImpl) {
|
|
|
2536
2589
|
try {
|
|
2537
2590
|
return { kind: "ok", response: await apiPost(cfg, TENANT_PATHS.PACKAGE_ADVICE, body, fetchImpl, ADVICE.TIMEOUT_MS) };
|
|
2538
2591
|
} catch (e) {
|
|
2539
|
-
return e instanceof HttpError ? adviceFailure(e
|
|
2592
|
+
return e instanceof HttpError ? adviceFailure(e) : { kind: "error", status: null, message: errText(e) };
|
|
2540
2593
|
}
|
|
2541
2594
|
}
|
|
2542
2595
|
async function createTask(cfg, slug2, fetchImpl) {
|
|
@@ -2621,8 +2674,8 @@ var readHeaders, noteEnvOverride, versionHeader, BadAnswerError, init_api = __es
|
|
|
2621
2674
|
};
|
|
2622
2675
|
} });
|
|
2623
2676
|
function payloadRefusal(payload, limit) {
|
|
2624
|
-
let
|
|
2625
|
-
return
|
|
2677
|
+
let bytes = payloadBytes(payload);
|
|
2678
|
+
return bytes > limit ? MESSAGES.PAYLOAD_OVER_LIMIT(bytes, limit) : null;
|
|
2626
2679
|
}
|
|
2627
2680
|
var payloadBytes, limitOrFallback, formatLimit, limitsNote, init_payload_limit = __esm({ "src/core/payload-limit.ts"() {
|
|
2628
2681
|
"use strict";
|
|
@@ -2630,7 +2683,7 @@ var payloadBytes, limitOrFallback, formatLimit, limitsNote, init_payload_limit =
|
|
|
2630
2683
|
init_constants();
|
|
2631
2684
|
init_output();
|
|
2632
2685
|
payloadBytes = (payload) => Buffer.byteLength(JSON.stringify(payload) ?? "", "utf8"), limitOrFallback = (limit, fallback) => typeof limit == "number" && Number.isFinite(limit) && limit > 0 ? limit : fallback;
|
|
2633
|
-
formatLimit = (
|
|
2686
|
+
formatLimit = (bytes) => formatBytes(bytes).replace(/\.0 /, " "), limitsNote = () => MESSAGES.TASK_LIMITS(formatLimit(PAYLOAD_LIMIT_FALLBACK_BYTES), formatLimit(RESULT_LIMIT_FALLBACK_BYTES));
|
|
2634
2687
|
} });
|
|
2635
2688
|
function apiConfig(args) {
|
|
2636
2689
|
return resolveApiConfig(strOpt(args, "api"));
|
|
@@ -2639,20 +2692,27 @@ async function payloadLimit(cfg) {
|
|
|
2639
2692
|
let whoami = await getWhoami(cfg).catch(() => null);
|
|
2640
2693
|
return limitOrFallback(whoami?.limits.max_payload_bytes, PAYLOAD_LIMIT_FALLBACK_BYTES);
|
|
2641
2694
|
}
|
|
2642
|
-
function consoleLogText(
|
|
2643
|
-
return out2.raw ?
|
|
2695
|
+
function consoleLogText(bytes, out2) {
|
|
2696
|
+
return out2.raw ? bytes : terminalSafe(bytes, out2.colour);
|
|
2644
2697
|
}
|
|
2645
2698
|
function printConsoleLog(data, raw, colour = outStyle().colour) {
|
|
2646
2699
|
if (writeRaw(consoleLogText(typeof data?.bytes == "string" ? data.bytes : "", { raw, colour })), data?.truncated === true) {
|
|
2647
2700
|
let lines = typeof data.lines == "number" ? data.lines : 0;
|
|
2648
2701
|
tell(`
|
|
2649
|
-
${warnMark(errStyle(),
|
|
2702
|
+
${warnMark(errStyle(), RESULT_MESSAGES.LOG_TRUNCATED(lines))}`);
|
|
2650
2703
|
}
|
|
2651
2704
|
}
|
|
2652
2705
|
function noteNextPage(args, list2, rows) {
|
|
2653
2706
|
let note = nextPageNoteFor2(args, list2, rows);
|
|
2654
2707
|
note !== void 0 && warn(note);
|
|
2655
2708
|
}
|
|
2709
|
+
async function runPagedList(args, verb) {
|
|
2710
|
+
let badLimit = limitRefusal(args);
|
|
2711
|
+
return badLimit !== null ? (fail(badLimit), 1) : guard(async () => {
|
|
2712
|
+
let data = await verb.fetchPage(apiConfig(args), { ...flagParams(args, verb.list.flags), ...verb.extra });
|
|
2713
|
+
return verb.show(data), noteNextPage(args, verb.list, verb.rowsOf(data)), 0;
|
|
2714
|
+
});
|
|
2715
|
+
}
|
|
2656
2716
|
var init_shared = __esm({ "src/commands/shared.ts"() {
|
|
2657
2717
|
"use strict";
|
|
2658
2718
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
@@ -2682,6 +2742,41 @@ var init_identity = __esm({ "src/commands/identity.ts"() {
|
|
|
2682
2742
|
init_output();
|
|
2683
2743
|
init_shared();
|
|
2684
2744
|
} });
|
|
2745
|
+
function backoffDelayMs(attempt, cadence) {
|
|
2746
|
+
return cappedExponentialMs(attempt, cadence.BASE_MS, cadence.MAX_MS);
|
|
2747
|
+
}
|
|
2748
|
+
function isTransientError(e) {
|
|
2749
|
+
return e instanceof HttpError ? e.status === 408 || e.status === 429 || e.status >= 500 && e.status <= 599 : e instanceof TypeError ? true : e instanceof Error && isRecord(e.cause) && e.cause.name === "TimeoutError";
|
|
2750
|
+
}
|
|
2751
|
+
function decidePollError(e, failuresInARow, failingForMs) {
|
|
2752
|
+
return isTransientError(e) ? failuresInARow >= POLL.ERROR.MIN_TRIES && failingForMs >= POLL.ERROR.GRACE_MS ? "give-up" : "retry" : "give-up";
|
|
2753
|
+
}
|
|
2754
|
+
async function pollUntil(loop) {
|
|
2755
|
+
let sleep = loop.clock?.sleep ?? REAL_CLOCK.sleep, now = loop.clock?.now ?? REAL_CLOCK.now, startedAt = now(), failures = 0, firstFailureAt = 0;
|
|
2756
|
+
for (let attempt = 0; ; ) {
|
|
2757
|
+
let view;
|
|
2758
|
+
try {
|
|
2759
|
+
view = await loop.fetch();
|
|
2760
|
+
} catch (error) {
|
|
2761
|
+
if (failures === 0 && (firstFailureAt = now()), failures += 1, decidePollError(error, failures, now() - firstFailureAt) === "give-up") return { kind: "lost", error };
|
|
2762
|
+
loop.onRetry?.(error), await sleep(loop.retryDelayMs);
|
|
2763
|
+
continue;
|
|
2764
|
+
}
|
|
2765
|
+
failures = 0, loop.onView?.(view);
|
|
2766
|
+
let action = loop.decide(view, now() - startedAt, attempt);
|
|
2767
|
+
if (!isWait(action)) return { action, view };
|
|
2768
|
+
loop.onWait?.(view, attempt), await sleep(action.delayMs), attempt += 1;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
var isWait, isLost, init_poll = __esm({ "src/core/poll.ts"() {
|
|
2772
|
+
"use strict";
|
|
2773
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
2774
|
+
init_http_client();
|
|
2775
|
+
init_tenant();
|
|
2776
|
+
init_constants();
|
|
2777
|
+
init_utils();
|
|
2778
|
+
isWait = (action) => action.kind === "wait", isLost = (end) => "kind" in end && end.kind === "lost";
|
|
2779
|
+
} });
|
|
2685
2780
|
function shortenHome(file, home) {
|
|
2686
2781
|
if (home === "" || !file.startsWith(home)) return file;
|
|
2687
2782
|
let rest = file.slice(home.length);
|
|
@@ -2710,9 +2805,6 @@ var INDENT, renderWaitingStatic, init_login_view = __esm({ "src/commands/login-v
|
|
|
2710
2805
|
INDENT = " ";
|
|
2711
2806
|
renderWaitingStatic = (minutes) => LOGIN_VIEW.WAITING_STATIC(minutes);
|
|
2712
2807
|
} });
|
|
2713
|
-
function formatUserCode(code) {
|
|
2714
|
-
return code.length === 8 ? `${code.slice(0, 4)}-${code.slice(4)}` : code;
|
|
2715
|
-
}
|
|
2716
2808
|
function replacedKeyNote(replacedKeyId, ownKeyId, label) {
|
|
2717
2809
|
return !replacedKeyId || replacedKeyId === ownKeyId ? null : MESSAGES.LOGIN_REPLACED(label);
|
|
2718
2810
|
}
|
|
@@ -2745,15 +2837,8 @@ async function withRetries(baseUrl, clock, waitMs, call) {
|
|
|
2745
2837
|
await clock.sleep(waitMs);
|
|
2746
2838
|
}
|
|
2747
2839
|
}
|
|
2748
|
-
function bodyOf(e) {
|
|
2749
|
-
try {
|
|
2750
|
-
return JSON.parse(e.body);
|
|
2751
|
-
} catch {
|
|
2752
|
-
return {};
|
|
2753
|
-
}
|
|
2754
|
-
}
|
|
2755
2840
|
function pollFailure(e, userCode) {
|
|
2756
|
-
let body =
|
|
2841
|
+
let body = httpErrorJson(e)?.body ?? {};
|
|
2757
2842
|
switch (e.status) {
|
|
2758
2843
|
case 410:
|
|
2759
2844
|
return MESSAGES.LOGIN_EXPIRED(formatUserCode(userCode));
|
|
@@ -2782,7 +2867,7 @@ async function pollForKey(baseUrl, started, deadline, deps) {
|
|
|
2782
2867
|
}
|
|
2783
2868
|
async function runLogin(args, deps = {}) {
|
|
2784
2869
|
return guard(async () => {
|
|
2785
|
-
let clock = deps.clock ?? REAL_CLOCK, baseUrl = assertApiUrl(
|
|
2870
|
+
let clock = deps.clock ?? REAL_CLOCK, baseUrl = assertApiUrl(apiUrlOf(args)), label = strOpt(args, "name") ?? (deps.hostname ?? import_node_os2.default.hostname)(), file = deps.file ?? credentialsPath(deps.env), started = await withRetries(baseUrl, clock, START_RETRY_MS, () => startDeviceLogin({ baseUrl }, { label, cli_version: CLIENT_VERSION }, deps.fetchImpl)).catch((e) => {
|
|
2786
2871
|
throw e instanceof HttpError && e.status === 429 ? new Error(MESSAGES.LOGIN_TOO_MANY, { cause: e }) : e;
|
|
2787
2872
|
}), env = deps.env ?? process.env, st = screenStyle(deps.screen, env), url = started.verification_uri_complete;
|
|
2788
2873
|
if (say(renderLoginStart(st, { code: formatUserCode(started.user_code), url })), say(""), url !== null) {
|
|
@@ -2830,35 +2915,28 @@ var import_node_os2, import_node_child_process, START_RETRY_MS, retryable, reach
|
|
|
2830
2915
|
"use strict";
|
|
2831
2916
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2832
2917
|
import_node_os2 = __toESM(require("node:os"), 1), import_node_child_process = require("node:child_process");
|
|
2918
|
+
init_tenant();
|
|
2833
2919
|
init_http_client();
|
|
2920
|
+
init_tenant();
|
|
2834
2921
|
init_api();
|
|
2835
2922
|
init_credentials();
|
|
2836
2923
|
init_version();
|
|
2837
2924
|
init_unreachable();
|
|
2925
|
+
init_poll();
|
|
2838
2926
|
init_api_url();
|
|
2839
2927
|
init_constants();
|
|
2840
2928
|
init_utils();
|
|
2841
2929
|
init_output();
|
|
2842
2930
|
init_login_view();
|
|
2843
|
-
START_RETRY_MS = 1e3, retryable = (e) =>
|
|
2844
|
-
} });
|
|
2845
|
-
function filters(args) {
|
|
2846
|
-
let q = {}, period = strOpt(args, "period");
|
|
2847
|
-
period !== void 0 && (q.period = period);
|
|
2848
|
-
let axis = strOpt(args, "axis");
|
|
2849
|
-
axis !== void 0 && (q.axis = axis);
|
|
2850
|
-
let vm = strOpt(args, "vm");
|
|
2851
|
-
vm !== void 0 && (q.vm = vm);
|
|
2852
|
-
let run2 = strOpt(args, "run");
|
|
2853
|
-
return run2 !== void 0 && (q.run = run2), q;
|
|
2854
|
-
}
|
|
2931
|
+
START_RETRY_MS = 1e3, retryable = (e) => isTransientError(e) && !(e instanceof HttpError && e.status === 429), reachDetail = (e) => e instanceof UnreachableError ? e.detail : isTransientError(e) && !(e instanceof HttpError) && !(e instanceof TypeError) ? errText(e) : null;
|
|
2932
|
+
} });
|
|
2855
2933
|
function selectLines(lines, runs, vms) {
|
|
2856
2934
|
return lines.filter((l) => runs && l.run_id !== null || vms && l.vm_id !== null);
|
|
2857
2935
|
}
|
|
2858
2936
|
async function runUsageShow(args) {
|
|
2859
2937
|
return guard(async () => {
|
|
2860
2938
|
let report = await getUsage(apiConfig(args), filters(args));
|
|
2861
|
-
if (boolFlag(args, "json")) return
|
|
2939
|
+
if (boolFlag(args, "json")) return emit(report), 0;
|
|
2862
2940
|
let runs = boolFlag(args, "runs"), vms = boolFlag(args, "vms"), shown = { ...report, lines: selectLines(report.lines, runs, vms) };
|
|
2863
2941
|
return out(renderUsageReport(outStyle(), shown, { lines: runs || vms })), 0;
|
|
2864
2942
|
});
|
|
@@ -2871,7 +2949,7 @@ async function runUsageExport(args) {
|
|
|
2871
2949
|
return out(json2 ? JSON.stringify(report.lines, null, 2) : toCsv(report)), 0;
|
|
2872
2950
|
});
|
|
2873
2951
|
}
|
|
2874
|
-
var init_usage_report = __esm({ "src/commands/usage-report.ts"() {
|
|
2952
|
+
var filters, init_usage_report = __esm({ "src/commands/usage-report.ts"() {
|
|
2875
2953
|
"use strict";
|
|
2876
2954
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2877
2955
|
init_api();
|
|
@@ -2880,10 +2958,10 @@ var init_usage_report = __esm({ "src/commands/usage-report.ts"() {
|
|
|
2880
2958
|
init_usage2();
|
|
2881
2959
|
init_output();
|
|
2882
2960
|
init_constants();
|
|
2961
|
+
filters = (args) => flagParams(args, USAGE_FLAG_PARAMS);
|
|
2883
2962
|
} });
|
|
2884
2963
|
function planTaskDeletion(input) {
|
|
2885
|
-
let affected =
|
|
2886
|
-
for (let run2 of input.runs) isTerminalRunStatus(run2.status) || affected.push({ runId: run2.id, status: run2.status, ...run2.vm_id ? { vmId: run2.vm_id } : {}, fate: fateOf(run2.status) });
|
|
2964
|
+
let affected = input.runs.filter((run2) => !isTerminalRunStatus(run2.status)).map((run2) => ({ runId: run2.id, status: run2.status, ...run2.vm_id ? { vmId: run2.vm_id } : {}, fate: fateOf(run2.status) }));
|
|
2887
2965
|
return { taskSlug: input.taskSlug, deploymentCount: input.deploymentCount, runCount: input.runCount, affected, unlinkDirs: linkedDirs(input.taskId, input.folders), hasInFlight: affected.length > 0 };
|
|
2888
2966
|
}
|
|
2889
2967
|
function linkedDirs(taskId, folders) {
|
|
@@ -2915,7 +2993,7 @@ var init_resolve_deployment = __esm({ "src/core/resolve-deployment.ts"() {
|
|
|
2915
2993
|
function parseRunOptions(args, config) {
|
|
2916
2994
|
let bare = bareValueFlag(args, VALUE_FLAGS);
|
|
2917
2995
|
if (bare !== void 0) return { ok: false, error: needsValueMessage(bare) };
|
|
2918
|
-
let payloadArg = strOpt(args, "payload"), payload = payloadArg === void 0 ? { ok: true, value: config.run?.payload ?? {} } :
|
|
2996
|
+
let payloadArg = strOpt(args, "payload"), payload = payloadArg === void 0 ? { ok: true, value: config.run?.payload ?? {} } : parseJsonText(payloadArg);
|
|
2919
2997
|
if (!payload.ok) return { ok: false, error: `--payload is not valid JSON: ${payloadArg}` };
|
|
2920
2998
|
let timeoutArg = strOpt(args, "timeout-sec"), timeoutOverride = timeoutArg === void 0 ? void 0 : Number(timeoutArg);
|
|
2921
2999
|
if (timeoutOverride !== void 0 && !(Number.isFinite(timeoutOverride) && timeoutOverride > 0)) return { ok: false, error: `--timeout-sec must be a positive number, got: ${timeoutArg}` };
|
|
@@ -2926,21 +3004,35 @@ function parseRunOptions(args, config) {
|
|
|
2926
3004
|
let wait = boolFlag(args, "wait");
|
|
2927
3005
|
return at !== void 0 && wait ? { ok: false, error: MESSAGES.RUN_AT_WITH_WAIT } : { ok: true, deploymentFlag: strOpt(args, "deployment"), wait, run: { payload: payload.value, preset: config.run?.preset, timeoutSec: timeoutOverride ?? config.run?.timeout_sec, execution: onBusy === void 0 ? config.execution : { ...config.execution ?? {}, on_busy: onBusy }, at } };
|
|
2928
3006
|
}
|
|
2929
|
-
function parseJson2(text) {
|
|
2930
|
-
try {
|
|
2931
|
-
return { ok: true, value: JSON.parse(text) };
|
|
2932
|
-
} catch {
|
|
2933
|
-
return { ok: false };
|
|
2934
|
-
}
|
|
2935
|
-
}
|
|
2936
3007
|
var VALUE_FLAGS, init_run_options = __esm({ "src/core/run-options.ts"() {
|
|
2937
3008
|
"use strict";
|
|
2938
3009
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
3010
|
+
init_tenant();
|
|
2939
3011
|
init_http_client();
|
|
2940
3012
|
init_constants();
|
|
2941
3013
|
init_utils();
|
|
2942
3014
|
VALUE_FLAGS = Object.entries(COMMAND_META[COMMANDS.TASK_RUN].flags).filter(([, kind]) => kind === "value").map(([flag]) => flag);
|
|
2943
3015
|
} });
|
|
3016
|
+
function classifyRunAnswer(res, at, wait) {
|
|
3017
|
+
return at !== void 0 ? res.schedule_id ? { kind: "scheduled", scheduleId: res.schedule_id, firesAt: res.fires_at ?? at } : res.run_id ? { kind: "skew-ran-now", runId: res.run_id } : { kind: "skew-no-schedule" } : wait && res.run_id ? { kind: "wait", runId: res.run_id } : { kind: "submitted" };
|
|
3018
|
+
}
|
|
3019
|
+
var init_run_answer = __esm({ "src/core/run-answer.ts"() {
|
|
3020
|
+
"use strict";
|
|
3021
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
3022
|
+
} });
|
|
3023
|
+
function writeFileAtomic(file, text) {
|
|
3024
|
+
let exists = import_node_fs3.default.existsSync(file), target = exists ? import_node_fs3.default.realpathSync(file) : file, mode = exists ? import_node_fs3.default.statSync(target).mode & 511 : NEW_FILE_MODE, name = `.${import_node_path2.default.basename(target)}.${process.pid}.${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.tmp`, tmp = import_node_path2.default.join(import_node_path2.default.dirname(target), name);
|
|
3025
|
+
try {
|
|
3026
|
+
import_node_fs3.default.writeFileSync(tmp, text, { mode, flag: "wx" }), exists && import_node_fs3.default.chmodSync(tmp, mode), import_node_fs3.default.renameSync(tmp, target);
|
|
3027
|
+
} finally {
|
|
3028
|
+
import_node_fs3.default.rmSync(tmp, { force: true });
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
var import_node_crypto2, import_node_fs3, import_node_path2, NEW_FILE_MODE, init_fs_atomic = __esm({ "src/io/fs-atomic.ts"() {
|
|
3032
|
+
"use strict";
|
|
3033
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
3034
|
+
import_node_crypto2 = require("node:crypto"), import_node_fs3 = __toESM(require("node:fs"), 1), import_node_path2 = __toESM(require("node:path"), 1), NEW_FILE_MODE = 438;
|
|
3035
|
+
} });
|
|
2944
3036
|
function parseState(raw) {
|
|
2945
3037
|
let parsed;
|
|
2946
3038
|
try {
|
|
@@ -2948,9 +3040,12 @@ function parseState(raw) {
|
|
|
2948
3040
|
} catch {
|
|
2949
3041
|
return {};
|
|
2950
3042
|
}
|
|
2951
|
-
if (
|
|
2952
|
-
let
|
|
2953
|
-
for (let key of STATE_KEYS)
|
|
3043
|
+
if (!isRecord(parsed)) return {};
|
|
3044
|
+
let out2 = {};
|
|
3045
|
+
for (let key of STATE_KEYS) {
|
|
3046
|
+
let value = parsed[key];
|
|
3047
|
+
typeof value == "string" && (out2[key] = value);
|
|
3048
|
+
}
|
|
2954
3049
|
return out2;
|
|
2955
3050
|
}
|
|
2956
3051
|
function serializeState(state) {
|
|
@@ -2964,19 +3059,19 @@ function writeState(taskDir, patch2) {
|
|
|
2964
3059
|
let merged = { ...readState(taskDir), ...patch2 }, statePath = import_path.default.join(taskDir, STATE.DIR, STATE.FILE);
|
|
2965
3060
|
import_fs.default.mkdirSync(import_path.default.dirname(statePath), { recursive: true });
|
|
2966
3061
|
let ignorePath = import_path.default.join(import_path.default.dirname(statePath), STATE.GITIGNORE_FILE);
|
|
2967
|
-
import_fs.default.existsSync(ignorePath) || import_fs.default.writeFileSync(ignorePath, STATE.GITIGNORE_TEXT);
|
|
2968
|
-
let tmpPath = `${statePath}.tmp`;
|
|
2969
|
-
return import_fs.default.writeFileSync(tmpPath, serializeState(merged)), import_fs.default.renameSync(tmpPath, statePath), merged;
|
|
3062
|
+
return import_fs.default.existsSync(ignorePath) || import_fs.default.writeFileSync(ignorePath, STATE.GITIGNORE_TEXT), writeFileAtomic(statePath, serializeState(merged)), merged;
|
|
2970
3063
|
}
|
|
2971
3064
|
var import_fs, import_path, STATE_KEYS, init_state = __esm({ "src/io/state.ts"() {
|
|
2972
3065
|
"use strict";
|
|
2973
3066
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
2974
3067
|
import_fs = __toESM(require("fs"), 1), import_path = __toESM(require("path"), 1);
|
|
3068
|
+
init_tenant();
|
|
3069
|
+
init_fs_atomic();
|
|
2975
3070
|
init_constants();
|
|
2976
3071
|
STATE_KEYS = ["task_id", "task_resource_id", "deployment_id"];
|
|
2977
3072
|
} });
|
|
2978
3073
|
function buildTaskReport(inputs) {
|
|
2979
|
-
let { slug: slug2, deployments, runs, usage } = inputs, taskDeployments = deployments === null ? null : deployments.filter((d) => d.task_slug === slug2), firstPage = (rows) => rows.length >= inputs.pageLimit ? ` (first ${inputs.pageLimit} shown; more may exist)` : "", newDeployment = decideNewDeployment(inputs.localContentHash, taskDeployments), newVm = decideNewVm(inputs.declared, inputs.declaredPreset, inputs.stateDeploymentId, newDeployment, runs), deployed = taskDeployments === null ? { yes: "unknown", detail: inputs.stateDeploymentId ? `server unreachable; .ignitify/state.json points at ${inputs.stateDeploymentId}` : "server unreachable; no local deployment pointer either" } : taskDeployments.length > 0 ? { yes: true, detail: `${taskDeployments.length} live deployment(s)${firstPage(taskDeployments)}${inputs.stateDeploymentId && !taskDeployments.some((d) => d.id === inputs.stateDeploymentId) ? ` \u2014 WARNING: state.json points at ${inputs.stateDeploymentId}, which is not among them (deleted?)` : ""}` } : { yes: false, detail: "no live deployments for this task" }, deploymentSummaries = taskDeployments === null ? "unknown" : byCreatedAtDesc(taskDeployments).map((d) => ({ id: d.id ?? "?", created_at: d.created_at ?? "?", status: d.status ?? "?", content_hash:
|
|
3074
|
+
let { slug: slug2, deployments, runs, usage } = inputs, taskDeployments = deployments === null ? null : deployments.filter((d) => d.task_slug === slug2), firstPage = (rows) => rows.length >= inputs.pageLimit ? ` (first ${inputs.pageLimit} shown; more may exist)` : "", newDeployment = decideNewDeployment(inputs.localContentHash, taskDeployments), newVm = decideNewVm(inputs.declared, inputs.declaredPreset, inputs.stateDeploymentId, newDeployment, runs), deployed = taskDeployments === null ? { yes: "unknown", detail: inputs.stateDeploymentId ? `server unreachable; .ignitify/state.json points at ${inputs.stateDeploymentId}` : "server unreachable; no local deployment pointer either" } : taskDeployments.length > 0 ? { yes: true, detail: `${taskDeployments.length} live deployment(s)${firstPage(taskDeployments)}${inputs.stateDeploymentId && !taskDeployments.some((d) => d.id === inputs.stateDeploymentId) ? ` \u2014 WARNING: state.json points at ${inputs.stateDeploymentId}, which is not among them (deleted?)` : ""}` } : { yes: false, detail: "no live deployments for this task" }, deploymentSummaries = taskDeployments === null ? "unknown" : byCreatedAtDesc(taskDeployments).map((d) => ({ id: d.id ?? "?", created_at: d.created_at ?? "?", status: d.status ?? "?", content_hash: stripSha256Prefix(d.content_hash ?? "").slice(0, 12), image_bytes: d.image_bytes ?? 0, detailCommand: `ignitify deployment:get ${d.id ?? "<id>"}` })), runsSummary = runs === null ? "unknown" : { total: runs.length, firstPageOnly: runs.length >= inputs.pageLimit, byStatus: runs.reduce((acc, r) => {
|
|
2980
3075
|
let s = r.status ?? "?";
|
|
2981
3076
|
return acc[s] = (acc[s] ?? 0) + 1, acc;
|
|
2982
3077
|
}, /* @__PURE__ */ Object.create(null)), recent: byCreatedAtDesc(runs).slice(0, 5).map((r) => ({ id: r.id ?? "?", created_at: r.created_at ?? "?", status: r.status ?? "?", detailCommand: `ignitify run:get ${r.id ?? "<id>"}` })), listCommand: `ignitify run:list --task-name ${slug2}` };
|
|
@@ -2984,7 +3079,7 @@ function buildTaskReport(inputs) {
|
|
|
2984
3079
|
}
|
|
2985
3080
|
function formatTaskReport(r) {
|
|
2986
3081
|
let lines = [];
|
|
2987
|
-
if (lines.push(`Task report: ${r.slug}`), lines.push(""), lines.push(`Deployed: ${r.deployed.yes
|
|
3082
|
+
if (lines.push(`Task report: ${r.slug}`), lines.push(""), lines.push(`Deployed: ${yesNoUnknown(r.deployed.yes)} \u2014 ${r.deployed.detail}`), lines.push(""), lines.push("Resources:"), lines.push(` task images on disk: ${r.resources.taskImageBytes === "unknown" ? "unknown (server unreachable)" : formatBytes(r.resources.taskImageBytes)}`), r.resources.tenant) {
|
|
2988
3083
|
let u = r.resources.tenant;
|
|
2989
3084
|
lines.push(` tenant-wide (whoami): tasks ${u.task_count ?? "?"}, active runs ${u.active_runs ?? "?"}, deployments ${u.deployment_count ?? "?"}, images ${formatBytes(u.total_image_bytes ?? 0)}, egress this month ${formatBytes(u.net_egress_bytes ?? 0)}`), lines.push(" more: ignitify quota");
|
|
2990
3085
|
}
|
|
@@ -3007,27 +3102,25 @@ function formatTaskReport(r) {
|
|
|
3007
3102
|
}
|
|
3008
3103
|
lines.push("");
|
|
3009
3104
|
}
|
|
3010
|
-
lines.push(`New deployment needed: ${
|
|
3105
|
+
lines.push(`New deployment needed: ${yesNoUnknown(r.newDeployment.needed)}`);
|
|
3011
3106
|
for (let reason of r.newDeployment.reasons) lines.push(` - ${reason}`);
|
|
3012
|
-
lines.push(""), lines.push(`New VM on next run: ${
|
|
3107
|
+
lines.push(""), lines.push(`New VM on next run: ${yesNoUnknown(r.newVm.needed)}`);
|
|
3013
3108
|
for (let reason of r.newVm.reasons) lines.push(` - ${reason}`);
|
|
3014
3109
|
return lines.join(`
|
|
3015
3110
|
`);
|
|
3016
3111
|
}
|
|
3017
|
-
var FINGERPRINT_AXES, resolveOrNull, runNature, fingerprintDiffs, presetIndeterminate, decideNewDeployment, decideNewVm, decideInbound,
|
|
3112
|
+
var FINGERPRINT_AXES, resolveOrNull, DEFAULT_NATURE, runNature, fingerprintDiffs, presetIndeterminate, decideNewDeployment, decideNewVm, decideInbound, yesNoUnknown, init_report = __esm({ "src/core/report.ts"() {
|
|
3018
3113
|
"use strict";
|
|
3019
3114
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
3020
3115
|
init_execution();
|
|
3021
3116
|
init_output();
|
|
3117
|
+
init_tenant();
|
|
3022
3118
|
init_utils();
|
|
3023
3119
|
init_constants();
|
|
3024
3120
|
FINGERPRINT_AXES = ["network", "storage_mib", "cardinality", "state", "interaction", "duration", "residency"], resolveOrNull = (declared) => {
|
|
3025
3121
|
let r = resolveNature(declared, PLATFORM_DEFAULT_NATURE);
|
|
3026
3122
|
return r.ok ? r.nature : null;
|
|
3027
|
-
}, runNature = (run2) => {
|
|
3028
|
-
let declared = run2.execution ?? void 0;
|
|
3029
|
-
return resolveOrNull(declared) ?? resolveNature(void 0, PLATFORM_DEFAULT_NATURE).nature;
|
|
3030
|
-
}, fingerprintDiffs = (prev, next, prevPreset, nextPreset) => {
|
|
3123
|
+
}, DEFAULT_NATURE = resolveOrNull(void 0) ?? PLATFORM_DEFAULT_NATURE, runNature = (run2) => resolveOrNull(run2.execution ?? void 0) ?? DEFAULT_NATURE, fingerprintDiffs = (prev, next, prevPreset, nextPreset) => {
|
|
3031
3124
|
let diffs = [];
|
|
3032
3125
|
prevPreset !== void 0 && nextPreset !== void 0 && prevPreset !== nextPreset && diffs.push(`preset ${prevPreset}\u2192${nextPreset}`);
|
|
3033
3126
|
for (let axis of FINGERPRINT_AXES) prev[axis] !== next[axis] && diffs.push(`${axis} ${String(prev[axis] ?? "default")}\u2192${String(next[axis] ?? "default")}`);
|
|
@@ -3036,7 +3129,7 @@ var FINGERPRINT_AXES, resolveOrNull, runNature, fingerprintDiffs, presetIndeterm
|
|
|
3036
3129
|
if (taskDeployments === null) return { needed: "unknown", reasons: ["server unreachable \u2014 cannot compare against live deployments"] };
|
|
3037
3130
|
if (taskDeployments.length === 0) return { needed: true, reasons: ["no live deployment exists for this task (never deployed, or all deleted)"] };
|
|
3038
3131
|
if (localContentHash === null) return { needed: "unknown", reasons: ["the local content hash could not be computed \u2014 the upload would be refused (run `ignitify task:pack` to see why)"] };
|
|
3039
|
-
let localHash =
|
|
3132
|
+
let localHash = stripSha256Prefix(localContentHash), match = taskDeployments.find((d) => stripSha256Prefix(d.content_hash ?? "") === localHash);
|
|
3040
3133
|
if (match) {
|
|
3041
3134
|
let rebuild = match.image_present === false;
|
|
3042
3135
|
return { needed: false, reasons: [`local code is identical to deployment ${match.id ?? "?"} (content_hash dedup \u2014 deploy would return reused: true)`, ...rebuild ? ["note: its image is no longer in the store (archived by the GC) \u2014 a deploy would rebuild the image under the SAME deployment id"] : []] };
|
|
@@ -3057,10 +3150,10 @@ var FINGERPRINT_AXES, resolveOrNull, runNature, fingerprintDiffs, presetIndeterm
|
|
|
3057
3150
|
}, decideInbound = (declared, taskDeployments, runs) => {
|
|
3058
3151
|
let nature = resolveOrNull(declared);
|
|
3059
3152
|
if (nature === null || nature.network !== "bidirectional" || nature.inbound_port === void 0) return null;
|
|
3060
|
-
let serving = (runs ?? []).some((r) => ACTIVE_RUN_STATUSES.has(r.status ?? "")), routes = taskDeployments === null ? "unknown" : taskDeployments.
|
|
3153
|
+
let serving = (runs ?? []).some((r) => ACTIVE_RUN_STATUSES.has(r.status ?? "")), routes = taskDeployments === null ? "unknown" : taskDeployments.flatMap((d) => d.id ? [{ deploymentId: d.id, routeId: deriveRouteId(d.id) }] : []);
|
|
3061
3154
|
return { port: nature.inbound_port, serving, routes };
|
|
3062
3155
|
};
|
|
3063
|
-
|
|
3156
|
+
yesNoUnknown = (answer) => answer === "unknown" ? "UNKNOWN" : answer ? "YES" : "NO";
|
|
3064
3157
|
} });
|
|
3065
3158
|
function getDefaultExportFromCjs(x) {
|
|
3066
3159
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
|
|
@@ -3721,7 +3814,7 @@ function requireLoader() {
|
|
|
3721
3814
|
function mergeMappings(state, destination, source, overridableKeys) {
|
|
3722
3815
|
common2.isObject(source) || throwError(state, "cannot merge mappings; the provided source object is unacceptable"), chargeMergeWork(state);
|
|
3723
3816
|
let sourceKeys = Object.keys(source);
|
|
3724
|
-
for (let index = 0,
|
|
3817
|
+
for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
|
|
3725
3818
|
let key = sourceKeys[index];
|
|
3726
3819
|
chargeMergeWork(state), _hasOwnProperty.call(destination, key) || (setProperty(destination, key, source[key]), overridableKeys[key] = true);
|
|
3727
3820
|
}
|
|
@@ -3729,11 +3822,11 @@ function requireLoader() {
|
|
|
3729
3822
|
function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startLineStart, startPos) {
|
|
3730
3823
|
if (Array.isArray(keyNode)) {
|
|
3731
3824
|
keyNode = Array.prototype.slice.call(keyNode);
|
|
3732
|
-
for (let index = 0,
|
|
3825
|
+
for (let index = 0, quantity = keyNode.length; index < quantity; index += 1) Array.isArray(keyNode[index]) && throwError(state, "nested arrays are not supported inside keys"), typeof keyNode == "object" && _class(keyNode[index]) === "[object Object]" && (keyNode[index] = "[object Object]");
|
|
3733
3826
|
}
|
|
3734
3827
|
if (typeof keyNode == "object" && _class(keyNode) === "[object Object]" && (keyNode = "[object Object]"), keyNode = String(keyNode), _result === null && (_result = {}), keyTag === "tag:yaml.org,2002:merge") if (Array.isArray(valueNode)) {
|
|
3735
3828
|
valueNode.length > 100 && throwError(state, "abnormal merge sequence size");
|
|
3736
|
-
for (let index = 0,
|
|
3829
|
+
for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) mergeMappings(state, _result, valueNode[index], overridableKeys);
|
|
3737
3830
|
} else mergeMappings(state, _result, valueNode, overridableKeys);
|
|
3738
3831
|
else !state.json && !_hasOwnProperty.call(overridableKeys, keyNode) && _hasOwnProperty.call(_result, keyNode) && (state.line = startLine || state.line, state.lineStart = startLineStart || state.lineStart, state.position = startPos || state.position, throwError(state, "duplicated mapping key")), setProperty(_result, keyNode, valueNode), delete overridableKeys[keyNode];
|
|
3739
3832
|
return _result;
|
|
@@ -8200,8 +8293,8 @@ function validateConfig(config, source = "task.yaml", payloadLimit2 = PAYLOAD_LI
|
|
|
8200
8293
|
let run2 = config.run;
|
|
8201
8294
|
if (run2) {
|
|
8202
8295
|
run2.preset !== void 0 && (typeof run2.preset != "string" || run2.preset.trim() === "") ? errors.push(MESSAGES.PRESET_INVALID) : run2.preset !== void 0 && !isKnownPreset(run2.preset) && errors.push(MESSAGES.PRESET_UNKNOWN(source, run2.preset, PRESET_NAMES)), run2.timeout_sec !== void 0 && !(typeof run2.timeout_sec == "number" && run2.timeout_sec > 0) && errors.push(MESSAGES.TIMEOUT_INVALID);
|
|
8203
|
-
let
|
|
8204
|
-
|
|
8296
|
+
let bytes = run2.payload === void 0 ? 0 : payloadBytes(run2.payload);
|
|
8297
|
+
bytes > payloadLimit2 && errors.push(MESSAGES.DEFAULT_PAYLOAD_OVER_LIMIT(source, bytes, payloadLimit2));
|
|
8205
8298
|
}
|
|
8206
8299
|
let resolved = resolveNature(config.execution, PLATFORM_DEFAULT_NATURE);
|
|
8207
8300
|
return resolved.ok ? warnings.push(...resolved.warnings) : errors.push(resolved.error), { ok: errors.length === 0, errors, warnings };
|
|
@@ -8223,26 +8316,26 @@ function checkTaskConfigText(text, source) {
|
|
|
8223
8316
|
return errors.push(...shared.errors), errors.length > 0 ? { ok: false, errors, warnings: shared.warnings } : { ok: true, config, errors, warnings: shared.warnings };
|
|
8224
8317
|
}
|
|
8225
8318
|
function slugDirRefusal(slug2, taskDir) {
|
|
8226
|
-
let dirName =
|
|
8319
|
+
let dirName = import_node_path3.default.basename(taskDir);
|
|
8227
8320
|
return slug2 === dirName ? null : `task.yaml slug "${slug2}" must match the task directory name "${dirName}". Every local lookup names the task by its directory, but runs dispatch by slug. Set slug: "${dirName}" or rename the directory.`;
|
|
8228
8321
|
}
|
|
8229
8322
|
function findTaskConfigFile(taskDir) {
|
|
8230
|
-
let name =
|
|
8231
|
-
return name === null ? null :
|
|
8323
|
+
let name = import_node_fs4.default.existsSync(taskDir) ? rootConfigName(import_node_fs4.default.readdirSync(taskDir)) : null;
|
|
8324
|
+
return name === null ? null : import_node_path3.default.join(taskDir, name);
|
|
8232
8325
|
}
|
|
8233
8326
|
function readTaskConfigFile(taskDir) {
|
|
8234
8327
|
let file = findTaskConfigFile(taskDir);
|
|
8235
8328
|
if (!file) return { ok: false, file: null, errors: [`No ${TASK_CONFIG_FILENAMES.join(" / ")} found in ${taskDir}`], warnings: [] };
|
|
8236
|
-
let parsed = checkTaskConfigText(
|
|
8329
|
+
let parsed = checkTaskConfigText(import_node_fs4.default.readFileSync(file, "utf8"), import_node_path3.default.basename(file)), slugError = parsed.ok ? slugDirRefusal(parsed.config.slug, taskDir) : null;
|
|
8237
8330
|
return slugError !== null ? { ok: false, file, errors: [slugError], warnings: parsed.warnings } : { ...parsed, file };
|
|
8238
8331
|
}
|
|
8239
8332
|
function resolvedEntry(config) {
|
|
8240
8333
|
return config.entry ?? RUNTIME_REGISTRY[config.runtime].entryFile;
|
|
8241
8334
|
}
|
|
8242
|
-
var
|
|
8335
|
+
var import_node_fs4, import_node_path3, init_task_config3 = __esm({ "src/io/task-config.ts"() {
|
|
8243
8336
|
"use strict";
|
|
8244
8337
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
8245
|
-
|
|
8338
|
+
import_node_fs4 = __toESM(require("node:fs"), 1), import_node_path3 = __toESM(require("node:path"), 1);
|
|
8246
8339
|
init_tenant();
|
|
8247
8340
|
init_task_config2();
|
|
8248
8341
|
init_validate2();
|
|
@@ -8256,7 +8349,7 @@ function readTaskFolders(baseDir) {
|
|
|
8256
8349
|
try {
|
|
8257
8350
|
return { dir, state: readState(dir) };
|
|
8258
8351
|
} catch (e) {
|
|
8259
|
-
throw new Error(`cannot read ${taskLinkPath(dir)}: ${
|
|
8352
|
+
throw new Error(`cannot read ${taskLinkPath(dir)}: ${errText(e)}`, { cause: e });
|
|
8260
8353
|
}
|
|
8261
8354
|
}) : [];
|
|
8262
8355
|
}
|
|
@@ -8279,7 +8372,7 @@ async function prepareTask(args, cwd, taskId = requiredArg(args)) {
|
|
|
8279
8372
|
for (let e of read.errors) fail(e);
|
|
8280
8373
|
return null;
|
|
8281
8374
|
}
|
|
8282
|
-
return { taskDir, config: read.config, warnings: read.warnings };
|
|
8375
|
+
return { taskDir, config: read.config, slug: read.config.slug ?? import_path2.default.basename(taskDir), warnings: read.warnings };
|
|
8283
8376
|
}
|
|
8284
8377
|
var import_fs2, import_path2, init_task_path = __esm({ "src/io/task-path.ts"() {
|
|
8285
8378
|
"use strict";
|
|
@@ -8290,7 +8383,7 @@ var import_fs2, import_path2, init_task_path = __esm({ "src/io/task-path.ts"() {
|
|
|
8290
8383
|
init_output();
|
|
8291
8384
|
init_constants();
|
|
8292
8385
|
init_args2();
|
|
8293
|
-
|
|
8386
|
+
init_tenant();
|
|
8294
8387
|
} });
|
|
8295
8388
|
function compile(body, anchored) {
|
|
8296
8389
|
let segs = body.split("/");
|
|
@@ -8337,11 +8430,11 @@ var UNSUPPORTED_CHARS, escapeRegex, segmentSource, init_ignore_file = __esm({ "s
|
|
|
8337
8430
|
} });
|
|
8338
8431
|
function scanSourceTree(root, maxBytes = UPLOAD_MAX_BYTES, ignoreRules = []) {
|
|
8339
8432
|
let entries = [], data = /* @__PURE__ */ new Map(), errors = [], warnings = [], ignored = [], totalBytes = 0, over = false;
|
|
8340
|
-
if (!
|
|
8433
|
+
if (!import_node_fs5.default.existsSync(root)) return { entries, data, errors: [`Task directory does not exist: ${root}`], warnings, ignored, totalBytes, truncated: false };
|
|
8341
8434
|
let walk = (dir) => {
|
|
8342
|
-
for (let dirent of
|
|
8435
|
+
for (let dirent of import_node_fs5.default.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : 1)) {
|
|
8343
8436
|
if (over) return;
|
|
8344
|
-
let abs =
|
|
8437
|
+
let abs = import_node_path4.default.join(dir, dirent.name), rel = import_node_path4.default.relative(root, abs).split(import_node_path4.default.sep).join("/"), skip = excludeReason(rel);
|
|
8345
8438
|
if (skip) {
|
|
8346
8439
|
dirent.isDirectory() || warnings.push(`excluded ${rel} \u2014 ${skip}`);
|
|
8347
8440
|
continue;
|
|
@@ -8369,7 +8462,7 @@ function scanSourceTree(root, maxBytes = UPLOAD_MAX_BYTES, ignoreRules = []) {
|
|
|
8369
8462
|
errors.push(symlinkRefusal(rel));
|
|
8370
8463
|
continue;
|
|
8371
8464
|
}
|
|
8372
|
-
let { fd, st } = opened,
|
|
8465
|
+
let { fd, st } = opened, bytes;
|
|
8373
8466
|
try {
|
|
8374
8467
|
if (!st.isFile()) {
|
|
8375
8468
|
errors.push(notRegularRefusal(rel));
|
|
@@ -8379,34 +8472,35 @@ function scanSourceTree(root, maxBytes = UPLOAD_MAX_BYTES, ignoreRules = []) {
|
|
|
8379
8472
|
over = true, errors.push(`the task directory holds more than ${maxBytes / MIB} MiB of files (reached at ${rel}); the server refuses a larger upload`);
|
|
8380
8473
|
return;
|
|
8381
8474
|
}
|
|
8382
|
-
|
|
8475
|
+
bytes = import_node_fs5.default.readFileSync(fd);
|
|
8383
8476
|
} finally {
|
|
8384
|
-
|
|
8477
|
+
import_node_fs5.default.closeSync(fd);
|
|
8385
8478
|
}
|
|
8386
8479
|
if (CREDENTIAL_CHECKED_FILES.includes(dirent.name)) {
|
|
8387
|
-
let cred = credentialReason(rel,
|
|
8480
|
+
let cred = credentialReason(rel, bytes.toString("utf8"));
|
|
8388
8481
|
if (cred !== null) {
|
|
8389
8482
|
errors.push(cred);
|
|
8390
8483
|
continue;
|
|
8391
8484
|
}
|
|
8392
8485
|
}
|
|
8393
8486
|
let keyWarning = privateKeyFileWarning(rel);
|
|
8394
|
-
keyWarning !== null && warnings.push(keyWarning), entries.push({ path: rel, exec: (st.mode & 73) !== 0, size:
|
|
8487
|
+
keyWarning !== null && warnings.push(keyWarning), entries.push({ path: rel, exec: (st.mode & 73) !== 0, size: bytes.length, sha256: import_node_crypto3.default.createHash("sha256").update(bytes).digest("hex") }), data.set(rel, bytes), totalBytes += bytes.length;
|
|
8395
8488
|
}
|
|
8396
8489
|
};
|
|
8397
8490
|
return walk(root), { entries, data, errors, warnings, ignored, totalBytes, truncated: over };
|
|
8398
8491
|
}
|
|
8399
8492
|
function computeSourceHash(entries, config) {
|
|
8400
|
-
|
|
8493
|
+
let manifest = checkSourceManifest(entries, config);
|
|
8494
|
+
return manifest.ok ? { ok: true, hash: `sha256:${import_node_crypto3.default.createHash("sha256").update(manifest.text, "utf8").digest("hex")}` } : manifest;
|
|
8401
8495
|
}
|
|
8402
8496
|
function checkLockfile(entries, runtime) {
|
|
8403
8497
|
let required = RUNTIME_REGISTRY[runtime].lockfile;
|
|
8404
8498
|
return entries.some((e) => e.path === required) ? null : `${required} is missing. A ${runtime} task must upload its lockfile: without one the build is not reproducible and two deployments of the same source can resolve different versions.`;
|
|
8405
8499
|
}
|
|
8406
|
-
var
|
|
8500
|
+
var import_node_fs5, import_node_path4, import_node_crypto3, MIB, symlinkRefusal, notRegularRefusal, init_source_tree = __esm({ "src/io/source-tree.ts"() {
|
|
8407
8501
|
"use strict";
|
|
8408
8502
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
8409
|
-
|
|
8503
|
+
import_node_fs5 = __toESM(require("node:fs"), 1), import_node_path4 = __toESM(require("node:path"), 1), import_node_crypto3 = __toESM(require("node:crypto"), 1);
|
|
8410
8504
|
init_tenant();
|
|
8411
8505
|
init_ignore_file();
|
|
8412
8506
|
init_constants();
|
|
@@ -8504,8 +8598,8 @@ var NAME_BYTES, MODE_FILE, MODE_EXEC, TYPE_FILE, TYPE_PAX, PAX_HEADER_NAME, TarF
|
|
|
8504
8598
|
};
|
|
8505
8599
|
} });
|
|
8506
8600
|
function readIgnoreRules(taskDir, protectedPaths) {
|
|
8507
|
-
let file =
|
|
8508
|
-
return
|
|
8601
|
+
let file = import_node_path5.default.join(taskDir, IGNORE_FILE);
|
|
8602
|
+
return import_node_fs6.default.existsSync(file) ? parseIgnoreFile(import_node_fs6.default.readFileSync(file, "utf8"), IGNORE_FILE, protectedPaths) : { ok: true, rules: [] };
|
|
8509
8603
|
}
|
|
8510
8604
|
function checkSourceUpload(taskDir) {
|
|
8511
8605
|
let read = readTaskConfigFile(taskDir), warnings = [...read.warnings];
|
|
@@ -8520,13 +8614,8 @@ function checkSourceUpload(taskDir) {
|
|
|
8520
8614
|
scan.entries.some((e) => e.path === entry) || errors.push(`the entry file "${entry}" is not in the upload.`);
|
|
8521
8615
|
}
|
|
8522
8616
|
if (errors.length > 0) return { ok: false, errors, warnings };
|
|
8523
|
-
let
|
|
8524
|
-
|
|
8525
|
-
contentHash = computeSourceHash(scan.entries, { name: import_node_path4.default.basename(read.file ?? ""), value: config });
|
|
8526
|
-
} catch (e) {
|
|
8527
|
-
return { ok: false, errors: [e.message.replace(/^source manifest: /, "")], warnings };
|
|
8528
|
-
}
|
|
8529
|
-
return { ok: true, source: { config, entries: scan.entries, data: scan.data, totalBytes: scan.totalBytes, ignored: scan.ignored, contentHash }, warnings };
|
|
8617
|
+
let key = computeSourceHash(scan.entries, { name: import_node_path5.default.basename(read.file ?? ""), value: config });
|
|
8618
|
+
return key.ok ? { ok: true, source: { config, entries: scan.entries, data: scan.data, totalBytes: scan.totalBytes, ignored: scan.ignored, contentHash: key.hash }, warnings } : { ok: false, errors: [key.reason], warnings };
|
|
8530
8619
|
}
|
|
8531
8620
|
function prepareSourceUpload(taskDir) {
|
|
8532
8621
|
let check = checkSourceUpload(taskDir);
|
|
@@ -8534,10 +8623,10 @@ function prepareSourceUpload(taskDir) {
|
|
|
8534
8623
|
let { warnings } = check, { config, entries, data, totalBytes, ignored, contentHash } = check.source, tar = packTarball(entries.map((e) => ({ name: e.path, data: data.get(e.path), exec: e.exec })));
|
|
8535
8624
|
return { ok: true, upload: { manifest: { contentHash, format: "source", ...config.execution ? { execution: config.execution } : {}, ...config.secrets?.length ? { secrets: [...config.secrets] } : {} }, tar, slug: config.slug, files: entries.length, totalBytes, ignored }, warnings };
|
|
8536
8625
|
}
|
|
8537
|
-
var
|
|
8626
|
+
var import_node_fs6, import_node_path5, init_source_upload = __esm({ "src/io/source-upload.ts"() {
|
|
8538
8627
|
"use strict";
|
|
8539
8628
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
8540
|
-
|
|
8629
|
+
import_node_fs6 = __toESM(require("node:fs"), 1), import_node_path5 = __toESM(require("node:path"), 1);
|
|
8541
8630
|
init_tenant();
|
|
8542
8631
|
init_ignore_file();
|
|
8543
8632
|
init_constants();
|
|
@@ -8798,9 +8887,9 @@ function packagesRoot() {
|
|
|
8798
8887
|
}
|
|
8799
8888
|
function checkoutReader(root = packagesRoot()) {
|
|
8800
8889
|
return (pkg, rel) => {
|
|
8801
|
-
let abs =
|
|
8890
|
+
let abs = import_node_path6.default.join(root, pkg, rel);
|
|
8802
8891
|
try {
|
|
8803
|
-
return
|
|
8892
|
+
return import_node_fs7.default.readFileSync(abs, "utf8");
|
|
8804
8893
|
} catch {
|
|
8805
8894
|
throw new Error(`the runtime client source ${abs} is not readable. A Go or Rust scaffold carries the client from packages/${pkg}, so this CLI must run from a checkout of the repository.`);
|
|
8806
8895
|
}
|
|
@@ -8878,10 +8967,10 @@ function rustScaffoldLock(pkgName, read = clientReader()) {
|
|
|
8878
8967
|
`) + `
|
|
8879
8968
|
`;
|
|
8880
8969
|
}
|
|
8881
|
-
var
|
|
8970
|
+
var import_node_fs7, import_node_path6, import_node_sea, import_node_url, VENDOR_DIR, CLIENT_FILES, CARGO_RESERVED, init_vendor = __esm({ "src/scaffold/vendor.ts"() {
|
|
8882
8971
|
"use strict";
|
|
8883
8972
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
8884
|
-
|
|
8973
|
+
import_node_fs7 = __toESM(require("node:fs"), 1), import_node_path6 = __toESM(require("node:path"), 1), import_node_sea = __toESM(require("node:sea"), 1), import_node_url = require("node:url"), VENDOR_DIR = "ignitify", CLIENT_FILES = { go: { pkg: "runtime-go", files: ["go.mod", "runtime.go"] }, rust: { pkg: "runtime-rust", files: ["Cargo.toml", "src/lib.rs"] } };
|
|
8885
8974
|
CARGO_RESERVED = /* @__PURE__ */ new Set(["build", "deps", "examples", "incremental"]);
|
|
8886
8975
|
} });
|
|
8887
8976
|
function templateFiles(taskId, runtime, withInit, dirFlag) {
|
|
@@ -8906,7 +8995,7 @@ function scaffoldTaskFiles(taskId, taskDir, withInit, dirFlag, runtime = "node")
|
|
|
8906
8995
|
try {
|
|
8907
8996
|
files = templateFiles(taskId, runtime, withInit, dirFlag);
|
|
8908
8997
|
} catch (e) {
|
|
8909
|
-
return
|
|
8998
|
+
return errText(e);
|
|
8910
8999
|
}
|
|
8911
9000
|
if (import_fs3.default.existsSync(taskDir)) {
|
|
8912
9001
|
let clashes = [.../* @__PURE__ */ new Set([...TASK_CONFIG_FILENAMES, ...Object.keys(files)])].filter((f) => import_fs3.default.existsSync(import_path3.default.join(taskDir, f)));
|
|
@@ -8926,40 +9015,6 @@ var import_fs3, import_path3, init_scaffold = __esm({ "src/scaffold/index.ts"()
|
|
|
8926
9015
|
init_templates();
|
|
8927
9016
|
init_vendor();
|
|
8928
9017
|
} });
|
|
8929
|
-
function backoffDelayMs(attempt, cadence) {
|
|
8930
|
-
return Math.min(cadence.BASE_MS * 2 ** Math.max(0, attempt), cadence.MAX_MS);
|
|
8931
|
-
}
|
|
8932
|
-
function isTransientPollError(e) {
|
|
8933
|
-
return e instanceof HttpError ? e.status === 408 || e.status === 429 || e.status >= 500 && e.status <= 599 : e instanceof TypeError ? true : e instanceof Error && e.cause?.name === "TimeoutError";
|
|
8934
|
-
}
|
|
8935
|
-
function decidePollError(e, failuresInARow, failingForMs) {
|
|
8936
|
-
return isTransientPollError(e) ? failuresInARow >= POLL.ERROR.MIN_TRIES && failingForMs >= POLL.ERROR.GRACE_MS ? "give-up" : "retry" : "give-up";
|
|
8937
|
-
}
|
|
8938
|
-
async function pollUntil(loop) {
|
|
8939
|
-
let sleep = loop.clock?.sleep ?? REAL_CLOCK.sleep, now = loop.clock?.now ?? REAL_CLOCK.now, startedAt = now(), failures = 0, firstFailureAt = 0;
|
|
8940
|
-
for (let attempt = 0; ; ) {
|
|
8941
|
-
let view;
|
|
8942
|
-
try {
|
|
8943
|
-
view = await loop.fetch();
|
|
8944
|
-
} catch (error) {
|
|
8945
|
-
if (failures === 0 && (firstFailureAt = now()), failures += 1, decidePollError(error, failures, now() - firstFailureAt) === "give-up") return { kind: "lost", error };
|
|
8946
|
-
loop.onRetry?.(error), await sleep(loop.retryDelayMs);
|
|
8947
|
-
continue;
|
|
8948
|
-
}
|
|
8949
|
-
failures = 0, loop.onView?.(view);
|
|
8950
|
-
let action = loop.decide(view, now() - startedAt, attempt);
|
|
8951
|
-
if (!isWait(action)) return { action, view };
|
|
8952
|
-
loop.onWait?.(view, attempt), await sleep(action.delayMs), attempt += 1;
|
|
8953
|
-
}
|
|
8954
|
-
}
|
|
8955
|
-
var isWait, isLost, init_poll = __esm({ "src/core/poll.ts"() {
|
|
8956
|
-
"use strict";
|
|
8957
|
-
init_define_IGNITIFY_CLIENT_FILES();
|
|
8958
|
-
init_http_client();
|
|
8959
|
-
init_constants();
|
|
8960
|
-
init_utils();
|
|
8961
|
-
isWait = (action) => action.kind === "wait", isLost = (end) => "kind" in end && end.kind === "lost";
|
|
8962
|
-
} });
|
|
8963
9018
|
function decidePoll(status, elapsedMs, attempt, failureReason) {
|
|
8964
9019
|
return status === READY ? { kind: "ready" } : status === FAILED ? { kind: "failed", reason: failureReason ?? "the build failed without recording a reason" } : status !== BUILDING ? { kind: "failed", reason: `deployment entered an unexpected status: ${status}` } : elapsedMs >= POLL.DEPLOY.TIMEOUT_MS ? { kind: "timeout" } : { kind: "wait", delayMs: nextDelayMs(attempt) };
|
|
8965
9020
|
}
|
|
@@ -9001,14 +9056,14 @@ async function waitForBuild(cfg, deploymentId, progress, reused = false) {
|
|
|
9001
9056
|
let view = await getApiDeploymentStatus(cfg, deploymentId);
|
|
9002
9057
|
return retrying && (retrying = false, progress.update(WAIT.BUILDING(deploymentId), WAIT.HINT_BUILD)), view;
|
|
9003
9058
|
}, fetchLog: async () => {
|
|
9004
|
-
let { bytes
|
|
9005
|
-
return typeof
|
|
9059
|
+
let { bytes } = await getApiDeploymentLogs(cfg, deploymentId);
|
|
9060
|
+
return typeof bytes == "string" && bytes !== "" ? bytes : null;
|
|
9006
9061
|
}, onBuilding: () => {
|
|
9007
9062
|
building = true, progress.update(WAIT.BUILDING(deploymentId), WAIT.HINT_BUILD);
|
|
9008
9063
|
}, onRetry: () => {
|
|
9009
9064
|
retrying = true, progress.update(WAIT.BUILDING(deploymentId), WAIT.HINT_RETRYING);
|
|
9010
9065
|
} }));
|
|
9011
|
-
if (built.kind === "lost") return progress.fail(WAIT.LOST), fail(WAIT.LOST_BUILD_DETAIL(deploymentId,
|
|
9066
|
+
if (built.kind === "lost") return progress.fail(WAIT.LOST), fail(WAIT.LOST_BUILD_DETAIL(deploymentId, errText(built.error))), 1;
|
|
9012
9067
|
if (built.kind === "failed") {
|
|
9013
9068
|
if (progress.fail(WAIT.BUILD_FAILED), fail(WAIT.BUILD_FAILED_DETAIL(deploymentId, built.reason)), built.log) {
|
|
9014
9069
|
let st = errStyle();
|
|
@@ -9024,7 +9079,7 @@ async function waitForRun(cfg, runId) {
|
|
|
9024
9079
|
let progress = startProgress(WAIT.RUN_SUBMITTED(runId)), lastStatus, settled = await withInterruptNotice(progress, () => WAIT.INTERRUPTED_RUN(runId), () => pollUntilSettled({ fetchRun: () => getApiRun(cfg, runId), onStatus: (status) => {
|
|
9025
9080
|
lastStatus = status, progress.update(WAIT.RUN(runId, status), WAIT.HINT_RUN);
|
|
9026
9081
|
}, onRetry: () => progress.update(lastStatus === void 0 ? WAIT.RUN_SUBMITTED(runId) : WAIT.RUN(runId, lastStatus), WAIT.HINT_RETRYING) }));
|
|
9027
|
-
if (isLost(settled)) return progress.fail(WAIT.LOST), fail(WAIT.LOST_RUN_DETAIL(runId,
|
|
9082
|
+
if (isLost(settled)) return progress.fail(WAIT.LOST), fail(WAIT.LOST_RUN_DETAIL(runId, errText(settled.error))), 1;
|
|
9028
9083
|
let { action, run: run2 } = settled;
|
|
9029
9084
|
if (action.kind === "timeout") return progress.fail(WAIT.RUN_TIMEOUT(action.status)), warn(WAIT.RUN_TIMEOUT_DETAIL(runId)), 1;
|
|
9030
9085
|
let completed = action.status === RUN_STATUS.COMPLETED;
|
|
@@ -9039,7 +9094,7 @@ var init_wait = __esm({ "src/commands/wait.ts"() {
|
|
|
9039
9094
|
init_poll();
|
|
9040
9095
|
init_output();
|
|
9041
9096
|
init_constants();
|
|
9042
|
-
|
|
9097
|
+
init_tenant();
|
|
9043
9098
|
} });
|
|
9044
9099
|
var MANIFEST_FILE, PACKAGE_SCOPE, RUNTIMES, NETWORK_TYPES, PRESETS, DURATIONS, INTERACTIONS, NAME_PATTERN, CALLBACK_ROUTE_PREFIX, EGRESS_HINT_PATTERN, DNS_LABEL, HOST_PATTERN, HOST_MAX_LENGTH, init_constants3 = __esm({ "../../node_modules/@ignitify-integrations/core/dist/constants.js"() {
|
|
9045
9100
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
@@ -12715,8 +12770,8 @@ var require_parser = __commonJS({ "../../node_modules/yaml/dist/parse/parser.js"
|
|
|
12715
12770
|
case "scalar":
|
|
12716
12771
|
case "single-quoted-scalar":
|
|
12717
12772
|
case "double-quoted-scalar": {
|
|
12718
|
-
let
|
|
12719
|
-
atNextItem || it.value ? (map2.items.push({ start, key:
|
|
12773
|
+
let fs14 = this.flowScalar(this.type);
|
|
12774
|
+
atNextItem || it.value ? (map2.items.push({ start, key: fs14, sep: [] }), this.onKeyLine = true) : it.sep ? this.stack.push(fs14) : (Object.assign(it, { key: fs14, sep: [] }), this.onKeyLine = true);
|
|
12720
12775
|
return;
|
|
12721
12776
|
}
|
|
12722
12777
|
default: {
|
|
@@ -12805,8 +12860,8 @@ var require_parser = __commonJS({ "../../node_modules/yaml/dist/parse/parser.js"
|
|
|
12805
12860
|
case "scalar":
|
|
12806
12861
|
case "single-quoted-scalar":
|
|
12807
12862
|
case "double-quoted-scalar": {
|
|
12808
|
-
let
|
|
12809
|
-
!it || it.value ? fc.items.push({ start: [], key:
|
|
12863
|
+
let fs14 = this.flowScalar(this.type);
|
|
12864
|
+
!it || it.value ? fc.items.push({ start: [], key: fs14, sep: [] }) : it.sep ? this.stack.push(fs14) : Object.assign(it, { key: fs14, sep: [] });
|
|
12810
12865
|
return;
|
|
12811
12866
|
}
|
|
12812
12867
|
case "flow-map-end":
|
|
@@ -12981,21 +13036,25 @@ var ok, err, init_result2 = __esm({ "../../node_modules/@ignitify-integrations/r
|
|
|
12981
13036
|
var init_ctx = __esm({ "../../node_modules/@ignitify-integrations/runtime/dist/ctx.js"() {
|
|
12982
13037
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
12983
13038
|
} });
|
|
12984
|
-
var SECRET_NAME_PATTERN, init_secrets = __esm({ "../../node_modules/@ignitify-integrations/runtime/dist/secrets.js"() {
|
|
13039
|
+
var SECRET_NAME_MAX_LENGTH, SECRET_NAME_PATTERN, init_secrets = __esm({ "../../node_modules/@ignitify-integrations/runtime/dist/secrets.js"() {
|
|
12985
13040
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
12986
13041
|
init_result2();
|
|
12987
|
-
SECRET_NAME_PATTERN =
|
|
13042
|
+
SECRET_NAME_MAX_LENGTH = 64, SECRET_NAME_PATTERN = new RegExp(`^[A-Z][A-Z0-9_]{0,${SECRET_NAME_MAX_LENGTH - 1}}$`);
|
|
12988
13043
|
} });
|
|
12989
13044
|
var ROUTE_PREFIX_PATTERN, init_platform = __esm({ "../../node_modules/@ignitify-integrations/runtime/dist/platform.js"() {
|
|
12990
13045
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
12991
13046
|
ROUTE_PREFIX_PATTERN = "^/[a-z0-9._~-]+(/[a-z0-9._~-]+)*/$";
|
|
12992
13047
|
} });
|
|
13048
|
+
var init_stop = __esm({ "../../node_modules/@ignitify-integrations/runtime/dist/stop.js"() {
|
|
13049
|
+
init_define_IGNITIFY_CLIENT_FILES();
|
|
13050
|
+
} });
|
|
12993
13051
|
var init_dist = __esm({ "../../node_modules/@ignitify-integrations/runtime/dist/index.js"() {
|
|
12994
13052
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
12995
13053
|
init_result2();
|
|
12996
13054
|
init_ctx();
|
|
12997
13055
|
init_secrets();
|
|
12998
13056
|
init_platform();
|
|
13057
|
+
init_stop();
|
|
12999
13058
|
} });
|
|
13000
13059
|
var list, MANIFEST_MESSAGES, PLAN_MESSAGES, COVERAGE_MESSAGES, init_messages = __esm({ "../../node_modules/@ignitify-integrations/core/dist/messages.js"() {
|
|
13001
13060
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
@@ -13006,7 +13065,7 @@ var nonEmptyString, uniqueStrings, closed, network, MANIFEST_SCHEMA, init_schema
|
|
|
13006
13065
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13007
13066
|
init_dist();
|
|
13008
13067
|
init_constants3();
|
|
13009
|
-
nonEmptyString = { type: "string", minLength: 1 }, uniqueStrings = { type: "array", items: nonEmptyString, uniqueItems: true }, closed = (properties, required = []) => ({ type: "object", additionalProperties: false, properties, required }), network = closed({ type: { enum: NETWORK_TYPES }, egress_allow: { type: "array", items: { type: "string", minLength: 1, maxLength: HOST_MAX_LENGTH }, uniqueItems: true, maxItems: 32 }, egress_hint: { type: "string", minLength: 1, maxLength: 200, pattern: EGRESS_HINT_PATTERN }, inbound_port: { type: "integer", minimum: 1024, maximum: 65535 }, inbound_routes: { type: "array", minItems: 1, items: closed({ prefix: { type: "string", pattern: ROUTE_PREFIX_PATTERN } }, ["prefix"]) }, inbound_max_concurrent: { type: "integer", minimum: 1 } }, ["type"]), MANIFEST_SCHEMA = { $schema: "https://json-schema.org/draft/2020-12/schema", title: "ignitify integration manifest", ...closed({ schema_version: { const: 1 }, name: { type: "string", pattern: NAME_PATTERN }, runtimes: { type: "array", items: { enum: RUNTIMES }, minItems: 1, uniqueItems: true }, secrets: { type: "array", items: { type: "string", pattern: SECRET_NAME_PATTERN.source }, uniqueItems: true }, network, execution: closed({ duration: { enum: DURATIONS }, interaction: { enum: INTERACTIONS } }), system_packages: uniqueStrings, min_preset: { enum: PRESETS } }, ["schema_version", "name", "runtimes"]) };
|
|
13068
|
+
nonEmptyString = { type: "string", minLength: 1 }, uniqueStrings = { type: "array", items: nonEmptyString, uniqueItems: true }, closed = (properties, required = []) => ({ type: "object", additionalProperties: false, properties, required }), network = closed({ type: { enum: NETWORK_TYPES }, egress_allow: { type: "array", items: { type: "string", minLength: 1, maxLength: HOST_MAX_LENGTH }, uniqueItems: true, maxItems: 32 }, egress_hint: { type: "string", minLength: 1, maxLength: 200, pattern: EGRESS_HINT_PATTERN }, inbound_port: { type: "integer", minimum: 1024, maximum: 65535 }, inbound_routes: { type: "array", minItems: 1, maxItems: 32, items: closed({ prefix: { type: "string", maxLength: 256, pattern: ROUTE_PREFIX_PATTERN } }, ["prefix"]) }, inbound_max_concurrent: { type: "integer", minimum: 1 } }, ["type"]), MANIFEST_SCHEMA = { $schema: "https://json-schema.org/draft/2020-12/schema", title: "ignitify integration manifest", ...closed({ schema_version: { const: 1 }, name: { type: "string", pattern: NAME_PATTERN }, runtimes: { type: "array", items: { enum: RUNTIMES }, minItems: 1, uniqueItems: true }, secrets: { type: "array", items: { type: "string", maxLength: SECRET_NAME_MAX_LENGTH, pattern: SECRET_NAME_PATTERN.source }, uniqueItems: true }, network, execution: closed({ duration: { enum: DURATIONS }, interaction: { enum: INTERACTIONS } }), system_packages: uniqueStrings, min_preset: { enum: PRESETS } }, ["schema_version", "name", "runtimes"]) };
|
|
13010
13069
|
} });
|
|
13011
13070
|
var import__2, import_yaml, INBOUND_KEYS, EGRESS_KEYS, ROOT_PATH, NUMERIC_LABEL, validate, isHostName, loadYaml, formatError, semanticIssues, parseManifest, init_manifest = __esm({ "../../node_modules/@ignitify-integrations/core/dist/manifest.js"() {
|
|
13012
13071
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
@@ -13041,7 +13100,7 @@ var packageName, hasCode, rank, maxOf, union, optional, init_utils2 = __esm({ ".
|
|
|
13041
13100
|
init_constants3();
|
|
13042
13101
|
packageName = (name) => `${PACKAGE_SCOPE}/${name}`, hasCode = (packageJson) => typeof packageJson == "object" && packageJson !== null && "exports" in packageJson, rank = (order, value) => order.indexOf(value), maxOf = (order, a, b) => rank(order, a) >= rank(order, b) ? a : b, union = (a, b) => [.../* @__PURE__ */ new Set([...a, ...b])], optional = (key, value) => value === void 0 ? {} : { [key]: value };
|
|
13043
13102
|
} });
|
|
13044
|
-
var EXECUTION_FIELDS, INBOUND_FIELDS, needsOf, planHeadline, pick, unionRoutes, egressFor, networkFor, presetFor, planAdd, coverageIssues, checkCoverage, init_plan = __esm({ "../../node_modules/@ignitify-integrations/core/dist/plan.js"() {
|
|
13103
|
+
var EXECUTION_FIELDS, INBOUND_FIELDS, needsOf, planHeadline, pick, prefixOf, unionRoutes, egressFor, networkFor, presetFor, planAdd, coverageIssues, checkCoverage, init_plan = __esm({ "../../node_modules/@ignitify-integrations/core/dist/plan.js"() {
|
|
13045
13104
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13046
13105
|
init_dist();
|
|
13047
13106
|
init_constants3();
|
|
@@ -13050,7 +13109,7 @@ var EXECUTION_FIELDS, INBOUND_FIELDS, needsOf, planHeadline, pick, unionRoutes,
|
|
|
13050
13109
|
EXECUTION_FIELDS = ["duration", "interaction"], INBOUND_FIELDS = ["inbound_port", "inbound_max_concurrent"], needsOf = (manifest) => ({ hosts: manifest.network?.egress_allow ?? [], secrets: manifest.secrets ?? [], networkType: manifest.network?.type ?? "none", inbound_port: manifest.network?.inbound_port, inbound_max_concurrent: manifest.network?.inbound_max_concurrent, inboundRoutes: manifest.network?.inbound_routes ?? [], execution: manifest.execution ?? {}, systemPackages: manifest.system_packages ?? [], minPreset: manifest.min_preset }), planHeadline = (manifest, version2, hasCode2) => {
|
|
13051
13110
|
let packages = manifest.system_packages ?? [];
|
|
13052
13111
|
return [`${packageName(manifest.name)}@${version2}`, hasCode2 ? PLAN_MESSAGES.settingsAndCode : PLAN_MESSAGES.settingsOnly, ...packages.length > 0 ? [PLAN_MESSAGES.runs(packages)] : []].join(" \xB7 ");
|
|
13053
|
-
}, pick = (field, current, wanted, label) => wanted === void 0 || current === wanted ? { value: current } : current === void 0 ? { value: wanted } : { value: current, conflict: PLAN_MESSAGES.conflict(field, current, wanted, label) }, unionRoutes = (current, wanted) => [...current, ...wanted.filter((route2) => !current.some((have) => have
|
|
13112
|
+
}, pick = (field, current, wanted, label) => wanted === void 0 || current === wanted ? { value: current } : current === void 0 ? { value: wanted } : { value: current, conflict: PLAN_MESSAGES.conflict(field, current, wanted, label) }, prefixOf = (route2) => "prefix" in route2 ? route2.prefix : void 0, unionRoutes = (current, wanted) => [...current, ...wanted.filter((route2) => !current.some((have) => prefixOf(have) === route2.prefix))], egressFor = (current, needs, notes) => {
|
|
13054
13113
|
if (current?.egress_allow !== void 0) return union(current.egress_allow, needs.hosts);
|
|
13055
13114
|
if ((current?.type ?? "none") !== "none") {
|
|
13056
13115
|
needs.hosts.length > 0 && notes.push(PLAN_MESSAGES.egressAnywhere(needs.hosts));
|
|
@@ -13088,7 +13147,7 @@ var EXECUTION_FIELDS, INBOUND_FIELDS, needsOf, planHeadline, pick, unionRoutes,
|
|
|
13088
13147
|
}), ...INBOUND_FIELDS.flatMap((field) => {
|
|
13089
13148
|
let need = needs[field];
|
|
13090
13149
|
return need === void 0 || network2?.[field] === need ? [] : [COVERAGE_MESSAGES.fieldMismatch(label, `execution.network.${field}`, network2?.[field], need)];
|
|
13091
|
-
}), ...needs.inboundRoutes.filter((route2) => !routes.some((present) => present
|
|
13150
|
+
}), ...needs.inboundRoutes.filter((route2) => !routes.some((present) => prefixOf(present) === route2.prefix)).map((route2) => COVERAGE_MESSAGES.routeMissing(label, route2.prefix)), ...needs.systemPackages.filter((name) => !packages.includes(name)).map((name) => COVERAGE_MESSAGES.packageMissing(label, name)), ...needs.minPreset !== void 0 && (preset === void 0 || presetRank >= 0 && presetRank < rank(PRESETS, needs.minPreset)) ? [COVERAGE_MESSAGES.presetTooSmall(label, preset, needs.minPreset)] : []];
|
|
13092
13151
|
}, checkCoverage = (config, manifests) => manifests.flatMap((manifest) => coverageIssues(config, packageName(manifest.name), needsOf(manifest)));
|
|
13093
13152
|
} });
|
|
13094
13153
|
var init_dist2 = __esm({ "../../node_modules/@ignitify-integrations/core/dist/index.js"() {
|
|
@@ -13105,31 +13164,38 @@ function diffLines(before, after, path12 = []) {
|
|
|
13105
13164
|
let had = Array.isArray(before) ? before : [], added = after.filter((item) => !had.some((old2) => (0, import_node_util.isDeepStrictEqual)(old2, item)));
|
|
13106
13165
|
return added.length > 0 ? [`+ ${here}: ${added.map(itemText).join(", ")}`] : [];
|
|
13107
13166
|
}
|
|
13108
|
-
if (!
|
|
13109
|
-
let old =
|
|
13167
|
+
if (!isRecord(after)) return before === void 0 || (0, import_node_util.isDeepStrictEqual)(before, after) || INTEGRATION.NOTED_FIELDS.includes(here) ? [] : [`${here}: ${String(before)} -> ${String(after)}`];
|
|
13168
|
+
let old = isRecord(before) ? before : {}, newScalars = [], nested = [];
|
|
13110
13169
|
for (let [key, value] of Object.entries(after)) {
|
|
13111
13170
|
let fieldPath = [...path12, key];
|
|
13112
|
-
old[key] === void 0 && !Array.isArray(value) && !
|
|
13171
|
+
old[key] === void 0 && !Array.isArray(value) && !isRecord(value) ? INTEGRATION.NOTED_FIELDS.includes(fieldPath.join(".")) || newScalars.push(`${key} ${String(value)}`) : nested.push(...diffLines(old[key], value, fieldPath));
|
|
13113
13172
|
}
|
|
13114
13173
|
return [...newScalars.length > 0 ? [`+ ${here}: ${newScalars.join(", ")}`] : [], ...nested];
|
|
13115
13174
|
}
|
|
13116
13175
|
function planIntegrationAdd(config, manifest, version2, hasCode2) {
|
|
13117
|
-
let
|
|
13176
|
+
let headline = planHeadline(manifest, version2, hasCode2), outcome = planAdd(config, manifest);
|
|
13118
13177
|
if (!outcome.ok) return { ok: false, headline, refusals: outcome.error };
|
|
13119
13178
|
let after = outcome.value.config;
|
|
13120
|
-
return { ok: true, headline, changes: [...outcome.value.notes, ...diffLines(
|
|
13179
|
+
return { ok: true, headline, changes: [...outcome.value.notes, ...diffLines(config, after)], youAdd: outcome.value.youAdd, config: after, changed: !(0, import_node_util.isDeepStrictEqual)(config, after) };
|
|
13121
13180
|
}
|
|
13122
13181
|
function renderAddPlan(plan) {
|
|
13123
13182
|
return [plan.headline, ...plan.changes.map((line) => ` ${line}`), ...plan.youAdd.length > 0 ? [INTEGRATION.YOU_ADD, ...plan.youAdd.map((line) => ` ${line}`)] : []];
|
|
13124
13183
|
}
|
|
13125
|
-
var import_node_util,
|
|
13184
|
+
var import_node_util, itemText, init_integration_plan = __esm({ "src/core/integration-plan.ts"() {
|
|
13126
13185
|
"use strict";
|
|
13127
13186
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13128
13187
|
import_node_util = require("node:util");
|
|
13129
13188
|
init_dist2();
|
|
13189
|
+
init_tenant();
|
|
13130
13190
|
init_constants();
|
|
13131
|
-
|
|
13191
|
+
itemText = (item) => isRecord(item) && typeof item.prefix == "string" ? item.prefix : isRecord(item) && typeof item.path == "string" ? item.path : typeof item == "string" ? item : JSON.stringify(item);
|
|
13132
13192
|
} });
|
|
13193
|
+
function assessIntegrations(installed, config) {
|
|
13194
|
+
let missing = installed.filter((entry) => entry.read.kind === "missing").map((entry) => entry.pkg);
|
|
13195
|
+
if (missing.length > 0) return { ok: false, missing };
|
|
13196
|
+
let integrations = installed.flatMap(({ pkg, read }) => read.kind === "installed" ? [{ pkg, version: read.version, manifest: parseManifest(read.manifestText) }] : []), manifests = integrations.flatMap(({ manifest }) => manifest.ok ? [manifest.value] : []);
|
|
13197
|
+
return { ok: true, errors: [...integrations.flatMap(({ pkg, manifest }) => manifest.ok ? [] : manifest.error.map((issue) => INTEGRATION.BAD_MANIFEST(pkg, issue))), ...checkCoverage(config, manifests)], versions: integrations.map(({ pkg, version: version2 }) => ({ pkg, version: version2 })) };
|
|
13198
|
+
}
|
|
13133
13199
|
function integrationDeps(packageJson) {
|
|
13134
13200
|
let deps = packageJson?.dependencies;
|
|
13135
13201
|
return typeof deps != "object" || deps === null ? [] : Object.keys(deps).filter((name) => name.startsWith(`${PACKAGE_SCOPE}/`));
|
|
@@ -13151,7 +13217,7 @@ var init_integration_coverage = __esm({ "src/core/integration-coverage.ts"() {
|
|
|
13151
13217
|
function patch(doc, before, after, path12) {
|
|
13152
13218
|
if ((0, import_node_util2.isDeepStrictEqual)(before, after)) return;
|
|
13153
13219
|
let node = path12.length === 0 ? doc.contents : doc.getIn(path12, true);
|
|
13154
|
-
if (
|
|
13220
|
+
if (isRecord(after) && isRecord(before) && (0, import_yaml2.isMap)(node)) {
|
|
13155
13221
|
for (let [key, value] of Object.entries(after)) patch(doc, before[key], value, [...path12, key]);
|
|
13156
13222
|
return;
|
|
13157
13223
|
}
|
|
@@ -13159,7 +13225,7 @@ function patch(doc, before, after, path12) {
|
|
|
13159
13225
|
for (let item of after.slice(before.length)) node.add(doc.createNode(item));
|
|
13160
13226
|
return;
|
|
13161
13227
|
}
|
|
13162
|
-
(0, import_yaml2.isScalar)(node) && !Array.isArray(after) && !
|
|
13228
|
+
(0, import_yaml2.isScalar)(node) && !Array.isArray(after) && !isRecord(after) ? node.value = after : doc.setIn(path12, doc.createNode(after));
|
|
13163
13229
|
}
|
|
13164
13230
|
function renderTaskConfigText(text, before, after, isJson) {
|
|
13165
13231
|
if ((0, import_node_util2.isDeepStrictEqual)(before, after)) return text;
|
|
@@ -13168,10 +13234,11 @@ function renderTaskConfigText(text, before, after, isJson) {
|
|
|
13168
13234
|
let doc = (0, import_yaml2.parseDocument)(text, { schema: "core" });
|
|
13169
13235
|
return patch(doc, before, after, []), doc.toString({ flowCollectionPadding: false });
|
|
13170
13236
|
}
|
|
13171
|
-
var import_node_util2, import_yaml2,
|
|
13237
|
+
var import_node_util2, import_yaml2, init_task_yaml_edit = __esm({ "src/core/task-yaml-edit.ts"() {
|
|
13172
13238
|
"use strict";
|
|
13173
13239
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13174
|
-
import_node_util2 = require("node:util"), import_yaml2 = __toESM(require_dist(), 1)
|
|
13240
|
+
import_node_util2 = require("node:util"), import_yaml2 = __toESM(require_dist(), 1);
|
|
13241
|
+
init_tenant();
|
|
13175
13242
|
} });
|
|
13176
13243
|
function integrationPackage(manifestText, packageJson) {
|
|
13177
13244
|
if (manifestText === null) return { kind: "not-integration" };
|
|
@@ -13180,25 +13247,25 @@ function integrationPackage(manifestText, packageJson) {
|
|
|
13180
13247
|
}
|
|
13181
13248
|
function readInstalledPackage(taskDir, pkg) {
|
|
13182
13249
|
let dir = packageDir(taskDir, pkg);
|
|
13183
|
-
if (!
|
|
13184
|
-
let manifestFile =
|
|
13185
|
-
return
|
|
13250
|
+
if (!import_node_fs8.default.existsSync(dir)) return { kind: "missing" };
|
|
13251
|
+
let manifestFile = import_node_path7.default.join(dir, MANIFEST_FILE);
|
|
13252
|
+
return import_node_fs8.default.existsSync(manifestFile) ? integrationPackage(readText(manifestFile), readJson(import_node_path7.default.join(dir, INTEGRATION.PACKAGE_JSON))) : { kind: "not-integration" };
|
|
13186
13253
|
}
|
|
13187
13254
|
function readPackedPackage(packDir) {
|
|
13188
|
-
let tarball =
|
|
13255
|
+
let tarball = import_node_fs8.default.readdirSync(packDir).find((f) => f.endsWith(INTEGRATION.TARBALL_EXT));
|
|
13189
13256
|
if (tarball === void 0) return { kind: "missing" };
|
|
13190
|
-
let file =
|
|
13257
|
+
let file = import_node_path7.default.join(packDir, tarball);
|
|
13191
13258
|
try {
|
|
13192
|
-
let members = readTar((0, import_node_zlib.gunzipSync)(
|
|
13259
|
+
let members = readTar((0, import_node_zlib.gunzipSync)(import_node_fs8.default.readFileSync(file), { maxOutputLength: INTEGRATION.PACKED_MAX_BYTES })), text = (name) => members.find((m) => m.kind === "file" && m.name === `${INTEGRATION.PACKED_ROOT}/${name}`)?.data.toString("utf8") ?? null, packageJson = text(INTEGRATION.PACKAGE_JSON);
|
|
13193
13260
|
return integrationPackage(text(MANIFEST_FILE), packageJson === null ? null : JSON.parse(packageJson));
|
|
13194
13261
|
} catch (e) {
|
|
13195
13262
|
let tooBig = e.code === INTEGRATION.ZLIB_TOO_BIG;
|
|
13196
|
-
throw new Error(tooBig ? INTEGRATION.PACKED_TOO_BIG(file, INTEGRATION.PACKED_MAX_BYTES) : INTEGRATION.UNREADABLE(file,
|
|
13263
|
+
throw new Error(tooBig ? INTEGRATION.PACKED_TOO_BIG(file, INTEGRATION.PACKED_MAX_BYTES) : INTEGRATION.UNREADABLE(file, errText(e)), { cause: e });
|
|
13197
13264
|
}
|
|
13198
13265
|
}
|
|
13199
13266
|
function readTaskPackageJson(taskDir) {
|
|
13200
|
-
let file =
|
|
13201
|
-
return
|
|
13267
|
+
let file = import_node_path7.default.join(taskDir, INTEGRATION.PACKAGE_JSON);
|
|
13268
|
+
return import_node_fs8.default.existsSync(file) ? readJson(file) : null;
|
|
13202
13269
|
}
|
|
13203
13270
|
async function fetchPackument(pkg, fetchImpl = fetch) {
|
|
13204
13271
|
try {
|
|
@@ -13208,19 +13275,11 @@ async function fetchPackument(pkg, fetchImpl = fetch) {
|
|
|
13208
13275
|
return { ok: false, reason: INTEGRATION.REGISTRY_UNREACHABLE };
|
|
13209
13276
|
}
|
|
13210
13277
|
}
|
|
13211
|
-
function writeFileAtomic(file, text) {
|
|
13212
|
-
let target = import_node_fs7.default.realpathSync(file), mode = import_node_fs7.default.statSync(target).mode & 511, name = `.${import_node_path6.default.basename(target)}.${process.pid}.${(0, import_node_crypto3.randomBytes)(6).toString("hex")}.tmp`, tmp = import_node_path6.default.join(import_node_path6.default.dirname(target), name);
|
|
13213
|
-
try {
|
|
13214
|
-
import_node_fs7.default.writeFileSync(tmp, text, { mode, flag: "wx" }), import_node_fs7.default.chmodSync(tmp, mode), import_node_fs7.default.renameSync(tmp, target);
|
|
13215
|
-
} finally {
|
|
13216
|
-
import_node_fs7.default.rmSync(tmp, { force: true });
|
|
13217
|
-
}
|
|
13218
|
-
}
|
|
13219
13278
|
function readText(file) {
|
|
13220
13279
|
try {
|
|
13221
|
-
return
|
|
13280
|
+
return import_node_fs8.default.readFileSync(file, "utf8");
|
|
13222
13281
|
} catch (e) {
|
|
13223
|
-
throw new Error(INTEGRATION.UNREADABLE(file,
|
|
13282
|
+
throw new Error(INTEGRATION.UNREADABLE(file, errText(e)), { cause: e });
|
|
13224
13283
|
}
|
|
13225
13284
|
}
|
|
13226
13285
|
function readJson(file) {
|
|
@@ -13228,19 +13287,23 @@ function readJson(file) {
|
|
|
13228
13287
|
try {
|
|
13229
13288
|
return JSON.parse(text);
|
|
13230
13289
|
} catch (e) {
|
|
13231
|
-
throw new Error(INTEGRATION.UNREADABLE(file,
|
|
13290
|
+
throw new Error(INTEGRATION.UNREADABLE(file, errText(e)), { cause: e });
|
|
13232
13291
|
}
|
|
13233
13292
|
}
|
|
13234
|
-
var import_node_child_process2,
|
|
13293
|
+
var import_node_child_process2, import_node_fs8, import_node_path7, import_node_zlib, NPM_OUTPUT_MAX_BYTES, npmOutputToShow, spawnNpm, packageDir, init_integrations = __esm({ "src/io/integrations.ts"() {
|
|
13235
13294
|
"use strict";
|
|
13236
13295
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13237
|
-
import_node_child_process2 = require("node:child_process"),
|
|
13296
|
+
import_node_child_process2 = require("node:child_process"), import_node_fs8 = __toESM(require("node:fs"), 1), import_node_path7 = __toESM(require("node:path"), 1), import_node_zlib = require("node:zlib");
|
|
13238
13297
|
init_dist2();
|
|
13239
13298
|
init_tar();
|
|
13240
13299
|
init_constants();
|
|
13241
13300
|
init_integration_coverage();
|
|
13242
|
-
|
|
13243
|
-
|
|
13301
|
+
init_manager();
|
|
13302
|
+
init_tenant();
|
|
13303
|
+
NPM_OUTPUT_MAX_BYTES = 16 * 1024 * 1024, npmOutputToShow = (status, output) => status === 0 ? "" : output, spawnNpm = (cwd, args) => {
|
|
13304
|
+
let r = (0, import_node_child_process2.spawnSync)(INTEGRATION.NPM, args, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8", maxBuffer: NPM_OUTPUT_MAX_BYTES }), shown = npmOutputToShow(r.status, `${r.stdout ?? ""}${r.stderr ?? ""}`);
|
|
13305
|
+
return shown !== "" && tell(shown.trimEnd()), r.status;
|
|
13306
|
+
}, packageDir = (taskDir, pkg) => import_node_path7.default.join(taskDir, INTEGRATION.NODE_MODULES, ...pkg.split("/"));
|
|
13244
13307
|
} });
|
|
13245
13308
|
async function runIntegrationAdd(args, cwd = process.cwd(), deps = REAL_INTEGRATION_ADD_DEPS) {
|
|
13246
13309
|
let name = requiredArg(args);
|
|
@@ -13254,16 +13317,17 @@ async function runIntegrationAdd(args, cwd = process.cwd(), deps = REAL_INTEGRAT
|
|
|
13254
13317
|
let task = await prepareTask(args, cwd, slug2);
|
|
13255
13318
|
if (!task) return 1;
|
|
13256
13319
|
if (printWarnings([...task.warnings]), task.config.runtime !== INTEGRATION.RUNTIME) return fail(INTEGRATION.NOT_NODE(task.config.runtime)), 1;
|
|
13257
|
-
|
|
13320
|
+
let taskDir = import_node_fs9.default.realpathSync(task.taskDir);
|
|
13321
|
+
if (readTaskPackageJson(taskDir) === null) return fail(INTEGRATION.NO_PACKAGE_JSON(taskDir)), 1;
|
|
13258
13322
|
let pkg = packageName(name);
|
|
13259
|
-
return guard(() => withPackDir((packDir) => addIntegration(args,
|
|
13323
|
+
return guard(() => withPackDir((packDir) => addIntegration(args, taskDir, task.config, pkg, packDir, dryRun, deps)));
|
|
13260
13324
|
}
|
|
13261
13325
|
async function withPackDir(fn) {
|
|
13262
|
-
let packDir =
|
|
13326
|
+
let packDir = import_node_fs9.default.mkdtempSync(import_node_path8.default.join(import_node_os3.default.tmpdir(), INTEGRATION.PACK_TMP_PREFIX));
|
|
13263
13327
|
try {
|
|
13264
13328
|
return await fn(packDir);
|
|
13265
13329
|
} finally {
|
|
13266
|
-
|
|
13330
|
+
import_node_fs9.default.rmSync(packDir, { recursive: true, force: true });
|
|
13267
13331
|
}
|
|
13268
13332
|
}
|
|
13269
13333
|
async function addIntegration(args, taskDir, config, pkg, packDir, dryRun, deps) {
|
|
@@ -13288,26 +13352,19 @@ async function addIntegration(args, taskDir, config, pkg, packDir, dryRun, deps)
|
|
|
13288
13352
|
if (installCode !== 0) return fail(INTEGRATION.INSTALL_FAILED(spec, installCode)), 1;
|
|
13289
13353
|
sayOk(INTEGRATION.INSTALLED(spec));
|
|
13290
13354
|
}
|
|
13291
|
-
return edit === null ? (emit({ ...result, written: false }), 0) : (writeFileAtomic(edit.file, edit.text), sayOk(INTEGRATION.WRITTEN(
|
|
13355
|
+
return edit === null ? (emit({ ...result, written: false }), 0) : (writeFileAtomic(edit.file, edit.text), sayOk(INTEGRATION.WRITTEN(import_node_path8.default.basename(edit.file))), emit({ ...result, written: true }), 0);
|
|
13292
13356
|
}
|
|
13293
13357
|
function taskConfigEdit(taskDir, config, planned) {
|
|
13294
13358
|
let file = findTaskConfigFile(taskDir);
|
|
13295
13359
|
if (file === null) throw new Error(INTEGRATION.UNREADABLE(taskDir, "no task.yaml"));
|
|
13296
|
-
let source =
|
|
13360
|
+
let source = import_node_path8.default.basename(file), text = renderTaskConfigText(import_node_fs9.default.readFileSync(file, "utf8"), config, planned, source.endsWith(".json")), check = checkTaskConfigText(text, source);
|
|
13297
13361
|
return !check.ok || !(0, import_node_util3.isDeepStrictEqual)(check.config, planned) ? (printErrors(check.errors), fail(INTEGRATION.WRITE_MISMATCH(source)), { ok: false }) : { ok: true, file, text };
|
|
13298
13362
|
}
|
|
13299
13363
|
async function checkIntegrations(taskDir, config, fetchImpl) {
|
|
13300
13364
|
let pkgs = integrationDeps(readTaskPackageJson(taskDir));
|
|
13301
13365
|
if (pkgs.length === 0) return true;
|
|
13302
|
-
let installed = pkgs.map((pkg) => ({ pkg, read: readInstalledPackage(taskDir, pkg) })),
|
|
13303
|
-
|
|
13304
|
-
let manifests = [], errors = [], versions = [];
|
|
13305
|
-
for (let { pkg, read } of installed) {
|
|
13306
|
-
if (read.kind !== "installed") continue;
|
|
13307
|
-
let manifest = parseManifest(read.manifestText);
|
|
13308
|
-
manifest.ok ? manifests.push(manifest.value) : errors.push(...manifest.error.map((issue) => INTEGRATION.BAD_MANIFEST(pkg, issue))), versions.push({ pkg, version: read.version });
|
|
13309
|
-
}
|
|
13310
|
-
return await warnObsolete(versions, fetchImpl), errors.push(...checkCoverage(asCoreConfig(config), manifests)), printErrors(errors), errors.length === 0;
|
|
13366
|
+
let installed = pkgs.map((pkg) => ({ pkg, read: readInstalledPackage(taskDir, pkg) })), assessed = assessIntegrations(installed, config);
|
|
13367
|
+
return assessed.ok ? (await warnObsolete(assessed.versions, fetchImpl), printErrors(assessed.errors), assessed.errors.length === 0) : (fail(INTEGRATION.NOT_INSTALLED(assessed.missing)), false);
|
|
13311
13368
|
}
|
|
13312
13369
|
async function warnObsolete(versions, fetchImpl) {
|
|
13313
13370
|
let lookups = await Promise.all(versions.map(async (entry) => ({ ...entry, lookup: await fetchPackument(entry.pkg, fetchImpl) }))), skipped = /* @__PURE__ */ new Set();
|
|
@@ -13321,16 +13378,17 @@ async function warnObsolete(versions, fetchImpl) {
|
|
|
13321
13378
|
}
|
|
13322
13379
|
for (let reason of skipped) warn(INTEGRATION.OBSOLETE_SKIPPED(reason));
|
|
13323
13380
|
}
|
|
13324
|
-
var
|
|
13381
|
+
var import_node_fs9, import_node_os3, import_node_path8, import_node_util3, REAL_INTEGRATION_ADD_DEPS, NAME_RE, init_integration = __esm({ "src/commands/integration.ts"() {
|
|
13325
13382
|
"use strict";
|
|
13326
13383
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13327
|
-
|
|
13384
|
+
import_node_fs9 = __toESM(require("node:fs"), 1), import_node_os3 = __toESM(require("node:os"), 1), import_node_path8 = __toESM(require("node:path"), 1), import_node_util3 = require("node:util");
|
|
13328
13385
|
init_dist2();
|
|
13329
13386
|
init_constants();
|
|
13330
13387
|
init_integration_plan();
|
|
13331
13388
|
init_integration_coverage();
|
|
13332
13389
|
init_task_yaml_edit();
|
|
13333
13390
|
init_integrations();
|
|
13391
|
+
init_fs_atomic();
|
|
13334
13392
|
init_prompt();
|
|
13335
13393
|
init_task_config3();
|
|
13336
13394
|
init_task_path();
|
|
@@ -13345,24 +13403,24 @@ async function printPackageAdvice(args, config, fetchImpl) {
|
|
|
13345
13403
|
let outcome = await postPackageAdvice(apiConfig(args), plan.request, fetchImpl), { lines, fault } = renderAdvice(outcome, screenStyle());
|
|
13346
13404
|
for (let line of lines) (fault ? tell : say)(line);
|
|
13347
13405
|
} catch (e) {
|
|
13348
|
-
fail(
|
|
13406
|
+
fail(errText(e));
|
|
13349
13407
|
}
|
|
13350
13408
|
}
|
|
13351
13409
|
async function runTaskValidate(args, cwd = process.cwd(), fetchImpl) {
|
|
13352
13410
|
let task = await prepareTask(args, cwd);
|
|
13353
|
-
return !task || (printWarnings([...task.warnings]), !await checkIntegrations(task.taskDir, task.config, fetchImpl)) ? 1 : (emit({ task_id: task.
|
|
13411
|
+
return !task || (printWarnings([...task.warnings]), !await checkIntegrations(task.taskDir, task.config, fetchImpl)) ? 1 : (emit({ task_id: task.slug, valid: true }, (st) => successLine(st, VALIDATE.VALID)), boolFlag(args, ADVICE.FLAG) && await printPackageAdvice(args, task.config, fetchImpl), 0);
|
|
13354
13412
|
}
|
|
13355
13413
|
async function runTaskGet(args, cwd = process.cwd()) {
|
|
13356
13414
|
let task = await prepareTask(args, cwd);
|
|
13357
13415
|
if (!task) return 1;
|
|
13358
|
-
let slug2 = task
|
|
13416
|
+
let { slug: slug2 } = task, state = readState(task.taskDir), check = checkSourceUpload(task.taskDir), localContentHash = check.ok ? check.source.contentHash : null, cfg = offlineTolerantConfig(args), orNull = (p) => p.catch(() => null), [whoami, deploymentsRes, runsRes] = cfg ? await Promise.all([orNull(getWhoami(cfg)), orNull(listApiDeploymentsForTask(cfg, slug2, void 0, { limit: TASK_REPORT_PAGE })), orNull(listApiRuns(cfg, { task_name: slug2, limit: String(TASK_REPORT_PAGE) }))]) : [null, null, null], report = buildTaskReport({ slug: slug2, declared: task.config.execution, declaredPreset: task.config.run?.preset, stateDeploymentId: state.deployment_id ?? null, localContentHash, deployments: deploymentsRes?.deployments ?? null, runs: runsRes?.runs ?? null, pageLimit: TASK_REPORT_PAGE, usage: whoami?.usage ?? null });
|
|
13359
13417
|
return emit(snakeCaseKeys(report), () => formatTaskReport(report)), 0;
|
|
13360
13418
|
}
|
|
13361
13419
|
function offlineTolerantConfig(args) {
|
|
13362
13420
|
try {
|
|
13363
13421
|
return apiConfig(args);
|
|
13364
13422
|
} catch (e) {
|
|
13365
|
-
return warn(RESULT_MESSAGES.TASK_GET_OFFLINE(
|
|
13423
|
+
return warn(RESULT_MESSAGES.TASK_GET_OFFLINE(errText(e))), null;
|
|
13366
13424
|
}
|
|
13367
13425
|
}
|
|
13368
13426
|
async function surveyTaskContents(cfg, taskRef) {
|
|
@@ -13409,7 +13467,7 @@ async function runTaskRun(args, cwd = process.cwd()) {
|
|
|
13409
13467
|
printWarnings([...task.warnings]);
|
|
13410
13468
|
let opts = parseRunOptions(args, task.config);
|
|
13411
13469
|
if (!opts.ok) return fail(opts.error), 1;
|
|
13412
|
-
let { run: run2 } = opts, taskName = task.
|
|
13470
|
+
let { run: run2 } = opts, taskName = task.slug, cfg = apiConfig(args);
|
|
13413
13471
|
if (payloadBytes(run2.payload) > PAYLOAD_LIMIT_FALLBACK_BYTES) {
|
|
13414
13472
|
let refusal = payloadRefusal(run2.payload, await payloadLimit(cfg));
|
|
13415
13473
|
if (refusal !== null) return fail(refusal), 1;
|
|
@@ -13428,26 +13486,37 @@ async function runTaskRun(args, cwd = process.cwd()) {
|
|
|
13428
13486
|
} catch (e) {
|
|
13429
13487
|
if (isJsonOutput()) throw e;
|
|
13430
13488
|
let trace = traceLine(e);
|
|
13431
|
-
if (isPayloadTooLarge(
|
|
13432
|
-
let explained = explainRunRefusal(
|
|
13489
|
+
if (isPayloadTooLarge(e)) return fail(MESSAGES.PAYLOAD_REFUSED_BY_SERVER(await payloadLimit(cfg)), { trace }), 1;
|
|
13490
|
+
let explained = explainRunRefusal(e) ?? explainLimitRefusal(e);
|
|
13433
13491
|
if (!explained) throw e;
|
|
13434
13492
|
return tell(explained), trace !== null && tell(errStyle().dim(trace)), 1;
|
|
13435
13493
|
}
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
13449
|
-
|
|
13450
|
-
|
|
13494
|
+
let answer = classifyRunAnswer(res, run2.at, opts.wait);
|
|
13495
|
+
switch (answer.kind) {
|
|
13496
|
+
case "skew-ran-now":
|
|
13497
|
+
return fail(`this server does not support scheduling \u2014 it IGNORED --at and ran the job NOW (run ${answer.runId}). Cancel it with 'ignitify run:cancel ${answer.runId}' if that is not what you wanted.`), 1;
|
|
13498
|
+
case "skew-no-schedule":
|
|
13499
|
+
return fail("this server does not support scheduling (no schedule_id in the response)."), 1;
|
|
13500
|
+
case "scheduled": {
|
|
13501
|
+
if (isJsonOutput()) return emit(res), 0;
|
|
13502
|
+
let st = outStyle();
|
|
13503
|
+
out(successLine(st, `Scheduled: ${answer.scheduleId} fires at ${answer.firesAt}`)), out(st.dim(`No run exists until it fires. List with 'ignitify schedule:list'; cancel with 'ignitify schedule:cancel ${answer.scheduleId}'.`));
|
|
13504
|
+
let scheduledNotices = renderRunNotices(res.notices);
|
|
13505
|
+
scheduledNotices && out(st.yellow(scheduledNotices));
|
|
13506
|
+
let capacity = renderCapacity(res.capacity, st);
|
|
13507
|
+
return capacity && out(capacity), 0;
|
|
13508
|
+
}
|
|
13509
|
+
case "submitted":
|
|
13510
|
+
return CliOutputManager.render("task:run", { ...res }), 0;
|
|
13511
|
+
case "wait": {
|
|
13512
|
+
let notices = isJsonOutput() ? "" : renderRunNotices(res.notices);
|
|
13513
|
+
notices && out(outStyle().yellow(notices));
|
|
13514
|
+
let capacity = isJsonOutput() ? "" : renderCapacity(res.capacity, outStyle());
|
|
13515
|
+
return capacity && out(capacity), waitForRun(cfg, answer.runId);
|
|
13516
|
+
}
|
|
13517
|
+
default:
|
|
13518
|
+
return answer;
|
|
13519
|
+
}
|
|
13451
13520
|
});
|
|
13452
13521
|
}
|
|
13453
13522
|
async function runTaskCreate(args, cwd = process.cwd()) {
|
|
@@ -13473,12 +13542,8 @@ async function runTaskCreate(args, cwd = process.cwd()) {
|
|
|
13473
13542
|
return CliOutputManager.render("task:create", { ...res, slug: taskId, ...local_dir ? { local_dir } : {} }), say(screenStyle().dim(limitsNote())), 0;
|
|
13474
13543
|
});
|
|
13475
13544
|
}
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
return badLimit !== null ? (fail(badLimit), 1) : guard(async () => {
|
|
13479
|
-
let cfg = apiConfig(args), data = await listApiTasks(cfg, flagParams(args, PAGE_FLAG_PARAMS));
|
|
13480
|
-
return CliOutputManager.render("task:list", data.tasks), noteNextPage(args, { command: COMMANDS.TASK_LIST, flags: PAGE_FLAG_PARAMS }, data.tasks), 0;
|
|
13481
|
-
});
|
|
13545
|
+
function runTaskList(args, _cwd = process.cwd()) {
|
|
13546
|
+
return runPagedList(args, { list: { command: COMMANDS.TASK_LIST, flags: PAGE_FLAG_PARAMS }, fetchPage: listApiTasks, rowsOf: (data) => data.tasks, show: (data) => CliOutputManager.render("task:list", data.tasks) });
|
|
13482
13547
|
}
|
|
13483
13548
|
async function runTaskDelete(args, cwd = process.cwd(), prompter = ttyPrompter) {
|
|
13484
13549
|
let id = requiredArg(args);
|
|
@@ -13495,21 +13560,22 @@ async function runTaskDelete(args, cwd = process.cwd(), prompter = ttyPrompter)
|
|
|
13495
13560
|
try {
|
|
13496
13561
|
import_fs4.default.rmSync(link, { recursive: true, force: true }), say(`${MESSAGES.TASK_LINK_REMOVED}: ${link}`);
|
|
13497
13562
|
} catch (e) {
|
|
13498
|
-
warn(MESSAGES.TASK_LINK_NOT_REMOVED(link,
|
|
13563
|
+
warn(MESSAGES.TASK_LINK_NOT_REMOVED(link, errText(e)));
|
|
13499
13564
|
}
|
|
13500
13565
|
}
|
|
13501
13566
|
return emit({ plan: snakeCaseKeys(plan), deleted: d ?? null }), 0;
|
|
13502
13567
|
});
|
|
13503
13568
|
}
|
|
13504
|
-
var import_fs4,
|
|
13569
|
+
var import_fs4, TASK_REPORT_PAGE, init_task = __esm({ "src/commands/task.ts"() {
|
|
13505
13570
|
"use strict";
|
|
13506
13571
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13507
|
-
import_fs4 = __toESM(require("fs"), 1)
|
|
13572
|
+
import_fs4 = __toESM(require("fs"), 1);
|
|
13508
13573
|
init_prompt();
|
|
13509
13574
|
init_api();
|
|
13510
13575
|
init_plan_task_delete();
|
|
13511
13576
|
init_resolve_deployment();
|
|
13512
13577
|
init_run_options();
|
|
13578
|
+
init_run_answer();
|
|
13513
13579
|
init_state();
|
|
13514
13580
|
init_constants();
|
|
13515
13581
|
init_payload_limit();
|
|
@@ -13527,12 +13593,8 @@ var import_fs4, import_path4, TASK_REPORT_PAGE, init_task = __esm({ "src/command
|
|
|
13527
13593
|
init_shared();
|
|
13528
13594
|
TASK_REPORT_PAGE = 100;
|
|
13529
13595
|
} });
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
return badLimit !== null ? (fail(badLimit), 1) : guard(async () => {
|
|
13533
|
-
let cfg = apiConfig(args), data = await listApiDeployments(cfg, flagParams(args, PAGE_FLAG_PARAMS));
|
|
13534
|
-
return CliOutputManager.render("deployment:list", data), noteNextPage(args, { command: COMMANDS.DEPLOYMENT_LIST, flags: PAGE_FLAG_PARAMS }, data.deployments), 0;
|
|
13535
|
-
});
|
|
13596
|
+
function runDeploymentList(args) {
|
|
13597
|
+
return runPagedList(args, { list: { command: COMMANDS.DEPLOYMENT_LIST, flags: PAGE_FLAG_PARAMS }, fetchPage: listApiDeployments, rowsOf: (data) => data.deployments, show: (data) => CliOutputManager.render("deployment:list", data) });
|
|
13536
13598
|
}
|
|
13537
13599
|
async function runDeploymentGet(args) {
|
|
13538
13600
|
let id = requireArg(args, "deployment-id");
|
|
@@ -13549,7 +13611,7 @@ async function runDeploymentDelete(args, prompter = ttyPrompter) {
|
|
|
13549
13611
|
let id = requireArg(args, "deployment-id");
|
|
13550
13612
|
return id ? guard(async () => {
|
|
13551
13613
|
let cfg = apiConfig(args);
|
|
13552
|
-
if (say(
|
|
13614
|
+
if (say(RESULT_MESSAGES.DEPLOYMENT_DELETE_PREVIEW(id)), !await confirmOrAbort(args, prompter)) return 1;
|
|
13553
13615
|
let res = await deleteDeployment(cfg, id);
|
|
13554
13616
|
emit(res);
|
|
13555
13617
|
let d = res.deleted;
|
|
@@ -13577,12 +13639,8 @@ var WHOLE_MS, init_grace = __esm({ "src/core/grace.ts"() {
|
|
|
13577
13639
|
init_constants();
|
|
13578
13640
|
WHOLE_MS = /^\d+$/;
|
|
13579
13641
|
} });
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
return badLimit !== null ? (fail(badLimit), 1) : guard(async () => {
|
|
13583
|
-
let cfg = apiConfig(args), data = await listApiRuns(cfg, flagParams(args, RUN_LIST_FLAG_PARAMS));
|
|
13584
|
-
return CliOutputManager.render("run:list", data.runs), noteNextPage(args, { command: COMMANDS.RUN_LIST, flags: RUN_LIST_FLAG_PARAMS }, data.runs), 0;
|
|
13585
|
-
});
|
|
13642
|
+
function runRunList(args) {
|
|
13643
|
+
return runPagedList(args, { list: { command: COMMANDS.RUN_LIST, flags: RUN_LIST_FLAG_PARAMS }, fetchPage: listApiRuns, rowsOf: (data) => data.runs, show: (data) => CliOutputManager.render("run:list", data.runs) });
|
|
13586
13644
|
}
|
|
13587
13645
|
async function runRunGet(args) {
|
|
13588
13646
|
let id = requireArg(args, "run-id");
|
|
@@ -13602,7 +13660,7 @@ async function runRunDelete(args, prompter = ttyPrompter) {
|
|
|
13602
13660
|
let id = requireArg(args, "run-id");
|
|
13603
13661
|
return id ? guard(async () => {
|
|
13604
13662
|
let cfg = apiConfig(args);
|
|
13605
|
-
return say(
|
|
13663
|
+
return say(RESULT_MESSAGES.RUN_DELETE_PREVIEW(id)), await confirmOrAbort(args, prompter) ? (emit(await deleteRun(cfg, id)), sayOk(`${MESSAGES.RUN_DELETED}: ${id}`), 0) : 1;
|
|
13606
13664
|
}) : 1;
|
|
13607
13665
|
}
|
|
13608
13666
|
async function runRunCancel(args, prompter = ttyPrompter) {
|
|
@@ -13613,16 +13671,16 @@ async function runRunCancel(args, prompter = ttyPrompter) {
|
|
|
13613
13671
|
let grace = parseGraceMs(strOpt(args, "grace"), force);
|
|
13614
13672
|
if (!grace.ok) return fail(grace.error), 1;
|
|
13615
13673
|
let graceMs = grace.graceMs, cfg = apiConfig(args), run2 = await getApiRun(cfg, id);
|
|
13616
|
-
if (run2?.status && isTerminalRunStatus(run2.status)) return emit({ run_id: id, outcome: RUN_CANCEL_OUTCOME.ALREADY_TERMINAL, status: run2.status }), say(
|
|
13617
|
-
if (say(
|
|
13674
|
+
if (run2?.status && isTerminalRunStatus(run2.status)) return emit({ run_id: id, outcome: RUN_CANCEL_OUTCOME.ALREADY_TERMINAL, status: run2.status }), say(RESULT_MESSAGES.RUN_ALREADY_OVER(id, run2.status)), 0;
|
|
13675
|
+
if (say(RESULT_MESSAGES.RUN_CANCEL_PREVIEW(id, force)), !await confirmOrAbort(args, prompter)) return 1;
|
|
13618
13676
|
let res = await cancelApiRun(cfg, id, force, graceMs);
|
|
13619
13677
|
emit({ run_id: id, outcome: res?.cancelled?.draining ? RUN_CANCEL_OUTCOME.DRAINING : RUN_CANCEL_OUTCOME.CANCELLED, ...res });
|
|
13620
13678
|
let prior = res?.cancelled?.prior_state, was = prior ? ` (was ${prior})` : "";
|
|
13621
13679
|
if (res?.cancelled?.draining) {
|
|
13622
13680
|
let armed = res.cancelled.grace_ms, window = armed === void 0 ? "" : ` (grace ${armed} ms)`;
|
|
13623
|
-
return say(
|
|
13681
|
+
return say(RESULT_MESSAGES.RUN_STOPPING(id, window, was)), 0;
|
|
13624
13682
|
}
|
|
13625
|
-
return sayOk(
|
|
13683
|
+
return sayOk(RESULT_MESSAGES.RUN_CANCELLED(id, was)), 0;
|
|
13626
13684
|
});
|
|
13627
13685
|
}
|
|
13628
13686
|
var init_run = __esm({ "src/commands/run.ts"() {
|
|
@@ -13638,8 +13696,8 @@ var init_run = __esm({ "src/commands/run.ts"() {
|
|
|
13638
13696
|
} });
|
|
13639
13697
|
function decideVmDelete(vm, force, vmId) {
|
|
13640
13698
|
if (vm.residency === "pinned" && !force) {
|
|
13641
|
-
let
|
|
13642
|
-
return { refuse: true, message: `Refusing to delete ${vmId}: this VM is PINNED (permanent standby, alive ${
|
|
13699
|
+
let age = vm.age_ms !== void 0 ? formatDuration(vm.age_ms) : "?";
|
|
13700
|
+
return { refuse: true, message: `Refusing to delete ${vmId}: this VM is PINNED (permanent standby, alive ${age}).
|
|
13643
13701
|
Deleting it is exactly what "permanent" protects against \u2014 re-run with --force if you mean it.` };
|
|
13644
13702
|
}
|
|
13645
13703
|
let pinnedNote = vm.residency === "pinned" ? " (PINNED \u2014 --force given)" : "", busyNote = vm.state === "busy" ? " \u2014 BUSY: its in-flight run will FAIL" : "";
|
|
@@ -13648,15 +13706,10 @@ Deleting it is exactly what "permanent" protects against \u2014 re-run with --fo
|
|
|
13648
13706
|
var init_decide_vm_delete = __esm({ "src/core/decide-vm-delete.ts"() {
|
|
13649
13707
|
"use strict";
|
|
13650
13708
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13709
|
+
init_output();
|
|
13651
13710
|
} });
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
return badLimit !== null ? (fail(badLimit), 1) : guard(async () => {
|
|
13655
|
-
let cfg = apiConfig(args), params = flagParams(args, VM_LIST_FLAG_PARAMS);
|
|
13656
|
-
boolFlag(args, "pinned") && (params.residency = "pinned");
|
|
13657
|
-
let data = await listApiVms(cfg, params);
|
|
13658
|
-
return CliOutputManager.render("vm:list", data), noteNextPage(args, VM_LIST_PAGE, data.vms ?? []), 0;
|
|
13659
|
-
});
|
|
13711
|
+
function runVmList(args) {
|
|
13712
|
+
return runPagedList(args, { list: VM_LIST_PAGE, fetchPage: listApiVms, extra: boolFlag(args, "pinned") ? { residency: "pinned" } : {}, rowsOf: (data) => data.vms ?? [], show: (data) => CliOutputManager.render("vm:list", data) });
|
|
13660
13713
|
}
|
|
13661
13714
|
async function runVmGet(args) {
|
|
13662
13715
|
let id = requireArg(args, "vm-id");
|
|
@@ -13712,7 +13765,7 @@ async function runSecretDelete(args, prompter = ttyPrompter) {
|
|
|
13712
13765
|
let name = args.positionals[0];
|
|
13713
13766
|
return name ? guard(async () => {
|
|
13714
13767
|
let cfg = apiConfig(args);
|
|
13715
|
-
if (tell(
|
|
13768
|
+
if (tell(RESULT_MESSAGES.SECRET_DELETE_PREVIEW(name)), !await confirmOrAbort(args, prompter)) return 1;
|
|
13716
13769
|
let res = await rmSecret(cfg, name);
|
|
13717
13770
|
return emit(res), sayOk(MESSAGES.SECRET_REMOVED(name)), 0;
|
|
13718
13771
|
}) : (tell(MESSAGES.SECRET_DELETE_USAGE), 1);
|
|
@@ -13739,11 +13792,11 @@ async function runScheduleCancel(args, prompter = ttyPrompter) {
|
|
|
13739
13792
|
let id = requireArg(args, "schedule-id");
|
|
13740
13793
|
return id ? guard(async () => {
|
|
13741
13794
|
let cfg = apiConfig(args);
|
|
13742
|
-
if (say(
|
|
13795
|
+
if (say(RESULT_MESSAGES.SCHEDULE_CANCEL_PREVIEW(id)), !await confirmOrAbort(args, prompter)) return 1;
|
|
13743
13796
|
try {
|
|
13744
13797
|
await deleteSchedule(cfg, id);
|
|
13745
13798
|
} catch (e) {
|
|
13746
|
-
if (e instanceof HttpError && e.status === 404) return fail(
|
|
13799
|
+
if (e instanceof HttpError && e.status === 404) return fail(RESULT_MESSAGES.SCHEDULE_NOT_CANCELLED(id)), 1;
|
|
13747
13800
|
throw e;
|
|
13748
13801
|
}
|
|
13749
13802
|
return emit({ schedule_id: id, cancelled: true }), sayOk(RESULT_MESSAGES.SCHEDULE_CANCELLED(id)), 0;
|
|
@@ -13760,11 +13813,11 @@ var init_schedule = __esm({ "src/commands/schedule.ts"() {
|
|
|
13760
13813
|
init_shared();
|
|
13761
13814
|
} });
|
|
13762
13815
|
function withAbsoluteUrl(created, baseUrl) {
|
|
13763
|
-
let url = created
|
|
13816
|
+
let { url } = created;
|
|
13764
13817
|
return typeof url != "string" || !url.startsWith("/") ? created : { ...created, url: `${baseUrl.replace(/\/+$/, "")}${url}` };
|
|
13765
13818
|
}
|
|
13766
13819
|
function renderHookCreated(st, created) {
|
|
13767
|
-
let { secret, ...rest } = created, rows =
|
|
13820
|
+
let { secret, ...rest } = created, rows = { ...rest, [RESULT_MESSAGES.HOOK_SECRET_KEY]: secret }, paint2 = { [RESULT_MESSAGES.HOOK_SECRET_KEY]: (s) => st.bold(st.yellow(s)) };
|
|
13768
13821
|
return `
|
|
13769
13822
|
${heading(st, RESULT_MESSAGES.HOOK_CREATED_TITLE, true)}
|
|
13770
13823
|
${renderFields(st, rows, void 0, paint2)}
|
|
@@ -13775,7 +13828,7 @@ async function runHookCreate(args) {
|
|
|
13775
13828
|
if (!deploymentId) return tell(MESSAGES.HOOK_CREATE_USAGE), 1;
|
|
13776
13829
|
let taskName = args.options["task-name"];
|
|
13777
13830
|
return typeof taskName != "string" || taskName.trim() === "" ? (fail(MESSAGES.HOOK_TASK_NAME_REQUIRED), 1) : guard(async () => {
|
|
13778
|
-
let cfg = apiConfig(args), created = withAbsoluteUrl(
|
|
13831
|
+
let cfg = apiConfig(args), created = withAbsoluteUrl(await createHook(cfg, deploymentId, { task_name: taskName }), cfg.baseUrl);
|
|
13779
13832
|
return warn(MESSAGES.HOOK_SECRET_SHOWN_ONCE), tell(MESSAGES.HOOK_PAYLOAD_LIMIT(formatLimit(await payloadLimit(cfg)))), emit(created, (st) => renderHookCreated(st, created)), 0;
|
|
13780
13833
|
});
|
|
13781
13834
|
}
|
|
@@ -13784,15 +13837,15 @@ async function runHookList(args) {
|
|
|
13784
13837
|
if (!deploymentId) return tell(MESSAGES.HOOK_LIST_USAGE), 1;
|
|
13785
13838
|
let badLimit = limitRefusal(args);
|
|
13786
13839
|
return badLimit !== null ? (fail(badLimit), 1) : guard(async () => {
|
|
13787
|
-
let cfg = apiConfig(args), res =
|
|
13788
|
-
return emit(res, (st) => renderList(hooks, st, EMPTY_LISTS.HOOKS)), noteNextPage(args, { command: COMMANDS.HOOK_LIST, flags: PAGE_FLAG_PARAMS }, hooks), 0;
|
|
13840
|
+
let cfg = apiConfig(args), res = await listHooks(cfg, deploymentId, flagParams(args, PAGE_FLAG_PARAMS)), hooks = Array.isArray(res.hooks) ? res.hooks : [];
|
|
13841
|
+
return emit(res, (st) => renderList(hooks.map((h) => ({ ...h })), st, EMPTY_LISTS.HOOKS)), noteNextPage(args, { command: COMMANDS.HOOK_LIST, flags: PAGE_FLAG_PARAMS }, hooks), 0;
|
|
13789
13842
|
});
|
|
13790
13843
|
}
|
|
13791
13844
|
async function runHookDelete(args, prompter = ttyPrompter) {
|
|
13792
13845
|
let hookId = args.positionals[0];
|
|
13793
13846
|
return hookId ? guard(async () => {
|
|
13794
13847
|
let cfg = apiConfig(args);
|
|
13795
|
-
return tell(
|
|
13848
|
+
return tell(RESULT_MESSAGES.HOOK_DELETE_PREVIEW(hookId)), await confirmOrAbort(args, prompter) ? (emit(await deleteHook(cfg, hookId)), sayOk(RESULT_MESSAGES.HOOK_DELETED(hookId)), 0) : 1;
|
|
13796
13849
|
}) : (tell(MESSAGES.HOOK_DELETE_USAGE), 1);
|
|
13797
13850
|
}
|
|
13798
13851
|
async function runNotifySet(args) {
|
|
@@ -13801,10 +13854,10 @@ async function runNotifySet(args) {
|
|
|
13801
13854
|
if (args.options.secret !== void 0) return fail(MESSAGES.NOTIFY_SECRET_ON_ARGV), 1;
|
|
13802
13855
|
let refusal = notifySetRefusal(args, url !== void 0, clear);
|
|
13803
13856
|
if (refusal !== null) return refuseNotifySet(refusal);
|
|
13804
|
-
let secret;
|
|
13805
|
-
return
|
|
13806
|
-
let cfg = apiConfig(args),
|
|
13807
|
-
return secret !== void 0
|
|
13857
|
+
let secret = args.options["secret-stdin"] === true ? import_fs6.default.readFileSync(0, "utf8").replace(/\n$/, "") : void 0;
|
|
13858
|
+
return secret === "" ? refuseNotifySet(MESSAGES.NOTIFY_SECRET_EMPTY) : guard(async () => {
|
|
13859
|
+
let cfg = apiConfig(args), target = clear || typeof url != "string" ? null : url;
|
|
13860
|
+
return emit(await setNotify(cfg, deploymentId, { url: target, ...secret !== void 0 ? { secret } : {} })), sayOk(target === null ? RESULT_MESSAGES.NOTIFY_CLEARED(deploymentId) : RESULT_MESSAGES.NOTIFY_SET(deploymentId, target)), 0;
|
|
13808
13861
|
});
|
|
13809
13862
|
}
|
|
13810
13863
|
function notifySetRefusal(args, hasUrl, clear) {
|
|
@@ -13814,7 +13867,7 @@ function notifySetRefusal(args, hasUrl, clear) {
|
|
|
13814
13867
|
function refuseNotifySet(reason) {
|
|
13815
13868
|
return fail(reason), tell(MESSAGES.NOTIFY_SET_USAGE), 1;
|
|
13816
13869
|
}
|
|
13817
|
-
var import_fs6,
|
|
13870
|
+
var import_fs6, init_hook = __esm({ "src/commands/hook.ts"() {
|
|
13818
13871
|
"use strict";
|
|
13819
13872
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13820
13873
|
import_fs6 = __toESM(require("fs"), 1);
|
|
@@ -13825,7 +13878,6 @@ var import_fs6, asRecord, init_hook = __esm({ "src/commands/hook.ts"() {
|
|
|
13825
13878
|
init_utils();
|
|
13826
13879
|
init_shared();
|
|
13827
13880
|
init_output();
|
|
13828
|
-
asRecord = (v) => typeof v == "object" && v !== null && !Array.isArray(v) ? v : {};
|
|
13829
13881
|
} });
|
|
13830
13882
|
var init_commands = __esm({ "src/commands/index.ts"() {
|
|
13831
13883
|
"use strict";
|
|
@@ -13850,9 +13902,7 @@ function allowedFlags(meta) {
|
|
|
13850
13902
|
return { ...meta.flags, ...GLOBAL_FLAGS };
|
|
13851
13903
|
}
|
|
13852
13904
|
function parserSpec(meta) {
|
|
13853
|
-
|
|
13854
|
-
if (meta !== void 0 && meta.secretArgv !== true) for (let [flag, kind] of Object.entries(meta.flags)) kind === "bool" && bools.add(flag);
|
|
13855
|
-
return { boolFlags: bools };
|
|
13905
|
+
return boolFlagSpec(meta === void 0 || meta.secretArgv === true ? GLOBAL_FLAGS : allowedFlags(meta));
|
|
13856
13906
|
}
|
|
13857
13907
|
function parseInvocation(argv) {
|
|
13858
13908
|
return parseArgs([...argv], parserSpec(metaFor(argv[0] ?? "")));
|
|
@@ -13893,12 +13943,11 @@ function planInvocation(argv) {
|
|
|
13893
13943
|
let refusal = checkInvocation(command, meta, pass);
|
|
13894
13944
|
return refusal === null ? { kind: "run", command, args } : { kind: "error", message: refusal };
|
|
13895
13945
|
}
|
|
13896
|
-
var
|
|
13946
|
+
var init_invocation2 = __esm({ "src/core/invocation.ts"() {
|
|
13897
13947
|
"use strict";
|
|
13898
13948
|
init_define_IGNITIFY_CLIENT_FILES();
|
|
13899
13949
|
init_http_client();
|
|
13900
13950
|
init_constants();
|
|
13901
|
-
looksShort = (tok) => tok.length > 1 && tok.startsWith("-") && !tok.startsWith("--");
|
|
13902
13951
|
} });
|
|
13903
13952
|
var index_exports = {};
|
|
13904
13953
|
__export(index_exports, { main: () => main, run: () => run });
|