@azlib/scheduler 1.1.0 → 1.2.1

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.
@@ -1,7 +1,7 @@
1
1
  import { s as parseSchedule } from "./store-dashboard-Cyf_JILa.mjs";
2
2
  import { asBoolean, asRecord, asString } from "@azlib/std";
3
- import { createReadStream, existsSync, statSync } from "node:fs";
4
3
  import * as http from "node:http";
4
+ import { createReadStream, existsSync, statSync } from "node:fs";
5
5
  import { dirname, extname, join, relative, resolve, sep } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -49,7 +49,11 @@ function parseScheduleFromRecord(record) {
49
49
  if (scheduleType !== "cron" && scheduleType !== "once") throw new DashboardHttpError(400, "scheduleType must be cron or once.");
50
50
  const expression = requiredText(record.expression ?? nested?.expression, "expression");
51
51
  const timezone = asString(record.timezone)?.trim() || asString(nested?.timezone)?.trim() || DEFAULT_TIMEZONE;
52
- parseSchedule(scheduleType, expression, timezone);
52
+ try {
53
+ parseSchedule(scheduleType, expression, timezone);
54
+ } catch (error) {
55
+ throw new DashboardHttpError(400, error instanceof Error ? error.message : "Invalid schedule.");
56
+ }
53
57
  return {
54
58
  scheduleType,
55
59
  expression,
@@ -79,6 +83,36 @@ function parseUpdateJobBody(body) {
79
83
  return patch;
80
84
  }
81
85
  //#endregion
86
+ //#region src/dashboard/http-path.ts
87
+ function normalizeDashboardBasePath(basePath) {
88
+ const trimmed = basePath?.trim();
89
+ if (!trimmed || trimmed === "/") return "";
90
+ return (trimmed.startsWith("/") ? trimmed : `/${trimmed}`).replace(/\/+$/, "");
91
+ }
92
+ function stripDashboardBasePath(pathname, basePath) {
93
+ const base = normalizeDashboardBasePath(basePath);
94
+ const path = pathname || "/";
95
+ if (!base) return path.startsWith("/") ? path : `/${path}`;
96
+ if (path === base || path === `${base}/`) return "/";
97
+ if (path.startsWith(`${base}/`)) {
98
+ const rest = path.slice(base.length);
99
+ return rest.startsWith("/") ? rest : `/${rest}`;
100
+ }
101
+ return null;
102
+ }
103
+ function resolveDashboardApiBase(pathname) {
104
+ const trimmed = (pathname.split("?")[0] || "/").replace(/\/index\.html$/i, "/").replace(/\/[^/]+\.[a-z0-9]+$/i, "/").replace(/\/+$/, "");
105
+ return trimmed === "" ? "/api" : `${trimmed}/api`;
106
+ }
107
+ function requestPathname(url, originalUrl) {
108
+ const raw = originalUrl || url || "/";
109
+ try {
110
+ return new URL(raw, "http://127.0.0.1").pathname;
111
+ } catch {
112
+ return raw.split("?")[0] || "/";
113
+ }
114
+ }
115
+ //#endregion
82
116
  //#region src/dashboard/public-dir.ts
83
117
  function resolveDashboardPublicDir(fromFileUrl) {
84
118
  const dir = dirname(fileURLToPath(fromFileUrl));
@@ -89,7 +123,7 @@ function resolveDashboardPublicDir(fromFileUrl) {
89
123
  return nested;
90
124
  }
91
125
  //#endregion
92
- //#region src/dashboard/http-server.ts
126
+ //#region src/dashboard/http-handler.ts
93
127
  const MIME_TYPES = {
94
128
  ".css": "text/css; charset=utf-8",
95
129
  ".html": "text/html; charset=utf-8",
@@ -103,7 +137,7 @@ function sendJson(res, status, body) {
103
137
  res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
104
138
  res.end(JSON.stringify(body));
105
139
  }
106
- function sendError(res, error) {
140
+ function sendDashboardError(res, error) {
107
141
  if (error instanceof DashboardHttpError) {
108
142
  sendJson(res, error.status, { error: error.message });
109
143
  return;
@@ -111,10 +145,17 @@ function sendError(res, error) {
111
145
  const message = error instanceof Error ? error.message : "Unknown error";
112
146
  sendJson(res, message.includes("not found") ? 404 : message.includes("Only failed") ? 400 : message.includes("Unknown handlerKey") ? 400 : 500, { error: message });
113
147
  }
148
+ function hasParsedBody(req) {
149
+ return Object.prototype.hasOwnProperty.call(req, "body");
150
+ }
114
151
  async function readJsonBody(req) {
152
+ if (req.readableEnded && hasParsedBody(req)) return req.body ?? {};
115
153
  const chunks = [];
116
154
  for await (const chunk of req) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
117
- if (chunks.length === 0) return {};
155
+ if (chunks.length === 0) {
156
+ if (hasParsedBody(req)) return req.body ?? {};
157
+ return {};
158
+ }
118
159
  const raw = Buffer.concat(chunks).toString("utf8");
119
160
  if (!raw.trim()) return {};
120
161
  try {
@@ -152,115 +193,158 @@ function servePublicFile(publicDir, urlPath, res) {
152
193
  createReadStream(filePath).pipe(res);
153
194
  return true;
154
195
  }
155
- function createSchedulerDashboardServer(options) {
156
- const port = options.port ?? 9100;
157
- const host = options.host ?? "127.0.0.1";
158
- const publicDir = options.publicDir ?? resolveDashboardPublicDir(import.meta.url);
159
- const dashboard = options.dashboard;
160
- const server = http.createServer((req, res) => {
161
- handleRequest(req, res).catch((error) => {
162
- if (!res.headersSent) sendError(res, error);
196
+ async function authorizeApi(options, method, pathname, req) {
197
+ if (options.authorize) {
198
+ await options.authorize({
199
+ method,
200
+ pathname,
201
+ authorization: req.headers.authorization
163
202
  });
203
+ return;
204
+ }
205
+ authorizeDashboardRequest({
206
+ token: options.token,
207
+ authorization: req.headers.authorization
164
208
  });
165
- async function handleRequest(req, res) {
166
- const method = req.method ?? "GET";
167
- const pathname = new URL(req.url ?? "/", `http://${host}:${port}`).pathname;
168
- if (method === "GET" && pathname === "/health") {
169
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
170
- res.end("ok");
209
+ }
210
+ async function handleApi(dashboard, method, pathname, req, res) {
211
+ if (method === "GET" && pathname === "/api/health") {
212
+ sendJson(res, 200, await dashboard.getHealth());
213
+ return;
214
+ }
215
+ if (method === "GET" && pathname === "/api/handlers") {
216
+ sendJson(res, 200, { handlers: dashboard.listHandlerKeys() });
217
+ return;
218
+ }
219
+ if (method === "GET" && pathname === "/api/jobs") {
220
+ sendJson(res, 200, { items: await dashboard.listItems() });
221
+ return;
222
+ }
223
+ if (method === "POST" && pathname === "/api/jobs") {
224
+ sendJson(res, 201, await dashboard.createJob(parseCreateJobBody(await readJsonBody(req))));
225
+ return;
226
+ }
227
+ const jobExec = matchPath(pathname, "/api/jobs/:jobId/executions");
228
+ if (jobExec && method === "GET") {
229
+ sendJson(res, 200, { executions: await dashboard.listExecutions(jobExec.jobId ?? "") });
230
+ return;
231
+ }
232
+ const jobAction = matchPath(pathname, "/api/jobs/:jobId/:action");
233
+ if (jobAction && method === "POST") {
234
+ const jobId = jobAction.jobId ?? "";
235
+ if (jobAction.action === "pause") {
236
+ await dashboard.pauseJob(jobId);
237
+ res.writeHead(204);
238
+ res.end();
171
239
  return;
172
240
  }
173
- if (pathname === "/api" || pathname.startsWith("/api/")) {
174
- authorizeDashboardRequest({
175
- token: options.token,
176
- authorization: req.headers.authorization
177
- });
178
- await handleApi(method, pathname, req, res);
241
+ if (jobAction.action === "resume") {
242
+ await dashboard.resumeJob(jobId);
243
+ res.writeHead(204);
244
+ res.end();
179
245
  return;
180
246
  }
181
- if (method === "GET" && servePublicFile(publicDir, pathname, res)) return;
247
+ if (jobAction.action === "run") {
248
+ await dashboard.runJob(jobId);
249
+ res.writeHead(204);
250
+ res.end();
251
+ return;
252
+ }
253
+ }
254
+ const retry = matchPath(pathname, "/api/executions/:executionId/retry");
255
+ if (retry && method === "POST") {
256
+ await dashboard.retryExecution(retry.executionId ?? "");
257
+ res.writeHead(204);
258
+ res.end();
259
+ return;
260
+ }
261
+ const job = matchPath(pathname, "/api/jobs/:jobId");
262
+ if (job) {
263
+ const jobId = job.jobId ?? "";
264
+ if (method === "GET") {
265
+ const item = await dashboard.getJob(jobId);
266
+ if (!item) throw new DashboardHttpError(404, `Job not found: ${jobId}`);
267
+ sendJson(res, 200, item);
268
+ return;
269
+ }
270
+ if (method === "PATCH") {
271
+ await dashboard.updateJob(jobId, parseUpdateJobBody(await readJsonBody(req)));
272
+ res.writeHead(204);
273
+ res.end();
274
+ return;
275
+ }
276
+ if (method === "DELETE") {
277
+ await dashboard.deleteJob(jobId);
278
+ res.writeHead(204);
279
+ res.end();
280
+ return;
281
+ }
282
+ }
283
+ sendJson(res, 404, { error: "Not Found" });
284
+ }
285
+ async function handleSchedulerDashboardRequest(req, res, options) {
286
+ const method = req.method ?? "GET";
287
+ const originalUrl = "originalUrl" in req && typeof req.originalUrl === "string" ? req.originalUrl : void 0;
288
+ const pathname = requestPathname(req.url, originalUrl);
289
+ const basePath = normalizeDashboardBasePath(options.basePath);
290
+ const relative = stripDashboardBasePath(pathname, basePath);
291
+ if (relative === null) return false;
292
+ if (method === "GET" && basePath && pathname === basePath) {
293
+ res.writeHead(302, { Location: `${basePath}/` });
294
+ res.end();
295
+ return true;
296
+ }
297
+ const publicDir = options.publicDir ?? resolveDashboardPublicDir(import.meta.url);
298
+ try {
299
+ if (method === "GET" && relative === "/health") {
300
+ res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
301
+ res.end("ok");
302
+ return true;
303
+ }
304
+ if (relative === "/api" || relative.startsWith("/api/")) {
305
+ await authorizeApi(options, method, relative, req);
306
+ await handleApi(options.dashboard, method, relative, req, res);
307
+ return true;
308
+ }
309
+ if (method === "GET" && servePublicFile(publicDir, relative, res)) return true;
182
310
  res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
183
311
  res.end("Not Found");
312
+ return true;
313
+ } catch (error) {
314
+ sendDashboardError(res, error);
315
+ return true;
184
316
  }
185
- async function handleApi(method, pathname, req, res) {
186
- try {
187
- if (method === "GET" && pathname === "/api/health") {
188
- sendJson(res, 200, await dashboard.getHealth());
189
- return;
190
- }
191
- if (method === "GET" && pathname === "/api/handlers") {
192
- sendJson(res, 200, { handlers: dashboard.listHandlerKeys() });
193
- return;
194
- }
195
- if (method === "GET" && pathname === "/api/jobs") {
196
- sendJson(res, 200, { items: await dashboard.listItems() });
197
- return;
198
- }
199
- if (method === "POST" && pathname === "/api/jobs") {
200
- sendJson(res, 201, await dashboard.createJob(parseCreateJobBody(await readJsonBody(req))));
201
- return;
202
- }
203
- const jobExec = matchPath(pathname, "/api/jobs/:jobId/executions");
204
- if (jobExec && method === "GET") {
205
- sendJson(res, 200, { executions: await dashboard.listExecutions(jobExec.jobId ?? "") });
206
- return;
207
- }
208
- const jobAction = matchPath(pathname, "/api/jobs/:jobId/:action");
209
- if (jobAction && method === "POST") {
210
- const jobId = jobAction.jobId ?? "";
211
- if (jobAction.action === "pause") {
212
- await dashboard.pauseJob(jobId);
213
- res.writeHead(204);
214
- res.end();
215
- return;
216
- }
217
- if (jobAction.action === "resume") {
218
- await dashboard.resumeJob(jobId);
219
- res.writeHead(204);
220
- res.end();
221
- return;
222
- }
223
- if (jobAction.action === "run") {
224
- await dashboard.runJob(jobId);
225
- res.writeHead(204);
226
- res.end();
227
- return;
228
- }
229
- }
230
- const retry = matchPath(pathname, "/api/executions/:executionId/retry");
231
- if (retry && method === "POST") {
232
- await dashboard.retryExecution(retry.executionId ?? "");
233
- res.writeHead(204);
234
- res.end();
317
+ }
318
+ function createSchedulerDashboardNodeHandler(options) {
319
+ return (req, res, next) => {
320
+ handleSchedulerDashboardRequest(req, res, options).then((handled) => {
321
+ if (!handled) next?.();
322
+ }).catch((error) => {
323
+ if (next) {
324
+ next(error);
235
325
  return;
236
326
  }
237
- const job = matchPath(pathname, "/api/jobs/:jobId");
238
- if (job) {
239
- const jobId = job.jobId ?? "";
240
- if (method === "GET") {
241
- const item = await dashboard.getJob(jobId);
242
- if (!item) throw new DashboardHttpError(404, `Job not found: ${jobId}`);
243
- sendJson(res, 200, item);
244
- return;
245
- }
246
- if (method === "PATCH") {
247
- await dashboard.updateJob(jobId, parseUpdateJobBody(await readJsonBody(req)));
248
- res.writeHead(204);
249
- res.end();
250
- return;
251
- }
252
- if (method === "DELETE") {
253
- await dashboard.deleteJob(jobId);
254
- res.writeHead(204);
255
- res.end();
256
- return;
257
- }
327
+ if (!res.headersSent) sendDashboardError(res, error);
328
+ });
329
+ };
330
+ }
331
+ //#endregion
332
+ //#region src/dashboard/http-server.ts
333
+ function createSchedulerDashboardServer(options) {
334
+ const port = options.port ?? 9100;
335
+ const host = options.host ?? "127.0.0.1";
336
+ const handler = createSchedulerDashboardNodeHandler({
337
+ ...options,
338
+ publicDir: options.publicDir ?? resolveDashboardPublicDir(import.meta.url)
339
+ });
340
+ const server = http.createServer((req, res) => {
341
+ handler(req, res, () => {
342
+ if (!res.headersSent) {
343
+ res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
344
+ res.end("Not Found");
258
345
  }
259
- sendJson(res, 404, { error: "Not Found" });
260
- } catch (error) {
261
- sendError(res, error);
262
- }
263
- }
346
+ });
347
+ });
264
348
  return {
265
349
  get port() {
266
350
  return port;
@@ -457,6 +541,6 @@ function parseDashboardCliEnv(env) {
457
541
  };
458
542
  }
459
543
  //#endregion
460
- export { resolveDashboardPublicDir as a, createSchedulerDashboardServer as i, createDashboardPersistenceConfig as n, createDashboardSqlDriver as r, parseDashboardCliEnv as t };
544
+ export { createSchedulerDashboardNodeHandler as a, normalizeDashboardBasePath as c, DashboardHttpError as d, createSchedulerDashboardServer as i, resolveDashboardApiBase as l, createDashboardPersistenceConfig as n, handleSchedulerDashboardRequest as o, createDashboardSqlDriver as r, resolveDashboardPublicDir as s, parseDashboardCliEnv as t, stripDashboardBasePath as u };
461
545
 
462
- //# sourceMappingURL=cli-config-7F2U8qPM.mjs.map
546
+ //# sourceMappingURL=cli-config-DrI08d47.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-config-DrI08d47.mjs","names":[],"sources":["../src/dashboard/http-auth.ts","../src/dashboard/http-parse.ts","../src/dashboard/http-path.ts","../src/dashboard/public-dir.ts","../src/dashboard/http-handler.ts","../src/dashboard/http-server.ts","../src/dashboard/sql-drivers.ts","../src/dashboard/cli-config.ts"],"sourcesContent":["export class DashboardHttpError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"DashboardHttpError\";\n this.status = status;\n }\n}\n\nexport function isLoopbackHost(host: string): boolean {\n const normalized = host.trim().toLowerCase();\n return (\n normalized === \"127.0.0.1\" ||\n normalized === \"localhost\" ||\n normalized === \"::1\" ||\n normalized === \"[::1]\"\n );\n}\n\nexport function authorizeDashboardRequest(input: {\n token?: string;\n authorization?: string | string[] | undefined;\n}): void {\n if (!input.token) {\n return;\n }\n const header = Array.isArray(input.authorization)\n ? input.authorization[0]\n : input.authorization;\n const expected = `Bearer ${input.token}`;\n if (header !== expected) {\n throw new DashboardHttpError(401, \"Unauthorized\");\n }\n}\n\nexport function assertDashboardBindSafety(input: {\n host: string;\n token?: string;\n}): void {\n if (!isLoopbackHost(input.host) && !input.token) {\n throw new Error(\n \"DASHBOARD_TOKEN is required when HOST is not a loopback address\",\n );\n }\n}\n","import { asBoolean, asRecord, asString } from \"@azlib/std\";\n\nimport type { SchedulerJobDefinition } from \"../contracts/scheduler-types.js\";\nimport { parseSchedule } from \"../core/schedule-parser.js\";\nimport { DashboardHttpError } from \"./http-auth.js\";\n\nconst DEFAULT_TIMEZONE = \"UTC\";\n\nfunction requiredText(value: unknown, field: string): string {\n const text = asString(value)?.trim();\n if (!text) {\n throw new DashboardHttpError(400, `${field} is required.`);\n }\n return text;\n}\n\nfunction parseConfig(value: unknown): unknown {\n if (value === undefined || value === null || value === \"\") {\n return {};\n }\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as unknown;\n } catch {\n throw new DashboardHttpError(400, \"config must be valid JSON.\");\n }\n }\n return value;\n}\n\nfunction parseScheduleFromRecord(\n record: Record<string, unknown>,\n): SchedulerJobDefinition[\"schedule\"] {\n const nested = asRecord(record.schedule);\n const scheduleType =\n asString(record.scheduleType)?.trim() ||\n asString(nested?.scheduleType)?.trim() ||\n \"cron\";\n if (scheduleType !== \"cron\" && scheduleType !== \"once\") {\n throw new DashboardHttpError(400, \"scheduleType must be cron or once.\");\n }\n const expression = requiredText(\n record.expression ?? nested?.expression,\n \"expression\",\n );\n const timezone =\n asString(record.timezone)?.trim() ||\n asString(nested?.timezone)?.trim() ||\n DEFAULT_TIMEZONE;\n try {\n parseSchedule(scheduleType, expression, timezone);\n } catch (error) {\n throw new DashboardHttpError(\n 400,\n error instanceof Error ? error.message : \"Invalid schedule.\",\n );\n }\n return {\n scheduleType,\n expression,\n timezone,\n };\n}\n\nexport function parseCreateJobBody(body: unknown): SchedulerJobDefinition {\n const record = asRecord(body);\n if (!record) {\n throw new DashboardHttpError(400, \"Request body must be a JSON object.\");\n }\n return {\n name: requiredText(record.name, \"name\"),\n handlerKey: requiredText(record.handlerKey, \"handlerKey\"),\n schedule: parseScheduleFromRecord(record),\n config: parseConfig(record.config),\n enabled: asBoolean(record.enabled) ?? true,\n };\n}\n\nexport function parseUpdateJobBody(\n body: unknown,\n): Partial<SchedulerJobDefinition> {\n const record = asRecord(body);\n if (!record) {\n throw new DashboardHttpError(400, \"Request body must be a JSON object.\");\n }\n const patch: Partial<SchedulerJobDefinition> = {};\n if (record.name !== undefined) {\n patch.name = requiredText(record.name, \"name\");\n }\n if (record.handlerKey !== undefined) {\n patch.handlerKey = requiredText(record.handlerKey, \"handlerKey\");\n }\n if (\n record.expression !== undefined ||\n record.timezone !== undefined ||\n record.scheduleType !== undefined ||\n record.schedule !== undefined\n ) {\n patch.schedule = parseScheduleFromRecord(record);\n }\n if (record.config !== undefined) {\n patch.config = parseConfig(record.config);\n }\n if (record.enabled !== undefined) {\n patch.enabled = asBoolean(record.enabled) ?? true;\n }\n return patch;\n}\n","export function normalizeDashboardBasePath(basePath?: string): string {\n const trimmed = basePath?.trim();\n if (!trimmed || trimmed === \"/\") {\n return \"\";\n }\n const withSlash = trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n return withSlash.replace(/\\/+$/, \"\");\n}\n\nexport function stripDashboardBasePath(\n pathname: string,\n basePath?: string,\n): string | null {\n const base = normalizeDashboardBasePath(basePath);\n const path = pathname || \"/\";\n if (!base) {\n return path.startsWith(\"/\") ? path : `/${path}`;\n }\n if (path === base || path === `${base}/`) {\n return \"/\";\n }\n if (path.startsWith(`${base}/`)) {\n const rest = path.slice(base.length);\n return rest.startsWith(\"/\") ? rest : `/${rest}`;\n }\n return null;\n}\n\nexport function resolveDashboardApiBase(pathname: string): string {\n const path = pathname.split(\"?\")[0] || \"/\";\n const withoutIndex = path.replace(/\\/index\\.html$/i, \"/\");\n const withoutAsset = withoutIndex.replace(/\\/[^/]+\\.[a-z0-9]+$/i, \"/\");\n const trimmed = withoutAsset.replace(/\\/+$/, \"\");\n return trimmed === \"\" ? \"/api\" : `${trimmed}/api`;\n}\n\nexport function requestPathname(\n url: string | undefined,\n originalUrl?: string,\n): string {\n const raw = originalUrl || url || \"/\";\n try {\n return new URL(raw, \"http://127.0.0.1\").pathname;\n } catch {\n return raw.split(\"?\")[0] || \"/\";\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function resolveDashboardPublicDir(fromFileUrl: string): string {\n const dir = dirname(fileURLToPath(fromFileUrl));\n const nested = join(dir, \"public\");\n const sibling = join(dir, \"dashboard\", \"public\");\n if (existsSync(join(nested, \"index.html\"))) {\n return nested;\n }\n if (existsSync(join(sibling, \"index.html\"))) {\n return sibling;\n }\n return nested;\n}\n","import {\n createReadStream,\n existsSync,\n statSync,\n} from \"node:fs\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { extname, join, relative, resolve, sep } from \"node:path\";\n\nimport type { SchedulerDashboardService } from \"./dashboard-types.js\";\nimport {\n authorizeDashboardRequest,\n DashboardHttpError,\n} from \"./http-auth.js\";\nimport { parseCreateJobBody, parseUpdateJobBody } from \"./http-parse.js\";\nimport {\n normalizeDashboardBasePath,\n requestPathname,\n stripDashboardBasePath,\n} from \"./http-path.js\";\nimport { resolveDashboardPublicDir } from \"./public-dir.js\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".css\": \"text/css; charset=utf-8\",\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".woff2\": \"font/woff2\",\n};\n\nexport type DashboardAuthorize = (input: {\n method: string;\n pathname: string;\n authorization?: string | string[];\n}) => void | Promise<void>;\n\nexport interface SchedulerDashboardHandlerOptions {\n dashboard: SchedulerDashboardService;\n token?: string;\n authorize?: DashboardAuthorize;\n publicDir?: string;\n basePath?: string;\n}\n\nexport type SchedulerDashboardRequestHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n next?: (err?: unknown) => void,\n) => void;\n\nfunction sendJson(\n res: ServerResponse,\n status: number,\n body: unknown,\n): void {\n res.writeHead(status, { \"Content-Type\": \"application/json; charset=utf-8\" });\n res.end(JSON.stringify(body));\n}\n\nexport function sendDashboardError(res: ServerResponse, error: unknown): void {\n if (error instanceof DashboardHttpError) {\n sendJson(res, error.status, { error: error.message });\n return;\n }\n const message = error instanceof Error ? error.message : \"Unknown error\";\n const status = message.includes(\"not found\")\n ? 404\n : message.includes(\"Only failed\")\n ? 400\n : message.includes(\"Unknown handlerKey\")\n ? 400\n : 500;\n sendJson(res, status, { error: message });\n}\n\nfunction hasParsedBody(req: IncomingMessage): boolean {\n return Object.prototype.hasOwnProperty.call(req, \"body\");\n}\n\nasync function readJsonBody(req: IncomingMessage): Promise<unknown> {\n if (req.readableEnded && hasParsedBody(req)) {\n return (req as IncomingMessage & { body?: unknown }).body ?? {};\n }\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n if (chunks.length === 0) {\n if (hasParsedBody(req)) {\n return (req as IncomingMessage & { body?: unknown }).body ?? {};\n }\n return {};\n }\n const raw = Buffer.concat(chunks).toString(\"utf8\");\n if (!raw.trim()) {\n return {};\n }\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n throw new DashboardHttpError(400, \"Request body must be valid JSON.\");\n }\n}\n\nfunction matchPath(\n pathname: string,\n pattern: string,\n): Record<string, string> | null {\n const pathParts = pathname.split(\"/\").filter(Boolean);\n const patternParts = pattern.split(\"/\").filter(Boolean);\n if (pathParts.length !== patternParts.length) {\n return null;\n }\n const params: Record<string, string> = {};\n for (let i = 0; i < patternParts.length; i += 1) {\n const expected = patternParts[i] ?? \"\";\n const actual = pathParts[i] ?? \"\";\n if (expected.startsWith(\":\")) {\n params[expected.slice(1)] = decodeURIComponent(actual);\n continue;\n }\n if (expected !== actual) {\n return null;\n }\n }\n return params;\n}\n\nfunction servePublicFile(\n publicDir: string,\n urlPath: string,\n res: ServerResponse,\n): boolean {\n if (!existsSync(publicDir)) {\n return false;\n }\n const pathname = decodeURIComponent(urlPath.split(\"?\")[0] ?? \"/\");\n const requested = pathname === \"/\" ? \"/index.html\" : pathname;\n const abs = resolve(publicDir, `.${requested}`);\n const rel = relative(resolve(publicDir), abs);\n if (rel.startsWith(\"..\") || rel.includes(`..${sep}`)) {\n return false;\n }\n\n const filePath =\n existsSync(abs) && statSync(abs).isFile()\n ? abs\n : join(publicDir, \"index.html\");\n if (!existsSync(filePath) || !statSync(filePath).isFile()) {\n return false;\n }\n\n const type = MIME_TYPES[extname(filePath)] ?? \"application/octet-stream\";\n res.writeHead(200, { \"Content-Type\": type });\n createReadStream(filePath).pipe(res);\n return true;\n}\n\nasync function authorizeApi(\n options: SchedulerDashboardHandlerOptions,\n method: string,\n pathname: string,\n req: IncomingMessage,\n): Promise<void> {\n if (options.authorize) {\n await options.authorize({\n method,\n pathname,\n authorization: req.headers.authorization,\n });\n return;\n }\n authorizeDashboardRequest({\n token: options.token,\n authorization: req.headers.authorization,\n });\n}\n\nasync function handleApi(\n dashboard: SchedulerDashboardService,\n method: string,\n pathname: string,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<void> {\n if (method === \"GET\" && pathname === \"/api/health\") {\n sendJson(res, 200, await dashboard.getHealth());\n return;\n }\n\n if (method === \"GET\" && pathname === \"/api/handlers\") {\n sendJson(res, 200, { handlers: dashboard.listHandlerKeys() });\n return;\n }\n\n if (method === \"GET\" && pathname === \"/api/jobs\") {\n sendJson(res, 200, { items: await dashboard.listItems() });\n return;\n }\n\n if (method === \"POST\" && pathname === \"/api/jobs\") {\n const created = await dashboard.createJob(\n parseCreateJobBody(await readJsonBody(req)),\n );\n sendJson(res, 201, created);\n return;\n }\n\n const jobExec = matchPath(pathname, \"/api/jobs/:jobId/executions\");\n if (jobExec && method === \"GET\") {\n sendJson(res, 200, {\n executions: await dashboard.listExecutions(jobExec.jobId ?? \"\"),\n });\n return;\n }\n\n const jobAction = matchPath(pathname, \"/api/jobs/:jobId/:action\");\n if (jobAction && method === \"POST\") {\n const jobId = jobAction.jobId ?? \"\";\n if (jobAction.action === \"pause\") {\n await dashboard.pauseJob(jobId);\n res.writeHead(204);\n res.end();\n return;\n }\n if (jobAction.action === \"resume\") {\n await dashboard.resumeJob(jobId);\n res.writeHead(204);\n res.end();\n return;\n }\n if (jobAction.action === \"run\") {\n await dashboard.runJob(jobId);\n res.writeHead(204);\n res.end();\n return;\n }\n }\n\n const retry = matchPath(pathname, \"/api/executions/:executionId/retry\");\n if (retry && method === \"POST\") {\n await dashboard.retryExecution(retry.executionId ?? \"\");\n res.writeHead(204);\n res.end();\n return;\n }\n\n const job = matchPath(pathname, \"/api/jobs/:jobId\");\n if (job) {\n const jobId = job.jobId ?? \"\";\n if (method === \"GET\") {\n const item = await dashboard.getJob(jobId);\n if (!item) {\n throw new DashboardHttpError(404, `Job not found: ${jobId}`);\n }\n sendJson(res, 200, item);\n return;\n }\n if (method === \"PATCH\") {\n await dashboard.updateJob(\n jobId,\n parseUpdateJobBody(await readJsonBody(req)),\n );\n res.writeHead(204);\n res.end();\n return;\n }\n if (method === \"DELETE\") {\n await dashboard.deleteJob(jobId);\n res.writeHead(204);\n res.end();\n return;\n }\n }\n\n sendJson(res, 404, { error: \"Not Found\" });\n}\n\nexport async function handleSchedulerDashboardRequest(\n req: IncomingMessage,\n res: ServerResponse,\n options: SchedulerDashboardHandlerOptions,\n): Promise<boolean> {\n const method = req.method ?? \"GET\";\n const originalUrl =\n \"originalUrl\" in req &&\n typeof (req as { originalUrl?: unknown }).originalUrl === \"string\"\n ? (req as { originalUrl: string }).originalUrl\n : undefined;\n const pathname = requestPathname(req.url, originalUrl);\n const basePath = normalizeDashboardBasePath(options.basePath);\n const relative = stripDashboardBasePath(pathname, basePath);\n if (relative === null) {\n return false;\n }\n\n if (method === \"GET\" && basePath && pathname === basePath) {\n res.writeHead(302, { Location: `${basePath}/` });\n res.end();\n return true;\n }\n\n const publicDir =\n options.publicDir ?? resolveDashboardPublicDir(import.meta.url);\n\n try {\n if (method === \"GET\" && relative === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(\"ok\");\n return true;\n }\n\n if (relative === \"/api\" || relative.startsWith(\"/api/\")) {\n await authorizeApi(options, method, relative, req);\n await handleApi(options.dashboard, method, relative, req, res);\n return true;\n }\n\n if (method === \"GET\" && servePublicFile(publicDir, relative, res)) {\n return true;\n }\n\n res.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(\"Not Found\");\n return true;\n } catch (error) {\n sendDashboardError(res, error);\n return true;\n }\n}\n\nexport function createSchedulerDashboardNodeHandler(\n options: SchedulerDashboardHandlerOptions,\n): SchedulerDashboardRequestHandler {\n return (req, res, next) => {\n void handleSchedulerDashboardRequest(req, res, options)\n .then((handled) => {\n if (!handled) {\n next?.();\n }\n })\n .catch((error: unknown) => {\n if (next) {\n next(error);\n return;\n }\n if (!res.headersSent) {\n sendDashboardError(res, error);\n }\n });\n };\n}\n","import * as http from \"node:http\";\n\nimport {\n createSchedulerDashboardNodeHandler,\n type SchedulerDashboardHandlerOptions,\n} from \"./http-handler.js\";\nimport { resolveDashboardPublicDir } from \"./public-dir.js\";\n\nexport type {\n DashboardAuthorize,\n SchedulerDashboardHandlerOptions,\n SchedulerDashboardRequestHandler,\n} from \"./http-handler.js\";\nexport {\n createSchedulerDashboardNodeHandler,\n handleSchedulerDashboardRequest,\n} from \"./http-handler.js\";\n\nexport interface SchedulerDashboardServerOptions\n extends SchedulerDashboardHandlerOptions {\n port?: number;\n host?: string;\n}\n\nexport interface SchedulerDashboardServer {\n readonly port: number;\n readonly host: string;\n listen(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport function createSchedulerDashboardServer(\n options: SchedulerDashboardServerOptions,\n): SchedulerDashboardServer {\n const port = options.port ?? 9100;\n const host = options.host ?? \"127.0.0.1\";\n const handler = createSchedulerDashboardNodeHandler({\n ...options,\n publicDir:\n options.publicDir ?? resolveDashboardPublicDir(import.meta.url),\n });\n\n const server = http.createServer((req, res) => {\n handler(req, res, () => {\n if (!res.headersSent) {\n res.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(\"Not Found\");\n }\n });\n });\n\n return {\n get port() {\n return port;\n },\n get host() {\n return host;\n },\n listen(): Promise<void> {\n return new Promise((resolveListen, reject) => {\n server.once(\"error\", reject);\n server.listen(port, host, () => {\n server.off(\"error\", reject);\n resolveListen();\n });\n });\n },\n close(): Promise<void> {\n return new Promise((resolveClose, reject) => {\n server.close((err) => (err ? reject(err) : resolveClose()));\n });\n },\n };\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport {\n createMySqlDialectAdapter,\n createPostgresDialectAdapter,\n createSqlClientAdapter,\n createSqlServerDialectAdapter,\n createSqliteDialectAdapter,\n type SqlDialectAdapter,\n type SqlDriverLike,\n} from \"@azlib/persistence\";\n\nexport type SchedulerDashboardDialect =\n | \"postgres\"\n | \"mysql\"\n | \"sqlite\"\n | \"mssql\";\n\nexport function rewriteQuestionParams(\n sql: string,\n style: \"$n\" | \"?\" | \"@pn\",\n): string {\n if (style === \"?\") {\n return sql;\n }\n let index = 0;\n return sql.replaceAll(\"?\", () => {\n index += 1;\n return style === \"$n\" ? `$${index}` : `@p${index}`;\n });\n}\n\nexport function inferDashboardDialect(\n databaseUrl: string,\n): SchedulerDashboardDialect {\n const scheme = databaseUrl.split(\":\")[0]?.toLowerCase() ?? \"\";\n if (scheme === \"postgres\" || scheme === \"postgresql\") {\n return \"postgres\";\n }\n if (scheme === \"mysql\" || scheme === \"mariadb\") {\n return \"mysql\";\n }\n if (scheme === \"mssql\" || scheme === \"sqlserver\") {\n return \"mssql\";\n }\n if (scheme === \"sqlite\" || scheme === \"file\") {\n return \"sqlite\";\n }\n return \"postgres\";\n}\n\nexport function dialectAdapterFor(\n dialect: SchedulerDashboardDialect,\n): SqlDialectAdapter {\n if (dialect === \"mysql\") {\n return createMySqlDialectAdapter();\n }\n if (dialect === \"sqlite\") {\n return createSqliteDialectAdapter();\n }\n if (dialect === \"mssql\") {\n return createSqlServerDialectAdapter();\n }\n return createPostgresDialectAdapter();\n}\n\nfunction sqlitePathFromUrl(databaseUrl: string): string {\n if (databaseUrl.startsWith(\"file:\")) {\n return databaseUrl.slice(\"file:\".length);\n }\n if (databaseUrl.startsWith(\"sqlite:\")) {\n return databaseUrl.slice(\"sqlite:\".length);\n }\n return databaseUrl;\n}\n\ntype PgQueryable = {\n query: (\n sql: string,\n params?: unknown[],\n ) => Promise<{ rows: unknown[] }>;\n};\n\ntype PgPool = PgQueryable & {\n connect: () => Promise<PgQueryable & { release: () => void }>;\n};\n\ntype MysqlConn = {\n execute: (\n sql: string,\n params?: unknown[],\n ) => Promise<[unknown, unknown]>;\n beginTransaction: () => Promise<void>;\n commit: () => Promise<void>;\n rollback: () => Promise<void>;\n release: () => void;\n};\n\ntype MysqlPool = {\n execute: (\n sql: string,\n params?: unknown[],\n ) => Promise<[unknown, unknown]>;\n getConnection: () => Promise<MysqlConn>;\n};\n\ntype SqliteDatabase = {\n prepare: (sql: string) => {\n all: (...params: unknown[]) => unknown[];\n run: (...params: unknown[]) => unknown;\n };\n};\n\ntype MssqlRequest = {\n input: (name: string, value: unknown) => void;\n query: (sql: string) => Promise<{ recordset: unknown[] }>;\n};\n\ntype MssqlPool = {\n request: () => MssqlRequest;\n};\n\nfunction bindMssqlParams(\n request: MssqlRequest,\n params: readonly unknown[] | undefined,\n): void {\n (params ?? []).forEach((value, index) => {\n request.input(`p${index + 1}`, value);\n });\n}\n\nfunction createPgDriver(pool: PgPool): SqlDriverLike {\n const txStore = new AsyncLocalStorage<PgQueryable>();\n const active = (): PgQueryable => txStore.getStore() ?? pool;\n const runQuery = async (sql: string, params?: readonly unknown[]) =>\n active().query(rewriteQuestionParams(sql, \"$n\"), [...(params ?? [])]);\n\n return {\n query: async <T = unknown>(sql: string, params?: readonly unknown[]) => {\n const result = await runQuery(sql, params);\n return result.rows as T[];\n },\n execute: async (sql: string, params?: readonly unknown[]) => {\n await runQuery(sql, params);\n },\n transaction: async <T>(run: () => Promise<T>): Promise<T> => {\n const existing = txStore.getStore();\n if (existing) {\n return run();\n }\n const conn = await pool.connect();\n try {\n await conn.query(\"BEGIN\");\n const result = await txStore.run(conn, run);\n await conn.query(\"COMMIT\");\n return result;\n } catch (error) {\n await conn.query(\"ROLLBACK\");\n throw error;\n } finally {\n conn.release();\n }\n },\n };\n}\n\nfunction createMysqlDriver(pool: MysqlPool): SqlDriverLike {\n const txStore = new AsyncLocalStorage<MysqlConn | MysqlPool>();\n const active = (): MysqlConn | MysqlPool => txStore.getStore() ?? pool;\n\n return {\n query: async <T = unknown>(sql: string, params?: readonly unknown[]) => {\n const [rows] = await active().execute(sql, [...(params ?? [])]);\n return rows as T[];\n },\n execute: async (sql: string, params?: readonly unknown[]) => {\n await active().execute(sql, [...(params ?? [])]);\n },\n transaction: async <T>(run: () => Promise<T>): Promise<T> => {\n const existing = txStore.getStore();\n if (existing) {\n return run();\n }\n const conn = await pool.getConnection();\n try {\n await conn.beginTransaction();\n const result = await txStore.run(conn, run);\n await conn.commit();\n return result;\n } catch (error) {\n await conn.rollback();\n throw error;\n } finally {\n conn.release();\n }\n },\n };\n}\n\nexport async function createDashboardSqlDriver(\n databaseUrl: string,\n dialect: SchedulerDashboardDialect,\n): Promise<SqlDriverLike> {\n if (dialect === \"postgres\") {\n const pg = (await import(\"pg\")) as {\n default?: { Pool: new (config: { connectionString: string }) => PgPool };\n Pool?: new (config: { connectionString: string }) => PgPool;\n };\n const Pool = pg.Pool ?? pg.default?.Pool;\n if (!Pool) {\n throw new Error(\"The pg package is required for postgres dashboards.\");\n }\n return createPgDriver(new Pool({ connectionString: databaseUrl }));\n }\n\n if (dialect === \"mysql\") {\n const mysql = (await import(\"mysql2/promise\")) as {\n default?: { createPool: (url: string) => MysqlPool };\n createPool?: (url: string) => MysqlPool;\n };\n const createPool = mysql.createPool ?? mysql.default?.createPool;\n if (!createPool) {\n throw new Error(\"The mysql2 package is required for mysql dashboards.\");\n }\n return createMysqlDriver(createPool(databaseUrl));\n }\n\n if (dialect === \"sqlite\") {\n const sqlite = (await import(\"better-sqlite3\")) as {\n default?: new (path: string) => SqliteDatabase;\n };\n const Database = sqlite.default;\n if (!Database) {\n throw new Error(\n \"The better-sqlite3 package is required for sqlite dashboards.\",\n );\n }\n const db = new Database(sqlitePathFromUrl(databaseUrl));\n return {\n query: async <T = unknown>(sql: string, params?: readonly unknown[]) =>\n db.prepare(sql).all(...(params ?? [])) as T[],\n execute: async (sql: string, params?: readonly unknown[]) => {\n db.prepare(sql).run(...(params ?? []));\n },\n transaction: async <T>(run: () => Promise<T>): Promise<T> => run(),\n };\n }\n\n const mssql = (await import(\"mssql\")) as {\n default?: { connect: (url: string) => Promise<MssqlPool> };\n connect?: (url: string) => Promise<MssqlPool>;\n };\n const connect = mssql.connect ?? mssql.default?.connect;\n if (!connect) {\n throw new Error(\"The mssql package is required for mssql dashboards.\");\n }\n const pool = await connect(databaseUrl);\n return {\n query: async <T = unknown>(sql: string, params?: readonly unknown[]) => {\n const request = pool.request();\n bindMssqlParams(request, params);\n const result = await request.query(rewriteQuestionParams(sql, \"@pn\"));\n return result.recordset as T[];\n },\n execute: async (sql: string, params?: readonly unknown[]) => {\n const request = pool.request();\n bindMssqlParams(request, params);\n await request.query(rewriteQuestionParams(sql, \"@pn\"));\n },\n transaction: async <T>(run: () => Promise<T>): Promise<T> => run(),\n };\n}\n\nexport function createDashboardPersistenceConfig(input: {\n driver: SqlDriverLike;\n dialect: SchedulerDashboardDialect;\n namespace?: string;\n}) {\n return {\n client: createSqlClientAdapter(input.driver),\n dialect: dialectAdapterFor(input.dialect),\n namespace: input.namespace,\n };\n}\n","import { asString } from \"@azlib/std\";\n\nimport { assertDashboardBindSafety } from \"./http-auth.js\";\nimport {\n inferDashboardDialect,\n type SchedulerDashboardDialect,\n} from \"./sql-drivers.js\";\n\nexport interface SchedulerDashboardCliConfig {\n databaseUrl: string;\n dialect: SchedulerDashboardDialect;\n namespace: string;\n port: number;\n host: string;\n token?: string;\n}\n\nfunction parsePort(value: string | undefined, fallback: number): number {\n if (!value) {\n return fallback;\n }\n const port = Number(value);\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(`Invalid PORT: ${value}`);\n }\n return port;\n}\n\nfunction parseDialect(\n value: string | undefined,\n databaseUrl: string,\n): SchedulerDashboardDialect {\n const explicit = value?.trim().toLowerCase();\n if (!explicit) {\n return inferDashboardDialect(databaseUrl);\n }\n if (\n explicit === \"postgres\" ||\n explicit === \"mysql\" ||\n explicit === \"sqlite\" ||\n explicit === \"mssql\"\n ) {\n return explicit;\n }\n throw new Error(\n `Invalid SCHEDULER_DIALECT: ${value}. Use postgres, mysql, sqlite, or mssql.`,\n );\n}\n\nexport function parseDashboardCliEnv(\n env: Record<string, string | undefined>,\n): SchedulerDashboardCliConfig {\n const databaseUrl = asString(env.DATABASE_URL)?.trim();\n if (!databaseUrl) {\n throw new Error(\"DATABASE_URL is required\");\n }\n\n const host = asString(env.HOST)?.trim() || \"127.0.0.1\";\n const token = asString(env.DASHBOARD_TOKEN)?.trim() || undefined;\n assertDashboardBindSafety({ host, token });\n\n return {\n databaseUrl,\n dialect: parseDialect(env.SCHEDULER_DIALECT, databaseUrl),\n namespace: asString(env.SCHEDULER_NAMESPACE)?.trim() || \"azlib\",\n port: parsePort(env.PORT, 9100),\n host,\n token,\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_cli_config = require("../cli-config-Cz8QP_4I.cjs");
3
+ const require_cli_config = require("../cli-config-DLwU62NO.cjs");
4
4
  const require_store_dashboard = require("../store-dashboard-Sg4BBWiJ.cjs");
5
5
  let node_url = require("node:url");
6
6
  //#region src/dashboard/cli.ts
@@ -1,4 +1,4 @@
1
- import { t as SchedulerDashboardServer } from "../http-server-DN6Lg464.cjs";
1
+ import { t as SchedulerDashboardServer } from "../http-server-u1BnbkAK.cjs";
2
2
  //#region src/dashboard/cli.d.ts
3
3
  declare function startSchedulerDashboardCli(env?: Record<string, string | undefined>): Promise<SchedulerDashboardServer>;
4
4
  //#endregion
@@ -1,4 +1,4 @@
1
- import { t as SchedulerDashboardServer } from "../http-server-DPQ9HIK-.mjs";
1
+ import { t as SchedulerDashboardServer } from "../http-server-Cme4XKyH.mjs";
2
2
  //#region src/dashboard/cli.d.ts
3
3
  declare function startSchedulerDashboardCli(env?: Record<string, string | undefined>): Promise<SchedulerDashboardServer>;
4
4
  //#endregion
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as createSchedulerDashboardFromPersistence } from "../store-dashboard-Cyf_JILa.mjs";
3
- import { a as resolveDashboardPublicDir, i as createSchedulerDashboardServer, n as createDashboardPersistenceConfig, r as createDashboardSqlDriver, t as parseDashboardCliEnv } from "../cli-config-7F2U8qPM.mjs";
3
+ import { i as createSchedulerDashboardServer, n as createDashboardPersistenceConfig, r as createDashboardSqlDriver, s as resolveDashboardPublicDir, t as parseDashboardCliEnv } from "../cli-config-DrI08d47.mjs";
4
4
  import { pathToFileURL } from "node:url";
5
5
  //#region src/dashboard/cli.ts
6
6
  async function startSchedulerDashboardCli(env = process.env) {