vela 0.11.0 → 0.11.2
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 +771 -512
- package/dist/bin.js.map +4 -4
- package/package.json +2 -1
- package/templates/minimal/template.json +2 -1
- package/templates/server/provision.sh +43 -5
- 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.2",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -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
|
|
@@ -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.");
|
|
@@ -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
|
}
|
|
@@ -5119,8 +5378,8 @@ var ui = new Command47("ui").description("generate ui components").configureHelp
|
|
|
5119
5378
|
import { Command as Command50 } from "commander";
|
|
5120
5379
|
|
|
5121
5380
|
// src/commands/legal/terms.ts
|
|
5122
|
-
import
|
|
5123
|
-
import
|
|
5381
|
+
import fs25 from "node:fs";
|
|
5382
|
+
import path23 from "node:path";
|
|
5124
5383
|
import { Command as Command48 } from "commander";
|
|
5125
5384
|
import * as p32 from "@clack/prompts";
|
|
5126
5385
|
|
|
@@ -5779,22 +6038,22 @@ async function termsAction() {
|
|
|
5779
6038
|
mobileApp,
|
|
5780
6039
|
contact
|
|
5781
6040
|
});
|
|
5782
|
-
const termsPage =
|
|
6041
|
+
const termsPage = path23.join(
|
|
5783
6042
|
workspaceRootDir,
|
|
5784
6043
|
publicRoutesDir,
|
|
5785
6044
|
LEGAL_DIR,
|
|
5786
6045
|
"terms",
|
|
5787
6046
|
"+page.svelte"
|
|
5788
6047
|
);
|
|
5789
|
-
const termsPageTs =
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
6048
|
+
const termsPageTs = path23.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
|
|
6049
|
+
fs25.mkdirSync(path23.dirname(termsPage), { recursive: true });
|
|
6050
|
+
fs25.writeFileSync(termsPage, html);
|
|
6051
|
+
fs25.writeFileSync(
|
|
5793
6052
|
termsPageTs,
|
|
5794
6053
|
pageMetaTagsLoader("Terms of Service", `Terms of Service for ${core.websiteName}`)
|
|
5795
6054
|
);
|
|
5796
|
-
const relativeTermsPage =
|
|
5797
|
-
const relativeTermsPageTs =
|
|
6055
|
+
const relativeTermsPage = path23.relative(workspaceRootDir, termsPage);
|
|
6056
|
+
const relativeTermsPageTs = path23.relative(workspaceRootDir, termsPageTs);
|
|
5798
6057
|
reportResult({
|
|
5799
6058
|
summary: "Generated placeholder terms and conditions.",
|
|
5800
6059
|
filesCreated: [relativeTermsPage, relativeTermsPageTs],
|
|
@@ -5808,8 +6067,8 @@ async function termsAction() {
|
|
|
5808
6067
|
var terms = new Command48("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
|
|
5809
6068
|
|
|
5810
6069
|
// src/commands/legal/privacy.ts
|
|
5811
|
-
import
|
|
5812
|
-
import
|
|
6070
|
+
import fs26 from "node:fs";
|
|
6071
|
+
import path24 from "node:path";
|
|
5813
6072
|
import { Command as Command49 } from "commander";
|
|
5814
6073
|
import * as p33 from "@clack/prompts";
|
|
5815
6074
|
var mapLabels = {
|
|
@@ -5898,9 +6157,9 @@ var compute2 = (a) => {
|
|
|
5898
6157
|
});
|
|
5899
6158
|
const piSelections = a.personalInfo ?? [];
|
|
5900
6159
|
const piLabels = piSelections.map(
|
|
5901
|
-
(
|
|
6160
|
+
(v10) => mapLabels.personalInfo[v10] ?? v10
|
|
5902
6161
|
);
|
|
5903
|
-
const lookup = (map, vs) => (vs ?? []).map((
|
|
6162
|
+
const lookup = (map, vs) => (vs ?? []).map((v10) => map[v10] ?? v10);
|
|
5904
6163
|
const companyName = a.core?.entityType === "business" ? a.core?.businessName ?? a.core?.websiteName : a.core?.websiteName ?? "Our Company";
|
|
5905
6164
|
const companyAddress = a.core?.entityType === "business" ? a.core?.businessAddress ?? "" : "";
|
|
5906
6165
|
const websiteName = a.core?.websiteName ?? "our website";
|
|
@@ -6522,28 +6781,28 @@ async function privacyAction() {
|
|
|
6522
6781
|
kids,
|
|
6523
6782
|
retention
|
|
6524
6783
|
});
|
|
6525
|
-
const privacyPage =
|
|
6784
|
+
const privacyPage = path24.join(
|
|
6526
6785
|
workspaceRootDir,
|
|
6527
6786
|
publicRoutesDir,
|
|
6528
6787
|
LEGAL_DIR,
|
|
6529
6788
|
"privacy",
|
|
6530
6789
|
"+page.svelte"
|
|
6531
6790
|
);
|
|
6532
|
-
const privacyPageTs =
|
|
6791
|
+
const privacyPageTs = path24.join(
|
|
6533
6792
|
workspaceRootDir,
|
|
6534
6793
|
publicRoutesDir,
|
|
6535
6794
|
LEGAL_DIR,
|
|
6536
6795
|
"privacy",
|
|
6537
6796
|
"+page.ts"
|
|
6538
6797
|
);
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6798
|
+
fs26.mkdirSync(path24.dirname(privacyPage), { recursive: true });
|
|
6799
|
+
fs26.writeFileSync(privacyPage, html);
|
|
6800
|
+
fs26.writeFileSync(
|
|
6542
6801
|
privacyPageTs,
|
|
6543
6802
|
pageMetaTagsLoader("Privacy Policy", `Privacy Policy for ${core.websiteName}`)
|
|
6544
6803
|
);
|
|
6545
|
-
const relativePrivacyPage =
|
|
6546
|
-
const relativePrivacyPageTs =
|
|
6804
|
+
const relativePrivacyPage = path24.relative(workspaceRootDir, privacyPage);
|
|
6805
|
+
const relativePrivacyPageTs = path24.relative(workspaceRootDir, privacyPageTs);
|
|
6547
6806
|
reportResult({
|
|
6548
6807
|
summary: "Generated placeholder privacy policy.",
|
|
6549
6808
|
filesCreated: [relativePrivacyPage, relativePrivacyPageTs],
|
|
@@ -6566,8 +6825,8 @@ import { Command as Command56 } from "commander";
|
|
|
6566
6825
|
import { Command as Command51 } from "commander";
|
|
6567
6826
|
|
|
6568
6827
|
// src/lib/data.ts
|
|
6569
|
-
import
|
|
6570
|
-
import
|
|
6828
|
+
import fs27 from "node:fs";
|
|
6829
|
+
import path25 from "node:path";
|
|
6571
6830
|
import { ClientResponseError } from "pocketbase";
|
|
6572
6831
|
|
|
6573
6832
|
// src/lib/collections.ts
|
|
@@ -6604,14 +6863,14 @@ function dependencyOrder(collections2, startingCollectionId) {
|
|
|
6604
6863
|
|
|
6605
6864
|
// src/lib/data.ts
|
|
6606
6865
|
function dataDir(cwd, kind) {
|
|
6607
|
-
return
|
|
6866
|
+
return path25.join(cwd, DATA_DIR, kind);
|
|
6608
6867
|
}
|
|
6609
6868
|
function getDataFiles(cwd, kind) {
|
|
6610
6869
|
const dir = dataDir(cwd, kind);
|
|
6611
|
-
if (!
|
|
6612
|
-
return
|
|
6870
|
+
if (!fs27.existsSync(dir)) return [];
|
|
6871
|
+
return fs27.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
|
|
6613
6872
|
collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
|
|
6614
|
-
filePath:
|
|
6873
|
+
filePath: path25.join(dir, file)
|
|
6615
6874
|
}));
|
|
6616
6875
|
}
|
|
6617
6876
|
function getSeedFiles(cwd) {
|
|
@@ -6621,7 +6880,7 @@ function getFixtureFiles(cwd) {
|
|
|
6621
6880
|
return getDataFiles(cwd, "fixtures");
|
|
6622
6881
|
}
|
|
6623
6882
|
function readRecords(filePath) {
|
|
6624
|
-
return JSON.parse(
|
|
6883
|
+
return JSON.parse(fs27.readFileSync(filePath, "utf8"));
|
|
6625
6884
|
}
|
|
6626
6885
|
function readSeedIds(cwd) {
|
|
6627
6886
|
const ids = /* @__PURE__ */ new Map();
|
|
@@ -6658,7 +6917,7 @@ function describeError(e) {
|
|
|
6658
6917
|
return e instanceof Error ? e.message : String(e);
|
|
6659
6918
|
}
|
|
6660
6919
|
function label3(cwd, filePath, count) {
|
|
6661
|
-
return `${
|
|
6920
|
+
return `${path25.relative(cwd, filePath)} (${count} records)`;
|
|
6662
6921
|
}
|
|
6663
6922
|
async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
|
|
6664
6923
|
const records = readRecords(filePath);
|
|
@@ -6666,7 +6925,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
|
|
|
6666
6925
|
try {
|
|
6667
6926
|
await pb.collection(collectionName).create(record);
|
|
6668
6927
|
} catch (e) {
|
|
6669
|
-
throw new DataLoadError(kind,
|
|
6928
|
+
throw new DataLoadError(kind, path25.relative(cwd, filePath), index, e);
|
|
6670
6929
|
}
|
|
6671
6930
|
}
|
|
6672
6931
|
return records.length;
|
|
@@ -6840,8 +7099,8 @@ var reset = new Command53("reset").description("clear and reload fixtures").conf
|
|
|
6840
7099
|
);
|
|
6841
7100
|
|
|
6842
7101
|
// src/commands/fixtures/generate.ts
|
|
6843
|
-
import
|
|
6844
|
-
import
|
|
7102
|
+
import fs28 from "node:fs";
|
|
7103
|
+
import path26 from "node:path";
|
|
6845
7104
|
import { Command as Command54, InvalidArgumentError } from "commander";
|
|
6846
7105
|
import * as p34 from "@clack/prompts";
|
|
6847
7106
|
import { annotate } from "annotate-json-schema";
|
|
@@ -6878,9 +7137,9 @@ async function loadCollections(pb) {
|
|
|
6878
7137
|
}
|
|
6879
7138
|
async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
6880
7139
|
const fixturesDir = dataDir(workspaceRootDir, "fixtures");
|
|
6881
|
-
|
|
6882
|
-
for (const file of
|
|
6883
|
-
if (file.endsWith(".json"))
|
|
7140
|
+
fs28.mkdirSync(fixturesDir, { recursive: true });
|
|
7141
|
+
for (const file of fs28.readdirSync(fixturesDir)) {
|
|
7142
|
+
if (file.endsWith(".json")) fs28.unlinkSync(path26.join(fixturesDir, file));
|
|
6884
7143
|
}
|
|
6885
7144
|
if (opts.seed !== void 0) faker.seed(opts.seed);
|
|
6886
7145
|
const generator = createGenerator({
|
|
@@ -6947,8 +7206,8 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
|
6947
7206
|
items.push(record);
|
|
6948
7207
|
}
|
|
6949
7208
|
const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
|
|
6950
|
-
|
|
6951
|
-
writtenFiles.push(`${
|
|
7209
|
+
fs28.writeFileSync(path26.join(fixturesDir, filename), JSON.stringify(items, null, 2));
|
|
7210
|
+
writtenFiles.push(`${path26.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
|
|
6952
7211
|
fileIndex++;
|
|
6953
7212
|
}
|
|
6954
7213
|
return { writtenFiles, warnings };
|
|
@@ -7095,8 +7354,8 @@ var load2 = new Command57("load").description("load seeds into the database").op
|
|
|
7095
7354
|
);
|
|
7096
7355
|
|
|
7097
7356
|
// src/commands/seeds/save.ts
|
|
7098
|
-
import
|
|
7099
|
-
import
|
|
7357
|
+
import fs29 from "node:fs";
|
|
7358
|
+
import path27 from "node:path";
|
|
7100
7359
|
import { Command as Command58 } from "commander";
|
|
7101
7360
|
var padZeros2 = (num, length) => num.toString().padStart(length, "0");
|
|
7102
7361
|
function filterSystemFields(record, systemFieldNames) {
|
|
@@ -7116,10 +7375,10 @@ var save = new Command58("save").description("save the current data as seeds").o
|
|
|
7116
7375
|
if (existing.length > 0 && !opts.force) {
|
|
7117
7376
|
throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
|
|
7118
7377
|
}
|
|
7119
|
-
|
|
7378
|
+
fs29.mkdirSync(seedsPath, { recursive: true });
|
|
7120
7379
|
if (opts.force) {
|
|
7121
|
-
for (const file of
|
|
7122
|
-
if (file.endsWith(".json"))
|
|
7380
|
+
for (const file of fs29.readdirSync(seedsPath)) {
|
|
7381
|
+
if (file.endsWith(".json")) fs29.unlinkSync(path27.join(seedsPath, file));
|
|
7123
7382
|
}
|
|
7124
7383
|
}
|
|
7125
7384
|
const saved = [];
|
|
@@ -7148,13 +7407,13 @@ var save = new Command58("save").description("save the current data as seeds").o
|
|
|
7148
7407
|
const filtered = records.map(
|
|
7149
7408
|
(r) => filterSystemFields(r, systemFieldNames)
|
|
7150
7409
|
);
|
|
7151
|
-
const relativeSeedPath =
|
|
7410
|
+
const relativeSeedPath = path27.join(
|
|
7152
7411
|
DATA_DIR,
|
|
7153
7412
|
"seeds",
|
|
7154
7413
|
`${padZeros2(count, 2)}-${collectionName}.json`
|
|
7155
7414
|
);
|
|
7156
|
-
const seedPath =
|
|
7157
|
-
|
|
7415
|
+
const seedPath = path27.join(workspaceRootDir, relativeSeedPath);
|
|
7416
|
+
fs29.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
|
|
7158
7417
|
saved.push(`${relativeSeedPath} (${filtered.length} records)`);
|
|
7159
7418
|
count++;
|
|
7160
7419
|
}
|
|
@@ -7220,7 +7479,7 @@ import * as p37 from "@clack/prompts";
|
|
|
7220
7479
|
import makeFetchCookie2 from "fetch-cookie";
|
|
7221
7480
|
|
|
7222
7481
|
// src/commands/login.ts
|
|
7223
|
-
import
|
|
7482
|
+
import os4 from "node:os";
|
|
7224
7483
|
import { Command as Command61 } from "commander";
|
|
7225
7484
|
import * as p36 from "@clack/prompts";
|
|
7226
7485
|
import makeFetchCookie from "fetch-cookie";
|
|
@@ -7254,7 +7513,7 @@ var login = new Command61("login").description("login to velastack.dev").configu
|
|
|
7254
7513
|
}, "Failed to login.")
|
|
7255
7514
|
);
|
|
7256
7515
|
async function issueApiKey(fetchCookie) {
|
|
7257
|
-
const label4 = `CLI - ${
|
|
7516
|
+
const label4 = `CLI - ${os4.hostname()}`;
|
|
7258
7517
|
await fetchCookie(`${API_URL}/api-keys/new`, {
|
|
7259
7518
|
method: "POST",
|
|
7260
7519
|
headers: {
|
|
@@ -7365,7 +7624,7 @@ import { Command as Command70 } from "commander";
|
|
|
7365
7624
|
import { Command as Command65 } from "commander";
|
|
7366
7625
|
|
|
7367
7626
|
// src/lib/migrate.ts
|
|
7368
|
-
import
|
|
7627
|
+
import path28 from "node:path";
|
|
7369
7628
|
import process19 from "node:process";
|
|
7370
7629
|
import { x as x2 } from "tinyexec";
|
|
7371
7630
|
async function runPocketbaseMigrate(args) {
|
|
@@ -7376,9 +7635,9 @@ async function runPocketbaseMigrate(args) {
|
|
|
7376
7635
|
binaryPath,
|
|
7377
7636
|
[
|
|
7378
7637
|
"--dir",
|
|
7379
|
-
|
|
7638
|
+
path28.join(cwd, DATA_DIR),
|
|
7380
7639
|
"--migrationsDir",
|
|
7381
|
-
|
|
7640
|
+
path28.join(cwd, MIGRATIONS_DIR),
|
|
7382
7641
|
"migrate",
|
|
7383
7642
|
...args
|
|
7384
7643
|
],
|
|
@@ -7426,8 +7685,8 @@ var down = new Command66("down").alias("rollback").description("revert the last
|
|
|
7426
7685
|
);
|
|
7427
7686
|
|
|
7428
7687
|
// src/commands/migrate/create.ts
|
|
7429
|
-
import
|
|
7430
|
-
import
|
|
7688
|
+
import fs30 from "node:fs";
|
|
7689
|
+
import path29 from "node:path";
|
|
7431
7690
|
import process20 from "node:process";
|
|
7432
7691
|
import { Command as Command67 } from "commander";
|
|
7433
7692
|
var create2 = new Command67("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
|
|
@@ -7439,7 +7698,7 @@ var create2 = new Command67("create").alias("new").description("create a new bla
|
|
|
7439
7698
|
const added = [...after].filter((f) => !before.has(f));
|
|
7440
7699
|
reportResult({
|
|
7441
7700
|
summary: `Created blank migration ${name}.`,
|
|
7442
|
-
filesCreated: added.map((f) =>
|
|
7701
|
+
filesCreated: added.map((f) => path29.join(MIGRATIONS_DIR, f)),
|
|
7443
7702
|
nextSteps: [
|
|
7444
7703
|
`Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
|
|
7445
7704
|
"Run `vela migrate up` to apply the migration once the handlers are written."
|
|
@@ -7448,14 +7707,14 @@ var create2 = new Command67("create").alias("new").description("create a new bla
|
|
|
7448
7707
|
}, "Failed to create migration.")
|
|
7449
7708
|
);
|
|
7450
7709
|
function listMigrationFiles(cwd) {
|
|
7451
|
-
const dir =
|
|
7452
|
-
if (!
|
|
7453
|
-
return new Set(
|
|
7710
|
+
const dir = path29.join(cwd, MIGRATIONS_DIR);
|
|
7711
|
+
if (!fs30.existsSync(dir)) return /* @__PURE__ */ new Set();
|
|
7712
|
+
return new Set(fs30.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
|
|
7454
7713
|
}
|
|
7455
7714
|
|
|
7456
7715
|
// src/commands/migrate/collections.ts
|
|
7457
|
-
import
|
|
7458
|
-
import
|
|
7716
|
+
import fs31 from "node:fs";
|
|
7717
|
+
import path30 from "node:path";
|
|
7459
7718
|
import process21 from "node:process";
|
|
7460
7719
|
import { Command as Command68 } from "commander";
|
|
7461
7720
|
var collections = new Command68("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
|
|
@@ -7473,7 +7732,7 @@ var collections = new Command68("collections").alias("snapshot").description("sn
|
|
|
7473
7732
|
}
|
|
7474
7733
|
reportResult({
|
|
7475
7734
|
summary: "Snapshotted local collections into a new migration.",
|
|
7476
|
-
filesCreated: added.map((f) =>
|
|
7735
|
+
filesCreated: added.map((f) => path30.join(MIGRATIONS_DIR, f)),
|
|
7477
7736
|
nextSteps: [
|
|
7478
7737
|
`Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
|
|
7479
7738
|
"Commit the snapshot so teammates pick up the new schema.",
|
|
@@ -7483,9 +7742,9 @@ var collections = new Command68("collections").alias("snapshot").description("sn
|
|
|
7483
7742
|
}, "Failed to snapshot collections.")
|
|
7484
7743
|
);
|
|
7485
7744
|
function listMigrationFiles2(cwd) {
|
|
7486
|
-
const dir =
|
|
7487
|
-
if (!
|
|
7488
|
-
return new Set(
|
|
7745
|
+
const dir = path30.join(cwd, MIGRATIONS_DIR);
|
|
7746
|
+
if (!fs31.existsSync(dir)) return /* @__PURE__ */ new Set();
|
|
7747
|
+
return new Set(fs31.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
|
|
7489
7748
|
}
|
|
7490
7749
|
|
|
7491
7750
|
// src/commands/migrate/history-sync.ts
|
|
@@ -7504,8 +7763,8 @@ var historySync = new Command69("history-sync").description("drop _migrations ro
|
|
|
7504
7763
|
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
7764
|
|
|
7506
7765
|
// src/commands/dev.ts
|
|
7507
|
-
import
|
|
7508
|
-
import
|
|
7766
|
+
import fs32 from "node:fs";
|
|
7767
|
+
import path32 from "node:path";
|
|
7509
7768
|
import process23 from "node:process";
|
|
7510
7769
|
import { performance } from "node:perf_hooks";
|
|
7511
7770
|
import { Command as Command71, InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
@@ -7513,7 +7772,7 @@ import pc15 from "picocolors";
|
|
|
7513
7772
|
import PocketBase4 from "pocketbase";
|
|
7514
7773
|
|
|
7515
7774
|
// src/lib/vite.ts
|
|
7516
|
-
import
|
|
7775
|
+
import path31 from "node:path";
|
|
7517
7776
|
import process22 from "node:process";
|
|
7518
7777
|
import { createRequire as createRequire2 } from "node:module";
|
|
7519
7778
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -7533,7 +7792,7 @@ function viteVersionError(version) {
|
|
|
7533
7792
|
}
|
|
7534
7793
|
function resolveProjectVite(cwd) {
|
|
7535
7794
|
try {
|
|
7536
|
-
return createRequire2(
|
|
7795
|
+
return createRequire2(path31.join(cwd, "package.json")).resolve("vite");
|
|
7537
7796
|
} catch {
|
|
7538
7797
|
return null;
|
|
7539
7798
|
}
|
|
@@ -7562,21 +7821,21 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
7562
7821
|
process23.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
7563
7822
|
const startTime = performance.now();
|
|
7564
7823
|
const { createServer, version } = await loadVite(cwd);
|
|
7565
|
-
const viteMetadataDir =
|
|
7566
|
-
const viteMetadataFile =
|
|
7824
|
+
const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
|
|
7825
|
+
const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
|
|
7567
7826
|
let pbProc;
|
|
7568
7827
|
const backend3 = hasBackend(cwd);
|
|
7569
7828
|
const needsStart = backend3 && !process23.env.POCKETBASE_URL;
|
|
7570
7829
|
const cleanup = () => {
|
|
7571
7830
|
if (pbProc?.pid) pbProc.kill();
|
|
7572
|
-
if (
|
|
7831
|
+
if (fs32.existsSync(viteMetadataFile)) fs32.rmSync(viteMetadataFile);
|
|
7573
7832
|
};
|
|
7574
7833
|
if (needsStart) {
|
|
7575
|
-
const dataDir2 =
|
|
7834
|
+
const dataDir2 = path32.join(cwd, DATA_DIR);
|
|
7576
7835
|
const started = await startPocketbaseServe({
|
|
7577
7836
|
dataDir: dataDir2,
|
|
7578
7837
|
migrationsDir: MIGRATIONS_DIR,
|
|
7579
|
-
hooksDir:
|
|
7838
|
+
hooksDir: path32.join(dataDir2, "hooks"),
|
|
7580
7839
|
dev: true,
|
|
7581
7840
|
stdio: "pipe"
|
|
7582
7841
|
});
|
|
@@ -7607,8 +7866,8 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
7607
7866
|
if (!backend3) return;
|
|
7608
7867
|
const { address, port: vitePort } = server.httpServer.address();
|
|
7609
7868
|
const viteHost = address === "::1" ? "localhost" : address;
|
|
7610
|
-
await
|
|
7611
|
-
await
|
|
7869
|
+
await fs32.promises.mkdir(viteMetadataDir, { recursive: true });
|
|
7870
|
+
await fs32.promises.writeFile(
|
|
7612
7871
|
viteMetadataFile,
|
|
7613
7872
|
JSON.stringify({
|
|
7614
7873
|
pocketbaseUrl: process23.env.POCKETBASE_URL,
|
|
@@ -7640,18 +7899,18 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
7640
7899
|
});
|
|
7641
7900
|
async function startWatchingTypes(cwd, pb) {
|
|
7642
7901
|
const { processTypes } = await import("@velastack/pocketbase-codegen");
|
|
7643
|
-
const typesDir =
|
|
7644
|
-
const pocketbaseDir =
|
|
7645
|
-
const pocketbaseTypes =
|
|
7902
|
+
const typesDir = path32.resolve(cwd, ".svelte-kit", "types");
|
|
7903
|
+
const pocketbaseDir = path32.join(typesDir, "pocketbase");
|
|
7904
|
+
const pocketbaseTypes = path32.join(pocketbaseDir, "$types.d.ts");
|
|
7646
7905
|
const regenerate = () => processTypes(pb, typesDir).catch(() => {
|
|
7647
7906
|
});
|
|
7648
7907
|
await regenerate();
|
|
7649
7908
|
void (async () => {
|
|
7650
7909
|
for (; ; ) {
|
|
7651
7910
|
try {
|
|
7652
|
-
await
|
|
7653
|
-
for await (const event of
|
|
7654
|
-
if (event.eventType === "rename" && event.filename === "$types.d.ts" && !
|
|
7911
|
+
await fs32.promises.mkdir(pocketbaseDir, { recursive: true });
|
|
7912
|
+
for await (const event of fs32.promises.watch(pocketbaseDir)) {
|
|
7913
|
+
if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs32.existsSync(pocketbaseTypes)) {
|
|
7655
7914
|
setTimeout(regenerate, 100);
|
|
7656
7915
|
}
|
|
7657
7916
|
}
|
|
@@ -7663,8 +7922,8 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
7663
7922
|
}
|
|
7664
7923
|
|
|
7665
7924
|
// src/commands/build.ts
|
|
7666
|
-
import
|
|
7667
|
-
import
|
|
7925
|
+
import fs33 from "node:fs";
|
|
7926
|
+
import path33 from "node:path";
|
|
7668
7927
|
import process25 from "node:process";
|
|
7669
7928
|
import { Command as Command72 } from "commander";
|
|
7670
7929
|
import * as p40 from "@clack/prompts";
|
|
@@ -7702,7 +7961,7 @@ function splitHosts(value) {
|
|
|
7702
7961
|
}
|
|
7703
7962
|
|
|
7704
7963
|
// src/commands/build.ts
|
|
7705
|
-
var PRERENDERED_DIR =
|
|
7964
|
+
var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
|
|
7706
7965
|
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
7966
|
const cwd = process25.cwd();
|
|
7708
7967
|
applyBuildEnv(cwd);
|
|
@@ -7715,11 +7974,11 @@ var build = new Command72("build").description("build the app").configureHelp(he
|
|
|
7715
7974
|
};
|
|
7716
7975
|
if (needsStart) {
|
|
7717
7976
|
await ensureSuperuser(cwd);
|
|
7718
|
-
const dataDir2 =
|
|
7977
|
+
const dataDir2 = path33.join(cwd, DATA_DIR);
|
|
7719
7978
|
const started = await startPocketbaseServe({
|
|
7720
7979
|
dataDir: dataDir2,
|
|
7721
7980
|
migrationsDir: MIGRATIONS_DIR,
|
|
7722
|
-
hooksDir:
|
|
7981
|
+
hooksDir: path33.join(dataDir2, "hooks"),
|
|
7723
7982
|
dev: true
|
|
7724
7983
|
});
|
|
7725
7984
|
pbProc = started.proc;
|
|
@@ -7758,8 +8017,8 @@ async function originForBuild(cwd, target) {
|
|
|
7758
8017
|
}
|
|
7759
8018
|
}
|
|
7760
8019
|
function warnIfPrerendered(cwd) {
|
|
7761
|
-
const dir =
|
|
7762
|
-
if (!
|
|
8020
|
+
const dir = path33.join(cwd, PRERENDERED_DIR);
|
|
8021
|
+
if (!fs33.existsSync(dir) || fs33.readdirSync(dir).length === 0) return;
|
|
7763
8022
|
p40.log.warn(
|
|
7764
8023
|
`Prerendered pages were built with no domain configured, so their canonical
|
|
7765
8024
|
links point at SvelteKit's placeholder host rather than at this site.
|
|
@@ -7769,7 +8028,7 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
|
|
|
7769
8028
|
}
|
|
7770
8029
|
|
|
7771
8030
|
// src/commands/preview.ts
|
|
7772
|
-
import
|
|
8031
|
+
import path34 from "node:path";
|
|
7773
8032
|
import process26 from "node:process";
|
|
7774
8033
|
import { Command as Command73 } from "commander";
|
|
7775
8034
|
import { x as x4 } from "tinyexec";
|
|
@@ -7784,11 +8043,11 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
7784
8043
|
if (pbProc?.pid) pbProc.kill();
|
|
7785
8044
|
};
|
|
7786
8045
|
if (needsStart) {
|
|
7787
|
-
const dataDir2 =
|
|
8046
|
+
const dataDir2 = path34.join(cwd, DATA_DIR);
|
|
7788
8047
|
const started = await startPocketbaseServe({
|
|
7789
8048
|
dataDir: dataDir2,
|
|
7790
8049
|
migrationsDir: MIGRATIONS_DIR,
|
|
7791
|
-
hooksDir:
|
|
8050
|
+
hooksDir: path34.join(dataDir2, "hooks"),
|
|
7792
8051
|
dev: true
|
|
7793
8052
|
});
|
|
7794
8053
|
pbProc = started.proc;
|
|
@@ -7814,12 +8073,12 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
7814
8073
|
});
|
|
7815
8074
|
|
|
7816
8075
|
// src/commands/sync.ts
|
|
7817
|
-
import
|
|
8076
|
+
import path35 from "node:path";
|
|
7818
8077
|
import { Command as Command74 } from "commander";
|
|
7819
8078
|
var sync = new Command74("sync").description("sync types from the database").configureHelp(helpConfig).action(
|
|
7820
8079
|
() => runCommand(async () => {
|
|
7821
8080
|
const { workspaceRootDir } = await getWorkspace();
|
|
7822
|
-
const typesDir =
|
|
8081
|
+
const typesDir = path35.join(workspaceRootDir, ".svelte-kit", "types");
|
|
7823
8082
|
const { processTypes } = await import("@velastack/pocketbase-codegen");
|
|
7824
8083
|
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
7825
8084
|
await processTypes(pb, typesDir);
|
|
@@ -7832,11 +8091,11 @@ var sync = new Command74("sync").description("sync types from the database").con
|
|
|
7832
8091
|
import { Command as Command75 } from "commander";
|
|
7833
8092
|
import * as p41 from "@clack/prompts";
|
|
7834
8093
|
import pc17 from "picocolors";
|
|
7835
|
-
import * as
|
|
7836
|
-
var OptionsSchema2 =
|
|
8094
|
+
import * as v7 from "valibot";
|
|
8095
|
+
var OptionsSchema2 = v7.object({
|
|
7837
8096
|
...SSH_OPTION_SCHEMA,
|
|
7838
|
-
pbVersion:
|
|
7839
|
-
nodeMajor:
|
|
8097
|
+
pbVersion: v7.optional(v7.string()),
|
|
8098
|
+
nodeMajor: v7.optional(v7.string())
|
|
7840
8099
|
});
|
|
7841
8100
|
var provision = addSshOptions(
|
|
7842
8101
|
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 +8140,22 @@ var provision = addSshOptions(
|
|
|
7881
8140
|
);
|
|
7882
8141
|
|
|
7883
8142
|
// src/commands/deploy.ts
|
|
7884
|
-
import
|
|
7885
|
-
import
|
|
8143
|
+
import path37 from "node:path";
|
|
8144
|
+
import fs35 from "node:fs";
|
|
7886
8145
|
import { Command as Command76, Option as Option2 } from "commander";
|
|
7887
8146
|
import * as p42 from "@clack/prompts";
|
|
7888
8147
|
import pc18 from "picocolors";
|
|
7889
|
-
import * as
|
|
8148
|
+
import * as v8 from "valibot";
|
|
7890
8149
|
|
|
7891
8150
|
// src/lib/pocketbase-settings.ts
|
|
7892
|
-
import
|
|
7893
|
-
import
|
|
8151
|
+
import fs34 from "node:fs";
|
|
8152
|
+
import path36 from "node:path";
|
|
7894
8153
|
import process27 from "node:process";
|
|
7895
8154
|
import PocketBase5 from "pocketbase";
|
|
7896
8155
|
var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
|
|
7897
8156
|
async function readLocalMeta(cwd) {
|
|
7898
|
-
const dataDir2 =
|
|
7899
|
-
if (!
|
|
8157
|
+
const dataDir2 = path36.join(cwd, DATA_DIR);
|
|
8158
|
+
if (!fs34.existsSync(dataDir2)) return null;
|
|
7900
8159
|
const email3 = process27.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
7901
8160
|
const password11 = process27.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
7902
8161
|
if (!email3 || !password11) return null;
|
|
@@ -7905,7 +8164,7 @@ async function readLocalMeta(cwd) {
|
|
|
7905
8164
|
const started = await startPocketbaseServe({
|
|
7906
8165
|
dataDir: dataDir2,
|
|
7907
8166
|
migrationsDir: MIGRATIONS_DIR,
|
|
7908
|
-
hooksDir:
|
|
8167
|
+
hooksDir: path36.join(dataDir2, "hooks")
|
|
7909
8168
|
});
|
|
7910
8169
|
proc = started.proc;
|
|
7911
8170
|
const pb = new PocketBase5(started.url);
|
|
@@ -7947,16 +8206,16 @@ async function seedRemoteMeta(session, instance, local, appURL) {
|
|
|
7947
8206
|
}
|
|
7948
8207
|
|
|
7949
8208
|
// src/commands/deploy.ts
|
|
7950
|
-
var OptionsSchema3 =
|
|
8209
|
+
var OptionsSchema3 = v8.object({
|
|
7951
8210
|
...SSH_OPTION_SCHEMA,
|
|
7952
|
-
env:
|
|
7953
|
-
project:
|
|
7954
|
-
remoteDb:
|
|
7955
|
-
domain:
|
|
7956
|
-
healthPath:
|
|
7957
|
-
keep:
|
|
7958
|
-
pbVersion:
|
|
7959
|
-
build:
|
|
8211
|
+
env: v8.optional(v8.string()),
|
|
8212
|
+
project: v8.optional(v8.string()),
|
|
8213
|
+
remoteDb: v8.optional(v8.boolean()),
|
|
8214
|
+
domain: v8.optional(v8.string()),
|
|
8215
|
+
healthPath: v8.optional(v8.string()),
|
|
8216
|
+
keep: v8.optional(v8.string()),
|
|
8217
|
+
pbVersion: v8.optional(v8.string()),
|
|
8218
|
+
build: v8.optional(v8.boolean())
|
|
7960
8219
|
});
|
|
7961
8220
|
var deploy = addTargetOptions(
|
|
7962
8221
|
new Command76("deploy").description("deploy the app").configureHelp(helpConfig),
|
|
@@ -8255,7 +8514,7 @@ async function uploadRelease(session, instance, release, entries) {
|
|
|
8255
8514
|
}
|
|
8256
8515
|
function isDirectory(target) {
|
|
8257
8516
|
try {
|
|
8258
|
-
return
|
|
8517
|
+
return fs35.statSync(target).isDirectory();
|
|
8259
8518
|
} catch {
|
|
8260
8519
|
return false;
|
|
8261
8520
|
}
|
|
@@ -8263,7 +8522,7 @@ function isDirectory(target) {
|
|
|
8263
8522
|
async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
8264
8523
|
const remote = await readRemoteEnv(session, instance);
|
|
8265
8524
|
if (Object.keys(remote).length > 0) return;
|
|
8266
|
-
if (!
|
|
8525
|
+
if (!fs35.existsSync(path37.join(workspaceRootDir, ".env"))) return;
|
|
8267
8526
|
p42.log.warn(
|
|
8268
8527
|
`This app has no production environment variables yet.
|
|
8269
8528
|
|
|
@@ -8273,7 +8532,7 @@ ${pc18.cyan("vela env set KEY")}, or copy a file across with ${pc18.cyan("vela e
|
|
|
8273
8532
|
}
|
|
8274
8533
|
|
|
8275
8534
|
// src/commands/link.ts
|
|
8276
|
-
import
|
|
8535
|
+
import path38 from "node:path";
|
|
8277
8536
|
import process28 from "node:process";
|
|
8278
8537
|
import { Command as Command77 } from "commander";
|
|
8279
8538
|
import * as p43 from "@clack/prompts";
|
|
@@ -8351,7 +8610,7 @@ async function promptProjectName(workspaceRootDir) {
|
|
|
8351
8610
|
defaultValue,
|
|
8352
8611
|
initialValue: defaultValue,
|
|
8353
8612
|
placeholder: defaultValue,
|
|
8354
|
-
validate: (
|
|
8613
|
+
validate: (v10) => !v10?.trim() ? "Required" : void 0
|
|
8355
8614
|
});
|
|
8356
8615
|
if (p43.isCancel(value)) {
|
|
8357
8616
|
p43.cancel("Operation cancelled.");
|
|
@@ -8361,12 +8620,12 @@ async function promptProjectName(workspaceRootDir) {
|
|
|
8361
8620
|
}
|
|
8362
8621
|
function defaultProjectName2(workspaceRootDir) {
|
|
8363
8622
|
try {
|
|
8364
|
-
const pkg = readPackageJson(
|
|
8623
|
+
const pkg = readPackageJson(path38.join(workspaceRootDir, "package.json"));
|
|
8365
8624
|
const name = pkg.name;
|
|
8366
8625
|
if (typeof name === "string" && name.trim()) return name.trim();
|
|
8367
8626
|
} catch {
|
|
8368
8627
|
}
|
|
8369
|
-
return
|
|
8628
|
+
return path38.basename(workspaceRootDir);
|
|
8370
8629
|
}
|
|
8371
8630
|
|
|
8372
8631
|
// src/commands/env.ts
|
|
@@ -8497,8 +8756,8 @@ var envUnset = addTargetOptions(
|
|
|
8497
8756
|
);
|
|
8498
8757
|
|
|
8499
8758
|
// src/commands/env/import.ts
|
|
8500
|
-
import
|
|
8501
|
-
import
|
|
8759
|
+
import fs36 from "node:fs";
|
|
8760
|
+
import path39 from "node:path";
|
|
8502
8761
|
import process30 from "node:process";
|
|
8503
8762
|
import { Command as Command81 } from "commander";
|
|
8504
8763
|
import * as p47 from "@clack/prompts";
|
|
@@ -8544,10 +8803,10 @@ var envImport = addTargetOptions(
|
|
|
8544
8803
|
)
|
|
8545
8804
|
);
|
|
8546
8805
|
function resolve(file) {
|
|
8547
|
-
return
|
|
8806
|
+
return path39.resolve(process30.cwd(), file);
|
|
8548
8807
|
}
|
|
8549
8808
|
function read(resolved, shown) {
|
|
8550
|
-
if (!
|
|
8809
|
+
if (!fs36.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
8551
8810
|
const incoming = readLocalEnvFile(resolved);
|
|
8552
8811
|
if (Object.keys(incoming).length === 0) p47.log.info(`${shown} has no variables to import.`);
|
|
8553
8812
|
return incoming;
|
|
@@ -8819,8 +9078,8 @@ var admin = new Command87("admin").description("manage admin panel logins").conf
|
|
|
8819
9078
|
import { Command as Command93 } from "commander";
|
|
8820
9079
|
|
|
8821
9080
|
// src/commands/backup/create.ts
|
|
8822
|
-
import
|
|
8823
|
-
import
|
|
9081
|
+
import fs37 from "node:fs";
|
|
9082
|
+
import path40 from "node:path";
|
|
8824
9083
|
import { Command as Command88 } from "commander";
|
|
8825
9084
|
import * as p51 from "@clack/prompts";
|
|
8826
9085
|
import pc26 from "picocolors";
|
|
@@ -8974,12 +9233,12 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
8974
9233
|
}, "Failed to create the backup.")
|
|
8975
9234
|
);
|
|
8976
9235
|
async function download(ctx, key, outputDir) {
|
|
8977
|
-
const dir =
|
|
8978
|
-
|
|
8979
|
-
const destination =
|
|
9236
|
+
const dir = path40.resolve(ctx.workspaceRootDir, outputDir);
|
|
9237
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
9238
|
+
const destination = path40.join(dir, key);
|
|
8980
9239
|
if (!ctx.session) {
|
|
8981
|
-
|
|
8982
|
-
return
|
|
9240
|
+
fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9241
|
+
return path40.relative(ctx.workspaceRootDir, destination);
|
|
8983
9242
|
}
|
|
8984
9243
|
const spinner7 = p51.spinner();
|
|
8985
9244
|
spinner7.start(`Downloading ${key}`);
|
|
@@ -8990,7 +9249,7 @@ async function download(ctx, key, outputDir) {
|
|
|
8990
9249
|
throw error;
|
|
8991
9250
|
}
|
|
8992
9251
|
spinner7.stop(`Downloaded ${key}`);
|
|
8993
|
-
return
|
|
9252
|
+
return path40.relative(ctx.workspaceRootDir, destination);
|
|
8994
9253
|
}
|
|
8995
9254
|
|
|
8996
9255
|
// src/commands/backup/list.ts
|
|
@@ -9024,8 +9283,8 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9024
9283
|
);
|
|
9025
9284
|
|
|
9026
9285
|
// src/commands/backup/download.ts
|
|
9027
|
-
import
|
|
9028
|
-
import
|
|
9286
|
+
import fs38 from "node:fs";
|
|
9287
|
+
import path41 from "node:path";
|
|
9029
9288
|
import { Command as Command90 } from "commander";
|
|
9030
9289
|
import * as p53 from "@clack/prompts";
|
|
9031
9290
|
import pc28 from "picocolors";
|
|
@@ -9052,11 +9311,11 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
|
|
|
9052
9311
|
Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
9053
9312
|
);
|
|
9054
9313
|
}
|
|
9055
|
-
const dir =
|
|
9056
|
-
|
|
9057
|
-
const destination =
|
|
9314
|
+
const dir = path41.resolve(ctx.workspaceRootDir, options.output);
|
|
9315
|
+
fs38.mkdirSync(dir, { recursive: true });
|
|
9316
|
+
const destination = path41.join(dir, key);
|
|
9058
9317
|
if (!ctx.session) {
|
|
9059
|
-
|
|
9318
|
+
fs38.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9060
9319
|
} else {
|
|
9061
9320
|
const spinner7 = p53.spinner();
|
|
9062
9321
|
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
@@ -9070,7 +9329,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9070
9329
|
}
|
|
9071
9330
|
reportResult({
|
|
9072
9331
|
summary: `Saved ${key} from ${ctx.targetName}.`,
|
|
9073
|
-
filesCreated: [
|
|
9332
|
+
filesCreated: [path41.relative(ctx.workspaceRootDir, destination)]
|
|
9074
9333
|
});
|
|
9075
9334
|
});
|
|
9076
9335
|
}, "Failed to download the backup.")
|
|
@@ -9165,8 +9424,8 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
|
9165
9424
|
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
9425
|
|
|
9167
9426
|
// src/commands/restore.ts
|
|
9168
|
-
import
|
|
9169
|
-
import
|
|
9427
|
+
import fs39 from "node:fs";
|
|
9428
|
+
import path42 from "node:path";
|
|
9170
9429
|
import process33 from "node:process";
|
|
9171
9430
|
import { Command as Command94 } from "commander";
|
|
9172
9431
|
import * as p56 from "@clack/prompts";
|
|
@@ -9187,7 +9446,7 @@ var restore = addTargetOptions(
|
|
|
9187
9446
|
`${ctx.targetName} was deployed without a database, so there is nothing to restore.`
|
|
9188
9447
|
);
|
|
9189
9448
|
}
|
|
9190
|
-
const local = source &&
|
|
9449
|
+
const local = source && fs39.existsSync(source) ? source : void 0;
|
|
9191
9450
|
const key = local ? void 0 : await resolveKey(ctx, source);
|
|
9192
9451
|
if (!options.yes) {
|
|
9193
9452
|
await confirm12(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
|
|
@@ -9209,7 +9468,7 @@ var restore = addTargetOptions(
|
|
|
9209
9468
|
});
|
|
9210
9469
|
p56.log.success(
|
|
9211
9470
|
`Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
|
|
9212
|
-
local ?
|
|
9471
|
+
local ? path42.basename(local) : key
|
|
9213
9472
|
)}.`
|
|
9214
9473
|
);
|
|
9215
9474
|
if (result?.storageCarriedOver) {
|
|
@@ -9275,21 +9534,21 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
|
|
|
9275
9534
|
}
|
|
9276
9535
|
async function stage(ctx, file) {
|
|
9277
9536
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
9278
|
-
const remote = `${dir}/${
|
|
9537
|
+
const remote = `${dir}/${path42.basename(file)}`;
|
|
9279
9538
|
const spinner7 = p56.spinner();
|
|
9280
|
-
spinner7.start(`Uploading ${
|
|
9539
|
+
spinner7.start(`Uploading ${path42.basename(file)}`);
|
|
9281
9540
|
try {
|
|
9282
9541
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
9283
9542
|
await ctx.session.upload([file], dir);
|
|
9284
9543
|
} catch (error) {
|
|
9285
|
-
spinner7.stop(`Could not upload ${
|
|
9544
|
+
spinner7.stop(`Could not upload ${path42.basename(file)}.`);
|
|
9286
9545
|
throw error;
|
|
9287
9546
|
}
|
|
9288
|
-
spinner7.stop(`Uploaded ${
|
|
9547
|
+
spinner7.stop(`Uploaded ${path42.basename(file)}`);
|
|
9289
9548
|
return remote;
|
|
9290
9549
|
}
|
|
9291
9550
|
async function confirm12(appName, targetName, envTag, from) {
|
|
9292
|
-
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(
|
|
9551
|
+
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path42.basename(from))}`;
|
|
9293
9552
|
if (isProd(envTag)) {
|
|
9294
9553
|
const answer = await p56.text({
|
|
9295
9554
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
@@ -9315,11 +9574,11 @@ async function confirm12(appName, targetName, envTag, from) {
|
|
|
9315
9574
|
import { Command as Command95 } from "commander";
|
|
9316
9575
|
import * as p57 from "@clack/prompts";
|
|
9317
9576
|
import pc32 from "picocolors";
|
|
9318
|
-
import * as
|
|
9319
|
-
var OptionsSchema4 =
|
|
9577
|
+
import * as v9 from "valibot";
|
|
9578
|
+
var OptionsSchema4 = v9.object({
|
|
9320
9579
|
...SSH_OPTION_SCHEMA,
|
|
9321
|
-
json:
|
|
9322
|
-
offline:
|
|
9580
|
+
json: v9.optional(v9.boolean()),
|
|
9581
|
+
offline: v9.optional(v9.boolean())
|
|
9323
9582
|
});
|
|
9324
9583
|
var targets = addSshOptions(
|
|
9325
9584
|
new Command95("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
|
|
@@ -9400,7 +9659,7 @@ Release and domain are shown from what this project recorded.`
|
|
|
9400
9659
|
}
|
|
9401
9660
|
|
|
9402
9661
|
// src/commands/test.ts
|
|
9403
|
-
import
|
|
9662
|
+
import path43 from "node:path";
|
|
9404
9663
|
import process34 from "node:process";
|
|
9405
9664
|
import { Command as Command96 } from "commander";
|
|
9406
9665
|
import PocketBase6 from "pocketbase";
|
|
@@ -9408,20 +9667,20 @@ import pc33 from "picocolors";
|
|
|
9408
9667
|
import { x as x5 } from "tinyexec";
|
|
9409
9668
|
import { detect as detect7 } from "package-manager-detector";
|
|
9410
9669
|
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
9411
|
-
import
|
|
9670
|
+
import fs40 from "node:fs";
|
|
9412
9671
|
var testServer = new Command96("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
9413
9672
|
const cwd = process34.cwd();
|
|
9414
9673
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
9415
9674
|
const password11 = "password";
|
|
9416
|
-
const testDataDir =
|
|
9417
|
-
|
|
9675
|
+
const testDataDir = path43.join(cwd, "test-data");
|
|
9676
|
+
fs40.rmSync(testDataDir, { recursive: true, force: true });
|
|
9418
9677
|
const { stop, url } = await launchPocketbase(cwd, {
|
|
9419
9678
|
dir: testDataDir,
|
|
9420
|
-
migrationsDir:
|
|
9679
|
+
migrationsDir: path43.join(cwd, MIGRATIONS_DIR),
|
|
9421
9680
|
// The app's PocketBase hooks (slug generation, personal teams, …) are part
|
|
9422
9681
|
// of its behaviour; the suite runs against the same server dev and build
|
|
9423
9682
|
// start, so it loads them from the same place.
|
|
9424
|
-
hooksDir:
|
|
9683
|
+
hooksDir: path43.join(cwd, DATA_DIR, "hooks"),
|
|
9425
9684
|
email: email3,
|
|
9426
9685
|
password: password11
|
|
9427
9686
|
});
|
|
@@ -9437,7 +9696,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9437
9696
|
if (cleanedUp) return;
|
|
9438
9697
|
cleanedUp = true;
|
|
9439
9698
|
stop();
|
|
9440
|
-
|
|
9699
|
+
fs40.rmSync(testDataDir, { recursive: true, force: true });
|
|
9441
9700
|
};
|
|
9442
9701
|
const cleanup = async () => {
|
|
9443
9702
|
if (cleanedUp) return;
|
|
@@ -9536,8 +9795,8 @@ function stubPagesPlugin() {
|
|
|
9536
9795
|
}
|
|
9537
9796
|
|
|
9538
9797
|
// src/commands/routes.ts
|
|
9539
|
-
import
|
|
9540
|
-
import
|
|
9798
|
+
import fs41 from "node:fs";
|
|
9799
|
+
import path44 from "node:path";
|
|
9541
9800
|
import { Command as Command97 } from "commander";
|
|
9542
9801
|
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
9543
9802
|
"GET",
|
|
@@ -9551,30 +9810,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
9551
9810
|
]);
|
|
9552
9811
|
var routes = new Command97("routes").description("list routes").configureHelp(helpConfig).action(async () => {
|
|
9553
9812
|
const { workspaceRootDir, routesDir } = await getWorkspace();
|
|
9554
|
-
const routesRoot =
|
|
9813
|
+
const routesRoot = path44.join(workspaceRootDir, routesDir);
|
|
9555
9814
|
const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
|
|
9556
9815
|
found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
|
|
9557
9816
|
printTable(found);
|
|
9558
9817
|
});
|
|
9559
9818
|
function walk(root, dir) {
|
|
9560
|
-
const entries =
|
|
9819
|
+
const entries = fs41.readdirSync(dir, { withFileTypes: true });
|
|
9561
9820
|
const routes2 = [];
|
|
9562
9821
|
const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
|
|
9563
9822
|
if (hasLeaf) {
|
|
9564
|
-
const id = "/" +
|
|
9823
|
+
const id = "/" + path44.relative(root, dir).split(path44.sep).filter(Boolean).join("/");
|
|
9565
9824
|
const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
|
|
9566
9825
|
const methods = /* @__PURE__ */ new Set();
|
|
9567
9826
|
for (const entry of entries) {
|
|
9568
9827
|
if (!entry.isFile()) continue;
|
|
9569
9828
|
if (entry.name.endsWith("+page.svelte")) methods.add("GET");
|
|
9570
9829
|
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(
|
|
9830
|
+
extractMethods(path44.join(dir, entry.name)).forEach((m) => methods.add(m));
|
|
9572
9831
|
}
|
|
9573
9832
|
}
|
|
9574
9833
|
routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
|
|
9575
9834
|
}
|
|
9576
9835
|
for (const entry of entries) {
|
|
9577
|
-
if (entry.isDirectory()) routes2.push(...walk(root,
|
|
9836
|
+
if (entry.isDirectory()) routes2.push(...walk(root, path44.join(dir, entry.name)));
|
|
9578
9837
|
}
|
|
9579
9838
|
return routes2;
|
|
9580
9839
|
}
|
|
@@ -9583,7 +9842,7 @@ function isRouteFile(name) {
|
|
|
9583
9842
|
}
|
|
9584
9843
|
function extractMethods(file) {
|
|
9585
9844
|
try {
|
|
9586
|
-
const content =
|
|
9845
|
+
const content = fs41.readFileSync(file, "utf8");
|
|
9587
9846
|
const methods = [];
|
|
9588
9847
|
const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
|
|
9589
9848
|
let match;
|
|
@@ -9640,11 +9899,11 @@ async function runWuchale(extraArgs) {
|
|
|
9640
9899
|
throwOnError: true
|
|
9641
9900
|
});
|
|
9642
9901
|
}
|
|
9643
|
-
var
|
|
9902
|
+
var extract2 = new Command98("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
|
|
9644
9903
|
var watch = new Command98("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
|
|
9645
9904
|
var status2 = new Command98("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
|
|
9646
9905
|
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(
|
|
9906
|
+
var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
|
|
9648
9907
|
|
|
9649
9908
|
// src/commands/oauth.ts
|
|
9650
9909
|
var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
@@ -9666,7 +9925,7 @@ import pc35 from "picocolors";
|
|
|
9666
9925
|
|
|
9667
9926
|
// src/lib/cms-backend.ts
|
|
9668
9927
|
import { createRequire as createRequire3 } from "node:module";
|
|
9669
|
-
import
|
|
9928
|
+
import path45 from "node:path";
|
|
9670
9929
|
import process36 from "node:process";
|
|
9671
9930
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
9672
9931
|
import pc34 from "picocolors";
|
|
@@ -9674,7 +9933,7 @@ var DEFAULT_PROJECT = "default";
|
|
|
9674
9933
|
async function loadBackendModule(root) {
|
|
9675
9934
|
let entry;
|
|
9676
9935
|
try {
|
|
9677
|
-
entry = createRequire3(
|
|
9936
|
+
entry = createRequire3(path45.join(root, "package.json")).resolve("@velastack/cms/backend");
|
|
9678
9937
|
} catch {
|
|
9679
9938
|
throw new Error(
|
|
9680
9939
|
`@velastack/cms is not installed in this project.
|
|
@@ -9692,8 +9951,8 @@ async function withCmsBackend(fn, cwd = process36.cwd()) {
|
|
|
9692
9951
|
const { createCmsBackend } = await loadBackendModule(root);
|
|
9693
9952
|
const dataDir2 = localDataDir(root);
|
|
9694
9953
|
const backend3 = createCmsBackend({
|
|
9695
|
-
dbPath:
|
|
9696
|
-
uploadDir:
|
|
9954
|
+
dbPath: path45.join(dataDir2, "cms.sqlite"),
|
|
9955
|
+
uploadDir: path45.join(dataDir2, "uploads")
|
|
9697
9956
|
});
|
|
9698
9957
|
try {
|
|
9699
9958
|
return await fn(backend3);
|
|
@@ -9805,14 +10064,14 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
|
9805
10064
|
if (isStub(actionCommand)) return;
|
|
9806
10065
|
const envRoot = findWorkspaceRoot() ?? process37.cwd();
|
|
9807
10066
|
dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
|
|
9808
|
-
const
|
|
9809
|
-
if (NO_BACKEND_COMMMANDS.has(
|
|
9810
|
-
const top =
|
|
10067
|
+
const path46 = getCommandPath(actionCommand);
|
|
10068
|
+
if (NO_BACKEND_COMMMANDS.has(path46)) return;
|
|
10069
|
+
const top = path46.split(" ", 1)[0];
|
|
9811
10070
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
9812
10071
|
if (!hasBackend()) {
|
|
9813
10072
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
9814
10073
|
p61.log.error(
|
|
9815
|
-
`${pc38.cyan(`vela ${
|
|
10074
|
+
`${pc38.cyan(`vela ${path46}`)} needs a backend, and this project does not have one.
|
|
9816
10075
|
|
|
9817
10076
|
Static projects have no database to talk to.
|
|
9818
10077
|
|
|
@@ -9822,7 +10081,7 @@ To add a backend to this project, run ${pc38.cyan("vela bless")}.`
|
|
|
9822
10081
|
p61.cancel("Operation failed.");
|
|
9823
10082
|
process37.exit(1);
|
|
9824
10083
|
}
|
|
9825
|
-
if (SELF_CREDENTIALED_COMMANDS.has(
|
|
10084
|
+
if (SELF_CREDENTIALED_COMMANDS.has(path46)) return;
|
|
9826
10085
|
if (!process37.env.POCKETBASE_SUPERUSER_EMAIL || !process37.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
9827
10086
|
p61.log.error(
|
|
9828
10087
|
`PocketBase superuser credentials are required.
|