vela 0.11.1 → 0.11.3
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 +1 -0
- package/dist/bin.js +819 -562
- package/dist/bin.js.map +4 -4
- package/package.json +3 -2
- package/templates/minimal/template.json +2 -1
- package/templates/static/template.json +2 -1
package/dist/bin.js
CHANGED
|
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.11.
|
|
24
|
+
version: "0.11.3",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -55,7 +55,7 @@ var package_default = {
|
|
|
55
55
|
dependencies: {
|
|
56
56
|
"@clack/prompts": "^1.7.0",
|
|
57
57
|
"@faker-js/faker": "^10.6.0",
|
|
58
|
-
"@velastack/patterns": "^0.2.
|
|
58
|
+
"@velastack/patterns": "^0.2.3",
|
|
59
59
|
"@velastack/pocketbase-codegen": "^0.1.0",
|
|
60
60
|
"annotate-json-schema": "^0.1.0",
|
|
61
61
|
commander: "^13.1.0",
|
|
@@ -71,6 +71,7 @@ var package_default = {
|
|
|
71
71
|
"pocketbase-server": "^0.39.11",
|
|
72
72
|
stripe: "^19.3.0",
|
|
73
73
|
svelte: "^5.56.10",
|
|
74
|
+
tar: "^7.5.22",
|
|
74
75
|
tinyexec: "^1.3.0",
|
|
75
76
|
"ts-morph": "^28.0.0",
|
|
76
77
|
valibot: "^1.4.2"
|
|
@@ -236,6 +237,7 @@ var API_URL = (process2.env.VELA_API_URL?.trim() || "https://velastack.dev").rep
|
|
|
236
237
|
""
|
|
237
238
|
);
|
|
238
239
|
var FIXTURE_PREFIX = "vela";
|
|
240
|
+
var TEMPLATE_INDEX_URL = process2.env.VELA_TEMPLATE_INDEX_URL?.trim() || "https://templates.velastack.app/index.json";
|
|
239
241
|
|
|
240
242
|
// src/lib/package-json.ts
|
|
241
243
|
import fs from "node:fs";
|
|
@@ -286,8 +288,8 @@ function mergePackageJson(user, template) {
|
|
|
286
288
|
}
|
|
287
289
|
return { merged, added, conflicts, replaced };
|
|
288
290
|
}
|
|
289
|
-
function readPackageJson(
|
|
290
|
-
return JSON.parse(fs.readFileSync(
|
|
291
|
+
function readPackageJson(path46) {
|
|
292
|
+
return JSON.parse(fs.readFileSync(path46, "utf8"));
|
|
291
293
|
}
|
|
292
294
|
var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
|
|
293
295
|
var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
|
|
@@ -300,12 +302,12 @@ function fillTemplatePlaceholders(raw, values) {
|
|
|
300
302
|
function escapeSingleQuoted(value) {
|
|
301
303
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
302
304
|
}
|
|
303
|
-
function readTemplatePackageJson(
|
|
304
|
-
const raw = fillTemplatePlaceholders(fs.readFileSync(
|
|
305
|
+
function readTemplatePackageJson(path46, values) {
|
|
306
|
+
const raw = fillTemplatePlaceholders(fs.readFileSync(path46, "utf8"), values);
|
|
305
307
|
return JSON.parse(raw);
|
|
306
308
|
}
|
|
307
|
-
function writePackageJson(
|
|
308
|
-
fs.writeFileSync(
|
|
309
|
+
function writePackageJson(path46, pkg) {
|
|
310
|
+
fs.writeFileSync(path46, JSON.stringify(pkg, null, " ") + "\n");
|
|
309
311
|
}
|
|
310
312
|
function toValidPackageName(name) {
|
|
311
313
|
return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
|
|
@@ -383,10 +385,10 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
|
|
|
383
385
|
}
|
|
384
386
|
|
|
385
387
|
// src/commands/bless.ts
|
|
386
|
-
import
|
|
387
|
-
import
|
|
388
|
-
import
|
|
389
|
-
import * as
|
|
388
|
+
import fs15 from "node:fs";
|
|
389
|
+
import path13 from "node:path";
|
|
390
|
+
import process7 from "node:process";
|
|
391
|
+
import * as v3 from "valibot";
|
|
390
392
|
import { Command as Command2 } from "commander";
|
|
391
393
|
import * as p4 from "@clack/prompts";
|
|
392
394
|
import pc3 from "picocolors";
|
|
@@ -420,32 +422,279 @@ function toFlag(key) {
|
|
|
420
422
|
}
|
|
421
423
|
|
|
422
424
|
// src/lib/templates.ts
|
|
425
|
+
import fs6 from "node:fs";
|
|
426
|
+
import path5 from "node:path";
|
|
427
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
428
|
+
|
|
429
|
+
// src/lib/template-files.ts
|
|
423
430
|
import fs3 from "node:fs";
|
|
424
431
|
import path2 from "node:path";
|
|
432
|
+
var PUBLISH_SAFE_NAMES = {
|
|
433
|
+
".gitignore": "_gitignore",
|
|
434
|
+
".npmrc": "_npmrc"
|
|
435
|
+
};
|
|
436
|
+
function templateName(projectRelPath) {
|
|
437
|
+
const safe = PUBLISH_SAFE_NAMES[path2.basename(projectRelPath)];
|
|
438
|
+
if (!safe) return projectRelPath;
|
|
439
|
+
const dir = path2.dirname(projectRelPath);
|
|
440
|
+
return dir === "." ? safe : path2.join(dir, safe);
|
|
441
|
+
}
|
|
442
|
+
function restoreTemplateNames(target) {
|
|
443
|
+
for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
|
|
444
|
+
const from = path2.join(target, safe);
|
|
445
|
+
if (!fs3.existsSync(from)) continue;
|
|
446
|
+
fs3.renameSync(from, path2.join(target, real));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
|
|
450
|
+
function applyTemplateFiles(target, values) {
|
|
451
|
+
const written = [];
|
|
452
|
+
for (const source of findTemplateSources(target)) {
|
|
453
|
+
const raw = fs3.readFileSync(source, "utf8");
|
|
454
|
+
const dest = source.replace(TEMPLATE_SOURCE, ".$1");
|
|
455
|
+
fs3.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
|
|
456
|
+
fs3.unlinkSync(source);
|
|
457
|
+
written.push(path2.relative(target, dest));
|
|
458
|
+
}
|
|
459
|
+
return written.sort();
|
|
460
|
+
}
|
|
461
|
+
function findTemplateSources(dir) {
|
|
462
|
+
const found = [];
|
|
463
|
+
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
464
|
+
const full = path2.join(dir, entry.name);
|
|
465
|
+
if (entry.isDirectory()) {
|
|
466
|
+
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
467
|
+
found.push(...findTemplateSources(full));
|
|
468
|
+
} else if (entry.isFile() && TEMPLATE_SOURCE.test(entry.name)) {
|
|
469
|
+
found.push(full);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return found;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/lib/template-registry.ts
|
|
476
|
+
import fs5 from "node:fs";
|
|
477
|
+
import os2 from "node:os";
|
|
478
|
+
import path4 from "node:path";
|
|
479
|
+
import { createHash } from "node:crypto";
|
|
425
480
|
import { fileURLToPath } from "node:url";
|
|
481
|
+
import * as v2 from "valibot";
|
|
482
|
+
import * as tar from "tar";
|
|
483
|
+
|
|
484
|
+
// src/lib/config.ts
|
|
485
|
+
import fs4 from "node:fs";
|
|
486
|
+
import os from "node:os";
|
|
487
|
+
import path3 from "node:path";
|
|
488
|
+
import process4 from "node:process";
|
|
489
|
+
function configDir() {
|
|
490
|
+
return path3.join(os.homedir(), ".vela");
|
|
491
|
+
}
|
|
492
|
+
var CONFIG_DIR = configDir();
|
|
493
|
+
var CONFIG_PATH = path3.join(CONFIG_DIR, "config.json");
|
|
494
|
+
function readConfig() {
|
|
495
|
+
if (!fs4.existsSync(CONFIG_PATH)) return null;
|
|
496
|
+
try {
|
|
497
|
+
return JSON.parse(fs4.readFileSync(CONFIG_PATH, "utf8"));
|
|
498
|
+
} catch {
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function writeConfig(config) {
|
|
503
|
+
fs4.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
504
|
+
fs4.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
505
|
+
}
|
|
506
|
+
function clearConfig() {
|
|
507
|
+
if (fs4.existsSync(CONFIG_PATH)) fs4.unlinkSync(CONFIG_PATH);
|
|
508
|
+
}
|
|
509
|
+
function readApiKey() {
|
|
510
|
+
const fromEnv = process4.env.VELA_API_KEY?.trim();
|
|
511
|
+
if (fromEnv) return fromEnv;
|
|
512
|
+
return readConfig()?.apiKey ?? null;
|
|
513
|
+
}
|
|
514
|
+
function requireApiKey() {
|
|
515
|
+
const apiKey = readApiKey();
|
|
516
|
+
if (!apiKey) {
|
|
517
|
+
throw new Error("Not logged in. Run `vela login` to login, or set VELA_API_KEY.");
|
|
518
|
+
}
|
|
519
|
+
return apiKey;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/lib/template-registry.ts
|
|
523
|
+
var CACHE_DIR_NAME = "templates";
|
|
524
|
+
var INDEX_CACHE_FILE = "index.json";
|
|
525
|
+
var TARBALL_CACHE_DIR = "cache";
|
|
526
|
+
var INDEX_CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
527
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
528
|
+
var entrySchema = v2.object({
|
|
529
|
+
name: v2.pipe(v2.string(), v2.regex(/^[a-z0-9][a-z0-9-]*$/)),
|
|
530
|
+
description: v2.string(),
|
|
531
|
+
backend: v2.boolean(),
|
|
532
|
+
title: v2.optional(v2.string()),
|
|
533
|
+
category: v2.optional(v2.string()),
|
|
534
|
+
tags: v2.optional(v2.array(v2.string())),
|
|
535
|
+
price: v2.optional(v2.number()),
|
|
536
|
+
previewUrl: v2.optional(v2.string()),
|
|
537
|
+
nextSteps: v2.optional(v2.array(v2.string())),
|
|
538
|
+
/** Tarball location, relative to the index URL. */
|
|
539
|
+
file: v2.string(),
|
|
540
|
+
sha256: v2.pipe(v2.string(), v2.regex(/^[0-9a-f]{64}$/)),
|
|
541
|
+
size: v2.optional(v2.number()),
|
|
542
|
+
version: v2.optional(v2.string())
|
|
543
|
+
});
|
|
544
|
+
var indexSchema = v2.object({
|
|
545
|
+
schemaVersion: v2.literal(1),
|
|
546
|
+
templates: v2.array(v2.unknown())
|
|
547
|
+
});
|
|
548
|
+
function cacheRoot() {
|
|
549
|
+
return path4.join(configDir(), CACHE_DIR_NAME);
|
|
550
|
+
}
|
|
551
|
+
function indexCachePath() {
|
|
552
|
+
return path4.join(cacheRoot(), INDEX_CACHE_FILE);
|
|
553
|
+
}
|
|
554
|
+
function readCachedIndex(url) {
|
|
555
|
+
const file = indexCachePath();
|
|
556
|
+
if (!fs5.existsSync(file)) return null;
|
|
557
|
+
try {
|
|
558
|
+
const cached2 = JSON.parse(fs5.readFileSync(file, "utf8"));
|
|
559
|
+
if (cached2.url !== url) return null;
|
|
560
|
+
return cached2;
|
|
561
|
+
} catch {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function writeCachedIndex(cached2) {
|
|
566
|
+
fs5.mkdirSync(cacheRoot(), { recursive: true });
|
|
567
|
+
fs5.writeFileSync(indexCachePath(), JSON.stringify(cached2, null, 2));
|
|
568
|
+
}
|
|
569
|
+
function parseTemplateIndex(text18, url) {
|
|
570
|
+
let parsed;
|
|
571
|
+
try {
|
|
572
|
+
parsed = JSON.parse(text18);
|
|
573
|
+
} catch (e) {
|
|
574
|
+
throw new Error(`Template index at ${url} is not valid JSON: ${e.message}`);
|
|
575
|
+
}
|
|
576
|
+
const doc = v2.safeParse(indexSchema, parsed);
|
|
577
|
+
if (!doc.success) {
|
|
578
|
+
throw new Error(`Template index at ${url} has an unsupported format`);
|
|
579
|
+
}
|
|
580
|
+
const templates = [];
|
|
581
|
+
let skipped = 0;
|
|
582
|
+
for (const raw of doc.output.templates) {
|
|
583
|
+
const entry = v2.safeParse(entrySchema, raw);
|
|
584
|
+
if (entry.success) templates.push(entry.output);
|
|
585
|
+
else skipped++;
|
|
586
|
+
}
|
|
587
|
+
return { url, templates, skipped };
|
|
588
|
+
}
|
|
589
|
+
function isFileUrl(url) {
|
|
590
|
+
return url.startsWith("file:");
|
|
591
|
+
}
|
|
592
|
+
async function readBytes(url, options) {
|
|
593
|
+
if (isFileUrl(url)) {
|
|
594
|
+
return new Uint8Array(fs5.readFileSync(fileURLToPath(url)));
|
|
595
|
+
}
|
|
596
|
+
const res = await fetch(url, {
|
|
597
|
+
headers: options.headers,
|
|
598
|
+
signal: AbortSignal.timeout(options.timeoutMs)
|
|
599
|
+
});
|
|
600
|
+
if (!res.ok) {
|
|
601
|
+
throw new Error(`${res.status} ${res.statusText}`.trim());
|
|
602
|
+
}
|
|
603
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
604
|
+
}
|
|
605
|
+
async function fetchTemplateIndex(url, options = {}) {
|
|
606
|
+
const now = options.now ?? Date.now();
|
|
607
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
608
|
+
const cached2 = options.noCache ? null : readCachedIndex(url);
|
|
609
|
+
if (cached2 && now - cached2.fetchedAt < INDEX_CACHE_TTL_MS && !isFileUrl(url)) {
|
|
610
|
+
return { index: cached2.index, stale: false };
|
|
611
|
+
}
|
|
612
|
+
try {
|
|
613
|
+
const bytes = await readBytes(url, { timeoutMs, headers: options.headers });
|
|
614
|
+
const index = parseTemplateIndex(Buffer.from(bytes).toString("utf8"), url);
|
|
615
|
+
if (!options.noCache && !isFileUrl(url)) {
|
|
616
|
+
writeCachedIndex({ url, fetchedAt: now, index });
|
|
617
|
+
}
|
|
618
|
+
return { index, stale: false };
|
|
619
|
+
} catch (e) {
|
|
620
|
+
const reason = e.message;
|
|
621
|
+
if (cached2) return { index: cached2.index, stale: true, reason };
|
|
622
|
+
return { index: null, stale: false, reason };
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function resolveDownloadUrl(entry, indexUrl) {
|
|
626
|
+
return new URL(entry.file, indexUrl).href;
|
|
627
|
+
}
|
|
628
|
+
function sha256(bytes) {
|
|
629
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
630
|
+
}
|
|
631
|
+
function tarballCachePath(entry) {
|
|
632
|
+
return path4.join(
|
|
633
|
+
cacheRoot(),
|
|
634
|
+
TARBALL_CACHE_DIR,
|
|
635
|
+
`${entry.name}-${entry.sha256.slice(0, 12)}.tgz`
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
async function downloadTemplate(entry, indexUrl, options = {}) {
|
|
639
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS * 6;
|
|
640
|
+
const cacheFile = tarballCachePath(entry);
|
|
641
|
+
let haveTarball = false;
|
|
642
|
+
if (fs5.existsSync(cacheFile)) {
|
|
643
|
+
const cached2 = new Uint8Array(fs5.readFileSync(cacheFile));
|
|
644
|
+
haveTarball = sha256(cached2) === entry.sha256;
|
|
645
|
+
}
|
|
646
|
+
if (!haveTarball) {
|
|
647
|
+
const url = resolveDownloadUrl(entry, indexUrl);
|
|
648
|
+
let fetched;
|
|
649
|
+
try {
|
|
650
|
+
fetched = await readBytes(url, { timeoutMs, headers: options.headers });
|
|
651
|
+
} catch (e) {
|
|
652
|
+
throw new Error(`Could not download template ${entry.name}: ${e.message}`);
|
|
653
|
+
}
|
|
654
|
+
const digest = sha256(fetched);
|
|
655
|
+
if (digest !== entry.sha256) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
`Downloaded template ${entry.name} did not match its checksum (expected ${entry.sha256}, got ${digest}). Try again, or set VELA_TEMPLATE_INDEX_URL to a registry you trust.`
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
fs5.mkdirSync(path4.dirname(cacheFile), { recursive: true });
|
|
661
|
+
fs5.writeFileSync(cacheFile, fetched);
|
|
662
|
+
}
|
|
663
|
+
const dir = fs5.mkdtempSync(path4.join(os2.tmpdir(), `vela-template-${entry.name}-`));
|
|
664
|
+
try {
|
|
665
|
+
await tar.extract({ file: cacheFile, cwd: dir, strip: 1 });
|
|
666
|
+
} catch (e) {
|
|
667
|
+
fs5.rmSync(dir, { recursive: true, force: true });
|
|
668
|
+
throw new Error(`Could not unpack template ${entry.name}: ${e.message}`);
|
|
669
|
+
}
|
|
670
|
+
return dir;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// src/lib/templates.ts
|
|
426
674
|
var TEMPLATE_MANIFEST = "template.json";
|
|
427
675
|
var DEFAULT_TEMPLATE = "minimal";
|
|
676
|
+
var DEFAULT_CATEGORY = "starter";
|
|
428
677
|
var cached;
|
|
429
678
|
function templatesDir() {
|
|
430
|
-
let dir =
|
|
431
|
-
const { root } =
|
|
679
|
+
let dir = path5.dirname(fileURLToPath2(import.meta.url));
|
|
680
|
+
const { root } = path5.parse(dir);
|
|
432
681
|
while (dir !== root) {
|
|
433
|
-
const candidate =
|
|
682
|
+
const candidate = path5.join(dir, "templates");
|
|
434
683
|
if (holdsManifest(candidate)) return candidate;
|
|
435
|
-
dir =
|
|
684
|
+
dir = path5.dirname(dir);
|
|
436
685
|
}
|
|
437
686
|
throw new Error("Could not locate the templates directory");
|
|
438
687
|
}
|
|
439
688
|
function holdsManifest(dir) {
|
|
440
|
-
if (!
|
|
441
|
-
return
|
|
442
|
-
(entry) => entry.isDirectory() &&
|
|
689
|
+
if (!fs6.existsSync(dir)) return false;
|
|
690
|
+
return fs6.readdirSync(dir, { withFileTypes: true }).some(
|
|
691
|
+
(entry) => entry.isDirectory() && fs6.existsSync(path5.join(dir, entry.name, TEMPLATE_MANIFEST))
|
|
443
692
|
);
|
|
444
693
|
}
|
|
445
694
|
function listProjectTemplates() {
|
|
446
695
|
if (cached) return cached;
|
|
447
696
|
const root = templatesDir();
|
|
448
|
-
cached =
|
|
697
|
+
cached = fs6.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readManifest(root, entry.name)).filter((template) => template !== void 0).sort((a, b) => a.name.localeCompare(b.name));
|
|
449
698
|
return cached;
|
|
450
699
|
}
|
|
451
700
|
function projectTemplateNames(options = {}) {
|
|
@@ -458,12 +707,84 @@ function findProjectTemplate(name) {
|
|
|
458
707
|
if (!template) throw new Error(`Template not found: ${name}`);
|
|
459
708
|
return template;
|
|
460
709
|
}
|
|
710
|
+
async function listAllTemplates(options = {}) {
|
|
711
|
+
const indexUrl = options.indexUrl ?? TEMPLATE_INDEX_URL;
|
|
712
|
+
const builtin = listProjectTemplates();
|
|
713
|
+
const names = new Set(builtin.map((template) => template.name));
|
|
714
|
+
const templates = [...builtin];
|
|
715
|
+
const result = await fetchTemplateIndex(indexUrl);
|
|
716
|
+
for (const entry of result.index?.templates ?? []) {
|
|
717
|
+
if (names.has(entry.name)) continue;
|
|
718
|
+
names.add(entry.name);
|
|
719
|
+
templates.push({
|
|
720
|
+
name: entry.name,
|
|
721
|
+
description: entry.description,
|
|
722
|
+
backend: entry.backend,
|
|
723
|
+
source: "remote",
|
|
724
|
+
category: entry.category ?? DEFAULT_CATEGORY,
|
|
725
|
+
title: entry.title,
|
|
726
|
+
tags: entry.tags,
|
|
727
|
+
price: entry.price,
|
|
728
|
+
nextSteps: entry.nextSteps,
|
|
729
|
+
entry,
|
|
730
|
+
indexUrl
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
templates.sort(compareTemplates);
|
|
734
|
+
return result.index ? { templates } : { templates, registryError: result.reason };
|
|
735
|
+
}
|
|
736
|
+
function compareTemplates(a, b) {
|
|
737
|
+
if (a.category !== b.category) {
|
|
738
|
+
if (a.category === DEFAULT_CATEGORY) return -1;
|
|
739
|
+
if (b.category === DEFAULT_CATEGORY) return 1;
|
|
740
|
+
return a.category.localeCompare(b.category);
|
|
741
|
+
}
|
|
742
|
+
return a.name.localeCompare(b.name);
|
|
743
|
+
}
|
|
744
|
+
function findTemplate(listing, name) {
|
|
745
|
+
const template = listing.templates.find((candidate) => candidate.name === name);
|
|
746
|
+
if (!template) throw new Error(`Template not found: ${name}`);
|
|
747
|
+
return template;
|
|
748
|
+
}
|
|
749
|
+
function templateChoicesMessage(templates) {
|
|
750
|
+
const groups = /* @__PURE__ */ new Map();
|
|
751
|
+
for (const template of [...templates].sort(compareTemplates)) {
|
|
752
|
+
const names = groups.get(template.category) ?? [];
|
|
753
|
+
names.push(template.name);
|
|
754
|
+
groups.set(template.category, names);
|
|
755
|
+
}
|
|
756
|
+
return [...groups].map(([category, names]) => `${category}: ${names.join(", ")}`).join("; ");
|
|
757
|
+
}
|
|
758
|
+
async function resolveTemplate(template) {
|
|
759
|
+
if (!("entry" in template)) {
|
|
760
|
+
return { ...template, cleanup() {
|
|
761
|
+
} };
|
|
762
|
+
}
|
|
763
|
+
const { entry, indexUrl, ...info } = template;
|
|
764
|
+
const dir = await downloadTemplate(entry, indexUrl);
|
|
765
|
+
return {
|
|
766
|
+
...info,
|
|
767
|
+
dir,
|
|
768
|
+
cleanup() {
|
|
769
|
+
fs6.rmSync(dir, { recursive: true, force: true });
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
function copyTemplate(template, target) {
|
|
774
|
+
fs6.mkdirSync(target, { recursive: true });
|
|
775
|
+
fs6.cpSync(template.dir, target, {
|
|
776
|
+
recursive: true,
|
|
777
|
+
// The manifest describes the template to the CLI; it isn't part of the project.
|
|
778
|
+
filter: (src) => path5.basename(src) !== ".DS_Store" && path5.relative(template.dir, src) !== TEMPLATE_MANIFEST
|
|
779
|
+
});
|
|
780
|
+
restoreTemplateNames(target);
|
|
781
|
+
}
|
|
461
782
|
function readManifest(root, name) {
|
|
462
|
-
const manifestPath =
|
|
463
|
-
if (!
|
|
783
|
+
const manifestPath = path5.join(root, name, TEMPLATE_MANIFEST);
|
|
784
|
+
if (!fs6.existsSync(manifestPath)) return void 0;
|
|
464
785
|
let parsed;
|
|
465
786
|
try {
|
|
466
|
-
parsed = JSON.parse(
|
|
787
|
+
parsed = JSON.parse(fs6.readFileSync(manifestPath, "utf8"));
|
|
467
788
|
} catch (e) {
|
|
468
789
|
throw new Error(
|
|
469
790
|
`Template ${name} has an unreadable ${TEMPLATE_MANIFEST}: ${e.message}`
|
|
@@ -479,14 +800,28 @@ function readManifest(root, name) {
|
|
|
479
800
|
name,
|
|
480
801
|
description: manifest.description,
|
|
481
802
|
backend: manifest.backend,
|
|
482
|
-
|
|
803
|
+
source: "builtin",
|
|
804
|
+
category: optionalString(manifest.category) ?? DEFAULT_CATEGORY,
|
|
805
|
+
title: optionalString(manifest.title),
|
|
806
|
+
tags: optionalStringArray(manifest.tags),
|
|
807
|
+
price: typeof manifest.price === "number" ? manifest.price : void 0,
|
|
808
|
+
nextSteps: optionalStringArray(manifest.nextSteps),
|
|
809
|
+
dir: path5.join(root, name)
|
|
483
810
|
};
|
|
484
811
|
}
|
|
812
|
+
function optionalString(value) {
|
|
813
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
814
|
+
}
|
|
815
|
+
function optionalStringArray(value) {
|
|
816
|
+
if (!Array.isArray(value)) return void 0;
|
|
817
|
+
const strings = value.filter((item) => typeof item === "string");
|
|
818
|
+
return strings.length > 0 ? strings : void 0;
|
|
819
|
+
}
|
|
485
820
|
|
|
486
821
|
// src/lib/package-manager.ts
|
|
487
|
-
import
|
|
488
|
-
import
|
|
489
|
-
import
|
|
822
|
+
import fs7 from "node:fs";
|
|
823
|
+
import path6 from "node:path";
|
|
824
|
+
import process5 from "node:process";
|
|
490
825
|
import { exec } from "tinyexec";
|
|
491
826
|
import { Option } from "commander";
|
|
492
827
|
import * as p2 from "@clack/prompts";
|
|
@@ -502,7 +837,7 @@ var installOption = new Option(
|
|
|
502
837
|
"installs dependencies with a specified package manager"
|
|
503
838
|
).choices(AGENT_NAMES);
|
|
504
839
|
function getUserAgent() {
|
|
505
|
-
const userAgent =
|
|
840
|
+
const userAgent = process5.env.npm_config_user_agent;
|
|
506
841
|
if (!userAgent) return void 0;
|
|
507
842
|
const pmSpec = userAgent.split(" ")[0];
|
|
508
843
|
const separatorPos = pmSpec.lastIndexOf("/");
|
|
@@ -512,7 +847,7 @@ function getUserAgent() {
|
|
|
512
847
|
async function packageManagerPrompt(cwd) {
|
|
513
848
|
const detected = await detect({ cwd });
|
|
514
849
|
const agent = detected?.name ?? getUserAgent();
|
|
515
|
-
if (!
|
|
850
|
+
if (!process5.stdout.isTTY) return agent;
|
|
516
851
|
const options = [
|
|
517
852
|
{ label: "None", value: void 0 },
|
|
518
853
|
...AGENT_NAMES.map((pm2) => ({ value: pm2, label: pm2 }))
|
|
@@ -524,14 +859,14 @@ async function packageManagerPrompt(cwd) {
|
|
|
524
859
|
});
|
|
525
860
|
if (p2.isCancel(pm)) {
|
|
526
861
|
p2.cancel("Operation cancelled.");
|
|
527
|
-
|
|
862
|
+
process5.exit(1);
|
|
528
863
|
}
|
|
529
864
|
return pm;
|
|
530
865
|
}
|
|
531
866
|
async function installDependencies(agent, cwd) {
|
|
532
867
|
const task = p2.taskLog({
|
|
533
868
|
title: `Installing dependencies with ${agent}...`,
|
|
534
|
-
limit: Math.ceil(
|
|
869
|
+
limit: Math.ceil(process5.stdout.rows / 2),
|
|
535
870
|
spacing: 0,
|
|
536
871
|
retainLog: true
|
|
537
872
|
});
|
|
@@ -548,14 +883,14 @@ async function installDependencies(agent, cwd) {
|
|
|
548
883
|
} catch {
|
|
549
884
|
task.error("Failed to install dependencies");
|
|
550
885
|
p2.cancel("Operation failed.");
|
|
551
|
-
|
|
886
|
+
process5.exit(2);
|
|
552
887
|
}
|
|
553
888
|
}
|
|
554
889
|
function addPnpmBuildDependencies(cwd, packageManager, allowedPackages) {
|
|
555
890
|
if (!packageManager || packageManager !== "pnpm") return;
|
|
556
|
-
const pkgPath =
|
|
557
|
-
if (!
|
|
558
|
-
const pkg = JSON.parse(
|
|
891
|
+
const pkgPath = path6.join(cwd, "package.json");
|
|
892
|
+
if (!fs7.existsSync(pkgPath)) return;
|
|
893
|
+
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
559
894
|
pkg.pnpm ??= {};
|
|
560
895
|
pkg.pnpm.onlyBuiltDependencies ??= [];
|
|
561
896
|
for (const name of allowedPackages) {
|
|
@@ -563,14 +898,14 @@ function addPnpmBuildDependencies(cwd, packageManager, allowedPackages) {
|
|
|
563
898
|
pkg.pnpm.onlyBuiltDependencies.push(name);
|
|
564
899
|
}
|
|
565
900
|
}
|
|
566
|
-
|
|
901
|
+
fs7.writeFileSync(pkgPath, JSON.stringify(pkg, null, " ") + "\n");
|
|
567
902
|
}
|
|
568
903
|
|
|
569
904
|
// src/lib/pocketbase.ts
|
|
570
|
-
import
|
|
905
|
+
import fs8 from "node:fs";
|
|
571
906
|
import net from "node:net";
|
|
572
|
-
import
|
|
573
|
-
import
|
|
907
|
+
import path7 from "node:path";
|
|
908
|
+
import process6 from "node:process";
|
|
574
909
|
import { createRequire } from "node:module";
|
|
575
910
|
import { spawn } from "node:child_process";
|
|
576
911
|
import PocketBase from "pocketbase";
|
|
@@ -682,9 +1017,9 @@ async function authWithRetries(pb, email3, password11, attempts = 3) {
|
|
|
682
1017
|
}
|
|
683
1018
|
}
|
|
684
1019
|
function getPocketbaseMetadata(cwd) {
|
|
685
|
-
const metadataPath =
|
|
686
|
-
if (
|
|
687
|
-
return JSON.parse(
|
|
1020
|
+
const metadataPath = path7.join(cwd, "node_modules", ".vite", "_pocketbase_metadata.json");
|
|
1021
|
+
if (fs8.existsSync(metadataPath)) {
|
|
1022
|
+
return JSON.parse(fs8.readFileSync(metadataPath, "utf8"));
|
|
688
1023
|
}
|
|
689
1024
|
return null;
|
|
690
1025
|
}
|
|
@@ -697,12 +1032,12 @@ async function execPackageBin(cwd, args, stdio = "pipe") {
|
|
|
697
1032
|
return x(command, resolvedArgs, { nodeOptions: { cwd, stdio }, throwOnError: true });
|
|
698
1033
|
}
|
|
699
1034
|
async function withPocketbase(cwd, fn, creds) {
|
|
700
|
-
const dir =
|
|
701
|
-
const migrationsDir =
|
|
1035
|
+
const dir = path7.join(cwd, DATA_DIR);
|
|
1036
|
+
const migrationsDir = path7.join(cwd, MIGRATIONS_DIR);
|
|
702
1037
|
const host = "localhost";
|
|
703
|
-
const email3 = creds?.email ??
|
|
704
|
-
const password11 = creds?.password ??
|
|
705
|
-
if (!
|
|
1038
|
+
const email3 = creds?.email ?? process6.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
1039
|
+
const password11 = creds?.password ?? process6.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
1040
|
+
if (!fs8.existsSync(dir)) {
|
|
706
1041
|
throw new Error("PocketBase data directory does not exist");
|
|
707
1042
|
}
|
|
708
1043
|
const metadata = getPocketbaseMetadata(cwd);
|
|
@@ -727,10 +1062,10 @@ async function withPocketbase(cwd, fn, creds) {
|
|
|
727
1062
|
}
|
|
728
1063
|
}
|
|
729
1064
|
async function createSuperuser(cwd, email3, password11) {
|
|
730
|
-
const dir =
|
|
731
|
-
const migrationsDir =
|
|
732
|
-
|
|
733
|
-
|
|
1065
|
+
const dir = path7.join(cwd, DATA_DIR);
|
|
1066
|
+
const migrationsDir = path7.join(cwd, MIGRATIONS_DIR);
|
|
1067
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
1068
|
+
fs8.mkdirSync(migrationsDir, { recursive: true });
|
|
734
1069
|
await execPackageBin(
|
|
735
1070
|
cwd,
|
|
736
1071
|
[
|
|
@@ -755,8 +1090,8 @@ async function launchPocketbase(cwd, {
|
|
|
755
1090
|
password: password11
|
|
756
1091
|
}) {
|
|
757
1092
|
const host = "localhost";
|
|
758
|
-
|
|
759
|
-
|
|
1093
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
1094
|
+
fs8.mkdirSync(migrationsDir, { recursive: true });
|
|
760
1095
|
await execPackageBin(
|
|
761
1096
|
cwd,
|
|
762
1097
|
[
|
|
@@ -795,11 +1130,11 @@ function pocketbaseVersion() {
|
|
|
795
1130
|
return pkg.version;
|
|
796
1131
|
}
|
|
797
1132
|
async function ensureSuperuser(cwd) {
|
|
798
|
-
const email3 =
|
|
799
|
-
const password11 =
|
|
1133
|
+
const email3 = process6.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
1134
|
+
const password11 = process6.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
800
1135
|
if (!email3 || !password11) return;
|
|
801
|
-
const dir =
|
|
802
|
-
if (!
|
|
1136
|
+
const dir = path7.join(cwd, DATA_DIR);
|
|
1137
|
+
if (!fs8.existsSync(dir)) return;
|
|
803
1138
|
const { getBinaryPath } = await import("pocketbase-server");
|
|
804
1139
|
await x(
|
|
805
1140
|
getBinaryPath(),
|
|
@@ -807,7 +1142,7 @@ async function ensureSuperuser(cwd) {
|
|
|
807
1142
|
"--dir",
|
|
808
1143
|
dir,
|
|
809
1144
|
"--migrationsDir",
|
|
810
|
-
|
|
1145
|
+
path7.join(cwd, MIGRATIONS_DIR),
|
|
811
1146
|
"superuser",
|
|
812
1147
|
"upsert",
|
|
813
1148
|
email3,
|
|
@@ -818,8 +1153,8 @@ async function ensureSuperuser(cwd) {
|
|
|
818
1153
|
}
|
|
819
1154
|
|
|
820
1155
|
// src/lib/env.ts
|
|
821
|
-
import
|
|
822
|
-
import
|
|
1156
|
+
import fs9 from "node:fs";
|
|
1157
|
+
import path8 from "node:path";
|
|
823
1158
|
function addEnvVar(content, key, value) {
|
|
824
1159
|
if (content.includes(`${key}=`)) return content;
|
|
825
1160
|
return appendLine(content, `${key}=${value}`);
|
|
@@ -834,11 +1169,11 @@ function appendLine(existing, line) {
|
|
|
834
1169
|
return withNewline + line + "\n";
|
|
835
1170
|
}
|
|
836
1171
|
function writeEnvFile(cwd, vars, comments = []) {
|
|
837
|
-
const envPath =
|
|
838
|
-
let content =
|
|
1172
|
+
const envPath = path8.join(cwd, ".env");
|
|
1173
|
+
let content = fs9.existsSync(envPath) ? fs9.readFileSync(envPath, "utf8") : "";
|
|
839
1174
|
for (const comment of comments) content = addEnvComment(content, comment);
|
|
840
1175
|
for (const [key, value] of Object.entries(vars)) content = addEnvVar(content, key, value);
|
|
841
|
-
|
|
1176
|
+
fs9.writeFileSync(envPath, content);
|
|
842
1177
|
}
|
|
843
1178
|
function upsertEnvVar(content, key, value) {
|
|
844
1179
|
const line = `${key}=${quoteEnvValue(value)}`;
|
|
@@ -871,7 +1206,7 @@ function quoteEnvValue(value) {
|
|
|
871
1206
|
}
|
|
872
1207
|
|
|
873
1208
|
// src/lib/app-css.ts
|
|
874
|
-
import
|
|
1209
|
+
import fs10 from "node:fs";
|
|
875
1210
|
var SHADCN_TAILWIND_CSS = "shadcn-svelte/tailwind.css";
|
|
876
1211
|
var SHADCN_TAILWIND_IMPORT = `@import '${SHADCN_TAILWIND_CSS}';`;
|
|
877
1212
|
function hasShadcnImport(css) {
|
|
@@ -897,21 +1232,21 @@ ${css}`;
|
|
|
897
1232
|
return lines.join("\n");
|
|
898
1233
|
}
|
|
899
1234
|
function ensureShadcnImport(appCssPath) {
|
|
900
|
-
if (!
|
|
901
|
-
const css =
|
|
1235
|
+
if (!fs10.existsSync(appCssPath)) return false;
|
|
1236
|
+
const css = fs10.readFileSync(appCssPath, "utf8");
|
|
902
1237
|
if (hasShadcnImport(css)) return false;
|
|
903
|
-
|
|
1238
|
+
fs10.writeFileSync(appCssPath, insertShadcnImport(css));
|
|
904
1239
|
return true;
|
|
905
1240
|
}
|
|
906
1241
|
|
|
907
1242
|
// src/lib/components-json.ts
|
|
908
|
-
import
|
|
909
|
-
import
|
|
1243
|
+
import fs11 from "node:fs";
|
|
1244
|
+
import path9 from "node:path";
|
|
910
1245
|
function readComponentsJson(root) {
|
|
911
|
-
const file =
|
|
912
|
-
if (!
|
|
1246
|
+
const file = path9.join(root, "components.json");
|
|
1247
|
+
if (!fs11.existsSync(file)) return void 0;
|
|
913
1248
|
try {
|
|
914
|
-
const parsed = JSON.parse(
|
|
1249
|
+
const parsed = JSON.parse(fs11.readFileSync(file, "utf8"));
|
|
915
1250
|
return parsed && typeof parsed === "object" ? parsed : void 0;
|
|
916
1251
|
} catch {
|
|
917
1252
|
return void 0;
|
|
@@ -933,12 +1268,12 @@ function componentsJsonHints(config) {
|
|
|
933
1268
|
}
|
|
934
1269
|
|
|
935
1270
|
// src/lib/config-merge.ts
|
|
936
|
-
import
|
|
937
|
-
import
|
|
1271
|
+
import fs13 from "node:fs";
|
|
1272
|
+
import path11 from "node:path";
|
|
938
1273
|
|
|
939
1274
|
// src/lib/config-target.ts
|
|
940
|
-
import
|
|
941
|
-
import
|
|
1275
|
+
import fs12 from "node:fs";
|
|
1276
|
+
import path10 from "node:path";
|
|
942
1277
|
import {
|
|
943
1278
|
Project,
|
|
944
1279
|
QuoteKind,
|
|
@@ -958,8 +1293,8 @@ var SVELTE_CONFIG_CANDIDATES = [
|
|
|
958
1293
|
];
|
|
959
1294
|
function probeFirstExisting(root, candidates) {
|
|
960
1295
|
for (const rel of candidates) {
|
|
961
|
-
const abs =
|
|
962
|
-
if (
|
|
1296
|
+
const abs = path10.join(root, rel);
|
|
1297
|
+
if (fs12.existsSync(abs)) return abs;
|
|
963
1298
|
}
|
|
964
1299
|
return null;
|
|
965
1300
|
}
|
|
@@ -1035,7 +1370,7 @@ function mergeSvelteConfig(projectRoot) {
|
|
|
1035
1370
|
};
|
|
1036
1371
|
}
|
|
1037
1372
|
function mergeRunesIntoViteArg(vite, arg) {
|
|
1038
|
-
const file =
|
|
1373
|
+
const file = path11.basename(vite.filePath);
|
|
1039
1374
|
const compilerOptions = getOrCreateObjectLiteralProperty(arg, "compilerOptions", "{}");
|
|
1040
1375
|
if (!compilerOptions) {
|
|
1041
1376
|
return {
|
|
@@ -1054,8 +1389,8 @@ function mergeRunesIntoViteArg(vite, arg) {
|
|
|
1054
1389
|
return { applied: true, reason: "added runes compilerOption", file };
|
|
1055
1390
|
}
|
|
1056
1391
|
function mergeRunesIntoSvelteConfig(filePath) {
|
|
1057
|
-
const file =
|
|
1058
|
-
const original =
|
|
1392
|
+
const file = path11.basename(filePath);
|
|
1393
|
+
const original = fs13.readFileSync(filePath, "utf8");
|
|
1059
1394
|
if (/runes\s*:/m.test(original)) {
|
|
1060
1395
|
return { applied: false, reason: "runes already configured", file };
|
|
1061
1396
|
}
|
|
@@ -1078,11 +1413,11 @@ function mergeRunesIntoSvelteConfig(filePath) {
|
|
|
1078
1413
|
}
|
|
1079
1414
|
const insertAt = anchor.index + anchor[0].length;
|
|
1080
1415
|
const updated = original.slice(0, insertAt) + RUNES_SNIPPET + original.slice(insertAt);
|
|
1081
|
-
|
|
1416
|
+
fs13.writeFileSync(filePath, updated);
|
|
1082
1417
|
return { applied: true, reason: "added runes compilerOption", file };
|
|
1083
1418
|
}
|
|
1084
1419
|
function mergeViteConfig(filePath) {
|
|
1085
|
-
if (!
|
|
1420
|
+
if (!fs13.existsSync(filePath)) {
|
|
1086
1421
|
return {
|
|
1087
1422
|
applied: false,
|
|
1088
1423
|
reason: "vite.config.ts not found",
|
|
@@ -1090,7 +1425,7 @@ function mergeViteConfig(filePath) {
|
|
|
1090
1425
|
// then add tailwindcss() to the plugins array`
|
|
1091
1426
|
};
|
|
1092
1427
|
}
|
|
1093
|
-
const original =
|
|
1428
|
+
const original = fs13.readFileSync(filePath, "utf8");
|
|
1094
1429
|
if (original.includes("@tailwindcss/vite")) {
|
|
1095
1430
|
return { applied: false, reason: "tailwindcss plugin already present" };
|
|
1096
1431
|
}
|
|
@@ -1109,14 +1444,14 @@ function mergeViteConfig(filePath) {
|
|
|
1109
1444
|
const trailing = withImport.slice(insertAt);
|
|
1110
1445
|
const prefix = /^\s*\]/.test(trailing) ? "tailwindcss()" : "tailwindcss(), ";
|
|
1111
1446
|
const updated = withImport.slice(0, insertAt) + prefix + withImport.slice(insertAt);
|
|
1112
|
-
|
|
1447
|
+
fs13.writeFileSync(filePath, updated);
|
|
1113
1448
|
return { applied: true, reason: "added @tailwindcss/vite plugin" };
|
|
1114
1449
|
}
|
|
1115
1450
|
function mergeTsconfig(filePath) {
|
|
1116
|
-
if (!
|
|
1451
|
+
if (!fs13.existsSync(filePath)) {
|
|
1117
1452
|
return { applied: false, reason: "tsconfig.json not found" };
|
|
1118
1453
|
}
|
|
1119
|
-
const original =
|
|
1454
|
+
const original = fs13.readFileSync(filePath, "utf8");
|
|
1120
1455
|
if (/rewriteRelativeImportExtensions/.test(original)) {
|
|
1121
1456
|
return { applied: false, reason: "rewriteRelativeImportExtensions already set" };
|
|
1122
1457
|
}
|
|
@@ -1132,7 +1467,7 @@ function mergeTsconfig(filePath) {
|
|
|
1132
1467
|
const indent = detectIndent(original, insertAt);
|
|
1133
1468
|
const updated = original.slice(0, insertAt) + `
|
|
1134
1469
|
${indent}"rewriteRelativeImportExtensions": true,` + original.slice(insertAt);
|
|
1135
|
-
|
|
1470
|
+
fs13.writeFileSync(filePath, updated);
|
|
1136
1471
|
return { applied: true, reason: "added rewriteRelativeImportExtensions" };
|
|
1137
1472
|
}
|
|
1138
1473
|
var GITIGNORE_ENTRIES = [
|
|
@@ -1144,7 +1479,7 @@ var GITIGNORE_ENTRIES = [
|
|
|
1144
1479
|
"vite.config.ts.timestamp-*"
|
|
1145
1480
|
];
|
|
1146
1481
|
function mergeGitignore(filePath) {
|
|
1147
|
-
const existing =
|
|
1482
|
+
const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf8") : "";
|
|
1148
1483
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
1149
1484
|
const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.includes(entry));
|
|
1150
1485
|
if (missing.length === 0) {
|
|
@@ -1153,7 +1488,7 @@ function mergeGitignore(filePath) {
|
|
|
1153
1488
|
const needsNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
1154
1489
|
const appended = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
|
|
1155
1490
|
`;
|
|
1156
|
-
|
|
1491
|
+
fs13.writeFileSync(filePath, appended);
|
|
1157
1492
|
return { applied: true, reason: `added ${missing.length} gitignore entries` };
|
|
1158
1493
|
}
|
|
1159
1494
|
function addImport(source, importLine) {
|
|
@@ -1178,14 +1513,14 @@ function detectIndent(source, atOffset) {
|
|
|
1178
1513
|
}
|
|
1179
1514
|
|
|
1180
1515
|
// src/lib/scaffold-detect.ts
|
|
1181
|
-
import
|
|
1182
|
-
import
|
|
1516
|
+
import fs14 from "node:fs";
|
|
1517
|
+
import path12 from "node:path";
|
|
1183
1518
|
var VANILLA_MARKER = "Welcome to SvelteKit";
|
|
1184
|
-
var PAGE_REL =
|
|
1519
|
+
var PAGE_REL = path12.join("src", "routes", "+page.svelte");
|
|
1185
1520
|
function isVanillaRoutes(cwd) {
|
|
1186
|
-
const pagePath =
|
|
1187
|
-
if (!
|
|
1188
|
-
return
|
|
1521
|
+
const pagePath = path12.join(cwd, PAGE_REL);
|
|
1522
|
+
if (!fs14.existsSync(pagePath)) return false;
|
|
1523
|
+
return fs14.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
|
|
1189
1524
|
}
|
|
1190
1525
|
|
|
1191
1526
|
// src/lib/result-report.ts
|
|
@@ -1232,62 +1567,16 @@ ${failure.message}` : headline);
|
|
|
1232
1567
|
}
|
|
1233
1568
|
}
|
|
1234
1569
|
|
|
1235
|
-
// src/lib/template-files.ts
|
|
1236
|
-
import fs12 from "node:fs";
|
|
1237
|
-
import path10 from "node:path";
|
|
1238
|
-
var PUBLISH_SAFE_NAMES = {
|
|
1239
|
-
".gitignore": "_gitignore",
|
|
1240
|
-
".npmrc": "_npmrc"
|
|
1241
|
-
};
|
|
1242
|
-
function templateName(projectRelPath) {
|
|
1243
|
-
const safe = PUBLISH_SAFE_NAMES[path10.basename(projectRelPath)];
|
|
1244
|
-
if (!safe) return projectRelPath;
|
|
1245
|
-
const dir = path10.dirname(projectRelPath);
|
|
1246
|
-
return dir === "." ? safe : path10.join(dir, safe);
|
|
1247
|
-
}
|
|
1248
|
-
function restoreTemplateNames(target) {
|
|
1249
|
-
for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
|
|
1250
|
-
const from = path10.join(target, safe);
|
|
1251
|
-
if (!fs12.existsSync(from)) continue;
|
|
1252
|
-
fs12.renameSync(from, path10.join(target, real));
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
|
|
1256
|
-
function applyTemplateFiles(target, values) {
|
|
1257
|
-
const written = [];
|
|
1258
|
-
for (const source of findTemplateSources(target)) {
|
|
1259
|
-
const raw = fs12.readFileSync(source, "utf8");
|
|
1260
|
-
const dest = source.replace(TEMPLATE_SOURCE, ".$1");
|
|
1261
|
-
fs12.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
|
|
1262
|
-
fs12.unlinkSync(source);
|
|
1263
|
-
written.push(path10.relative(target, dest));
|
|
1264
|
-
}
|
|
1265
|
-
return written.sort();
|
|
1266
|
-
}
|
|
1267
|
-
function findTemplateSources(dir) {
|
|
1268
|
-
const found = [];
|
|
1269
|
-
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
1270
|
-
const full = path10.join(dir, entry.name);
|
|
1271
|
-
if (entry.isDirectory()) {
|
|
1272
|
-
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
1273
|
-
found.push(...findTemplateSources(full));
|
|
1274
|
-
} else if (entry.isFile() && TEMPLATE_SOURCE.test(entry.name)) {
|
|
1275
|
-
found.push(full);
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
return found;
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
1570
|
// src/commands/bless.ts
|
|
1282
1571
|
function optionsSchema() {
|
|
1283
1572
|
const templates = projectTemplateNames({ backend: true });
|
|
1284
|
-
return
|
|
1285
|
-
install:
|
|
1286
|
-
template:
|
|
1287
|
-
email:
|
|
1288
|
-
password:
|
|
1289
|
-
skipRoutes:
|
|
1290
|
-
forceRoutes:
|
|
1573
|
+
return v3.strictObject({
|
|
1574
|
+
install: v3.union([v3.boolean(), v3.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
1575
|
+
template: v3.optional(v3.picklist(templates, `must be one of: ${templates.join(", ")}`)),
|
|
1576
|
+
email: v3.optional(v3.pipe(v3.string(), v3.email("must be a valid email address"))),
|
|
1577
|
+
password: v3.optional(v3.pipe(v3.string(), v3.minLength(8, "must be at least 8 characters long"))),
|
|
1578
|
+
skipRoutes: v3.optional(v3.boolean()),
|
|
1579
|
+
forceRoutes: v3.optional(v3.boolean())
|
|
1291
1580
|
});
|
|
1292
1581
|
}
|
|
1293
1582
|
var VELA_ONLY_FILES = [
|
|
@@ -1343,7 +1632,7 @@ async function blessProject(cwdArg, options) {
|
|
|
1343
1632
|
{
|
|
1344
1633
|
onCancel: () => {
|
|
1345
1634
|
p4.cancel("Operation cancelled.");
|
|
1346
|
-
|
|
1635
|
+
process7.exit(0);
|
|
1347
1636
|
}
|
|
1348
1637
|
}
|
|
1349
1638
|
);
|
|
@@ -1378,7 +1667,7 @@ async function blessProject(cwdArg, options) {
|
|
|
1378
1667
|
printNextSteps(projectPath, packageManager);
|
|
1379
1668
|
}
|
|
1380
1669
|
function ensureShadcnCss(projectPath) {
|
|
1381
|
-
if (ensureShadcnImport(
|
|
1670
|
+
if (ensureShadcnImport(path13.join(projectPath, "src", "app.css"))) {
|
|
1382
1671
|
p4.log.info(
|
|
1383
1672
|
"src/app.css: added the shadcn-svelte/tailwind.css import its registry components rely on."
|
|
1384
1673
|
);
|
|
@@ -1390,22 +1679,22 @@ function hintComponentsJson(projectPath) {
|
|
|
1390
1679
|
for (const hint of componentsJsonHints(config)) p4.log.warn(hint);
|
|
1391
1680
|
}
|
|
1392
1681
|
function resolveProjectPath(cwdArg) {
|
|
1393
|
-
const projectPath =
|
|
1394
|
-
if (!
|
|
1682
|
+
const projectPath = path13.resolve(cwdArg);
|
|
1683
|
+
if (!fs15.existsSync(projectPath)) {
|
|
1395
1684
|
throw new Error(`Path does not exist: ${projectPath}`);
|
|
1396
1685
|
}
|
|
1397
|
-
if (!
|
|
1686
|
+
if (!fs15.existsSync(path13.join(projectPath, "package.json"))) {
|
|
1398
1687
|
throw new Error(`No package.json found at ${projectPath}`);
|
|
1399
1688
|
}
|
|
1400
|
-
if (!
|
|
1689
|
+
if (!fs15.existsSync(path13.join(projectPath, "src", "routes"))) {
|
|
1401
1690
|
throw new Error(`No src/routes directory found at ${projectPath}`);
|
|
1402
1691
|
}
|
|
1403
1692
|
return projectPath;
|
|
1404
1693
|
}
|
|
1405
1694
|
function assertNotAlreadyBlessed(projectPath) {
|
|
1406
|
-
const hooksPath =
|
|
1407
|
-
if (!
|
|
1408
|
-
const content =
|
|
1695
|
+
const hooksPath = path13.join(projectPath, "src", "hooks.server.ts");
|
|
1696
|
+
if (!fs15.existsSync(hooksPath)) return;
|
|
1697
|
+
const content = fs15.readFileSync(hooksPath, "utf8");
|
|
1409
1698
|
if (content.includes("@velastack/pocketbase")) {
|
|
1410
1699
|
throw new Error(
|
|
1411
1700
|
"This project already looks blessed (src/hooks.server.ts imports @velastack/pocketbase). Run `vela sync` instead."
|
|
@@ -1413,8 +1702,8 @@ function assertNotAlreadyBlessed(projectPath) {
|
|
|
1413
1702
|
}
|
|
1414
1703
|
}
|
|
1415
1704
|
function mergeDependencies(projectPath, templateDir) {
|
|
1416
|
-
const userPkgPath =
|
|
1417
|
-
const templatePkgPath =
|
|
1705
|
+
const userPkgPath = path13.join(projectPath, "package.json");
|
|
1706
|
+
const templatePkgPath = path13.join(templateDir, "package.template.json");
|
|
1418
1707
|
const userPkg = readPackageJson(userPkgPath);
|
|
1419
1708
|
const appName = typeof userPkg.name === "string" ? userPkg.name : "sveltekit";
|
|
1420
1709
|
const templatePkg = readTemplatePackageJson(templatePkgPath, {
|
|
@@ -1446,21 +1735,21 @@ ${lines.join("\n")}`);
|
|
|
1446
1735
|
function copyVelaOnlyFiles(templateDir, projectPath) {
|
|
1447
1736
|
const kept = [];
|
|
1448
1737
|
for (const file of VELA_ONLY_FILES) {
|
|
1449
|
-
const src =
|
|
1450
|
-
const dest =
|
|
1451
|
-
if (!
|
|
1452
|
-
if (
|
|
1738
|
+
const src = path13.join(templateDir, templateName(file.path));
|
|
1739
|
+
const dest = path13.join(projectPath, file.path);
|
|
1740
|
+
if (!fs15.existsSync(src)) continue;
|
|
1741
|
+
if (fs15.existsSync(dest)) {
|
|
1453
1742
|
kept.push(file);
|
|
1454
1743
|
continue;
|
|
1455
1744
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1745
|
+
fs15.mkdirSync(path13.dirname(dest), { recursive: true });
|
|
1746
|
+
fs15.copyFileSync(src, dest);
|
|
1458
1747
|
}
|
|
1459
1748
|
reportKeptFiles(kept);
|
|
1460
1749
|
for (const rel of VELA_ONLY_DIRS) {
|
|
1461
|
-
const src =
|
|
1462
|
-
const dest =
|
|
1463
|
-
if (!
|
|
1750
|
+
const src = path13.join(templateDir, rel);
|
|
1751
|
+
const dest = path13.join(projectPath, rel);
|
|
1752
|
+
if (!fs15.existsSync(src)) continue;
|
|
1464
1753
|
copyDirShallow(src, dest);
|
|
1465
1754
|
}
|
|
1466
1755
|
}
|
|
@@ -1474,15 +1763,15 @@ ${lines.join("\n")}`
|
|
|
1474
1763
|
);
|
|
1475
1764
|
}
|
|
1476
1765
|
function copyDirShallow(src, dest) {
|
|
1477
|
-
|
|
1478
|
-
for (const entry of
|
|
1766
|
+
fs15.mkdirSync(dest, { recursive: true });
|
|
1767
|
+
for (const entry of fs15.readdirSync(src, { withFileTypes: true })) {
|
|
1479
1768
|
if (entry.name === ".DS_Store") continue;
|
|
1480
|
-
const srcChild =
|
|
1481
|
-
const destChild =
|
|
1769
|
+
const srcChild = path13.join(src, entry.name);
|
|
1770
|
+
const destChild = path13.join(dest, entry.name);
|
|
1482
1771
|
if (entry.isDirectory()) {
|
|
1483
1772
|
copyDirShallow(srcChild, destChild);
|
|
1484
|
-
} else if (entry.isFile() && !
|
|
1485
|
-
|
|
1773
|
+
} else if (entry.isFile() && !fs15.existsSync(destChild)) {
|
|
1774
|
+
fs15.copyFileSync(srcChild, destChild);
|
|
1486
1775
|
}
|
|
1487
1776
|
}
|
|
1488
1777
|
}
|
|
@@ -1490,9 +1779,9 @@ function mergeConfigFiles(projectPath) {
|
|
|
1490
1779
|
const runes = mergeSvelteConfig(projectPath);
|
|
1491
1780
|
const outcomes = [
|
|
1492
1781
|
[runes.file ?? "svelte.config", runes],
|
|
1493
|
-
["vite.config.ts", mergeViteConfig(
|
|
1494
|
-
["tsconfig.json", mergeTsconfig(
|
|
1495
|
-
[".gitignore", mergeGitignore(
|
|
1782
|
+
["vite.config.ts", mergeViteConfig(path13.join(projectPath, "vite.config.ts"))],
|
|
1783
|
+
["tsconfig.json", mergeTsconfig(path13.join(projectPath, "tsconfig.json"))],
|
|
1784
|
+
[".gitignore", mergeGitignore(path13.join(projectPath, ".gitignore"))]
|
|
1496
1785
|
];
|
|
1497
1786
|
for (const [name, outcome] of outcomes) {
|
|
1498
1787
|
if (outcome.applied) {
|
|
@@ -1509,14 +1798,14 @@ ${pc3.cyan(outcome.snippet)}`
|
|
|
1509
1798
|
}
|
|
1510
1799
|
}
|
|
1511
1800
|
function mergeAppDts(templateDir, projectPath) {
|
|
1512
|
-
const dest =
|
|
1513
|
-
const templateFile =
|
|
1514
|
-
if (!
|
|
1515
|
-
if (!
|
|
1516
|
-
|
|
1801
|
+
const dest = path13.join(projectPath, "src", "app.d.ts");
|
|
1802
|
+
const templateFile = path13.join(templateDir, "src", "app.d.ts");
|
|
1803
|
+
if (!fs15.existsSync(dest)) {
|
|
1804
|
+
if (!fs15.existsSync(templateFile)) return;
|
|
1805
|
+
fs15.copyFileSync(templateFile, dest);
|
|
1517
1806
|
return;
|
|
1518
1807
|
}
|
|
1519
|
-
const current =
|
|
1808
|
+
const current = fs15.readFileSync(dest, "utf8");
|
|
1520
1809
|
if (current.includes("namespace Superforms")) return;
|
|
1521
1810
|
const block = ` namespace Superforms {
|
|
1522
1811
|
type Message = {
|
|
@@ -1535,7 +1824,7 @@ ${pc3.cyan(block)}`
|
|
|
1535
1824
|
}
|
|
1536
1825
|
const insertAt = match.index + match[0].length;
|
|
1537
1826
|
const updated = current.slice(0, insertAt) + block + current.slice(insertAt);
|
|
1538
|
-
|
|
1827
|
+
fs15.writeFileSync(dest, updated);
|
|
1539
1828
|
}
|
|
1540
1829
|
function maybeReplaceRoutes(projectPath, templateDir, options) {
|
|
1541
1830
|
if (options.skipRoutes) {
|
|
@@ -1546,12 +1835,12 @@ function maybeReplaceRoutes(projectPath, templateDir, options) {
|
|
|
1546
1835
|
p4.log.info("Leaving src/routes alone (looks customized).");
|
|
1547
1836
|
return;
|
|
1548
1837
|
}
|
|
1549
|
-
const target =
|
|
1550
|
-
|
|
1551
|
-
const src =
|
|
1552
|
-
|
|
1838
|
+
const target = path13.join(projectPath, "src", "routes");
|
|
1839
|
+
fs15.rmSync(target, { recursive: true, force: true });
|
|
1840
|
+
const src = path13.join(templateDir, "src", "routes");
|
|
1841
|
+
fs15.cpSync(src, target, {
|
|
1553
1842
|
recursive: true,
|
|
1554
|
-
filter: (s) =>
|
|
1843
|
+
filter: (s) => path13.basename(s) !== ".DS_Store"
|
|
1555
1844
|
});
|
|
1556
1845
|
p4.log.success("Replaced src/routes with the vela template.");
|
|
1557
1846
|
}
|
|
@@ -1560,7 +1849,7 @@ function summarize(names) {
|
|
|
1560
1849
|
return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
|
|
1561
1850
|
}
|
|
1562
1851
|
function printNextSteps(projectPath, packageManager) {
|
|
1563
|
-
const relative =
|
|
1852
|
+
const relative = path13.relative(process7.cwd(), projectPath);
|
|
1564
1853
|
const pm = packageManager ?? getUserAgent() ?? "npm";
|
|
1565
1854
|
const nextSteps = [];
|
|
1566
1855
|
if (relative !== "") {
|
|
@@ -1584,31 +1873,37 @@ function printNextSteps(projectPath, packageManager) {
|
|
|
1584
1873
|
}
|
|
1585
1874
|
|
|
1586
1875
|
// src/commands/create.ts
|
|
1587
|
-
import
|
|
1588
|
-
import
|
|
1589
|
-
import
|
|
1590
|
-
import * as
|
|
1876
|
+
import fs16 from "node:fs";
|
|
1877
|
+
import path14 from "node:path";
|
|
1878
|
+
import process8 from "node:process";
|
|
1879
|
+
import * as v4 from "valibot";
|
|
1591
1880
|
import { Command as Command3 } from "commander";
|
|
1592
1881
|
import * as p5 from "@clack/prompts";
|
|
1593
1882
|
import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
1594
|
-
function optionsSchema2() {
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1883
|
+
function optionsSchema2(listing) {
|
|
1884
|
+
const names = listing.templates.map((template) => template.name);
|
|
1885
|
+
let choices = `must be one of: ${templateChoicesMessage(listing.templates)}`;
|
|
1886
|
+
if (listing.registryError) {
|
|
1887
|
+
choices += ` (could not reach the template registry: ${listing.registryError})`;
|
|
1888
|
+
}
|
|
1889
|
+
return v4.strictObject({
|
|
1890
|
+
install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
1891
|
+
template: v4.optional(v4.picklist(names, choices)),
|
|
1892
|
+
name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
|
|
1893
|
+
email: v4.optional(v4.pipe(v4.string(), v4.email("must be a valid email address"))),
|
|
1894
|
+
password: v4.optional(v4.pipe(v4.string(), v4.minLength(8, "must be at least 8 characters long")))
|
|
1602
1895
|
});
|
|
1603
1896
|
}
|
|
1604
|
-
var create = new Command3("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
|
|
1897
|
+
var create = new Command3("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold (built-in or from the registry)", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
|
|
1605
1898
|
return runCommand(async () => {
|
|
1606
|
-
const
|
|
1899
|
+
const listing = await listAllTemplates();
|
|
1900
|
+
const options = parseOptions(optionsSchema2(listing), rawOpts);
|
|
1607
1901
|
const { directory, packageManager, name, template } = await createProject(
|
|
1608
1902
|
projectPath,
|
|
1609
|
-
options
|
|
1903
|
+
options,
|
|
1904
|
+
listing
|
|
1610
1905
|
);
|
|
1611
|
-
const relative =
|
|
1906
|
+
const relative = path14.relative(process8.cwd(), directory);
|
|
1612
1907
|
const pm = packageManager ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
1613
1908
|
const nextSteps = [];
|
|
1614
1909
|
if (relative !== "") {
|
|
@@ -1629,7 +1924,9 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1629
1924
|
`\`${runDev.command} ${runDev.args.join(" ")}\` to start the dev server (Ctrl-C to stop)`
|
|
1630
1925
|
);
|
|
1631
1926
|
}
|
|
1632
|
-
if (template.
|
|
1927
|
+
if (template.nextSteps) {
|
|
1928
|
+
nextSteps.push(...template.nextSteps);
|
|
1929
|
+
} else if (template.backend) {
|
|
1633
1930
|
nextSteps.push("Run `vela generate scaffold <model>` to generate your first CRUD pages.");
|
|
1634
1931
|
} else {
|
|
1635
1932
|
nextSteps.push(
|
|
@@ -1644,12 +1941,12 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1644
1941
|
});
|
|
1645
1942
|
}, "Failed to create project.");
|
|
1646
1943
|
});
|
|
1647
|
-
async function createProject(cwdArg, options) {
|
|
1944
|
+
async function createProject(cwdArg, options, listing) {
|
|
1648
1945
|
const onCancel2 = () => {
|
|
1649
1946
|
p5.cancel("Operation cancelled.");
|
|
1650
|
-
|
|
1947
|
+
process8.exit(0);
|
|
1651
1948
|
};
|
|
1652
|
-
const template =
|
|
1949
|
+
const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
|
|
1653
1950
|
if (!template.backend && (options.email || options.password)) {
|
|
1654
1951
|
throw new Error(
|
|
1655
1952
|
`--email and --password don't apply to the ${template.name} template \u2014 it has no backend.`
|
|
@@ -1657,7 +1954,7 @@ async function createProject(cwdArg, options) {
|
|
|
1657
1954
|
}
|
|
1658
1955
|
let directory;
|
|
1659
1956
|
if (cwdArg) {
|
|
1660
|
-
directory =
|
|
1957
|
+
directory = path14.resolve(cwdArg);
|
|
1661
1958
|
} else {
|
|
1662
1959
|
const answer = await p5.text({
|
|
1663
1960
|
message: "Where would you like your project to be created?",
|
|
@@ -1665,16 +1962,16 @@ async function createProject(cwdArg, options) {
|
|
|
1665
1962
|
defaultValue: "./"
|
|
1666
1963
|
});
|
|
1667
1964
|
if (p5.isCancel(answer)) onCancel2();
|
|
1668
|
-
directory =
|
|
1965
|
+
directory = path14.resolve(answer);
|
|
1669
1966
|
}
|
|
1670
|
-
if (
|
|
1967
|
+
if (fs16.existsSync(directory) && fs16.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
|
|
1671
1968
|
const force = await p5.confirm({
|
|
1672
1969
|
message: "Directory not empty. Continue?",
|
|
1673
1970
|
initialValue: false
|
|
1674
1971
|
});
|
|
1675
1972
|
if (p5.isCancel(force) || !force) onCancel2();
|
|
1676
1973
|
}
|
|
1677
|
-
const dirName =
|
|
1974
|
+
const dirName = path14.basename(directory);
|
|
1678
1975
|
const { name } = await p5.group(
|
|
1679
1976
|
{
|
|
1680
1977
|
name: () => {
|
|
@@ -1690,9 +1987,15 @@ async function createProject(cwdArg, options) {
|
|
|
1690
1987
|
);
|
|
1691
1988
|
const credentials = template.backend ? await promptCredentials(options, onCancel2) : void 0;
|
|
1692
1989
|
const projectPath = directory;
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1990
|
+
if (template.source === "remote") p5.log.step(`Downloading template ${template.name}...`);
|
|
1991
|
+
const resolved = await resolveTemplate(template);
|
|
1992
|
+
try {
|
|
1993
|
+
copyTemplate(resolved, projectPath);
|
|
1994
|
+
applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
|
|
1995
|
+
} finally {
|
|
1996
|
+
resolved.cleanup();
|
|
1997
|
+
}
|
|
1998
|
+
if (!fs16.existsSync(path14.join(projectPath, "package.json"))) {
|
|
1696
1999
|
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
1697
2000
|
}
|
|
1698
2001
|
p5.log.success("Project created");
|
|
@@ -1753,15 +2056,6 @@ function promptCredentials(options, onCancel2) {
|
|
|
1753
2056
|
{ onCancel: onCancel2 }
|
|
1754
2057
|
);
|
|
1755
2058
|
}
|
|
1756
|
-
function copyTemplate(template, target) {
|
|
1757
|
-
fs14.mkdirSync(target, { recursive: true });
|
|
1758
|
-
fs14.cpSync(template.dir, target, {
|
|
1759
|
-
recursive: true,
|
|
1760
|
-
// The manifest describes the template to the CLI; it isn't part of the project.
|
|
1761
|
-
filter: (src) => path12.basename(src) !== ".DS_Store" && path12.relative(template.dir, src) !== TEMPLATE_MANIFEST
|
|
1762
|
-
});
|
|
1763
|
-
restoreTemplateNames(target);
|
|
1764
|
-
}
|
|
1765
2059
|
|
|
1766
2060
|
// src/commands/generate.ts
|
|
1767
2061
|
import { Command as Command9 } from "commander";
|
|
@@ -1771,11 +2065,11 @@ import { Command as Command4 } from "commander";
|
|
|
1771
2065
|
import * as p11 from "@clack/prompts";
|
|
1772
2066
|
|
|
1773
2067
|
// src/lib/pattern-runner.ts
|
|
1774
|
-
import
|
|
2068
|
+
import path15 from "node:path";
|
|
1775
2069
|
import * as p6 from "@clack/prompts";
|
|
1776
2070
|
import { bySlug } from "@velastack/patterns";
|
|
1777
2071
|
function toRelative(root, filePath) {
|
|
1778
|
-
return
|
|
2072
|
+
return path15.isAbsolute(filePath) ? path15.relative(root, filePath) : filePath;
|
|
1779
2073
|
}
|
|
1780
2074
|
var isSuccess = (f) => (f.status ?? "success") === "success";
|
|
1781
2075
|
async function runPattern(slug2, argv, input, report4) {
|
|
@@ -1842,57 +2136,22 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
1842
2136
|
}
|
|
1843
2137
|
|
|
1844
2138
|
// src/lib/ai-flow.ts
|
|
1845
|
-
import
|
|
1846
|
-
import
|
|
2139
|
+
import fs18 from "node:fs";
|
|
2140
|
+
import path17 from "node:path";
|
|
1847
2141
|
import * as p10 from "@clack/prompts";
|
|
1848
2142
|
import pc4 from "picocolors";
|
|
1849
2143
|
|
|
1850
|
-
// src/lib/config.ts
|
|
1851
|
-
import fs15 from "node:fs";
|
|
1852
|
-
import os from "node:os";
|
|
1853
|
-
import path14 from "node:path";
|
|
1854
|
-
import process8 from "node:process";
|
|
1855
|
-
var CONFIG_DIR = path14.join(os.homedir(), ".vela");
|
|
1856
|
-
var CONFIG_PATH = path14.join(CONFIG_DIR, "config.json");
|
|
1857
|
-
function readConfig() {
|
|
1858
|
-
if (!fs15.existsSync(CONFIG_PATH)) return null;
|
|
1859
|
-
try {
|
|
1860
|
-
return JSON.parse(fs15.readFileSync(CONFIG_PATH, "utf8"));
|
|
1861
|
-
} catch {
|
|
1862
|
-
return null;
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
function writeConfig(config) {
|
|
1866
|
-
fs15.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
1867
|
-
fs15.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
1868
|
-
}
|
|
1869
|
-
function clearConfig() {
|
|
1870
|
-
if (fs15.existsSync(CONFIG_PATH)) fs15.unlinkSync(CONFIG_PATH);
|
|
1871
|
-
}
|
|
1872
|
-
function readApiKey() {
|
|
1873
|
-
const fromEnv = process8.env.VELA_API_KEY?.trim();
|
|
1874
|
-
if (fromEnv) return fromEnv;
|
|
1875
|
-
return readConfig()?.apiKey ?? null;
|
|
1876
|
-
}
|
|
1877
|
-
function requireApiKey() {
|
|
1878
|
-
const apiKey = readApiKey();
|
|
1879
|
-
if (!apiKey) {
|
|
1880
|
-
throw new Error("Not logged in. Run `vela login` to login, or set VELA_API_KEY.");
|
|
1881
|
-
}
|
|
1882
|
-
return apiKey;
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
2144
|
// src/lib/project-config.ts
|
|
1886
|
-
import
|
|
1887
|
-
import
|
|
2145
|
+
import fs17 from "node:fs";
|
|
2146
|
+
import path16 from "node:path";
|
|
1888
2147
|
function projectConfigPath(workspaceRootDir) {
|
|
1889
|
-
return
|
|
2148
|
+
return path16.join(workspaceRootDir, ".vela", "project.json");
|
|
1890
2149
|
}
|
|
1891
2150
|
function readProjectConfig(workspaceRootDir) {
|
|
1892
2151
|
const file = projectConfigPath(workspaceRootDir);
|
|
1893
|
-
if (!
|
|
2152
|
+
if (!fs17.existsSync(file)) return null;
|
|
1894
2153
|
try {
|
|
1895
|
-
const parsed = JSON.parse(
|
|
2154
|
+
const parsed = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
1896
2155
|
if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
|
|
1897
2156
|
return null;
|
|
1898
2157
|
}
|
|
@@ -1907,15 +2166,15 @@ function readProjectConfig(workspaceRootDir) {
|
|
|
1907
2166
|
}
|
|
1908
2167
|
function writeProjectConfig(workspaceRootDir, config) {
|
|
1909
2168
|
const file = projectConfigPath(workspaceRootDir);
|
|
1910
|
-
|
|
2169
|
+
fs17.mkdirSync(path16.dirname(file), { recursive: true });
|
|
1911
2170
|
let existing = {};
|
|
1912
|
-
if (
|
|
2171
|
+
if (fs17.existsSync(file)) {
|
|
1913
2172
|
try {
|
|
1914
|
-
existing = JSON.parse(
|
|
2173
|
+
existing = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
1915
2174
|
} catch {
|
|
1916
2175
|
}
|
|
1917
2176
|
}
|
|
1918
|
-
|
|
2177
|
+
fs17.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
|
|
1919
2178
|
}
|
|
1920
2179
|
|
|
1921
2180
|
// src/lib/ai-client.ts
|
|
@@ -2189,11 +2448,11 @@ function specToArgv(spec) {
|
|
|
2189
2448
|
return collectionSpecToArgv(spec);
|
|
2190
2449
|
}
|
|
2191
2450
|
function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
|
|
2192
|
-
const dir =
|
|
2193
|
-
|
|
2194
|
-
const file =
|
|
2195
|
-
|
|
2196
|
-
return
|
|
2451
|
+
const dir = path17.join(workspaceRootDir, "data", "ai-form-layouts");
|
|
2452
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
2453
|
+
const file = path17.join(dir, `${modelName}.json`);
|
|
2454
|
+
fs18.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
|
|
2455
|
+
return path17.relative(workspaceRootDir, file);
|
|
2197
2456
|
}
|
|
2198
2457
|
|
|
2199
2458
|
// src/commands/generate/form.ts
|
|
@@ -2203,7 +2462,7 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2203
2462
|
).option(
|
|
2204
2463
|
"--ai <description>",
|
|
2205
2464
|
"design the form with AI from a natural-language description (two stages: schema \u2192 layout)"
|
|
2206
|
-
).allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2465
|
+
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2207
2466
|
(model, fields, options) => runCommand(async () => {
|
|
2208
2467
|
let argv;
|
|
2209
2468
|
let modelName;
|
|
@@ -2262,7 +2521,7 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2262
2521
|
// src/commands/generate/schema.ts
|
|
2263
2522
|
import { Command as Command5 } from "commander";
|
|
2264
2523
|
import * as p12 from "@clack/prompts";
|
|
2265
|
-
var schema = new Command5("schema").description("generate a schema from a model").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--ai <description>", "design the schema with AI from a natural-language description").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2524
|
+
var schema = new Command5("schema").description("generate a schema from a model").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--ai <description>", "design the schema with AI from a natural-language description").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2266
2525
|
(model, fields, options) => runCommand(async () => {
|
|
2267
2526
|
let argv;
|
|
2268
2527
|
let modelName;
|
|
@@ -2306,7 +2565,7 @@ var schema = new Command5("schema").description("generate a schema from a model"
|
|
|
2306
2565
|
|
|
2307
2566
|
// src/commands/generate/resource.ts
|
|
2308
2567
|
import { Command as Command6 } from "commander";
|
|
2309
|
-
var resource = new Command6("resource").description("generate a resource (model + CRUD pages)").argument("<model>", "model name").argument("[fields...]", "field definitions").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2568
|
+
var resource = new Command6("resource").description("generate a resource (model + CRUD pages)").argument("<model>", "model name").argument("[fields...]", "field definitions").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2310
2569
|
(model, fields) => runCommand(
|
|
2311
2570
|
() => runPattern(
|
|
2312
2571
|
"generate-resource",
|
|
@@ -2339,7 +2598,7 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2339
2598
|
).option(
|
|
2340
2599
|
"--ai <description>",
|
|
2341
2600
|
"design the scaffold with AI from a natural-language description (two stages: schema \u2192 layout)"
|
|
2342
|
-
).allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2601
|
+
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2343
2602
|
(model, fields, options) => runCommand(async () => {
|
|
2344
2603
|
let argv;
|
|
2345
2604
|
let modelName;
|
|
@@ -2398,7 +2657,7 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2398
2657
|
|
|
2399
2658
|
// src/commands/generate/migration.ts
|
|
2400
2659
|
import { Command as Command8 } from "commander";
|
|
2401
|
-
var migration = new Command8("migration").description("generate a migration for an existing collection").argument("<collection>", "collection name").argument("<op>", "operation (add, remove, rename, references)").argument("[args...]", 'operation arguments (e.g. "birthday:date")').allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2660
|
+
var migration = new Command8("migration").description("generate a migration for an existing collection").argument("<collection>", "collection name").argument("<op>", "operation (add, remove, rename, references)").argument("[args...]", 'operation arguments (e.g. "birthday:date")').allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2402
2661
|
(collection, op, args) => runCommand(
|
|
2403
2662
|
() => runPattern(
|
|
2404
2663
|
"generate-migration",
|
|
@@ -2429,7 +2688,7 @@ import { Command as Command24 } from "commander";
|
|
|
2429
2688
|
|
|
2430
2689
|
// src/commands/enable/auth.ts
|
|
2431
2690
|
import { Command as Command10 } from "commander";
|
|
2432
|
-
var auth = new Command10("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2691
|
+
var auth = new Command10("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2433
2692
|
(_opts, cmd) => runCommand(
|
|
2434
2693
|
() => runPattern(
|
|
2435
2694
|
"enable-auth",
|
|
@@ -2455,7 +2714,7 @@ var auth = new Command10("auth").description("enable authentication (email/passw
|
|
|
2455
2714
|
|
|
2456
2715
|
// src/commands/enable/api.ts
|
|
2457
2716
|
import { Command as Command11 } from "commander";
|
|
2458
|
-
var api = new Command11("api").description("enable the PocketBase REST API").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2717
|
+
var api = new Command11("api").description("enable the PocketBase REST API").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2459
2718
|
(_opts, cmd) => runCommand(
|
|
2460
2719
|
() => runPattern(
|
|
2461
2720
|
"enable-api",
|
|
@@ -2481,7 +2740,7 @@ var api = new Command11("api").description("enable the PocketBase REST API").all
|
|
|
2481
2740
|
|
|
2482
2741
|
// src/commands/enable/api-keys.ts
|
|
2483
2742
|
import { Command as Command12 } from "commander";
|
|
2484
|
-
var apiKeys = new Command12("api-keys").description("enable API key management").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2743
|
+
var apiKeys = new Command12("api-keys").description("enable API key management").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2485
2744
|
(_opts, cmd) => runCommand(
|
|
2486
2745
|
() => runPattern(
|
|
2487
2746
|
"enable-api-keys",
|
|
@@ -2507,7 +2766,7 @@ var apiKeys = new Command12("api-keys").description("enable API key management")
|
|
|
2507
2766
|
|
|
2508
2767
|
// src/commands/enable/backend.ts
|
|
2509
2768
|
import { Command as Command13 } from "commander";
|
|
2510
|
-
var backend = new Command13("backend").description("enable the PocketBase backend").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2769
|
+
var backend = new Command13("backend").description("enable the PocketBase backend").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2511
2770
|
(_opts, cmd) => runCommand(
|
|
2512
2771
|
() => runPattern(
|
|
2513
2772
|
"enable-backend",
|
|
@@ -2533,7 +2792,7 @@ var backend = new Command13("backend").description("enable the PocketBase backen
|
|
|
2533
2792
|
|
|
2534
2793
|
// src/commands/enable/i18n.ts
|
|
2535
2794
|
import { Command as Command14 } from "commander";
|
|
2536
|
-
var i18n = new Command14("i18n").description("enable internationalization").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2795
|
+
var i18n = new Command14("i18n").description("enable internationalization").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2537
2796
|
(_opts, cmd) => runCommand(
|
|
2538
2797
|
() => runPattern(
|
|
2539
2798
|
"enable-i18n",
|
|
@@ -2559,7 +2818,7 @@ var i18n = new Command14("i18n").description("enable internationalization").allo
|
|
|
2559
2818
|
|
|
2560
2819
|
// src/commands/enable/teams.ts
|
|
2561
2820
|
import { Command as Command15 } from "commander";
|
|
2562
|
-
var teams = new Command15("teams").description("enable team / multi-tenant support").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2821
|
+
var teams = new Command15("teams").description("enable team / multi-tenant support").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2563
2822
|
(_opts, cmd) => runCommand(
|
|
2564
2823
|
() => runPattern(
|
|
2565
2824
|
"enable-teams",
|
|
@@ -2588,7 +2847,7 @@ import process9 from "node:process";
|
|
|
2588
2847
|
import { Command as Command16 } from "commander";
|
|
2589
2848
|
import * as p14 from "@clack/prompts";
|
|
2590
2849
|
var PROVIDERS = [{ value: "stripe", label: "Stripe" }];
|
|
2591
|
-
var payments = new Command16("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2850
|
+
var payments = new Command16("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2592
2851
|
(opts, cmd) => runCommand(async () => {
|
|
2593
2852
|
const provider = await resolveProvider(opts.provider, cmd.getOptionValueSource("provider"));
|
|
2594
2853
|
const input = {
|
|
@@ -2675,7 +2934,7 @@ async function ensureKey(envVar, message) {
|
|
|
2675
2934
|
async function promptPassword(message) {
|
|
2676
2935
|
const value = await p14.password({
|
|
2677
2936
|
message,
|
|
2678
|
-
validate: (
|
|
2937
|
+
validate: (v10) => v10 && v10.length ? void 0 : "Required"
|
|
2679
2938
|
});
|
|
2680
2939
|
if (p14.isCancel(value)) {
|
|
2681
2940
|
p14.cancel("Operation cancelled.");
|
|
@@ -2686,7 +2945,7 @@ async function promptPassword(message) {
|
|
|
2686
2945
|
|
|
2687
2946
|
// src/commands/enable/subscriptions.ts
|
|
2688
2947
|
import { Command as Command17 } from "commander";
|
|
2689
|
-
var subscriptions = new Command17("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2948
|
+
var subscriptions = new Command17("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2690
2949
|
(_opts, cmd) => runCommand(
|
|
2691
2950
|
() => runPattern(
|
|
2692
2951
|
"enable-subscriptions",
|
|
@@ -2712,7 +2971,7 @@ var subscriptions = new Command17("subscriptions").description("enable Stripe su
|
|
|
2712
2971
|
|
|
2713
2972
|
// src/commands/enable/notifications.ts
|
|
2714
2973
|
import { Command as Command18 } from "commander";
|
|
2715
|
-
var notifications = new Command18("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
2974
|
+
var notifications = new Command18("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2716
2975
|
(_opts, cmd) => runCommand(
|
|
2717
2976
|
() => runPattern(
|
|
2718
2977
|
"enable-notifications",
|
|
@@ -2744,13 +3003,13 @@ import pc8 from "picocolors";
|
|
|
2744
3003
|
|
|
2745
3004
|
// src/lib/server-command.ts
|
|
2746
3005
|
import process11 from "node:process";
|
|
2747
|
-
import * as
|
|
3006
|
+
import * as v6 from "valibot";
|
|
2748
3007
|
import * as p15 from "@clack/prompts";
|
|
2749
3008
|
import pc5 from "picocolors";
|
|
2750
3009
|
|
|
2751
3010
|
// src/lib/deploy-config.ts
|
|
2752
|
-
import
|
|
2753
|
-
import
|
|
3011
|
+
import fs19 from "node:fs";
|
|
3012
|
+
import path18 from "node:path";
|
|
2754
3013
|
import crypto from "node:crypto";
|
|
2755
3014
|
import { pathToFileURL } from "node:url";
|
|
2756
3015
|
var CONFIG_BASENAMES = [
|
|
@@ -2761,8 +3020,8 @@ var CONFIG_BASENAMES = [
|
|
|
2761
3020
|
];
|
|
2762
3021
|
function findConfigFile(workspaceRootDir) {
|
|
2763
3022
|
for (const name of CONFIG_BASENAMES) {
|
|
2764
|
-
const file =
|
|
2765
|
-
if (
|
|
3023
|
+
const file = path18.join(workspaceRootDir, name);
|
|
3024
|
+
if (fs19.existsSync(file)) return file;
|
|
2766
3025
|
}
|
|
2767
3026
|
return null;
|
|
2768
3027
|
}
|
|
@@ -2770,49 +3029,49 @@ async function loadDeployConfig(workspaceRootDir) {
|
|
|
2770
3029
|
const file = findConfigFile(workspaceRootDir);
|
|
2771
3030
|
if (!file) return {};
|
|
2772
3031
|
if (file.endsWith(".json")) {
|
|
2773
|
-
return JSON.parse(
|
|
3032
|
+
return JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
2774
3033
|
}
|
|
2775
3034
|
const url = file.endsWith(".ts") ? await transpileToTemp(file) : pathToFileURL(file).href;
|
|
2776
3035
|
try {
|
|
2777
3036
|
const mod = await import(url);
|
|
2778
3037
|
const config = mod.default;
|
|
2779
3038
|
if (!config || typeof config !== "object") {
|
|
2780
|
-
throw new Error(`${
|
|
3039
|
+
throw new Error(`${path18.basename(file)} must export a config object as its default export.`);
|
|
2781
3040
|
}
|
|
2782
3041
|
return config;
|
|
2783
3042
|
} finally {
|
|
2784
|
-
if (url !== pathToFileURL(file).href)
|
|
3043
|
+
if (url !== pathToFileURL(file).href) fs19.rmSync(new URL(url), { force: true });
|
|
2785
3044
|
}
|
|
2786
3045
|
}
|
|
2787
3046
|
async function transpileToTemp(file) {
|
|
2788
3047
|
const { ts } = await import("ts-morph");
|
|
2789
|
-
const source =
|
|
3048
|
+
const source = fs19.readFileSync(file, "utf8");
|
|
2790
3049
|
const { outputText } = ts.transpileModule(source, {
|
|
2791
3050
|
compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 }
|
|
2792
3051
|
});
|
|
2793
|
-
const temp =
|
|
2794
|
-
|
|
3052
|
+
const temp = path18.join(
|
|
3053
|
+
path18.dirname(file),
|
|
2795
3054
|
`.velastack.config.${crypto.randomBytes(4).toString("hex")}.mjs`
|
|
2796
3055
|
);
|
|
2797
|
-
|
|
3056
|
+
fs19.writeFileSync(temp, outputText);
|
|
2798
3057
|
return pathToFileURL(temp).href;
|
|
2799
3058
|
}
|
|
2800
3059
|
function projectFilePath(workspaceRootDir) {
|
|
2801
|
-
return
|
|
3060
|
+
return path18.join(workspaceRootDir, ".vela", "project.json");
|
|
2802
3061
|
}
|
|
2803
3062
|
function readProjectFile(workspaceRootDir) {
|
|
2804
3063
|
const file = projectFilePath(workspaceRootDir);
|
|
2805
|
-
if (!
|
|
3064
|
+
if (!fs19.existsSync(file)) return {};
|
|
2806
3065
|
try {
|
|
2807
|
-
return JSON.parse(
|
|
3066
|
+
return JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
2808
3067
|
} catch {
|
|
2809
3068
|
return {};
|
|
2810
3069
|
}
|
|
2811
3070
|
}
|
|
2812
3071
|
function writeProjectFile(workspaceRootDir, data) {
|
|
2813
3072
|
const file = projectFilePath(workspaceRootDir);
|
|
2814
|
-
|
|
2815
|
-
|
|
3073
|
+
fs19.mkdirSync(path18.dirname(file), { recursive: true });
|
|
3074
|
+
fs19.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
|
|
2816
3075
|
}
|
|
2817
3076
|
function resolveAppIdentity(workspaceRootDir, config = {}) {
|
|
2818
3077
|
const project = readProjectFile(workspaceRootDir);
|
|
@@ -2837,11 +3096,11 @@ function readAppIdentity(workspaceRootDir, config = {}) {
|
|
|
2837
3096
|
}
|
|
2838
3097
|
function defaultProjectName(workspaceRootDir) {
|
|
2839
3098
|
try {
|
|
2840
|
-
const pkg = readPackageJson(
|
|
3099
|
+
const pkg = readPackageJson(path18.join(workspaceRootDir, "package.json"));
|
|
2841
3100
|
if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
|
|
2842
3101
|
} catch {
|
|
2843
3102
|
}
|
|
2844
|
-
return
|
|
3103
|
+
return path18.basename(workspaceRootDir);
|
|
2845
3104
|
}
|
|
2846
3105
|
function slug(value) {
|
|
2847
3106
|
return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
|
|
@@ -2902,15 +3161,15 @@ function releaseId(date = /* @__PURE__ */ new Date()) {
|
|
|
2902
3161
|
}
|
|
2903
3162
|
|
|
2904
3163
|
// src/lib/artifact.ts
|
|
2905
|
-
import
|
|
2906
|
-
import
|
|
3164
|
+
import fs21 from "node:fs";
|
|
3165
|
+
import path20 from "node:path";
|
|
2907
3166
|
import { detect as detect4 } from "package-manager-detector";
|
|
2908
3167
|
import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
|
|
2909
3168
|
|
|
2910
3169
|
// src/lib/ssh.ts
|
|
2911
|
-
import
|
|
2912
|
-
import
|
|
2913
|
-
import
|
|
3170
|
+
import fs20 from "node:fs";
|
|
3171
|
+
import os3 from "node:os";
|
|
3172
|
+
import path19 from "node:path";
|
|
2914
3173
|
import crypto2 from "node:crypto";
|
|
2915
3174
|
import process10 from "node:process";
|
|
2916
3175
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -2953,9 +3212,9 @@ var SshSession = class {
|
|
|
2953
3212
|
}
|
|
2954
3213
|
async open() {
|
|
2955
3214
|
if (this.controlPath) return;
|
|
2956
|
-
const dir =
|
|
2957
|
-
|
|
2958
|
-
const socket =
|
|
3215
|
+
const dir = path19.join(os3.tmpdir(), "vela-ssh");
|
|
3216
|
+
fs20.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3217
|
+
const socket = path19.join(dir, `${crypto2.randomBytes(6).toString("hex")}.sock`);
|
|
2959
3218
|
this.controlPath = socket;
|
|
2960
3219
|
const args = [
|
|
2961
3220
|
...this.sshArgs(),
|
|
@@ -3245,11 +3504,11 @@ function collectArtifact(cwd, config = {}) {
|
|
|
3245
3504
|
const outputDir = config.outputDir ?? DEFAULT_OUTPUT_DIR;
|
|
3246
3505
|
const entries = [];
|
|
3247
3506
|
const add2 = (rel, remoteDir = "") => {
|
|
3248
|
-
const localPath =
|
|
3249
|
-
if (
|
|
3507
|
+
const localPath = path20.join(cwd, rel);
|
|
3508
|
+
if (fs21.existsSync(localPath)) entries.push({ localPath, remoteDir });
|
|
3250
3509
|
};
|
|
3251
|
-
const buildPath =
|
|
3252
|
-
if (!
|
|
3510
|
+
const buildPath = path20.join(cwd, outputDir);
|
|
3511
|
+
if (!fs21.existsSync(path20.join(buildPath, "index.js"))) {
|
|
3253
3512
|
throw new BuildError(
|
|
3254
3513
|
`No ${outputDir}/index.js after the build.
|
|
3255
3514
|
|
|
@@ -3262,8 +3521,8 @@ the adapter in your Vite or Svelte config, then build again.`
|
|
|
3262
3521
|
add2("package-lock.json");
|
|
3263
3522
|
add2(".npmrc");
|
|
3264
3523
|
add2(MIGRATIONS_DIR);
|
|
3265
|
-
const hooks =
|
|
3266
|
-
if (
|
|
3524
|
+
const hooks = path20.join(cwd, DATA_DIR, "hooks");
|
|
3525
|
+
if (fs21.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
|
|
3267
3526
|
for (const extra of config.include ?? []) add2(extra);
|
|
3268
3527
|
return entries;
|
|
3269
3528
|
}
|
|
@@ -3285,11 +3544,11 @@ Name it: \`-t preview:<branch>\`.`
|
|
|
3285
3544
|
}
|
|
3286
3545
|
|
|
3287
3546
|
// src/lib/ssh-options.ts
|
|
3288
|
-
import * as
|
|
3547
|
+
import * as v5 from "valibot";
|
|
3289
3548
|
var SSH_OPTION_SCHEMA = {
|
|
3290
|
-
identity:
|
|
3291
|
-
sshPort:
|
|
3292
|
-
acceptHostKeys:
|
|
3549
|
+
identity: v5.optional(v5.string()),
|
|
3550
|
+
sshPort: v5.optional(v5.string()),
|
|
3551
|
+
acceptHostKeys: v5.optional(v5.boolean())
|
|
3293
3552
|
};
|
|
3294
3553
|
function addSshOptions(command) {
|
|
3295
3554
|
return command.option("-i, --identity <file>", "SSH private key to authenticate with").option("--ssh-port <port>", "SSH port").option("--accept-host-keys", "trust an unknown host key on first connect (CI)");
|
|
@@ -3303,7 +3562,7 @@ function sshOptionsFrom(options) {
|
|
|
3303
3562
|
}
|
|
3304
3563
|
|
|
3305
3564
|
// src/lib/remote.ts
|
|
3306
|
-
import
|
|
3565
|
+
import path21 from "node:path";
|
|
3307
3566
|
var VELA_ROOT = "/var/lib/vela";
|
|
3308
3567
|
var VELA_ETC = "/etc/vela";
|
|
3309
3568
|
var VELA_USER = "vela";
|
|
@@ -3311,7 +3570,7 @@ var SCRIPTS_DIR = `${VELA_ROOT}/scripts`;
|
|
|
3311
3570
|
var PROVISIONED_MARKER = `${VELA_ETC}/provisioned`;
|
|
3312
3571
|
var ORIGIN_FILE = `${VELA_ETC}/origin.json`;
|
|
3313
3572
|
function serverTemplatesDir() {
|
|
3314
|
-
return
|
|
3573
|
+
return path21.join(templatesDir(), "server");
|
|
3315
3574
|
}
|
|
3316
3575
|
async function syncServerScripts(session) {
|
|
3317
3576
|
await session.script(`mkdir -p "$1" && chmod 0755 "$1"`, { args: [SCRIPTS_DIR] });
|
|
@@ -3394,7 +3653,7 @@ var remotePaths = {
|
|
|
3394
3653
|
};
|
|
3395
3654
|
|
|
3396
3655
|
// src/lib/remote-env.ts
|
|
3397
|
-
import
|
|
3656
|
+
import fs22 from "node:fs";
|
|
3398
3657
|
import dotenv from "dotenv";
|
|
3399
3658
|
var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3400
3659
|
function isValidKey(key) {
|
|
@@ -3442,7 +3701,7 @@ function quote(value) {
|
|
|
3442
3701
|
return `"${escaped}"`;
|
|
3443
3702
|
}
|
|
3444
3703
|
function readLocalEnvFile(file) {
|
|
3445
|
-
const parsed = dotenv.parse(
|
|
3704
|
+
const parsed = dotenv.parse(fs22.readFileSync(file));
|
|
3446
3705
|
const result = {};
|
|
3447
3706
|
for (const [key, value] of Object.entries(parsed)) {
|
|
3448
3707
|
if (isValidKey(key)) result[key] = value;
|
|
@@ -3554,10 +3813,10 @@ function bold(text18) {
|
|
|
3554
3813
|
// src/lib/server-command.ts
|
|
3555
3814
|
var SERVER_OPTIONS_SCHEMA = {
|
|
3556
3815
|
...SSH_OPTION_SCHEMA,
|
|
3557
|
-
target:
|
|
3558
|
-
server:
|
|
3816
|
+
target: v6.optional(v6.string()),
|
|
3817
|
+
server: v6.optional(v6.string())
|
|
3559
3818
|
};
|
|
3560
|
-
var OptionsSchema =
|
|
3819
|
+
var OptionsSchema = v6.object(SERVER_OPTIONS_SCHEMA);
|
|
3561
3820
|
function addTargetOptions(command, fallback) {
|
|
3562
3821
|
return addSshOptions(command).option("-t, --target <target>", "which copy of the app to act on", fallback).option("--server <ssh>", "server this target runs on \u2014 recorded on first use");
|
|
3563
3822
|
}
|
|
@@ -3737,17 +3996,17 @@ function envFilePath(workspaceRootDir) {
|
|
|
3737
3996
|
import pc7 from "picocolors";
|
|
3738
3997
|
|
|
3739
3998
|
// src/lib/local-env.ts
|
|
3740
|
-
import
|
|
3999
|
+
import fs23 from "node:fs";
|
|
3741
4000
|
import * as p16 from "@clack/prompts";
|
|
3742
4001
|
import pc6 from "picocolors";
|
|
3743
4002
|
function readLocalEnv(envFile) {
|
|
3744
|
-
if (!
|
|
4003
|
+
if (!fs23.existsSync(envFile)) return {};
|
|
3745
4004
|
return readLocalEnvFile(envFile);
|
|
3746
4005
|
}
|
|
3747
4006
|
function editLocalEnv(envFile, edit) {
|
|
3748
|
-
const before =
|
|
4007
|
+
const before = fs23.existsSync(envFile) ? fs23.readFileSync(envFile, "utf8") : "";
|
|
3749
4008
|
const after = edit(before);
|
|
3750
|
-
if (after !== before)
|
|
4009
|
+
if (after !== before) fs23.writeFileSync(envFile, after);
|
|
3751
4010
|
}
|
|
3752
4011
|
function setLocalEnv(envFile, key, value) {
|
|
3753
4012
|
editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
|
|
@@ -3879,8 +4138,8 @@ Set ${pc7.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc7.cyan("POCKETBASE_SUPERUS
|
|
|
3879
4138
|
}
|
|
3880
4139
|
|
|
3881
4140
|
// src/lib/s3-settings.ts
|
|
3882
|
-
import
|
|
3883
|
-
import
|
|
4141
|
+
import fs24 from "node:fs";
|
|
4142
|
+
import path22 from "node:path";
|
|
3884
4143
|
var VIRTUAL_HOSTED = [/\.amazonaws\.com$/i, /\.r2\.cloudflarestorage\.com$/i];
|
|
3885
4144
|
function defaultForcePathStyle(endpoint) {
|
|
3886
4145
|
let host;
|
|
@@ -3918,18 +4177,18 @@ async function hasLocalUploads(session, instance, workspaceRootDir) {
|
|
|
3918
4177
|
});
|
|
3919
4178
|
return result.stdout.trim().length > 0;
|
|
3920
4179
|
}
|
|
3921
|
-
return hasFile(
|
|
4180
|
+
return hasFile(path22.join(workspaceRootDir, DATA_DIR, "storage"));
|
|
3922
4181
|
}
|
|
3923
4182
|
function hasFile(dir) {
|
|
3924
4183
|
let entries;
|
|
3925
4184
|
try {
|
|
3926
|
-
entries =
|
|
4185
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
3927
4186
|
} catch {
|
|
3928
4187
|
return false;
|
|
3929
4188
|
}
|
|
3930
4189
|
for (const entry of entries) {
|
|
3931
4190
|
if (entry.isFile()) return true;
|
|
3932
|
-
if (entry.isDirectory() && hasFile(
|
|
4191
|
+
if (entry.isDirectory() && hasFile(path22.join(dir, entry.name))) return true;
|
|
3933
4192
|
}
|
|
3934
4193
|
return false;
|
|
3935
4194
|
}
|
|
@@ -4053,14 +4312,14 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
|
|
|
4053
4312
|
host: () => p18.text({
|
|
4054
4313
|
message: "SMTP host",
|
|
4055
4314
|
placeholder: "smtp.example.com",
|
|
4056
|
-
validate: (
|
|
4315
|
+
validate: (v10) => v10 ? void 0 : "Host is required"
|
|
4057
4316
|
}),
|
|
4058
4317
|
port: () => p18.text({
|
|
4059
4318
|
message: "SMTP port",
|
|
4060
4319
|
initialValue: "587",
|
|
4061
|
-
validate: (
|
|
4062
|
-
if (!
|
|
4063
|
-
const n = Number(
|
|
4320
|
+
validate: (v10) => {
|
|
4321
|
+
if (!v10) return "Port is required";
|
|
4322
|
+
const n = Number(v10);
|
|
4064
4323
|
if (!Number.isInteger(n) || n <= 0 || n > 65535) return "Invalid port";
|
|
4065
4324
|
return void 0;
|
|
4066
4325
|
}
|
|
@@ -4102,43 +4361,41 @@ import process14 from "node:process";
|
|
|
4102
4361
|
import { Command as Command21 } from "commander";
|
|
4103
4362
|
import * as p19 from "@clack/prompts";
|
|
4104
4363
|
import pc9 from "picocolors";
|
|
4105
|
-
var cms = new Command21("cms").description("enable an inline-editing CMS with an admin bar").
|
|
4106
|
-
|
|
4107
|
-
|
|
4364
|
+
var cms = new Command21("cms").description("enable an inline-editing CMS with an admin bar").option(
|
|
4365
|
+
"--endpoint <url>",
|
|
4366
|
+
"read from a hosted CMS at this URL instead of installing the backend in this app"
|
|
4367
|
+
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4368
|
+
(opts, cmd) => runCommand(async () => {
|
|
4369
|
+
if (!opts.endpoint && !hasBackend()) {
|
|
4108
4370
|
p19.log.error(
|
|
4109
4371
|
`${pc9.cyan("vela enable cms")} needs a server to host the CMS backend, and this project is static.
|
|
4110
4372
|
|
|
4111
|
-
Run ${pc9.cyan("vela bless")} to add a backend
|
|
4373
|
+
Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${pc9.cyan("vela enable cms --endpoint <url>")}.`
|
|
4112
4374
|
);
|
|
4113
4375
|
p19.log.message();
|
|
4114
4376
|
p19.cancel("Operation failed.");
|
|
4115
4377
|
process14.exitCode = 1;
|
|
4116
4378
|
return;
|
|
4117
4379
|
}
|
|
4118
|
-
await runPattern(
|
|
4119
|
-
"
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
task: {
|
|
4130
|
-
title: "Enabling CMS",
|
|
4131
|
-
success: "Enabled CMS",
|
|
4132
|
-
error: "Failed to enable CMS"
|
|
4133
|
-
}
|
|
4380
|
+
await runPattern("enable-cms", cmd.args, opts.endpoint ? { endpoint: opts.endpoint } : {}, {
|
|
4381
|
+
summary: "Enabled CMS.",
|
|
4382
|
+
nextSteps: [
|
|
4383
|
+
opts.endpoint ? "Editors are managed where the CMS is hosted, not with `vela cms editor`." : "Run `vela cms editor add you@example.com` to create the first editor login.",
|
|
4384
|
+
"Run `vela dev`, open any page with `?edit` on the URL, and sign in from the admin bar.",
|
|
4385
|
+
"Wrap page copy in `<CmsText>` and images in `<CmsImage>` to make them editable."
|
|
4386
|
+
],
|
|
4387
|
+
task: {
|
|
4388
|
+
title: "Enabling CMS",
|
|
4389
|
+
success: "Enabled CMS",
|
|
4390
|
+
error: "Failed to enable CMS"
|
|
4134
4391
|
}
|
|
4135
|
-
);
|
|
4392
|
+
});
|
|
4136
4393
|
}, "Failed to enable CMS.")
|
|
4137
4394
|
);
|
|
4138
4395
|
|
|
4139
4396
|
// src/commands/enable/blog.ts
|
|
4140
4397
|
import { Command as Command22 } from "commander";
|
|
4141
|
-
var blog = new Command22("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4398
|
+
var blog = new Command22("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4142
4399
|
(_opts, cmd) => runCommand(
|
|
4143
4400
|
() => runPattern(
|
|
4144
4401
|
"enable-blog",
|
|
@@ -4164,7 +4421,7 @@ var blog = new Command22("blog").description("enable an mdsvex blog with posts,
|
|
|
4164
4421
|
|
|
4165
4422
|
// src/commands/enable/content-negotiation.ts
|
|
4166
4423
|
import { Command as Command23 } from "commander";
|
|
4167
|
-
var contentNegotiation = new Command23("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4424
|
+
var contentNegotiation = new Command23("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4168
4425
|
(_opts, cmd) => runCommand(
|
|
4169
4426
|
() => runPattern(
|
|
4170
4427
|
"enable-content-negotiation",
|
|
@@ -4214,7 +4471,7 @@ async function runDisable(opts, flags, cmdArgs) {
|
|
|
4214
4471
|
}
|
|
4215
4472
|
|
|
4216
4473
|
// src/commands/disable/auth.ts
|
|
4217
|
-
var auth2 = new Command25("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4474
|
+
var auth2 = new Command25("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4218
4475
|
(opts, cmd) => runCommand(
|
|
4219
4476
|
() => runDisable(
|
|
4220
4477
|
{
|
|
@@ -4241,7 +4498,7 @@ var auth2 = new Command25("auth").description("disable authentication").option("
|
|
|
4241
4498
|
|
|
4242
4499
|
// src/commands/disable/api.ts
|
|
4243
4500
|
import { Command as Command26 } from "commander";
|
|
4244
|
-
var api2 = new Command26("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4501
|
+
var api2 = new Command26("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4245
4502
|
(opts, cmd) => runCommand(
|
|
4246
4503
|
() => runDisable(
|
|
4247
4504
|
{
|
|
@@ -4265,7 +4522,7 @@ var api2 = new Command26("api").description("disable the REST API").option("-y,
|
|
|
4265
4522
|
|
|
4266
4523
|
// src/commands/disable/api-keys.ts
|
|
4267
4524
|
import { Command as Command27 } from "commander";
|
|
4268
|
-
var apiKeys2 = new Command27("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4525
|
+
var apiKeys2 = new Command27("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4269
4526
|
(opts, cmd) => runCommand(
|
|
4270
4527
|
() => runDisable(
|
|
4271
4528
|
{
|
|
@@ -4289,7 +4546,7 @@ var apiKeys2 = new Command27("api-keys").description("disable API key management
|
|
|
4289
4546
|
|
|
4290
4547
|
// src/commands/disable/backend.ts
|
|
4291
4548
|
import { Command as Command28 } from "commander";
|
|
4292
|
-
var backend2 = new Command28("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4549
|
+
var backend2 = new Command28("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4293
4550
|
(opts, cmd) => runCommand(
|
|
4294
4551
|
() => runDisable(
|
|
4295
4552
|
{
|
|
@@ -4313,7 +4570,7 @@ var backend2 = new Command28("backend").description("disable the PocketBase back
|
|
|
4313
4570
|
|
|
4314
4571
|
// src/commands/disable/content-negotiation.ts
|
|
4315
4572
|
import { Command as Command29 } from "commander";
|
|
4316
|
-
var contentNegotiation2 = new Command29("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4573
|
+
var contentNegotiation2 = new Command29("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4317
4574
|
(opts, cmd) => runCommand(
|
|
4318
4575
|
() => runDisable(
|
|
4319
4576
|
{
|
|
@@ -4337,7 +4594,7 @@ var contentNegotiation2 = new Command29("content-negotiation").description("disa
|
|
|
4337
4594
|
|
|
4338
4595
|
// src/commands/disable/i18n.ts
|
|
4339
4596
|
import { Command as Command30 } from "commander";
|
|
4340
|
-
var i18n2 = new Command30("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4597
|
+
var i18n2 = new Command30("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4341
4598
|
(opts, cmd) => runCommand(
|
|
4342
4599
|
() => runDisable(
|
|
4343
4600
|
{
|
|
@@ -4364,7 +4621,7 @@ var i18n2 = new Command30("i18n").description("disable internationalization").op
|
|
|
4364
4621
|
|
|
4365
4622
|
// src/commands/disable/teams.ts
|
|
4366
4623
|
import { Command as Command31 } from "commander";
|
|
4367
|
-
var teams2 = new Command31("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4624
|
+
var teams2 = new Command31("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4368
4625
|
(opts, cmd) => runCommand(
|
|
4369
4626
|
() => runDisable(
|
|
4370
4627
|
{
|
|
@@ -4391,7 +4648,7 @@ var teams2 = new Command31("teams").description("disable teams").option("-y, --y
|
|
|
4391
4648
|
|
|
4392
4649
|
// src/commands/disable/payments.ts
|
|
4393
4650
|
import { Command as Command32 } from "commander";
|
|
4394
|
-
var payments2 = new Command32("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4651
|
+
var payments2 = new Command32("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4395
4652
|
(opts, cmd) => runCommand(
|
|
4396
4653
|
() => runDisable(
|
|
4397
4654
|
{
|
|
@@ -4495,7 +4752,7 @@ async function runDestroy(slug2, model, confirmMessage, report4, flags) {
|
|
|
4495
4752
|
var form2 = new Command36("form").description("destroy a form generated by `vela generate form`").argument("<model>", "model name used when the form was generated (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").option(
|
|
4496
4753
|
"--route <route>",
|
|
4497
4754
|
"custom route the form was generated at (must match the --route used at generation)"
|
|
4498
|
-
).allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4755
|
+
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4499
4756
|
(model, opts) => runCommand(
|
|
4500
4757
|
() => runDestroy(
|
|
4501
4758
|
"destroy-form",
|
|
@@ -4517,7 +4774,7 @@ var form2 = new Command36("form").description("destroy a form generated by `vela
|
|
|
4517
4774
|
|
|
4518
4775
|
// src/commands/destroy/schema.ts
|
|
4519
4776
|
import { Command as Command37 } from "commander";
|
|
4520
|
-
var schema2 = new Command37("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4777
|
+
var schema2 = new Command37("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4521
4778
|
(model, opts) => runCommand(
|
|
4522
4779
|
() => runDestroy(
|
|
4523
4780
|
"destroy-schema",
|
|
@@ -4539,7 +4796,7 @@ var schema2 = new Command37("schema").description("destroy a zod schema generate
|
|
|
4539
4796
|
|
|
4540
4797
|
// src/commands/destroy/resource.ts
|
|
4541
4798
|
import { Command as Command38 } from "commander";
|
|
4542
|
-
var resource2 = new Command38("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4799
|
+
var resource2 = new Command38("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4543
4800
|
(model, opts) => runCommand(
|
|
4544
4801
|
() => runDestroy(
|
|
4545
4802
|
"destroy-resource",
|
|
@@ -4564,7 +4821,7 @@ import { Command as Command39 } from "commander";
|
|
|
4564
4821
|
var scaffold2 = new Command39("scaffold").description("destroy a scaffold generated by `vela generate scaffold`").argument("<model>", "model name used when the scaffold was generated (e.g., contact, todo)").option("-y, --yes", "skip confirmation prompt").option(
|
|
4565
4822
|
"--route <route>",
|
|
4566
4823
|
"custom route the scaffold was generated at (must match the --route used at generation)"
|
|
4567
|
-
).allowUnknownOption(true).configureHelp(helpConfig).action(
|
|
4824
|
+
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4568
4825
|
(model, opts) => runCommand(
|
|
4569
4826
|
() => runDestroy(
|
|
4570
4827
|
"destroy-scaffold",
|
|
@@ -5119,8 +5376,8 @@ var ui = new Command47("ui").description("generate ui components").configureHelp
|
|
|
5119
5376
|
import { Command as Command50 } from "commander";
|
|
5120
5377
|
|
|
5121
5378
|
// src/commands/legal/terms.ts
|
|
5122
|
-
import
|
|
5123
|
-
import
|
|
5379
|
+
import fs25 from "node:fs";
|
|
5380
|
+
import path23 from "node:path";
|
|
5124
5381
|
import { Command as Command48 } from "commander";
|
|
5125
5382
|
import * as p32 from "@clack/prompts";
|
|
5126
5383
|
|
|
@@ -5779,22 +6036,22 @@ async function termsAction() {
|
|
|
5779
6036
|
mobileApp,
|
|
5780
6037
|
contact
|
|
5781
6038
|
});
|
|
5782
|
-
const termsPage =
|
|
6039
|
+
const termsPage = path23.join(
|
|
5783
6040
|
workspaceRootDir,
|
|
5784
6041
|
publicRoutesDir,
|
|
5785
6042
|
LEGAL_DIR,
|
|
5786
6043
|
"terms",
|
|
5787
6044
|
"+page.svelte"
|
|
5788
6045
|
);
|
|
5789
|
-
const termsPageTs =
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
6046
|
+
const termsPageTs = path23.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
|
|
6047
|
+
fs25.mkdirSync(path23.dirname(termsPage), { recursive: true });
|
|
6048
|
+
fs25.writeFileSync(termsPage, html);
|
|
6049
|
+
fs25.writeFileSync(
|
|
5793
6050
|
termsPageTs,
|
|
5794
6051
|
pageMetaTagsLoader("Terms of Service", `Terms of Service for ${core.websiteName}`)
|
|
5795
6052
|
);
|
|
5796
|
-
const relativeTermsPage =
|
|
5797
|
-
const relativeTermsPageTs =
|
|
6053
|
+
const relativeTermsPage = path23.relative(workspaceRootDir, termsPage);
|
|
6054
|
+
const relativeTermsPageTs = path23.relative(workspaceRootDir, termsPageTs);
|
|
5798
6055
|
reportResult({
|
|
5799
6056
|
summary: "Generated placeholder terms and conditions.",
|
|
5800
6057
|
filesCreated: [relativeTermsPage, relativeTermsPageTs],
|
|
@@ -5808,8 +6065,8 @@ async function termsAction() {
|
|
|
5808
6065
|
var terms = new Command48("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
|
|
5809
6066
|
|
|
5810
6067
|
// src/commands/legal/privacy.ts
|
|
5811
|
-
import
|
|
5812
|
-
import
|
|
6068
|
+
import fs26 from "node:fs";
|
|
6069
|
+
import path24 from "node:path";
|
|
5813
6070
|
import { Command as Command49 } from "commander";
|
|
5814
6071
|
import * as p33 from "@clack/prompts";
|
|
5815
6072
|
var mapLabels = {
|
|
@@ -5898,9 +6155,9 @@ var compute2 = (a) => {
|
|
|
5898
6155
|
});
|
|
5899
6156
|
const piSelections = a.personalInfo ?? [];
|
|
5900
6157
|
const piLabels = piSelections.map(
|
|
5901
|
-
(
|
|
6158
|
+
(v10) => mapLabels.personalInfo[v10] ?? v10
|
|
5902
6159
|
);
|
|
5903
|
-
const lookup = (map, vs) => (vs ?? []).map((
|
|
6160
|
+
const lookup = (map, vs) => (vs ?? []).map((v10) => map[v10] ?? v10);
|
|
5904
6161
|
const companyName = a.core?.entityType === "business" ? a.core?.businessName ?? a.core?.websiteName : a.core?.websiteName ?? "Our Company";
|
|
5905
6162
|
const companyAddress = a.core?.entityType === "business" ? a.core?.businessAddress ?? "" : "";
|
|
5906
6163
|
const websiteName = a.core?.websiteName ?? "our website";
|
|
@@ -6522,28 +6779,28 @@ async function privacyAction() {
|
|
|
6522
6779
|
kids,
|
|
6523
6780
|
retention
|
|
6524
6781
|
});
|
|
6525
|
-
const privacyPage =
|
|
6782
|
+
const privacyPage = path24.join(
|
|
6526
6783
|
workspaceRootDir,
|
|
6527
6784
|
publicRoutesDir,
|
|
6528
6785
|
LEGAL_DIR,
|
|
6529
6786
|
"privacy",
|
|
6530
6787
|
"+page.svelte"
|
|
6531
6788
|
);
|
|
6532
|
-
const privacyPageTs =
|
|
6789
|
+
const privacyPageTs = path24.join(
|
|
6533
6790
|
workspaceRootDir,
|
|
6534
6791
|
publicRoutesDir,
|
|
6535
6792
|
LEGAL_DIR,
|
|
6536
6793
|
"privacy",
|
|
6537
6794
|
"+page.ts"
|
|
6538
6795
|
);
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6796
|
+
fs26.mkdirSync(path24.dirname(privacyPage), { recursive: true });
|
|
6797
|
+
fs26.writeFileSync(privacyPage, html);
|
|
6798
|
+
fs26.writeFileSync(
|
|
6542
6799
|
privacyPageTs,
|
|
6543
6800
|
pageMetaTagsLoader("Privacy Policy", `Privacy Policy for ${core.websiteName}`)
|
|
6544
6801
|
);
|
|
6545
|
-
const relativePrivacyPage =
|
|
6546
|
-
const relativePrivacyPageTs =
|
|
6802
|
+
const relativePrivacyPage = path24.relative(workspaceRootDir, privacyPage);
|
|
6803
|
+
const relativePrivacyPageTs = path24.relative(workspaceRootDir, privacyPageTs);
|
|
6547
6804
|
reportResult({
|
|
6548
6805
|
summary: "Generated placeholder privacy policy.",
|
|
6549
6806
|
filesCreated: [relativePrivacyPage, relativePrivacyPageTs],
|
|
@@ -6566,8 +6823,8 @@ import { Command as Command56 } from "commander";
|
|
|
6566
6823
|
import { Command as Command51 } from "commander";
|
|
6567
6824
|
|
|
6568
6825
|
// src/lib/data.ts
|
|
6569
|
-
import
|
|
6570
|
-
import
|
|
6826
|
+
import fs27 from "node:fs";
|
|
6827
|
+
import path25 from "node:path";
|
|
6571
6828
|
import { ClientResponseError } from "pocketbase";
|
|
6572
6829
|
|
|
6573
6830
|
// src/lib/collections.ts
|
|
@@ -6604,14 +6861,14 @@ function dependencyOrder(collections2, startingCollectionId) {
|
|
|
6604
6861
|
|
|
6605
6862
|
// src/lib/data.ts
|
|
6606
6863
|
function dataDir(cwd, kind) {
|
|
6607
|
-
return
|
|
6864
|
+
return path25.join(cwd, DATA_DIR, kind);
|
|
6608
6865
|
}
|
|
6609
6866
|
function getDataFiles(cwd, kind) {
|
|
6610
6867
|
const dir = dataDir(cwd, kind);
|
|
6611
|
-
if (!
|
|
6612
|
-
return
|
|
6868
|
+
if (!fs27.existsSync(dir)) return [];
|
|
6869
|
+
return fs27.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
|
|
6613
6870
|
collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
|
|
6614
|
-
filePath:
|
|
6871
|
+
filePath: path25.join(dir, file)
|
|
6615
6872
|
}));
|
|
6616
6873
|
}
|
|
6617
6874
|
function getSeedFiles(cwd) {
|
|
@@ -6621,7 +6878,7 @@ function getFixtureFiles(cwd) {
|
|
|
6621
6878
|
return getDataFiles(cwd, "fixtures");
|
|
6622
6879
|
}
|
|
6623
6880
|
function readRecords(filePath) {
|
|
6624
|
-
return JSON.parse(
|
|
6881
|
+
return JSON.parse(fs27.readFileSync(filePath, "utf8"));
|
|
6625
6882
|
}
|
|
6626
6883
|
function readSeedIds(cwd) {
|
|
6627
6884
|
const ids = /* @__PURE__ */ new Map();
|
|
@@ -6658,7 +6915,7 @@ function describeError(e) {
|
|
|
6658
6915
|
return e instanceof Error ? e.message : String(e);
|
|
6659
6916
|
}
|
|
6660
6917
|
function label3(cwd, filePath, count) {
|
|
6661
|
-
return `${
|
|
6918
|
+
return `${path25.relative(cwd, filePath)} (${count} records)`;
|
|
6662
6919
|
}
|
|
6663
6920
|
async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
|
|
6664
6921
|
const records = readRecords(filePath);
|
|
@@ -6666,7 +6923,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
|
|
|
6666
6923
|
try {
|
|
6667
6924
|
await pb.collection(collectionName).create(record);
|
|
6668
6925
|
} catch (e) {
|
|
6669
|
-
throw new DataLoadError(kind,
|
|
6926
|
+
throw new DataLoadError(kind, path25.relative(cwd, filePath), index, e);
|
|
6670
6927
|
}
|
|
6671
6928
|
}
|
|
6672
6929
|
return records.length;
|
|
@@ -6840,8 +7097,8 @@ var reset = new Command53("reset").description("clear and reload fixtures").conf
|
|
|
6840
7097
|
);
|
|
6841
7098
|
|
|
6842
7099
|
// src/commands/fixtures/generate.ts
|
|
6843
|
-
import
|
|
6844
|
-
import
|
|
7100
|
+
import fs28 from "node:fs";
|
|
7101
|
+
import path26 from "node:path";
|
|
6845
7102
|
import { Command as Command54, InvalidArgumentError } from "commander";
|
|
6846
7103
|
import * as p34 from "@clack/prompts";
|
|
6847
7104
|
import { annotate } from "annotate-json-schema";
|
|
@@ -6878,9 +7135,9 @@ async function loadCollections(pb) {
|
|
|
6878
7135
|
}
|
|
6879
7136
|
async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
6880
7137
|
const fixturesDir = dataDir(workspaceRootDir, "fixtures");
|
|
6881
|
-
|
|
6882
|
-
for (const file of
|
|
6883
|
-
if (file.endsWith(".json"))
|
|
7138
|
+
fs28.mkdirSync(fixturesDir, { recursive: true });
|
|
7139
|
+
for (const file of fs28.readdirSync(fixturesDir)) {
|
|
7140
|
+
if (file.endsWith(".json")) fs28.unlinkSync(path26.join(fixturesDir, file));
|
|
6884
7141
|
}
|
|
6885
7142
|
if (opts.seed !== void 0) faker.seed(opts.seed);
|
|
6886
7143
|
const generator = createGenerator({
|
|
@@ -6947,8 +7204,8 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
|
6947
7204
|
items.push(record);
|
|
6948
7205
|
}
|
|
6949
7206
|
const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
|
|
6950
|
-
|
|
6951
|
-
writtenFiles.push(`${
|
|
7207
|
+
fs28.writeFileSync(path26.join(fixturesDir, filename), JSON.stringify(items, null, 2));
|
|
7208
|
+
writtenFiles.push(`${path26.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
|
|
6952
7209
|
fileIndex++;
|
|
6953
7210
|
}
|
|
6954
7211
|
return { writtenFiles, warnings };
|
|
@@ -7095,8 +7352,8 @@ var load2 = new Command57("load").description("load seeds into the database").op
|
|
|
7095
7352
|
);
|
|
7096
7353
|
|
|
7097
7354
|
// src/commands/seeds/save.ts
|
|
7098
|
-
import
|
|
7099
|
-
import
|
|
7355
|
+
import fs29 from "node:fs";
|
|
7356
|
+
import path27 from "node:path";
|
|
7100
7357
|
import { Command as Command58 } from "commander";
|
|
7101
7358
|
var padZeros2 = (num, length) => num.toString().padStart(length, "0");
|
|
7102
7359
|
function filterSystemFields(record, systemFieldNames) {
|
|
@@ -7116,10 +7373,10 @@ var save = new Command58("save").description("save the current data as seeds").o
|
|
|
7116
7373
|
if (existing.length > 0 && !opts.force) {
|
|
7117
7374
|
throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
|
|
7118
7375
|
}
|
|
7119
|
-
|
|
7376
|
+
fs29.mkdirSync(seedsPath, { recursive: true });
|
|
7120
7377
|
if (opts.force) {
|
|
7121
|
-
for (const file of
|
|
7122
|
-
if (file.endsWith(".json"))
|
|
7378
|
+
for (const file of fs29.readdirSync(seedsPath)) {
|
|
7379
|
+
if (file.endsWith(".json")) fs29.unlinkSync(path27.join(seedsPath, file));
|
|
7123
7380
|
}
|
|
7124
7381
|
}
|
|
7125
7382
|
const saved = [];
|
|
@@ -7148,13 +7405,13 @@ var save = new Command58("save").description("save the current data as seeds").o
|
|
|
7148
7405
|
const filtered = records.map(
|
|
7149
7406
|
(r) => filterSystemFields(r, systemFieldNames)
|
|
7150
7407
|
);
|
|
7151
|
-
const relativeSeedPath =
|
|
7408
|
+
const relativeSeedPath = path27.join(
|
|
7152
7409
|
DATA_DIR,
|
|
7153
7410
|
"seeds",
|
|
7154
7411
|
`${padZeros2(count, 2)}-${collectionName}.json`
|
|
7155
7412
|
);
|
|
7156
|
-
const seedPath =
|
|
7157
|
-
|
|
7413
|
+
const seedPath = path27.join(workspaceRootDir, relativeSeedPath);
|
|
7414
|
+
fs29.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
|
|
7158
7415
|
saved.push(`${relativeSeedPath} (${filtered.length} records)`);
|
|
7159
7416
|
count++;
|
|
7160
7417
|
}
|
|
@@ -7220,7 +7477,7 @@ import * as p37 from "@clack/prompts";
|
|
|
7220
7477
|
import makeFetchCookie2 from "fetch-cookie";
|
|
7221
7478
|
|
|
7222
7479
|
// src/commands/login.ts
|
|
7223
|
-
import
|
|
7480
|
+
import os4 from "node:os";
|
|
7224
7481
|
import { Command as Command61 } from "commander";
|
|
7225
7482
|
import * as p36 from "@clack/prompts";
|
|
7226
7483
|
import makeFetchCookie from "fetch-cookie";
|
|
@@ -7254,7 +7511,7 @@ var login = new Command61("login").description("login to velastack.dev").configu
|
|
|
7254
7511
|
}, "Failed to login.")
|
|
7255
7512
|
);
|
|
7256
7513
|
async function issueApiKey(fetchCookie) {
|
|
7257
|
-
const label4 = `CLI - ${
|
|
7514
|
+
const label4 = `CLI - ${os4.hostname()}`;
|
|
7258
7515
|
await fetchCookie(`${API_URL}/api-keys/new`, {
|
|
7259
7516
|
method: "POST",
|
|
7260
7517
|
headers: {
|
|
@@ -7365,7 +7622,7 @@ import { Command as Command70 } from "commander";
|
|
|
7365
7622
|
import { Command as Command65 } from "commander";
|
|
7366
7623
|
|
|
7367
7624
|
// src/lib/migrate.ts
|
|
7368
|
-
import
|
|
7625
|
+
import path28 from "node:path";
|
|
7369
7626
|
import process19 from "node:process";
|
|
7370
7627
|
import { x as x2 } from "tinyexec";
|
|
7371
7628
|
async function runPocketbaseMigrate(args) {
|
|
@@ -7376,9 +7633,9 @@ async function runPocketbaseMigrate(args) {
|
|
|
7376
7633
|
binaryPath,
|
|
7377
7634
|
[
|
|
7378
7635
|
"--dir",
|
|
7379
|
-
|
|
7636
|
+
path28.join(cwd, DATA_DIR),
|
|
7380
7637
|
"--migrationsDir",
|
|
7381
|
-
|
|
7638
|
+
path28.join(cwd, MIGRATIONS_DIR),
|
|
7382
7639
|
"migrate",
|
|
7383
7640
|
...args
|
|
7384
7641
|
],
|
|
@@ -7426,8 +7683,8 @@ var down = new Command66("down").alias("rollback").description("revert the last
|
|
|
7426
7683
|
);
|
|
7427
7684
|
|
|
7428
7685
|
// src/commands/migrate/create.ts
|
|
7429
|
-
import
|
|
7430
|
-
import
|
|
7686
|
+
import fs30 from "node:fs";
|
|
7687
|
+
import path29 from "node:path";
|
|
7431
7688
|
import process20 from "node:process";
|
|
7432
7689
|
import { Command as Command67 } from "commander";
|
|
7433
7690
|
var create2 = new Command67("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
|
|
@@ -7439,7 +7696,7 @@ var create2 = new Command67("create").alias("new").description("create a new bla
|
|
|
7439
7696
|
const added = [...after].filter((f) => !before.has(f));
|
|
7440
7697
|
reportResult({
|
|
7441
7698
|
summary: `Created blank migration ${name}.`,
|
|
7442
|
-
filesCreated: added.map((f) =>
|
|
7699
|
+
filesCreated: added.map((f) => path29.join(MIGRATIONS_DIR, f)),
|
|
7443
7700
|
nextSteps: [
|
|
7444
7701
|
`Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
|
|
7445
7702
|
"Run `vela migrate up` to apply the migration once the handlers are written."
|
|
@@ -7448,14 +7705,14 @@ var create2 = new Command67("create").alias("new").description("create a new bla
|
|
|
7448
7705
|
}, "Failed to create migration.")
|
|
7449
7706
|
);
|
|
7450
7707
|
function listMigrationFiles(cwd) {
|
|
7451
|
-
const dir =
|
|
7452
|
-
if (!
|
|
7453
|
-
return new Set(
|
|
7708
|
+
const dir = path29.join(cwd, MIGRATIONS_DIR);
|
|
7709
|
+
if (!fs30.existsSync(dir)) return /* @__PURE__ */ new Set();
|
|
7710
|
+
return new Set(fs30.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
|
|
7454
7711
|
}
|
|
7455
7712
|
|
|
7456
7713
|
// src/commands/migrate/collections.ts
|
|
7457
|
-
import
|
|
7458
|
-
import
|
|
7714
|
+
import fs31 from "node:fs";
|
|
7715
|
+
import path30 from "node:path";
|
|
7459
7716
|
import process21 from "node:process";
|
|
7460
7717
|
import { Command as Command68 } from "commander";
|
|
7461
7718
|
var collections = new Command68("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
|
|
@@ -7473,7 +7730,7 @@ var collections = new Command68("collections").alias("snapshot").description("sn
|
|
|
7473
7730
|
}
|
|
7474
7731
|
reportResult({
|
|
7475
7732
|
summary: "Snapshotted local collections into a new migration.",
|
|
7476
|
-
filesCreated: added.map((f) =>
|
|
7733
|
+
filesCreated: added.map((f) => path30.join(MIGRATIONS_DIR, f)),
|
|
7477
7734
|
nextSteps: [
|
|
7478
7735
|
`Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
|
|
7479
7736
|
"Commit the snapshot so teammates pick up the new schema.",
|
|
@@ -7483,9 +7740,9 @@ var collections = new Command68("collections").alias("snapshot").description("sn
|
|
|
7483
7740
|
}, "Failed to snapshot collections.")
|
|
7484
7741
|
);
|
|
7485
7742
|
function listMigrationFiles2(cwd) {
|
|
7486
|
-
const dir =
|
|
7487
|
-
if (!
|
|
7488
|
-
return new Set(
|
|
7743
|
+
const dir = path30.join(cwd, MIGRATIONS_DIR);
|
|
7744
|
+
if (!fs31.existsSync(dir)) return /* @__PURE__ */ new Set();
|
|
7745
|
+
return new Set(fs31.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
|
|
7489
7746
|
}
|
|
7490
7747
|
|
|
7491
7748
|
// src/commands/migrate/history-sync.ts
|
|
@@ -7504,8 +7761,8 @@ var historySync = new Command69("history-sync").description("drop _migrations ro
|
|
|
7504
7761
|
var migrate = new Command70("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
|
|
7505
7762
|
|
|
7506
7763
|
// src/commands/dev.ts
|
|
7507
|
-
import
|
|
7508
|
-
import
|
|
7764
|
+
import fs32 from "node:fs";
|
|
7765
|
+
import path32 from "node:path";
|
|
7509
7766
|
import process23 from "node:process";
|
|
7510
7767
|
import { performance } from "node:perf_hooks";
|
|
7511
7768
|
import { Command as Command71, InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
@@ -7513,7 +7770,7 @@ import pc15 from "picocolors";
|
|
|
7513
7770
|
import PocketBase4 from "pocketbase";
|
|
7514
7771
|
|
|
7515
7772
|
// src/lib/vite.ts
|
|
7516
|
-
import
|
|
7773
|
+
import path31 from "node:path";
|
|
7517
7774
|
import process22 from "node:process";
|
|
7518
7775
|
import { createRequire as createRequire2 } from "node:module";
|
|
7519
7776
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -7533,7 +7790,7 @@ function viteVersionError(version) {
|
|
|
7533
7790
|
}
|
|
7534
7791
|
function resolveProjectVite(cwd) {
|
|
7535
7792
|
try {
|
|
7536
|
-
return createRequire2(
|
|
7793
|
+
return createRequire2(path31.join(cwd, "package.json")).resolve("vite");
|
|
7537
7794
|
} catch {
|
|
7538
7795
|
return null;
|
|
7539
7796
|
}
|
|
@@ -7562,21 +7819,21 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
7562
7819
|
process23.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
7563
7820
|
const startTime = performance.now();
|
|
7564
7821
|
const { createServer, version } = await loadVite(cwd);
|
|
7565
|
-
const viteMetadataDir =
|
|
7566
|
-
const viteMetadataFile =
|
|
7822
|
+
const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
|
|
7823
|
+
const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
|
|
7567
7824
|
let pbProc;
|
|
7568
7825
|
const backend3 = hasBackend(cwd);
|
|
7569
7826
|
const needsStart = backend3 && !process23.env.POCKETBASE_URL;
|
|
7570
7827
|
const cleanup = () => {
|
|
7571
7828
|
if (pbProc?.pid) pbProc.kill();
|
|
7572
|
-
if (
|
|
7829
|
+
if (fs32.existsSync(viteMetadataFile)) fs32.rmSync(viteMetadataFile);
|
|
7573
7830
|
};
|
|
7574
7831
|
if (needsStart) {
|
|
7575
|
-
const dataDir2 =
|
|
7832
|
+
const dataDir2 = path32.join(cwd, DATA_DIR);
|
|
7576
7833
|
const started = await startPocketbaseServe({
|
|
7577
7834
|
dataDir: dataDir2,
|
|
7578
7835
|
migrationsDir: MIGRATIONS_DIR,
|
|
7579
|
-
hooksDir:
|
|
7836
|
+
hooksDir: path32.join(dataDir2, "hooks"),
|
|
7580
7837
|
dev: true,
|
|
7581
7838
|
stdio: "pipe"
|
|
7582
7839
|
});
|
|
@@ -7607,8 +7864,8 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
7607
7864
|
if (!backend3) return;
|
|
7608
7865
|
const { address, port: vitePort } = server.httpServer.address();
|
|
7609
7866
|
const viteHost = address === "::1" ? "localhost" : address;
|
|
7610
|
-
await
|
|
7611
|
-
await
|
|
7867
|
+
await fs32.promises.mkdir(viteMetadataDir, { recursive: true });
|
|
7868
|
+
await fs32.promises.writeFile(
|
|
7612
7869
|
viteMetadataFile,
|
|
7613
7870
|
JSON.stringify({
|
|
7614
7871
|
pocketbaseUrl: process23.env.POCKETBASE_URL,
|
|
@@ -7640,18 +7897,18 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
7640
7897
|
});
|
|
7641
7898
|
async function startWatchingTypes(cwd, pb) {
|
|
7642
7899
|
const { processTypes } = await import("@velastack/pocketbase-codegen");
|
|
7643
|
-
const typesDir =
|
|
7644
|
-
const pocketbaseDir =
|
|
7645
|
-
const pocketbaseTypes =
|
|
7900
|
+
const typesDir = path32.resolve(cwd, ".svelte-kit", "types");
|
|
7901
|
+
const pocketbaseDir = path32.join(typesDir, "pocketbase");
|
|
7902
|
+
const pocketbaseTypes = path32.join(pocketbaseDir, "$types.d.ts");
|
|
7646
7903
|
const regenerate = () => processTypes(pb, typesDir).catch(() => {
|
|
7647
7904
|
});
|
|
7648
7905
|
await regenerate();
|
|
7649
7906
|
void (async () => {
|
|
7650
7907
|
for (; ; ) {
|
|
7651
7908
|
try {
|
|
7652
|
-
await
|
|
7653
|
-
for await (const event of
|
|
7654
|
-
if (event.eventType === "rename" && event.filename === "$types.d.ts" && !
|
|
7909
|
+
await fs32.promises.mkdir(pocketbaseDir, { recursive: true });
|
|
7910
|
+
for await (const event of fs32.promises.watch(pocketbaseDir)) {
|
|
7911
|
+
if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs32.existsSync(pocketbaseTypes)) {
|
|
7655
7912
|
setTimeout(regenerate, 100);
|
|
7656
7913
|
}
|
|
7657
7914
|
}
|
|
@@ -7663,8 +7920,8 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
7663
7920
|
}
|
|
7664
7921
|
|
|
7665
7922
|
// src/commands/build.ts
|
|
7666
|
-
import
|
|
7667
|
-
import
|
|
7923
|
+
import fs33 from "node:fs";
|
|
7924
|
+
import path33 from "node:path";
|
|
7668
7925
|
import process25 from "node:process";
|
|
7669
7926
|
import { Command as Command72 } from "commander";
|
|
7670
7927
|
import * as p40 from "@clack/prompts";
|
|
@@ -7702,7 +7959,7 @@ function splitHosts(value) {
|
|
|
7702
7959
|
}
|
|
7703
7960
|
|
|
7704
7961
|
// src/commands/build.ts
|
|
7705
|
-
var PRERENDERED_DIR =
|
|
7962
|
+
var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
|
|
7706
7963
|
var build = new Command72("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
|
|
7707
7964
|
const cwd = process25.cwd();
|
|
7708
7965
|
applyBuildEnv(cwd);
|
|
@@ -7715,11 +7972,11 @@ var build = new Command72("build").description("build the app").configureHelp(he
|
|
|
7715
7972
|
};
|
|
7716
7973
|
if (needsStart) {
|
|
7717
7974
|
await ensureSuperuser(cwd);
|
|
7718
|
-
const dataDir2 =
|
|
7975
|
+
const dataDir2 = path33.join(cwd, DATA_DIR);
|
|
7719
7976
|
const started = await startPocketbaseServe({
|
|
7720
7977
|
dataDir: dataDir2,
|
|
7721
7978
|
migrationsDir: MIGRATIONS_DIR,
|
|
7722
|
-
hooksDir:
|
|
7979
|
+
hooksDir: path33.join(dataDir2, "hooks"),
|
|
7723
7980
|
dev: true
|
|
7724
7981
|
});
|
|
7725
7982
|
pbProc = started.proc;
|
|
@@ -7758,8 +8015,8 @@ async function originForBuild(cwd, target) {
|
|
|
7758
8015
|
}
|
|
7759
8016
|
}
|
|
7760
8017
|
function warnIfPrerendered(cwd) {
|
|
7761
|
-
const dir =
|
|
7762
|
-
if (!
|
|
8018
|
+
const dir = path33.join(cwd, PRERENDERED_DIR);
|
|
8019
|
+
if (!fs33.existsSync(dir) || fs33.readdirSync(dir).length === 0) return;
|
|
7763
8020
|
p40.log.warn(
|
|
7764
8021
|
`Prerendered pages were built with no domain configured, so their canonical
|
|
7765
8022
|
links point at SvelteKit's placeholder host rather than at this site.
|
|
@@ -7769,7 +8026,7 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
|
|
|
7769
8026
|
}
|
|
7770
8027
|
|
|
7771
8028
|
// src/commands/preview.ts
|
|
7772
|
-
import
|
|
8029
|
+
import path34 from "node:path";
|
|
7773
8030
|
import process26 from "node:process";
|
|
7774
8031
|
import { Command as Command73 } from "commander";
|
|
7775
8032
|
import { x as x4 } from "tinyexec";
|
|
@@ -7784,11 +8041,11 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
7784
8041
|
if (pbProc?.pid) pbProc.kill();
|
|
7785
8042
|
};
|
|
7786
8043
|
if (needsStart) {
|
|
7787
|
-
const dataDir2 =
|
|
8044
|
+
const dataDir2 = path34.join(cwd, DATA_DIR);
|
|
7788
8045
|
const started = await startPocketbaseServe({
|
|
7789
8046
|
dataDir: dataDir2,
|
|
7790
8047
|
migrationsDir: MIGRATIONS_DIR,
|
|
7791
|
-
hooksDir:
|
|
8048
|
+
hooksDir: path34.join(dataDir2, "hooks"),
|
|
7792
8049
|
dev: true
|
|
7793
8050
|
});
|
|
7794
8051
|
pbProc = started.proc;
|
|
@@ -7814,12 +8071,12 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
7814
8071
|
});
|
|
7815
8072
|
|
|
7816
8073
|
// src/commands/sync.ts
|
|
7817
|
-
import
|
|
8074
|
+
import path35 from "node:path";
|
|
7818
8075
|
import { Command as Command74 } from "commander";
|
|
7819
8076
|
var sync = new Command74("sync").description("sync types from the database").configureHelp(helpConfig).action(
|
|
7820
8077
|
() => runCommand(async () => {
|
|
7821
8078
|
const { workspaceRootDir } = await getWorkspace();
|
|
7822
|
-
const typesDir =
|
|
8079
|
+
const typesDir = path35.join(workspaceRootDir, ".svelte-kit", "types");
|
|
7823
8080
|
const { processTypes } = await import("@velastack/pocketbase-codegen");
|
|
7824
8081
|
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
7825
8082
|
await processTypes(pb, typesDir);
|
|
@@ -7832,11 +8089,11 @@ var sync = new Command74("sync").description("sync types from the database").con
|
|
|
7832
8089
|
import { Command as Command75 } from "commander";
|
|
7833
8090
|
import * as p41 from "@clack/prompts";
|
|
7834
8091
|
import pc17 from "picocolors";
|
|
7835
|
-
import * as
|
|
7836
|
-
var OptionsSchema2 =
|
|
8092
|
+
import * as v7 from "valibot";
|
|
8093
|
+
var OptionsSchema2 = v7.object({
|
|
7837
8094
|
...SSH_OPTION_SCHEMA,
|
|
7838
|
-
pbVersion:
|
|
7839
|
-
nodeMajor:
|
|
8095
|
+
pbVersion: v7.optional(v7.string()),
|
|
8096
|
+
nodeMajor: v7.optional(v7.string())
|
|
7840
8097
|
});
|
|
7841
8098
|
var provision = addSshOptions(
|
|
7842
8099
|
new Command75("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
|
|
@@ -7881,22 +8138,22 @@ var provision = addSshOptions(
|
|
|
7881
8138
|
);
|
|
7882
8139
|
|
|
7883
8140
|
// src/commands/deploy.ts
|
|
7884
|
-
import
|
|
7885
|
-
import
|
|
8141
|
+
import path37 from "node:path";
|
|
8142
|
+
import fs35 from "node:fs";
|
|
7886
8143
|
import { Command as Command76, Option as Option2 } from "commander";
|
|
7887
8144
|
import * as p42 from "@clack/prompts";
|
|
7888
8145
|
import pc18 from "picocolors";
|
|
7889
|
-
import * as
|
|
8146
|
+
import * as v8 from "valibot";
|
|
7890
8147
|
|
|
7891
8148
|
// src/lib/pocketbase-settings.ts
|
|
7892
|
-
import
|
|
7893
|
-
import
|
|
8149
|
+
import fs34 from "node:fs";
|
|
8150
|
+
import path36 from "node:path";
|
|
7894
8151
|
import process27 from "node:process";
|
|
7895
8152
|
import PocketBase5 from "pocketbase";
|
|
7896
8153
|
var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
|
|
7897
8154
|
async function readLocalMeta(cwd) {
|
|
7898
|
-
const dataDir2 =
|
|
7899
|
-
if (!
|
|
8155
|
+
const dataDir2 = path36.join(cwd, DATA_DIR);
|
|
8156
|
+
if (!fs34.existsSync(dataDir2)) return null;
|
|
7900
8157
|
const email3 = process27.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
7901
8158
|
const password11 = process27.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
7902
8159
|
if (!email3 || !password11) return null;
|
|
@@ -7905,7 +8162,7 @@ async function readLocalMeta(cwd) {
|
|
|
7905
8162
|
const started = await startPocketbaseServe({
|
|
7906
8163
|
dataDir: dataDir2,
|
|
7907
8164
|
migrationsDir: MIGRATIONS_DIR,
|
|
7908
|
-
hooksDir:
|
|
8165
|
+
hooksDir: path36.join(dataDir2, "hooks")
|
|
7909
8166
|
});
|
|
7910
8167
|
proc = started.proc;
|
|
7911
8168
|
const pb = new PocketBase5(started.url);
|
|
@@ -7947,16 +8204,16 @@ async function seedRemoteMeta(session, instance, local, appURL) {
|
|
|
7947
8204
|
}
|
|
7948
8205
|
|
|
7949
8206
|
// src/commands/deploy.ts
|
|
7950
|
-
var OptionsSchema3 =
|
|
8207
|
+
var OptionsSchema3 = v8.object({
|
|
7951
8208
|
...SSH_OPTION_SCHEMA,
|
|
7952
|
-
env:
|
|
7953
|
-
project:
|
|
7954
|
-
remoteDb:
|
|
7955
|
-
domain:
|
|
7956
|
-
healthPath:
|
|
7957
|
-
keep:
|
|
7958
|
-
pbVersion:
|
|
7959
|
-
build:
|
|
8209
|
+
env: v8.optional(v8.string()),
|
|
8210
|
+
project: v8.optional(v8.string()),
|
|
8211
|
+
remoteDb: v8.optional(v8.boolean()),
|
|
8212
|
+
domain: v8.optional(v8.string()),
|
|
8213
|
+
healthPath: v8.optional(v8.string()),
|
|
8214
|
+
keep: v8.optional(v8.string()),
|
|
8215
|
+
pbVersion: v8.optional(v8.string()),
|
|
8216
|
+
build: v8.optional(v8.boolean())
|
|
7960
8217
|
});
|
|
7961
8218
|
var deploy = addTargetOptions(
|
|
7962
8219
|
new Command76("deploy").description("deploy the app").configureHelp(helpConfig),
|
|
@@ -8255,7 +8512,7 @@ async function uploadRelease(session, instance, release, entries) {
|
|
|
8255
8512
|
}
|
|
8256
8513
|
function isDirectory(target) {
|
|
8257
8514
|
try {
|
|
8258
|
-
return
|
|
8515
|
+
return fs35.statSync(target).isDirectory();
|
|
8259
8516
|
} catch {
|
|
8260
8517
|
return false;
|
|
8261
8518
|
}
|
|
@@ -8263,7 +8520,7 @@ function isDirectory(target) {
|
|
|
8263
8520
|
async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
8264
8521
|
const remote = await readRemoteEnv(session, instance);
|
|
8265
8522
|
if (Object.keys(remote).length > 0) return;
|
|
8266
|
-
if (!
|
|
8523
|
+
if (!fs35.existsSync(path37.join(workspaceRootDir, ".env"))) return;
|
|
8267
8524
|
p42.log.warn(
|
|
8268
8525
|
`This app has no production environment variables yet.
|
|
8269
8526
|
|
|
@@ -8273,7 +8530,7 @@ ${pc18.cyan("vela env set KEY")}, or copy a file across with ${pc18.cyan("vela e
|
|
|
8273
8530
|
}
|
|
8274
8531
|
|
|
8275
8532
|
// src/commands/link.ts
|
|
8276
|
-
import
|
|
8533
|
+
import path38 from "node:path";
|
|
8277
8534
|
import process28 from "node:process";
|
|
8278
8535
|
import { Command as Command77 } from "commander";
|
|
8279
8536
|
import * as p43 from "@clack/prompts";
|
|
@@ -8351,7 +8608,7 @@ async function promptProjectName(workspaceRootDir) {
|
|
|
8351
8608
|
defaultValue,
|
|
8352
8609
|
initialValue: defaultValue,
|
|
8353
8610
|
placeholder: defaultValue,
|
|
8354
|
-
validate: (
|
|
8611
|
+
validate: (v10) => !v10?.trim() ? "Required" : void 0
|
|
8355
8612
|
});
|
|
8356
8613
|
if (p43.isCancel(value)) {
|
|
8357
8614
|
p43.cancel("Operation cancelled.");
|
|
@@ -8361,12 +8618,12 @@ async function promptProjectName(workspaceRootDir) {
|
|
|
8361
8618
|
}
|
|
8362
8619
|
function defaultProjectName2(workspaceRootDir) {
|
|
8363
8620
|
try {
|
|
8364
|
-
const pkg = readPackageJson(
|
|
8621
|
+
const pkg = readPackageJson(path38.join(workspaceRootDir, "package.json"));
|
|
8365
8622
|
const name = pkg.name;
|
|
8366
8623
|
if (typeof name === "string" && name.trim()) return name.trim();
|
|
8367
8624
|
} catch {
|
|
8368
8625
|
}
|
|
8369
|
-
return
|
|
8626
|
+
return path38.basename(workspaceRootDir);
|
|
8370
8627
|
}
|
|
8371
8628
|
|
|
8372
8629
|
// src/commands/env.ts
|
|
@@ -8497,8 +8754,8 @@ var envUnset = addTargetOptions(
|
|
|
8497
8754
|
);
|
|
8498
8755
|
|
|
8499
8756
|
// src/commands/env/import.ts
|
|
8500
|
-
import
|
|
8501
|
-
import
|
|
8757
|
+
import fs36 from "node:fs";
|
|
8758
|
+
import path39 from "node:path";
|
|
8502
8759
|
import process30 from "node:process";
|
|
8503
8760
|
import { Command as Command81 } from "commander";
|
|
8504
8761
|
import * as p47 from "@clack/prompts";
|
|
@@ -8544,10 +8801,10 @@ var envImport = addTargetOptions(
|
|
|
8544
8801
|
)
|
|
8545
8802
|
);
|
|
8546
8803
|
function resolve(file) {
|
|
8547
|
-
return
|
|
8804
|
+
return path39.resolve(process30.cwd(), file);
|
|
8548
8805
|
}
|
|
8549
8806
|
function read(resolved, shown) {
|
|
8550
|
-
if (!
|
|
8807
|
+
if (!fs36.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
8551
8808
|
const incoming = readLocalEnvFile(resolved);
|
|
8552
8809
|
if (Object.keys(incoming).length === 0) p47.log.info(`${shown} has no variables to import.`);
|
|
8553
8810
|
return incoming;
|
|
@@ -8819,8 +9076,8 @@ var admin = new Command87("admin").description("manage admin panel logins").conf
|
|
|
8819
9076
|
import { Command as Command93 } from "commander";
|
|
8820
9077
|
|
|
8821
9078
|
// src/commands/backup/create.ts
|
|
8822
|
-
import
|
|
8823
|
-
import
|
|
9079
|
+
import fs37 from "node:fs";
|
|
9080
|
+
import path40 from "node:path";
|
|
8824
9081
|
import { Command as Command88 } from "commander";
|
|
8825
9082
|
import * as p51 from "@clack/prompts";
|
|
8826
9083
|
import pc26 from "picocolors";
|
|
@@ -8974,12 +9231,12 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
8974
9231
|
}, "Failed to create the backup.")
|
|
8975
9232
|
);
|
|
8976
9233
|
async function download(ctx, key, outputDir) {
|
|
8977
|
-
const dir =
|
|
8978
|
-
|
|
8979
|
-
const destination =
|
|
9234
|
+
const dir = path40.resolve(ctx.workspaceRootDir, outputDir);
|
|
9235
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
9236
|
+
const destination = path40.join(dir, key);
|
|
8980
9237
|
if (!ctx.session) {
|
|
8981
|
-
|
|
8982
|
-
return
|
|
9238
|
+
fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9239
|
+
return path40.relative(ctx.workspaceRootDir, destination);
|
|
8983
9240
|
}
|
|
8984
9241
|
const spinner7 = p51.spinner();
|
|
8985
9242
|
spinner7.start(`Downloading ${key}`);
|
|
@@ -8990,7 +9247,7 @@ async function download(ctx, key, outputDir) {
|
|
|
8990
9247
|
throw error;
|
|
8991
9248
|
}
|
|
8992
9249
|
spinner7.stop(`Downloaded ${key}`);
|
|
8993
|
-
return
|
|
9250
|
+
return path40.relative(ctx.workspaceRootDir, destination);
|
|
8994
9251
|
}
|
|
8995
9252
|
|
|
8996
9253
|
// src/commands/backup/list.ts
|
|
@@ -9024,8 +9281,8 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9024
9281
|
);
|
|
9025
9282
|
|
|
9026
9283
|
// src/commands/backup/download.ts
|
|
9027
|
-
import
|
|
9028
|
-
import
|
|
9284
|
+
import fs38 from "node:fs";
|
|
9285
|
+
import path41 from "node:path";
|
|
9029
9286
|
import { Command as Command90 } from "commander";
|
|
9030
9287
|
import * as p53 from "@clack/prompts";
|
|
9031
9288
|
import pc28 from "picocolors";
|
|
@@ -9052,11 +9309,11 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
|
|
|
9052
9309
|
Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
9053
9310
|
);
|
|
9054
9311
|
}
|
|
9055
|
-
const dir =
|
|
9056
|
-
|
|
9057
|
-
const destination =
|
|
9312
|
+
const dir = path41.resolve(ctx.workspaceRootDir, options.output);
|
|
9313
|
+
fs38.mkdirSync(dir, { recursive: true });
|
|
9314
|
+
const destination = path41.join(dir, key);
|
|
9058
9315
|
if (!ctx.session) {
|
|
9059
|
-
|
|
9316
|
+
fs38.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9060
9317
|
} else {
|
|
9061
9318
|
const spinner7 = p53.spinner();
|
|
9062
9319
|
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
@@ -9070,7 +9327,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9070
9327
|
}
|
|
9071
9328
|
reportResult({
|
|
9072
9329
|
summary: `Saved ${key} from ${ctx.targetName}.`,
|
|
9073
|
-
filesCreated: [
|
|
9330
|
+
filesCreated: [path41.relative(ctx.workspaceRootDir, destination)]
|
|
9074
9331
|
});
|
|
9075
9332
|
});
|
|
9076
9333
|
}, "Failed to download the backup.")
|
|
@@ -9165,8 +9422,8 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
|
9165
9422
|
var backup = new Command93("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
|
|
9166
9423
|
|
|
9167
9424
|
// src/commands/restore.ts
|
|
9168
|
-
import
|
|
9169
|
-
import
|
|
9425
|
+
import fs39 from "node:fs";
|
|
9426
|
+
import path42 from "node:path";
|
|
9170
9427
|
import process33 from "node:process";
|
|
9171
9428
|
import { Command as Command94 } from "commander";
|
|
9172
9429
|
import * as p56 from "@clack/prompts";
|
|
@@ -9187,7 +9444,7 @@ var restore = addTargetOptions(
|
|
|
9187
9444
|
`${ctx.targetName} was deployed without a database, so there is nothing to restore.`
|
|
9188
9445
|
);
|
|
9189
9446
|
}
|
|
9190
|
-
const local = source &&
|
|
9447
|
+
const local = source && fs39.existsSync(source) ? source : void 0;
|
|
9191
9448
|
const key = local ? void 0 : await resolveKey(ctx, source);
|
|
9192
9449
|
if (!options.yes) {
|
|
9193
9450
|
await confirm12(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
|
|
@@ -9209,7 +9466,7 @@ var restore = addTargetOptions(
|
|
|
9209
9466
|
});
|
|
9210
9467
|
p56.log.success(
|
|
9211
9468
|
`Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
|
|
9212
|
-
local ?
|
|
9469
|
+
local ? path42.basename(local) : key
|
|
9213
9470
|
)}.`
|
|
9214
9471
|
);
|
|
9215
9472
|
if (result?.storageCarriedOver) {
|
|
@@ -9275,21 +9532,21 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
|
|
|
9275
9532
|
}
|
|
9276
9533
|
async function stage(ctx, file) {
|
|
9277
9534
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
9278
|
-
const remote = `${dir}/${
|
|
9535
|
+
const remote = `${dir}/${path42.basename(file)}`;
|
|
9279
9536
|
const spinner7 = p56.spinner();
|
|
9280
|
-
spinner7.start(`Uploading ${
|
|
9537
|
+
spinner7.start(`Uploading ${path42.basename(file)}`);
|
|
9281
9538
|
try {
|
|
9282
9539
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
9283
9540
|
await ctx.session.upload([file], dir);
|
|
9284
9541
|
} catch (error) {
|
|
9285
|
-
spinner7.stop(`Could not upload ${
|
|
9542
|
+
spinner7.stop(`Could not upload ${path42.basename(file)}.`);
|
|
9286
9543
|
throw error;
|
|
9287
9544
|
}
|
|
9288
|
-
spinner7.stop(`Uploaded ${
|
|
9545
|
+
spinner7.stop(`Uploaded ${path42.basename(file)}`);
|
|
9289
9546
|
return remote;
|
|
9290
9547
|
}
|
|
9291
9548
|
async function confirm12(appName, targetName, envTag, from) {
|
|
9292
|
-
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(
|
|
9549
|
+
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path42.basename(from))}`;
|
|
9293
9550
|
if (isProd(envTag)) {
|
|
9294
9551
|
const answer = await p56.text({
|
|
9295
9552
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
@@ -9315,11 +9572,11 @@ async function confirm12(appName, targetName, envTag, from) {
|
|
|
9315
9572
|
import { Command as Command95 } from "commander";
|
|
9316
9573
|
import * as p57 from "@clack/prompts";
|
|
9317
9574
|
import pc32 from "picocolors";
|
|
9318
|
-
import * as
|
|
9319
|
-
var OptionsSchema4 =
|
|
9575
|
+
import * as v9 from "valibot";
|
|
9576
|
+
var OptionsSchema4 = v9.object({
|
|
9320
9577
|
...SSH_OPTION_SCHEMA,
|
|
9321
|
-
json:
|
|
9322
|
-
offline:
|
|
9578
|
+
json: v9.optional(v9.boolean()),
|
|
9579
|
+
offline: v9.optional(v9.boolean())
|
|
9323
9580
|
});
|
|
9324
9581
|
var targets = addSshOptions(
|
|
9325
9582
|
new Command95("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
|
|
@@ -9400,7 +9657,7 @@ Release and domain are shown from what this project recorded.`
|
|
|
9400
9657
|
}
|
|
9401
9658
|
|
|
9402
9659
|
// src/commands/test.ts
|
|
9403
|
-
import
|
|
9660
|
+
import path43 from "node:path";
|
|
9404
9661
|
import process34 from "node:process";
|
|
9405
9662
|
import { Command as Command96 } from "commander";
|
|
9406
9663
|
import PocketBase6 from "pocketbase";
|
|
@@ -9408,20 +9665,20 @@ import pc33 from "picocolors";
|
|
|
9408
9665
|
import { x as x5 } from "tinyexec";
|
|
9409
9666
|
import { detect as detect7 } from "package-manager-detector";
|
|
9410
9667
|
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
9411
|
-
import
|
|
9668
|
+
import fs40 from "node:fs";
|
|
9412
9669
|
var testServer = new Command96("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
9413
9670
|
const cwd = process34.cwd();
|
|
9414
9671
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
9415
9672
|
const password11 = "password";
|
|
9416
|
-
const testDataDir =
|
|
9417
|
-
|
|
9673
|
+
const testDataDir = path43.join(cwd, "test-data");
|
|
9674
|
+
fs40.rmSync(testDataDir, { recursive: true, force: true });
|
|
9418
9675
|
const { stop, url } = await launchPocketbase(cwd, {
|
|
9419
9676
|
dir: testDataDir,
|
|
9420
|
-
migrationsDir:
|
|
9677
|
+
migrationsDir: path43.join(cwd, MIGRATIONS_DIR),
|
|
9421
9678
|
// The app's PocketBase hooks (slug generation, personal teams, …) are part
|
|
9422
9679
|
// of its behaviour; the suite runs against the same server dev and build
|
|
9423
9680
|
// start, so it loads them from the same place.
|
|
9424
|
-
hooksDir:
|
|
9681
|
+
hooksDir: path43.join(cwd, DATA_DIR, "hooks"),
|
|
9425
9682
|
email: email3,
|
|
9426
9683
|
password: password11
|
|
9427
9684
|
});
|
|
@@ -9437,7 +9694,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9437
9694
|
if (cleanedUp) return;
|
|
9438
9695
|
cleanedUp = true;
|
|
9439
9696
|
stop();
|
|
9440
|
-
|
|
9697
|
+
fs40.rmSync(testDataDir, { recursive: true, force: true });
|
|
9441
9698
|
};
|
|
9442
9699
|
const cleanup = async () => {
|
|
9443
9700
|
if (cleanedUp) return;
|
|
@@ -9536,8 +9793,8 @@ function stubPagesPlugin() {
|
|
|
9536
9793
|
}
|
|
9537
9794
|
|
|
9538
9795
|
// src/commands/routes.ts
|
|
9539
|
-
import
|
|
9540
|
-
import
|
|
9796
|
+
import fs41 from "node:fs";
|
|
9797
|
+
import path44 from "node:path";
|
|
9541
9798
|
import { Command as Command97 } from "commander";
|
|
9542
9799
|
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
9543
9800
|
"GET",
|
|
@@ -9551,30 +9808,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
9551
9808
|
]);
|
|
9552
9809
|
var routes = new Command97("routes").description("list routes").configureHelp(helpConfig).action(async () => {
|
|
9553
9810
|
const { workspaceRootDir, routesDir } = await getWorkspace();
|
|
9554
|
-
const routesRoot =
|
|
9811
|
+
const routesRoot = path44.join(workspaceRootDir, routesDir);
|
|
9555
9812
|
const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
|
|
9556
9813
|
found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
|
|
9557
9814
|
printTable(found);
|
|
9558
9815
|
});
|
|
9559
9816
|
function walk(root, dir) {
|
|
9560
|
-
const entries =
|
|
9817
|
+
const entries = fs41.readdirSync(dir, { withFileTypes: true });
|
|
9561
9818
|
const routes2 = [];
|
|
9562
9819
|
const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
|
|
9563
9820
|
if (hasLeaf) {
|
|
9564
|
-
const id = "/" +
|
|
9821
|
+
const id = "/" + path44.relative(root, dir).split(path44.sep).filter(Boolean).join("/");
|
|
9565
9822
|
const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
|
|
9566
9823
|
const methods = /* @__PURE__ */ new Set();
|
|
9567
9824
|
for (const entry of entries) {
|
|
9568
9825
|
if (!entry.isFile()) continue;
|
|
9569
9826
|
if (entry.name.endsWith("+page.svelte")) methods.add("GET");
|
|
9570
9827
|
if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
|
|
9571
|
-
extractMethods(
|
|
9828
|
+
extractMethods(path44.join(dir, entry.name)).forEach((m) => methods.add(m));
|
|
9572
9829
|
}
|
|
9573
9830
|
}
|
|
9574
9831
|
routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
|
|
9575
9832
|
}
|
|
9576
9833
|
for (const entry of entries) {
|
|
9577
|
-
if (entry.isDirectory()) routes2.push(...walk(root,
|
|
9834
|
+
if (entry.isDirectory()) routes2.push(...walk(root, path44.join(dir, entry.name)));
|
|
9578
9835
|
}
|
|
9579
9836
|
return routes2;
|
|
9580
9837
|
}
|
|
@@ -9583,7 +9840,7 @@ function isRouteFile(name) {
|
|
|
9583
9840
|
}
|
|
9584
9841
|
function extractMethods(file) {
|
|
9585
9842
|
try {
|
|
9586
|
-
const content =
|
|
9843
|
+
const content = fs41.readFileSync(file, "utf8");
|
|
9587
9844
|
const methods = [];
|
|
9588
9845
|
const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
|
|
9589
9846
|
let match;
|
|
@@ -9640,11 +9897,11 @@ async function runWuchale(extraArgs) {
|
|
|
9640
9897
|
throwOnError: true
|
|
9641
9898
|
});
|
|
9642
9899
|
}
|
|
9643
|
-
var
|
|
9900
|
+
var extract2 = new Command98("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
|
|
9644
9901
|
var watch = new Command98("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
|
|
9645
9902
|
var status2 = new Command98("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
|
|
9646
9903
|
var clean = new Command98("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--clean"]));
|
|
9647
|
-
var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(
|
|
9904
|
+
var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
|
|
9648
9905
|
|
|
9649
9906
|
// src/commands/oauth.ts
|
|
9650
9907
|
var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
@@ -9666,7 +9923,7 @@ import pc35 from "picocolors";
|
|
|
9666
9923
|
|
|
9667
9924
|
// src/lib/cms-backend.ts
|
|
9668
9925
|
import { createRequire as createRequire3 } from "node:module";
|
|
9669
|
-
import
|
|
9926
|
+
import path45 from "node:path";
|
|
9670
9927
|
import process36 from "node:process";
|
|
9671
9928
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
9672
9929
|
import pc34 from "picocolors";
|
|
@@ -9674,7 +9931,7 @@ var DEFAULT_PROJECT = "default";
|
|
|
9674
9931
|
async function loadBackendModule(root) {
|
|
9675
9932
|
let entry;
|
|
9676
9933
|
try {
|
|
9677
|
-
entry = createRequire3(
|
|
9934
|
+
entry = createRequire3(path45.join(root, "package.json")).resolve("@velastack/cms/backend");
|
|
9678
9935
|
} catch {
|
|
9679
9936
|
throw new Error(
|
|
9680
9937
|
`@velastack/cms is not installed in this project.
|
|
@@ -9692,8 +9949,8 @@ async function withCmsBackend(fn, cwd = process36.cwd()) {
|
|
|
9692
9949
|
const { createCmsBackend } = await loadBackendModule(root);
|
|
9693
9950
|
const dataDir2 = localDataDir(root);
|
|
9694
9951
|
const backend3 = createCmsBackend({
|
|
9695
|
-
dbPath:
|
|
9696
|
-
uploadDir:
|
|
9952
|
+
dbPath: path45.join(dataDir2, "cms.sqlite"),
|
|
9953
|
+
uploadDir: path45.join(dataDir2, "uploads")
|
|
9697
9954
|
});
|
|
9698
9955
|
try {
|
|
9699
9956
|
return await fn(backend3);
|
|
@@ -9805,14 +10062,14 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
|
9805
10062
|
if (isStub(actionCommand)) return;
|
|
9806
10063
|
const envRoot = findWorkspaceRoot() ?? process37.cwd();
|
|
9807
10064
|
dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
|
|
9808
|
-
const
|
|
9809
|
-
if (NO_BACKEND_COMMMANDS.has(
|
|
9810
|
-
const top =
|
|
10065
|
+
const path46 = getCommandPath(actionCommand);
|
|
10066
|
+
if (NO_BACKEND_COMMMANDS.has(path46)) return;
|
|
10067
|
+
const top = path46.split(" ", 1)[0];
|
|
9811
10068
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
9812
10069
|
if (!hasBackend()) {
|
|
9813
10070
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
9814
10071
|
p61.log.error(
|
|
9815
|
-
`${pc38.cyan(`vela ${
|
|
10072
|
+
`${pc38.cyan(`vela ${path46}`)} needs a backend, and this project does not have one.
|
|
9816
10073
|
|
|
9817
10074
|
Static projects have no database to talk to.
|
|
9818
10075
|
|
|
@@ -9822,7 +10079,7 @@ To add a backend to this project, run ${pc38.cyan("vela bless")}.`
|
|
|
9822
10079
|
p61.cancel("Operation failed.");
|
|
9823
10080
|
process37.exit(1);
|
|
9824
10081
|
}
|
|
9825
|
-
if (SELF_CREDENTIALED_COMMANDS.has(
|
|
10082
|
+
if (SELF_CREDENTIALED_COMMANDS.has(path46)) return;
|
|
9826
10083
|
if (!process37.env.POCKETBASE_SUPERUSER_EMAIL || !process37.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
9827
10084
|
p61.log.error(
|
|
9828
10085
|
`PocketBase superuser credentials are required.
|