@meetploy/cli 1.13.0 → 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 +78 -2
- package/dist/index.js +176 -19
- package/package.json +1 -1
- package/dist/dashboard-dist/assets/main-Bj2g1WCI.js +0 -324
- package/dist/dashboard-dist/assets/main-q4PKg1PN.css +0 -1
package/dist/index.js
CHANGED
|
@@ -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)`);
|
|
@@ -197,6 +194,7 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
|
|
|
197
194
|
validateBindings(config.db, "db", configFile);
|
|
198
195
|
validateBindings(config.queue, "queue", configFile);
|
|
199
196
|
validateBindings(config.cache, "cache", configFile);
|
|
197
|
+
validateBindings(config.state, "state", configFile);
|
|
200
198
|
validateBindings(config.workflow, "workflow", configFile);
|
|
201
199
|
if (config.ai !== void 0 && typeof config.ai !== "boolean") {
|
|
202
200
|
throw new Error(`'ai' in ${configFile} must be a boolean`);
|
|
@@ -223,9 +221,6 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
|
|
|
223
221
|
}
|
|
224
222
|
}
|
|
225
223
|
if (config.auth !== void 0) {
|
|
226
|
-
if (typeof config.auth !== "object" || config.auth === null) {
|
|
227
|
-
throw new Error(`'auth' in ${configFile} must be an object`);
|
|
228
|
-
}
|
|
229
224
|
if (!config.auth.binding) {
|
|
230
225
|
throw new Error(`'auth.binding' is required in ${configFile} when auth is configured`);
|
|
231
226
|
}
|
|
@@ -239,7 +234,7 @@ function validatePloyConfig(config, configFile = "ploy.yaml", options = {}) {
|
|
|
239
234
|
return validatedConfig;
|
|
240
235
|
}
|
|
241
236
|
async function readPloyConfig(projectDir, configPath) {
|
|
242
|
-
const configFile = configPath
|
|
237
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
243
238
|
const fullPath = join(projectDir, configFile);
|
|
244
239
|
try {
|
|
245
240
|
const content = await readFileAsync(fullPath, "utf-8");
|
|
@@ -254,7 +249,7 @@ async function readPloyConfig(projectDir, configPath) {
|
|
|
254
249
|
}
|
|
255
250
|
}
|
|
256
251
|
function readPloyConfigSync(projectDir, configPath) {
|
|
257
|
-
const configFile = configPath
|
|
252
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
258
253
|
const fullPath = join(projectDir, configFile);
|
|
259
254
|
if (!existsSync(fullPath)) {
|
|
260
255
|
throw new Error(`Config file not found: ${fullPath}`);
|
|
@@ -263,7 +258,7 @@ function readPloyConfigSync(projectDir, configPath) {
|
|
|
263
258
|
return parse(content);
|
|
264
259
|
}
|
|
265
260
|
async function readAndValidatePloyConfig(projectDir, configPath, validationOptions) {
|
|
266
|
-
const configFile = configPath
|
|
261
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
267
262
|
const config = await readPloyConfig(projectDir, configPath);
|
|
268
263
|
if (!config) {
|
|
269
264
|
return null;
|
|
@@ -271,12 +266,12 @@ async function readAndValidatePloyConfig(projectDir, configPath, validationOptio
|
|
|
271
266
|
return validatePloyConfig(config, configFile, validationOptions);
|
|
272
267
|
}
|
|
273
268
|
function readAndValidatePloyConfigSync(projectDir, configPath, validationOptions) {
|
|
274
|
-
const configFile = configPath
|
|
269
|
+
const configFile = configPath ?? "ploy.yaml";
|
|
275
270
|
const config = readPloyConfigSync(projectDir, configPath);
|
|
276
271
|
return validatePloyConfig(config, configFile, validationOptions);
|
|
277
272
|
}
|
|
278
273
|
function hasBindings(config) {
|
|
279
|
-
return !!(config.db || config.queue || config.cache || config.workflow || config.ai || config.auth);
|
|
274
|
+
return !!(config.db || config.queue || config.cache || config.state || config.workflow || config.ai || config.auth);
|
|
280
275
|
}
|
|
281
276
|
function getWorkerEntryPoint(projectDir, config) {
|
|
282
277
|
if (config.main) {
|
|
@@ -777,6 +772,66 @@ export function initializeQueue<T = unknown>(queueName: string, serviceUrl: stri
|
|
|
777
772
|
}
|
|
778
773
|
});
|
|
779
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
|
+
|
|
780
835
|
// ../emulator/dist/runtime/workflow-runtime.js
|
|
781
836
|
var WORKFLOW_RUNTIME_CODE;
|
|
782
837
|
var init_workflow_runtime = __esm({
|
|
@@ -1009,6 +1064,12 @@ function generateWrapperCode(config, mockServiceUrl) {
|
|
|
1009
1064
|
bindings.push(` ${bindingName}: initializeCache("${cacheName}", "${mockServiceUrl}"),`);
|
|
1010
1065
|
}
|
|
1011
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
|
+
}
|
|
1012
1073
|
if (config.workflow) {
|
|
1013
1074
|
imports.push('import { initializeWorkflow, createStepContext, executeWorkflow } from "__ploy_workflow_runtime__";');
|
|
1014
1075
|
for (const [bindingName, workflowName] of Object.entries(config.workflow)) {
|
|
@@ -1116,6 +1177,10 @@ function createRuntimePlugin(_config) {
|
|
|
1116
1177
|
path: "__ploy_cache_runtime__",
|
|
1117
1178
|
namespace: "ploy-runtime"
|
|
1118
1179
|
}));
|
|
1180
|
+
build2.onResolve({ filter: /^__ploy_state_runtime__$/ }, () => ({
|
|
1181
|
+
path: "__ploy_state_runtime__",
|
|
1182
|
+
namespace: "ploy-runtime"
|
|
1183
|
+
}));
|
|
1119
1184
|
build2.onResolve({ filter: /^__ploy_workflow_runtime__$/ }, () => ({
|
|
1120
1185
|
path: "__ploy_workflow_runtime__",
|
|
1121
1186
|
namespace: "ploy-runtime"
|
|
@@ -1132,6 +1197,10 @@ function createRuntimePlugin(_config) {
|
|
|
1132
1197
|
contents: CACHE_RUNTIME_CODE,
|
|
1133
1198
|
loader: "ts"
|
|
1134
1199
|
}));
|
|
1200
|
+
build2.onLoad({ filter: /^__ploy_state_runtime__$/, namespace: "ploy-runtime" }, () => ({
|
|
1201
|
+
contents: STATE_RUNTIME_CODE,
|
|
1202
|
+
loader: "ts"
|
|
1203
|
+
}));
|
|
1135
1204
|
build2.onLoad({ filter: /^__ploy_workflow_runtime__$/, namespace: "ploy-runtime" }, () => ({
|
|
1136
1205
|
contents: WORKFLOW_RUNTIME_CODE,
|
|
1137
1206
|
loader: "ts"
|
|
@@ -1175,6 +1244,7 @@ var init_bundler = __esm({
|
|
|
1175
1244
|
init_cache_runtime();
|
|
1176
1245
|
init_db_runtime();
|
|
1177
1246
|
init_queue_runtime();
|
|
1247
|
+
init_state_runtime();
|
|
1178
1248
|
init_workflow_runtime();
|
|
1179
1249
|
NODE_BUILTINS = [
|
|
1180
1250
|
"assert",
|
|
@@ -1731,6 +1801,7 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
1731
1801
|
db: config.db,
|
|
1732
1802
|
queue: config.queue,
|
|
1733
1803
|
cache: config.cache,
|
|
1804
|
+
state: config.state,
|
|
1734
1805
|
workflow: config.workflow,
|
|
1735
1806
|
auth: config.auth
|
|
1736
1807
|
});
|
|
@@ -2104,6 +2175,38 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
2104
2175
|
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2105
2176
|
}
|
|
2106
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
|
+
});
|
|
2107
2210
|
app.get("/api/workflow/:binding/executions", (c) => {
|
|
2108
2211
|
const binding = c.req.param("binding");
|
|
2109
2212
|
const workflowConfig = config.workflow?.[binding];
|
|
@@ -2531,6 +2634,37 @@ var init_queue_service = __esm({
|
|
|
2531
2634
|
"../emulator/dist/services/queue-service.js"() {
|
|
2532
2635
|
}
|
|
2533
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
|
+
});
|
|
2534
2668
|
function createWorkflowHandlers(db, workerUrl) {
|
|
2535
2669
|
const triggerHandler = async (c) => {
|
|
2536
2670
|
try {
|
|
@@ -2739,6 +2873,12 @@ async function startMockServer(dbManager2, config, options = {}) {
|
|
|
2739
2873
|
app.post("/cache/set", cacheHandlers.setHandler);
|
|
2740
2874
|
app.post("/cache/delete", cacheHandlers.deleteHandler);
|
|
2741
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
|
+
}
|
|
2742
2882
|
if (config.auth) {
|
|
2743
2883
|
const authHandlers = createAuthHandlers(dbManager2.emulatorDb);
|
|
2744
2884
|
app.post("/auth/signup", authHandlers.signupHandler);
|
|
@@ -2759,7 +2899,9 @@ async function startMockServer(dbManager2, config, options = {}) {
|
|
|
2759
2899
|
resolve({
|
|
2760
2900
|
port: info.port,
|
|
2761
2901
|
close: () => new Promise((res) => {
|
|
2762
|
-
server.close(() =>
|
|
2902
|
+
server.close(() => {
|
|
2903
|
+
res();
|
|
2904
|
+
});
|
|
2763
2905
|
})
|
|
2764
2906
|
});
|
|
2765
2907
|
});
|
|
@@ -2773,6 +2915,7 @@ var init_mock_server = __esm({
|
|
|
2773
2915
|
init_dashboard_routes();
|
|
2774
2916
|
init_db_service();
|
|
2775
2917
|
init_queue_service();
|
|
2918
|
+
init_state_service();
|
|
2776
2919
|
init_workflow_service();
|
|
2777
2920
|
DEFAULT_MOCK_SERVER_PORT = 4003;
|
|
2778
2921
|
}
|
|
@@ -2938,6 +3081,14 @@ CREATE TABLE IF NOT EXISTS cache_entries (
|
|
|
2938
3081
|
expires_at INTEGER NOT NULL,
|
|
2939
3082
|
PRIMARY KEY (cache_name, key)
|
|
2940
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
|
+
);
|
|
2941
3092
|
`;
|
|
2942
3093
|
}
|
|
2943
3094
|
});
|
|
@@ -3071,7 +3222,7 @@ var init_emulator = __esm({
|
|
|
3071
3222
|
const workerdBin = this.findWorkerdBinary();
|
|
3072
3223
|
log(`[ploy] Using workerd binary: ${workerdBin}`);
|
|
3073
3224
|
debug(`Starting workerd: ${workerdBin} ${args2.join(" ")}`, this.options.verbose);
|
|
3074
|
-
|
|
3225
|
+
await new Promise((resolve, reject) => {
|
|
3075
3226
|
const workerdBinDir = dirname(workerdBin);
|
|
3076
3227
|
this.workerdProcess = spawn(workerdBin, args2, {
|
|
3077
3228
|
cwd: this.tempDir,
|
|
@@ -3091,7 +3242,7 @@ var init_emulator = __esm({
|
|
|
3091
3242
|
}
|
|
3092
3243
|
if (!started && (output.includes("Listening") || output.includes("running"))) {
|
|
3093
3244
|
started = true;
|
|
3094
|
-
resolve();
|
|
3245
|
+
resolve(void 0);
|
|
3095
3246
|
}
|
|
3096
3247
|
});
|
|
3097
3248
|
this.workerdProcess.stderr?.on("data", (data) => {
|
|
@@ -3105,7 +3256,7 @@ var init_emulator = __esm({
|
|
|
3105
3256
|
}
|
|
3106
3257
|
if (!started && output.includes("Listening")) {
|
|
3107
3258
|
started = true;
|
|
3108
|
-
resolve();
|
|
3259
|
+
resolve(void 0);
|
|
3109
3260
|
}
|
|
3110
3261
|
});
|
|
3111
3262
|
this.workerdProcess.on("error", (err) => {
|
|
@@ -3128,7 +3279,7 @@ var init_emulator = __esm({
|
|
|
3128
3279
|
setTimeout(() => {
|
|
3129
3280
|
if (!started) {
|
|
3130
3281
|
started = true;
|
|
3131
|
-
resolve();
|
|
3282
|
+
resolve(void 0);
|
|
3132
3283
|
}
|
|
3133
3284
|
}, 2e3);
|
|
3134
3285
|
});
|
|
@@ -4685,7 +4836,7 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4685
4836
|
</html>
|
|
4686
4837
|
`);
|
|
4687
4838
|
server?.close();
|
|
4688
|
-
reject(err);
|
|
4839
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4689
4840
|
}
|
|
4690
4841
|
});
|
|
4691
4842
|
server.on("error", (err) => {
|
|
@@ -5031,6 +5182,12 @@ function generateEnvType(config) {
|
|
|
5031
5182
|
properties.push(` ${bindingName}: CacheBinding;`);
|
|
5032
5183
|
}
|
|
5033
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
|
+
}
|
|
5034
5191
|
if (config.workflow) {
|
|
5035
5192
|
imports.push("WorkflowBinding");
|
|
5036
5193
|
for (const bindingName of Object.keys(config.workflow)) {
|
|
@@ -5078,7 +5235,7 @@ async function typesCommand(options = {}) {
|
|
|
5078
5235
|
console.error("Error: ploy.yaml not found in current directory");
|
|
5079
5236
|
process.exit(1);
|
|
5080
5237
|
}
|
|
5081
|
-
const hasBindings2 = config.ai || config.db || config.queue || config.cache || config.workflow;
|
|
5238
|
+
const hasBindings2 = config.ai || config.db || config.queue || config.cache || config.state || config.workflow;
|
|
5082
5239
|
if (!hasBindings2) {
|
|
5083
5240
|
console.log("No bindings found in ploy.yaml. Generating empty Env.");
|
|
5084
5241
|
}
|