@cloudwerk/cli 0.11.0 → 0.12.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 +483 -119
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1217,97 +1217,7 @@ function getEnvConfig(config, env) {
|
|
|
1217
1217
|
}
|
|
1218
1218
|
function extractBindings(config, env) {
|
|
1219
1219
|
const envConfig = getEnvConfig(config, env);
|
|
1220
|
-
|
|
1221
|
-
if (envConfig.d1_databases) {
|
|
1222
|
-
for (const db of envConfig.d1_databases) {
|
|
1223
|
-
bindings2.push({
|
|
1224
|
-
type: "d1",
|
|
1225
|
-
name: db.binding,
|
|
1226
|
-
resourceId: db.database_id,
|
|
1227
|
-
resourceName: db.database_name
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
if (envConfig.kv_namespaces) {
|
|
1232
|
-
for (const kv of envConfig.kv_namespaces) {
|
|
1233
|
-
bindings2.push({
|
|
1234
|
-
type: "kv",
|
|
1235
|
-
name: kv.binding,
|
|
1236
|
-
resourceId: kv.id
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
if (envConfig.r2_buckets) {
|
|
1241
|
-
for (const r2 of envConfig.r2_buckets) {
|
|
1242
|
-
bindings2.push({
|
|
1243
|
-
type: "r2",
|
|
1244
|
-
name: r2.binding,
|
|
1245
|
-
resourceName: r2.bucket_name
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
if (envConfig.queues?.producers) {
|
|
1250
|
-
for (const queue of envConfig.queues.producers) {
|
|
1251
|
-
bindings2.push({
|
|
1252
|
-
type: "queue",
|
|
1253
|
-
name: queue.binding,
|
|
1254
|
-
resourceName: queue.queue
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
if (envConfig.durable_objects?.bindings) {
|
|
1259
|
-
for (const doBinding of envConfig.durable_objects.bindings) {
|
|
1260
|
-
bindings2.push({
|
|
1261
|
-
type: "do",
|
|
1262
|
-
name: doBinding.name,
|
|
1263
|
-
resourceName: doBinding.class_name,
|
|
1264
|
-
extra: doBinding.script_name ? { script_name: doBinding.script_name } : void 0
|
|
1265
|
-
});
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
if (envConfig.services) {
|
|
1269
|
-
for (const service of envConfig.services) {
|
|
1270
|
-
bindings2.push({
|
|
1271
|
-
type: "service",
|
|
1272
|
-
name: service.binding,
|
|
1273
|
-
resourceName: service.service,
|
|
1274
|
-
extra: service.environment ? { environment: service.environment } : void 0
|
|
1275
|
-
});
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
if (envConfig.vars) {
|
|
1279
|
-
for (const [name] of Object.entries(envConfig.vars)) {
|
|
1280
|
-
bindings2.push({
|
|
1281
|
-
type: "secret",
|
|
1282
|
-
name
|
|
1283
|
-
});
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
if (envConfig.ai) {
|
|
1287
|
-
bindings2.push({
|
|
1288
|
-
type: "ai",
|
|
1289
|
-
name: envConfig.ai.binding
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
if (envConfig.vectorize) {
|
|
1293
|
-
for (const vec of envConfig.vectorize) {
|
|
1294
|
-
bindings2.push({
|
|
1295
|
-
type: "vectorize",
|
|
1296
|
-
name: vec.binding,
|
|
1297
|
-
resourceName: vec.index_name
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
if (envConfig.hyperdrive) {
|
|
1302
|
-
for (const hd of envConfig.hyperdrive) {
|
|
1303
|
-
bindings2.push({
|
|
1304
|
-
type: "hyperdrive",
|
|
1305
|
-
name: hd.binding,
|
|
1306
|
-
resourceId: hd.id
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
return bindings2;
|
|
1220
|
+
return extractBindingsFromConfig(envConfig);
|
|
1311
1221
|
}
|
|
1312
1222
|
function getEnvironments(config) {
|
|
1313
1223
|
if (!config.env) {
|
|
@@ -1521,10 +1431,109 @@ function removeBinding(cwd, bindingName, env) {
|
|
|
1521
1431
|
}
|
|
1522
1432
|
return removed;
|
|
1523
1433
|
}
|
|
1434
|
+
function setAccountId(cwd, accountId) {
|
|
1435
|
+
const config = readWranglerToml(cwd);
|
|
1436
|
+
config.account_id = accountId;
|
|
1437
|
+
writeWranglerToml(cwd, config);
|
|
1438
|
+
}
|
|
1524
1439
|
function bindingExists(config, bindingName, env) {
|
|
1525
|
-
const
|
|
1440
|
+
const targetConfig = env && config.env?.[env] ? config.env[env] : config;
|
|
1441
|
+
const bindings2 = extractBindingsFromConfig(targetConfig);
|
|
1526
1442
|
return bindings2.some((b) => b.name === bindingName);
|
|
1527
1443
|
}
|
|
1444
|
+
function extractBindingsFromConfig(config) {
|
|
1445
|
+
const bindings2 = [];
|
|
1446
|
+
if (config.d1_databases) {
|
|
1447
|
+
for (const db of config.d1_databases) {
|
|
1448
|
+
bindings2.push({
|
|
1449
|
+
type: "d1",
|
|
1450
|
+
name: db.binding,
|
|
1451
|
+
resourceId: db.database_id,
|
|
1452
|
+
resourceName: db.database_name
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
if (config.kv_namespaces) {
|
|
1457
|
+
for (const kv of config.kv_namespaces) {
|
|
1458
|
+
bindings2.push({
|
|
1459
|
+
type: "kv",
|
|
1460
|
+
name: kv.binding,
|
|
1461
|
+
resourceId: kv.id
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
if (config.r2_buckets) {
|
|
1466
|
+
for (const r2 of config.r2_buckets) {
|
|
1467
|
+
bindings2.push({
|
|
1468
|
+
type: "r2",
|
|
1469
|
+
name: r2.binding,
|
|
1470
|
+
resourceName: r2.bucket_name
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
if (config.queues?.producers) {
|
|
1475
|
+
for (const queue of config.queues.producers) {
|
|
1476
|
+
bindings2.push({
|
|
1477
|
+
type: "queue",
|
|
1478
|
+
name: queue.binding,
|
|
1479
|
+
resourceName: queue.queue
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
if (config.durable_objects?.bindings) {
|
|
1484
|
+
for (const doBinding of config.durable_objects.bindings) {
|
|
1485
|
+
bindings2.push({
|
|
1486
|
+
type: "do",
|
|
1487
|
+
name: doBinding.name,
|
|
1488
|
+
resourceName: doBinding.class_name,
|
|
1489
|
+
extra: doBinding.script_name ? { script_name: doBinding.script_name } : void 0
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
if (config.services) {
|
|
1494
|
+
for (const service of config.services) {
|
|
1495
|
+
bindings2.push({
|
|
1496
|
+
type: "service",
|
|
1497
|
+
name: service.binding,
|
|
1498
|
+
resourceName: service.service,
|
|
1499
|
+
extra: service.environment ? { environment: service.environment } : void 0
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
if (config.vars) {
|
|
1504
|
+
for (const [name] of Object.entries(config.vars)) {
|
|
1505
|
+
bindings2.push({
|
|
1506
|
+
type: "secret",
|
|
1507
|
+
name
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
if (config.ai) {
|
|
1512
|
+
bindings2.push({
|
|
1513
|
+
type: "ai",
|
|
1514
|
+
name: config.ai.binding
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
if (config.vectorize) {
|
|
1518
|
+
for (const vec of config.vectorize) {
|
|
1519
|
+
bindings2.push({
|
|
1520
|
+
type: "vectorize",
|
|
1521
|
+
name: vec.binding,
|
|
1522
|
+
resourceName: vec.index_name
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (config.hyperdrive) {
|
|
1527
|
+
for (const hd of config.hyperdrive) {
|
|
1528
|
+
bindings2.push({
|
|
1529
|
+
type: "hyperdrive",
|
|
1530
|
+
name: hd.binding,
|
|
1531
|
+
resourceId: hd.id
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
return bindings2;
|
|
1536
|
+
}
|
|
1528
1537
|
function getBindingTypeName(type) {
|
|
1529
1538
|
switch (type) {
|
|
1530
1539
|
case "d1":
|
|
@@ -1826,7 +1835,7 @@ async function addD1(cwd, options) {
|
|
|
1826
1835
|
});
|
|
1827
1836
|
const databaseName = await input({
|
|
1828
1837
|
message: "Database name:",
|
|
1829
|
-
default: `${config.name || "my-app"}
|
|
1838
|
+
default: `${config.name || "my-app"}${env ? `-${env}` : ""}-db`,
|
|
1830
1839
|
validate: (value) => {
|
|
1831
1840
|
if (!value.trim()) return "Database name is required";
|
|
1832
1841
|
return true;
|
|
@@ -1963,7 +1972,7 @@ async function addR2(cwd, options) {
|
|
|
1963
1972
|
if (createNew) {
|
|
1964
1973
|
bucketName = await input({
|
|
1965
1974
|
message: "Bucket name:",
|
|
1966
|
-
default: `${config.name || "my-app"}
|
|
1975
|
+
default: `${config.name || "my-app"}${env ? `-${env}` : ""}-bucket`,
|
|
1967
1976
|
validate: (value) => {
|
|
1968
1977
|
if (!value.trim()) return "Bucket name is required";
|
|
1969
1978
|
return true;
|
|
@@ -2021,7 +2030,7 @@ async function addQueue(cwd, options) {
|
|
|
2021
2030
|
if (createNew) {
|
|
2022
2031
|
queueName = await input({
|
|
2023
2032
|
message: "Queue name:",
|
|
2024
|
-
default: `${config.name || "my-app"}
|
|
2033
|
+
default: `${config.name || "my-app"}${env ? `-${env}` : ""}-queue`,
|
|
2025
2034
|
validate: (value) => {
|
|
2026
2035
|
if (!value.trim()) return "Queue name is required";
|
|
2027
2036
|
return true;
|
|
@@ -2163,8 +2172,59 @@ function showTypeHint(bindingName, type) {
|
|
|
2163
2172
|
console.log();
|
|
2164
2173
|
console.log(pc5.dim(`TypeScript type: ${bindingName}: ${tsType}`));
|
|
2165
2174
|
}
|
|
2166
|
-
function
|
|
2167
|
-
|
|
2175
|
+
function parseAccountsFromError(errorMessage) {
|
|
2176
|
+
const accounts = [];
|
|
2177
|
+
const accountRegex = /`([^`]+)`:\s*`([a-f0-9]+)`/g;
|
|
2178
|
+
let match;
|
|
2179
|
+
while ((match = accountRegex.exec(errorMessage)) !== null) {
|
|
2180
|
+
accounts.push({
|
|
2181
|
+
name: match[1],
|
|
2182
|
+
id: match[2]
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
return accounts;
|
|
2186
|
+
}
|
|
2187
|
+
function isMultiAccountError(errorMessage) {
|
|
2188
|
+
return errorMessage.includes("More than one account available");
|
|
2189
|
+
}
|
|
2190
|
+
async function promptForAccount(accounts) {
|
|
2191
|
+
console.log();
|
|
2192
|
+
const selected = await select({
|
|
2193
|
+
message: "Multiple Cloudflare accounts available. Which account do you want to use?",
|
|
2194
|
+
choices: accounts.map((account) => ({
|
|
2195
|
+
name: `${account.name} (${account.id.slice(0, 8)}...)`,
|
|
2196
|
+
value: account.id
|
|
2197
|
+
}))
|
|
2198
|
+
});
|
|
2199
|
+
return selected;
|
|
2200
|
+
}
|
|
2201
|
+
async function handleWranglerResult(result, retryFn, cwd) {
|
|
2202
|
+
if (result.error && isMultiAccountError(result.stderr)) {
|
|
2203
|
+
const accounts = parseAccountsFromError(result.stderr);
|
|
2204
|
+
if (accounts.length > 0) {
|
|
2205
|
+
const selectedAccountId = await promptForAccount(accounts);
|
|
2206
|
+
const projectCwd = cwd || process.cwd();
|
|
2207
|
+
setAccountId(projectCwd, selectedAccountId);
|
|
2208
|
+
console.log(pc5.green("\u2713") + " Set account_id in wrangler.toml");
|
|
2209
|
+
console.log();
|
|
2210
|
+
const retryResult = await retryFn();
|
|
2211
|
+
if (retryResult.error) {
|
|
2212
|
+
throw new Error(retryResult.stderr || `wrangler exited with code ${retryResult.code}`);
|
|
2213
|
+
}
|
|
2214
|
+
return retryResult.stdout;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
if (result.error) {
|
|
2218
|
+
throw new Error(result.stderr || `wrangler exited with code ${result.code}`);
|
|
2219
|
+
}
|
|
2220
|
+
return result.stdout;
|
|
2221
|
+
}
|
|
2222
|
+
async function runWranglerCommand(args, cwd) {
|
|
2223
|
+
const result = await runWranglerCommandRaw(args);
|
|
2224
|
+
return handleWranglerResult(result, () => runWranglerCommandRaw(args), cwd);
|
|
2225
|
+
}
|
|
2226
|
+
function runWranglerCommandRaw(args) {
|
|
2227
|
+
return new Promise((resolve4) => {
|
|
2168
2228
|
let stdout = "";
|
|
2169
2229
|
let stderr = "";
|
|
2170
2230
|
const child = spawn2("npx", ["wrangler", ...args], {
|
|
@@ -2177,19 +2237,23 @@ function runWranglerCommand(args) {
|
|
|
2177
2237
|
stderr += data.toString();
|
|
2178
2238
|
});
|
|
2179
2239
|
child.on("error", (error) => {
|
|
2180
|
-
|
|
2240
|
+
resolve4({ stdout, stderr: error.message, code: null, error: true });
|
|
2181
2241
|
});
|
|
2182
2242
|
child.on("close", (code) => {
|
|
2183
|
-
|
|
2184
|
-
reject(new Error(stderr || `wrangler exited with code ${code}`));
|
|
2185
|
-
} else {
|
|
2186
|
-
resolve4(stdout);
|
|
2187
|
-
}
|
|
2243
|
+
resolve4({ stdout, stderr, code, error: code !== 0 });
|
|
2188
2244
|
});
|
|
2189
2245
|
});
|
|
2190
2246
|
}
|
|
2191
|
-
function runWranglerCommandWithInput(args, inputData) {
|
|
2192
|
-
|
|
2247
|
+
async function runWranglerCommandWithInput(args, inputData, cwd) {
|
|
2248
|
+
const result = await runWranglerCommandWithInputRaw(args, inputData);
|
|
2249
|
+
return handleWranglerResult(
|
|
2250
|
+
result,
|
|
2251
|
+
() => runWranglerCommandWithInputRaw(args, inputData),
|
|
2252
|
+
cwd
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2255
|
+
function runWranglerCommandWithInputRaw(args, inputData) {
|
|
2256
|
+
return new Promise((resolve4) => {
|
|
2193
2257
|
let stdout = "";
|
|
2194
2258
|
let stderr = "";
|
|
2195
2259
|
const child = spawn2("npx", ["wrangler", ...args], {
|
|
@@ -2202,14 +2266,10 @@ function runWranglerCommandWithInput(args, inputData) {
|
|
|
2202
2266
|
stderr += data.toString();
|
|
2203
2267
|
});
|
|
2204
2268
|
child.on("error", (error) => {
|
|
2205
|
-
|
|
2269
|
+
resolve4({ stdout, stderr: error.message, code: null, error: true });
|
|
2206
2270
|
});
|
|
2207
2271
|
child.on("close", (code) => {
|
|
2208
|
-
|
|
2209
|
-
reject(new Error(stderr || `wrangler exited with code ${code}`));
|
|
2210
|
-
} else {
|
|
2211
|
-
resolve4(stdout);
|
|
2212
|
-
}
|
|
2272
|
+
resolve4({ stdout, stderr, code, error: code !== 0 });
|
|
2213
2273
|
});
|
|
2214
2274
|
child.stdin?.write(inputData);
|
|
2215
2275
|
child.stdin?.end();
|
|
@@ -2726,6 +2786,279 @@ function runWranglerCommandWithInput2(args, inputData) {
|
|
|
2726
2786
|
|
|
2727
2787
|
// src/commands/bindings/generate-types.ts
|
|
2728
2788
|
import pc8 from "picocolors";
|
|
2789
|
+
|
|
2790
|
+
// src/utils/type-generator.ts
|
|
2791
|
+
import * as fs9 from "fs";
|
|
2792
|
+
import * as path10 from "path";
|
|
2793
|
+
var CLOUDWERK_TYPES_DIR = ".cloudwerk/types";
|
|
2794
|
+
var BINDINGS_DTS = "bindings.d.ts";
|
|
2795
|
+
var CONTEXT_DTS = "context.d.ts";
|
|
2796
|
+
function generateCloudwerkTypes(cwd, bindings2, options = {}) {
|
|
2797
|
+
const includeTimestamp = options.includeTimestamp ?? true;
|
|
2798
|
+
const typesDir = path10.join(cwd, CLOUDWERK_TYPES_DIR);
|
|
2799
|
+
fs9.mkdirSync(typesDir, { recursive: true });
|
|
2800
|
+
const bindingsPath = path10.join(typesDir, BINDINGS_DTS);
|
|
2801
|
+
const bindingsContent = generateBindingsDts(bindings2, includeTimestamp);
|
|
2802
|
+
fs9.writeFileSync(bindingsPath, bindingsContent, "utf-8");
|
|
2803
|
+
const contextPath = path10.join(typesDir, CONTEXT_DTS);
|
|
2804
|
+
const contextContent = generateContextDts(bindings2, includeTimestamp);
|
|
2805
|
+
fs9.writeFileSync(contextPath, contextContent, "utf-8");
|
|
2806
|
+
const bindingInfo = bindings2.map((b) => ({
|
|
2807
|
+
name: b.name,
|
|
2808
|
+
type: getTypeForBinding(b.type)
|
|
2809
|
+
}));
|
|
2810
|
+
return {
|
|
2811
|
+
typesDir,
|
|
2812
|
+
files: {
|
|
2813
|
+
bindings: bindingsPath,
|
|
2814
|
+
context: contextPath
|
|
2815
|
+
},
|
|
2816
|
+
bindingCount: bindings2.length,
|
|
2817
|
+
bindings: bindingInfo
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
function generateBindingsDts(bindings2, includeTimestamp) {
|
|
2821
|
+
const lines = [];
|
|
2822
|
+
lines.push("// Auto-generated by cloudwerk bindings - DO NOT EDIT");
|
|
2823
|
+
if (includeTimestamp) {
|
|
2824
|
+
lines.push(`// Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
2825
|
+
}
|
|
2826
|
+
lines.push("//");
|
|
2827
|
+
lines.push("// This file provides type information for @cloudwerk/core/bindings");
|
|
2828
|
+
lines.push('// Add ".cloudwerk/types" to your tsconfig.json include array');
|
|
2829
|
+
lines.push("");
|
|
2830
|
+
lines.push("declare module '@cloudwerk/core/bindings' {");
|
|
2831
|
+
const bindingsByType = groupBindingsByType(bindings2);
|
|
2832
|
+
const typeOrder = [
|
|
2833
|
+
"d1",
|
|
2834
|
+
"kv",
|
|
2835
|
+
"r2",
|
|
2836
|
+
"queue",
|
|
2837
|
+
"do",
|
|
2838
|
+
"service",
|
|
2839
|
+
"ai",
|
|
2840
|
+
"vectorize",
|
|
2841
|
+
"hyperdrive",
|
|
2842
|
+
"secret"
|
|
2843
|
+
];
|
|
2844
|
+
let firstSection = true;
|
|
2845
|
+
for (const type of typeOrder) {
|
|
2846
|
+
const typeBindings = bindingsByType.get(type);
|
|
2847
|
+
if (!typeBindings || typeBindings.length === 0) continue;
|
|
2848
|
+
const tsType = getTypeForBinding(type);
|
|
2849
|
+
const sectionName = getSectionName2(type);
|
|
2850
|
+
if (!firstSection) {
|
|
2851
|
+
lines.push("");
|
|
2852
|
+
}
|
|
2853
|
+
lines.push(` // ${sectionName}`);
|
|
2854
|
+
firstSection = false;
|
|
2855
|
+
for (const binding of typeBindings) {
|
|
2856
|
+
lines.push(` export const ${binding.name}: ${tsType}`);
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
lines.push("");
|
|
2860
|
+
lines.push(" // Bindings proxy object (for dynamic access)");
|
|
2861
|
+
lines.push(" export const bindings: Record<string, unknown>");
|
|
2862
|
+
lines.push("");
|
|
2863
|
+
lines.push(" // Helper functions");
|
|
2864
|
+
lines.push(" export function getBinding<T = unknown>(name: string): T");
|
|
2865
|
+
lines.push(" export function hasBinding(name: string): boolean");
|
|
2866
|
+
lines.push(" export function getBindingNames(): string[]");
|
|
2867
|
+
lines.push("}");
|
|
2868
|
+
lines.push("");
|
|
2869
|
+
return lines.join("\n");
|
|
2870
|
+
}
|
|
2871
|
+
function generateContextDts(bindings2, includeTimestamp) {
|
|
2872
|
+
const lines = [];
|
|
2873
|
+
lines.push("// Auto-generated by cloudwerk bindings - DO NOT EDIT");
|
|
2874
|
+
if (includeTimestamp) {
|
|
2875
|
+
lines.push(`// Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
2876
|
+
}
|
|
2877
|
+
lines.push("//");
|
|
2878
|
+
lines.push("// This file provides type information for @cloudwerk/core/context");
|
|
2879
|
+
lines.push('// Add ".cloudwerk/types" to your tsconfig.json include array');
|
|
2880
|
+
lines.push("");
|
|
2881
|
+
lines.push("interface CloudwerkEnv {");
|
|
2882
|
+
const bindingsByType = groupBindingsByType(bindings2);
|
|
2883
|
+
const typeOrder = [
|
|
2884
|
+
"d1",
|
|
2885
|
+
"kv",
|
|
2886
|
+
"r2",
|
|
2887
|
+
"queue",
|
|
2888
|
+
"do",
|
|
2889
|
+
"service",
|
|
2890
|
+
"ai",
|
|
2891
|
+
"vectorize",
|
|
2892
|
+
"hyperdrive",
|
|
2893
|
+
"secret"
|
|
2894
|
+
];
|
|
2895
|
+
let firstSection = true;
|
|
2896
|
+
for (const type of typeOrder) {
|
|
2897
|
+
const typeBindings = bindingsByType.get(type);
|
|
2898
|
+
if (!typeBindings || typeBindings.length === 0) continue;
|
|
2899
|
+
const tsType = getTypeForBinding(type);
|
|
2900
|
+
const sectionName = getSectionName2(type);
|
|
2901
|
+
if (!firstSection) {
|
|
2902
|
+
lines.push("");
|
|
2903
|
+
}
|
|
2904
|
+
lines.push(` // ${sectionName}`);
|
|
2905
|
+
firstSection = false;
|
|
2906
|
+
for (const binding of typeBindings) {
|
|
2907
|
+
lines.push(` ${binding.name}: ${tsType}`);
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
lines.push("}");
|
|
2911
|
+
lines.push("");
|
|
2912
|
+
lines.push("declare module '@cloudwerk/core/context' {");
|
|
2913
|
+
lines.push(" // Route parameters proxy");
|
|
2914
|
+
lines.push(" export const params: Record<string, string>");
|
|
2915
|
+
lines.push("");
|
|
2916
|
+
lines.push(" // Current request proxy");
|
|
2917
|
+
lines.push(" export const request: Request");
|
|
2918
|
+
lines.push("");
|
|
2919
|
+
lines.push(" // Environment bindings proxy (typed from wrangler.toml)");
|
|
2920
|
+
lines.push(" export const env: CloudwerkEnv");
|
|
2921
|
+
lines.push("");
|
|
2922
|
+
lines.push(" // Cloudflare execution context proxy");
|
|
2923
|
+
lines.push(" export const executionCtx: {");
|
|
2924
|
+
lines.push(" waitUntil(promise: Promise<unknown>): void");
|
|
2925
|
+
lines.push(" passThroughOnException(): void");
|
|
2926
|
+
lines.push(" }");
|
|
2927
|
+
lines.push("");
|
|
2928
|
+
lines.push(" // Helper functions");
|
|
2929
|
+
lines.push(" export function getRequestId(): string");
|
|
2930
|
+
lines.push(" export function get<T>(key: string): T | undefined");
|
|
2931
|
+
lines.push(" export function set<T>(key: string, value: T): void");
|
|
2932
|
+
lines.push("}");
|
|
2933
|
+
lines.push("");
|
|
2934
|
+
return lines.join("\n");
|
|
2935
|
+
}
|
|
2936
|
+
function groupBindingsByType(bindings2) {
|
|
2937
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
2938
|
+
for (const binding of bindings2) {
|
|
2939
|
+
const existing = grouped.get(binding.type) || [];
|
|
2940
|
+
existing.push(binding);
|
|
2941
|
+
grouped.set(binding.type, existing);
|
|
2942
|
+
}
|
|
2943
|
+
return grouped;
|
|
2944
|
+
}
|
|
2945
|
+
function getSectionName2(type) {
|
|
2946
|
+
switch (type) {
|
|
2947
|
+
case "d1":
|
|
2948
|
+
return "D1 Databases";
|
|
2949
|
+
case "kv":
|
|
2950
|
+
return "KV Namespaces";
|
|
2951
|
+
case "r2":
|
|
2952
|
+
return "R2 Buckets";
|
|
2953
|
+
case "queue":
|
|
2954
|
+
return "Queues";
|
|
2955
|
+
case "do":
|
|
2956
|
+
return "Durable Objects";
|
|
2957
|
+
case "service":
|
|
2958
|
+
return "Services";
|
|
2959
|
+
case "secret":
|
|
2960
|
+
return "Environment Variables";
|
|
2961
|
+
case "ai":
|
|
2962
|
+
return "AI";
|
|
2963
|
+
case "vectorize":
|
|
2964
|
+
return "Vectorize Indexes";
|
|
2965
|
+
case "hyperdrive":
|
|
2966
|
+
return "Hyperdrive";
|
|
2967
|
+
default:
|
|
2968
|
+
return "Other";
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
// src/utils/tsconfig-updater.ts
|
|
2973
|
+
import * as fs10 from "fs";
|
|
2974
|
+
import * as path11 from "path";
|
|
2975
|
+
var CLOUDWERK_TYPES_INCLUDE = ".cloudwerk/types/**/*";
|
|
2976
|
+
var BINDINGS_PATH_KEY = "@cloudwerk/core/bindings";
|
|
2977
|
+
var CONTEXT_PATH_KEY = "@cloudwerk/core/context";
|
|
2978
|
+
function updateTsConfigPaths(cwd) {
|
|
2979
|
+
const tsconfigPath = path11.join(cwd, "tsconfig.json");
|
|
2980
|
+
const changes = {
|
|
2981
|
+
addedIncludes: [],
|
|
2982
|
+
addedPaths: [],
|
|
2983
|
+
setBaseUrl: false
|
|
2984
|
+
};
|
|
2985
|
+
if (!fs10.existsSync(tsconfigPath)) {
|
|
2986
|
+
const newConfig = {
|
|
2987
|
+
compilerOptions: {
|
|
2988
|
+
baseUrl: ".",
|
|
2989
|
+
paths: {
|
|
2990
|
+
[BINDINGS_PATH_KEY]: ["./.cloudwerk/types/bindings.d.ts"],
|
|
2991
|
+
[CONTEXT_PATH_KEY]: ["./.cloudwerk/types/context.d.ts"]
|
|
2992
|
+
}
|
|
2993
|
+
},
|
|
2994
|
+
include: [CLOUDWERK_TYPES_INCLUDE]
|
|
2995
|
+
};
|
|
2996
|
+
fs10.writeFileSync(tsconfigPath, JSON.stringify(newConfig, null, 2) + "\n", "utf-8");
|
|
2997
|
+
return {
|
|
2998
|
+
tsconfigPath,
|
|
2999
|
+
modified: true,
|
|
3000
|
+
changes: {
|
|
3001
|
+
addedIncludes: [CLOUDWERK_TYPES_INCLUDE],
|
|
3002
|
+
addedPaths: [BINDINGS_PATH_KEY, CONTEXT_PATH_KEY],
|
|
3003
|
+
setBaseUrl: true
|
|
3004
|
+
}
|
|
3005
|
+
};
|
|
3006
|
+
}
|
|
3007
|
+
const content = fs10.readFileSync(tsconfigPath, "utf-8");
|
|
3008
|
+
let config;
|
|
3009
|
+
try {
|
|
3010
|
+
config = JSON.parse(content);
|
|
3011
|
+
} catch {
|
|
3012
|
+
throw new Error(
|
|
3013
|
+
`Invalid JSON in tsconfig.json. Please fix the syntax and try again.`
|
|
3014
|
+
);
|
|
3015
|
+
}
|
|
3016
|
+
let modified = false;
|
|
3017
|
+
if (!config.compilerOptions) {
|
|
3018
|
+
config.compilerOptions = {};
|
|
3019
|
+
}
|
|
3020
|
+
if (!config.compilerOptions.baseUrl) {
|
|
3021
|
+
config.compilerOptions.baseUrl = ".";
|
|
3022
|
+
changes.setBaseUrl = true;
|
|
3023
|
+
modified = true;
|
|
3024
|
+
}
|
|
3025
|
+
if (!config.compilerOptions.paths) {
|
|
3026
|
+
config.compilerOptions.paths = {};
|
|
3027
|
+
}
|
|
3028
|
+
if (!config.compilerOptions.paths[BINDINGS_PATH_KEY]) {
|
|
3029
|
+
config.compilerOptions.paths[BINDINGS_PATH_KEY] = [
|
|
3030
|
+
"./.cloudwerk/types/bindings.d.ts"
|
|
3031
|
+
];
|
|
3032
|
+
changes.addedPaths.push(BINDINGS_PATH_KEY);
|
|
3033
|
+
modified = true;
|
|
3034
|
+
}
|
|
3035
|
+
if (!config.compilerOptions.paths[CONTEXT_PATH_KEY]) {
|
|
3036
|
+
config.compilerOptions.paths[CONTEXT_PATH_KEY] = [
|
|
3037
|
+
"./.cloudwerk/types/context.d.ts"
|
|
3038
|
+
];
|
|
3039
|
+
changes.addedPaths.push(CONTEXT_PATH_KEY);
|
|
3040
|
+
modified = true;
|
|
3041
|
+
}
|
|
3042
|
+
if (!config.include) {
|
|
3043
|
+
config.include = [];
|
|
3044
|
+
}
|
|
3045
|
+
if (!config.include.includes(CLOUDWERK_TYPES_INCLUDE)) {
|
|
3046
|
+
config.include.unshift(CLOUDWERK_TYPES_INCLUDE);
|
|
3047
|
+
changes.addedIncludes.push(CLOUDWERK_TYPES_INCLUDE);
|
|
3048
|
+
modified = true;
|
|
3049
|
+
}
|
|
3050
|
+
if (modified) {
|
|
3051
|
+
const newContent = JSON.stringify(config, null, 2) + "\n";
|
|
3052
|
+
fs10.writeFileSync(tsconfigPath, newContent, "utf-8");
|
|
3053
|
+
}
|
|
3054
|
+
return {
|
|
3055
|
+
tsconfigPath,
|
|
3056
|
+
modified,
|
|
3057
|
+
changes
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
// src/commands/bindings/generate-types.ts
|
|
2729
3062
|
async function bindingsGenerateTypes(options) {
|
|
2730
3063
|
const verbose = options.verbose ?? false;
|
|
2731
3064
|
const logger = createLogger(verbose);
|
|
@@ -2763,15 +3096,46 @@ async function bindingsGenerateTypes(options) {
|
|
|
2763
3096
|
for (const binding of result.bindings) {
|
|
2764
3097
|
console.log(` ${pc8.cyan(binding.name)}: ${pc8.dim(binding.type)}`);
|
|
2765
3098
|
}
|
|
3099
|
+
logger.debug("Generating .cloudwerk/types/...");
|
|
3100
|
+
const cloudwerkResult = generateCloudwerkTypes(cwd, bindings2);
|
|
2766
3101
|
console.log();
|
|
2767
|
-
logger.success("Types generated successfully!");
|
|
2768
|
-
console.log();
|
|
2769
|
-
console.log(
|
|
2770
|
-
pc8.dim("Make sure env.d.ts is included in your tsconfig.json:")
|
|
2771
|
-
);
|
|
2772
3102
|
console.log(
|
|
2773
|
-
pc8.
|
|
3103
|
+
pc8.green("\u2713") + ` Generated ${pc8.bold(".cloudwerk/types/")} for importable bindings:`
|
|
2774
3104
|
);
|
|
3105
|
+
console.log(` ${pc8.dim(cloudwerkResult.files.bindings)}`);
|
|
3106
|
+
console.log(` ${pc8.dim(cloudwerkResult.files.context)}`);
|
|
3107
|
+
logger.debug("Updating tsconfig.json...");
|
|
3108
|
+
const tsconfigResult = updateTsConfigPaths(cwd);
|
|
3109
|
+
if (tsconfigResult.modified) {
|
|
3110
|
+
console.log();
|
|
3111
|
+
console.log(
|
|
3112
|
+
pc8.green("\u2713") + ` Updated ${pc8.bold("tsconfig.json")}:`
|
|
3113
|
+
);
|
|
3114
|
+
if (tsconfigResult.changes.setBaseUrl) {
|
|
3115
|
+
console.log(` ${pc8.dim('Added baseUrl: "."')}`);
|
|
3116
|
+
}
|
|
3117
|
+
for (const pathKey of tsconfigResult.changes.addedPaths) {
|
|
3118
|
+
console.log(` ${pc8.dim(`Added paths: "${pathKey}"`)}`);
|
|
3119
|
+
}
|
|
3120
|
+
for (const include of tsconfigResult.changes.addedIncludes) {
|
|
3121
|
+
console.log(` ${pc8.dim(`Added include: "${include}"`)}`);
|
|
3122
|
+
}
|
|
3123
|
+
} else {
|
|
3124
|
+
logger.debug("tsconfig.json already configured");
|
|
3125
|
+
}
|
|
3126
|
+
console.log();
|
|
3127
|
+
logger.success("Types generated successfully!");
|
|
3128
|
+
console.log();
|
|
3129
|
+
console.log(pc8.bold("Usage:"));
|
|
3130
|
+
console.log();
|
|
3131
|
+
console.log(pc8.dim(" // Import bindings directly (new)"));
|
|
3132
|
+
console.log(pc8.cyan(` import { ${bindings2[0]?.name || "DB"} } from '@cloudwerk/core/bindings'`));
|
|
3133
|
+
console.log();
|
|
3134
|
+
console.log(pc8.dim(" // Import context helpers (new)"));
|
|
3135
|
+
console.log(pc8.cyan(` import { params, request, get } from '@cloudwerk/core/context'`));
|
|
3136
|
+
console.log();
|
|
3137
|
+
console.log(pc8.dim(" // Or use getContext() (existing)"));
|
|
3138
|
+
console.log(pc8.cyan(` import { getContext } from '@cloudwerk/core'`));
|
|
2775
3139
|
console.log();
|
|
2776
3140
|
} catch (error) {
|
|
2777
3141
|
handleCommandError(error, verbose);
|
|
@@ -2779,14 +3143,14 @@ async function bindingsGenerateTypes(options) {
|
|
|
2779
3143
|
}
|
|
2780
3144
|
|
|
2781
3145
|
// src/index.ts
|
|
2782
|
-
program.name("cloudwerk").description("Cloudwerk CLI - Build and deploy full-stack apps to Cloudflare").version(VERSION);
|
|
3146
|
+
program.name("cloudwerk").description("Cloudwerk CLI - Build and deploy full-stack apps to Cloudflare").version(VERSION).enablePositionalOptions();
|
|
2783
3147
|
program.command("dev [path]").description("Start development server").option("-p, --port <number>", "Port to listen on", String(DEFAULT_PORT)).option("-H, --host <host>", "Host to bind", DEFAULT_HOST).option("-c, --config <path>", "Path to config file").option("--verbose", "Enable verbose logging").action(dev);
|
|
2784
3148
|
program.command("build [path]").description("Build project for production deployment to Cloudflare Workers").option("-o, --output <dir>", "Output directory", "./dist").option("--ssg", "Generate static pages for routes with rendering: static").option("--minify", "Minify bundles (default: true)").option("--no-minify", "Disable minification").option("--sourcemap", "Generate source maps").option("-c, --config <path>", "Path to config file").option("--verbose", "Enable verbose logging").action(build);
|
|
2785
3149
|
program.command("deploy [path]").description("Deploy to Cloudflare Workers").option("-e, --env <environment>", "Environment to deploy to").option("--dry-run", "Preview deployment without executing").option("--skip-build", "Skip the build step").option("-c, --config <path>", "Path to config file").option("--verbose", "Enable verbose logging").action(deploy);
|
|
2786
3150
|
var configCmd = program.command("config").description("Manage Cloudwerk configuration");
|
|
2787
3151
|
configCmd.command("get <key>").description("Get a configuration value").action(configGet);
|
|
2788
3152
|
configCmd.command("set <key> <value>").description("Set a configuration value").action(configSet);
|
|
2789
|
-
var bindingsCmd = program.command("bindings").description("Manage Cloudflare bindings (D1, KV, R2, Queues, etc.)").
|
|
3153
|
+
var bindingsCmd = program.command("bindings").description("Manage Cloudflare bindings (D1, KV, R2, Queues, etc.)").enablePositionalOptions().passThroughOptions().option("--verbose", "Enable verbose logging").action(bindings);
|
|
2790
3154
|
bindingsCmd.command("add [type]").description("Add a new binding (d1, kv, r2, queue, do, secret)").option("-e, --env <environment>", "Environment to add binding to").option("--skip-types", "Skip TypeScript type generation").option("--verbose", "Enable verbose logging").action(bindingsAdd);
|
|
2791
3155
|
bindingsCmd.command("remove [name]").description("Remove a binding").option("-e, --env <environment>", "Environment to remove binding from").option("-f, --force", "Skip confirmation prompt").option("--skip-types", "Skip TypeScript type generation").option("--verbose", "Enable verbose logging").action(bindingsRemove);
|
|
2792
3156
|
bindingsCmd.command("update [name]").description("Update an existing binding").option("-e, --env <environment>", "Environment to update binding in").option("--skip-types", "Skip TypeScript type generation").option("--verbose", "Enable verbose logging").action(bindingsUpdate);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudwerk/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Dev server, build, deploy commands for Cloudwerk",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"esbuild": "^0.25.0",
|
|
31
31
|
"picocolors": "^1.1.0",
|
|
32
32
|
"vite": "^6.0.0",
|
|
33
|
-
"@cloudwerk/
|
|
34
|
-
"@cloudwerk/
|
|
35
|
-
"@cloudwerk/core": "^0.
|
|
33
|
+
"@cloudwerk/ui": "^0.12.0",
|
|
34
|
+
"@cloudwerk/vite-plugin": "^0.5.0",
|
|
35
|
+
"@cloudwerk/core": "^0.12.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^20.0.0",
|