@meetploy/cli 1.12.2 → 1.13.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.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
3
  import { mkdir, writeFile, readFile, chmod, access } from 'fs/promises';
4
- import { join, dirname, relative } from 'path';
4
+ import { join, dirname, relative, basename } from 'path';
5
5
  import { existsSync, readFileSync, writeFileSync, unlinkSync, readFile as readFile$1, mkdirSync } from 'fs';
6
6
  import { promisify } from 'util';
7
7
  import { parse } from 'yaml';
@@ -196,6 +196,7 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
196
196
  validatedConfig.main = validateRelativePath(config.main, "main", configFile);
197
197
  validateBindings(config.db, "db", configFile);
198
198
  validateBindings(config.queue, "queue", configFile);
199
+ validateBindings(config.cache, "cache", configFile);
199
200
  validateBindings(config.workflow, "workflow", configFile);
200
201
  if (config.ai !== void 0 && typeof config.ai !== "boolean") {
201
202
  throw new Error(`'ai' in ${configFile} must be a boolean`);
@@ -275,7 +276,7 @@ function readAndValidatePloyConfigSync(projectDir, configPath, validationOptions
275
276
  return validatePloyConfig(config, configFile, validationOptions);
276
277
  }
277
278
  function hasBindings(config) {
278
- return !!(config.db || config.queue || config.workflow || config.ai || config.auth);
279
+ return !!(config.db || config.queue || config.cache || config.workflow || config.ai || config.auth);
279
280
  }
280
281
  function getWorkerEntryPoint(projectDir, config) {
281
282
  if (config.main) {
@@ -331,6 +332,66 @@ var init_cli = __esm({
331
332
  }
332
333
  });
333
334
 
335
+ // ../emulator/dist/runtime/cache-runtime.js
336
+ var CACHE_RUNTIME_CODE;
337
+ var init_cache_runtime = __esm({
338
+ "../emulator/dist/runtime/cache-runtime.js"() {
339
+ CACHE_RUNTIME_CODE = `
340
+ interface CacheBinding {
341
+ get: (key: string) => Promise<string | null>;
342
+ set: (key: string, value: string, opts: { ttl: number }) => Promise<void>;
343
+ delete: (key: string) => Promise<void>;
344
+ }
345
+
346
+ export function initializeCache(cacheName: string, serviceUrl: string): CacheBinding {
347
+ return {
348
+ async get(key: string): Promise<string | null> {
349
+ const response = await fetch(serviceUrl + "/cache/get", {
350
+ method: "POST",
351
+ headers: { "Content-Type": "application/json" },
352
+ body: JSON.stringify({ cacheName, key }),
353
+ });
354
+
355
+ if (!response.ok) {
356
+ const errorText = await response.text();
357
+ throw new Error("Cache get failed: " + errorText);
358
+ }
359
+
360
+ const result = await response.json();
361
+ return result.value ?? null;
362
+ },
363
+
364
+ async set(key: string, value: string, opts: { ttl: number }): Promise<void> {
365
+ const response = await fetch(serviceUrl + "/cache/set", {
366
+ method: "POST",
367
+ headers: { "Content-Type": "application/json" },
368
+ body: JSON.stringify({ cacheName, key, value, ttl: opts.ttl }),
369
+ });
370
+
371
+ if (!response.ok) {
372
+ const errorText = await response.text();
373
+ throw new Error("Cache set failed: " + errorText);
374
+ }
375
+ },
376
+
377
+ async delete(key: string): Promise<void> {
378
+ const response = await fetch(serviceUrl + "/cache/delete", {
379
+ method: "POST",
380
+ headers: { "Content-Type": "application/json" },
381
+ body: JSON.stringify({ cacheName, key }),
382
+ });
383
+
384
+ if (!response.ok) {
385
+ const errorText = await response.text();
386
+ throw new Error("Cache delete failed: " + errorText);
387
+ }
388
+ },
389
+ };
390
+ }
391
+ `;
392
+ }
393
+ });
394
+
334
395
  // ../shared/dist/d1-runtime.js
335
396
  var DB_RUNTIME_CODE, DB_RUNTIME_CODE_PRODUCTION;
336
397
  var init_d1_runtime = __esm({
@@ -942,6 +1003,12 @@ function generateWrapperCode(config, mockServiceUrl) {
942
1003
  bindings.push(` ${bindingName}: initializeQueue("${queueName}", "${mockServiceUrl}"),`);
943
1004
  }
944
1005
  }
1006
+ if (config.cache) {
1007
+ imports.push('import { initializeCache } from "__ploy_cache_runtime__";');
1008
+ for (const [bindingName, cacheName] of Object.entries(config.cache)) {
1009
+ bindings.push(` ${bindingName}: initializeCache("${cacheName}", "${mockServiceUrl}"),`);
1010
+ }
1011
+ }
945
1012
  if (config.workflow) {
946
1013
  imports.push('import { initializeWorkflow, createStepContext, executeWorkflow } from "__ploy_workflow_runtime__";');
947
1014
  for (const [bindingName, workflowName] of Object.entries(config.workflow)) {
@@ -1045,6 +1112,10 @@ function createRuntimePlugin(_config) {
1045
1112
  path: "__ploy_queue_runtime__",
1046
1113
  namespace: "ploy-runtime"
1047
1114
  }));
1115
+ build2.onResolve({ filter: /^__ploy_cache_runtime__$/ }, () => ({
1116
+ path: "__ploy_cache_runtime__",
1117
+ namespace: "ploy-runtime"
1118
+ }));
1048
1119
  build2.onResolve({ filter: /^__ploy_workflow_runtime__$/ }, () => ({
1049
1120
  path: "__ploy_workflow_runtime__",
1050
1121
  namespace: "ploy-runtime"
@@ -1057,6 +1128,10 @@ function createRuntimePlugin(_config) {
1057
1128
  contents: QUEUE_RUNTIME_CODE,
1058
1129
  loader: "ts"
1059
1130
  }));
1131
+ build2.onLoad({ filter: /^__ploy_cache_runtime__$/, namespace: "ploy-runtime" }, () => ({
1132
+ contents: CACHE_RUNTIME_CODE,
1133
+ loader: "ts"
1134
+ }));
1060
1135
  build2.onLoad({ filter: /^__ploy_workflow_runtime__$/, namespace: "ploy-runtime" }, () => ({
1061
1136
  contents: WORKFLOW_RUNTIME_CODE,
1062
1137
  loader: "ts"
@@ -1097,6 +1172,7 @@ async function bundleWorker(options) {
1097
1172
  var NODE_BUILTINS;
1098
1173
  var init_bundler = __esm({
1099
1174
  "../emulator/dist/bundler/bundler.js"() {
1175
+ init_cache_runtime();
1100
1176
  init_db_runtime();
1101
1177
  init_queue_runtime();
1102
1178
  init_workflow_runtime();
@@ -1156,9 +1232,6 @@ function log(message) {
1156
1232
  function success(message) {
1157
1233
  console.log(`${COLORS.dim}[${timestamp()}]${COLORS.reset} ${COLORS.green}[ploy]${COLORS.reset} ${message}`);
1158
1234
  }
1159
- function warn(message) {
1160
- console.log(`${COLORS.dim}[${timestamp()}]${COLORS.reset} ${COLORS.yellow}[ploy]${COLORS.reset} ${message}`);
1161
- }
1162
1235
  function error(message) {
1163
1236
  console.error(`${COLORS.dim}[${timestamp()}]${COLORS.reset} ${COLORS.red}[ploy]${COLORS.reset} ${message}`);
1164
1237
  }
@@ -1181,6 +1254,22 @@ var init_logger = __esm({
1181
1254
  };
1182
1255
  }
1183
1256
  });
1257
+ function isIgnored(filePath) {
1258
+ const name = basename(filePath);
1259
+ if (name.startsWith(".")) {
1260
+ return true;
1261
+ }
1262
+ if (IGNORED_DIRS.has(name)) {
1263
+ return true;
1264
+ }
1265
+ if (IGNORED_FILES.has(name)) {
1266
+ return true;
1267
+ }
1268
+ if (name.endsWith(".log")) {
1269
+ return true;
1270
+ }
1271
+ return false;
1272
+ }
1184
1273
  function createFileWatcher(srcDir, onRebuild) {
1185
1274
  let watcher = null;
1186
1275
  let debounceTimer = null;
@@ -1213,25 +1302,11 @@ function createFileWatcher(srcDir, onRebuild) {
1213
1302
  watcher = watch(srcDir, {
1214
1303
  persistent: true,
1215
1304
  ignoreInitial: true,
1216
- ignored: [
1217
- "**/node_modules/**",
1218
- "**/dist/**",
1219
- "**/.*",
1220
- "**/.*/**",
1221
- "**/coverage/**",
1222
- "**/build/**",
1223
- "**/*.log",
1224
- "**/pnpm-lock.yaml",
1225
- "**/package-lock.json",
1226
- "**/yarn.lock"
1227
- ]
1305
+ ignored: isIgnored
1228
1306
  });
1229
1307
  watcher.on("error", (err) => {
1230
1308
  const error2 = err;
1231
- if (error2.code === "EMFILE") {
1232
- warn("Warning: Too many open files. Some file changes may not be detected.");
1233
- warn("Consider increasing your system's file descriptor limit (ulimit -n).");
1234
- } else {
1309
+ if (error2.code !== "EMFILE") {
1235
1310
  error(`File watcher error: ${error2.message || String(err)}`);
1236
1311
  }
1237
1312
  });
@@ -1263,9 +1338,16 @@ function createFileWatcher(srcDir, onRebuild) {
1263
1338
  }
1264
1339
  };
1265
1340
  }
1341
+ var IGNORED_DIRS, IGNORED_FILES;
1266
1342
  var init_watcher = __esm({
1267
1343
  "../emulator/dist/bundler/watcher.js"() {
1268
1344
  init_logger();
1345
+ IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage", "build"]);
1346
+ IGNORED_FILES = /* @__PURE__ */ new Set([
1347
+ "pnpm-lock.yaml",
1348
+ "package-lock.json",
1349
+ "yarn.lock"
1350
+ ]);
1269
1351
  }
1270
1352
  });
1271
1353
 
@@ -1587,6 +1669,40 @@ var init_auth_service = __esm({
1587
1669
  SESSION_TOKEN_EXPIRY = 7 * 24 * 60 * 60;
1588
1670
  }
1589
1671
  });
1672
+
1673
+ // ../emulator/dist/services/cache-service.js
1674
+ function createCacheHandlers(db) {
1675
+ const getHandler = async (c) => {
1676
+ const body = await c.req.json();
1677
+ const { cacheName, key } = body;
1678
+ const now = Math.floor(Date.now() / 1e3);
1679
+ const row = db.prepare(`SELECT value FROM cache_entries WHERE cache_name = ? AND key = ? AND expires_at > ?`).get(cacheName, key, now);
1680
+ return c.json({ value: row?.value ?? null });
1681
+ };
1682
+ const setHandler = async (c) => {
1683
+ const body = await c.req.json();
1684
+ const { cacheName, key, value, ttl } = body;
1685
+ const now = Math.floor(Date.now() / 1e3);
1686
+ const expiresAt = now + ttl;
1687
+ db.prepare(`INSERT OR REPLACE INTO cache_entries (cache_name, key, value, expires_at) VALUES (?, ?, ?, ?)`).run(cacheName, key, value, expiresAt);
1688
+ return c.json({ success: true });
1689
+ };
1690
+ const deleteHandler = async (c) => {
1691
+ const body = await c.req.json();
1692
+ const { cacheName, key } = body;
1693
+ db.prepare(`DELETE FROM cache_entries WHERE cache_name = ? AND key = ?`).run(cacheName, key);
1694
+ return c.json({ success: true });
1695
+ };
1696
+ return {
1697
+ getHandler,
1698
+ setHandler,
1699
+ deleteHandler
1700
+ };
1701
+ }
1702
+ var init_cache_service = __esm({
1703
+ "../emulator/dist/services/cache-service.js"() {
1704
+ }
1705
+ });
1590
1706
  function findDashboardDistPath() {
1591
1707
  const possiblePaths = [
1592
1708
  join(__dirname, "dashboard-dist"),
@@ -1614,6 +1730,7 @@ function createDashboardRoutes(app, dbManager2, config) {
1614
1730
  return c.json({
1615
1731
  db: config.db,
1616
1732
  queue: config.queue,
1733
+ cache: config.cache,
1617
1734
  workflow: config.workflow,
1618
1735
  auth: config.auth
1619
1736
  });
@@ -1954,6 +2071,39 @@ function createDashboardRoutes(app, dbManager2, config) {
1954
2071
  return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
1955
2072
  }
1956
2073
  });
2074
+ app.get("/api/cache/:binding/entries", (c) => {
2075
+ const binding = c.req.param("binding");
2076
+ const cacheName = config.cache?.[binding];
2077
+ const limit = parseInt(c.req.query("limit") || "20", 10);
2078
+ const offset = parseInt(c.req.query("offset") || "0", 10);
2079
+ const now = Math.floor(Date.now() / 1e3);
2080
+ if (!cacheName) {
2081
+ return c.json({ error: "Cache binding not found" }, 404);
2082
+ }
2083
+ try {
2084
+ const db = dbManager2.emulatorDb;
2085
+ const total = db.prepare(`SELECT COUNT(*) as count FROM cache_entries
2086
+ WHERE cache_name = ? AND expires_at > ?`).get(cacheName, now).count;
2087
+ const entries = db.prepare(`SELECT key, value, expires_at
2088
+ FROM cache_entries
2089
+ WHERE cache_name = ? AND expires_at > ?
2090
+ ORDER BY key ASC
2091
+ LIMIT ? OFFSET ?`).all(cacheName, now, limit, offset);
2092
+ return c.json({
2093
+ entries: entries.map((e) => ({
2094
+ key: e.key,
2095
+ value: e.value,
2096
+ ttlSeconds: Math.max(0, e.expires_at - now),
2097
+ expiresAt: new Date(e.expires_at * 1e3).toISOString()
2098
+ })),
2099
+ total,
2100
+ limit,
2101
+ offset
2102
+ });
2103
+ } catch (err) {
2104
+ return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
2105
+ }
2106
+ });
1957
2107
  app.get("/api/workflow/:binding/executions", (c) => {
1958
2108
  const binding = c.req.param("binding");
1959
2109
  const workflowConfig = config.workflow?.[binding];
@@ -2583,6 +2733,12 @@ async function startMockServer(dbManager2, config, options = {}) {
2583
2733
  app.post("/workflow/complete", workflowHandlers.completeHandler);
2584
2734
  app.post("/workflow/fail", workflowHandlers.failHandler);
2585
2735
  }
2736
+ if (config.cache) {
2737
+ const cacheHandlers = createCacheHandlers(dbManager2.emulatorDb);
2738
+ app.post("/cache/get", cacheHandlers.getHandler);
2739
+ app.post("/cache/set", cacheHandlers.setHandler);
2740
+ app.post("/cache/delete", cacheHandlers.deleteHandler);
2741
+ }
2586
2742
  if (config.auth) {
2587
2743
  const authHandlers = createAuthHandlers(dbManager2.emulatorDb);
2588
2744
  app.post("/auth/signup", authHandlers.signupHandler);
@@ -2613,6 +2769,7 @@ var DEFAULT_MOCK_SERVER_PORT;
2613
2769
  var init_mock_server = __esm({
2614
2770
  "../emulator/dist/services/mock-server.js"() {
2615
2771
  init_auth_service();
2772
+ init_cache_service();
2616
2773
  init_dashboard_routes();
2617
2774
  init_db_service();
2618
2775
  init_queue_service();
@@ -2772,6 +2929,15 @@ CREATE TABLE IF NOT EXISTS auth_settings (
2772
2929
 
2773
2930
  -- Insert default settings if not exists
2774
2931
  INSERT OR IGNORE INTO auth_settings (id) VALUES (1);
2932
+
2933
+ -- Cache entries table
2934
+ CREATE TABLE IF NOT EXISTS cache_entries (
2935
+ cache_name TEXT NOT NULL,
2936
+ key TEXT NOT NULL,
2937
+ value TEXT NOT NULL,
2938
+ expires_at INTEGER NOT NULL,
2939
+ PRIMARY KEY (cache_name, key)
2940
+ );
2775
2941
  `;
2776
2942
  }
2777
2943
  });
@@ -2872,6 +3038,9 @@ var init_emulator = __esm({
2872
3038
  if (this.config.queue) {
2873
3039
  log(` Queue bindings: ${Object.keys(this.config.queue).join(", ")}`);
2874
3040
  }
3041
+ if (this.config.cache) {
3042
+ log(` Cache bindings: ${Object.keys(this.config.cache).join(", ")}`);
3043
+ }
2875
3044
  if (this.config.workflow) {
2876
3045
  log(` Workflow bindings: ${Object.keys(this.config.workflow).join(", ")}`);
2877
3046
  }
@@ -4856,6 +5025,12 @@ function generateEnvType(config) {
4856
5025
  properties.push(` ${bindingName}: QueueBinding;`);
4857
5026
  }
4858
5027
  }
5028
+ if (config.cache) {
5029
+ imports.push("CacheBinding");
5030
+ for (const bindingName of Object.keys(config.cache)) {
5031
+ properties.push(` ${bindingName}: CacheBinding;`);
5032
+ }
5033
+ }
4859
5034
  if (config.workflow) {
4860
5035
  imports.push("WorkflowBinding");
4861
5036
  for (const bindingName of Object.keys(config.workflow)) {
@@ -4903,7 +5078,7 @@ async function typesCommand(options = {}) {
4903
5078
  console.error("Error: ploy.yaml not found in current directory");
4904
5079
  process.exit(1);
4905
5080
  }
4906
- const hasBindings2 = config.ai || config.db || config.queue || config.workflow;
5081
+ const hasBindings2 = config.ai || config.db || config.queue || config.cache || config.workflow;
4907
5082
  if (!hasBindings2) {
4908
5083
  console.log("No bindings found in ploy.yaml. Generating empty Env.");
4909
5084
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meetploy/cli",
3
- "version": "1.12.2",
3
+ "version": "1.13.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",