@cloud-cli/on 1.18.1 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export declare function runMigrations(): Promise<void>;
2
+ //# sourceMappingURL=migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAmBA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD"}
package/dist/on.js CHANGED
@@ -3857,7 +3857,7 @@ var qn = class {
3857
3857
  let t = Buffer.from(e, "base64"), n = c.createDecipheriv("aes-256-gcm", this.encryptionKey(), t.subarray(0, 12));
3858
3858
  return n.setAuthTag(t.subarray(12, 28)), Buffer.concat([n.update(t.subarray(28)), n.final()]).toString("utf8");
3859
3859
  }
3860
- }, Jn = "<!doctype html>\n<html lang=\"en\" class=\"dark\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <meta name=\"theme-color\" content=\"#030712\" />\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\n <link rel=\"manifest\" href=\"/manifest.webmanifest\" />\n <link rel=\"icon\" href=\"/app-icon.svg\" type=\"image/svg+xml\" />\n <title>Runner Workflow Management</title>\n <script type=\"importmap\">\n { \"imports\": { \"@li3/\": \"https://cdn.li3.dev/@li3/\" } }\n <\/script>\n <style>\n body[data-page='list'] .editor-panel {\n display: none;\n }\n body[data-page='editor'] .workflow-list,\n body[data-page='editor'] .secrets-panel {\n display: none;\n }\n </style>\n </head>\n <body data-page=\"__WORKFLOW_PAGE__\" class=\"min-h-screen bg-gray-950 p-4 font-sans text-gray-100 md:p-6\">\n <link rel=\"component\" href=\"https://sodium.static.apphor.de/code-editor.html\" />\n <link rel=\"component\" href=\"https://sodium.static.apphor.de/lucide-icon.html\" />\n\n <template app>\n <main class=\"mx-auto max-w-6xl space-y-5\">\n <header class=\"flex flex-col gap-4 border-b border-gray-800 pb-5 sm:flex-row sm:items-end sm:justify-between\">\n <div class=\"flex items-start gap-3\">\n <a\n href=\"/runs\"\n aria-label=\"Back to dashboard\"\n class=\"mt-1 rounded-lg border border-gray-800 bg-gray-900 p-2 text-gray-400 transition hover:border-indigo-500/60 hover:text-indigo-300\"\n >\n <lucide-icon icon=\"arrow-left\" size=\"17\"></lucide-icon>\n </a>\n <div>\n <p class=\"text-xs font-semibold uppercase tracking-[0.18em] text-indigo-400\">Runner engine</p>\n <h1 class=\"mt-1 text-2xl font-bold tracking-tight text-white\">Workflow control room</h1>\n <p class=\"mt-1 text-sm text-gray-400\">Draft, validate, and publish revisioned YAML definitions.</p>\n </div>\n </div>\n <a\n href=\"/workflows/new\"\n class=\"inline-flex items-center justify-center gap-2 rounded-lg bg-indigo-500 px-4 py-2.5 text-sm font-semibold text-white shadow-lg shadow-indigo-950/40 transition hover:bg-indigo-400\"\n >\n <lucide-icon icon=\"plus\" size=\"16\"></lucide-icon>\n New workflow\n </a>\n </header>\n\n <template if=\"notice\">\n <div\n role=\"status\"\n class=\"flex items-center gap-2 rounded-lg border px-3 py-2.5 text-sm\"\n bind-class=\"noticeError ? 'border-rose-500/40.bg-rose-500/10.text-rose-100' : 'border-emerald-500/40.bg-emerald-500/10.text-emerald-100'\"\n >\n <lucide-icon bind-icon=\"noticeError ? 'circle-alert' : 'circle-check'\" size=\"17\"></lucide-icon>\n <span>{{ notice }}</span>\n </div>\n </template>\n\n <section id=\"workflow-layout\" class=\"space-y-5\">\n <aside class=\"workflow-list rounded-xl border border-gray-800 bg-gray-900/80 p-3 shadow-xl shadow-black/10\">\n <div class=\"mb-3 flex items-center justify-between px-2\">\n <h2 class=\"text-xs font-semibold uppercase tracking-wider text-gray-400\">Workflows</h2>\n <span class=\"rounded-full bg-gray-800 px-2 py-0.5 text-xs font-mono text-gray-400\"\n >{{ workflows.length }}</span\n >\n </div>\n <div class=\"space-y-1 flex flex-col w-full\">\n <template for=\"workflow of workflows\">\n <button\n on-click=\"visitWorkflow(workflow.id)\"\n class=\"flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-left text-sm transition hover:bg-gray-800\"\n bind-class=\"workflow.id === selectedId ? 'bg-indigo-500/15.text-indigo-100' : 'text-gray-300'\"\n >\n <span class=\"truncate font-medium\">{{ workflow.name }}</span>\n <span\n class=\"ml-3 rounded-full border border-gray-700 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-gray-400\"\n >{{ workflow.status }}</span\n >\n </button>\n </template>\n <p class=\"px-3 py-5 text-center text-sm text-gray-500\" class-hidden=\"workflows.length > 0\">\n No workflows yet.\n </p>\n </div>\n </aside>\n\n <section\n class=\"editor-panel overflow-hidden rounded-xl border border-gray-800 bg-gray-900/80 shadow-xl shadow-black/10\"\n >\n <div class=\"border-b border-gray-800 bg-gray-900 px-4 py-4 sm:px-5\">\n <div class=\"flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between\">\n <label class=\"block max-w-xl flex-1 text-xs font-semibold uppercase tracking-wider text-gray-400\"\n >Workflow ID\n <input\n bind-value=\"workflowId\"\n on-input=\"setWorkflowId($event)\"\n class=\"mt-2 w-full rounded-lg border border-gray-700 bg-gray-950 px-3 py-2.5 font-mono text-sm normal-case tracking-normal text-white outline-none transition focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20\"\n placeholder=\"derived-from-workflow-name\"\n />\n </label>\n <div class=\"flex flex-wrap gap-2\">\n <button\n on-click=\"validate()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg border border-gray-700 px-3 py-2.5 text-sm font-medium text-gray-200 transition hover:border-gray-500 hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"badge-check\" size=\"16\"></lucide-icon>\n Validate\n </button>\n <button\n on-click=\"save()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg bg-indigo-500 px-3 py-2.5 text-sm font-semibold text-white transition hover:bg-indigo-400 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"save\" size=\"16\"></lucide-icon>\n Save draft\n </button>\n <button\n on-click=\"publish()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg border border-emerald-500/50 px-3 py-2.5 text-sm font-medium text-emerald-300 transition hover:bg-emerald-500/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"rocket\" size=\"16\"></lucide-icon>\n Publish\n </button>\n <button\n on-click=\"remove()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg border border-rose-500/50 px-3 py-2.5 text-sm font-medium text-rose-300 transition hover:bg-rose-500/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"trash-2\" size=\"16\"></lucide-icon>\n Delete\n </button>\n </div>\n </div>\n </div>\n <div class=\"p-3 sm:p-5\">\n <div class=\"mb-2 flex items-center justify-between px-1 text-xs text-gray-500\">\n <span class=\"font-medium\">YAML definition</span>\n <span class=\"font-mono\">{{ source.length }} characters</span>\n </div>\n <code-editor\n id=\"source-yaml\"\n language=\"yaml\"\n theme=\"atom-one-dark\"\n nostatus=\"true\"\n class=\"block h-[calc(100vh-23rem)] min-h-[28rem] overflow-hidden rounded-lg border border-gray-700 bg-gray-950\"\n bind-value=\"source\"\n on-change=\"setSource($event.detail)\"\n ></code-editor>\n </div>\n </section>\n </section>\n\n <section\n class=\"secrets-panel rounded-xl border border-gray-800 bg-gray-900/80 p-4 shadow-xl shadow-black/10 sm:p-5\"\n >\n <div class=\"mb-4 flex items-start gap-3\">\n <span class=\"rounded-lg bg-indigo-500/10 p-2 text-indigo-300\"\n ><lucide-icon icon=\"key-round\" size=\"18\"></lucide-icon\n ></span>\n <div>\n <h2 class=\"text-base font-semibold text-white\">Secrets</h2>\n <p class=\"mt-0.5 text-sm text-gray-400\">\n Values are write-only and encrypted. Re-saving a name replaces its value.\n </p>\n </div>\n </div>\n <div class=\"grid gap-3 md:grid-cols-[14rem_1fr_auto_auto]\">\n <input\n bind-value=\"secretName\"\n on-input=\"setSecretName($event)\"\n class=\"rounded-lg border border-gray-700 bg-gray-950 px-3 py-2.5 font-mono text-sm uppercase outline-none transition focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20\"\n placeholder=\"NPM_TOKEN\"\n />\n <input\n ref=\"secretValueInput\"\n bind-value=\"secretValue\"\n on-input=\"setSecretValue($event)\"\n type=\"password\"\n class=\"rounded-lg border border-gray-700 bg-gray-950 px-3 py-2.5 font-mono text-sm outline-none transition focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20\"\n placeholder=\"New secret value\"\n />\n <button\n on-click=\"saveSecret()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center justify-center gap-2 rounded-lg border border-indigo-500/60 px-3 py-2.5 text-sm font-medium text-indigo-200 transition hover:bg-indigo-500/10 disabled:opacity-50\"\n >\n <lucide-icon icon=\"lock-keyhole\" size=\"16\"></lucide-icon>Save value\n </button>\n <button\n on-click=\"removeSecret()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center justify-center gap-2 rounded-lg border border-rose-500/50 px-3 py-2.5 text-sm font-medium text-rose-300 transition hover:bg-rose-500/10 disabled:opacity-50\"\n >\n <lucide-icon icon=\"trash-2\" size=\"16\"></lucide-icon>Delete\n </button>\n </div>\n <div class=\"mt-4 flex flex-col space-y-1\">\n <template for=\"name of secrets\"\n ><button\n on-click=\"selectSecret(name)\"\n class=\"rounded-md border border-gray-700 px-2.5 py-1.5 font-mono text-xs text-gray-300 transition hover:border-indigo-500 hover:text-indigo-200 w-full\"\n >\n {{ name }}\n </button></template\n >\n </div>\n </section>\n </main>\n\n <script setup>\n import { onInit, ref, templateRef } from '@li3/web';\n\n export default function () {\n const page = document.body.dataset.page;\n const initialId = __WORKFLOW_ID__;\n const workflows = ref([]);\n const secrets = ref([]);\n const source = ref('');\n const workflowId = ref('');\n const selectedId = ref('');\n const secretName = ref('');\n const secretValue = ref('');\n const notice = ref('');\n const noticeError = ref(false);\n const busy = ref(false);\n const secretValueInput = templateRef('secretValueInput');\n\n const showNotice = (message, error = false) => {\n notice.value = message;\n noticeError.value = error;\n };\n const api = async (url, options = {}) => {\n const response = await fetch(url, {\n headers: { accept: 'application/json', ...(options.body ? { 'content-type': 'application/json' } : {}) },\n ...options,\n });\n const body = response.status === 204 ? null : await response.json().catch(() => ({}));\n if (!response.ok) throw new Error(body.error || `Request failed: ${response.status}`);\n return body;\n };\n const derivedId = () =>\n source.value\n .match(/^\\s*(?:id:\\s*([^\\n]+)|name:\\s*([^\\n]+))/m)\n ?.slice(1)\n .find(Boolean)\n ?.trim()\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '-')\n .replace(/(^-|-$)/g, '') || '';\n const run = async (action) => {\n if (busy.value) return;\n busy.value = true;\n try {\n await action();\n } catch (error) {\n showNotice(error.message, true);\n } finally {\n busy.value = false;\n }\n };\n const loadWorkflows = async () => {\n workflows.value = (await api('/api/workflows')).workflows;\n };\n const loadSecrets = async () => {\n secrets.value = (await api('/api/secrets')).secrets;\n };\n const openWorkflow = async (id) => {\n const workflow = await api(`/api/workflows/${id}`);\n selectedId.value = workflow.id;\n workflowId.value = workflow.id;\n source.value = workflow.sourceYaml;\n };\n const validate = () =>\n run(async () => {\n const result = await api('/api/workflows/validate', {\n method: 'POST',\n body: JSON.stringify({ sourceYaml: source.value }),\n });\n showNotice(`Valid: ${result.workflows.length} workflow definition(s).`);\n });\n const save = () =>\n run(async () => {\n const id = workflowId.value.trim() || derivedId();\n if (!id) throw new Error('Set an ID or add a workflow name first.');\n const workflow = await api(`/api/workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify({ sourceYaml: source.value }),\n });\n selectedId.value = workflow.id;\n workflowId.value = workflow.id;\n showNotice(`Saved ${workflow.id} as draft revision ${workflow.revision}.`);\n if (!initialId) history.replaceState(null, '', `/workflows/${workflow.id}`);\n });\n const publish = () =>\n run(async () => {\n const id = workflowId.value.trim() || selectedId.value;\n if (!id) throw new Error('Save a workflow before publishing it.');\n const workflow = await api(`/api/workflows/${id}/publish`, { method: 'POST' });\n selectedId.value = workflow.id;\n showNotice(`Published ${workflow.id} revision ${workflow.revision}.`);\n });\n const remove = () =>\n run(async () => {\n const id = workflowId.value.trim() || selectedId.value;\n if (!id || !confirm(`Delete ${id} and all of its revisions?`)) return;\n await api(`/api/workflows/${id}`, { method: 'DELETE' });\n window.location.href = '/workflows';\n });\n const saveSecret = () =>\n run(async () => {\n const name = secretName.value.trim();\n if (!name || !secretValue.value) throw new Error('Set a secret name and value first.');\n await api(`/api/secrets/${name}`, { method: 'PUT', body: JSON.stringify({ value: secretValue.value }) });\n secretValue.value = '';\n await loadSecrets();\n showNotice(`Saved ${name}.`);\n });\n const removeSecret = () =>\n run(async () => {\n const name = secretName.value.trim();\n if (!name || !confirm(`Delete ${name}?`)) return;\n await api(`/api/secrets/${name}`, { method: 'DELETE' });\n secretName.value = '';\n secretValue.value = '';\n await loadSecrets();\n showNotice(`Deleted ${name}.`);\n });\n const setSource = (value) => {\n source.value = value;\n };\n const setWorkflowId = (event) => {\n workflowId.value = event.target.value;\n };\n const setSecretName = (event) => {\n secretName.value = event.target.value;\n };\n const setSecretValue = (event) => {\n secretValue.value = event.target.value;\n };\n const selectSecret = (name) => {\n secretName.value = name;\n secretValueInput.value?.focus();\n };\n const visitWorkflow = (id) => {\n window.location.href = `/workflows/${id}`;\n };\n\n onInit(() => {\n const loadPage =\n page === 'editor'\n ? initialId\n ? openWorkflow(initialId)\n : Promise.resolve()\n : Promise.all([loadWorkflows(), loadSecrets()]);\n loadPage.catch((error) => showNotice(error.message, true));\n });\n return {\n workflows,\n secrets,\n source,\n workflowId,\n selectedId,\n secretName,\n secretValue,\n notice,\n noticeError,\n busy,\n validate,\n save,\n publish,\n remove,\n saveSecret,\n removeSecret,\n setSource,\n setWorkflowId,\n setSecretName,\n setSecretValue,\n selectSecret,\n visitWorkflow,\n };\n }\n <\/script>\n </template>\n\n <script type=\"module\">\n import '@li3/web';\n <\/script>\n <script src=\"https://cdn.tailwindcss.com\"><\/script>\n </body>\n</html>\n";
3860
+ }, Jn = "<!doctype html>\n<html lang=\"en\" class=\"dark\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <meta name=\"theme-color\" content=\"#030712\" />\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\n <link rel=\"manifest\" href=\"/manifest.webmanifest\" />\n <link rel=\"icon\" href=\"/app-icon.svg\" type=\"image/svg+xml\" />\n <title>Runner Workflow Management</title>\n <script type=\"importmap\">\n { \"imports\": { \"@li3/\": \"https://cdn.li3.dev/@li3/\" } }\n <\/script>\n <style>\n body[data-page='list'] .editor-panel {\n display: none;\n }\n body[data-page='editor'] .workflow-list,\n body[data-page='editor'] .secrets-panel {\n display: none;\n }\n </style>\n </head>\n <body data-page=\"__WORKFLOW_PAGE__\" class=\"min-h-screen bg-gray-950 p-4 font-sans text-gray-100 md:p-6\">\n <link rel=\"component\" href=\"https://sodium.static.apphor.de/code-editor.html\" />\n <link rel=\"component\" href=\"https://sodium.static.apphor.de/lucide-icon.html\" />\n\n <template app>\n <main class=\"mx-auto max-w-6xl space-y-5\">\n <header class=\"flex flex-col gap-4 border-b border-gray-800 pb-5 sm:flex-row sm:items-end sm:justify-between\">\n <div class=\"flex items-start gap-3\">\n <a\n href=\"/runs\"\n aria-label=\"Back to dashboard\"\n class=\"mt-1 rounded-lg border border-gray-800 bg-gray-900 p-2 text-gray-400 transition hover:border-indigo-500/60 hover:text-indigo-300\"\n >\n <lucide-icon icon=\"arrow-left\" size=\"17\"></lucide-icon>\n </a>\n <div>\n <p class=\"text-xs font-semibold uppercase tracking-[0.18em] text-indigo-400\">Runner engine</p>\n <h1 class=\"mt-1 text-2xl font-bold tracking-tight text-white\">Workflow control room</h1>\n <p class=\"mt-1 text-sm text-gray-400\">Draft, validate, and publish revisioned YAML definitions.</p>\n </div>\n </div>\n <a\n href=\"/workflows/new\"\n class=\"inline-flex items-center justify-center gap-2 rounded-lg bg-indigo-500 px-4 py-2.5 text-sm font-semibold text-white shadow-lg shadow-indigo-950/40 transition hover:bg-indigo-400\"\n >\n <lucide-icon icon=\"plus\" size=\"16\"></lucide-icon>\n New workflow\n </a>\n </header>\n\n <template if=\"notice\">\n <div\n role=\"status\"\n class=\"flex items-center gap-2 rounded-lg border px-3 py-2.5 text-sm\"\n bind-class=\"noticeError ? 'border-rose-500/40.bg-rose-500/10.text-rose-100' : 'border-emerald-500/40.bg-emerald-500/10.text-emerald-100'\"\n >\n <lucide-icon bind-icon=\"noticeError ? 'circle-alert' : 'circle-check'\" size=\"17\"></lucide-icon>\n <span>{{ notice }}</span>\n </div>\n </template>\n\n <section id=\"workflow-layout\" class=\"space-y-5\">\n <aside class=\"workflow-list rounded-xl border border-gray-800 bg-gray-900/80 p-3 shadow-xl shadow-black/10\">\n <div class=\"mb-3 flex items-center justify-between px-2\">\n <h2 class=\"text-xs font-semibold uppercase tracking-wider text-gray-400\">Workflows</h2>\n <span class=\"rounded-full bg-gray-800 px-2 py-0.5 text-xs font-mono text-gray-400\"\n >{{ workflows.length }}</span\n >\n </div>\n <div class=\"space-y-1 flex flex-col w-full\">\n <template for=\"workflow of workflows\">\n <button\n on-click=\"visitWorkflow(workflow.id)\"\n class=\"flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-left text-sm transition hover:bg-gray-800\"\n bind-class=\"workflow.id === selectedId ? 'bg-indigo-500/15.text-indigo-100' : 'text-gray-300'\"\n >\n <span class=\"truncate font-medium\">{{ workflow.name }}</span>\n <span\n class=\"ml-3 rounded-full border border-gray-700 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-gray-400\"\n >{{ workflow.status }}</span\n >\n </button>\n </template>\n <p class=\"px-3 py-5 text-center text-sm text-gray-500\" class-hidden=\"workflows.length > 0\">\n No workflows yet.\n </p>\n </div>\n </aside>\n\n <section\n class=\"editor-panel overflow-hidden rounded-xl border border-gray-800 bg-gray-900/80 shadow-xl shadow-black/10\"\n >\n <div class=\"border-b border-gray-800 bg-gray-900 px-4 py-4 sm:px-5\">\n <div class=\"flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between\">\n <label class=\"block max-w-xl flex-1 text-xs font-semibold uppercase tracking-wider text-gray-400\"\n >Workflow ID\n <input\n bind-value=\"workflowId\"\n on-input=\"setWorkflowId($event)\"\n class=\"mt-2 w-full rounded-lg border border-gray-700 bg-gray-950 px-3 py-2.5 font-mono text-sm normal-case tracking-normal text-white outline-none transition focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20\"\n placeholder=\"derived-from-workflow-name\"\n />\n </label>\n <label class=\"inline-flex items-center gap-2 text-sm text-gray-300\">\n <input\n type=\"checkbox\"\n bind-checked=\"enabled\"\n on-change=\"setEnabled($event)\"\n class=\"h-4 w-4 rounded border-gray-700 bg-gray-950 text-indigo-500 focus:ring-2 focus:ring-indigo-500/30\"\n />\n Enabled\n </label>\n <div class=\"flex flex-wrap gap-2\">\n <button\n on-click=\"validate()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg border border-gray-700 px-3 py-2.5 text-sm font-medium text-gray-200 transition hover:border-gray-500 hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"badge-check\" size=\"16\"></lucide-icon>\n Validate\n </button>\n <button\n on-click=\"save()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg bg-indigo-500 px-3 py-2.5 text-sm font-semibold text-white transition hover:bg-indigo-400 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"save\" size=\"16\"></lucide-icon>\n Save draft\n </button>\n <button\n on-click=\"publish()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg border border-emerald-500/50 px-3 py-2.5 text-sm font-medium text-emerald-300 transition hover:bg-emerald-500/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"rocket\" size=\"16\"></lucide-icon>\n Publish\n </button>\n <button\n on-click=\"remove()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center gap-2 rounded-lg border border-rose-500/50 px-3 py-2.5 text-sm font-medium text-rose-300 transition hover:bg-rose-500/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <lucide-icon icon=\"trash-2\" size=\"16\"></lucide-icon>\n Delete\n </button>\n </div>\n </div>\n </div>\n <div class=\"p-3 sm:p-5\">\n <div class=\"mb-2 flex items-center justify-between px-1 text-xs text-gray-500\">\n <span class=\"font-medium\">YAML definition</span>\n <span class=\"font-mono\">{{ source.length }} characters</span>\n </div>\n <code-editor\n id=\"source-yaml\"\n language=\"yaml\"\n theme=\"atom-one-dark\"\n nostatus=\"true\"\n class=\"block h-[calc(100vh-23rem)] min-h-[28rem] overflow-hidden rounded-lg border border-gray-700 bg-gray-950\"\n bind-value=\"source\"\n on-change=\"setSource($event.detail)\"\n ></code-editor>\n </div>\n </section>\n </section>\n\n <section\n class=\"secrets-panel rounded-xl border border-gray-800 bg-gray-900/80 p-4 shadow-xl shadow-black/10 sm:p-5\"\n >\n <div class=\"mb-4 flex items-start gap-3\">\n <span class=\"rounded-lg bg-indigo-500/10 p-2 text-indigo-300\"\n ><lucide-icon icon=\"key-round\" size=\"18\"></lucide-icon\n ></span>\n <div>\n <h2 class=\"text-base font-semibold text-white\">Secrets</h2>\n <p class=\"mt-0.5 text-sm text-gray-400\">\n Values are write-only and encrypted. Re-saving a name replaces its value.\n </p>\n </div>\n </div>\n <div class=\"grid gap-3 md:grid-cols-[14rem_1fr_auto_auto]\">\n <input\n bind-value=\"secretName\"\n on-input=\"setSecretName($event)\"\n class=\"rounded-lg border border-gray-700 bg-gray-950 px-3 py-2.5 font-mono text-sm uppercase outline-none transition focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20\"\n placeholder=\"NPM_TOKEN\"\n />\n <input\n ref=\"secretValueInput\"\n bind-value=\"secretValue\"\n on-input=\"setSecretValue($event)\"\n type=\"password\"\n class=\"rounded-lg border border-gray-700 bg-gray-950 px-3 py-2.5 font-mono text-sm outline-none transition focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20\"\n placeholder=\"New secret value\"\n />\n <button\n on-click=\"saveSecret()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center justify-center gap-2 rounded-lg border border-indigo-500/60 px-3 py-2.5 text-sm font-medium text-indigo-200 transition hover:bg-indigo-500/10 disabled:opacity-50\"\n >\n <lucide-icon icon=\"lock-keyhole\" size=\"16\"></lucide-icon>Save value\n </button>\n <button\n on-click=\"removeSecret()\"\n bind-disabled=\"busy\"\n class=\"inline-flex items-center justify-center gap-2 rounded-lg border border-rose-500/50 px-3 py-2.5 text-sm font-medium text-rose-300 transition hover:bg-rose-500/10 disabled:opacity-50\"\n >\n <lucide-icon icon=\"trash-2\" size=\"16\"></lucide-icon>Delete\n </button>\n </div>\n <div class=\"mt-4 flex flex-col space-y-1\">\n <template for=\"name of secrets\"\n ><button\n on-click=\"selectSecret(name)\"\n class=\"rounded-md border border-gray-700 px-2.5 py-1.5 font-mono text-xs text-gray-300 transition hover:border-indigo-500 hover:text-indigo-200 w-full\"\n >\n {{ name }}\n </button></template\n >\n </div>\n </section>\n </main>\n\n <script setup>\n import { onInit, ref, templateRef } from '@li3/web';\n\n export default function () {\n const page = document.body.dataset.page;\n const initialId = __WORKFLOW_ID__;\n const workflows = ref([]);\n const secrets = ref([]);\n const source = ref('');\n const workflowId = ref('');\n const enabled = ref(true);\n const selectedId = ref('');\n const secretName = ref('');\n const secretValue = ref('');\n const notice = ref('');\n const noticeError = ref(false);\n const busy = ref(false);\n const secretValueInput = templateRef('secretValueInput');\n\n const showNotice = (message, error = false) => {\n notice.value = message;\n noticeError.value = error;\n };\n const api = async (url, options = {}) => {\n const response = await fetch(url, {\n headers: { accept: 'application/json', ...(options.body ? { 'content-type': 'application/json' } : {}) },\n ...options,\n });\n const body = response.status === 204 ? null : await response.json().catch(() => ({}));\n if (!response.ok) throw new Error(body.error || `Request failed: ${response.status}`);\n return body;\n };\n const derivedId = () =>\n source.value\n .match(/^\\s*(?:id:\\s*([^\\n]+)|name:\\s*([^\\n]+))/m)\n ?.slice(1)\n .find(Boolean)\n ?.trim()\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '-')\n .replace(/(^-|-$)/g, '') || '';\n const run = async (action) => {\n if (busy.value) return;\n busy.value = true;\n try {\n await action();\n } catch (error) {\n showNotice(error.message, true);\n } finally {\n busy.value = false;\n }\n };\n const loadWorkflows = async () => {\n workflows.value = (await api('/api/workflows')).workflows;\n };\n const loadSecrets = async () => {\n secrets.value = (await api('/api/secrets')).secrets;\n };\n const openWorkflow = async (id) => {\n const workflow = await api(`/api/workflows/${id}`);\n selectedId.value = workflow.id;\n workflowId.value = workflow.id;\n source.value = workflow.sourceYaml;\n enabled.value = workflow.enabled;\n };\n const validate = () =>\n run(async () => {\n const result = await api('/api/workflows/validate', {\n method: 'POST',\n body: JSON.stringify({ sourceYaml: source.value }),\n });\n showNotice(`Valid: ${result.workflows.length} workflow definition(s).`);\n });\n const save = () =>\n run(async () => {\n const id = workflowId.value.trim() || derivedId();\n if (!id) throw new Error('Set an ID or add a workflow name first.');\n const workflow = await api(`/api/workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify({ sourceYaml: source.value, enabled: enabled.value }),\n });\n selectedId.value = workflow.id;\n workflowId.value = workflow.id;\n showNotice(`Saved ${workflow.id} as draft revision ${workflow.revision}.`);\n if (!initialId) history.replaceState(null, '', `/workflows/${workflow.id}`);\n });\n const publish = () =>\n run(async () => {\n const id = workflowId.value.trim() || selectedId.value;\n if (!id) throw new Error('Save a workflow before publishing it.');\n const workflow = await api(`/api/workflows/${id}/publish`, { method: 'POST' });\n selectedId.value = workflow.id;\n showNotice(`Published ${workflow.id} revision ${workflow.revision}.`);\n });\n const remove = () =>\n run(async () => {\n const id = workflowId.value.trim() || selectedId.value;\n if (!id || !confirm(`Delete ${id} and all of its revisions?`)) return;\n await api(`/api/workflows/${id}`, { method: 'DELETE' });\n window.location.href = '/workflows';\n });\n const saveSecret = () =>\n run(async () => {\n const name = secretName.value.trim();\n if (!name || !secretValue.value) throw new Error('Set a secret name and value first.');\n await api(`/api/secrets/${name}`, { method: 'PUT', body: JSON.stringify({ value: secretValue.value }) });\n secretValue.value = '';\n await loadSecrets();\n showNotice(`Saved ${name}.`);\n });\n const removeSecret = () =>\n run(async () => {\n const name = secretName.value.trim();\n if (!name || !confirm(`Delete ${name}?`)) return;\n await api(`/api/secrets/${name}`, { method: 'DELETE' });\n secretName.value = '';\n secretValue.value = '';\n await loadSecrets();\n showNotice(`Deleted ${name}.`);\n });\n const setSource = (value) => {\n source.value = value;\n };\n const setWorkflowId = (event) => {\n workflowId.value = event.target.value;\n };\n const setEnabled = (event) => {\n enabled.value = event.target.checked;\n };\n const setSecretName = (event) => {\n secretName.value = event.target.value;\n };\n const setSecretValue = (event) => {\n secretValue.value = event.target.value;\n };\n const selectSecret = (name) => {\n secretName.value = name;\n secretValueInput.value?.focus();\n };\n const visitWorkflow = (id) => {\n window.location.href = `/workflows/${id}`;\n };\n\n onInit(() => {\n const loadPage =\n page === 'editor'\n ? initialId\n ? openWorkflow(initialId)\n : Promise.resolve()\n : Promise.all([loadWorkflows(), loadSecrets()]);\n loadPage.catch((error) => showNotice(error.message, true));\n });\n return {\n workflows,\n secrets,\n source,\n workflowId,\n enabled,\n selectedId,\n secretName,\n secretValue,\n notice,\n noticeError,\n busy,\n validate,\n save,\n publish,\n remove,\n saveSecret,\n removeSecret,\n setSource,\n setWorkflowId,\n setEnabled,\n setSecretName,\n setSecretValue,\n selectSecret,\n visitWorkflow,\n };\n }\n <\/script>\n </template>\n\n <script type=\"module\">\n import '@li3/web';\n <\/script>\n <script src=\"https://cdn.tailwindcss.com\"><\/script>\n </body>\n</html>\n";
3861
3861
  //#endregion
3862
3862
  //#region src/workflows-ui.ts
3863
3863
  function Yn(e, t = "") {
@@ -8138,10 +8138,20 @@ var qo = /* @__PURE__ */ g({
8138
8138
  stringify: () => Ko,
8139
8139
  visit: () => lr,
8140
8140
  visitAsync: () => dr
8141
- });
8141
+ }), Jo = [{
8142
+ version: "001_add_workflow_enabled",
8143
+ async apply() {
8144
+ (await S.all("PRAGMA table_info(workflows)")).some((e) => e.name === "enabled") || await S.run("ALTER TABLE workflows ADD COLUMN enabled INTEGER NOT NULL DEFAULT 1");
8145
+ }
8146
+ }];
8147
+ async function Yo() {
8148
+ await S.exec("\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version TEXT PRIMARY KEY,\n applied_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n ");
8149
+ let e = new Set((await S.all("SELECT version FROM schema_migrations")).map((e) => e.version));
8150
+ for (let t of Jo) e.has(t.version) || (await t.apply(), await S.run("INSERT INTO schema_migrations (version) VALUES (?)", [t.version]));
8151
+ }
8142
8152
  //#endregion
8143
8153
  //#region src/parser/matrix-expander.ts
8144
- function Jo(e) {
8154
+ function Xo(e) {
8145
8155
  if (!e.matrix || Object.keys(e.matrix).length === 0) return [e];
8146
8156
  let t = e.matrix;
8147
8157
  return Object.keys(t).reduce((e, n) => {
@@ -8168,22 +8178,22 @@ function Jo(e) {
8168
8178
  }
8169
8179
  //#endregion
8170
8180
  //#region src/workflows.ts
8171
- function Yo(e) {
8181
+ function Zo(e) {
8172
8182
  let t = String(e || "").toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/^-+|-+$/g, "");
8173
8183
  if (!t) throw Error("Workflow requires a name or id");
8174
8184
  return t;
8175
8185
  }
8176
- function Xo(e) {
8186
+ function Qo(e) {
8177
8187
  let t = qo.parse(e);
8178
8188
  if (!t || typeof t != "object" || Array.isArray(t)) throw Error("Workflow must be a YAML object");
8179
8189
  if (t.includes) throw Error("includes is not supported for database workflows");
8180
8190
  if (typeof t.name != "string" || !t.name.trim()) throw Error("Workflow name is required");
8181
8191
  if (!Array.isArray(t.steps) || !t.steps.length) throw Error("Workflow requires at least one step");
8182
8192
  if (!t.on || typeof t.on != "object") throw Error("Workflow requires an on block");
8183
- return Jo(t).map((e) => {
8193
+ return Xo(t).map((e) => {
8184
8194
  let [t, n] = Object.entries(e.on).find(([e]) => e !== "schedule" && e !== "solar") || ["generic", {}];
8185
8195
  return {
8186
- id: Yo(e.id || e.name),
8196
+ id: Zo(e.id || e.name),
8187
8197
  name: e.name,
8188
8198
  on: {
8189
8199
  ...n,
@@ -8198,37 +8208,39 @@ function Xo(e) {
8198
8208
  };
8199
8209
  });
8200
8210
  }
8201
- var Zo = class {
8211
+ var $o = class {
8202
8212
  async init() {
8203
- await S.exec("\n CREATE TABLE IF NOT EXISTS workflows (\n id TEXT PRIMARY KEY, name TEXT NOT NULL, source_yaml TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'draft', active_revision INTEGER,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n CREATE TABLE IF NOT EXISTS workflow_revisions (\n workflow_id TEXT NOT NULL, revision INTEGER NOT NULL, source_yaml TEXT NOT NULL,\n normalized_json TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (workflow_id, revision)\n );\n CREATE TABLE IF NOT EXISTS scheduled_runs (\n workflow_id TEXT NOT NULL, trigger_id TEXT NOT NULL, scheduled_for TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (workflow_id, trigger_id, scheduled_for)\n );\n ");
8213
+ await S.exec("\n CREATE TABLE IF NOT EXISTS workflows (\n id TEXT PRIMARY KEY, name TEXT NOT NULL, source_yaml TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'draft', active_revision INTEGER, enabled INTEGER NOT NULL DEFAULT 1,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n CREATE TABLE IF NOT EXISTS workflow_revisions (\n workflow_id TEXT NOT NULL, revision INTEGER NOT NULL, source_yaml TEXT NOT NULL,\n normalized_json TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (workflow_id, revision)\n );\n CREATE TABLE IF NOT EXISTS scheduled_runs (\n workflow_id TEXT NOT NULL, trigger_id TEXT NOT NULL, scheduled_for TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (workflow_id, trigger_id, scheduled_for)\n );\n "), await Yo();
8204
8214
  }
8205
8215
  validate(e) {
8206
- let t = Xo(e);
8216
+ let t = Qo(e);
8207
8217
  for (let e of t) {
8208
8218
  for (let t of e.schedule || []) if (typeof t.cron != "string" || t.cron.trim().split(/\s+/).length !== 5) throw Error("schedule.cron must have five fields");
8209
8219
  for (let t of e.solar || []) if (!t.event || !Number.isFinite(t.latitude) || !Number.isFinite(t.longitude)) throw Error("solar triggers require event, latitude, and longitude");
8210
8220
  }
8211
8221
  return t;
8212
8222
  }
8213
- async saveDraft(e, t) {
8214
- let n = this.validate(t);
8215
- if (n.length !== 1 || n[0].id !== e) throw Error("Workflow id must match the YAML name or id");
8216
- let r = await S.get("SELECT COALESCE(MAX(revision), 0) AS revision FROM workflow_revisions WHERE workflow_id = ?", [e]), i = Number(r?.revision || 0) + 1;
8217
- return await S.run("INSERT INTO workflows (id, name, source_yaml, status) VALUES (?, ?, ?, 'draft')\n ON CONFLICT(id) DO UPDATE SET name = excluded.name, source_yaml = excluded.source_yaml, status = 'draft', updated_at = CURRENT_TIMESTAMP", [
8223
+ async saveDraft(e, t, n = !0) {
8224
+ let r = this.validate(t);
8225
+ if (r.length !== 1 || r[0].id !== e) throw Error("Workflow id must match the YAML name or id");
8226
+ let i = await S.get("SELECT COALESCE(MAX(revision), 0) AS revision FROM workflow_revisions WHERE workflow_id = ?", [e]), a = Number(i?.revision || 0) + 1;
8227
+ return await S.run("INSERT INTO workflows (id, name, source_yaml, status, enabled) VALUES (?, ?, ?, 'draft', ?)\n ON CONFLICT(id) DO UPDATE SET name = excluded.name, source_yaml = excluded.source_yaml, status = 'draft', enabled = excluded.enabled, updated_at = CURRENT_TIMESTAMP", [
8218
8228
  e,
8219
- n[0].name,
8220
- t
8229
+ r[0].name,
8230
+ t,
8231
+ +!!n
8221
8232
  ]), await S.run("INSERT INTO workflow_revisions (workflow_id, revision, source_yaml, normalized_json) VALUES (?, ?, ?, ?)", [
8222
8233
  e,
8223
- i,
8234
+ a,
8224
8235
  t,
8225
- JSON.stringify(n[0])
8236
+ JSON.stringify(r[0])
8226
8237
  ]), {
8227
8238
  id: e,
8228
- name: n[0].name,
8239
+ name: r[0].name,
8229
8240
  sourceYaml: t,
8230
- revision: i,
8231
- status: "draft"
8241
+ revision: a,
8242
+ status: "draft",
8243
+ enabled: n
8232
8244
  };
8233
8245
  }
8234
8246
  async publish(e) {
@@ -8241,33 +8253,36 @@ var Zo = class {
8241
8253
  name: t.name,
8242
8254
  sourceYaml: t.source_yaml,
8243
8255
  revision: Number(n.revision),
8244
- status: "published"
8256
+ status: "published",
8257
+ enabled: !!t.enabled
8245
8258
  };
8246
8259
  }
8247
8260
  async list() {
8248
- return (await S.all("SELECT id, name, source_yaml, COALESCE(active_revision, 0) AS revision, status FROM workflows ORDER BY name")).map((e) => ({
8261
+ return (await S.all("SELECT id, name, source_yaml, COALESCE(active_revision, 0) AS revision, status, enabled FROM workflows ORDER BY name")).map((e) => ({
8249
8262
  id: e.id,
8250
8263
  name: e.name,
8251
8264
  sourceYaml: e.source_yaml,
8252
8265
  revision: Number(e.revision),
8253
- status: e.status
8266
+ status: e.status,
8267
+ enabled: !!e.enabled
8254
8268
  }));
8255
8269
  }
8256
8270
  async get(e) {
8257
- let t = await S.get("SELECT id, name, source_yaml, COALESCE(active_revision, 0) AS revision, status FROM workflows WHERE id = ?", [e]);
8271
+ let t = await S.get("SELECT id, name, source_yaml, COALESCE(active_revision, 0) AS revision, status, enabled FROM workflows WHERE id = ?", [e]);
8258
8272
  return t ? {
8259
8273
  id: t.id,
8260
8274
  name: t.name,
8261
8275
  sourceYaml: t.source_yaml,
8262
8276
  revision: Number(t.revision),
8263
- status: t.status
8277
+ status: t.status,
8278
+ enabled: !!t.enabled
8264
8279
  } : null;
8265
8280
  }
8266
8281
  async delete(e) {
8267
8282
  return await this.get(e) ? (await S.run("DELETE FROM scheduled_runs WHERE workflow_id = ?", [e]), await S.run("DELETE FROM workflow_revisions WHERE workflow_id = ?", [e]), await S.run("DELETE FROM workflows WHERE id = ?", [e]), !0) : !1;
8268
8283
  }
8269
8284
  async published() {
8270
- return (await S.all("SELECT w.id AS workflow_id, r.revision, r.normalized_json FROM workflows w JOIN workflow_revisions r\n ON r.workflow_id = w.id AND r.revision = w.active_revision WHERE w.status = 'published'")).map((e) => ({
8285
+ return (await S.all("SELECT w.id AS workflow_id, r.revision, r.normalized_json FROM workflows w JOIN workflow_revisions r\n ON r.workflow_id = w.id AND r.revision = w.active_revision WHERE w.status = 'published' AND w.enabled = 1")).map((e) => ({
8271
8286
  workflowId: e.workflow_id,
8272
8287
  revision: Number(e.revision),
8273
8288
  definition: JSON.parse(e.normalized_json)
@@ -8284,10 +8299,10 @@ var Zo = class {
8284
8299
  n
8285
8300
  ]);
8286
8301
  }
8287
- }, Qo = 50, $o = 500, es = class e {
8302
+ }, es = 50, ts = 500, ns = class e {
8288
8303
  server;
8289
8304
  preprocessors = /* @__PURE__ */ new Map();
8290
- workflows = new Zo();
8305
+ workflows = new $o();
8291
8306
  secretRepository = new qn();
8292
8307
  queue;
8293
8308
  secrets;
@@ -8334,8 +8349,8 @@ var Zo = class {
8334
8349
  }), t.end(Yn("editor", n));
8335
8350
  }
8336
8351
  if (e.method === "GET" && n.pathname === "/api/jobs") {
8337
- let e = n.searchParams.get("afterId"), r = n.searchParams.get("beforeId"), i = n.searchParams.get("limit"), a = e === null ? void 0 : Number(e), o = r === null ? void 0 : Number(r), s = i === null ? Qo : Number(i);
8338
- return a !== void 0 && (!Number.isSafeInteger(a) || a < 0) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "afterId must be a non-negative integer" }))) : o !== void 0 && (!Number.isSafeInteger(o) || o < 1) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "beforeId must be a positive integer" }))) : !Number.isSafeInteger(s) || s < 1 || s > $o ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: `limit must be an integer from 1 to ${$o}` }))) : this.renderDashboardJobs(t, s, a, o);
8352
+ let e = n.searchParams.get("afterId"), r = n.searchParams.get("beforeId"), i = n.searchParams.get("limit"), a = e === null ? void 0 : Number(e), o = r === null ? void 0 : Number(r), s = i === null ? es : Number(i);
8353
+ return a !== void 0 && (!Number.isSafeInteger(a) || a < 0) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "afterId must be a non-negative integer" }))) : o !== void 0 && (!Number.isSafeInteger(o) || o < 1) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "beforeId must be a positive integer" }))) : !Number.isSafeInteger(s) || s < 1 || s > ts ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: `limit must be an integer from 1 to ${ts}` }))) : this.renderDashboardJobs(t, s, a, o);
8339
8354
  }
8340
8355
  if (e.method === "GET" && n.pathname === "/api/events") return this.events.subscribe(e, t);
8341
8356
  if (n.pathname === "/api/workflows/validate" && e.method === "POST") return this.handleWorkflowValidation(e, t);
@@ -8526,7 +8541,7 @@ var Zo = class {
8526
8541
  return;
8527
8542
  }
8528
8543
  try {
8529
- let e = await this.workflows.saveDraft(n, r.sourceYaml);
8544
+ let e = await this.workflows.saveDraft(n, r.sourceYaml, r.enabled !== !1);
8530
8545
  t.writeHead(200, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify(e));
8531
8546
  } catch (e) {
8532
8547
  t.writeHead(422, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: e.message }));
@@ -8593,7 +8608,7 @@ var Zo = class {
8593
8608
  this.events.publish("jobs.changed", r ? { jobId: r } : {}), t.writeHead(202).end();
8594
8609
  }
8595
8610
  async renderDashboard(e) {
8596
- let t = await this.queue.listJobs(51), n = fe(t.slice(0, Qo)), r = await this.redactText(pe(n, t.length > Qo));
8611
+ let t = await this.queue.listJobs(51), n = fe(t.slice(0, es)), r = await this.redactText(pe(n, t.length > es));
8597
8612
  e.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }), e.end(r);
8598
8613
  }
8599
8614
  async renderDashboardJobs(e, t, n, r) {
@@ -8653,8 +8668,8 @@ var Zo = class {
8653
8668
  async redactText(e) {
8654
8669
  return this.redact(e, await this.currentSecrets());
8655
8670
  }
8656
- listen(e) {
8657
- return new Promise((t) => {
8671
+ async listen(e) {
8672
+ return await this.workflowsLoaded, new Promise((t) => {
8658
8673
  this.server.listen(e, process.env.RUNNER_HOST || "0.0.0.0", () => {
8659
8674
  console.log(`🌐 Webhook Ingress Server running on port ${e}`), t(this);
8660
8675
  });
@@ -8667,7 +8682,7 @@ var Zo = class {
8667
8682
  });
8668
8683
  });
8669
8684
  }
8670
- }, ts = class extends m {
8685
+ }, rs = class extends m {
8671
8686
  fd;
8672
8687
  pending = "";
8673
8688
  constructor(e) {
@@ -8690,7 +8705,7 @@ var Zo = class {
8690
8705
  }
8691
8706
  e.write(this.fd, t, 0, "utf8", (e) => n(e));
8692
8707
  }
8693
- }, ns = s(d), rs = class {
8708
+ }, is = s(d), as = class {
8694
8709
  name = "systemd";
8695
8710
  async isSupported() {
8696
8711
  try {
@@ -8702,7 +8717,7 @@ var Zo = class {
8702
8717
  execute(t) {
8703
8718
  let n = null, r = null, a = Date.now(), o = i.join(t.logsDir, `step-${t.step.id}.log`);
8704
8719
  try {
8705
- e.mkdirSync(t.logsDir, { recursive: !0 }), e.mkdirSync(t.workingDir, { recursive: !0 }), e.chmodSync(t.workingDir, 511), n = e.openSync(o, "a"), r = new ts(n);
8720
+ e.mkdirSync(t.logsDir, { recursive: !0 }), e.mkdirSync(t.workingDir, { recursive: !0 }), e.chmodSync(t.workingDir, 511), n = e.openSync(o, "a"), r = new rs(n);
8706
8721
  } catch (e) {
8707
8722
  return {
8708
8723
  done: Promise.resolve({
@@ -8812,7 +8827,7 @@ var Zo = class {
8812
8827
  cancel: async () => {
8813
8828
  p = !0;
8814
8829
  try {
8815
- t.image && await ns(`docker stop -t 2 ${s}`).catch(() => {}), await ns(`systemctl stop ${s}.service`).catch(() => {});
8830
+ t.image && await is(`docker stop -t 2 ${s}`).catch(() => {}), await is(`systemctl stop ${s}.service`).catch(() => {});
8816
8831
  } catch {}
8817
8832
  },
8818
8833
  logFilePath: o
@@ -8822,7 +8837,7 @@ var Zo = class {
8822
8837
  let t = await p(e, "utf-8"), n = t.includes("Running as unit: ") ? t.indexOf("\n") + 1 : 0, r = t.includes("Finished with result: ") ? t.lastIndexOf("Finished with result: ") : t.length;
8823
8838
  return t.slice(n, r);
8824
8839
  }
8825
- }, is = class {
8840
+ }, os = class {
8826
8841
  name = "standard-process";
8827
8842
  async isSupported() {
8828
8843
  return !0;
@@ -8830,7 +8845,7 @@ var Zo = class {
8830
8845
  execute(t) {
8831
8846
  let n = null, r = null, a = Date.now(), o = i.join(t.logsDir, `step-${t.step.id}.log`);
8832
8847
  try {
8833
- e.mkdirSync(t.logsDir, { recursive: !0 }), e.mkdirSync(t.workingDir, { recursive: !0 }), e.chmodSync(t.workingDir, 511), n = e.openSync(o, "a"), r = new ts(n);
8848
+ e.mkdirSync(t.logsDir, { recursive: !0 }), e.mkdirSync(t.workingDir, { recursive: !0 }), e.chmodSync(t.workingDir, 511), n = e.openSync(o, "a"), r = new rs(n);
8834
8849
  } catch (e) {
8835
8850
  return {
8836
8851
  done: Promise.resolve({
@@ -8936,19 +8951,19 @@ var Zo = class {
8936
8951
  };
8937
8952
  //#endregion
8938
8953
  //#region src/drivers/index.ts
8939
- async function as() {
8940
- let e = new rs();
8941
- return await e.isSupported() ? (console.log("⚡ Selected Execution Driver: Systemd (cgroups enabled)"), e) : (console.log("📦 Selected Execution Driver: Standard Process (Fallback)"), new is());
8954
+ async function ss() {
8955
+ let e = new as();
8956
+ return await e.isSupported() ? (console.log("⚡ Selected Execution Driver: Systemd (cgroups enabled)"), e) : (console.log("📦 Selected Execution Driver: Standard Process (Fallback)"), new os());
8942
8957
  }
8943
8958
  //#endregion
8944
8959
  //#region src/signals.ts
8945
- async function os(e) {
8960
+ async function cs(e) {
8946
8961
  let t = !1;
8947
8962
  async function n(n) {
8948
8963
  if (!t) {
8949
8964
  t = !0, console.log(`\n🛑 Received ${n}. Initiating graceful shutdown...`);
8950
8965
  try {
8951
- fs(), e.length > 0 && (console.log("⚙️ Waiting for active worker jobs to drain..."), await Promise.allSettled(e)), console.log("✨ Engine stopped cleanly. Goodbye!"), process.exit(0);
8966
+ ms(), e.length > 0 && (console.log("⚙️ Waiting for active worker jobs to drain..."), await Promise.allSettled(e)), console.log("✨ Engine stopped cleanly. Goodbye!"), process.exit(0);
8952
8967
  } catch (e) {
8953
8968
  console.error("❌ Error during graceful shutdown:", e.message), process.exit(1);
8954
8969
  }
@@ -8958,7 +8973,7 @@ async function os(e) {
8958
8973
  }
8959
8974
  //#endregion
8960
8975
  //#region src/plugins/manager.ts
8961
- var ss = class {
8976
+ var ls = class {
8962
8977
  plugins;
8963
8978
  constructor(e = []) {
8964
8979
  this.plugins = e;
@@ -8980,38 +8995,38 @@ var ss = class {
8980
8995
  console.error(`[Plugin Error] ${n.name}.onWorkflowFinish:`, e);
8981
8996
  }
8982
8997
  }
8983
- }, cs = { isStopping: !1 }, ls = /* @__PURE__ */ new Set(), us = null, ds = null;
8984
- function fs() {
8985
- cs.isStopping = !0, us?.abort(), ds?.();
8998
+ }, us = { isStopping: !1 }, ds = /* @__PURE__ */ new Set(), fs = null, ps = null;
8999
+ function ms() {
9000
+ us.isStopping = !0, fs?.abort(), ps?.();
8986
9001
  }
8987
- function ps(e, t, n, r) {
8988
- cs.isStopping = !1;
8989
- let i = [ms(e, t, n, r)];
8990
- return os(i), i;
9002
+ function hs(e, t, n, r) {
9003
+ us.isStopping = !1;
9004
+ let i = [gs(e, t, n, r)];
9005
+ return cs(i), i;
8991
9006
  }
8992
- async function ms(e, t, n, r) {
8993
- let i = await as(), a = new Zo(), o = /* @__PURE__ */ new Set(), s = 0, c = null, l = () => {
9007
+ async function gs(e, t, n, r) {
9008
+ let i = await ss(), a = new $o(), o = /* @__PURE__ */ new Set(), s = 0, c = null, l = () => {
8994
9009
  s++, c?.();
8995
9010
  };
8996
- ds = l, us = new AbortController();
8997
- let u = hs(r, us.signal, l);
8998
- for (console.log(`🚀 Worker scheduler started. Driver: ${i.name}. Concurrency: ${e}. Tags: ${r.tags.join(", ") || "(none)"}`); !cs.isStopping;) {
9011
+ ps = l, fs = new AbortController();
9012
+ let u = _s(r, fs.signal, l);
9013
+ for (console.log(`🚀 Worker scheduler started. Driver: ${i.name}. Concurrency: ${e}. Tags: ${r.tags.join(", ") || "(none)"}`); !us.isStopping;) {
8999
9014
  let n = s;
9000
9015
  try {
9001
- for (; o.size < e && !cs.isStopping;) {
9016
+ for (; o.size < e && !us.isStopping;) {
9002
9017
  let e = await t.claimNextJob(r.tags);
9003
9018
  if (!e) break;
9004
- if (cs.isStopping) {
9019
+ if (us.isStopping) {
9005
9020
  await t.releaseJob(e.id);
9006
9021
  break;
9007
9022
  }
9008
9023
  let n = process.env.WORKER_NAME || "cli", s;
9009
9024
  s = (async () => {
9010
- vs(r, e.id);
9025
+ bs(r, e.id);
9011
9026
  let o = await a.getRevision(e.workflow_id, e.workflow_revision);
9012
9027
  if (!o) throw await t.finishJob(e.id, "failed"), Error(`Workflow ${e.workflow_id} revision ${e.workflow_revision} was not found`);
9013
9028
  let s = new le();
9014
- s.replace(await ys(r, n, e.id)), await bs({
9029
+ s.replace(await xs(r, n, e.id)), await Ss({
9015
9030
  workerId: n,
9016
9031
  job: e,
9017
9032
  queue: t,
@@ -9021,17 +9036,17 @@ async function ms(e, t, n, r) {
9021
9036
  workflow: o
9022
9037
  });
9023
9038
  })().catch((e) => console.error(`[${n}] ⚠️ Worker execution error:`, e)).finally(() => {
9024
- o.delete(s), vs(r, e.id), l();
9039
+ o.delete(s), bs(r, e.id), l();
9025
9040
  }), o.add(s);
9026
9041
  }
9027
9042
  } catch (e) {
9028
9043
  console.error("⚠️ Worker scheduler claim error:", e), setTimeout(l, 5e3).unref();
9029
9044
  }
9030
- !cs.isStopping && s === n && (await gs(n, () => s, (e) => c = e), c = null);
9045
+ !us.isStopping && s === n && (await vs(n, () => s, (e) => c = e), c = null);
9031
9046
  }
9032
- us.abort(), await Promise.allSettled(o), await u, ds = null, console.log("🛑 Worker scheduler stopped cleanly.");
9047
+ fs.abort(), await Promise.allSettled(o), await u, ps = null, console.log("🛑 Worker scheduler stopped cleanly.");
9033
9048
  }
9034
- async function hs(e, t, n) {
9049
+ async function _s(e, t, n) {
9035
9050
  let r = 1e3;
9036
9051
  for (; !t.aborted;) {
9037
9052
  try {
@@ -9042,10 +9057,10 @@ async function hs(e, t, n) {
9042
9057
  if (t.aborted || e?.name === "AbortError") break;
9043
9058
  console.error(`⚠️ Worker event stream disconnected: ${e.message}`);
9044
9059
  }
9045
- await _s(r, t), r = Math.min(r * 2, 3e4);
9060
+ await ys(r, t), r = Math.min(r * 2, 3e4);
9046
9061
  }
9047
9062
  }
9048
- function gs(e, t, n) {
9063
+ function vs(e, t, n) {
9049
9064
  return new Promise((r) => {
9050
9065
  if (t() !== e) return r();
9051
9066
  let i = setTimeout(r, 6e4);
@@ -9054,7 +9069,7 @@ function gs(e, t, n) {
9054
9069
  });
9055
9070
  });
9056
9071
  }
9057
- function _s(e, t) {
9072
+ function ys(e, t) {
9058
9073
  return new Promise((n) => {
9059
9074
  if (t.aborted) return n();
9060
9075
  let r = () => {
@@ -9065,7 +9080,7 @@ function _s(e, t) {
9065
9080
  t.addEventListener("abort", r, { once: !0 });
9066
9081
  });
9067
9082
  }
9068
- async function vs(e, t) {
9083
+ async function bs(e, t) {
9069
9084
  if (e.workerToken) try {
9070
9085
  let n = await fetch(new URL("/api/events", e.serverUrl), {
9071
9086
  method: "POST",
@@ -9081,7 +9096,7 @@ async function vs(e, t) {
9081
9096
  Hn("Failed to publish job status event:", e);
9082
9097
  }
9083
9098
  }
9084
- async function ys(e, t, n) {
9099
+ async function xs(e, t, n) {
9085
9100
  if (!e.workerToken) return {};
9086
9101
  try {
9087
9102
  let r = await fetch(new URL(`/api/jobs/${n}/secrets`, e.serverUrl), {
@@ -9097,7 +9112,7 @@ async function ys(e, t, n) {
9097
9112
  throw console.error(`Unable to retrieve secrets for job ${n}:`, e), e;
9098
9113
  }
9099
9114
  }
9100
- async function bs(e) {
9115
+ async function Ss(e) {
9101
9116
  let { workerId: t, job: n, config: r, secrets: a, queue: o } = e;
9102
9117
  console.log(`\n[${t}] 📦 Claimed Job #${n.id} (Workflow: ${n.workflow_id})`);
9103
9118
  let s = typeof n.payload == "string" ? JSON.parse(n.payload) : n.payload;
@@ -9117,27 +9132,27 @@ async function bs(e) {
9117
9132
  durationMs: 0,
9118
9133
  outputs: {},
9119
9134
  logContent: ""
9120
- })), g = Ds(n, "running", u, l, m.env, h, s);
9121
- await o.saveReport(n.id, g), vs(r, n.id);
9122
- let _ = new ss(r.plugins), v = {
9135
+ })), g = ks(n, "running", u, l, m.env, h, s);
9136
+ await o.saveReport(n.id, g), bs(r, n.id);
9137
+ let _ = new ls(r.plugins), v = {
9123
9138
  jobId: String(n.id),
9124
9139
  workflowName: n.workflow_id,
9125
9140
  inputs: l,
9126
9141
  runUrl: new URL(`/runs/${n.id}`, r.serverUrl).toString()
9127
9142
  };
9128
9143
  await _.triggerWorkflowStart(v);
9129
- let { cancelled: y, failed: ee } = await xs({
9144
+ let { cancelled: y, failed: ee } = await Cs({
9130
9145
  payload: s,
9131
9146
  steps: c,
9132
9147
  executionContext: m,
9133
9148
  ...e
9134
9149
  }, g), b = y ? "cancelled" : ee ? "failed" : "success";
9135
- g.status = b, g.durationMs = Date.now() - u, g.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), await o.completeJob(n.id, b, g), vs(r, n.id), console.log(`[${t}] ✅ Job #${n.id} completed as: ${b}`), await _.triggerWorkflowFinish(v, b);
9150
+ g.status = b, g.durationMs = Date.now() - u, g.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), await o.completeJob(n.id, b, g), bs(r, n.id), console.log(`[${t}] ✅ Job #${n.id} completed as: ${b}`), await _.triggerWorkflowFinish(v, b);
9136
9151
  }
9137
- async function xs(e, t) {
9152
+ async function Cs(e, t) {
9138
9153
  let { driver: n, workerId: r, queue: i, config: a, job: o, payload: s, steps: c, executionContext: l } = e, u = t.steps, d = !1, f = !1, p = 0;
9139
9154
  try {
9140
- e.workflow?.env && Object.assign(l.env, await ws(e.workflow.env, l));
9155
+ e.workflow?.env && Object.assign(l.env, await Es(e.workflow.env, l));
9141
9156
  for (let e = 0; e < c.length; e++) {
9142
9157
  let s = c[e], m = (/* @__PURE__ */ new Date()).toISOString();
9143
9158
  u[e] = {
@@ -9150,8 +9165,8 @@ async function xs(e, t) {
9150
9165
  logContent: "",
9151
9166
  startedAt: m,
9152
9167
  finishedAt: void 0
9153
- }, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), vs(a, o.id);
9154
- let h = await Ss({
9168
+ }, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), bs(a, o.id);
9169
+ let h = await ws({
9155
9170
  workerId: r,
9156
9171
  jobId: o.id,
9157
9172
  step: s,
@@ -9178,7 +9193,7 @@ async function xs(e, t) {
9178
9193
  exitCode: 1,
9179
9194
  error: "Step failed before execution started",
9180
9195
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
9181
- }, p = e + 1, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), vs(a, o.id), h.skipped) break;
9196
+ }, p = e + 1, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), bs(a, o.id), h.skipped) break;
9182
9197
  if (h.cancelled) {
9183
9198
  f = !0, d = !0;
9184
9199
  break;
@@ -9191,13 +9206,13 @@ async function xs(e, t) {
9191
9206
  } catch (e) {
9192
9207
  console.log("🛑 Step failed", e), d = !0;
9193
9208
  }
9194
- return p < c.length && (Es(c, p, u), t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), vs(a, o.id)), {
9209
+ return p < c.length && (Os(c, p, u), t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t), bs(a, o.id)), {
9195
9210
  failed: d,
9196
9211
  cancelled: f,
9197
9212
  stepReports: u
9198
9213
  };
9199
9214
  }
9200
- async function Ss(e) {
9215
+ async function ws(e) {
9201
9216
  let { step: t, stepIndex: n, executionContext: r } = e;
9202
9217
  if (t.id ||= `step-${n}`, t.name ||= t.id, t.if && !await Gn.evaluateConditions(t.if, r)) return Hn(`⏩ Skipped step ${t.id} based on condition: ${t.if}`, r), {
9203
9218
  failed: !1,
@@ -9206,7 +9221,7 @@ async function Ss(e) {
9206
9221
  report: null
9207
9222
  };
9208
9223
  try {
9209
- let n = await ws(t.env, r), i = {
9224
+ let n = await Es(t.env, r), i = {
9210
9225
  jobId: String(e.jobId),
9211
9226
  step: t,
9212
9227
  command: t.run,
@@ -9220,10 +9235,10 @@ async function Ss(e) {
9220
9235
  WORKING_DIR: r.workingDir
9221
9236
  }
9222
9237
  };
9223
- return t.eval ? Cs({
9238
+ return t.eval ? Ts({
9224
9239
  ...e,
9225
9240
  stepContext: i
9226
- }) : Ts({
9241
+ }) : Ds({
9227
9242
  ...e,
9228
9243
  stepContext: i
9229
9244
  });
@@ -9236,7 +9251,7 @@ async function Ss(e) {
9236
9251
  };
9237
9252
  }
9238
9253
  }
9239
- async function Cs(e) {
9254
+ async function Ts(e) {
9240
9255
  let { queue: t, stepContext: n, executionContext: r } = e, { jobId: i, step: a } = n, o = Date.now(), s = a.id, c = a.name;
9241
9256
  try {
9242
9257
  let e = await Gn.evaluateExpression(a.eval, r);
@@ -9282,12 +9297,12 @@ async function Cs(e) {
9282
9297
  };
9283
9298
  }
9284
9299
  }
9285
- async function ws(e, t) {
9300
+ async function Es(e, t) {
9286
9301
  let n = {};
9287
9302
  if (e) for (let [r, i] of Object.entries(e)) n[r] = String(await Gn.evaluateValue(i, t));
9288
9303
  return n;
9289
9304
  }
9290
- async function Ts(t) {
9305
+ async function Ds(t) {
9291
9306
  let { workerId: n, jobId: r, stepContext: i, executionContext: a, driver: o, queue: s } = t, { step: c } = i, l = c.id, u = c.name, d;
9292
9307
  try {
9293
9308
  d = o.execute(i);
@@ -9302,11 +9317,11 @@ async function Ts(t) {
9302
9317
  logFilePath: ""
9303
9318
  };
9304
9319
  }
9305
- ls.add(d);
9320
+ ds.add(d);
9306
9321
  let f = !1, p = setInterval(async () => {
9307
9322
  await s.isCancelled(r) && (console.log(`[${n}] 🛑 Job #${r} was cancelled! Halting execution.`), f = !0, clearInterval(p), await d.cancel());
9308
9323
  }, 3e3), m = await d.done;
9309
- if (clearInterval(p), ls.delete(d), d.logFilePath && e.existsSync(d.logFilePath)) try {
9324
+ if (clearInterval(p), ds.delete(d), d.logFilePath && e.existsSync(d.logFilePath)) try {
9310
9325
  let e = await o.readLog(d.logFilePath);
9311
9326
  await s.saveStepLog(r, l, e);
9312
9327
  } catch (e) {
@@ -9333,7 +9348,7 @@ async function Ts(t) {
9333
9348
  }
9334
9349
  };
9335
9350
  }
9336
- function Es(e, t, n) {
9351
+ function Os(e, t, n) {
9337
9352
  for (let r = t; r < e.length; r++) {
9338
9353
  let t = e[r], i = t.id || `step-${r}`;
9339
9354
  n[r] = {
@@ -9347,7 +9362,7 @@ function Es(e, t, n) {
9347
9362
  };
9348
9363
  }
9349
9364
  }
9350
- function Ds(e, t, n, r, i, a, o) {
9365
+ function ks(e, t, n, r, i, a, o) {
9351
9366
  return {
9352
9367
  jobId: String(e.id),
9353
9368
  parentId: String(e.parentId || ""),
@@ -9368,7 +9383,7 @@ function Ds(e, t, n, r, i, a, o) {
9368
9383
  }
9369
9384
  //#endregion
9370
9385
  //#region src/scheduler.ts
9371
- function Os(e, t, n, r) {
9386
+ function As(e, t, n, r) {
9372
9387
  return e.split(",").some((e) => {
9373
9388
  let [i, a] = e.split("/"), o = a ? Number(a) : 1;
9374
9389
  if (!Number.isInteger(o) || o < 1) return !1;
@@ -9376,7 +9391,7 @@ function Os(e, t, n, r) {
9376
9391
  return Number.isInteger(l) && Number.isInteger(u) && t >= l && t <= u && (t - l) % o === 0;
9377
9392
  });
9378
9393
  }
9379
- function ks(e, t, n = "UTC") {
9394
+ function js(e, t, n = "UTC") {
9380
9395
  let r = e.trim().split(/\s+/);
9381
9396
  if (r.length !== 5) return !1;
9382
9397
  let i = new Intl.DateTimeFormat("en-US", {
@@ -9398,16 +9413,16 @@ function ks(e, t, n = "UTC") {
9398
9413
  "Thu",
9399
9414
  "Fri",
9400
9415
  "Sat"
9401
- ].indexOf(i.weekday), o = Os(r[2], Number(i.day), 1, 31), s = Os(r[4].replace(/7/g, "0"), a, 0, 6);
9402
- return Os(r[0], Number(i.minute), 0, 59) && Os(r[1], Number(i.hour), 0, 23) && Os(r[3], Number(i.month), 1, 12) && (r[2] === "*" || r[4] === "*" ? o && s : o || s);
9416
+ ].indexOf(i.weekday), o = As(r[2], Number(i.day), 1, 31), s = As(r[4].replace(/7/g, "0"), a, 0, 6);
9417
+ return As(r[0], Number(i.minute), 0, 59) && As(r[1], Number(i.hour), 0, 23) && As(r[3], Number(i.month), 1, 12) && (r[2] === "*" || r[4] === "*" ? o && s : o || s);
9403
9418
  }
9404
- function As(e) {
9419
+ function Ms(e) {
9405
9420
  if (!e) return 0;
9406
9421
  let t = e.match(/^([+-]?)(\d+)(m|h)$/);
9407
9422
  if (!t) throw Error(`Invalid solar offset: ${e}`);
9408
9423
  return (t[1] === "-" ? -1 : 1) * Number(t[2]) * (t[3] === "h" ? 36e5 : 6e4);
9409
9424
  }
9410
- function js(e, t) {
9425
+ function Ns(e, t) {
9411
9426
  let n = t.latitude, r = t.longitude, i = Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), e.getUTCDate()), a = Math.floor((i - Date.UTC(e.getUTCFullYear(), 0, 0)) / 864e5), o = r / 15, s = a + ((t.event === "sunrise" ? 6 : 18) - o) / 24, c = .9856 * s - 3.289, l = c + 1.916 * Math.sin(c * Math.PI / 180) + .02 * Math.sin(2 * c * Math.PI / 180) + 282.634;
9412
9427
  l = (l + 360) % 360;
9413
9428
  let u = Math.atan(.91764 * Math.tan(l * Math.PI / 180)) * 180 / Math.PI;
@@ -9415,9 +9430,9 @@ function js(e, t) {
9415
9430
  let d = .39782 * Math.sin(l * Math.PI / 180), f = Math.cos(Math.asin(d)), p = (Math.cos(90.833 * Math.PI / 180) - d * Math.sin(n * Math.PI / 180)) / (f * Math.cos(n * Math.PI / 180));
9416
9431
  if (p > 1 || p < -1) return null;
9417
9432
  let m = (t.event === "sunrise" ? 360 - Math.acos(p) * 180 / Math.PI : Math.acos(p) * 180 / Math.PI) / 15;
9418
- return m = (m + u - .06571 * s - 6.622 - o + 24) % 24, new Date(i + m * 36e5 + As(t.offset));
9433
+ return m = (m + u - .06571 * s - 6.622 - o + 24) % 24, new Date(i + m * 36e5 + Ms(t.offset));
9419
9434
  }
9420
- var Ms = class {
9435
+ var Ps = class {
9421
9436
  queue;
9422
9437
  workflows;
9423
9438
  config;
@@ -9434,9 +9449,9 @@ var Ms = class {
9434
9449
  async tick(e = /* @__PURE__ */ new Date()) {
9435
9450
  let t = /* @__PURE__ */ new Date(Math.floor(e.getTime() / 6e4) * 6e4);
9436
9451
  for (let { definition: e, revision: n } of await this.workflows.published()) {
9437
- for (let [r, i] of (e.schedule || []).entries()) ks(i.cron, t, i.timezone || "UTC") && await this.enqueue(e, n, i, `cron-${r}`, t);
9452
+ for (let [r, i] of (e.schedule || []).entries()) js(i.cron, t, i.timezone || "UTC") && await this.enqueue(e, n, i, `cron-${r}`, t);
9438
9453
  for (let [r, i] of (e.solar || []).entries()) {
9439
- let a = js(t, i);
9454
+ let a = Ns(t, i);
9440
9455
  a && Math.floor(a.getTime() / 6e4) === t.getTime() / 6e4 && await this.enqueue(e, n, i, `solar-${r}`, t);
9441
9456
  }
9442
9457
  }
@@ -9452,7 +9467,7 @@ var Ms = class {
9452
9467
  } } };
9453
9468
  await this.queue.enqueue(e.id, t, o, e.tags), console.log(`Scheduled ${e.id} via ${a}`);
9454
9469
  }
9455
- }, Ns = class {
9470
+ }, Fs = class {
9456
9471
  name = "github-commit-status";
9457
9472
  token;
9458
9473
  apiUrl;
@@ -9494,13 +9509,13 @@ var Ms = class {
9494
9509
  };
9495
9510
  //#endregion
9496
9511
  //#region src/index.ts
9497
- async function Ps() {
9512
+ async function Is() {
9498
9513
  let { config: e, command: t } = await se();
9499
9514
  e || process.exit(1);
9500
9515
  let n = new le(), r = new ce(process.env.WORKER_NAME || "cli");
9501
9516
  switch (t) {
9502
9517
  case "start-server":
9503
- console.log("🌐 Starting Ingress Gateway..."), await r.init(), await es.withPort({
9518
+ console.log("🌐 Starting Ingress Gateway..."), await r.init(), await ns.withPort({
9504
9519
  config: e,
9505
9520
  queue: r,
9506
9521
  secrets: n,
@@ -9509,13 +9524,13 @@ async function Ps() {
9509
9524
  });
9510
9525
  break;
9511
9526
  case "start-workers":
9512
- console.log(`⚙️ Starting worker scheduler with ${e.workers} concurrent slot(s)...`), await r.init(), ps(e.workers, r, n, e);
9527
+ console.log(`⚙️ Starting worker scheduler with ${e.workers} concurrent slot(s)...`), await r.init(), hs(e.workers, r, n, e);
9513
9528
  break;
9514
9529
  case "start-scheduler": {
9515
9530
  console.log("Starting workflow scheduler..."), await r.init();
9516
- let t = new Zo();
9531
+ let t = new $o();
9517
9532
  await t.init();
9518
- let n = new Ms(r, t, e);
9533
+ let n = new Ps(r, t, e);
9519
9534
  n.start();
9520
9535
  let i = () => {
9521
9536
  n.stop(), process.exit(0);
@@ -9526,6 +9541,6 @@ async function Ps() {
9526
9541
  default: console.error(`❌ Unknown command: '${t}'`), oe(), process.exit(1);
9527
9542
  }
9528
9543
  }
9529
- Ps().catch(console.error);
9544
+ Is().catch(console.error);
9530
9545
  //#endregion
9531
- export { Ns as GitHubStatusPlugin };
9546
+ export { Fs as GitHubStatusPlugin };
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAc,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAOxF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,eAAe,CAAgB;WAE1B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;gBAK1D,OAAO,EAAE,oBAAoB;IAYzC,oBAAoB,CAAC,YAAY,EAAE,mBAAmB;YAIxC,aAAa;IA8H3B;;OAEG;YACW,aAAa;YA0Bb,WAAW;YAwBX,UAAU;YAyBV,cAAc;IAuC5B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,YAAY;YAUN,QAAQ;YAYR,wBAAwB;YAcxB,kBAAkB;YAOlB,iBAAiB;YAWjB,kBAAkB;YAoBlB,oBAAoB;YASpB,qBAAqB;YAWrB,gBAAgB;YAMhB,gBAAgB;YAiBhB,kBAAkB;YASlB,gBAAgB;IAc9B;;OAEG;YACW,kBAAkB;YAclB,iBAAiB;IAuB/B;;OAEG;YACW,eAAe;YAQf,mBAAmB;IAWjC;;OAEG;YACW,gBAAgB;YAuBhB,gBAAgB;YAehB,eAAe;YAkBf,cAAc;IAS5B,OAAO,CAAC,MAAM;YAMA,UAAU;IAIxB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAStC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAS5B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAc,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAOxF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,eAAe,CAAgB;WAE1B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;gBAK1D,OAAO,EAAE,oBAAoB;IAYzC,oBAAoB,CAAC,YAAY,EAAE,mBAAmB;YAIxC,aAAa;IA8H3B;;OAEG;YACW,aAAa;YA0Bb,WAAW;YAwBX,UAAU;YAyBV,cAAc;IAuC5B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,YAAY;YAUN,QAAQ;YAYR,wBAAwB;YAcxB,kBAAkB;YAOlB,iBAAiB;YAWjB,kBAAkB;YAoBlB,oBAAoB;YASpB,qBAAqB;YAWrB,gBAAgB;YAMhB,gBAAgB;YAiBhB,kBAAkB;YASlB,gBAAgB;IAc9B;;OAEG;YACW,kBAAkB;YAclB,iBAAiB;IAuB/B;;OAEG;YACW,eAAe;YAQf,mBAAmB;IAWjC;;OAEG;YACW,gBAAgB;YAuBhB,gBAAgB;YAehB,eAAe;YAkBf,cAAc;IAS5B,OAAO,CAAC,MAAM;YAMA,UAAU;IAIlB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAU5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAS5B"}
@@ -5,13 +5,14 @@ export interface StoredWorkflow {
5
5
  sourceYaml: string;
6
6
  revision: number;
7
7
  status: 'draft' | 'published' | 'archived';
8
+ enabled: boolean;
8
9
  }
9
10
  /** Parses the portable, DB-stored YAML format. Includes are deliberately unsupported. */
10
11
  export declare function parseWorkflow(sourceYaml: string): WorkflowDefinition[];
11
12
  export declare class WorkflowRepository {
12
13
  init(): Promise<void>;
13
14
  validate(sourceYaml: string): WorkflowDefinition[];
14
- saveDraft(id: string, sourceYaml: string): Promise<StoredWorkflow>;
15
+ saveDraft(id: string, sourceYaml: string, enabled?: boolean): Promise<StoredWorkflow>;
15
16
  publish(id: string): Promise<StoredWorkflow | null>;
16
17
  list(): Promise<StoredWorkflow[]>;
17
18
  get(id: string): Promise<StoredWorkflow | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../src/workflows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;CAC5C;AAQD,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAuBtE;AAED,qBAAa,kBAAkB;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAa5C,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWlE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IASnD,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAKjC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAK/C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASpC,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAMxC,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAKrF,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAKvG"}
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../src/workflows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,OAAO,EAAE,OAAO,CAAC;CAClB;AAQD,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAuBtE;AAED,qBAAa,kBAAkB;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAa5C,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAWlF,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IASnD,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAKjC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAK/C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASpC,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAMxC,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAKrF,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAKvG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud-cli/on",
3
- "version": "1.18.1",
3
+ "version": "1.20.0",
4
4
  "description": "CLI entry point for the on plugin ecosystem.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.30.3",