@heychunky/core 0.8.2 → 0.9.0

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.
Files changed (47) hide show
  1. package/dist/admin/chunks.d.ts +53 -0
  2. package/dist/admin/chunks.d.ts.map +1 -1
  3. package/dist/admin/chunks.js +132 -20
  4. package/dist/admin/chunks.js.map +1 -1
  5. package/dist/admin/decommission.d.ts +40 -0
  6. package/dist/admin/decommission.d.ts.map +1 -0
  7. package/dist/admin/decommission.js +134 -0
  8. package/dist/admin/decommission.js.map +1 -0
  9. package/dist/admin/entrypoints.d.ts +16 -0
  10. package/dist/admin/entrypoints.d.ts.map +1 -0
  11. package/dist/admin/entrypoints.js +41 -0
  12. package/dist/admin/entrypoints.js.map +1 -0
  13. package/dist/admin/index.d.ts +2 -0
  14. package/dist/admin/index.d.ts.map +1 -1
  15. package/dist/admin/index.js +2 -0
  16. package/dist/admin/index.js.map +1 -1
  17. package/dist/admin/provision.d.ts.map +1 -1
  18. package/dist/admin/provision.js +116 -4
  19. package/dist/admin/provision.js.map +1 -1
  20. package/dist/admin/services/bunny.d.ts +3 -0
  21. package/dist/admin/services/bunny.d.ts.map +1 -1
  22. package/dist/admin/services/bunny.js +12 -0
  23. package/dist/admin/services/bunny.js.map +1 -1
  24. package/dist/admin/services/cloudflare.d.ts +11 -0
  25. package/dist/admin/services/cloudflare.d.ts.map +1 -1
  26. package/dist/admin/services/cloudflare.js +19 -0
  27. package/dist/admin/services/cloudflare.js.map +1 -1
  28. package/dist/admin/services/github.d.ts +3 -0
  29. package/dist/admin/services/github.d.ts.map +1 -1
  30. package/dist/admin/services/github.js +29 -1
  31. package/dist/admin/services/github.js.map +1 -1
  32. package/dist/admin/services/neon.d.ts +3 -0
  33. package/dist/admin/services/neon.d.ts.map +1 -1
  34. package/dist/admin/services/neon.js +16 -0
  35. package/dist/admin/services/neon.js.map +1 -1
  36. package/dist/admin/services/vercel.d.ts +19 -9
  37. package/dist/admin/services/vercel.d.ts.map +1 -1
  38. package/dist/admin/services/vercel.js +40 -7
  39. package/dist/admin/services/vercel.js.map +1 -1
  40. package/dist/config/environments.d.ts +41 -1
  41. package/dist/config/environments.d.ts.map +1 -1
  42. package/dist/config/environments.js +50 -1
  43. package/dist/config/environments.js.map +1 -1
  44. package/dist/registry.d.ts.map +1 -1
  45. package/dist/registry.js +8 -0
  46. package/dist/registry.js.map +1 -1
  47. package/package.json +4 -1
@@ -25,6 +25,25 @@ export interface ChunkManifest {
25
25
  tags: string[];
26
26
  /** npm packages the chunk needs at runtime. Ours are files; these are not. */
27
27
  dependencies: string[];
28
+ /**
29
+ * Other chunks this one will not work without.
30
+ *
31
+ * A real dependency graph — sitenav does not render without coreui's button
32
+ * — and one that is kept shallow on purpose. A deep chunk graph reproduces
33
+ * the dependency hell the copy-and-own model exists to avoid, so a chunk
34
+ * that needs four others is usually one chunk pretending to be five.
35
+ */
36
+ requires?: {
37
+ chunks?: string[];
38
+ };
39
+ /**
40
+ * Stylesheets the chunk ships, in the order they should be imported.
41
+ *
42
+ * Declared rather than inferred from the file list: a chunk's CSS has to be
43
+ * imported by something or it lands in the repository and styles nothing,
44
+ * which is exactly what happened to the first chunk on the shelf.
45
+ */
46
+ styles?: string[];
28
47
  /**
29
48
  * SQL the chunk needs run against the app's own database, before its code
30
49
  * is deployed. Written to be safe to run twice — `create table if not
@@ -51,6 +70,13 @@ export interface ChunkFile {
51
70
  /** Path in the app, relative to its root. */
52
71
  path: string;
53
72
  content: string;
73
+ /**
74
+ * Set for files that are not text.
75
+ *
76
+ * A chunk that renders a logo has to ship the logo, and a PNG decoded as
77
+ * UTF-8 and written back is noise. Base64 passes through both ends untouched.
78
+ */
79
+ encoding?: "base64";
54
80
  }
55
81
  export interface AddResult {
56
82
  chunk: string;
@@ -84,6 +110,18 @@ export declare function readChunk(name: string, ctx: RunContext): Promise<{
84
110
  manifest: ChunkManifest;
85
111
  files: ChunkFile[];
86
112
  }>;
113
+ /**
114
+ * A chunk and everything it will not work without, dependencies first.
115
+ *
116
+ * Depth-first so a dependency is always written before the chunk that imports
117
+ * it, and cycle-aware because a graph that can be declared can be declared
118
+ * wrong. Returned as one flat list: the caller writes them in a single commit,
119
+ * so an app never exists in a state where half a chunk's imports resolve.
120
+ */
121
+ export declare function resolveChunk(name: string, ctx: RunContext, seen?: string[]): Promise<{
122
+ manifest: ChunkManifest;
123
+ files: ChunkFile[];
124
+ }[]>;
87
125
  /** The config file, written from the chunk's own declared defaults. */
88
126
  export declare function configFor(manifest: ChunkManifest): string | undefined;
89
127
  export interface AddWatcher {
@@ -97,6 +135,21 @@ export interface AddWatcher {
97
135
  * already there with the content it would be given, nothing is written and the
98
136
  * run says so. That is what makes it safe to ask twice.
99
137
  */
138
+ /**
139
+ * Register a chunk's stylesheets with the app.
140
+ *
141
+ * A stylesheet that lands in the repository and is imported by nothing styles
142
+ * nothing — the first chunk on the shelf shipped four components and none of
143
+ * their CSS, and no part of the pipeline noticed. `index.css` is where an app
144
+ * collects its imports, and it holds only imports, which is what the CSS rule
145
+ * that `@import` must precede every other rule requires.
146
+ *
147
+ * Returns the file to write, or undefined when every import is already there.
148
+ */
149
+ export declare function registerStyles(index: {
150
+ path: string;
151
+ content: string;
152
+ }, styles: string[], uiDir: string): ChunkFile | undefined;
100
153
  export declare function addChunk(opts: {
101
154
  chunk: string;
102
155
  repo: string;
@@ -1 +1 @@
1
- {"version":3,"file":"chunks.d.ts","sourceRoot":"","sources":["../../src/admin/chunks.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAGpD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,wBAAwB,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8EAA8E;IAC9E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf;;;;;;OAMG;IACH,GAAG,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,qDAAqD;IACrD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,WAAY,SAAQ,KAAK;gBACxB,IAAI,EAAE,MAAM;CAIzB;AAQD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,UAAU,GACd,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC,CAoB1D;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAerE;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE;IACJ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,sDAAsD;IACtD,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAClC,EACD,GAAG,EAAE,UAAU,EACf,KAAK,CAAC,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC,CA4EpB"}
1
+ {"version":3,"file":"chunks.d.ts","sourceRoot":"","sources":["../../src/admin/chunks.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@
19
19
  import { github } from "./services/github.js";
20
20
  import { vercel } from "./services/vercel.js";
21
21
  import { KEY_FOR } from "./run.js";
22
+ import { entryPoints } from "./entrypoints.js";
22
23
  import { DEFAULT_BRANCH } from "../config/environments.js";
23
24
  /**
24
25
  * Where the chunks live. Folders in one repository, one per chunk.
@@ -29,6 +30,14 @@ import { DEFAULT_BRANCH } from "../config/environments.js";
29
30
  * cannot happen here.
30
31
  */
31
32
  export const CHUNKS_REPO = "heychunkydev/chunks";
33
+ /**
34
+ * What must not be decoded on the way through.
35
+ *
36
+ * By extension rather than by sniffing: a chunk's file list is known before
37
+ * anything is fetched, and guessing from content would mean downloading it
38
+ * wrongly first to find out.
39
+ */
40
+ const BINARY = /\.(png|jpe?g|gif|webp|avif|ico|svgz|woff2?|ttf|otf|eot|mp4|webm|pdf|zip)$/i;
32
41
  export class NoSuchChunk extends Error {
33
42
  constructor(name) {
34
43
  super(`No chunk called "${name}"`);
@@ -61,13 +70,39 @@ export async function readChunk(name, ctx) {
61
70
  const manifest = JSON.parse(raw);
62
71
  const files = [];
63
72
  for (const path of await gh.listFiles(CHUNKS_REPO, `${root}/files`)) {
73
+ const binary = BINARY.test(path);
64
74
  files.push({
65
75
  path: path.slice(`${root}/files/`.length),
66
- content: await gh.readFile(CHUNKS_REPO, path),
76
+ content: binary ? await gh.readBinaryFile(CHUNKS_REPO, path) : await gh.readFile(CHUNKS_REPO, path),
77
+ ...(binary ? { encoding: "base64" } : {}),
67
78
  });
68
79
  }
69
80
  return { manifest, files };
70
81
  }
82
+ /**
83
+ * A chunk and everything it will not work without, dependencies first.
84
+ *
85
+ * Depth-first so a dependency is always written before the chunk that imports
86
+ * it, and cycle-aware because a graph that can be declared can be declared
87
+ * wrong. Returned as one flat list: the caller writes them in a single commit,
88
+ * so an app never exists in a state where half a chunk's imports resolve.
89
+ */
90
+ export async function resolveChunk(name, ctx, seen = []) {
91
+ if (seen.includes(name)) {
92
+ throw new Error(`Chunk dependencies form a cycle: ${[...seen, name].join(" → ")}`);
93
+ }
94
+ const read = await readChunk(name, ctx);
95
+ const out = [];
96
+ for (const required of read.manifest.requires?.chunks ?? []) {
97
+ for (const dep of await resolveChunk(required, ctx, [...seen, name])) {
98
+ // A chunk two others need is read twice and written once.
99
+ if (!out.some((c) => c.manifest.name === dep.manifest.name))
100
+ out.push(dep);
101
+ }
102
+ }
103
+ out.push(read);
104
+ return out;
105
+ }
71
106
  /** The config file, written from the chunk's own declared defaults. */
72
107
  export function configFor(manifest) {
73
108
  if (!manifest.config || !manifest.options.length)
@@ -91,24 +126,97 @@ ${lines.join("\n")}
91
126
  * already there with the content it would be given, nothing is written and the
92
127
  * run says so. That is what makes it safe to ask twice.
93
128
  */
129
+ /**
130
+ * Register a chunk's stylesheets with the app.
131
+ *
132
+ * A stylesheet that lands in the repository and is imported by nothing styles
133
+ * nothing — the first chunk on the shelf shipped four components and none of
134
+ * their CSS, and no part of the pipeline noticed. `index.css` is where an app
135
+ * collects its imports, and it holds only imports, which is what the CSS rule
136
+ * that `@import` must precede every other rule requires.
137
+ *
138
+ * Returns the file to write, or undefined when every import is already there.
139
+ */
140
+ export function registerStyles(index, styles, uiDir) {
141
+ let content = index.content;
142
+ let added = 0;
143
+ for (const style of styles) {
144
+ // Relative to index.css, which sits at the root of the ui directory.
145
+ const rel = `./${style.startsWith(`${uiDir}/`) ? style.slice(uiDir.length + 1) : style}`;
146
+ const line = `@import "${rel}";`;
147
+ if (content.includes(line))
148
+ continue;
149
+ const imports = [...content.matchAll(/^@import .*;$/gm)];
150
+ const last = imports.at(-1);
151
+ if (last?.index === undefined) {
152
+ content = `${line}\n${content}`;
153
+ }
154
+ else {
155
+ const at = last.index + last[0].length;
156
+ content = `${content.slice(0, at)}\n${line}${content.slice(at)}`;
157
+ }
158
+ added += 1;
159
+ }
160
+ return added ? { path: index.path, content } : undefined;
161
+ }
162
+ /** Where this app keeps its stylesheets, as its own manifest declares. */
163
+ async function uiDirOf(repo, gh) {
164
+ try {
165
+ const raw = await gh.readFile(repo, "heychunky.json");
166
+ const ui = JSON.parse(raw).ui;
167
+ if (ui?.dir)
168
+ return ui.dir;
169
+ }
170
+ catch {
171
+ // An app without a manifest is one provisioned before the format had one.
172
+ }
173
+ return ".heychunky/ui";
174
+ }
94
175
  export async function addChunk(opts, ctx, watch) {
95
176
  const { gh, vc } = await clients(ctx);
96
177
  watch?.start?.("read chunk");
97
- const { manifest, files } = await readChunk(opts.chunk, ctx);
98
- const all = [...files];
99
- // Generated only when the chunk does not ship one of its own. A chunk that
100
- // hand-writes its config knows something the generator does not, and adding
101
- // a second file at the same path put it in the list twice.
102
- const shipped = manifest.config && files.some((f) => f.path === manifest.config);
103
- const config = shipped ? undefined : configFor(manifest);
104
- if (config && manifest.config) {
105
- // And only if it is not already in the app: this file is the developer's
106
- // once written, and rewriting it would silently undo their settings.
107
- const existing = await gh.readFile(opts.repo, manifest.config).catch(() => undefined);
108
- if (existing === undefined)
109
- all.push({ path: manifest.config, content: config });
178
+ // The chunk and everything it will not work without, dependencies first, so
179
+ // an app never exists in a state where half of an import resolves.
180
+ const resolved = await resolveChunk(opts.chunk, ctx);
181
+ const manifest = resolved.at(-1).manifest;
182
+ const all = [];
183
+ for (const { manifest: m, files } of resolved) {
184
+ all.push(...files);
185
+ // Generated only when the chunk does not ship one of its own. A chunk that
186
+ // hand-writes its config knows something the generator does not, and adding
187
+ // a second file at the same path put it in the list twice.
188
+ const shipped = m.config && files.some((f) => f.path === m.config);
189
+ const config = shipped ? undefined : configFor(m);
190
+ if (config && m.config) {
191
+ // And only if it is not already in the app: this file is the developer's
192
+ // once written, and rewriting it would silently undo their settings.
193
+ const existing = await gh.readFile(opts.repo, m.config).catch(() => undefined);
194
+ if (existing === undefined)
195
+ all.push({ path: m.config, content: config });
196
+ }
197
+ }
198
+ // Stylesheets have to be imported by something. `index.css` is where an app
199
+ // collects them, and its location is the app's decision rather than ours.
200
+ const styles = resolved.flatMap((c) => c.manifest.styles ?? []);
201
+ if (styles.length) {
202
+ const uiDir = await uiDirOf(opts.repo, gh);
203
+ const path = `${uiDir}/index.css`;
204
+ const content = await gh.readFile(opts.repo, path).catch(() => undefined);
205
+ if (content === undefined) {
206
+ all.push({ path, content: styles.map((s) => `@import "./${s.slice(uiDir.length + 1)}";`).join("\n") + "\n" });
207
+ }
208
+ else {
209
+ const updated = registerStyles({ path, content }, styles, uiDir);
210
+ if (updated)
211
+ all.push(updated);
212
+ }
110
213
  }
111
- watch?.done?.("read chunk", `${manifest.name} ${manifest.version} · ${all.length} files`);
214
+ // `src/app/` is derived from the manifest, so anything the manifest gained
215
+ // and the target has not is regenerated in the same commit as the chunk.
216
+ // A route that exists in one and not the other is a page nobody can visit.
217
+ all.push(...(await entryPoints(opts.repo, gh)));
218
+ const named = resolved.map((c) => c.manifest.name).join(" → ");
219
+ watch?.done?.("read chunk", `${named} · ${all.length} files`);
112
220
  watch?.start?.("check app");
113
221
  const unchanged = [];
114
222
  for (const file of all) {
@@ -124,9 +232,12 @@ export async function addChunk(opts, ctx, watch) {
124
232
  // Before the code that needs them, so a deployment never lands on a schema
125
233
  // that has not caught up. Failing here stops the run with nothing written.
126
234
  let migrated = 0;
127
- if (manifest.sql?.length) {
235
+ // In dependency order: a chunk's tables may reference a table its dependency
236
+ // creates, and resolveChunk already put them in that order.
237
+ const statements = resolved.flatMap((c) => c.manifest.sql ?? []);
238
+ if (statements.length) {
128
239
  watch?.start?.("database");
129
- for (const statement of manifest.sql) {
240
+ for (const statement of statements) {
130
241
  await opts.migrate(statement);
131
242
  migrated += 1;
132
243
  }
@@ -142,11 +253,12 @@ export async function addChunk(opts, ctx, watch) {
142
253
  // Named, not filled. A chunk cannot know somebody's Resend key; what it can
143
254
  // do is say which are missing rather than let the app boot broken.
144
255
  const missing = [];
145
- if (manifest.env?.length) {
256
+ const wanted = resolved.flatMap((c) => c.manifest.env ?? []);
257
+ if (wanted.length) {
146
258
  watch?.start?.("settings");
147
259
  const have = new Set(await opts.envKeys());
148
- for (const e of manifest.env)
149
- if (!have.has(e.key))
260
+ for (const e of wanted)
261
+ if (!have.has(e.key) && !missing.some((m) => m.key === e.key))
150
262
  missing.push(e);
151
263
  watch?.done?.("settings", missing.length
152
264
  ? `${missing.length} still needed: ${missing.map((m) => m.key).join(", ")}`
@@ -1 +1 @@
1
- {"version":3,"file":"chunks.js","sourceRoot":"","sources":["../../src/admin/chunks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chunks.js","sourceRoot":"","sources":["../../src/admin/chunks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type RunContext } from "./run.ts";
2
+ import type { StepResult } from "./provision.ts";
3
+ export interface Teardown {
4
+ /** The app's name, as provisioning knew it. */
5
+ name: string;
6
+ /** Its organisation. Defaults to the factory's, as provisioning does. */
7
+ org?: string;
8
+ /** The address it was given. Defaults to the apps-zone subdomain. */
9
+ domain?: string;
10
+ /**
11
+ * Remove the repository too.
12
+ *
13
+ * Separate from the rest because it is the only irreversible loss that is
14
+ * not a cost: the infrastructure can be rebuilt from the code, and the code
15
+ * cannot be rebuilt from anything.
16
+ */
17
+ repo?: boolean;
18
+ }
19
+ export interface Removal {
20
+ app: string;
21
+ /** True when nothing was removed, because nothing was confirmed. */
22
+ planned: boolean;
23
+ steps: StepResult[];
24
+ /** Every step reached a good state. */
25
+ ok: boolean;
26
+ }
27
+ interface Watcher {
28
+ start?(step: string): void;
29
+ done?(step: string, detail: string): void;
30
+ }
31
+ /**
32
+ * What has to go, and how to find it.
33
+ *
34
+ * Each step looks the resource up before touching it, so an app that was never
35
+ * fully provisioned — or was taken down halfway yesterday — reports "gone"
36
+ * rather than failing on something that was never there.
37
+ */
38
+ export declare function decommission(spec: Teardown, ctx: RunContext, watch?: Watcher): Promise<Removal>;
39
+ export {};
40
+ //# sourceMappingURL=decommission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decommission.d.ts","sourceRoot":"","sources":["../../src/admin/decommission.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,gBAAgB,CAAC;AAE5D,MAAM,WAAW,QAAQ;IACvB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,oEAAoE;IACpE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,uCAAuC;IACvC,EAAE,EAAE,OAAO,CAAC;CACb;AAED,UAAU,OAAO;IACf,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,UAAU,EACf,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,OAAO,CAAC,CAgHlB"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Taking an app down.
3
+ *
4
+ * The counterpart to `provision`, and the reason it had to exist: until this
5
+ * did, an app could be created and never removed. Every app ever made kept a
6
+ * Neon project, a Vercel project and a storage zone billing for as long as the
7
+ * account lived, and the only things that could be deleted — a repository and
8
+ * a DNS record — were the two that cost nothing.
9
+ *
10
+ * Order is deliberate and runs the opposite way to creation:
11
+ *
12
+ * 1. the address, so nothing is being served while the rest goes
13
+ * 2. the hosting project
14
+ * 3. the database
15
+ * 4. the storage
16
+ * 5. the repository, last, because the code is the one thing somebody might
17
+ * still want and the one thing nobody can rebuild
18
+ *
19
+ * A failure stops the run where it stands rather than pressing on, so a
20
+ * half-removed app is reported as exactly that and can be asked again.
21
+ */
22
+ import { github } from "./services/github.js";
23
+ import { vercel } from "./services/vercel.js";
24
+ import { neon } from "./services/neon.js";
25
+ import { cloudflare } from "./services/cloudflare.js";
26
+ import { bunny } from "./services/bunny.js";
27
+ import { KEY_FOR } from "./run.js";
28
+ import { DEFAULT_ORG, defaultDomain, stagingDomain } from "../config/environments.js";
29
+ /**
30
+ * What has to go, and how to find it.
31
+ *
32
+ * Each step looks the resource up before touching it, so an app that was never
33
+ * fully provisioned — or was taken down halfway yesterday — reports "gone"
34
+ * rather than failing on something that was never there.
35
+ */
36
+ export async function decommission(spec, ctx, watch) {
37
+ const key = (service) => ctx.secrets.get(ctx.reference(KEY_FOR[service]));
38
+ const [g, v, n, c, b] = await Promise.all([
39
+ key("github"), key("vercel"), key("neon"), key("cloudflare"), key("bunny"),
40
+ ]);
41
+ const gh = github(g), vc = vercel(v), nn = neon(n), cf = cloudflare(c), bn = bunny(b);
42
+ const domain = spec.domain ?? defaultDomain(spec.name);
43
+ /**
44
+ * Every name this factory pointed at the app.
45
+ *
46
+ * Staging has an address of its own, and a record left behind in Cloudflare
47
+ * after the project it pointed at is gone is precisely the orphan this run
48
+ * exists to prevent — cheaper than a database, and just as much a lie about
49
+ * what still exists.
50
+ */
51
+ const domains = [domain, stagingDomain(domain)];
52
+ const repo = `${spec.org ?? DEFAULT_ORG}/${spec.name}`;
53
+ const steps = [];
54
+ let ok = true;
55
+ const run = async (step, find, remove) => {
56
+ if (!ok)
57
+ return;
58
+ watch?.start?.(step);
59
+ try {
60
+ const found = await find();
61
+ if (found === undefined) {
62
+ settle(step, "exists", "gone already");
63
+ return;
64
+ }
65
+ if (!ctx.confirmed) {
66
+ settle(step, "would-create", `would remove ${found}`);
67
+ return;
68
+ }
69
+ settle(step, "created", await remove());
70
+ }
71
+ catch (error) {
72
+ ok = false;
73
+ settle(step, "failed", error instanceof Error ? error.message : String(error));
74
+ }
75
+ };
76
+ const settle = (step, state, detail) => {
77
+ steps.push({ step, state, detail });
78
+ watch?.done?.(step, detail);
79
+ };
80
+ // The address first: whatever else fails, nothing is still being served.
81
+ const pointedHere = async () => {
82
+ const here = [];
83
+ for (const name of domains) {
84
+ const zone = await cf.zoneFor(name);
85
+ if (!zone)
86
+ continue;
87
+ if ((await cf.dnsRecords(zone.name)).some((r) => r.name === name))
88
+ here.push(name);
89
+ }
90
+ return here;
91
+ };
92
+ await run("dns record", async () => {
93
+ const here = await pointedHere();
94
+ return here.length ? here.join(", ") : undefined;
95
+ }, async () => {
96
+ let gone = 0;
97
+ const removed = [];
98
+ for (const name of await pointedHere()) {
99
+ const zone = (await cf.zoneFor(name));
100
+ gone += await cf.deleteDnsRecords(zone.name, name, { confirmed: true });
101
+ removed.push(name);
102
+ }
103
+ return `${gone} record${gone === 1 ? "" : "s"} for ${removed.join(", ")}`;
104
+ });
105
+ await run("vercel project", async () => (await vc.findProject(spec.name))?.name, async () => {
106
+ const project = (await vc.findProject(spec.name));
107
+ await vc.deleteProject(project.id, await vc.teamId(), { confirmed: true });
108
+ return project.name;
109
+ });
110
+ await run("neon project", async () => (await nn.projects()).find((p) => p.name === spec.name)?.name, async () => {
111
+ const project = (await nn.projects()).find((p) => p.name === spec.name);
112
+ await nn.deleteProject(project.id, { confirmed: true });
113
+ return `${project.name} · every branch with it`;
114
+ });
115
+ await run("storage zones", async () => {
116
+ const zones = await bn.zonesForApp(spec.name);
117
+ return zones.length ? zones.map((z) => z.Name).join(", ") : undefined;
118
+ }, async () => {
119
+ const zones = await bn.zonesForApp(spec.name);
120
+ for (const zone of zones)
121
+ await bn.deleteStorageZone(zone.Id, { confirmed: true });
122
+ return zones.map((z) => z.Name).join(", ");
123
+ });
124
+ // Last, and only when asked. Everything above can be rebuilt from what is
125
+ // in here; nothing can rebuild what is in here.
126
+ if (spec.repo) {
127
+ await run("github repo", async () => ((await gh.findRepo(repo)) ? repo : undefined), async () => {
128
+ await gh.deleteRepo(repo, { confirmed: true });
129
+ return repo;
130
+ });
131
+ }
132
+ return { app: spec.name, planned: !ctx.confirmed, steps, ok };
133
+ }
134
+ //# sourceMappingURL=decommission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decommission.js","sourceRoot":"","sources":["../../src/admin/decommission.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ChunkFile } from "./chunks.ts";
2
+ /** The app's own manifest, as its repository holds it. */
3
+ export declare const MANIFEST = "heychunky.json";
4
+ interface Reader {
5
+ readFile(repo: string, path: string): Promise<string>;
6
+ }
7
+ /**
8
+ * What the framework target should contain, minus what it already does.
9
+ *
10
+ * Returns only files whose content differs, so a run that changes nothing
11
+ * commits nothing — the same rule the chunk installer follows, and the reason
12
+ * asking twice is safe.
13
+ */
14
+ export declare function entryPoints(repo: string, gh: Reader): Promise<ChunkFile[]>;
15
+ export {};
16
+ //# sourceMappingURL=entrypoints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/admin/entrypoints.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,0DAA0D;AAC1D,eAAO,MAAM,QAAQ,mBAAmB,CAAC;AAEzC,UAAU,MAAM;IACd,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAgBhF"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Keeping an app's generated entry points in step with its manifest.
3
+ *
4
+ * `.heychunky/` is the app and `src/app/` is the framework's view of it. The
5
+ * second is derived from the first — two-line files that re-export the real
6
+ * implementation — which is what lets the same app be generated for another
7
+ * target later, and what stops anybody hand-maintaining a directory of shims.
8
+ *
9
+ * Derived, and therefore worth regenerating: a route added to the manifest and
10
+ * not to `src/app/` is a page that does not exist, and nothing would say so
11
+ * until somebody visited it.
12
+ */
13
+ import { generate } from "@heychunky/framework";
14
+ /** The app's own manifest, as its repository holds it. */
15
+ export const MANIFEST = "heychunky.json";
16
+ /**
17
+ * What the framework target should contain, minus what it already does.
18
+ *
19
+ * Returns only files whose content differs, so a run that changes nothing
20
+ * commits nothing — the same rule the chunk installer follows, and the reason
21
+ * asking twice is safe.
22
+ */
23
+ export async function entryPoints(repo, gh) {
24
+ let manifest;
25
+ try {
26
+ manifest = JSON.parse(await gh.readFile(repo, MANIFEST));
27
+ }
28
+ catch {
29
+ // An app with no manifest predates the format. Nothing to generate from,
30
+ // and guessing a route table would be worse than leaving it alone.
31
+ return [];
32
+ }
33
+ const out = [];
34
+ for (const file of generate(manifest)) {
35
+ const there = await gh.readFile(repo, file.path).catch(() => undefined);
36
+ if (there !== file.contents)
37
+ out.push({ path: file.path, content: file.contents });
38
+ }
39
+ return out;
40
+ }
41
+ //# sourceMappingURL=entrypoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../../src/admin/entrypoints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,QAAQ,EAAiB,MAAM,sBAAsB,CAAC;AAG/D,0DAA0D;AAC1D,MAAM,CAAC,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AAMzC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,EAAU;IACxD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAa,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,mEAAmE;QACnE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -11,6 +11,8 @@ export * from "./apps.ts";
11
11
  export * from "./users.ts";
12
12
  export * from "./run.ts";
13
13
  export * from "./provision.ts";
14
+ export * from "./decommission.ts";
15
+ export * from "./entrypoints.ts";
14
16
  export * from "./chunks.ts";
15
17
  export * from "./services/github.ts";
16
18
  export * from "./services/vercel.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAG5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAG5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
@@ -11,6 +11,8 @@ export * from "./apps.js";
11
11
  export * from "./users.js";
12
12
  export * from "./run.js";
13
13
  export * from "./provision.js";
14
+ export * from "./decommission.js";
15
+ export * from "./entrypoints.js";
14
16
  export * from "./chunks.js";
15
17
  // One file per service, matching the registry.
16
18
  export * from "./services/github.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAE5B,+CAA+C;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAE5B,+CAA+C;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}