@meetploy/cli 1.12.2 → 1.14.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/dashboard-dist/assets/main-BhNa7Fn7.js +334 -0
- package/dist/dashboard-dist/assets/main-oiFVz50x.js +334 -0
- package/dist/dashboard-dist/assets/main-qA3kxECS.css +1 -0
- package/dist/dashboard-dist/index.html +2 -2
- package/dist/dev.js +157 -2
- package/dist/index.js +371 -39
- package/package.json +1 -1
- package/dist/dashboard-dist/assets/main-BnI0iIIW.css +0 -1
- package/dist/dashboard-dist/assets/main-DnrX4BgS.js +0 -319
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';
|
|
@@ -137,15 +137,12 @@ function getCompatibilityFlags(config) {
|
|
|
137
137
|
return [...new Set(allFlags)];
|
|
138
138
|
}
|
|
139
139
|
function getCompatibilityDate(config) {
|
|
140
|
-
return config.compatibility_date
|
|
140
|
+
return config.compatibility_date ?? DEFAULT_COMPATIBILITY_DATE;
|
|
141
141
|
}
|
|
142
142
|
function validateBindings(bindings, bindingType, configFile) {
|
|
143
143
|
if (bindings === void 0) {
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
|
-
if (typeof bindings !== "object" || bindings === null) {
|
|
147
|
-
throw new Error(`'${bindingType}' in ${configFile} must be an object`);
|
|
148
|
-
}
|
|
149
146
|
for (const [bindingName, resourceName] of Object.entries(bindings)) {
|
|
150
147
|
if (!BINDING_NAME_REGEX.test(bindingName)) {
|
|
151
148
|
throw new Error(`Invalid ${bindingType} binding name '${bindingName}' in ${configFile}. Binding names must be uppercase with underscores (e.g., DB, USERS_DB)`);
|
|
@@ -196,6 +193,8 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
|
|
|
196
193
|
validatedConfig.main = validateRelativePath(config.main, "main", configFile);
|
|
197
194
|
validateBindings(config.db, "db", configFile);
|
|
198
195
|
validateBindings(config.queue, "queue", configFile);
|
|
196
|
+
validateBindings(config.cache, "cache", configFile);
|
|
197
|
+
validateBindings(config.state, "state", configFile);
|
|
199
198
|
validateBindings(config.workflow, "workflow", configFile);
|
|
200
199
|
if (config.ai !== void 0 && typeof config.ai !== "boolean") {
|
|
201
200
|
throw new Error(`'ai' in ${configFile} must be a boolean`);
|
|
@@ -222,9 +221,6 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
|
|
|
222
221
|
}
|
|
223
222
|
}
|
|
224
223
|
if (config.auth !== void 0) {
|
|
225
|
-
if (typeof config.auth !== "object" || config.auth === null) {
|
|
226
|
-
throw new Error(`'auth' in ${configFile} must be an object`);
|
|
227
|
-
}
|
|
228
224
|
if (!config.auth.binding) {
|
|
229
225
|
throw new Error(`'auth.binding' is required in ${configFile} when auth is configured`);
|
|
230
226
|
}
|
|
@@ -238,7 +234,7 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
|
|
|
238
234
|
return validatedConfig;
|
|
239
235
|
}
|
|
240
236
|
async function readPloyConfig(projectDir, configPath) {
|
|
241
|
-
const configFile = configPath
|
|
237
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
242
238
|
const fullPath = join(projectDir, configFile);
|
|
243
239
|
try {
|
|
244
240
|
const content = await readFileAsync(fullPath, "utf-8");
|
|
@@ -253,7 +249,7 @@ async function readPloyConfig(projectDir, configPath) {
|
|
|
253
249
|
}
|
|
254
250
|
}
|
|
255
251
|
function readPloyConfigSync(projectDir, configPath) {
|
|
256
|
-
const configFile = configPath
|
|
252
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
257
253
|
const fullPath = join(projectDir, configFile);
|
|
258
254
|
if (!existsSync(fullPath)) {
|
|
259
255
|
throw new Error(`Config file not found: ${fullPath}`);
|
|
@@ -262,7 +258,7 @@ function readPloyConfigSync(projectDir, configPath) {
|
|
|
262
258
|
return parse(content);
|
|
263
259
|
}
|
|
264
260
|
async function readAndValidatePloyConfig(projectDir, configPath, validationOptions) {
|
|
265
|
-
const configFile = configPath
|
|
261
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
266
262
|
const config = await readPloyConfig(projectDir, configPath);
|
|
267
263
|
if (!config) {
|
|
268
264
|
return null;
|
|
@@ -270,12 +266,12 @@ async function readAndValidatePloyConfig(projectDir, configPath, validationOptio
|
|
|
270
266
|
return validatePloyConfig(config, configFile, validationOptions);
|
|
271
267
|
}
|
|
272
268
|
function readAndValidatePloyConfigSync(projectDir, configPath, validationOptions) {
|
|
273
|
-
const configFile = configPath
|
|
269
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
274
270
|
const config = readPloyConfigSync(projectDir, configPath);
|
|
275
271
|
return validatePloyConfig(config, configFile, validationOptions);
|
|
276
272
|
}
|
|
277
273
|
function hasBindings(config) {
|
|
278
|
-
return !!(config.db || config.queue || config.workflow || config.ai || config.auth);
|
|
274
|
+
return !!(config.db || config.queue || config.cache || config.state || config.workflow || config.ai || config.auth);
|
|
279
275
|
}
|
|
280
276
|
function getWorkerEntryPoint(projectDir, config) {
|
|
281
277
|
if (config.main) {
|
|
@@ -331,6 +327,66 @@ var init_cli = __esm({
|
|
|
331
327
|
}
|
|
332
328
|
});
|
|
333
329
|
|
|
330
|
+
// ../emulator/dist/runtime/cache-runtime.js
|
|
331
|
+
var CACHE_RUNTIME_CODE;
|
|
332
|
+
var init_cache_runtime = __esm({
|
|
333
|
+
"../emulator/dist/runtime/cache-runtime.js"() {
|
|
334
|
+
CACHE_RUNTIME_CODE = `
|
|
335
|
+
interface CacheBinding {
|
|
336
|
+
get: (key: string) => Promise<string | null>;
|
|
337
|
+
set: (key: string, value: string, opts: { ttl: number }) => Promise<void>;
|
|
338
|
+
delete: (key: string) => Promise<void>;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function initializeCache(cacheName: string, serviceUrl: string): CacheBinding {
|
|
342
|
+
return {
|
|
343
|
+
async get(key: string): Promise<string | null> {
|
|
344
|
+
const response = await fetch(serviceUrl + "/cache/get", {
|
|
345
|
+
method: "POST",
|
|
346
|
+
headers: { "Content-Type": "application/json" },
|
|
347
|
+
body: JSON.stringify({ cacheName, key }),
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
if (!response.ok) {
|
|
351
|
+
const errorText = await response.text();
|
|
352
|
+
throw new Error("Cache get failed: " + errorText);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const result = await response.json();
|
|
356
|
+
return result.value ?? null;
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
async set(key: string, value: string, opts: { ttl: number }): Promise<void> {
|
|
360
|
+
const response = await fetch(serviceUrl + "/cache/set", {
|
|
361
|
+
method: "POST",
|
|
362
|
+
headers: { "Content-Type": "application/json" },
|
|
363
|
+
body: JSON.stringify({ cacheName, key, value, ttl: opts.ttl }),
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
if (!response.ok) {
|
|
367
|
+
const errorText = await response.text();
|
|
368
|
+
throw new Error("Cache set failed: " + errorText);
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
|
|
372
|
+
async delete(key: string): Promise<void> {
|
|
373
|
+
const response = await fetch(serviceUrl + "/cache/delete", {
|
|
374
|
+
method: "POST",
|
|
375
|
+
headers: { "Content-Type": "application/json" },
|
|
376
|
+
body: JSON.stringify({ cacheName, key }),
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
if (!response.ok) {
|
|
380
|
+
const errorText = await response.text();
|
|
381
|
+
throw new Error("Cache delete failed: " + errorText);
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
`;
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
334
390
|
// ../shared/dist/d1-runtime.js
|
|
335
391
|
var DB_RUNTIME_CODE, DB_RUNTIME_CODE_PRODUCTION;
|
|
336
392
|
var init_d1_runtime = __esm({
|
|
@@ -716,6 +772,66 @@ export function initializeQueue<T = unknown>(queueName: string, serviceUrl: stri
|
|
|
716
772
|
}
|
|
717
773
|
});
|
|
718
774
|
|
|
775
|
+
// ../emulator/dist/runtime/state-runtime.js
|
|
776
|
+
var STATE_RUNTIME_CODE;
|
|
777
|
+
var init_state_runtime = __esm({
|
|
778
|
+
"../emulator/dist/runtime/state-runtime.js"() {
|
|
779
|
+
STATE_RUNTIME_CODE = `
|
|
780
|
+
interface StateBinding {
|
|
781
|
+
get: (key: string) => Promise<string | null>;
|
|
782
|
+
set: (key: string, value: string) => Promise<void>;
|
|
783
|
+
delete: (key: string) => Promise<void>;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
export function initializeState(stateName: string, serviceUrl: string): StateBinding {
|
|
787
|
+
return {
|
|
788
|
+
async get(key: string): Promise<string | null> {
|
|
789
|
+
const response = await fetch(serviceUrl + "/state/get", {
|
|
790
|
+
method: "POST",
|
|
791
|
+
headers: { "Content-Type": "application/json" },
|
|
792
|
+
body: JSON.stringify({ stateName, key }),
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
if (!response.ok) {
|
|
796
|
+
const errorText = await response.text();
|
|
797
|
+
throw new Error("State get failed: " + errorText);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const result = await response.json();
|
|
801
|
+
return result.value ?? null;
|
|
802
|
+
},
|
|
803
|
+
|
|
804
|
+
async set(key: string, value: string): Promise<void> {
|
|
805
|
+
const response = await fetch(serviceUrl + "/state/set", {
|
|
806
|
+
method: "POST",
|
|
807
|
+
headers: { "Content-Type": "application/json" },
|
|
808
|
+
body: JSON.stringify({ stateName, key, value }),
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
if (!response.ok) {
|
|
812
|
+
const errorText = await response.text();
|
|
813
|
+
throw new Error("State set failed: " + errorText);
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
|
|
817
|
+
async delete(key: string): Promise<void> {
|
|
818
|
+
const response = await fetch(serviceUrl + "/state/delete", {
|
|
819
|
+
method: "POST",
|
|
820
|
+
headers: { "Content-Type": "application/json" },
|
|
821
|
+
body: JSON.stringify({ stateName, key }),
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
if (!response.ok) {
|
|
825
|
+
const errorText = await response.text();
|
|
826
|
+
throw new Error("State delete failed: " + errorText);
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
`;
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
|
|
719
835
|
// ../emulator/dist/runtime/workflow-runtime.js
|
|
720
836
|
var WORKFLOW_RUNTIME_CODE;
|
|
721
837
|
var init_workflow_runtime = __esm({
|
|
@@ -942,6 +1058,18 @@ function generateWrapperCode(config, mockServiceUrl) {
|
|
|
942
1058
|
bindings.push(` ${bindingName}: initializeQueue("${queueName}", "${mockServiceUrl}"),`);
|
|
943
1059
|
}
|
|
944
1060
|
}
|
|
1061
|
+
if (config.cache) {
|
|
1062
|
+
imports.push('import { initializeCache } from "__ploy_cache_runtime__";');
|
|
1063
|
+
for (const [bindingName, cacheName] of Object.entries(config.cache)) {
|
|
1064
|
+
bindings.push(` ${bindingName}: initializeCache("${cacheName}", "${mockServiceUrl}"),`);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
if (config.state) {
|
|
1068
|
+
imports.push('import { initializeState } from "__ploy_state_runtime__";');
|
|
1069
|
+
for (const [bindingName, stateName] of Object.entries(config.state)) {
|
|
1070
|
+
bindings.push(` ${bindingName}: initializeState("${stateName}", "${mockServiceUrl}"),`);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
945
1073
|
if (config.workflow) {
|
|
946
1074
|
imports.push('import { initializeWorkflow, createStepContext, executeWorkflow } from "__ploy_workflow_runtime__";');
|
|
947
1075
|
for (const [bindingName, workflowName] of Object.entries(config.workflow)) {
|
|
@@ -1045,6 +1173,14 @@ function createRuntimePlugin(_config) {
|
|
|
1045
1173
|
path: "__ploy_queue_runtime__",
|
|
1046
1174
|
namespace: "ploy-runtime"
|
|
1047
1175
|
}));
|
|
1176
|
+
build2.onResolve({ filter: /^__ploy_cache_runtime__$/ }, () => ({
|
|
1177
|
+
path: "__ploy_cache_runtime__",
|
|
1178
|
+
namespace: "ploy-runtime"
|
|
1179
|
+
}));
|
|
1180
|
+
build2.onResolve({ filter: /^__ploy_state_runtime__$/ }, () => ({
|
|
1181
|
+
path: "__ploy_state_runtime__",
|
|
1182
|
+
namespace: "ploy-runtime"
|
|
1183
|
+
}));
|
|
1048
1184
|
build2.onResolve({ filter: /^__ploy_workflow_runtime__$/ }, () => ({
|
|
1049
1185
|
path: "__ploy_workflow_runtime__",
|
|
1050
1186
|
namespace: "ploy-runtime"
|
|
@@ -1057,6 +1193,14 @@ function createRuntimePlugin(_config) {
|
|
|
1057
1193
|
contents: QUEUE_RUNTIME_CODE,
|
|
1058
1194
|
loader: "ts"
|
|
1059
1195
|
}));
|
|
1196
|
+
build2.onLoad({ filter: /^__ploy_cache_runtime__$/, namespace: "ploy-runtime" }, () => ({
|
|
1197
|
+
contents: CACHE_RUNTIME_CODE,
|
|
1198
|
+
loader: "ts"
|
|
1199
|
+
}));
|
|
1200
|
+
build2.onLoad({ filter: /^__ploy_state_runtime__$/, namespace: "ploy-runtime" }, () => ({
|
|
1201
|
+
contents: STATE_RUNTIME_CODE,
|
|
1202
|
+
loader: "ts"
|
|
1203
|
+
}));
|
|
1060
1204
|
build2.onLoad({ filter: /^__ploy_workflow_runtime__$/, namespace: "ploy-runtime" }, () => ({
|
|
1061
1205
|
contents: WORKFLOW_RUNTIME_CODE,
|
|
1062
1206
|
loader: "ts"
|
|
@@ -1097,8 +1241,10 @@ async function bundleWorker(options) {
|
|
|
1097
1241
|
var NODE_BUILTINS;
|
|
1098
1242
|
var init_bundler = __esm({
|
|
1099
1243
|
"../emulator/dist/bundler/bundler.js"() {
|
|
1244
|
+
init_cache_runtime();
|
|
1100
1245
|
init_db_runtime();
|
|
1101
1246
|
init_queue_runtime();
|
|
1247
|
+
init_state_runtime();
|
|
1102
1248
|
init_workflow_runtime();
|
|
1103
1249
|
NODE_BUILTINS = [
|
|
1104
1250
|
"assert",
|
|
@@ -1156,9 +1302,6 @@ function log(message) {
|
|
|
1156
1302
|
function success(message) {
|
|
1157
1303
|
console.log(`${COLORS.dim}[${timestamp()}]${COLORS.reset} ${COLORS.green}[ploy]${COLORS.reset} ${message}`);
|
|
1158
1304
|
}
|
|
1159
|
-
function warn(message) {
|
|
1160
|
-
console.log(`${COLORS.dim}[${timestamp()}]${COLORS.reset} ${COLORS.yellow}[ploy]${COLORS.reset} ${message}`);
|
|
1161
|
-
}
|
|
1162
1305
|
function error(message) {
|
|
1163
1306
|
console.error(`${COLORS.dim}[${timestamp()}]${COLORS.reset} ${COLORS.red}[ploy]${COLORS.reset} ${message}`);
|
|
1164
1307
|
}
|
|
@@ -1181,6 +1324,22 @@ var init_logger = __esm({
|
|
|
1181
1324
|
};
|
|
1182
1325
|
}
|
|
1183
1326
|
});
|
|
1327
|
+
function isIgnored(filePath) {
|
|
1328
|
+
const name = basename(filePath);
|
|
1329
|
+
if (name.startsWith(".")) {
|
|
1330
|
+
return true;
|
|
1331
|
+
}
|
|
1332
|
+
if (IGNORED_DIRS.has(name)) {
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
if (IGNORED_FILES.has(name)) {
|
|
1336
|
+
return true;
|
|
1337
|
+
}
|
|
1338
|
+
if (name.endsWith(".log")) {
|
|
1339
|
+
return true;
|
|
1340
|
+
}
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1184
1343
|
function createFileWatcher(srcDir, onRebuild) {
|
|
1185
1344
|
let watcher = null;
|
|
1186
1345
|
let debounceTimer = null;
|
|
@@ -1213,25 +1372,11 @@ function createFileWatcher(srcDir, onRebuild) {
|
|
|
1213
1372
|
watcher = watch(srcDir, {
|
|
1214
1373
|
persistent: true,
|
|
1215
1374
|
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
|
-
]
|
|
1375
|
+
ignored: isIgnored
|
|
1228
1376
|
});
|
|
1229
1377
|
watcher.on("error", (err) => {
|
|
1230
1378
|
const error2 = err;
|
|
1231
|
-
if (error2.code
|
|
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 {
|
|
1379
|
+
if (error2.code !== "EMFILE") {
|
|
1235
1380
|
error(`File watcher error: ${error2.message || String(err)}`);
|
|
1236
1381
|
}
|
|
1237
1382
|
});
|
|
@@ -1263,9 +1408,16 @@ function createFileWatcher(srcDir, onRebuild) {
|
|
|
1263
1408
|
}
|
|
1264
1409
|
};
|
|
1265
1410
|
}
|
|
1411
|
+
var IGNORED_DIRS, IGNORED_FILES;
|
|
1266
1412
|
var init_watcher = __esm({
|
|
1267
1413
|
"../emulator/dist/bundler/watcher.js"() {
|
|
1268
1414
|
init_logger();
|
|
1415
|
+
IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage", "build"]);
|
|
1416
|
+
IGNORED_FILES = /* @__PURE__ */ new Set([
|
|
1417
|
+
"pnpm-lock.yaml",
|
|
1418
|
+
"package-lock.json",
|
|
1419
|
+
"yarn.lock"
|
|
1420
|
+
]);
|
|
1269
1421
|
}
|
|
1270
1422
|
});
|
|
1271
1423
|
|
|
@@ -1587,6 +1739,40 @@ var init_auth_service = __esm({
|
|
|
1587
1739
|
SESSION_TOKEN_EXPIRY = 7 * 24 * 60 * 60;
|
|
1588
1740
|
}
|
|
1589
1741
|
});
|
|
1742
|
+
|
|
1743
|
+
// ../emulator/dist/services/cache-service.js
|
|
1744
|
+
function createCacheHandlers(db) {
|
|
1745
|
+
const getHandler = async (c) => {
|
|
1746
|
+
const body = await c.req.json();
|
|
1747
|
+
const { cacheName, key } = body;
|
|
1748
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1749
|
+
const row = db.prepare(`SELECT value FROM cache_entries WHERE cache_name = ? AND key = ? AND expires_at > ?`).get(cacheName, key, now);
|
|
1750
|
+
return c.json({ value: row?.value ?? null });
|
|
1751
|
+
};
|
|
1752
|
+
const setHandler = async (c) => {
|
|
1753
|
+
const body = await c.req.json();
|
|
1754
|
+
const { cacheName, key, value, ttl } = body;
|
|
1755
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1756
|
+
const expiresAt = now + ttl;
|
|
1757
|
+
db.prepare(`INSERT OR REPLACE INTO cache_entries (cache_name, key, value, expires_at) VALUES (?, ?, ?, ?)`).run(cacheName, key, value, expiresAt);
|
|
1758
|
+
return c.json({ success: true });
|
|
1759
|
+
};
|
|
1760
|
+
const deleteHandler = async (c) => {
|
|
1761
|
+
const body = await c.req.json();
|
|
1762
|
+
const { cacheName, key } = body;
|
|
1763
|
+
db.prepare(`DELETE FROM cache_entries WHERE cache_name = ? AND key = ?`).run(cacheName, key);
|
|
1764
|
+
return c.json({ success: true });
|
|
1765
|
+
};
|
|
1766
|
+
return {
|
|
1767
|
+
getHandler,
|
|
1768
|
+
setHandler,
|
|
1769
|
+
deleteHandler
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
var init_cache_service = __esm({
|
|
1773
|
+
"../emulator/dist/services/cache-service.js"() {
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1590
1776
|
function findDashboardDistPath() {
|
|
1591
1777
|
const possiblePaths = [
|
|
1592
1778
|
join(__dirname, "dashboard-dist"),
|
|
@@ -1614,6 +1800,8 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
1614
1800
|
return c.json({
|
|
1615
1801
|
db: config.db,
|
|
1616
1802
|
queue: config.queue,
|
|
1803
|
+
cache: config.cache,
|
|
1804
|
+
state: config.state,
|
|
1617
1805
|
workflow: config.workflow,
|
|
1618
1806
|
auth: config.auth
|
|
1619
1807
|
});
|
|
@@ -1954,6 +2142,71 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
1954
2142
|
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
1955
2143
|
}
|
|
1956
2144
|
});
|
|
2145
|
+
app.get("/api/cache/:binding/entries", (c) => {
|
|
2146
|
+
const binding = c.req.param("binding");
|
|
2147
|
+
const cacheName = config.cache?.[binding];
|
|
2148
|
+
const limit = parseInt(c.req.query("limit") || "20", 10);
|
|
2149
|
+
const offset = parseInt(c.req.query("offset") || "0", 10);
|
|
2150
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2151
|
+
if (!cacheName) {
|
|
2152
|
+
return c.json({ error: "Cache binding not found" }, 404);
|
|
2153
|
+
}
|
|
2154
|
+
try {
|
|
2155
|
+
const db = dbManager2.emulatorDb;
|
|
2156
|
+
const total = db.prepare(`SELECT COUNT(*) as count FROM cache_entries
|
|
2157
|
+
WHERE cache_name = ? AND expires_at > ?`).get(cacheName, now).count;
|
|
2158
|
+
const entries = db.prepare(`SELECT key, value, expires_at
|
|
2159
|
+
FROM cache_entries
|
|
2160
|
+
WHERE cache_name = ? AND expires_at > ?
|
|
2161
|
+
ORDER BY key ASC
|
|
2162
|
+
LIMIT ? OFFSET ?`).all(cacheName, now, limit, offset);
|
|
2163
|
+
return c.json({
|
|
2164
|
+
entries: entries.map((e) => ({
|
|
2165
|
+
key: e.key,
|
|
2166
|
+
value: e.value,
|
|
2167
|
+
ttlSeconds: Math.max(0, e.expires_at - now),
|
|
2168
|
+
expiresAt: new Date(e.expires_at * 1e3).toISOString()
|
|
2169
|
+
})),
|
|
2170
|
+
total,
|
|
2171
|
+
limit,
|
|
2172
|
+
offset
|
|
2173
|
+
});
|
|
2174
|
+
} catch (err) {
|
|
2175
|
+
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2176
|
+
}
|
|
2177
|
+
});
|
|
2178
|
+
app.get("/api/state/:binding/entries", (c) => {
|
|
2179
|
+
const binding = c.req.param("binding");
|
|
2180
|
+
const stateName = config.state?.[binding];
|
|
2181
|
+
const limit = parseInt(c.req.query("limit") || "20", 10);
|
|
2182
|
+
const offset = parseInt(c.req.query("offset") || "0", 10);
|
|
2183
|
+
const search = c.req.query("search") || "";
|
|
2184
|
+
if (!stateName) {
|
|
2185
|
+
return c.json({ error: "State binding not found" }, 404);
|
|
2186
|
+
}
|
|
2187
|
+
try {
|
|
2188
|
+
const db = dbManager2.emulatorDb;
|
|
2189
|
+
const fetchLimit = limit + 1;
|
|
2190
|
+
const entries = search ? db.prepare(`SELECT key, value
|
|
2191
|
+
FROM state_entries
|
|
2192
|
+
WHERE state_name = ? AND key LIKE ?
|
|
2193
|
+
ORDER BY key ASC
|
|
2194
|
+
LIMIT ? OFFSET ?`).all(stateName, `%${search}%`, fetchLimit, offset) : db.prepare(`SELECT key, value
|
|
2195
|
+
FROM state_entries
|
|
2196
|
+
WHERE state_name = ?
|
|
2197
|
+
ORDER BY key ASC
|
|
2198
|
+
LIMIT ? OFFSET ?`).all(stateName, fetchLimit, offset);
|
|
2199
|
+
const hasMore = entries.length > limit;
|
|
2200
|
+
return c.json({
|
|
2201
|
+
entries: entries.slice(0, limit),
|
|
2202
|
+
hasMore,
|
|
2203
|
+
limit,
|
|
2204
|
+
offset
|
|
2205
|
+
});
|
|
2206
|
+
} catch (err) {
|
|
2207
|
+
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
1957
2210
|
app.get("/api/workflow/:binding/executions", (c) => {
|
|
1958
2211
|
const binding = c.req.param("binding");
|
|
1959
2212
|
const workflowConfig = config.workflow?.[binding];
|
|
@@ -2381,6 +2634,37 @@ var init_queue_service = __esm({
|
|
|
2381
2634
|
"../emulator/dist/services/queue-service.js"() {
|
|
2382
2635
|
}
|
|
2383
2636
|
});
|
|
2637
|
+
|
|
2638
|
+
// ../emulator/dist/services/state-service.js
|
|
2639
|
+
function createStateHandlers(db) {
|
|
2640
|
+
const getHandler = async (c) => {
|
|
2641
|
+
const body = await c.req.json();
|
|
2642
|
+
const { stateName, key } = body;
|
|
2643
|
+
const row = db.prepare(`SELECT value FROM state_entries WHERE state_name = ? AND key = ?`).get(stateName, key);
|
|
2644
|
+
return c.json({ value: row?.value ?? null });
|
|
2645
|
+
};
|
|
2646
|
+
const setHandler = async (c) => {
|
|
2647
|
+
const body = await c.req.json();
|
|
2648
|
+
const { stateName, key, value } = body;
|
|
2649
|
+
db.prepare(`INSERT OR REPLACE INTO state_entries (state_name, key, value) VALUES (?, ?, ?)`).run(stateName, key, value);
|
|
2650
|
+
return c.json({ success: true });
|
|
2651
|
+
};
|
|
2652
|
+
const deleteHandler = async (c) => {
|
|
2653
|
+
const body = await c.req.json();
|
|
2654
|
+
const { stateName, key } = body;
|
|
2655
|
+
db.prepare(`DELETE FROM state_entries WHERE state_name = ? AND key = ?`).run(stateName, key);
|
|
2656
|
+
return c.json({ success: true });
|
|
2657
|
+
};
|
|
2658
|
+
return {
|
|
2659
|
+
getHandler,
|
|
2660
|
+
setHandler,
|
|
2661
|
+
deleteHandler
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
var init_state_service = __esm({
|
|
2665
|
+
"../emulator/dist/services/state-service.js"() {
|
|
2666
|
+
}
|
|
2667
|
+
});
|
|
2384
2668
|
function createWorkflowHandlers(db, workerUrl) {
|
|
2385
2669
|
const triggerHandler = async (c) => {
|
|
2386
2670
|
try {
|
|
@@ -2583,6 +2867,18 @@ async function startMockServer(dbManager2, config, options = {}) {
|
|
|
2583
2867
|
app.post("/workflow/complete", workflowHandlers.completeHandler);
|
|
2584
2868
|
app.post("/workflow/fail", workflowHandlers.failHandler);
|
|
2585
2869
|
}
|
|
2870
|
+
if (config.cache) {
|
|
2871
|
+
const cacheHandlers = createCacheHandlers(dbManager2.emulatorDb);
|
|
2872
|
+
app.post("/cache/get", cacheHandlers.getHandler);
|
|
2873
|
+
app.post("/cache/set", cacheHandlers.setHandler);
|
|
2874
|
+
app.post("/cache/delete", cacheHandlers.deleteHandler);
|
|
2875
|
+
}
|
|
2876
|
+
if (config.state) {
|
|
2877
|
+
const stateHandlers = createStateHandlers(dbManager2.emulatorDb);
|
|
2878
|
+
app.post("/state/get", stateHandlers.getHandler);
|
|
2879
|
+
app.post("/state/set", stateHandlers.setHandler);
|
|
2880
|
+
app.post("/state/delete", stateHandlers.deleteHandler);
|
|
2881
|
+
}
|
|
2586
2882
|
if (config.auth) {
|
|
2587
2883
|
const authHandlers = createAuthHandlers(dbManager2.emulatorDb);
|
|
2588
2884
|
app.post("/auth/signup", authHandlers.signupHandler);
|
|
@@ -2603,7 +2899,9 @@ async function startMockServer(dbManager2, config, options = {}) {
|
|
|
2603
2899
|
resolve({
|
|
2604
2900
|
port: info.port,
|
|
2605
2901
|
close: () => new Promise((res) => {
|
|
2606
|
-
server.close(() =>
|
|
2902
|
+
server.close(() => {
|
|
2903
|
+
res();
|
|
2904
|
+
});
|
|
2607
2905
|
})
|
|
2608
2906
|
});
|
|
2609
2907
|
});
|
|
@@ -2613,9 +2911,11 @@ var DEFAULT_MOCK_SERVER_PORT;
|
|
|
2613
2911
|
var init_mock_server = __esm({
|
|
2614
2912
|
"../emulator/dist/services/mock-server.js"() {
|
|
2615
2913
|
init_auth_service();
|
|
2914
|
+
init_cache_service();
|
|
2616
2915
|
init_dashboard_routes();
|
|
2617
2916
|
init_db_service();
|
|
2618
2917
|
init_queue_service();
|
|
2918
|
+
init_state_service();
|
|
2619
2919
|
init_workflow_service();
|
|
2620
2920
|
DEFAULT_MOCK_SERVER_PORT = 4003;
|
|
2621
2921
|
}
|
|
@@ -2772,6 +3072,23 @@ CREATE TABLE IF NOT EXISTS auth_settings (
|
|
|
2772
3072
|
|
|
2773
3073
|
-- Insert default settings if not exists
|
|
2774
3074
|
INSERT OR IGNORE INTO auth_settings (id) VALUES (1);
|
|
3075
|
+
|
|
3076
|
+
-- Cache entries table
|
|
3077
|
+
CREATE TABLE IF NOT EXISTS cache_entries (
|
|
3078
|
+
cache_name TEXT NOT NULL,
|
|
3079
|
+
key TEXT NOT NULL,
|
|
3080
|
+
value TEXT NOT NULL,
|
|
3081
|
+
expires_at INTEGER NOT NULL,
|
|
3082
|
+
PRIMARY KEY (cache_name, key)
|
|
3083
|
+
);
|
|
3084
|
+
|
|
3085
|
+
-- State entries table (durable key-value store, no expiry)
|
|
3086
|
+
CREATE TABLE IF NOT EXISTS state_entries (
|
|
3087
|
+
state_name TEXT NOT NULL,
|
|
3088
|
+
key TEXT NOT NULL,
|
|
3089
|
+
value TEXT NOT NULL,
|
|
3090
|
+
PRIMARY KEY (state_name, key)
|
|
3091
|
+
);
|
|
2775
3092
|
`;
|
|
2776
3093
|
}
|
|
2777
3094
|
});
|
|
@@ -2872,6 +3189,9 @@ var init_emulator = __esm({
|
|
|
2872
3189
|
if (this.config.queue) {
|
|
2873
3190
|
log(` Queue bindings: ${Object.keys(this.config.queue).join(", ")}`);
|
|
2874
3191
|
}
|
|
3192
|
+
if (this.config.cache) {
|
|
3193
|
+
log(` Cache bindings: ${Object.keys(this.config.cache).join(", ")}`);
|
|
3194
|
+
}
|
|
2875
3195
|
if (this.config.workflow) {
|
|
2876
3196
|
log(` Workflow bindings: ${Object.keys(this.config.workflow).join(", ")}`);
|
|
2877
3197
|
}
|
|
@@ -2902,7 +3222,7 @@ var init_emulator = __esm({
|
|
|
2902
3222
|
const workerdBin = this.findWorkerdBinary();
|
|
2903
3223
|
log(`[ploy] Using workerd binary: ${workerdBin}`);
|
|
2904
3224
|
debug(`Starting workerd: ${workerdBin} ${args2.join(" ")}`, this.options.verbose);
|
|
2905
|
-
|
|
3225
|
+
await new Promise((resolve, reject) => {
|
|
2906
3226
|
const workerdBinDir = dirname(workerdBin);
|
|
2907
3227
|
this.workerdProcess = spawn(workerdBin, args2, {
|
|
2908
3228
|
cwd: this.tempDir,
|
|
@@ -2922,7 +3242,7 @@ var init_emulator = __esm({
|
|
|
2922
3242
|
}
|
|
2923
3243
|
if (!started && (output.includes("Listening") || output.includes("running"))) {
|
|
2924
3244
|
started = true;
|
|
2925
|
-
resolve();
|
|
3245
|
+
resolve(void 0);
|
|
2926
3246
|
}
|
|
2927
3247
|
});
|
|
2928
3248
|
this.workerdProcess.stderr?.on("data", (data) => {
|
|
@@ -2936,7 +3256,7 @@ var init_emulator = __esm({
|
|
|
2936
3256
|
}
|
|
2937
3257
|
if (!started && output.includes("Listening")) {
|
|
2938
3258
|
started = true;
|
|
2939
|
-
resolve();
|
|
3259
|
+
resolve(void 0);
|
|
2940
3260
|
}
|
|
2941
3261
|
});
|
|
2942
3262
|
this.workerdProcess.on("error", (err) => {
|
|
@@ -2959,7 +3279,7 @@ var init_emulator = __esm({
|
|
|
2959
3279
|
setTimeout(() => {
|
|
2960
3280
|
if (!started) {
|
|
2961
3281
|
started = true;
|
|
2962
|
-
resolve();
|
|
3282
|
+
resolve(void 0);
|
|
2963
3283
|
}
|
|
2964
3284
|
}, 2e3);
|
|
2965
3285
|
});
|
|
@@ -4516,7 +4836,7 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4516
4836
|
</html>
|
|
4517
4837
|
`);
|
|
4518
4838
|
server?.close();
|
|
4519
|
-
reject(err);
|
|
4839
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4520
4840
|
}
|
|
4521
4841
|
});
|
|
4522
4842
|
server.on("error", (err) => {
|
|
@@ -4856,6 +5176,18 @@ function generateEnvType(config) {
|
|
|
4856
5176
|
properties.push(` ${bindingName}: QueueBinding;`);
|
|
4857
5177
|
}
|
|
4858
5178
|
}
|
|
5179
|
+
if (config.cache) {
|
|
5180
|
+
imports.push("CacheBinding");
|
|
5181
|
+
for (const bindingName of Object.keys(config.cache)) {
|
|
5182
|
+
properties.push(` ${bindingName}: CacheBinding;`);
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
if (config.state) {
|
|
5186
|
+
imports.push("StateBinding");
|
|
5187
|
+
for (const bindingName of Object.keys(config.state)) {
|
|
5188
|
+
properties.push(` ${bindingName}: StateBinding;`);
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
4859
5191
|
if (config.workflow) {
|
|
4860
5192
|
imports.push("WorkflowBinding");
|
|
4861
5193
|
for (const bindingName of Object.keys(config.workflow)) {
|
|
@@ -4903,7 +5235,7 @@ async function typesCommand(options = {}) {
|
|
|
4903
5235
|
console.error("Error: ploy.yaml not found in current directory");
|
|
4904
5236
|
process.exit(1);
|
|
4905
5237
|
}
|
|
4906
|
-
const hasBindings2 = config.ai || config.db || config.queue || config.workflow;
|
|
5238
|
+
const hasBindings2 = config.ai || config.db || config.queue || config.cache || config.state || config.workflow;
|
|
4907
5239
|
if (!hasBindings2) {
|
|
4908
5240
|
console.log("No bindings found in ploy.yaml. Generating empty Env.");
|
|
4909
5241
|
}
|