@cloud-cli/on 1.59.0 → 1.60.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,200 @@
1
+ import { n as e } from "./timestamped-log-Dtz_Euu0.js";
2
+ import { t } from "./db-client-BvMkK1lx.js";
3
+ //#region src/file-storage.ts
4
+ var n = class {
5
+ baseUrl;
6
+ binId;
7
+ authorization;
8
+ constructor() {
9
+ this.baseUrl = (process.env.RUNNER_FILE_API_URL || "https://file.api.apphor.de").replace(/\/$/, ""), this.binId = process.env.RUNNER_FILE_BIN || "", this.authorization = process.env.RUNNER_FILE_PASSWORD ? `Basic ${Buffer.from(`runner:${process.env.RUNNER_FILE_PASSWORD}`).toString("base64")}` : void 0;
10
+ }
11
+ get enabled() {
12
+ return !!this.binId;
13
+ }
14
+ headers(e = {}) {
15
+ return {
16
+ ...this.authorization ? { authorization: this.authorization } : {},
17
+ ...e
18
+ };
19
+ }
20
+ async request(e, t = {}) {
21
+ let n = await fetch(`${this.baseUrl}${e}`, {
22
+ ...t,
23
+ headers: this.headers(t.headers || {})
24
+ });
25
+ if (!n.ok) throw Error(`File storage request failed: ${n.status} ${e}`);
26
+ return n;
27
+ }
28
+ async save(e, t) {
29
+ let n = await this.index();
30
+ for (let r of t) {
31
+ let t = `${e}/${r.path}`, i = n.get(t) || await this.create(t);
32
+ await this.request(`/f/${this.binId}/${i}`, {
33
+ method: "PUT",
34
+ headers: this.headers({ "content-type": "application/octet-stream" }),
35
+ body: Buffer.from(r.content, "base64")
36
+ });
37
+ }
38
+ }
39
+ async load(e) {
40
+ let t = await this.index(), n = [];
41
+ for (let [r, i] of t) {
42
+ if (!r.startsWith(`${e}/`)) continue;
43
+ let t = Buffer.from(await (await this.request(`/f/${this.binId}/${i}`)).arrayBuffer()).toString("base64");
44
+ n.push({
45
+ path: r.slice(e.length + 1),
46
+ content: t
47
+ });
48
+ }
49
+ return n;
50
+ }
51
+ async create(e) {
52
+ return (await (await this.request(`/f/${this.binId}`, {
53
+ method: "POST",
54
+ headers: this.headers({ "content-type": "application/json" }),
55
+ body: JSON.stringify({ name: e })
56
+ })).json()).fileId;
57
+ }
58
+ async index() {
59
+ let e = await (await this.request(`/bin/${this.binId}`)).json(), t = await Promise.all(e.map(async (e) => [(await (await this.request(`/meta/${this.binId}/${e}`)).json()).name, e]));
60
+ return new Map(t);
61
+ }
62
+ }, r = class {
63
+ workerId;
64
+ fileStorage = new n();
65
+ constructor(e) {
66
+ this.workerId = e;
67
+ }
68
+ async init() {
69
+ await this.createTables(), await this.clearStaleJobs();
70
+ }
71
+ async enqueue(e, n, r, i = [], a) {
72
+ a && await t.run("UPDATE jobs SET status = 'cancelled' WHERE concurrency_key = ? AND status IN ('pending', 'running');", [a]);
73
+ let o = await t.run("INSERT INTO jobs (workflow_id, workflow_revision, required_tags, concurrency_key, payload) VALUES (?, ?, ?, ?, ?);", [
74
+ e,
75
+ n,
76
+ JSON.stringify(i),
77
+ a || "",
78
+ JSON.stringify(r)
79
+ ]);
80
+ return Number(o?.lastInsertRowid ?? o?.id ?? 0);
81
+ }
82
+ async claimNextJob(e = []) {
83
+ return await t.get("\n UPDATE jobs\n SET\n status = 'running',\n worker_id = ?,\n started_at = CURRENT_TIMESTAMP\n WHERE id = (\n SELECT id FROM jobs\n WHERE status = 'pending'\n AND NOT EXISTS (\n SELECT 1\n FROM json_each(COALESCE(jobs.required_tags, '[]')) AS required_tag\n WHERE required_tag.value NOT IN (SELECT value FROM json_each(?))\n )\n ORDER BY created_at ASC\n LIMIT 1\n )\n RETURNING *;\n ", [this.workerId, JSON.stringify(e)]) || null;
84
+ }
85
+ async releaseJob(e) {
86
+ await t.run("UPDATE jobs SET status = 'pending', worker_id = NULL, started_at = NULL WHERE id = ? AND status = 'running';", [e]);
87
+ }
88
+ async finishJob(e, n) {
89
+ await t.run("UPDATE jobs SET status = ?, finished_at = CURRENT_TIMESTAMP WHERE id = ?;", [n, e]);
90
+ }
91
+ async completeJob(e, n, r) {
92
+ await t.run("UPDATE jobs\n SET status = CASE WHEN status = 'cancelled' THEN 'cancelled' ELSE ? END,\n report = ?, updated_at = CURRENT_TIMESTAMP, finished_at = CURRENT_TIMESTAMP\n WHERE id = ?;", [
93
+ n,
94
+ JSON.stringify(r),
95
+ e
96
+ ]);
97
+ }
98
+ async cancelJob(e) {
99
+ let n = await this.getJob(e);
100
+ return n ? n.status !== "pending" && n.status !== "running" ? "not_active" : (await t.run("UPDATE jobs SET status = 'cancelled', updated_at = CURRENT_TIMESTAMP, finished_at = CURRENT_TIMESTAMP\n WHERE id = ? AND status IN ('pending', 'running');", [e]), (await this.getJob(e))?.status === "cancelled" ? "cancelled" : "not_active") : "not_found";
101
+ }
102
+ async restartJob(e, n = {}) {
103
+ let r = await this.getJob(e);
104
+ if (!r) return;
105
+ r.status === "running" && await t.run("UPDATE jobs SET status = 'cancelled', finished_at = CURRENT_TIMESTAMP WHERE id = ?;", [e]);
106
+ let i = await t.get("SELECT active_revision FROM workflows WHERE id = ?", [r.workflow_id]), a = Number(i?.active_revision);
107
+ if (!Number.isSafeInteger(a) || a < 1) throw Error(`Workflow ${r.workflow_id} has no active revision`);
108
+ let o = r.payload ? typeof r.payload == "string" ? JSON.parse(r.payload) : r.payload : { inputs: {} };
109
+ return o.inputs = {
110
+ ...o.inputs || {},
111
+ ...n
112
+ }, (await t.get("INSERT INTO jobs (\n parentId, workflow_id, workflow_revision, required_tags, concurrency_key, payload,\n status, worker_id, report, started_at, finished_at\n )\n SELECT id, workflow_id, ?, required_tags, concurrency_key, ?,\n 'pending', NULL, NULL, NULL, NULL\n FROM jobs\n WHERE id = ?\n RETURNING *", [
113
+ a,
114
+ JSON.stringify(o),
115
+ e
116
+ ])).id;
117
+ }
118
+ async isCancelled(e) {
119
+ return (await t.get("SELECT status FROM jobs WHERE id = ?;", [+e]))?.status === "cancelled";
120
+ }
121
+ async clearStaleJobs() {
122
+ return await t.run("UPDATE jobs SET status = 'pending', worker_id = NULL WHERE status = 'running' AND started_at < datetime('now', '-1 hour');");
123
+ }
124
+ async createTables() {
125
+ await t.exec("\n CREATE TABLE IF NOT EXISTS jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parentId INTEGER,\n workflow_id TEXT NOT NULL,\n workflow_revision INTEGER NOT NULL,\n required_tags TEXT NOT NULL DEFAULT '[]',\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n concurrency_key TEXT,\n worker_id TEXT,\n report TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n started_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n finished_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE TABLE IF NOT EXISTS step_logs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id INTEGER NOT NULL,\n step_id TEXT NOT NULL,\n log_content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_step_logs_job ON step_logs(job_id);\n\n DELETE FROM step_logs\n WHERE id NOT IN (\n SELECT MAX(id) FROM step_logs GROUP BY job_id, step_id\n );\n CREATE UNIQUE INDEX IF NOT EXISTS idx_step_logs_job_step ON step_logs(job_id, step_id);\n\n CREATE TABLE IF NOT EXISTS stored_files (\n kind TEXT NOT NULL,\n owner_key TEXT NOT NULL,\n file_path TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (kind, owner_key, file_path)\n );\n CREATE INDEX IF NOT EXISTS idx_stored_files_owner ON stored_files(kind, owner_key);\n\n CREATE TABLE IF NOT EXISTS worker_presence (\n worker_id TEXT PRIMARY KEY,\n version TEXT NOT NULL,\n tags TEXT NOT NULL DEFAULT '[]',\n concurrency INTEGER NOT NULL DEFAULT 0,\n active_jobs INTEGER NOT NULL DEFAULT 0,\n last_seen DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n ");
126
+ }
127
+ async getJob(e) {
128
+ return t.get("SELECT * FROM jobs WHERE id = ?", [e]);
129
+ }
130
+ async listJobs(e = 50, n, r, i, a) {
131
+ let o = [], s = [];
132
+ if (n !== void 0 && (o.push("id > ?"), s.push(n)), r !== void 0 && (o.push("id < ?"), s.push(r)), i) {
133
+ let e = i.indexOf(":");
134
+ if (e > 0) {
135
+ let t = i.slice(0, e).trim(), n = i.slice(e + 1).trim();
136
+ if (!/^[A-Za-z0-9_-]+$/.test(t) || !n) throw Error("Invalid job filter");
137
+ o.push("json_extract(payload, '$.inputs.' || ?) GLOB ?"), s.push(t, n);
138
+ } else o.push("LOWER(payload) LIKE LOWER(?)"), s.push(`%${i}%`);
139
+ }
140
+ a && (o.push("workflow_id = ?"), s.push(a));
141
+ let c = o.length ? ` WHERE ${o.join(" AND ")}` : "";
142
+ return t.all(`SELECT * FROM jobs${c} ORDER BY id DESC LIMIT ?;`, [...s, e]);
143
+ }
144
+ async saveReport(e, n) {
145
+ await t.run("UPDATE jobs SET report = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?", [JSON.stringify(n), e]);
146
+ }
147
+ async saveStepLog(n, r, i) {
148
+ await t.run("INSERT INTO step_logs (job_id, step_id, log_content) VALUES (?, ?, ?)\n ON CONFLICT(job_id, step_id) DO UPDATE SET\n log_content = excluded.log_content,\n created_at = CURRENT_TIMESTAMP", [
149
+ n,
150
+ r,
151
+ e(i)
152
+ ]);
153
+ }
154
+ async getJobLogs(e) {
155
+ let n = await t.all("SELECT step_id, log_content FROM step_logs WHERE job_id = ?", [e]), r = {};
156
+ for (let e of n) r[e.step_id] = e.log_content;
157
+ return r;
158
+ }
159
+ async saveStoredFiles(e, n, r) {
160
+ if (this.fileStorage.enabled) return this.fileStorage.save(`${e}/${n}`, r);
161
+ for (let i of r) await t.run("INSERT INTO stored_files (kind, owner_key, file_path, content) VALUES (?, ?, ?, ?)\n ON CONFLICT(kind, owner_key, file_path) DO UPDATE SET content = excluded.content, created_at = CURRENT_TIMESTAMP", [
162
+ e,
163
+ n,
164
+ i.path,
165
+ i.content
166
+ ]);
167
+ }
168
+ async getStoredFiles(e, n) {
169
+ return this.fileStorage.enabled ? this.fileStorage.load(`${e}/${n}`) : t.all("SELECT file_path AS path, content FROM stored_files WHERE kind = ? AND owner_key = ?", [e, n]);
170
+ }
171
+ async updateWorkerPresence(e) {
172
+ await t.run("INSERT INTO worker_presence (worker_id, version, tags, concurrency, active_jobs, last_seen)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)\n ON CONFLICT(worker_id) DO UPDATE SET version = excluded.version, tags = excluded.tags,\n concurrency = excluded.concurrency, active_jobs = excluded.active_jobs, last_seen = CURRENT_TIMESTAMP", [
173
+ e.id,
174
+ e.version,
175
+ JSON.stringify(e.tags),
176
+ e.concurrency,
177
+ e.activeJobs
178
+ ]);
179
+ }
180
+ async listWorkerPresence() {
181
+ return (await t.all("SELECT worker_id, version, tags, concurrency, active_jobs, last_seen FROM worker_presence ORDER BY worker_id")).map((e) => ({
182
+ workerId: e.worker_id,
183
+ version: e.version,
184
+ tags: JSON.parse(e.tags || "[]"),
185
+ concurrency: e.concurrency,
186
+ activeJobs: e.active_jobs,
187
+ lastSeen: e.last_seen,
188
+ online: Date.now() - Date.parse(`${e.last_seen}Z`) < 45e3
189
+ }));
190
+ }
191
+ async saveAiRequest(e, n, r) {
192
+ await t.run("INSERT INTO ai_requests (job_id, workflow_url, request_json) VALUES (?, ?, ?)", [
193
+ e,
194
+ n,
195
+ JSON.stringify(r)
196
+ ]);
197
+ }
198
+ };
199
+ //#endregion
200
+ export { r as QueueManager };
@@ -0,0 +1,20 @@
1
+ //#region \0rolldown/runtime.js
2
+ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), s = (e, n) => {
3
+ let r = {};
4
+ for (var i in e) t(r, i, {
5
+ get: e[i],
6
+ enumerable: !0
7
+ });
8
+ return n || t(r, Symbol.toStringTag, { value: "Module" }), r;
9
+ }, c = (e, i, o, s) => {
10
+ if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, {
11
+ get: ((e) => i[e]).bind(null, d),
12
+ enumerable: !(s = n(i, d)) || s.enumerable
13
+ });
14
+ return e;
15
+ }, l = (n, r, o) => (o = n == null ? {} : e(i(n)), c(r || !n || !n.__esModule || !a.call(n, "default") ? t(o, "default", {
16
+ value: n,
17
+ enumerable: !0
18
+ }) : o, n));
19
+ //#endregion
20
+ export { s as n, l as r, o as t };
@@ -0,0 +1,96 @@
1
+ import { n as e, t } from "./matrix-expander-BItKqWu2.js";
2
+ //#region src/scheduler.ts
3
+ function n(e, t, n, r) {
4
+ return e.split(",").some((e) => {
5
+ let [i, a] = e.split("/"), o = a ? Number(a) : 1;
6
+ if (!Number.isInteger(o) || o < 1) return !1;
7
+ let [s, c] = i === "*" ? [String(n), String(r)] : i.split("-"), l = Number(s), u = c === void 0 ? l : Number(c);
8
+ return Number.isInteger(l) && Number.isInteger(u) && t >= l && t <= u && (t - l) % o === 0;
9
+ });
10
+ }
11
+ function r(e, t, r = "UTC") {
12
+ let i = e.trim().split(/\s+/);
13
+ if (i.length !== 5) return !1;
14
+ let a = new Intl.DateTimeFormat("en-US", {
15
+ timeZone: r,
16
+ minute: "numeric",
17
+ hour: "numeric",
18
+ day: "numeric",
19
+ month: "numeric",
20
+ weekday: "short",
21
+ hourCycle: "h23"
22
+ }).formatToParts(t).reduce((e, t) => ({
23
+ ...e,
24
+ [t.type]: t.value
25
+ }), {}), o = [
26
+ "Sun",
27
+ "Mon",
28
+ "Tue",
29
+ "Wed",
30
+ "Thu",
31
+ "Fri",
32
+ "Sat"
33
+ ].indexOf(a.weekday), s = n(i[2], Number(a.day), 1, 31), c = n(i[4].replace(/7/g, "0"), o, 0, 6);
34
+ return n(i[0], Number(a.minute), 0, 59) && n(i[1], Number(a.hour), 0, 23) && n(i[3], Number(a.month), 1, 12) && (i[2] === "*" || i[4] === "*" ? s && c : s || c);
35
+ }
36
+ function i(e) {
37
+ if (!e) return 0;
38
+ let t = e.match(/^([+-]?)(\d+)(m|h)$/);
39
+ if (!t) throw Error(`Invalid solar offset: ${e}`);
40
+ return (t[1] === "-" ? -1 : 1) * Number(t[2]) * (t[3] === "h" ? 36e5 : 6e4);
41
+ }
42
+ function a(e, t) {
43
+ let n = t.latitude, r = t.longitude, a = Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), e.getUTCDate()), o = Math.floor((a - Date.UTC(e.getUTCFullYear(), 0, 0)) / 864e5), s = r / 15, c = o + ((t.event === "sunrise" ? 6 : 18) - s) / 24, l = .9856 * c - 3.289, u = l + 1.916 * Math.sin(l * Math.PI / 180) + .02 * Math.sin(2 * l * Math.PI / 180) + 282.634;
44
+ u = (u + 360) % 360;
45
+ let d = Math.atan(.91764 * Math.tan(u * Math.PI / 180)) * 180 / Math.PI;
46
+ d = (d + 360) % 360, d += Math.floor(u / 90) * 90 - Math.floor(d / 90) * 90, d /= 15;
47
+ let f = .39782 * Math.sin(u * Math.PI / 180), p = Math.cos(Math.asin(f)), m = (Math.cos(90.833 * Math.PI / 180) - f * Math.sin(n * Math.PI / 180)) / (p * Math.cos(n * Math.PI / 180));
48
+ if (m > 1 || m < -1) return null;
49
+ let h = (t.event === "sunrise" ? 360 - Math.acos(m) * 180 / Math.PI : Math.acos(m) * 180 / Math.PI) / 15;
50
+ return h = (h + d - .06571 * c - 6.622 - s + 24) % 24, new Date(a + h * 36e5 + i(t.offset));
51
+ }
52
+ var o = class {
53
+ queue;
54
+ workflows;
55
+ config;
56
+ timer;
57
+ constructor(e, t, n) {
58
+ this.queue = e, this.workflows = t, this.config = n;
59
+ }
60
+ start(e = 15e3) {
61
+ this.tick(), this.timer = setInterval(() => void this.tick(), e), console.log(`Scheduler started with ${e}ms polling`);
62
+ }
63
+ stop() {
64
+ this.timer && clearInterval(this.timer);
65
+ }
66
+ async tick(e = /* @__PURE__ */ new Date()) {
67
+ let t = /* @__PURE__ */ new Date(Math.floor(e.getTime() / 6e4) * 6e4);
68
+ for (let { definition: e, revision: n } of await this.workflows.published()) {
69
+ for (let [i, a] of (e.schedule || []).entries()) r(a.cron, t, a.timezone || "UTC") && await this.enqueue(e, n, a, `cron-${i}`, t);
70
+ for (let [r, i] of (e.solar || []).entries()) {
71
+ let o = a(t, i);
72
+ o && Math.floor(o.getTime() / 6e4) === t.getTime() / 6e4 && await this.enqueue(e, n, i, `solar-${r}`, t);
73
+ }
74
+ }
75
+ }
76
+ async enqueue(n, r, i, a, o) {
77
+ let s = i.id || a;
78
+ if (!await this.workflows.claimScheduledRun(n.id, s, o.toISOString())) return;
79
+ let c = { trigger: {
80
+ type: i.cron ? "schedule" : "solar",
81
+ id: s,
82
+ scheduledFor: o.toISOString(),
83
+ ...i
84
+ } };
85
+ for (let i of t(n)) {
86
+ let t = {
87
+ inputs: c,
88
+ matrix: i.matrixContext
89
+ };
90
+ await this.queue.enqueue(n.id, r, t, await e(i.tags, i.matrixContext, c));
91
+ }
92
+ console.log(`Scheduled ${n.id} via ${s}`);
93
+ }
94
+ };
95
+ //#endregion
96
+ export { o as WorkflowScheduler, r as cronMatches };
@@ -0,0 +1,30 @@
1
+ //#region src/secrets.ts
2
+ var e = class {
3
+ secrets = /* @__PURE__ */ new Map();
4
+ constructor() {
5
+ this.reload();
6
+ }
7
+ reload() {}
8
+ get(e) {
9
+ return this.secrets.get(e)?.value;
10
+ }
11
+ getValue(e) {
12
+ return this.secrets.get(e);
13
+ }
14
+ getAll() {
15
+ return Object.fromEntries([...this.secrets].map(([e, t]) => [e, t.value]));
16
+ }
17
+ replace(e) {
18
+ this.secrets = new Map(Object.entries(e).map(([e, t]) => [e, typeof t == "string" ? {
19
+ value: t,
20
+ encoding: "utf8"
21
+ } : t]));
22
+ }
23
+ redactText(e) {
24
+ let t = Array.from(this.secrets.values()).map((e) => e.value).filter((e) => e.length > 3).slice().sort((e, t) => t.length - e.length);
25
+ for (let n of t) e = e.replaceAll(n, "****");
26
+ return e;
27
+ }
28
+ };
29
+ //#endregion
30
+ export { e as t };
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./secrets-BR6K16WY.js";
2
+ export { e as SecretStore };