@meetploy/cli 1.17.1 → 1.18.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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Ploy Dev Dashboard</title>
7
- <script type="module" crossorigin src="/assets/main-Ch3tPHX5.js"></script>
7
+ <script type="module" crossorigin src="/assets/main-BFhQn9QT.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/main-5Kt9I_hM.css">
9
9
  </head>
10
10
  <body>
package/dist/dev.js CHANGED
@@ -10,9 +10,9 @@ import { parse } from 'yaml';
10
10
  import { randomUUID, createHmac, pbkdf2Sync, timingSafeEqual, randomBytes } from 'crypto';
11
11
  import { serve } from '@hono/node-server';
12
12
  import { Hono } from 'hono';
13
- import 'os';
13
+ import { tmpdir } from 'os';
14
14
  import { getCookie, deleteCookie, setCookie } from 'hono/cookie';
15
- import Database from 'better-sqlite3';
15
+ import { DatabaseSync, backup } from 'node:sqlite';
16
16
 
17
17
  createRequire(import.meta.url);
18
18
 
@@ -49,62 +49,6 @@ function readPloyConfig(projectDir, configPath) {
49
49
  }
50
50
  return config;
51
51
  }
52
-
53
- // ../emulator/dist/services/alarm-service.js
54
- function createAlarmHandlers(db) {
55
- const setHandler = async (c) => {
56
- try {
57
- const body = await c.req.json();
58
- const { alarmName, id, scheduledTime, payload, intervalMs } = body;
59
- const now = Math.floor(Date.now() / 1e3);
60
- const scheduledTimeSec = Math.floor(scheduledTime / 1e3);
61
- db.prepare(`INSERT OR REPLACE INTO alarm_entries (id, alarm_name, scheduled_time, payload, interval_ms, status, created_at)
62
- VALUES (?, ?, ?, ?, ?, 'pending', ?)`).run(id, alarmName, scheduledTimeSec, payload !== void 0 ? JSON.stringify(payload) : null, intervalMs ?? null, now);
63
- return c.json({ success: true });
64
- } catch (err) {
65
- const message = err instanceof Error ? err.message : String(err);
66
- return c.json({ success: false, error: message }, 500);
67
- }
68
- };
69
- const getHandler = async (c) => {
70
- try {
71
- const body = await c.req.json();
72
- const { alarmName, id } = body;
73
- const row = db.prepare(`SELECT id, scheduled_time, payload, interval_ms FROM alarm_entries
74
- WHERE alarm_name = ? AND id = ? AND status = 'pending'`).get(alarmName, id);
75
- if (!row) {
76
- return c.json({ alarm: null });
77
- }
78
- return c.json({
79
- alarm: {
80
- id: row.id,
81
- scheduledTime: row.scheduled_time * 1e3,
82
- payload: row.payload ? JSON.parse(row.payload) : void 0,
83
- intervalMs: row.interval_ms ?? void 0
84
- }
85
- });
86
- } catch (err) {
87
- const message = err instanceof Error ? err.message : String(err);
88
- return c.json({ success: false, error: message }, 500);
89
- }
90
- };
91
- const deleteHandler = async (c) => {
92
- try {
93
- const body = await c.req.json();
94
- const { alarmName, id } = body;
95
- db.prepare(`DELETE FROM alarm_entries WHERE alarm_name = ? AND id = ?`).run(alarmName, id);
96
- return c.json({ success: true });
97
- } catch (err) {
98
- const message = err instanceof Error ? err.message : String(err);
99
- return c.json({ success: false, error: message }, 500);
100
- }
101
- };
102
- return {
103
- setHandler,
104
- getHandler,
105
- deleteHandler
106
- };
107
- }
108
52
  function getDataDir(projectDir) {
109
53
  return join(projectDir, ".ploy");
110
54
  }
@@ -437,7 +381,7 @@ function createDashboardRoutes(app, dbManager2, config) {
437
381
  fs: config.fs,
438
382
  workflow: config.workflow,
439
383
  cron: config.cron,
440
- alarm: config.alarm,
384
+ timer: config.timer,
441
385
  auth: config.auth
442
386
  });
443
387
  });
@@ -992,22 +936,22 @@ function createDashboardRoutes(app, dbManager2, config) {
992
936
  return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
993
937
  }
994
938
  });
995
- app.get("/api/alarm/:binding/entries", (c) => {
939
+ app.get("/api/timer/:binding/entries", (c) => {
996
940
  const binding = c.req.param("binding");
997
- const alarmName = config.alarm?.[binding];
941
+ const timerName = config.timer?.[binding];
998
942
  const limit = parseInt(c.req.query("limit") ?? "20", 10);
999
943
  const offset = parseInt(c.req.query("offset") ?? "0", 10);
1000
- if (!alarmName) {
1001
- return c.json({ error: "Alarm binding not found" }, 404);
944
+ if (!timerName) {
945
+ return c.json({ error: "Timer binding not found" }, 404);
1002
946
  }
1003
947
  try {
1004
948
  const db = dbManager2.emulatorDb;
1005
- const total = db.prepare(`SELECT COUNT(*) as count FROM alarm_entries WHERE alarm_name = ?`).get(alarmName).count;
949
+ const total = db.prepare(`SELECT COUNT(*) as count FROM timer_entries WHERE timer_name = ?`).get(timerName).count;
1006
950
  const entries = db.prepare(`SELECT id, scheduled_time, payload, interval_ms, status, created_at
1007
- FROM alarm_entries
1008
- WHERE alarm_name = ?
951
+ FROM timer_entries
952
+ WHERE timer_name = ?
1009
953
  ORDER BY scheduled_time DESC
1010
- LIMIT ? OFFSET ?`).all(alarmName, limit, offset);
954
+ LIMIT ? OFFSET ?`).all(timerName, limit, offset);
1011
955
  return c.json({
1012
956
  entries: entries.map((e) => ({
1013
957
  id: e.id,
@@ -1025,19 +969,19 @@ function createDashboardRoutes(app, dbManager2, config) {
1025
969
  return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
1026
970
  }
1027
971
  });
1028
- app.get("/api/alarm/:binding/metrics", (c) => {
972
+ app.get("/api/timer/:binding/metrics", (c) => {
1029
973
  const binding = c.req.param("binding");
1030
- const alarmName = config.alarm?.[binding];
1031
- if (!alarmName) {
1032
- return c.json({ error: "Alarm binding not found" }, 404);
974
+ const timerName = config.timer?.[binding];
975
+ if (!timerName) {
976
+ return c.json({ error: "Timer binding not found" }, 404);
1033
977
  }
1034
978
  try {
1035
979
  const db = dbManager2.emulatorDb;
1036
980
  const metrics = { pending: 0, fired: 0 };
1037
981
  const statusCounts = db.prepare(`SELECT status, COUNT(*) as count
1038
- FROM alarm_entries
1039
- WHERE alarm_name = ?
1040
- GROUP BY status`).all(alarmName);
982
+ FROM timer_entries
983
+ WHERE timer_name = ?
984
+ GROUP BY status`).all(timerName);
1041
985
  for (const row of statusCounts) {
1042
986
  if (row.status === "pending") {
1043
987
  metrics.pending = row.count;
@@ -1050,24 +994,24 @@ function createDashboardRoutes(app, dbManager2, config) {
1050
994
  return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
1051
995
  }
1052
996
  });
1053
- app.get("/api/alarm/:binding/executions", (c) => {
997
+ app.get("/api/timer/:binding/executions", (c) => {
1054
998
  const binding = c.req.param("binding");
1055
- const alarmName = config.alarm?.[binding];
999
+ const timerName = config.timer?.[binding];
1056
1000
  const limit = parseInt(c.req.query("limit") ?? "20", 10);
1057
- if (!alarmName) {
1058
- return c.json({ error: "Alarm binding not found" }, 404);
1001
+ if (!timerName) {
1002
+ return c.json({ error: "Timer binding not found" }, 404);
1059
1003
  }
1060
1004
  try {
1061
1005
  const db = dbManager2.emulatorDb;
1062
- const executions = db.prepare(`SELECT id, alarm_id, scheduled_time, status, error, duration_ms, created_at
1063
- FROM alarm_executions
1064
- WHERE alarm_name = ?
1006
+ const executions = db.prepare(`SELECT id, timer_id, scheduled_time, status, error, duration_ms, created_at
1007
+ FROM timer_executions
1008
+ WHERE timer_name = ?
1065
1009
  ORDER BY created_at DESC
1066
- LIMIT ?`).all(alarmName, limit);
1010
+ LIMIT ?`).all(timerName, limit);
1067
1011
  return c.json({
1068
1012
  executions: executions.map((e) => ({
1069
1013
  id: e.id,
1070
- alarmId: e.alarm_id,
1014
+ timerId: e.timer_id,
1071
1015
  scheduledTime: new Date(e.scheduled_time * 1e3).toISOString(),
1072
1016
  status: e.status.toUpperCase(),
1073
1017
  error: e.error,
@@ -1192,7 +1136,7 @@ function createDbHandler(getDatabase) {
1192
1136
  return c.json(results);
1193
1137
  }
1194
1138
  if (method === "dump") {
1195
- const buffer = db.serialize();
1139
+ const buffer = await db.dumpToBuffer();
1196
1140
  return new Response(new Uint8Array(buffer), {
1197
1141
  headers: {
1198
1142
  "Content-Type": "application/octet-stream"
@@ -1461,6 +1405,62 @@ function createStateHandlers(db) {
1461
1405
  deleteHandler
1462
1406
  };
1463
1407
  }
1408
+
1409
+ // ../emulator/dist/services/timer-service.js
1410
+ function createTimerHandlers(db) {
1411
+ const setHandler = async (c) => {
1412
+ try {
1413
+ const body = await c.req.json();
1414
+ const { timerName, id, scheduledTime, payload, intervalMs } = body;
1415
+ const now = Math.floor(Date.now() / 1e3);
1416
+ const scheduledTimeSec = Math.floor(scheduledTime / 1e3);
1417
+ db.prepare(`INSERT OR REPLACE INTO timer_entries (id, timer_name, scheduled_time, payload, interval_ms, status, created_at)
1418
+ VALUES (?, ?, ?, ?, ?, 'pending', ?)`).run(id, timerName, scheduledTimeSec, payload !== void 0 ? JSON.stringify(payload) : null, intervalMs ?? null, now);
1419
+ return c.json({ success: true });
1420
+ } catch (err) {
1421
+ const message = err instanceof Error ? err.message : String(err);
1422
+ return c.json({ success: false, error: message }, 500);
1423
+ }
1424
+ };
1425
+ const getHandler = async (c) => {
1426
+ try {
1427
+ const body = await c.req.json();
1428
+ const { timerName, id } = body;
1429
+ const row = db.prepare(`SELECT id, scheduled_time, payload, interval_ms FROM timer_entries
1430
+ WHERE timer_name = ? AND id = ? AND status = 'pending'`).get(timerName, id);
1431
+ if (!row) {
1432
+ return c.json({ timer: null });
1433
+ }
1434
+ return c.json({
1435
+ timer: {
1436
+ id: row.id,
1437
+ scheduledTime: row.scheduled_time * 1e3,
1438
+ payload: row.payload ? JSON.parse(row.payload) : void 0,
1439
+ intervalMs: row.interval_ms ?? void 0
1440
+ }
1441
+ });
1442
+ } catch (err) {
1443
+ const message = err instanceof Error ? err.message : String(err);
1444
+ return c.json({ success: false, error: message }, 500);
1445
+ }
1446
+ };
1447
+ const deleteHandler = async (c) => {
1448
+ try {
1449
+ const body = await c.req.json();
1450
+ const { timerName, id } = body;
1451
+ db.prepare(`DELETE FROM timer_entries WHERE timer_name = ? AND id = ?`).run(timerName, id);
1452
+ return c.json({ success: true });
1453
+ } catch (err) {
1454
+ const message = err instanceof Error ? err.message : String(err);
1455
+ return c.json({ success: false, error: message }, 500);
1456
+ }
1457
+ };
1458
+ return {
1459
+ setHandler,
1460
+ getHandler,
1461
+ deleteHandler
1462
+ };
1463
+ }
1464
1464
  function createWorkflowHandlers(db, workerUrl) {
1465
1465
  const triggerHandler = async (c) => {
1466
1466
  try {
@@ -1682,11 +1682,11 @@ async function startMockServer(dbManager2, config, options = {}) {
1682
1682
  app.post("/fs/delete", fsHandlers.deleteHandler);
1683
1683
  app.post("/fs/list", fsHandlers.listHandler);
1684
1684
  }
1685
- if (config.alarm) {
1686
- const alarmHandlers = createAlarmHandlers(dbManager2.emulatorDb);
1687
- app.post("/alarm/set", alarmHandlers.setHandler);
1688
- app.post("/alarm/get", alarmHandlers.getHandler);
1689
- app.post("/alarm/delete", alarmHandlers.deleteHandler);
1685
+ if (config.timer) {
1686
+ const timerHandlers = createTimerHandlers(dbManager2.emulatorDb);
1687
+ app.post("/timer/set", timerHandlers.setHandler);
1688
+ app.post("/timer/get", timerHandlers.getHandler);
1689
+ app.post("/timer/delete", timerHandlers.deleteHandler);
1690
1690
  }
1691
1691
  if (config.auth) {
1692
1692
  const authHandlers = createAuthHandlers(dbManager2.emulatorDb);
@@ -1716,6 +1716,65 @@ async function startMockServer(dbManager2, config, options = {}) {
1716
1716
  });
1717
1717
  });
1718
1718
  }
1719
+ function openDatabase(filepath) {
1720
+ const db = new DatabaseSync(filepath);
1721
+ return {
1722
+ prepare(sql) {
1723
+ const stmt = db.prepare(sql);
1724
+ return {
1725
+ run(...params) {
1726
+ const result = stmt.run(...params);
1727
+ return {
1728
+ changes: Number(result.changes),
1729
+ lastInsertRowid: result.lastInsertRowid
1730
+ };
1731
+ },
1732
+ get(...params) {
1733
+ return stmt.get(...params);
1734
+ },
1735
+ all(...params) {
1736
+ return stmt.all(...params);
1737
+ }
1738
+ };
1739
+ },
1740
+ exec(sql) {
1741
+ db.exec(sql);
1742
+ },
1743
+ close() {
1744
+ db.close();
1745
+ },
1746
+ pragma(pragma) {
1747
+ db.exec(`PRAGMA ${pragma}`);
1748
+ },
1749
+ transaction(fn) {
1750
+ return () => {
1751
+ db.exec("BEGIN");
1752
+ try {
1753
+ const result = fn();
1754
+ db.exec("COMMIT");
1755
+ return result;
1756
+ } catch (e) {
1757
+ db.exec("ROLLBACK");
1758
+ throw e;
1759
+ }
1760
+ };
1761
+ },
1762
+ async dumpToBuffer() {
1763
+ const tempPath = join(tmpdir(), `ploy-dump-${randomUUID()}.db`);
1764
+ try {
1765
+ await backup(db, tempPath);
1766
+ return readFileSync(tempPath);
1767
+ } finally {
1768
+ try {
1769
+ unlinkSync(tempPath);
1770
+ } catch {
1771
+ }
1772
+ }
1773
+ }
1774
+ };
1775
+ }
1776
+
1777
+ // ../emulator/dist/utils/sqlite.js
1719
1778
  var EMULATOR_SCHEMA = `
1720
1779
  -- Queue messages table
1721
1780
  CREATE TABLE IF NOT EXISTS queue_messages (
@@ -1852,26 +1911,26 @@ CREATE TABLE IF NOT EXISTS cron_executions (
1852
1911
  CREATE INDEX IF NOT EXISTS idx_cron_executions_name
1853
1912
  ON cron_executions(cron_name, triggered_at);
1854
1913
 
1855
- -- Alarm entries table (durable timers, optionally recurring)
1856
- CREATE TABLE IF NOT EXISTS alarm_entries (
1914
+ -- Timer entries table (durable timers, optionally recurring)
1915
+ CREATE TABLE IF NOT EXISTS timer_entries (
1857
1916
  id TEXT NOT NULL,
1858
- alarm_name TEXT NOT NULL,
1917
+ timer_name TEXT NOT NULL,
1859
1918
  scheduled_time INTEGER NOT NULL,
1860
1919
  payload TEXT,
1861
1920
  interval_ms INTEGER,
1862
1921
  status TEXT DEFAULT 'pending',
1863
1922
  created_at INTEGER DEFAULT (strftime('%s', 'now')),
1864
- PRIMARY KEY (alarm_name, id)
1923
+ PRIMARY KEY (timer_name, id)
1865
1924
  );
1866
1925
 
1867
- CREATE INDEX IF NOT EXISTS idx_alarm_entries_status_time
1868
- ON alarm_entries(status, scheduled_time);
1926
+ CREATE INDEX IF NOT EXISTS idx_timer_entries_status_time
1927
+ ON timer_entries(status, scheduled_time);
1869
1928
 
1870
- -- Alarm execution log
1871
- CREATE TABLE IF NOT EXISTS alarm_executions (
1929
+ -- Timer execution log
1930
+ CREATE TABLE IF NOT EXISTS timer_executions (
1872
1931
  id INTEGER PRIMARY KEY AUTOINCREMENT,
1873
- alarm_id TEXT NOT NULL,
1874
- alarm_name TEXT NOT NULL,
1932
+ timer_id TEXT NOT NULL,
1933
+ timer_name TEXT NOT NULL,
1875
1934
  scheduled_time INTEGER NOT NULL,
1876
1935
  status TEXT DEFAULT 'pending',
1877
1936
  error TEXT,
@@ -1879,19 +1938,19 @@ CREATE TABLE IF NOT EXISTS alarm_executions (
1879
1938
  created_at INTEGER DEFAULT (strftime('%s', 'now'))
1880
1939
  );
1881
1940
 
1882
- CREATE INDEX IF NOT EXISTS idx_alarm_executions_name
1883
- ON alarm_executions(alarm_name, created_at);
1941
+ CREATE INDEX IF NOT EXISTS idx_timer_executions_name
1942
+ ON timer_executions(timer_name, created_at);
1884
1943
  `;
1885
1944
  function initializeDatabases(projectDir) {
1886
1945
  const dataDir = ensureDataDir(projectDir);
1887
1946
  const d1Databases = /* @__PURE__ */ new Map();
1888
- const emulatorDb = new Database(join(dataDir, "emulator.db"));
1947
+ const emulatorDb = openDatabase(join(dataDir, "emulator.db"));
1889
1948
  emulatorDb.pragma("journal_mode = WAL");
1890
1949
  emulatorDb.exec(EMULATOR_SCHEMA);
1891
1950
  function getD1Database(bindingName) {
1892
1951
  let db = d1Databases.get(bindingName);
1893
1952
  if (!db) {
1894
- db = new Database(join(dataDir, "db", `${bindingName}.db`));
1953
+ db = openDatabase(join(dataDir, "db", `${bindingName}.db`));
1895
1954
  db.pragma("journal_mode = WAL");
1896
1955
  d1Databases.set(bindingName, db);
1897
1956
  }