hatchkit 0.2.1 → 0.2.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/dist/assets/env.d.ts +2 -2
- package/dist/assets/env.d.ts.map +1 -1
- package/dist/assets/index.js +11 -11
- package/dist/assets/index.js.map +1 -1
- package/dist/assets/mirror.js +1 -1
- package/dist/completion.js +1 -1
- package/dist/completion.js.map +1 -1
- package/dist/dev-setup.d.ts +3 -1
- package/dist/dev-setup.d.ts.map +1 -1
- package/dist/dev-setup.js +104 -4
- package/dist/dev-setup.js.map +1 -1
- package/dist/explain.js +1 -1
- package/dist/explain.js.map +1 -1
- package/dist/index.js +254 -39
- package/dist/index.js.map +1 -1
- package/dist/provision/glitchtip.d.ts +1 -0
- package/dist/provision/glitchtip.d.ts.map +1 -1
- package/dist/provision/glitchtip.js +16 -0
- package/dist/provision/glitchtip.js.map +1 -1
- package/dist/provision/index.d.ts +5 -0
- package/dist/provision/index.d.ts.map +1 -1
- package/dist/provision/index.js +104 -7
- package/dist/provision/index.js.map +1 -1
- package/dist/provision/openpanel.d.ts +1 -0
- package/dist/provision/openpanel.d.ts.map +1 -1
- package/dist/provision/openpanel.js +21 -0
- package/dist/provision/openpanel.js.map +1 -1
- package/dist/provision/plausible.d.ts +1 -0
- package/dist/provision/plausible.d.ts.map +1 -1
- package/dist/provision/plausible.js +5 -0
- package/dist/provision/plausible.js.map +1 -1
- package/dist/provision/resend.d.ts +4 -0
- package/dist/provision/resend.d.ts.map +1 -1
- package/dist/provision/resend.js +11 -6
- package/dist/provision/resend.js.map +1 -1
- package/dist/scaffold/app.js +2 -2
- package/dist/scaffold/app.js.map +1 -1
- package/dist/scaffold/manifest.d.ts +14 -0
- package/dist/scaffold/manifest.d.ts.map +1 -1
- package/dist/scaffold/manifest.js.map +1 -1
- package/dist/scaffold/server-add.js +3 -1
- package/dist/scaffold/server-add.js.map +1 -1
- package/dist/scaffold/starter-files.d.ts +3 -3
- package/dist/scaffold/starter-files.js +3 -3
- package/package.json +2 -2
package/dist/explain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,MAAM,KAAK,GAAiB;IAC1B,OAAO,EAAE,wEAAwE;IACjF,YAAY,EAAE;QACZ,kHAAkH;QAClH,6GAA6G;QAC7G,+HAA+H;QAC/H,+DAA+D;KAChE;IACD,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,UAAU;YAChB,WAAW,EACT,0MAA0M;SAC7M;QACD;YACE,IAAI,EAAE,SAAS;YACf,WAAW,EACT,mJAAmJ;SACtJ;QACD;YACE,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,8NAA8N;SACjO;QACD;YACE,IAAI,EAAE,UAAU;YAChB,WAAW,EACT,6HAA6H;SAChI;QACD;YACE,IAAI,EAAE,aAAa;YACnB,WAAW,EACT,8LAA8L;SACjM;KACF;IACD,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,oFAAoF;YAC7F,IAAI,EAAE,gDAAgD;SACvD;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,oEAAoE;YAC7E,IAAI,EAAE,mDAAmD;SAC1D;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,OAAO,EACL,oGAAoG;YACtG,IAAI,EAAE,oEAAoE;SAC3E;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,8DAA8D;YACvE,IAAI,EAAE,yBAAyB;SAChC;QACD;YACE,IAAI,EAAE,gBAAgB;YACtB,OAAO,EACL,sOAAsO;YACxO,IAAI,EAAE,mEAAmE;SAC1E;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,kEAAkE;YAC3E,IAAI,EAAE,yDAAyD;SAChE;QACD;YACE,IAAI,EAAE,wBAAwB;YAC9B,OAAO,EACL,6FAA6F;YAC/F,IAAI,EAAE,+EAA+E;SACtF;QACD;YACE,IAAI,EAAE,+CAA+C;YACrD,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { confirm } from "@inquirer/prompts";
|
|
5
5
|
import chalk from "chalk";
|
|
@@ -11,9 +11,10 @@ import { pushProjectKeyToCoolify, pushProjectKeyToGh, rotateProjectKey, setProje
|
|
|
11
11
|
import { handleCreateFailure, runRollback } from "./deploy/rollback.js";
|
|
12
12
|
import { runTerraform } from "./deploy/terraform.js";
|
|
13
13
|
import { collectProjectConfig } from "./prompts.js";
|
|
14
|
-
import { runProvision, runUnprovision } from "./provision/index.js";
|
|
14
|
+
import { runProvision, runUnprovision, } from "./provision/index.js";
|
|
15
15
|
import { scaffoldApp } from "./scaffold/app.js";
|
|
16
16
|
import { scaffoldInfra } from "./scaffold/infra.js";
|
|
17
|
+
import { readManifest } from "./scaffold/manifest.js";
|
|
17
18
|
import { mlEnvVarName, printMlSummary, resolveMlServices } from "./scaffold/ml-client.js";
|
|
18
19
|
import { runUpdate } from "./scaffold/update.js";
|
|
19
20
|
import { installCancelHandler, isCancelInProgress, uninstallCancelHandler, } from "./utils/cancel-handler.js";
|
|
@@ -438,10 +439,10 @@ function opts(result) {
|
|
|
438
439
|
* dir already lives inside the project (`packages/server`,
|
|
439
440
|
* `apps/web`, etc.). Returns undefined when no manifest is found —
|
|
440
441
|
* callers fall back to "skip s3" with a hint. */
|
|
441
|
-
function inferProjectDir(
|
|
442
|
-
if (!
|
|
442
|
+
function inferProjectDir(startDir) {
|
|
443
|
+
if (!startDir)
|
|
443
444
|
return undefined;
|
|
444
|
-
let cur =
|
|
445
|
+
let cur = startDir;
|
|
445
446
|
for (let i = 0; i < 4; i++) {
|
|
446
447
|
if (existsSync(join(cur, ".hatchkit.json")))
|
|
447
448
|
return cur;
|
|
@@ -452,15 +453,164 @@ function inferProjectDir(serverEnvDir) {
|
|
|
452
453
|
}
|
|
453
454
|
return undefined;
|
|
454
455
|
}
|
|
456
|
+
function manifestBucketEntries(manifest) {
|
|
457
|
+
const buckets = manifest?.s3Buckets;
|
|
458
|
+
if (!buckets)
|
|
459
|
+
return [];
|
|
460
|
+
const out = [];
|
|
461
|
+
for (const [key, value] of Object.entries(buckets)) {
|
|
462
|
+
if (key === "tokenId" || key === "accountId")
|
|
463
|
+
continue;
|
|
464
|
+
if (value && typeof value === "object" && "name" in value) {
|
|
465
|
+
out.push(value);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return out;
|
|
469
|
+
}
|
|
470
|
+
function readIfExists(path) {
|
|
471
|
+
if (!existsSync(path))
|
|
472
|
+
return "";
|
|
473
|
+
try {
|
|
474
|
+
return readFileSync(path, "utf-8");
|
|
475
|
+
}
|
|
476
|
+
catch {
|
|
477
|
+
return "";
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function readProjectEnvText(projectDir, baseName) {
|
|
481
|
+
const chunks = [];
|
|
482
|
+
if (projectDir) {
|
|
483
|
+
for (const dir of [
|
|
484
|
+
".",
|
|
485
|
+
"packages/server",
|
|
486
|
+
"packages/client",
|
|
487
|
+
"packages/web",
|
|
488
|
+
"apps/server",
|
|
489
|
+
"apps/api",
|
|
490
|
+
"apps/web",
|
|
491
|
+
"apps/client",
|
|
492
|
+
"server",
|
|
493
|
+
"client",
|
|
494
|
+
"web",
|
|
495
|
+
]) {
|
|
496
|
+
const abs = resolve(projectDir, dir);
|
|
497
|
+
chunks.push(readIfExists(join(abs, ".env.production")));
|
|
498
|
+
chunks.push(readIfExists(join(abs, ".env.development")));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (baseName) {
|
|
502
|
+
const provisionedDir = join(dirname(getConfigPath()), "provisioned");
|
|
503
|
+
if (existsSync(provisionedDir)) {
|
|
504
|
+
for (const file of readdirSync(provisionedDir)) {
|
|
505
|
+
if (file.startsWith(`${baseName}.`) && file.endsWith(".env")) {
|
|
506
|
+
chunks.push(readIfExists(join(provisionedDir, file)));
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return chunks.join("\n");
|
|
512
|
+
}
|
|
513
|
+
function servicesAlreadyAdded(args) {
|
|
514
|
+
const text = readProjectEnvText(args.projectDir, args.baseName);
|
|
515
|
+
const added = new Set();
|
|
516
|
+
if (/(^|\n)(PUBLIC_)?GLITCHTIP_DSN=/m.test(text))
|
|
517
|
+
added.add("glitchtip");
|
|
518
|
+
if (/(^|\n)(PUBLIC_)?OPENPANEL_CLIENT_ID=/m.test(text))
|
|
519
|
+
added.add("openpanel");
|
|
520
|
+
if (/(^|\n)(NEXT_PUBLIC_|PUBLIC_)?PLAUSIBLE_DOMAIN=/m.test(text))
|
|
521
|
+
added.add("plausible");
|
|
522
|
+
if (/(^|\n)RESEND_API_KEY=/m.test(text))
|
|
523
|
+
added.add("resend");
|
|
524
|
+
if (/(^|\n)R2(_[A-Z0-9]+)?_ACCESS_KEY_ID=/m.test(text))
|
|
525
|
+
added.add("s3");
|
|
526
|
+
if (manifestBucketEntries(args.manifest).some((bucket) => bucket.tokenId))
|
|
527
|
+
added.add("s3");
|
|
528
|
+
if (args.manifest?.integrations?.email)
|
|
529
|
+
added.add("email");
|
|
530
|
+
if (args.manifest?.integrations?.searchConsole)
|
|
531
|
+
added.add("search-console");
|
|
532
|
+
return added;
|
|
533
|
+
}
|
|
534
|
+
function servicesImpossibleForProject(manifest) {
|
|
535
|
+
const blocked = new Set();
|
|
536
|
+
if (!manifest)
|
|
537
|
+
return blocked;
|
|
538
|
+
if (!manifest.domain) {
|
|
539
|
+
blocked.add("email");
|
|
540
|
+
blocked.add("search-console");
|
|
541
|
+
}
|
|
542
|
+
if (manifest.surfaces === "server-only")
|
|
543
|
+
blocked.add("plausible");
|
|
544
|
+
if (manifest.surfaces === "client-only") {
|
|
545
|
+
blocked.add("resend");
|
|
546
|
+
blocked.add("s3");
|
|
547
|
+
}
|
|
548
|
+
if (manifestBucketEntries(manifest).length === 0)
|
|
549
|
+
blocked.add("s3");
|
|
550
|
+
return blocked;
|
|
551
|
+
}
|
|
552
|
+
function recordProvisionedEvent(ledger, event) {
|
|
553
|
+
if (event.service === "glitchtip")
|
|
554
|
+
ledger.record({ kind: "glitchtip", project: event.project });
|
|
555
|
+
if (event.service === "openpanel")
|
|
556
|
+
ledger.record({ kind: "openpanel", project: event.project });
|
|
557
|
+
if (event.service === "plausible")
|
|
558
|
+
ledger.record({ kind: "plausible", project: event.project });
|
|
559
|
+
if (event.service === "resend")
|
|
560
|
+
ledger.record({ kind: "resend", client: event.client });
|
|
561
|
+
if (event.service === "s3" && event.minted) {
|
|
562
|
+
ledger.record({
|
|
563
|
+
kind: "r2Token",
|
|
564
|
+
tokenId: event.tokenId,
|
|
565
|
+
accountId: event.accountId,
|
|
566
|
+
audience: "account",
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
if (event.service === "search-console" && event.dnsRecord?.created) {
|
|
570
|
+
ledger.record({
|
|
571
|
+
kind: "cloudflareDnsRecord",
|
|
572
|
+
zoneId: event.dnsRecord.zoneId,
|
|
573
|
+
recordId: event.dnsRecord.id,
|
|
574
|
+
name: event.dnsRecord.name,
|
|
575
|
+
type: event.dnsRecord.type,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
if (event.service === "email") {
|
|
579
|
+
if (event.destinationCreatedThisRun) {
|
|
580
|
+
ledger.record({
|
|
581
|
+
kind: "cloudflareEmailDestination",
|
|
582
|
+
accountId: event.accountId,
|
|
583
|
+
destinationId: event.destinationId,
|
|
584
|
+
email: event.destinationEmail,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
for (const dns of event.dnsRecords) {
|
|
588
|
+
ledger.record({
|
|
589
|
+
kind: "cloudflareDnsRecord",
|
|
590
|
+
zoneId: event.zoneId,
|
|
591
|
+
recordId: dns.id,
|
|
592
|
+
name: dns.name,
|
|
593
|
+
type: dns.type,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
for (const rule of event.rules) {
|
|
597
|
+
if (!rule.created)
|
|
598
|
+
continue;
|
|
599
|
+
ledger.record({
|
|
600
|
+
kind: "cloudflareEmailRoutingRule",
|
|
601
|
+
zoneId: event.zoneId,
|
|
602
|
+
ruleId: rule.id,
|
|
603
|
+
address: rule.address,
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
455
608
|
async function handleAdd() {
|
|
456
609
|
// Positional args are optional — anything missing is prompted for.
|
|
457
610
|
// hatchkit add (fully interactive)
|
|
458
611
|
// hatchkit add raptor-runner (prompts for services)
|
|
459
612
|
// hatchkit add raptor-runner all
|
|
460
613
|
// hatchkit add raptor-runner glitchtip,resend
|
|
461
|
-
const positional = args.slice(1).filter((a) => !a.startsWith("--"));
|
|
462
|
-
let baseName = positional[0];
|
|
463
|
-
const rawService = positional[1];
|
|
464
614
|
const allServices = [
|
|
465
615
|
"glitchtip",
|
|
466
616
|
"openpanel",
|
|
@@ -470,6 +620,24 @@ async function handleAdd() {
|
|
|
470
620
|
"email",
|
|
471
621
|
"search-console",
|
|
472
622
|
];
|
|
623
|
+
const isServiceExpr = (value) => {
|
|
624
|
+
if (!value)
|
|
625
|
+
return false;
|
|
626
|
+
if (value === "all")
|
|
627
|
+
return true;
|
|
628
|
+
return value
|
|
629
|
+
.split(",")
|
|
630
|
+
.map((s) => s.trim().toLowerCase())
|
|
631
|
+
.every((s) => allServices.includes(s));
|
|
632
|
+
};
|
|
633
|
+
const positional = args.slice(1).filter((a) => !a.startsWith("--"));
|
|
634
|
+
const inferredProjectDir = inferProjectDir(process.cwd());
|
|
635
|
+
const inferredManifest = inferredProjectDir ? readManifest(inferredProjectDir) : null;
|
|
636
|
+
const firstArgIsService = isServiceExpr(positional[0]);
|
|
637
|
+
let baseName = firstArgIsService
|
|
638
|
+
? inferredManifest?.name
|
|
639
|
+
: (positional[0] ?? inferredManifest?.name);
|
|
640
|
+
const rawService = firstArgIsService ? positional[0] : positional[1];
|
|
473
641
|
if (!baseName) {
|
|
474
642
|
const { input } = await import("@inquirer/prompts");
|
|
475
643
|
const { validateProjectName } = await import("./utils/validate.js");
|
|
@@ -478,37 +646,54 @@ async function handleAdd() {
|
|
|
478
646
|
validate: validateProjectName,
|
|
479
647
|
});
|
|
480
648
|
}
|
|
649
|
+
const alreadyAdded = servicesAlreadyAdded({
|
|
650
|
+
baseName,
|
|
651
|
+
projectDir: inferredProjectDir,
|
|
652
|
+
manifest: inferredManifest,
|
|
653
|
+
});
|
|
654
|
+
const impossible = servicesImpossibleForProject(inferredManifest);
|
|
655
|
+
const hiddenServices = new Set([...alreadyAdded, ...impossible]);
|
|
656
|
+
const addableServices = allServices.filter((service) => !hiddenServices.has(service));
|
|
481
657
|
let services;
|
|
482
658
|
if (!rawService) {
|
|
659
|
+
if (addableServices.length === 0) {
|
|
660
|
+
console.log(chalk.green(` Nothing to add — ${baseName} already has every supported service.`));
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
483
663
|
const { multiselect } = await import("./utils/multiselect.js");
|
|
664
|
+
const serviceChoices = [
|
|
665
|
+
{ name: "GlitchTip (error tracking)", value: "glitchtip", checked: false },
|
|
666
|
+
{ name: "OpenPanel (product analytics)", value: "openpanel", checked: false },
|
|
667
|
+
{ name: "Plausible (web analytics)", value: "plausible", checked: false },
|
|
668
|
+
{ name: "Resend (transactional email)", value: "resend", checked: false },
|
|
669
|
+
{
|
|
670
|
+
name: "S3 / R2 (per-bucket scoped credentials from .hatchkit.json)",
|
|
671
|
+
value: "s3",
|
|
672
|
+
checked: false,
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
name: "Email forwarding (Cloudflare Email Routing — MX/SPF/DMARC + rules)",
|
|
676
|
+
value: "email",
|
|
677
|
+
checked: false,
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
name: "Google Search Console (DNS verification + domain property)",
|
|
681
|
+
value: "search-console",
|
|
682
|
+
checked: false,
|
|
683
|
+
},
|
|
684
|
+
];
|
|
484
685
|
services = await multiselect({
|
|
485
686
|
message: "Which services to add?",
|
|
486
|
-
choices:
|
|
487
|
-
{ name: "GlitchTip (error tracking)", value: "glitchtip", checked: true },
|
|
488
|
-
{ name: "OpenPanel (product analytics)", value: "openpanel", checked: true },
|
|
489
|
-
{ name: "Plausible (web analytics)", value: "plausible", checked: false },
|
|
490
|
-
{ name: "Resend (transactional email)", value: "resend", checked: true },
|
|
491
|
-
{
|
|
492
|
-
name: "S3 / R2 (per-bucket scoped credentials from .hatchkit.json)",
|
|
493
|
-
value: "s3",
|
|
494
|
-
checked: false,
|
|
495
|
-
},
|
|
496
|
-
{
|
|
497
|
-
name: "Email forwarding (Cloudflare Email Routing — MX/SPF/DMARC + rules)",
|
|
498
|
-
value: "email",
|
|
499
|
-
checked: false,
|
|
500
|
-
},
|
|
501
|
-
{
|
|
502
|
-
name: "Google Search Console (DNS verification + domain property)",
|
|
503
|
-
value: "search-console",
|
|
504
|
-
checked: false,
|
|
505
|
-
},
|
|
506
|
-
],
|
|
687
|
+
choices: serviceChoices.filter((choice) => addableServices.includes(choice.value)),
|
|
507
688
|
required: true,
|
|
508
689
|
});
|
|
509
690
|
}
|
|
510
691
|
else if (rawService === "all") {
|
|
511
|
-
services =
|
|
692
|
+
services = addableServices;
|
|
693
|
+
if (services.length === 0) {
|
|
694
|
+
console.log(chalk.green(` Nothing to add — ${baseName} already has every supported service.`));
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
512
697
|
}
|
|
513
698
|
else {
|
|
514
699
|
const requested = rawService.split(",").map((s) => s.trim().toLowerCase());
|
|
@@ -518,7 +703,17 @@ async function handleAdd() {
|
|
|
518
703
|
console.log(chalk.dim(` Valid: ${allServices.join(", ")}, or 'all'`));
|
|
519
704
|
process.exit(1);
|
|
520
705
|
}
|
|
521
|
-
|
|
706
|
+
const skipped = requested.filter((service) => hiddenServices.has(service));
|
|
707
|
+
if (skipped.length > 0) {
|
|
708
|
+
console.log(chalk.red(` Refusing to add already-present/unavailable service(s): ${skipped.join(", ")}`));
|
|
709
|
+
console.log(chalk.dim(" Run `hatchkit remove` first if you want Hatchkit to recreate them."));
|
|
710
|
+
process.exit(1);
|
|
711
|
+
}
|
|
712
|
+
services = requested.filter((service) => !hiddenServices.has(service));
|
|
713
|
+
if (services.length === 0) {
|
|
714
|
+
console.log(chalk.green(` Nothing to add — requested service(s) are already present or unavailable.`));
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
522
717
|
}
|
|
523
718
|
// Flag parsing:
|
|
524
719
|
// --no-write → never write; print a cache summary only
|
|
@@ -573,7 +768,16 @@ async function handleAdd() {
|
|
|
573
768
|
: inferProjectDir(needsServer ? resolvePath(serverDirFlag) : undefined),
|
|
574
769
|
};
|
|
575
770
|
}
|
|
576
|
-
|
|
771
|
+
const ledger = RunLedger.resumeOrStart(baseName);
|
|
772
|
+
await runProvision({
|
|
773
|
+
baseName,
|
|
774
|
+
services,
|
|
775
|
+
surfaces,
|
|
776
|
+
enableDevObs,
|
|
777
|
+
failIfExists: true,
|
|
778
|
+
onProvisioned: (event) => recordProvisionedEvent(ledger, event),
|
|
779
|
+
});
|
|
780
|
+
ledger.complete();
|
|
577
781
|
}
|
|
578
782
|
async function handleProvisionS3() {
|
|
579
783
|
// `hatchkit provision s3` — create the public+private bucket pair
|
|
@@ -2021,9 +2225,13 @@ function printHelp(topic) {
|
|
|
2021
2225
|
without the fragment).
|
|
2022
2226
|
|
|
2023
2227
|
${chalk.bold("DNS:")}
|
|
2024
|
-
${chalk.cyan("dev-setup init")} auto-upserts a DNS-only A record
|
|
2228
|
+
${chalk.cyan("dev-setup init")} auto-upserts a DNS-only A record on a
|
|
2229
|
+
dedicated ${chalk.cyan("local.")} subdomain:
|
|
2025
2230
|
*.local.<your-domain> A <your-tailnet-ip> (DNS-only)
|
|
2026
2231
|
|
|
2232
|
+
Custom ${chalk.cyan("--domain")} values must use that ${chalk.cyan("local.")} prefix so
|
|
2233
|
+
Hatchkit never overwrites a production wildcard such as *.example.com.
|
|
2234
|
+
|
|
2027
2235
|
If Cloudflare credentials are unavailable, add that record manually.
|
|
2028
2236
|
|
|
2029
2237
|
This feature is fully optional: until you run ${chalk.cyan("dev-setup init")},
|
|
@@ -2138,6 +2346,7 @@ function printHelp(topic) {
|
|
|
2138
2346
|
|
|
2139
2347
|
${chalk.bold("Usage:")}
|
|
2140
2348
|
hatchkit add [<project-name>] [<services>] [flags]
|
|
2349
|
+
hatchkit add [<services>] [flags] ${chalk.dim("(inside a project with .hatchkit.json)")}
|
|
2141
2350
|
|
|
2142
2351
|
${chalk.bold("What it does:")}
|
|
2143
2352
|
· GlitchTip / OpenPanel: ${chalk.bold("one project per product")}, events tagged by
|
|
@@ -2155,6 +2364,11 @@ function printHelp(topic) {
|
|
|
2155
2364
|
· A 0600 cache of every value is saved under
|
|
2156
2365
|
${chalk.dim("<config-dir>/provisioned/<project>.*.env")} for recoverability.
|
|
2157
2366
|
${chalk.dim("Secret values never hit stdout.")}
|
|
2367
|
+
· The interactive menu only shows services not already present for the
|
|
2368
|
+
current project, starts with nothing selected, and refuses explicit
|
|
2369
|
+
requests that would recreate known resources.
|
|
2370
|
+
· Before creating provider resources, add runs read-only existence probes
|
|
2371
|
+
for the selected services and stops on conflicts so cleanup stays safe.
|
|
2158
2372
|
|
|
2159
2373
|
${chalk.bold("Surfaces:")}
|
|
2160
2374
|
hatchkit asks which surfaces your project has. Options:
|
|
@@ -2190,6 +2404,7 @@ function printHelp(topic) {
|
|
|
2190
2404
|
|
|
2191
2405
|
${chalk.bold("Examples:")}
|
|
2192
2406
|
hatchkit add
|
|
2407
|
+
hatchkit add search-console
|
|
2193
2408
|
hatchkit add raptor-runner
|
|
2194
2409
|
hatchkit add raptor-runner all --enable-dev-obs
|
|
2195
2410
|
hatchkit add raptor-runner glitchtip,resend --no-write
|
|
@@ -2513,13 +2728,13 @@ function printHelp(topic) {
|
|
|
2513
2728
|
}
|
|
2514
2729
|
if (topic === "assets") {
|
|
2515
2730
|
console.log(`
|
|
2516
|
-
${chalk.bold("hatchkit assets")} — move bytes between local
|
|
2731
|
+
${chalk.bold("hatchkit assets")} — move bytes between local S3 and prod buckets
|
|
2517
2732
|
|
|
2518
2733
|
${chalk.bold("Subcommands:")}
|
|
2519
|
-
assets seed [--from <dir>] Local dir → local
|
|
2734
|
+
assets seed [--from <dir>] Local dir → local S3 bucket.
|
|
2520
2735
|
Defaults to ./seed/assets.
|
|
2521
|
-
assets push [--bucket assets|state] Local
|
|
2522
|
-
assets pull [--bucket assets|state] Prod bucket → local
|
|
2736
|
+
assets push [--bucket assets|state] Local S3 → prod bucket.
|
|
2737
|
+
assets pull [--bucket assets|state] Prod bucket → local S3.
|
|
2523
2738
|
Caution: prod data may include PII.
|
|
2524
2739
|
assets migrate --from-endpoint=URL External S3 → prod bucket.
|
|
2525
2740
|
--from-bucket=NAME The adoption escape hatch — copy
|
|
@@ -2546,7 +2761,7 @@ function printHelp(topic) {
|
|
|
2546
2761
|
the env doesn't carry them (R2's URL-driven assets bucket).
|
|
2547
2762
|
|
|
2548
2763
|
${chalk.bold("Examples:")}
|
|
2549
|
-
hatchkit assets seed # ./seed/assets/ → local
|
|
2764
|
+
hatchkit assets seed # ./seed/assets/ → local S3
|
|
2550
2765
|
hatchkit assets push --dry-run # see what would ship to prod
|
|
2551
2766
|
hatchkit assets push # actually ship it
|
|
2552
2767
|
hatchkit assets migrate --from-endpoint https://nyc3.digitaloceanspaces.com \\
|
|
@@ -2587,7 +2802,7 @@ function printHelp(topic) {
|
|
|
2587
2802
|
update Add features to an already-scaffolded project (run in project dir)
|
|
2588
2803
|
server add Retrofit a server into a client-only project
|
|
2589
2804
|
add Create GlitchTip / OpenPanel / Plausible / Resend clients for an existing project
|
|
2590
|
-
assets Move bytes between local
|
|
2805
|
+
assets Move bytes between local S3 and prod buckets (seed/push/pull/migrate)
|
|
2591
2806
|
remove Delete the -dev/-prod clients created by 'add' (inverse of add)
|
|
2592
2807
|
destroy Roll back everything ${chalk.cyan("hatchkit create")} did for a project
|
|
2593
2808
|
rename-domain Move a scaffolded project to a new domain (rewrites tfvars/env/manifest)
|