gistajs 0.1.5 → 0.1.7
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/README.md +2 -1
- package/dist/bin.cjs +137 -122
- package/dist/index.d.ts +2 -0
- package/dist/index.js +127 -112
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ npx gistajs create my-app --starter website --no-install --no-git
|
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Today the CLI covers project creation, starter diffs, pin management, Turso provisioning, and Vercel provisioning.
|
|
13
|
+
For starters that define `pnpm prep`, `gistajs create` offers to run that setup step after dependencies install.
|
|
13
14
|
|
|
14
15
|
### Diff
|
|
15
16
|
|
|
@@ -67,7 +68,7 @@ npx gistajs provision turso
|
|
|
67
68
|
npx gistajs provision vercel
|
|
68
69
|
```
|
|
69
70
|
|
|
70
|
-
The command is interactive. It asks for a shared region first, defaults new projects to Oregon, reuses the saved region on later runs, creates a Turso group in that region when needed, links Vercel when needed, and asks before overwriting existing database credentials in `.env`.
|
|
71
|
+
The command is interactive. It asks for a shared region first, defaults new projects to Turso's nearest region when available, falls back to Oregon otherwise, reuses the saved `gistajs.region` on later runs, creates a Turso group in that region when needed, links Vercel when needed, and asks before overwriting existing database credentials in `.env`.
|
|
71
72
|
|
|
72
73
|
## Development
|
|
73
74
|
|
package/dist/bin.cjs
CHANGED
|
@@ -166,6 +166,17 @@ async function runInput(command, args, cwd, input) {
|
|
|
166
166
|
input
|
|
167
167
|
});
|
|
168
168
|
}
|
|
169
|
+
async function assertCommand(runFn, cwd, command, args, failureMessage) {
|
|
170
|
+
try {
|
|
171
|
+
await runFn(command, args, cwd);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
let code = error.code;
|
|
174
|
+
if (code === "ENOENT") {
|
|
175
|
+
throw new Error(`Required command not found: ${command}`);
|
|
176
|
+
}
|
|
177
|
+
throw new Error(failureMessage);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
169
180
|
async function exec(command, args, cwd, options) {
|
|
170
181
|
return await new Promise((resolve2, reject) => {
|
|
171
182
|
let { capture, input } = options;
|
|
@@ -273,7 +284,9 @@ var UsageError = class extends Error {
|
|
|
273
284
|
// src/commands/create.ts
|
|
274
285
|
var defaultCreateProjectDeps = {
|
|
275
286
|
initGit,
|
|
276
|
-
|
|
287
|
+
promptConfirm,
|
|
288
|
+
run,
|
|
289
|
+
stdout: console
|
|
277
290
|
};
|
|
278
291
|
function parseCreateArgs(argv) {
|
|
279
292
|
let options = {};
|
|
@@ -358,6 +371,9 @@ async function createProject(starter, options, deps = defaultCreateProjectDeps)
|
|
|
358
371
|
}
|
|
359
372
|
if (options.install !== false) {
|
|
360
373
|
await installDependencies(root, deps.run);
|
|
374
|
+
if (await hasPrepScript(root)) {
|
|
375
|
+
await runPrepScript(root, deps);
|
|
376
|
+
}
|
|
361
377
|
}
|
|
362
378
|
return root;
|
|
363
379
|
} finally {
|
|
@@ -420,8 +436,24 @@ async function rewritePackageName(root, projectName) {
|
|
|
420
436
|
}
|
|
421
437
|
}
|
|
422
438
|
async function installDependencies(root, runCommand) {
|
|
439
|
+
await runPnpmCommand(root, runCommand, "install");
|
|
440
|
+
}
|
|
441
|
+
async function runPrepScript(root, deps) {
|
|
442
|
+
let shouldRun = await deps.promptConfirm("Run project setup now? (Y/n) ");
|
|
443
|
+
if (!shouldRun) return;
|
|
423
444
|
try {
|
|
424
|
-
await
|
|
445
|
+
await runPnpmCommand(root, deps.run, "prep");
|
|
446
|
+
} catch (error) {
|
|
447
|
+
let detail = error instanceof Error ? error.message : String(error);
|
|
448
|
+
deps.stdout.log(`Warning: Project setup failed. ${detail}`);
|
|
449
|
+
deps.stdout.log(
|
|
450
|
+
`Run ${c.path(`cd ${root} && pnpm prep`)} to retry project setup.`
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
async function runPnpmCommand(root, runCommand, script) {
|
|
455
|
+
try {
|
|
456
|
+
await runCommand("corepack", ["pnpm", script], root);
|
|
425
457
|
return;
|
|
426
458
|
} catch (error) {
|
|
427
459
|
if (!isCommandNotFound(error)) {
|
|
@@ -429,16 +461,22 @@ async function installDependencies(root, runCommand) {
|
|
|
429
461
|
}
|
|
430
462
|
}
|
|
431
463
|
try {
|
|
432
|
-
await runCommand("pnpm", [
|
|
464
|
+
await runCommand("pnpm", [script], root);
|
|
433
465
|
} catch (error) {
|
|
434
466
|
if (!isCommandNotFound(error)) {
|
|
435
467
|
throw error;
|
|
436
468
|
}
|
|
437
469
|
throw new Error(
|
|
438
|
-
|
|
470
|
+
`Could not run pnpm ${script} because neither corepack nor pnpm is available. Install Node.js with corepack enabled, or install pnpm and rerun the command.`
|
|
439
471
|
);
|
|
440
472
|
}
|
|
441
473
|
}
|
|
474
|
+
async function hasPrepScript(root) {
|
|
475
|
+
let path = (0, import_node_path.join)(root, "package.json");
|
|
476
|
+
let source = await (0, import_promises2.readFile)(path, "utf8");
|
|
477
|
+
let pkg = JSON.parse(source);
|
|
478
|
+
return typeof pkg.scripts?.prep === "string" && pkg.scripts.prep.length > 0;
|
|
479
|
+
}
|
|
442
480
|
function getErrorCode(error) {
|
|
443
481
|
return error?.code;
|
|
444
482
|
}
|
|
@@ -553,6 +591,8 @@ function getHelpText(command) {
|
|
|
553
591
|
` ${c.bold("Examples:")}`,
|
|
554
592
|
` ${c.dim("$")} gistajs create my-app`,
|
|
555
593
|
` ${c.dim("$")} gistajs create my-app --starter website`,
|
|
594
|
+
"",
|
|
595
|
+
` Some starters offer an optional setup step after dependencies install.`,
|
|
556
596
|
""
|
|
557
597
|
].join("\n");
|
|
558
598
|
}
|
|
@@ -619,6 +659,9 @@ function getHelpText(command) {
|
|
|
619
659
|
` ${c.bold("Examples:")}`,
|
|
620
660
|
` ${c.dim("$")} gistajs create my-app`,
|
|
621
661
|
` ${c.dim("$")} gistajs create my-app --starter website`,
|
|
662
|
+
"",
|
|
663
|
+
` Some starters offer an optional setup step after dependencies install.`,
|
|
664
|
+
"",
|
|
622
665
|
` ${c.dim("$")} gistajs diff --latest`,
|
|
623
666
|
` ${c.dim("$")} gistajs diff --latest --stat`,
|
|
624
667
|
` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001`,
|
|
@@ -797,8 +840,41 @@ function getErrorMessage(error) {
|
|
|
797
840
|
}
|
|
798
841
|
|
|
799
842
|
// src/commands/pin.ts
|
|
843
|
+
var import_promises5 = require("fs/promises");
|
|
844
|
+
var import_node_path4 = require("path");
|
|
845
|
+
|
|
846
|
+
// src/utils/package.ts
|
|
800
847
|
var import_promises4 = require("fs/promises");
|
|
801
848
|
var import_node_path3 = require("path");
|
|
849
|
+
async function readProjectPackage(root, readFileFn = (p, e) => (0, import_promises4.readFile)(p, e)) {
|
|
850
|
+
let path = (0, import_node_path3.join)(root, "package.json");
|
|
851
|
+
let source;
|
|
852
|
+
try {
|
|
853
|
+
source = await readFileFn(path, "utf8");
|
|
854
|
+
} catch (error) {
|
|
855
|
+
let code = error.code;
|
|
856
|
+
if (code === "ENOENT") {
|
|
857
|
+
throw new Error(
|
|
858
|
+
"No package.json found. Run this from a Gista.js project directory."
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
throw error;
|
|
862
|
+
}
|
|
863
|
+
try {
|
|
864
|
+
let pkg = JSON.parse(source);
|
|
865
|
+
if (!pkg || typeof pkg !== "object" || Array.isArray(pkg)) {
|
|
866
|
+
throw new Error("package.json must contain a JSON object");
|
|
867
|
+
}
|
|
868
|
+
return pkg;
|
|
869
|
+
} catch (error) {
|
|
870
|
+
if (error instanceof SyntaxError) {
|
|
871
|
+
throw new Error("Could not parse package.json in the current directory.");
|
|
872
|
+
}
|
|
873
|
+
throw error;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// src/commands/pin.ts
|
|
802
878
|
function parsePinArgs(argv) {
|
|
803
879
|
let options = {};
|
|
804
880
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -859,35 +935,13 @@ async function writeProjectStarterPin(root, pin) {
|
|
|
859
935
|
let parsed = splitProjectStarterPin(pin);
|
|
860
936
|
let gistajs = pkg.gistajs && typeof pkg.gistajs === "object" && !Array.isArray(pkg.gistajs) ? { ...pkg.gistajs } : {};
|
|
861
937
|
gistajs.pin = parsed.pin;
|
|
862
|
-
await (0,
|
|
863
|
-
(0,
|
|
938
|
+
await (0, import_promises5.writeFile)(
|
|
939
|
+
(0, import_node_path4.join)(root, "package.json"),
|
|
864
940
|
`${JSON.stringify({ ...pkg, gistajs }, null, 2)}
|
|
865
941
|
`
|
|
866
942
|
);
|
|
867
943
|
return parsed;
|
|
868
944
|
}
|
|
869
|
-
async function readProjectPackage(root) {
|
|
870
|
-
let path = (0, import_node_path3.join)(root, "package.json");
|
|
871
|
-
let source;
|
|
872
|
-
try {
|
|
873
|
-
source = await (0, import_promises4.readFile)(path, "utf8");
|
|
874
|
-
} catch (error) {
|
|
875
|
-
if (error?.code === "ENOENT") {
|
|
876
|
-
throw new Error(`Could not find package.json in ${root}`);
|
|
877
|
-
}
|
|
878
|
-
throw error;
|
|
879
|
-
}
|
|
880
|
-
try {
|
|
881
|
-
let pkg = JSON.parse(source);
|
|
882
|
-
if (!pkg || typeof pkg !== "object" || Array.isArray(pkg)) {
|
|
883
|
-
throw new Error("package.json must contain a JSON object");
|
|
884
|
-
}
|
|
885
|
-
return pkg;
|
|
886
|
-
} catch (error) {
|
|
887
|
-
let message = error instanceof Error ? error.message : String(error);
|
|
888
|
-
throw new Error(`Invalid package.json: ${message}`);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
945
|
|
|
892
946
|
// src/providers/regions.ts
|
|
893
947
|
var sharedRegions = [
|
|
@@ -931,11 +985,6 @@ function getSharedRegion(value) {
|
|
|
931
985
|
function getDefaultSharedRegion() {
|
|
932
986
|
return getSharedRegion(defaultSharedRegionId);
|
|
933
987
|
}
|
|
934
|
-
function parseSharedRegion(value) {
|
|
935
|
-
let normalized = value.trim().toLowerCase();
|
|
936
|
-
if (!normalized) return null;
|
|
937
|
-
return getSharedRegion(normalized);
|
|
938
|
-
}
|
|
939
988
|
|
|
940
989
|
// src/utils/version.ts
|
|
941
990
|
function satisfiesVersion(version, range) {
|
|
@@ -1065,7 +1114,7 @@ async function runProviderProvision(provider, deps) {
|
|
|
1065
1114
|
if (provider !== "turso" && provider !== "vercel") {
|
|
1066
1115
|
throw new UsageError(`Unknown provider: ${provider}`, "provision");
|
|
1067
1116
|
}
|
|
1068
|
-
let pkg = await
|
|
1117
|
+
let pkg = await readProvisionPackage(deps);
|
|
1069
1118
|
let region = await resolveProjectRegion(pkg, deps);
|
|
1070
1119
|
await writeProjectRegion(pkg, region.id, deps);
|
|
1071
1120
|
if (provider === "turso") {
|
|
@@ -1078,7 +1127,7 @@ async function runProviderProvision(provider, deps) {
|
|
|
1078
1127
|
}
|
|
1079
1128
|
}
|
|
1080
1129
|
async function runProjectProvision(deps) {
|
|
1081
|
-
let pkg = await
|
|
1130
|
+
let pkg = await readProvisionPackage(deps);
|
|
1082
1131
|
let providers = pkg.gistajs?.providers;
|
|
1083
1132
|
if (!providers?.length) {
|
|
1084
1133
|
throw new Error(
|
|
@@ -1116,23 +1165,8 @@ async function runProjectProvision(deps) {
|
|
|
1116
1165
|
}
|
|
1117
1166
|
printSummary(summary, deps);
|
|
1118
1167
|
}
|
|
1119
|
-
async function
|
|
1120
|
-
|
|
1121
|
-
try {
|
|
1122
|
-
let file = await deps.readFile(path, "utf8");
|
|
1123
|
-
return JSON.parse(file);
|
|
1124
|
-
} catch (error) {
|
|
1125
|
-
let code = error.code;
|
|
1126
|
-
if (code === "ENOENT") {
|
|
1127
|
-
throw new Error(
|
|
1128
|
-
"No package.json found. Run this from a Gista.js project directory."
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
if (error instanceof SyntaxError) {
|
|
1132
|
-
throw new Error("Could not parse package.json in the current directory.");
|
|
1133
|
-
}
|
|
1134
|
-
throw error;
|
|
1135
|
-
}
|
|
1168
|
+
async function readProvisionPackage(deps) {
|
|
1169
|
+
return await readProjectPackage(deps.cwd, deps.readFile);
|
|
1136
1170
|
}
|
|
1137
1171
|
async function writeProjectRegion(pkg, region, deps) {
|
|
1138
1172
|
let nextPkg = {
|
|
@@ -1161,7 +1195,7 @@ async function resolveProjectRegion(pkg, deps) {
|
|
|
1161
1195
|
}
|
|
1162
1196
|
while (true) {
|
|
1163
1197
|
let answer = await deps.promptText(`Region (${fallback.label}): `);
|
|
1164
|
-
let selected =
|
|
1198
|
+
let selected = getSharedRegion(answer.trim() || fallback.id);
|
|
1165
1199
|
if (selected) return selected;
|
|
1166
1200
|
deps.stdout.log(`Invalid region. Choose from: ${labels}`);
|
|
1167
1201
|
}
|
|
@@ -1194,21 +1228,50 @@ function assertCliVersion(version, range) {
|
|
|
1194
1228
|
}
|
|
1195
1229
|
|
|
1196
1230
|
// src/utils/deps.ts
|
|
1197
|
-
var
|
|
1231
|
+
var import_promises8 = require("fs/promises");
|
|
1198
1232
|
var import_node_process5 = __toESM(require("process"), 1);
|
|
1199
1233
|
|
|
1200
1234
|
// src/providers/turso.ts
|
|
1201
|
-
var
|
|
1202
|
-
var
|
|
1235
|
+
var import_promises6 = require("fs/promises");
|
|
1236
|
+
var import_node_path5 = require("path");
|
|
1203
1237
|
var import_node_process3 = __toESM(require("process"), 1);
|
|
1238
|
+
|
|
1239
|
+
// src/utils/env.ts
|
|
1240
|
+
function getEnvVar(file, key) {
|
|
1241
|
+
return file.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.trim() ?? "";
|
|
1242
|
+
}
|
|
1243
|
+
function setEnvVar(file, key, value) {
|
|
1244
|
+
if (file.match(new RegExp(`^${key}=.*$`, "m"))) {
|
|
1245
|
+
return file.replace(new RegExp(`^${key}=.*$`, "m"), `${key}=${value}`);
|
|
1246
|
+
}
|
|
1247
|
+
return `${file.trimEnd()}
|
|
1248
|
+
${key}=${value}
|
|
1249
|
+
`;
|
|
1250
|
+
}
|
|
1251
|
+
function getRequiredEnvVar(file, key) {
|
|
1252
|
+
let value = getEnvVar(file, key);
|
|
1253
|
+
if (!value) {
|
|
1254
|
+
throw new Error(
|
|
1255
|
+
`Missing ${key} in .env. Provision Turso and prep the app first.`
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
return value;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/utils/table.ts
|
|
1262
|
+
function parseFirstColumn(table) {
|
|
1263
|
+
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => line.split(/\s+/)[0]).filter(Boolean);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// src/providers/turso.ts
|
|
1204
1267
|
var defaultDeps2 = {
|
|
1205
1268
|
run,
|
|
1206
1269
|
runOutput,
|
|
1207
1270
|
promptConfirm,
|
|
1208
1271
|
promptText,
|
|
1209
|
-
readFile:
|
|
1210
|
-
writeFile:
|
|
1211
|
-
cp:
|
|
1272
|
+
readFile: import_promises6.readFile,
|
|
1273
|
+
writeFile: import_promises6.writeFile,
|
|
1274
|
+
cp: import_promises6.cp,
|
|
1212
1275
|
stdout: console,
|
|
1213
1276
|
isTTY: import_node_process3.default.stdin.isTTY
|
|
1214
1277
|
};
|
|
@@ -1218,8 +1281,8 @@ async function provisionTurso(cwd, region, deps = defaultDeps2) {
|
|
|
1218
1281
|
"`gistajs provision turso` requires an interactive terminal"
|
|
1219
1282
|
);
|
|
1220
1283
|
}
|
|
1221
|
-
let envPath = (0,
|
|
1222
|
-
let envExamplePath = (0,
|
|
1284
|
+
let envPath = (0, import_node_path5.join)(cwd, ".env");
|
|
1285
|
+
let envExamplePath = (0, import_node_path5.join)(cwd, ".env.example");
|
|
1223
1286
|
let file = await ensureEnvFile(envPath, envExamplePath, deps);
|
|
1224
1287
|
let currentUrl = getEnvVar(file, "DB_URL");
|
|
1225
1288
|
let currentToken = getEnvVar(file, "DB_AUTH_TOKEN");
|
|
@@ -1243,7 +1306,7 @@ async function provisionTurso(cwd, region, deps = defaultDeps2) {
|
|
|
1243
1306
|
}
|
|
1244
1307
|
}
|
|
1245
1308
|
await assertCommand(
|
|
1246
|
-
deps,
|
|
1309
|
+
deps.run,
|
|
1247
1310
|
cwd,
|
|
1248
1311
|
"turso",
|
|
1249
1312
|
["auth", "status"],
|
|
@@ -1275,7 +1338,7 @@ Available orgs: ${slugs.join(", ")}`);
|
|
|
1275
1338
|
let groups = parseGroupTable(
|
|
1276
1339
|
await deps.runOutput("turso", ["group", "list"], cwd)
|
|
1277
1340
|
);
|
|
1278
|
-
let fallback = (0,
|
|
1341
|
+
let fallback = (0, import_node_path5.basename)(cwd).replaceAll(".", "-");
|
|
1279
1342
|
let name = "";
|
|
1280
1343
|
while (true) {
|
|
1281
1344
|
let dbName = await deps.promptText(`Database name (${fallback}): `);
|
|
@@ -1332,31 +1395,6 @@ async function ensureEnvFile(envPath, envExamplePath, deps) {
|
|
|
1332
1395
|
deps.stdout.log("Created empty .env");
|
|
1333
1396
|
return "";
|
|
1334
1397
|
}
|
|
1335
|
-
async function assertCommand(deps, cwd, command, args, failureMessage) {
|
|
1336
|
-
try {
|
|
1337
|
-
await deps.run(command, args, cwd);
|
|
1338
|
-
} catch (error) {
|
|
1339
|
-
let code = error.code;
|
|
1340
|
-
if (code === "ENOENT") {
|
|
1341
|
-
throw new Error(`Required command not found: ${command}`);
|
|
1342
|
-
}
|
|
1343
|
-
throw new Error(failureMessage);
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
function getEnvVar(file, key) {
|
|
1347
|
-
return file.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.trim() ?? "";
|
|
1348
|
-
}
|
|
1349
|
-
function setEnvVar(file, key, value) {
|
|
1350
|
-
if (file.match(new RegExp(`^${key}=.*$`, "m"))) {
|
|
1351
|
-
return file.replace(new RegExp(`^${key}=.*$`, "m"), `${key}=${value}`);
|
|
1352
|
-
}
|
|
1353
|
-
return `${file.trimEnd()}
|
|
1354
|
-
${key}=${value}
|
|
1355
|
-
`;
|
|
1356
|
-
}
|
|
1357
|
-
function parseFirstColumn(table) {
|
|
1358
|
-
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => line.split(/\s+/)[0]).filter(Boolean);
|
|
1359
|
-
}
|
|
1360
1398
|
function parseGroupTable(table) {
|
|
1361
1399
|
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
1362
1400
|
let parts = line.split(/\s+/);
|
|
@@ -1386,14 +1424,14 @@ function matchesRegion(location, region) {
|
|
|
1386
1424
|
|
|
1387
1425
|
// src/providers/vercel.ts
|
|
1388
1426
|
var import_node_fs = require("fs");
|
|
1389
|
-
var
|
|
1390
|
-
var
|
|
1427
|
+
var import_promises7 = require("fs/promises");
|
|
1428
|
+
var import_node_path6 = require("path");
|
|
1391
1429
|
var import_node_process4 = __toESM(require("process"), 1);
|
|
1392
1430
|
var defaultDeps3 = {
|
|
1393
1431
|
run,
|
|
1394
1432
|
runInput,
|
|
1395
1433
|
runOutput,
|
|
1396
|
-
readFile:
|
|
1434
|
+
readFile: import_promises7.readFile,
|
|
1397
1435
|
existsSync: import_node_fs.existsSync,
|
|
1398
1436
|
stdout: console,
|
|
1399
1437
|
isTTY: import_node_process4.default.stdin.isTTY
|
|
@@ -1405,23 +1443,23 @@ async function provisionVercel(cwd, region, deps = defaultDeps3) {
|
|
|
1405
1443
|
"`gistajs provision vercel` requires an interactive terminal"
|
|
1406
1444
|
);
|
|
1407
1445
|
}
|
|
1408
|
-
await
|
|
1409
|
-
deps,
|
|
1446
|
+
await assertCommand(
|
|
1447
|
+
deps.run,
|
|
1410
1448
|
cwd,
|
|
1411
1449
|
"vercel",
|
|
1412
1450
|
["whoami"],
|
|
1413
1451
|
"Not logged in. Run `vercel login` first."
|
|
1414
1452
|
);
|
|
1415
|
-
if (!deps.existsSync((0,
|
|
1453
|
+
if (!deps.existsSync((0, import_node_path6.join)(cwd, ".vercel", "project.json"))) {
|
|
1416
1454
|
deps.stdout.log("Linking this directory to a Vercel project...");
|
|
1417
1455
|
await deps.run("vercel", ["link"], cwd);
|
|
1418
1456
|
}
|
|
1419
1457
|
deps.stdout.log(`Setting the Vercel function region to ${region.label}...`);
|
|
1420
1458
|
await deps.run("vercel", ["--regions", region.vercel], cwd);
|
|
1421
|
-
let envPath = (0,
|
|
1459
|
+
let envPath = (0, import_node_path6.join)(cwd, ".env");
|
|
1422
1460
|
let file = await readEnvFile(envPath, deps);
|
|
1423
1461
|
let values = requiredEnvVars.map((key) => [key, getRequiredEnvVar(file, key)]);
|
|
1424
|
-
let existing =
|
|
1462
|
+
let existing = parseFirstColumn(
|
|
1425
1463
|
await deps.runOutput("vercel", ["env", "ls", "production"], cwd)
|
|
1426
1464
|
);
|
|
1427
1465
|
for (let [key, value] of values) {
|
|
@@ -1447,29 +1485,6 @@ async function readEnvFile(envPath, deps) {
|
|
|
1447
1485
|
throw error;
|
|
1448
1486
|
}
|
|
1449
1487
|
}
|
|
1450
|
-
async function assertCommand2(deps, cwd, command, args, failureMessage) {
|
|
1451
|
-
try {
|
|
1452
|
-
await deps.run(command, args, cwd);
|
|
1453
|
-
} catch (error) {
|
|
1454
|
-
let code = error.code;
|
|
1455
|
-
if (code === "ENOENT") {
|
|
1456
|
-
throw new Error(`Required command not found: ${command}`);
|
|
1457
|
-
}
|
|
1458
|
-
throw new Error(failureMessage);
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
function getRequiredEnvVar(file, key) {
|
|
1462
|
-
let value = file.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.trim();
|
|
1463
|
-
if (!value) {
|
|
1464
|
-
throw new Error(
|
|
1465
|
-
`Missing ${key} in .env. Provision Turso and prep the app first.`
|
|
1466
|
-
);
|
|
1467
|
-
}
|
|
1468
|
-
return value;
|
|
1469
|
-
}
|
|
1470
|
-
function parseFirstColumn2(table) {
|
|
1471
|
-
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => line.split(/\s+/)[0]).filter(Boolean);
|
|
1472
|
-
}
|
|
1473
1488
|
|
|
1474
1489
|
// src/utils/catalog.ts
|
|
1475
1490
|
var DEFAULT_CATALOG_URL = "https://gistajs.com/manifests/starters.json";
|
|
@@ -1506,7 +1521,7 @@ async function readCliVersion() {
|
|
|
1506
1521
|
if (false) {
|
|
1507
1522
|
throw new Error("Could not resolve the installed gistajs version");
|
|
1508
1523
|
}
|
|
1509
|
-
return "0.1.
|
|
1524
|
+
return "0.1.7";
|
|
1510
1525
|
}
|
|
1511
1526
|
async function readDefaultProvisionRegion() {
|
|
1512
1527
|
try {
|
|
@@ -1530,8 +1545,8 @@ var defaultDeps4 = {
|
|
|
1530
1545
|
promptForStarter,
|
|
1531
1546
|
promptConfirm,
|
|
1532
1547
|
promptText,
|
|
1533
|
-
readFile:
|
|
1534
|
-
writeFile:
|
|
1548
|
+
readFile: import_promises8.readFile,
|
|
1549
|
+
writeFile: import_promises8.writeFile,
|
|
1535
1550
|
stdout: console,
|
|
1536
1551
|
cwd: import_node_process5.default.cwd(),
|
|
1537
1552
|
getCliVersion: readCliVersion,
|
package/dist/index.d.ts
CHANGED
|
@@ -69,7 +69,9 @@ declare function readGitConfig(cwd: string, key: string): string;
|
|
|
69
69
|
|
|
70
70
|
type CreateProjectDeps = {
|
|
71
71
|
initGit: typeof initGit;
|
|
72
|
+
promptConfirm: typeof promptConfirm;
|
|
72
73
|
run: typeof run;
|
|
74
|
+
stdout: Pick<typeof console, 'log'>;
|
|
73
75
|
};
|
|
74
76
|
declare function createProject(starter: StarterSpec, options: CreateOptions, deps?: CreateProjectDeps): Promise<string>;
|
|
75
77
|
|
package/dist/index.js
CHANGED
|
@@ -151,6 +151,17 @@ async function runInput(command, args, cwd, input) {
|
|
|
151
151
|
input
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
|
+
async function assertCommand(runFn, cwd, command, args, failureMessage) {
|
|
155
|
+
try {
|
|
156
|
+
await runFn(command, args, cwd);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
let code = error.code;
|
|
159
|
+
if (code === "ENOENT") {
|
|
160
|
+
throw new Error(`Required command not found: ${command}`);
|
|
161
|
+
}
|
|
162
|
+
throw new Error(failureMessage);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
154
165
|
async function exec(command, args, cwd, options) {
|
|
155
166
|
return await new Promise((resolve2, reject) => {
|
|
156
167
|
let { capture, input } = options;
|
|
@@ -258,7 +269,9 @@ var UsageError = class extends Error {
|
|
|
258
269
|
// src/commands/create.ts
|
|
259
270
|
var defaultCreateProjectDeps = {
|
|
260
271
|
initGit,
|
|
261
|
-
|
|
272
|
+
promptConfirm,
|
|
273
|
+
run,
|
|
274
|
+
stdout: console
|
|
262
275
|
};
|
|
263
276
|
function parseCreateArgs(argv) {
|
|
264
277
|
let options = {};
|
|
@@ -343,6 +356,9 @@ async function createProject(starter, options, deps = defaultCreateProjectDeps)
|
|
|
343
356
|
}
|
|
344
357
|
if (options.install !== false) {
|
|
345
358
|
await installDependencies(root, deps.run);
|
|
359
|
+
if (await hasPrepScript(root)) {
|
|
360
|
+
await runPrepScript(root, deps);
|
|
361
|
+
}
|
|
346
362
|
}
|
|
347
363
|
return root;
|
|
348
364
|
} finally {
|
|
@@ -405,8 +421,24 @@ async function rewritePackageName(root, projectName) {
|
|
|
405
421
|
}
|
|
406
422
|
}
|
|
407
423
|
async function installDependencies(root, runCommand) {
|
|
424
|
+
await runPnpmCommand(root, runCommand, "install");
|
|
425
|
+
}
|
|
426
|
+
async function runPrepScript(root, deps) {
|
|
427
|
+
let shouldRun = await deps.promptConfirm("Run project setup now? (Y/n) ");
|
|
428
|
+
if (!shouldRun) return;
|
|
429
|
+
try {
|
|
430
|
+
await runPnpmCommand(root, deps.run, "prep");
|
|
431
|
+
} catch (error) {
|
|
432
|
+
let detail = error instanceof Error ? error.message : String(error);
|
|
433
|
+
deps.stdout.log(`Warning: Project setup failed. ${detail}`);
|
|
434
|
+
deps.stdout.log(
|
|
435
|
+
`Run ${c.path(`cd ${root} && pnpm prep`)} to retry project setup.`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async function runPnpmCommand(root, runCommand, script) {
|
|
408
440
|
try {
|
|
409
|
-
await runCommand("corepack", ["pnpm",
|
|
441
|
+
await runCommand("corepack", ["pnpm", script], root);
|
|
410
442
|
return;
|
|
411
443
|
} catch (error) {
|
|
412
444
|
if (!isCommandNotFound(error)) {
|
|
@@ -414,16 +446,22 @@ async function installDependencies(root, runCommand) {
|
|
|
414
446
|
}
|
|
415
447
|
}
|
|
416
448
|
try {
|
|
417
|
-
await runCommand("pnpm", [
|
|
449
|
+
await runCommand("pnpm", [script], root);
|
|
418
450
|
} catch (error) {
|
|
419
451
|
if (!isCommandNotFound(error)) {
|
|
420
452
|
throw error;
|
|
421
453
|
}
|
|
422
454
|
throw new Error(
|
|
423
|
-
|
|
455
|
+
`Could not run pnpm ${script} because neither corepack nor pnpm is available. Install Node.js with corepack enabled, or install pnpm and rerun the command.`
|
|
424
456
|
);
|
|
425
457
|
}
|
|
426
458
|
}
|
|
459
|
+
async function hasPrepScript(root) {
|
|
460
|
+
let path = join(root, "package.json");
|
|
461
|
+
let source = await readFile(path, "utf8");
|
|
462
|
+
let pkg = JSON.parse(source);
|
|
463
|
+
return typeof pkg.scripts?.prep === "string" && pkg.scripts.prep.length > 0;
|
|
464
|
+
}
|
|
427
465
|
function getErrorCode(error) {
|
|
428
466
|
return error?.code;
|
|
429
467
|
}
|
|
@@ -538,6 +576,8 @@ function getHelpText(command) {
|
|
|
538
576
|
` ${c.bold("Examples:")}`,
|
|
539
577
|
` ${c.dim("$")} gistajs create my-app`,
|
|
540
578
|
` ${c.dim("$")} gistajs create my-app --starter website`,
|
|
579
|
+
"",
|
|
580
|
+
` Some starters offer an optional setup step after dependencies install.`,
|
|
541
581
|
""
|
|
542
582
|
].join("\n");
|
|
543
583
|
}
|
|
@@ -604,6 +644,9 @@ function getHelpText(command) {
|
|
|
604
644
|
` ${c.bold("Examples:")}`,
|
|
605
645
|
` ${c.dim("$")} gistajs create my-app`,
|
|
606
646
|
` ${c.dim("$")} gistajs create my-app --starter website`,
|
|
647
|
+
"",
|
|
648
|
+
` Some starters offer an optional setup step after dependencies install.`,
|
|
649
|
+
"",
|
|
607
650
|
` ${c.dim("$")} gistajs diff --latest`,
|
|
608
651
|
` ${c.dim("$")} gistajs diff --latest --stat`,
|
|
609
652
|
` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001`,
|
|
@@ -782,8 +825,41 @@ function getErrorMessage(error) {
|
|
|
782
825
|
}
|
|
783
826
|
|
|
784
827
|
// src/commands/pin.ts
|
|
785
|
-
import {
|
|
828
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
829
|
+
import { join as join4 } from "path";
|
|
830
|
+
|
|
831
|
+
// src/utils/package.ts
|
|
832
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
786
833
|
import { join as join3 } from "path";
|
|
834
|
+
async function readProjectPackage(root, readFileFn = (p, e) => readFile2(p, e)) {
|
|
835
|
+
let path = join3(root, "package.json");
|
|
836
|
+
let source;
|
|
837
|
+
try {
|
|
838
|
+
source = await readFileFn(path, "utf8");
|
|
839
|
+
} catch (error) {
|
|
840
|
+
let code = error.code;
|
|
841
|
+
if (code === "ENOENT") {
|
|
842
|
+
throw new Error(
|
|
843
|
+
"No package.json found. Run this from a Gista.js project directory."
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
throw error;
|
|
847
|
+
}
|
|
848
|
+
try {
|
|
849
|
+
let pkg = JSON.parse(source);
|
|
850
|
+
if (!pkg || typeof pkg !== "object" || Array.isArray(pkg)) {
|
|
851
|
+
throw new Error("package.json must contain a JSON object");
|
|
852
|
+
}
|
|
853
|
+
return pkg;
|
|
854
|
+
} catch (error) {
|
|
855
|
+
if (error instanceof SyntaxError) {
|
|
856
|
+
throw new Error("Could not parse package.json in the current directory.");
|
|
857
|
+
}
|
|
858
|
+
throw error;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// src/commands/pin.ts
|
|
787
863
|
function parsePinArgs(argv) {
|
|
788
864
|
let options = {};
|
|
789
865
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -845,34 +921,12 @@ async function writeProjectStarterPin(root, pin) {
|
|
|
845
921
|
let gistajs = pkg.gistajs && typeof pkg.gistajs === "object" && !Array.isArray(pkg.gistajs) ? { ...pkg.gistajs } : {};
|
|
846
922
|
gistajs.pin = parsed.pin;
|
|
847
923
|
await writeFile2(
|
|
848
|
-
|
|
924
|
+
join4(root, "package.json"),
|
|
849
925
|
`${JSON.stringify({ ...pkg, gistajs }, null, 2)}
|
|
850
926
|
`
|
|
851
927
|
);
|
|
852
928
|
return parsed;
|
|
853
929
|
}
|
|
854
|
-
async function readProjectPackage(root) {
|
|
855
|
-
let path = join3(root, "package.json");
|
|
856
|
-
let source;
|
|
857
|
-
try {
|
|
858
|
-
source = await readFile2(path, "utf8");
|
|
859
|
-
} catch (error) {
|
|
860
|
-
if (error?.code === "ENOENT") {
|
|
861
|
-
throw new Error(`Could not find package.json in ${root}`);
|
|
862
|
-
}
|
|
863
|
-
throw error;
|
|
864
|
-
}
|
|
865
|
-
try {
|
|
866
|
-
let pkg = JSON.parse(source);
|
|
867
|
-
if (!pkg || typeof pkg !== "object" || Array.isArray(pkg)) {
|
|
868
|
-
throw new Error("package.json must contain a JSON object");
|
|
869
|
-
}
|
|
870
|
-
return pkg;
|
|
871
|
-
} catch (error) {
|
|
872
|
-
let message = error instanceof Error ? error.message : String(error);
|
|
873
|
-
throw new Error(`Invalid package.json: ${message}`);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
930
|
|
|
877
931
|
// src/providers/regions.ts
|
|
878
932
|
var sharedRegions = [
|
|
@@ -916,11 +970,6 @@ function getSharedRegion(value) {
|
|
|
916
970
|
function getDefaultSharedRegion() {
|
|
917
971
|
return getSharedRegion(defaultSharedRegionId);
|
|
918
972
|
}
|
|
919
|
-
function parseSharedRegion(value) {
|
|
920
|
-
let normalized = value.trim().toLowerCase();
|
|
921
|
-
if (!normalized) return null;
|
|
922
|
-
return getSharedRegion(normalized);
|
|
923
|
-
}
|
|
924
973
|
|
|
925
974
|
// src/utils/version.ts
|
|
926
975
|
function satisfiesVersion(version, range) {
|
|
@@ -1050,7 +1099,7 @@ async function runProviderProvision(provider, deps) {
|
|
|
1050
1099
|
if (provider !== "turso" && provider !== "vercel") {
|
|
1051
1100
|
throw new UsageError(`Unknown provider: ${provider}`, "provision");
|
|
1052
1101
|
}
|
|
1053
|
-
let pkg = await
|
|
1102
|
+
let pkg = await readProvisionPackage(deps);
|
|
1054
1103
|
let region = await resolveProjectRegion(pkg, deps);
|
|
1055
1104
|
await writeProjectRegion(pkg, region.id, deps);
|
|
1056
1105
|
if (provider === "turso") {
|
|
@@ -1063,7 +1112,7 @@ async function runProviderProvision(provider, deps) {
|
|
|
1063
1112
|
}
|
|
1064
1113
|
}
|
|
1065
1114
|
async function runProjectProvision(deps) {
|
|
1066
|
-
let pkg = await
|
|
1115
|
+
let pkg = await readProvisionPackage(deps);
|
|
1067
1116
|
let providers = pkg.gistajs?.providers;
|
|
1068
1117
|
if (!providers?.length) {
|
|
1069
1118
|
throw new Error(
|
|
@@ -1101,23 +1150,8 @@ async function runProjectProvision(deps) {
|
|
|
1101
1150
|
}
|
|
1102
1151
|
printSummary(summary, deps);
|
|
1103
1152
|
}
|
|
1104
|
-
async function
|
|
1105
|
-
|
|
1106
|
-
try {
|
|
1107
|
-
let file = await deps.readFile(path, "utf8");
|
|
1108
|
-
return JSON.parse(file);
|
|
1109
|
-
} catch (error) {
|
|
1110
|
-
let code = error.code;
|
|
1111
|
-
if (code === "ENOENT") {
|
|
1112
|
-
throw new Error(
|
|
1113
|
-
"No package.json found. Run this from a Gista.js project directory."
|
|
1114
|
-
);
|
|
1115
|
-
}
|
|
1116
|
-
if (error instanceof SyntaxError) {
|
|
1117
|
-
throw new Error("Could not parse package.json in the current directory.");
|
|
1118
|
-
}
|
|
1119
|
-
throw error;
|
|
1120
|
-
}
|
|
1153
|
+
async function readProvisionPackage(deps) {
|
|
1154
|
+
return await readProjectPackage(deps.cwd, deps.readFile);
|
|
1121
1155
|
}
|
|
1122
1156
|
async function writeProjectRegion(pkg, region, deps) {
|
|
1123
1157
|
let nextPkg = {
|
|
@@ -1146,7 +1180,7 @@ async function resolveProjectRegion(pkg, deps) {
|
|
|
1146
1180
|
}
|
|
1147
1181
|
while (true) {
|
|
1148
1182
|
let answer = await deps.promptText(`Region (${fallback.label}): `);
|
|
1149
|
-
let selected =
|
|
1183
|
+
let selected = getSharedRegion(answer.trim() || fallback.id);
|
|
1150
1184
|
if (selected) return selected;
|
|
1151
1185
|
deps.stdout.log(`Invalid region. Choose from: ${labels}`);
|
|
1152
1186
|
}
|
|
@@ -1184,8 +1218,37 @@ import process5 from "process";
|
|
|
1184
1218
|
|
|
1185
1219
|
// src/providers/turso.ts
|
|
1186
1220
|
import { cp as cp2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
1187
|
-
import { basename as basename2, join as
|
|
1221
|
+
import { basename as basename2, join as join5 } from "path";
|
|
1188
1222
|
import process3 from "process";
|
|
1223
|
+
|
|
1224
|
+
// src/utils/env.ts
|
|
1225
|
+
function getEnvVar(file, key) {
|
|
1226
|
+
return file.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.trim() ?? "";
|
|
1227
|
+
}
|
|
1228
|
+
function setEnvVar(file, key, value) {
|
|
1229
|
+
if (file.match(new RegExp(`^${key}=.*$`, "m"))) {
|
|
1230
|
+
return file.replace(new RegExp(`^${key}=.*$`, "m"), `${key}=${value}`);
|
|
1231
|
+
}
|
|
1232
|
+
return `${file.trimEnd()}
|
|
1233
|
+
${key}=${value}
|
|
1234
|
+
`;
|
|
1235
|
+
}
|
|
1236
|
+
function getRequiredEnvVar(file, key) {
|
|
1237
|
+
let value = getEnvVar(file, key);
|
|
1238
|
+
if (!value) {
|
|
1239
|
+
throw new Error(
|
|
1240
|
+
`Missing ${key} in .env. Provision Turso and prep the app first.`
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
return value;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// src/utils/table.ts
|
|
1247
|
+
function parseFirstColumn(table) {
|
|
1248
|
+
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => line.split(/\s+/)[0]).filter(Boolean);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// src/providers/turso.ts
|
|
1189
1252
|
var defaultDeps2 = {
|
|
1190
1253
|
run,
|
|
1191
1254
|
runOutput,
|
|
@@ -1203,8 +1266,8 @@ async function provisionTurso(cwd, region, deps = defaultDeps2) {
|
|
|
1203
1266
|
"`gistajs provision turso` requires an interactive terminal"
|
|
1204
1267
|
);
|
|
1205
1268
|
}
|
|
1206
|
-
let envPath =
|
|
1207
|
-
let envExamplePath =
|
|
1269
|
+
let envPath = join5(cwd, ".env");
|
|
1270
|
+
let envExamplePath = join5(cwd, ".env.example");
|
|
1208
1271
|
let file = await ensureEnvFile(envPath, envExamplePath, deps);
|
|
1209
1272
|
let currentUrl = getEnvVar(file, "DB_URL");
|
|
1210
1273
|
let currentToken = getEnvVar(file, "DB_AUTH_TOKEN");
|
|
@@ -1228,7 +1291,7 @@ async function provisionTurso(cwd, region, deps = defaultDeps2) {
|
|
|
1228
1291
|
}
|
|
1229
1292
|
}
|
|
1230
1293
|
await assertCommand(
|
|
1231
|
-
deps,
|
|
1294
|
+
deps.run,
|
|
1232
1295
|
cwd,
|
|
1233
1296
|
"turso",
|
|
1234
1297
|
["auth", "status"],
|
|
@@ -1317,31 +1380,6 @@ async function ensureEnvFile(envPath, envExamplePath, deps) {
|
|
|
1317
1380
|
deps.stdout.log("Created empty .env");
|
|
1318
1381
|
return "";
|
|
1319
1382
|
}
|
|
1320
|
-
async function assertCommand(deps, cwd, command, args, failureMessage) {
|
|
1321
|
-
try {
|
|
1322
|
-
await deps.run(command, args, cwd);
|
|
1323
|
-
} catch (error) {
|
|
1324
|
-
let code = error.code;
|
|
1325
|
-
if (code === "ENOENT") {
|
|
1326
|
-
throw new Error(`Required command not found: ${command}`);
|
|
1327
|
-
}
|
|
1328
|
-
throw new Error(failureMessage);
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
function getEnvVar(file, key) {
|
|
1332
|
-
return file.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.trim() ?? "";
|
|
1333
|
-
}
|
|
1334
|
-
function setEnvVar(file, key, value) {
|
|
1335
|
-
if (file.match(new RegExp(`^${key}=.*$`, "m"))) {
|
|
1336
|
-
return file.replace(new RegExp(`^${key}=.*$`, "m"), `${key}=${value}`);
|
|
1337
|
-
}
|
|
1338
|
-
return `${file.trimEnd()}
|
|
1339
|
-
${key}=${value}
|
|
1340
|
-
`;
|
|
1341
|
-
}
|
|
1342
|
-
function parseFirstColumn(table) {
|
|
1343
|
-
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => line.split(/\s+/)[0]).filter(Boolean);
|
|
1344
|
-
}
|
|
1345
1383
|
function parseGroupTable(table) {
|
|
1346
1384
|
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
1347
1385
|
let parts = line.split(/\s+/);
|
|
@@ -1372,7 +1410,7 @@ function matchesRegion(location, region) {
|
|
|
1372
1410
|
// src/providers/vercel.ts
|
|
1373
1411
|
import { existsSync } from "fs";
|
|
1374
1412
|
import { readFile as readFileFs } from "fs/promises";
|
|
1375
|
-
import { join as
|
|
1413
|
+
import { join as join6 } from "path";
|
|
1376
1414
|
import process4 from "process";
|
|
1377
1415
|
var defaultDeps3 = {
|
|
1378
1416
|
run,
|
|
@@ -1390,23 +1428,23 @@ async function provisionVercel(cwd, region, deps = defaultDeps3) {
|
|
|
1390
1428
|
"`gistajs provision vercel` requires an interactive terminal"
|
|
1391
1429
|
);
|
|
1392
1430
|
}
|
|
1393
|
-
await
|
|
1394
|
-
deps,
|
|
1431
|
+
await assertCommand(
|
|
1432
|
+
deps.run,
|
|
1395
1433
|
cwd,
|
|
1396
1434
|
"vercel",
|
|
1397
1435
|
["whoami"],
|
|
1398
1436
|
"Not logged in. Run `vercel login` first."
|
|
1399
1437
|
);
|
|
1400
|
-
if (!deps.existsSync(
|
|
1438
|
+
if (!deps.existsSync(join6(cwd, ".vercel", "project.json"))) {
|
|
1401
1439
|
deps.stdout.log("Linking this directory to a Vercel project...");
|
|
1402
1440
|
await deps.run("vercel", ["link"], cwd);
|
|
1403
1441
|
}
|
|
1404
1442
|
deps.stdout.log(`Setting the Vercel function region to ${region.label}...`);
|
|
1405
1443
|
await deps.run("vercel", ["--regions", region.vercel], cwd);
|
|
1406
|
-
let envPath =
|
|
1444
|
+
let envPath = join6(cwd, ".env");
|
|
1407
1445
|
let file = await readEnvFile(envPath, deps);
|
|
1408
1446
|
let values = requiredEnvVars.map((key) => [key, getRequiredEnvVar(file, key)]);
|
|
1409
|
-
let existing =
|
|
1447
|
+
let existing = parseFirstColumn(
|
|
1410
1448
|
await deps.runOutput("vercel", ["env", "ls", "production"], cwd)
|
|
1411
1449
|
);
|
|
1412
1450
|
for (let [key, value] of values) {
|
|
@@ -1432,29 +1470,6 @@ async function readEnvFile(envPath, deps) {
|
|
|
1432
1470
|
throw error;
|
|
1433
1471
|
}
|
|
1434
1472
|
}
|
|
1435
|
-
async function assertCommand2(deps, cwd, command, args, failureMessage) {
|
|
1436
|
-
try {
|
|
1437
|
-
await deps.run(command, args, cwd);
|
|
1438
|
-
} catch (error) {
|
|
1439
|
-
let code = error.code;
|
|
1440
|
-
if (code === "ENOENT") {
|
|
1441
|
-
throw new Error(`Required command not found: ${command}`);
|
|
1442
|
-
}
|
|
1443
|
-
throw new Error(failureMessage);
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
function getRequiredEnvVar(file, key) {
|
|
1447
|
-
let value = file.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.trim();
|
|
1448
|
-
if (!value) {
|
|
1449
|
-
throw new Error(
|
|
1450
|
-
`Missing ${key} in .env. Provision Turso and prep the app first.`
|
|
1451
|
-
);
|
|
1452
|
-
}
|
|
1453
|
-
return value;
|
|
1454
|
-
}
|
|
1455
|
-
function parseFirstColumn2(table) {
|
|
1456
|
-
return table.trim().split("\n").slice(1).map((line) => line.trim()).filter(Boolean).map((line) => line.split(/\s+/)[0]).filter(Boolean);
|
|
1457
|
-
}
|
|
1458
1473
|
|
|
1459
1474
|
// src/utils/catalog.ts
|
|
1460
1475
|
var DEFAULT_CATALOG_URL = "https://gistajs.com/manifests/starters.json";
|
|
@@ -1491,7 +1506,7 @@ async function readCliVersion() {
|
|
|
1491
1506
|
if (false) {
|
|
1492
1507
|
throw new Error("Could not resolve the installed gistajs version");
|
|
1493
1508
|
}
|
|
1494
|
-
return "0.1.
|
|
1509
|
+
return "0.1.7";
|
|
1495
1510
|
}
|
|
1496
1511
|
async function readDefaultProvisionRegion() {
|
|
1497
1512
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gistajs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Scaffold and manage Gista.js starter projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"test": "vitest run",
|
|
54
54
|
"test:watch": "vitest",
|
|
55
55
|
"typecheck": "tsc -b",
|
|
56
|
-
"release:prepare": "pnpm typecheck && pnpm
|
|
56
|
+
"release:prepare": "pnpm typecheck && pnpm test",
|
|
57
57
|
"np": "pnpm release:prepare && np"
|
|
58
58
|
}
|
|
59
59
|
}
|