hatchkit 0.1.40 → 0.1.42
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/adopt.d.ts.map +1 -1
- package/dist/adopt.js +663 -82
- package/dist/adopt.js.map +1 -1
- package/dist/config.d.ts +32 -10
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +91 -38
- package/dist/config.js.map +1 -1
- package/dist/deploy/coolify-app.d.ts.map +1 -1
- package/dist/deploy/coolify-app.js +0 -7
- package/dist/deploy/coolify-app.js.map +1 -1
- package/dist/deploy/coolify.d.ts.map +1 -1
- package/dist/deploy/coolify.js +20 -1
- package/dist/deploy/coolify.js.map +1 -1
- package/dist/deploy/ghcr.d.ts +4 -2
- package/dist/deploy/ghcr.d.ts.map +1 -1
- package/dist/deploy/ghcr.js +1 -1
- package/dist/deploy/ghcr.js.map +1 -1
- package/dist/deploy/github.d.ts +4 -3
- package/dist/deploy/github.d.ts.map +1 -1
- package/dist/deploy/github.js +5 -2
- package/dist/deploy/github.js.map +1 -1
- package/dist/deploy/pages.d.ts +41 -0
- package/dist/deploy/pages.d.ts.map +1 -1
- package/dist/deploy/pages.js +363 -22
- package/dist/deploy/pages.js.map +1 -1
- package/dist/deploy/regen-infra.d.ts.map +1 -1
- package/dist/deploy/regen-infra.js +5 -11
- package/dist/deploy/regen-infra.js.map +1 -1
- package/dist/deploy/rollback.d.ts.map +1 -1
- package/dist/deploy/rollback.js +44 -6
- package/dist/deploy/rollback.js.map +1 -1
- package/dist/deploy/terraform.d.ts.map +1 -1
- package/dist/deploy/terraform.js +20 -37
- package/dist/deploy/terraform.js.map +1 -1
- package/dist/dns.d.ts.map +1 -1
- package/dist/dns.js +4 -5
- package/dist/dns.js.map +1 -1
- package/dist/doctor.d.ts +15 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +110 -36
- package/dist/doctor.js.map +1 -1
- package/dist/email/index.d.ts +31 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +251 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/presets.d.ts +14 -0
- package/dist/email/presets.d.ts.map +1 -0
- package/dist/email/presets.js +33 -0
- package/dist/email/presets.js.map +1 -0
- package/dist/email/setup.d.ts +93 -0
- package/dist/email/setup.d.ts.map +1 -0
- package/dist/email/setup.js +263 -0
- package/dist/email/setup.js.map +1 -0
- package/dist/email/spf.d.ts +56 -0
- package/dist/email/spf.d.ts.map +1 -0
- package/dist/email/spf.js +102 -0
- package/dist/email/spf.js.map +1 -0
- package/dist/index.js +306 -22
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +37 -0
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +536 -55
- package/dist/inventory.js.map +1 -1
- package/dist/overview.d.ts +101 -0
- package/dist/overview.d.ts.map +1 -0
- package/dist/overview.js +880 -0
- package/dist/overview.js.map +1 -0
- package/dist/prompts.d.ts +27 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +262 -34
- package/dist/prompts.js.map +1 -1
- package/dist/provision/index.d.ts +20 -1
- package/dist/provision/index.d.ts.map +1 -1
- package/dist/provision/index.js +115 -0
- package/dist/provision/index.js.map +1 -1
- package/dist/provision/s3-buckets.js +1 -1
- package/dist/provision/s3-buckets.js.map +1 -1
- package/dist/scaffold/app.d.ts.map +1 -1
- package/dist/scaffold/app.js +15 -7
- package/dist/scaffold/app.js.map +1 -1
- package/dist/scaffold/build-pipeline.d.ts +16 -0
- package/dist/scaffold/build-pipeline.d.ts.map +1 -1
- package/dist/scaffold/build-pipeline.js +47 -4
- package/dist/scaffold/build-pipeline.js.map +1 -1
- package/dist/scaffold/infra.d.ts +4 -5
- package/dist/scaffold/infra.d.ts.map +1 -1
- package/dist/scaffold/infra.js +18 -57
- package/dist/scaffold/infra.js.map +1 -1
- package/dist/scaffold/manifest.d.ts +6 -0
- package/dist/scaffold/manifest.d.ts.map +1 -1
- package/dist/scaffold/manifest.js +2 -0
- package/dist/scaffold/manifest.js.map +1 -1
- package/dist/scaffold/pages-heuristics.d.ts +17 -0
- package/dist/scaffold/pages-heuristics.d.ts.map +1 -0
- package/dist/scaffold/pages-heuristics.js +344 -0
- package/dist/scaffold/pages-heuristics.js.map +1 -0
- package/dist/scaffold/pages-mode.d.ts +10 -0
- package/dist/scaffold/pages-mode.d.ts.map +1 -0
- package/dist/scaffold/pages-mode.js +107 -0
- package/dist/scaffold/pages-mode.js.map +1 -0
- package/dist/scaffold/pkg-json.d.ts +4 -0
- package/dist/scaffold/pkg-json.d.ts.map +1 -1
- package/dist/scaffold/pkg-json.js +17 -0
- package/dist/scaffold/pkg-json.js.map +1 -1
- package/dist/scaffold/surfaces.d.ts.map +1 -1
- package/dist/scaffold/surfaces.js +12 -1
- package/dist/scaffold/surfaces.js.map +1 -1
- package/dist/scaffold/update.js +1 -1
- package/dist/scaffold/update.js.map +1 -1
- package/dist/templates/build-pipeline/Dockerfile.nextjs.hbs +103 -0
- package/dist/templates/build-pipeline/docker-compose.yml.hbs +23 -6
- package/dist/utils/cloudflare-api.d.ts +158 -13
- package/dist/utils/cloudflare-api.d.ts.map +1 -1
- package/dist/utils/cloudflare-api.js +219 -11
- package/dist/utils/cloudflare-api.js.map +1 -1
- package/dist/utils/coolify-api.d.ts +9 -0
- package/dist/utils/coolify-api.d.ts.map +1 -1
- package/dist/utils/coolify-api.js +26 -0
- package/dist/utils/coolify-api.js.map +1 -1
- package/dist/utils/run-ledger.d.ts +42 -1
- package/dist/utils/run-ledger.d.ts.map +1 -1
- package/dist/utils/run-ledger.js.map +1 -1
- package/dist/utils/s3-admin.d.ts +9 -0
- package/dist/utils/s3-admin.d.ts.map +1 -0
- package/dist/utils/s3-admin.js +46 -0
- package/dist/utils/s3-admin.js.map +1 -0
- package/package.json +1 -1
package/dist/deploy/ghcr.d.ts
CHANGED
|
@@ -3,8 +3,10 @@ export interface GhcrSetupOptions {
|
|
|
3
3
|
/** Owner/repo slug, e.g. `trebeljahr/extinction-protocol`. */
|
|
4
4
|
repoSlug: string;
|
|
5
5
|
/** Maximum time to wait for the first Actions push to create the
|
|
6
|
-
* package in GHCR. Default
|
|
7
|
-
*
|
|
6
|
+
* package in GHCR. Default 10 minutes — the starter's verify + e2e
|
|
7
|
+
* + build-server/client pipeline routinely takes 5–8 min on a cold
|
|
8
|
+
* GHA runner, so 5 was right at the boundary and timed out
|
|
9
|
+
* intermittently. */
|
|
8
10
|
waitTimeoutMs?: number;
|
|
9
11
|
/** How often to recheck whether the package exists. Default 8s —
|
|
10
12
|
* matches GHCR's typical sync delay after a push. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ghcr.d.ts","sourceRoot":"","sources":["../../src/deploy/ghcr.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB
|
|
1
|
+
{"version":3,"file":"ghcr.d.ts","sourceRoot":"","sources":["../../src/deploy/ghcr.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;0BAIsB;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;0DACsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;oBAGoB;AACpB,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,QAAQ,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAiE/F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,gBAAgB,GAAG;IAC1B,GAAG,EAAE,UAAU,CAAC;IAChB;+DAC2D;IAC3D,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;6CAEyC;IACzC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,GACA,OAAO,CAAC,eAAe,CAAC,CA2C1B"}
|
package/dist/deploy/ghcr.js
CHANGED
|
@@ -42,7 +42,7 @@ import { exec, execOk } from "../utils/exec.js";
|
|
|
42
42
|
* the user isn't stuck if Actions failed for an unrelated reason.
|
|
43
43
|
*/
|
|
44
44
|
export async function makeGhcrPackagePublic(options) {
|
|
45
|
-
const { repoSlug, waitTimeoutMs =
|
|
45
|
+
const { repoSlug, waitTimeoutMs = 10 * 60_000, pollIntervalMs = 8_000 } = options;
|
|
46
46
|
const [owner, name] = splitSlug(repoSlug);
|
|
47
47
|
// Cheap upfront check — bail before the wait if `gh` can't possibly
|
|
48
48
|
// succeed at the PATCH step. Saves 5 minutes of false hope.
|
package/dist/deploy/ghcr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ghcr.js","sourceRoot":"","sources":["../../src/deploy/ghcr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ghcr.js","sourceRoot":"","sources":["../../src/deploy/ghcr.ts"],"names":[],"mappings":"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"}
|
package/dist/deploy/github.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ import type { ProjectConfig } from "../prompts.js";
|
|
|
7
7
|
export declare function setupGitHub(config: ProjectConfig, appDir: string): Promise<string | null>;
|
|
8
8
|
/** Push the working branch to `origin`. Run AFTER Coolify wiring +
|
|
9
9
|
* GH Actions secrets are in place so the workflow's first run can
|
|
10
|
-
* hit the redeploy webhook successfully.
|
|
11
|
-
*
|
|
12
|
-
|
|
10
|
+
* hit the redeploy webhook successfully. Returns true on a clean
|
|
11
|
+
* push, false otherwise — the caller uses this to gate the GHCR
|
|
12
|
+
* visibility flip (no push = no Actions run = no image to wait for). */
|
|
13
|
+
export declare function pushInitialBranch(projectDir: string): Promise<boolean>;
|
|
13
14
|
//# sourceMappingURL=github.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/deploy/github.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD;;;;eAIe;AACf,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmD/F;AAED
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/deploy/github.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD;;;;eAIe;AACf,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmD/F;AAED;;;;yEAIyE;AACzE,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAwB5E"}
|
package/dist/deploy/github.js
CHANGED
|
@@ -44,8 +44,9 @@ export async function setupGitHub(config, appDir) {
|
|
|
44
44
|
}
|
|
45
45
|
/** Push the working branch to `origin`. Run AFTER Coolify wiring +
|
|
46
46
|
* GH Actions secrets are in place so the workflow's first run can
|
|
47
|
-
* hit the redeploy webhook successfully.
|
|
48
|
-
*
|
|
47
|
+
* hit the redeploy webhook successfully. Returns true on a clean
|
|
48
|
+
* push, false otherwise — the caller uses this to gate the GHCR
|
|
49
|
+
* visibility flip (no push = no Actions run = no image to wait for). */
|
|
49
50
|
export async function pushInitialBranch(projectDir) {
|
|
50
51
|
// `git symbolic-ref --short HEAD` is more reliable than rev-parse
|
|
51
52
|
// for the brand-new `git init` case where HEAD points at an unborn
|
|
@@ -63,6 +64,8 @@ export async function pushInitialBranch(projectDir) {
|
|
|
63
64
|
console.log(chalk.yellow(` Couldn't push ${branch} to origin — push manually:\n` +
|
|
64
65
|
` cd ${projectDir}\n` +
|
|
65
66
|
` git push -u origin ${branch}`));
|
|
67
|
+
return false;
|
|
66
68
|
}
|
|
69
|
+
return true;
|
|
67
70
|
}
|
|
68
71
|
//# sourceMappingURL=github.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/deploy/github.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC;;;;eAIe;AACf,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAqB,EAAE,MAAc;IACrE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC,CAAC;IAE5F,WAAW;IACX,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;QAC1B,GAAG,EAAE,MAAM;QACX,OAAO,EAAE,0BAA0B;KACpC,CAAC,CAAC;IAEH,iBAAiB;IACjB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,kBAAkB,CAAC,EAAE;QACtD,GAAG,EAAE,MAAM;QACX,OAAO,EAAE,4BAA4B;KACtC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+DAA+D;IAC/D,iEAAiE;IACjE,6CAA6C;IAC7C,MAAM,YAAY,GAAG,MAAM,IAAI,CAC7B,IAAI,EACJ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,CAAC,EAC1D,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,MAAM,CAAC,IAAI,KAAK,EAAE,CACpE,CAAC;IAEF,IAAI,YAAY,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,+DAA+D,CAAC,CAAC,CAAC;QAC3F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,IAAI,8BAA8B,CAAC,CAAC,CAAC;QACxF,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,iFAAiF,CAClF,CACF,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mBAAmB;IACnB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE;QAClF,GAAG,EAAE,MAAM;KACZ,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC,CAAC;IACxD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/deploy/github.ts"],"names":[],"mappings":"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"}
|
package/dist/deploy/pages.d.ts
CHANGED
|
@@ -1,2 +1,43 @@
|
|
|
1
|
+
/** What kind of site lives in a folder — determines the build workflow. */
|
|
2
|
+
export type SiteKind = "static" | "node-build" | "docusaurus" | "jekyll";
|
|
3
|
+
export interface Detected {
|
|
4
|
+
kind: SiteKind;
|
|
5
|
+
/** Folder uploaded to Pages. Relative to repo root. */
|
|
6
|
+
publishDir: string;
|
|
7
|
+
/** Package manager for node-build sites. */
|
|
8
|
+
packageManager?: "pnpm" | "npm" | "yarn" | "bun";
|
|
9
|
+
/** npm script name used for the build (usually "build"). */
|
|
10
|
+
buildScript?: string;
|
|
11
|
+
/** Working directory for the build. Empty string = repo root. */
|
|
12
|
+
workDir: string;
|
|
13
|
+
}
|
|
1
14
|
export declare function runPagesSetup(cwd: string): Promise<void>;
|
|
15
|
+
/** Programmatic entrypoint for the create/adopt flows.
|
|
16
|
+
*
|
|
17
|
+
* Takes already-resolved values (detected site shape, optional
|
|
18
|
+
* custom domain) and runs the same enable / workflow / DNS / cert
|
|
19
|
+
* pipeline as the interactive flow. Skips the pickSite + promptDomain
|
|
20
|
+
* steps so it's safe to call from within a larger non-interactive
|
|
21
|
+
* scaffold.
|
|
22
|
+
*
|
|
23
|
+
* Returns the public URL the site will be served from so callers
|
|
24
|
+
* can include it in their summary. */
|
|
25
|
+
export declare function runPagesSetupProgrammatic(cwd: string, opts: {
|
|
26
|
+
detected: Detected;
|
|
27
|
+
domain: string | null;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
pageUrl: string;
|
|
30
|
+
}>;
|
|
31
|
+
interface UndoOptions {
|
|
32
|
+
dryRun: boolean;
|
|
33
|
+
yes: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reverse what `hatchkit gh-pages` did: disables Pages, deletes the
|
|
37
|
+
* Cloudflare records it created, removes the workflow file, removes any
|
|
38
|
+
* CNAME files matching the registered domain. Idempotent — safe to run
|
|
39
|
+
* even if some pieces are already gone.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runPagesUndo(cwd: string, opts: UndoOptions): Promise<void>;
|
|
42
|
+
export {};
|
|
2
43
|
//# sourceMappingURL=pages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/deploy/pages.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/deploy/pages.ts"],"names":[],"mappings":"AAuBA,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEzE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IACjD,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AA4BD,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9D;AAED;;;;;;;;;uCASuC;AACvC,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAClD,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAS9B;AA8yBD,UAAU,WAAW;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd;AAgBD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0ChF"}
|
package/dist/deploy/pages.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolve4 } from "node:dns/promises";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
3
|
import { join } from "node:path";
|
|
4
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
3
5
|
import { confirm, input, select } from "@inquirer/prompts";
|
|
4
6
|
import chalk from "chalk";
|
|
7
|
+
import ora from "ora";
|
|
5
8
|
import { ensureDns, getDnsConfig } from "../config.js";
|
|
6
9
|
import { CloudflareApi } from "../utils/cloudflare-api.js";
|
|
7
10
|
import { exec } from "../utils/exec.js";
|
|
@@ -18,16 +21,47 @@ export async function runPagesSetup(cwd) {
|
|
|
18
21
|
console.log(chalk.bold("\n ── hatchkit gh-pages ──────────────────────────────────────\n"));
|
|
19
22
|
// 1. Repo — must be a git repo with an `origin` pointing at GitHub.
|
|
20
23
|
const repo = await detectRepo(cwd);
|
|
21
|
-
|
|
22
|
-
if (repo.private) {
|
|
23
|
-
console.log(chalk.yellow(" ⚠ Private repos need a paid GitHub plan (Pro/Team/Enterprise) for Pages.\n Continuing anyway — will fail at API call if unsupported."));
|
|
24
|
-
}
|
|
24
|
+
printRepoHeader(repo);
|
|
25
25
|
// 2. Pick a site. Auto-confirm when there's one obvious candidate;
|
|
26
26
|
// ask when zero or many. Also let the user override the detected
|
|
27
27
|
// publish folder before we commit to writing anything.
|
|
28
28
|
const confirmed = await pickSite(cwd);
|
|
29
29
|
// 3. Custom domain (optional).
|
|
30
30
|
const domain = await promptDomain();
|
|
31
|
+
await executePagesSetup(cwd, repo, confirmed, domain);
|
|
32
|
+
}
|
|
33
|
+
/** Programmatic entrypoint for the create/adopt flows.
|
|
34
|
+
*
|
|
35
|
+
* Takes already-resolved values (detected site shape, optional
|
|
36
|
+
* custom domain) and runs the same enable / workflow / DNS / cert
|
|
37
|
+
* pipeline as the interactive flow. Skips the pickSite + promptDomain
|
|
38
|
+
* steps so it's safe to call from within a larger non-interactive
|
|
39
|
+
* scaffold.
|
|
40
|
+
*
|
|
41
|
+
* Returns the public URL the site will be served from so callers
|
|
42
|
+
* can include it in their summary. */
|
|
43
|
+
export async function runPagesSetupProgrammatic(cwd, opts) {
|
|
44
|
+
const repo = await detectRepo(cwd);
|
|
45
|
+
printRepoHeader(repo);
|
|
46
|
+
await executePagesSetup(cwd, repo, opts.detected, opts.domain);
|
|
47
|
+
return {
|
|
48
|
+
pageUrl: opts.domain
|
|
49
|
+
? `https://${opts.domain}`
|
|
50
|
+
: `https://${repo.owner}.github.io/${repo.repo}/`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function printRepoHeader(repo) {
|
|
54
|
+
console.log(chalk.dim(` Repo: ${repo.fullName} (${repo.private ? "private" : "public"})`));
|
|
55
|
+
if (repo.private) {
|
|
56
|
+
console.log(chalk.yellow(" ⚠ Private repos need a paid GitHub plan (Pro/Team/Enterprise) for Pages.\n Continuing anyway — will fail at API call if unsupported."));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** The shared execution pipeline used by both the interactive
|
|
60
|
+
* `runPagesSetup` and the programmatic `runPagesSetupProgrammatic`.
|
|
61
|
+
* Everything from "we know what to deploy and where" onwards lives
|
|
62
|
+
* here — anything *before* that (site detection, domain prompt) is
|
|
63
|
+
* caller-specific. */
|
|
64
|
+
async function executePagesSetup(cwd, repo, confirmed, domain) {
|
|
31
65
|
// 4. Enable Pages via GitHub API.
|
|
32
66
|
await enablePages(repo);
|
|
33
67
|
// 5. Write the workflow — unless the repo already has a Pages-deploying
|
|
@@ -36,10 +70,23 @@ export async function runPagesSetup(cwd) {
|
|
|
36
70
|
// 6. CNAME file — only when a custom domain is chosen.
|
|
37
71
|
if (domain)
|
|
38
72
|
writeCnameFile(cwd, confirmed, domain);
|
|
39
|
-
// 7. Pages CNAME +
|
|
73
|
+
// 7. DNS + Pages CNAME + HTTPS.
|
|
74
|
+
//
|
|
75
|
+
// Order matters: GitHub validates the cname by resolving DNS the moment
|
|
76
|
+
// we PUT it. If DNS isn't in place yet, validation fails silently, cert
|
|
77
|
+
// provisioning is never kicked off, and GitHub doesn't retry. So:
|
|
78
|
+
// a. Wire DNS first.
|
|
79
|
+
// b. Wait for DNS to actually resolve (only when we wrote it ourselves).
|
|
80
|
+
// c. Then tell GitHub the cname — bouncing it first if a prior run
|
|
81
|
+
// left it stuck without a cert.
|
|
82
|
+
// d. Wait for the Let's Encrypt cert to be issued, then flip
|
|
83
|
+
// `https_enforced` so http:// redirects to https://.
|
|
40
84
|
if (domain) {
|
|
85
|
+
const { wired } = await configureDns(domain);
|
|
86
|
+
if (wired)
|
|
87
|
+
await waitForDnsResolves(domain);
|
|
41
88
|
await setPagesCname(repo, domain);
|
|
42
|
-
await
|
|
89
|
+
await provisionHttps(repo, wired);
|
|
43
90
|
}
|
|
44
91
|
printSummary(repo, confirmed, domain);
|
|
45
92
|
}
|
|
@@ -280,12 +327,121 @@ async function enablePages(repo) {
|
|
|
280
327
|
throw new Error(`Couldn't enable Pages: ${res.stderr.trim() || res.stdout.trim()}`);
|
|
281
328
|
}
|
|
282
329
|
async function setPagesCname(repo, domain) {
|
|
330
|
+
// If the cname is already correct but no cert exists, GitHub is stuck
|
|
331
|
+
// (most often because an earlier run set the cname before DNS was live,
|
|
332
|
+
// so the validation+cert flow ran against missing DNS and never retried).
|
|
333
|
+
// Bounce the cname — clear, then re-set — to force a fresh validation
|
|
334
|
+
// pass now that DNS is in place. Idempotent on the happy path: if a cert
|
|
335
|
+
// is already issued we skip the bounce entirely.
|
|
336
|
+
const current = await getPagesInfo(repo);
|
|
337
|
+
const stuck = current?.cname === domain && !current?.https_certificate;
|
|
338
|
+
if (stuck) {
|
|
339
|
+
await exec("gh", ["api", "-X", "PUT", `repos/${repo.fullName}/pages`, "-f", "cname="], {
|
|
340
|
+
silent: true,
|
|
341
|
+
spinner: "Resetting Pages CNAME to retry cert provisioning...",
|
|
342
|
+
});
|
|
343
|
+
await sleep(2000);
|
|
344
|
+
}
|
|
283
345
|
const res = await exec("gh", ["api", "-X", "PUT", `repos/${repo.fullName}/pages`, "-f", `cname=${domain}`], { silent: true, spinner: `Registering ${domain} with Pages...` });
|
|
284
346
|
if (res.exitCode !== 0) {
|
|
285
|
-
// Non-fatal: DNS might not be
|
|
347
|
+
// Non-fatal: DNS might still not be visible to GitHub yet.
|
|
286
348
|
console.log(chalk.yellow(` ⚠ Couldn't set Pages CNAME to ${domain} (${res.stderr.trim()}).\n Set it manually in Settings → Pages once DNS resolves.`));
|
|
287
349
|
}
|
|
288
350
|
}
|
|
351
|
+
async function getPagesInfo(repo) {
|
|
352
|
+
const res = await exec("gh", ["api", `repos/${repo.fullName}/pages`], { silent: true });
|
|
353
|
+
if (res.exitCode !== 0)
|
|
354
|
+
return null;
|
|
355
|
+
try {
|
|
356
|
+
return JSON.parse(res.stdout);
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// ---------------------------------------------------------------------------
|
|
363
|
+
// HTTPS provisioning
|
|
364
|
+
// ---------------------------------------------------------------------------
|
|
365
|
+
/**
|
|
366
|
+
* Wait for `domain` to resolve to one of GitHub's Pages IPs. Important when
|
|
367
|
+
* we just wrote DNS records via API — GitHub validates the cname by hitting
|
|
368
|
+
* authoritative DNS, and Cloudflare propagation is usually a few seconds
|
|
369
|
+
* but can briefly lag. Bounded wait; on timeout we proceed anyway.
|
|
370
|
+
*/
|
|
371
|
+
async function waitForDnsResolves(domain, timeoutMs = 60_000) {
|
|
372
|
+
const githubIps = new Set(GITHUB_APEX_A);
|
|
373
|
+
const spinner = ora(`Waiting for DNS for ${domain} to resolve to GitHub...`).start();
|
|
374
|
+
const start = Date.now();
|
|
375
|
+
while (Date.now() - start < timeoutMs) {
|
|
376
|
+
try {
|
|
377
|
+
const ips = await resolve4(domain);
|
|
378
|
+
if (ips.some((ip) => githubIps.has(ip))) {
|
|
379
|
+
spinner.succeed(`DNS resolves: ${domain} → ${ips[0]}`);
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
// ENOTFOUND / SERVFAIL — keep polling.
|
|
385
|
+
}
|
|
386
|
+
await sleep(3000);
|
|
387
|
+
}
|
|
388
|
+
spinner.warn(`DNS for ${domain} hasn't propagated yet — continuing anyway`);
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Drive GitHub's HTTPS state machine to completion: poll until the Let's
|
|
393
|
+
* Encrypt cert is `issued`, then flip `https_enforced=true` so http://
|
|
394
|
+
* redirects to https://. Pre-existing fully-configured sites short-circuit
|
|
395
|
+
* on the first poll.
|
|
396
|
+
*
|
|
397
|
+
* If the user added DNS records manually we don't know when they'll land,
|
|
398
|
+
* so we skip the wait and print the finishing commands instead of blocking
|
|
399
|
+
* the CLI for what could be hours.
|
|
400
|
+
*/
|
|
401
|
+
async function provisionHttps(repo, autoDns) {
|
|
402
|
+
if (!autoDns) {
|
|
403
|
+
console.log(chalk.dim(`\n Once your DNS records resolve, GitHub will provision an HTTPS cert (usually <5 min).`));
|
|
404
|
+
console.log(chalk.dim(` Check: gh api repos/${repo.fullName}/pages | jq .https_certificate`));
|
|
405
|
+
console.log(chalk.dim(` Enforce: gh api -X PUT repos/${repo.fullName}/pages -F https_enforced=true`));
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const issued = await waitForCertIssued(repo);
|
|
409
|
+
if (!issued) {
|
|
410
|
+
console.log(chalk.yellow(`\n ⚠ HTTPS cert wasn't issued within the wait window — leaving https_enforced off.`));
|
|
411
|
+
console.log(chalk.dim(` Check: gh api repos/${repo.fullName}/pages | jq .https_certificate`));
|
|
412
|
+
console.log(chalk.dim(` Enforce: gh api -X PUT repos/${repo.fullName}/pages -F https_enforced=true`));
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const info = await getPagesInfo(repo);
|
|
416
|
+
if (info?.https_enforced) {
|
|
417
|
+
console.log(chalk.dim(" HTTPS already enforced."));
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const res = await exec("gh", ["api", "-X", "PUT", `repos/${repo.fullName}/pages`, "-F", "https_enforced=true"], { silent: true, spinner: "Enabling Enforce HTTPS..." });
|
|
421
|
+
if (res.exitCode !== 0) {
|
|
422
|
+
console.log(chalk.yellow(` ⚠ Couldn't enable HTTPS enforcement: ${res.stderr.trim() || res.stdout.trim()}`));
|
|
423
|
+
console.log(chalk.dim(` Run later: gh api -X PUT repos/${repo.fullName}/pages -F https_enforced=true`));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function waitForCertIssued(repo, timeoutMs = 5 * 60_000) {
|
|
427
|
+
const spinner = ora("Waiting for GitHub to provision the HTTPS certificate...").start();
|
|
428
|
+
const start = Date.now();
|
|
429
|
+
let lastState = "pending";
|
|
430
|
+
while (Date.now() - start < timeoutMs) {
|
|
431
|
+
const info = await getPagesInfo(repo);
|
|
432
|
+
const state = info?.https_certificate?.state;
|
|
433
|
+
if (state)
|
|
434
|
+
lastState = state;
|
|
435
|
+
if (state === "issued" || state === "approved") {
|
|
436
|
+
spinner.succeed(`HTTPS certificate ${state}`);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
spinner.text = `Waiting for HTTPS certificate (state: ${lastState})...`;
|
|
440
|
+
await sleep(15_000);
|
|
441
|
+
}
|
|
442
|
+
spinner.warn(`HTTPS cert not ready after ${Math.round(timeoutMs / 1000)}s (last: ${lastState})`);
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
289
445
|
// ---------------------------------------------------------------------------
|
|
290
446
|
// Workflow + CNAME file
|
|
291
447
|
// ---------------------------------------------------------------------------
|
|
@@ -472,22 +628,16 @@ async function configureDns(domain) {
|
|
|
472
628
|
if (wantConfigure)
|
|
473
629
|
dns = await ensureDns();
|
|
474
630
|
}
|
|
475
|
-
if (!dns
|
|
631
|
+
if (!dns) {
|
|
476
632
|
printManualDnsRecords(baseDomain, subdomain, target, isApex);
|
|
477
|
-
return;
|
|
633
|
+
return { wired: false };
|
|
478
634
|
}
|
|
479
|
-
if (dns.
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
await configureCloudflareDns(dns.apiToken, baseDomain, subdomain, target, isApex);
|
|
486
|
-
return;
|
|
635
|
+
if (!dns.apiToken) {
|
|
636
|
+
console.log(chalk.yellow(" ⚠ Cloudflare token missing from keychain."));
|
|
637
|
+
printManualDnsRecords(baseDomain, subdomain, target, isApex);
|
|
638
|
+
return { wired: false };
|
|
487
639
|
}
|
|
488
|
-
|
|
489
|
-
console.log(chalk.dim(" INWX auto-configure isn't implemented for Pages — showing manual records:"));
|
|
490
|
-
printManualDnsRecords(baseDomain, subdomain, target, isApex);
|
|
640
|
+
return configureCloudflareDns(dns.apiToken, baseDomain, subdomain, target, isApex);
|
|
491
641
|
}
|
|
492
642
|
async function getGitHubUser() {
|
|
493
643
|
const res = await exec("gh", ["api", "user", "--jq", ".login"], { silent: true });
|
|
@@ -514,7 +664,7 @@ async function configureCloudflareDns(token, baseDomain, subdomain, target, isAp
|
|
|
514
664
|
if (!zone) {
|
|
515
665
|
console.log(chalk.yellow(` ⚠ No Cloudflare zone found for ${baseDomain}. Falling back to manual records.`));
|
|
516
666
|
printManualDnsRecords(baseDomain, subdomain, target, isApex);
|
|
517
|
-
return;
|
|
667
|
+
return { wired: false };
|
|
518
668
|
}
|
|
519
669
|
const recordName = isApex ? baseDomain : `${subdomain}.${baseDomain}`;
|
|
520
670
|
// GitHub Pages apex needs A records for all four IPs (round-robin
|
|
@@ -535,6 +685,7 @@ async function configureCloudflareDns(token, baseDomain, subdomain, target, isAp
|
|
|
535
685
|
const line = ` ${rec.type} ${recordName} → ${rec.content} (${status})`;
|
|
536
686
|
console.log(result.created || result.updated ? chalk.green(`✓ ${line.trimStart()}`) : chalk.dim(line));
|
|
537
687
|
}
|
|
688
|
+
return { wired: true };
|
|
538
689
|
}
|
|
539
690
|
// ---------------------------------------------------------------------------
|
|
540
691
|
// Summary
|
|
@@ -554,4 +705,194 @@ function printSummary(repo, d, domain) {
|
|
|
554
705
|
}
|
|
555
706
|
console.log(chalk.yellow(`\n Next: commit & push the new workflow (and CNAME file) to ${repo.defaultBranch}.\n`));
|
|
556
707
|
}
|
|
708
|
+
/**
|
|
709
|
+
* Reverse what `hatchkit gh-pages` did: disables Pages, deletes the
|
|
710
|
+
* Cloudflare records it created, removes the workflow file, removes any
|
|
711
|
+
* CNAME files matching the registered domain. Idempotent — safe to run
|
|
712
|
+
* even if some pieces are already gone.
|
|
713
|
+
*/
|
|
714
|
+
export async function runPagesUndo(cwd, opts) {
|
|
715
|
+
console.log(chalk.bold("\n ── hatchkit gh-pages --undo ───────────────────────────────\n"));
|
|
716
|
+
const repo = await detectRepo(cwd);
|
|
717
|
+
console.log(chalk.dim(` Repo: ${repo.fullName}`));
|
|
718
|
+
const plan = await buildUndoPlan(cwd, repo);
|
|
719
|
+
if (!isAnythingToUndo(plan)) {
|
|
720
|
+
console.log(chalk.dim("\n Nothing to undo — no Pages config, workflow, or CNAME files found.\n"));
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
printUndoPlan(plan);
|
|
724
|
+
if (opts.dryRun) {
|
|
725
|
+
console.log(chalk.dim("\n --dry-run set, nothing changed.\n"));
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
if (!opts.yes) {
|
|
729
|
+
const ok = await confirm({
|
|
730
|
+
message: "Proceed with the steps above?",
|
|
731
|
+
default: false,
|
|
732
|
+
});
|
|
733
|
+
if (!ok) {
|
|
734
|
+
console.log(chalk.dim("\n Aborted — nothing changed.\n"));
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
await executeUndo(repo, plan);
|
|
739
|
+
console.log(chalk.bold("\n ── Done ───────────────────────────────────────────────────\n"));
|
|
740
|
+
if (plan.cname) {
|
|
741
|
+
console.log(chalk.dim(` DNS at other providers (registrar caches, AAAA records, etc.) may need manual cleanup.\n`));
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
async function buildUndoPlan(cwd, repo) {
|
|
745
|
+
const info = await getPagesInfo(repo);
|
|
746
|
+
const cname = info?.cname ?? null;
|
|
747
|
+
// Workflow: only the one we write. Hand-written Pages workflows
|
|
748
|
+
// (e.g. docs.yml) belong to the user — don't touch them.
|
|
749
|
+
const wfPath = join(cwd, ".github", "workflows", WORKFLOW_FILENAME);
|
|
750
|
+
const workflowPath = existsSync(wfPath) ? wfPath : null;
|
|
751
|
+
// CNAME files: scan the spots `writeCnameFile` could have written.
|
|
752
|
+
// Only flag files whose content matches the registered cname so we
|
|
753
|
+
// never delete a CNAME the user wrote for some other purpose.
|
|
754
|
+
const cnamePaths = cname ? findCnameFiles(cwd, cname) : [];
|
|
755
|
+
// Cloudflare records: present only if a cname was registered AND
|
|
756
|
+
// we have a Cloudflare token AND the zone is in this account.
|
|
757
|
+
const cloudflare = { available: false, records: [] };
|
|
758
|
+
if (cname) {
|
|
759
|
+
const dns = await getDnsConfig();
|
|
760
|
+
if (dns?.apiToken) {
|
|
761
|
+
const { baseDomain, subdomain } = parseDomain(cname);
|
|
762
|
+
const recordName = subdomain === "" ? baseDomain : `${subdomain}.${baseDomain}`;
|
|
763
|
+
const api = new CloudflareApi({ token: dns.apiToken });
|
|
764
|
+
const zone = await api.getZoneByName(baseDomain);
|
|
765
|
+
if (zone) {
|
|
766
|
+
const ghUser = await getGitHubUser().catch(() => "");
|
|
767
|
+
const target = ghUser ? `${ghUser}.github.io` : "";
|
|
768
|
+
const all = await api.findRecordsByName(zone.id, recordName);
|
|
769
|
+
// Only delete records that match what hatchkit could plausibly
|
|
770
|
+
// have written: A records pointing at GitHub's Pages IPs, or a
|
|
771
|
+
// CNAME pointing at <user>.github.io. Anything else stays.
|
|
772
|
+
const records = all.filter((r) => (r.type === "A" && GITHUB_APEX_A.includes(r.content)) ||
|
|
773
|
+
(r.type === "CNAME" && target && r.content === target));
|
|
774
|
+
cloudflare.available = true;
|
|
775
|
+
cloudflare.zoneId = zone.id;
|
|
776
|
+
cloudflare.baseDomain = baseDomain;
|
|
777
|
+
cloudflare.records = records.map((r) => ({
|
|
778
|
+
id: r.id,
|
|
779
|
+
type: r.type,
|
|
780
|
+
name: r.name,
|
|
781
|
+
content: r.content,
|
|
782
|
+
}));
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return {
|
|
787
|
+
pagesEnabled: info !== null,
|
|
788
|
+
cname,
|
|
789
|
+
workflowPath,
|
|
790
|
+
cnamePaths,
|
|
791
|
+
cloudflare,
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function isAnythingToUndo(plan) {
|
|
795
|
+
return (plan.pagesEnabled ||
|
|
796
|
+
plan.workflowPath !== null ||
|
|
797
|
+
plan.cnamePaths.length > 0 ||
|
|
798
|
+
plan.cloudflare.records.length > 0);
|
|
799
|
+
}
|
|
800
|
+
function printUndoPlan(plan) {
|
|
801
|
+
console.log(chalk.bold("\n Will undo:\n"));
|
|
802
|
+
if (plan.pagesEnabled) {
|
|
803
|
+
const suffix = plan.cname ? ` (cname: ${plan.cname})` : "";
|
|
804
|
+
console.log(chalk.yellow(` • Disable GitHub Pages${suffix}`));
|
|
805
|
+
}
|
|
806
|
+
for (const rec of plan.cloudflare.records) {
|
|
807
|
+
console.log(chalk.yellow(` • Delete Cloudflare ${rec.type} ${rec.name} → ${rec.content}`));
|
|
808
|
+
}
|
|
809
|
+
if (plan.workflowPath) {
|
|
810
|
+
console.log(chalk.yellow(` • Delete ${relPath(plan.workflowPath)}`));
|
|
811
|
+
}
|
|
812
|
+
for (const p of plan.cnamePaths) {
|
|
813
|
+
console.log(chalk.yellow(` • Delete ${relPath(p)}`));
|
|
814
|
+
}
|
|
815
|
+
if (plan.cname && !plan.cloudflare.available) {
|
|
816
|
+
console.log(chalk.dim(`\n (Cloudflare records for ${plan.cname} can't be auto-deleted — no token / zone not in this account.\n Remove them manually at your DNS provider.)`));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
async function executeUndo(repo, plan) {
|
|
820
|
+
if (plan.pagesEnabled) {
|
|
821
|
+
const res = await exec("gh", ["api", "-X", "DELETE", `repos/${repo.fullName}/pages`], {
|
|
822
|
+
silent: true,
|
|
823
|
+
spinner: "Disabling GitHub Pages...",
|
|
824
|
+
});
|
|
825
|
+
if (res.exitCode !== 0) {
|
|
826
|
+
console.log(chalk.yellow(` ⚠ Couldn't disable Pages: ${res.stderr.trim() || res.stdout.trim()}`));
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
if (plan.cloudflare.records.length > 0 && plan.cloudflare.zoneId) {
|
|
830
|
+
const dns = await getDnsConfig();
|
|
831
|
+
if (dns?.apiToken) {
|
|
832
|
+
const api = new CloudflareApi({ token: dns.apiToken });
|
|
833
|
+
for (const rec of plan.cloudflare.records) {
|
|
834
|
+
const result = await api.deleteRecord(plan.cloudflare.zoneId, rec.id);
|
|
835
|
+
const tag = result === "deleted" ? chalk.green("✓") : chalk.dim("—");
|
|
836
|
+
console.log(` ${tag} Cloudflare ${rec.type} ${rec.name} → ${rec.content} (${result})`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (plan.workflowPath) {
|
|
841
|
+
try {
|
|
842
|
+
unlinkSync(plan.workflowPath);
|
|
843
|
+
console.log(chalk.green(` ✓ Removed ${relPath(plan.workflowPath)}`));
|
|
844
|
+
}
|
|
845
|
+
catch (err) {
|
|
846
|
+
console.log(chalk.yellow(` ⚠ Couldn't remove ${relPath(plan.workflowPath)}: ${err.message}`));
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
for (const p of plan.cnamePaths) {
|
|
850
|
+
try {
|
|
851
|
+
unlinkSync(p);
|
|
852
|
+
console.log(chalk.green(` ✓ Removed ${relPath(p)}`));
|
|
853
|
+
}
|
|
854
|
+
catch (err) {
|
|
855
|
+
console.log(chalk.yellow(` ⚠ Couldn't remove ${relPath(p)}: ${err.message}`));
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Look for `CNAME` files in the places `writeCnameFile` could have put
|
|
861
|
+
* one, in the current working dir and each candidate scan dir. Only
|
|
862
|
+
* returns files whose content matches `expected` (trimmed, case-insensitive)
|
|
863
|
+
* so we never delete an unrelated CNAME file.
|
|
864
|
+
*/
|
|
865
|
+
function findCnameFiles(cwd, expected) {
|
|
866
|
+
const target = expected.trim().toLowerCase();
|
|
867
|
+
const out = [];
|
|
868
|
+
const seen = new Set();
|
|
869
|
+
const bases = ["", ...SCAN_DIRS.filter((d) => d !== "")];
|
|
870
|
+
for (const base of bases) {
|
|
871
|
+
const baseAbs = base ? join(cwd, base) : cwd;
|
|
872
|
+
if (base && !existsSync(baseAbs))
|
|
873
|
+
continue;
|
|
874
|
+
for (const sub of ["", "public", "static"]) {
|
|
875
|
+
const subAbs = sub ? join(baseAbs, sub) : baseAbs;
|
|
876
|
+
const candidate = join(subAbs, "CNAME");
|
|
877
|
+
if (seen.has(candidate))
|
|
878
|
+
continue;
|
|
879
|
+
seen.add(candidate);
|
|
880
|
+
if (!existsSync(candidate))
|
|
881
|
+
continue;
|
|
882
|
+
try {
|
|
883
|
+
const content = readFileSync(candidate, "utf8").trim().toLowerCase();
|
|
884
|
+
if (content === target)
|
|
885
|
+
out.push(candidate);
|
|
886
|
+
}
|
|
887
|
+
catch {
|
|
888
|
+
// unreadable — skip
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return out;
|
|
893
|
+
}
|
|
894
|
+
function relPath(p) {
|
|
895
|
+
const cwd = process.cwd();
|
|
896
|
+
return p.startsWith(cwd) ? p.slice(cwd.length + 1) : p;
|
|
897
|
+
}
|
|
557
898
|
//# sourceMappingURL=pages.js.map
|