@heychunky/core 0.8.2 → 0.10.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 +59 -0
  2. package/dist/admin/chunks.d.ts.map +1 -1
  3. package/dist/admin/chunks.js +171 -27
  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 +14 -0
  29. package/dist/admin/services/github.d.ts.map +1 -1
  30. package/dist/admin/services/github.js +47 -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;
@@ -66,6 +92,12 @@ export interface AddResult {
66
92
  files: string[];
67
93
  /** The commit, or undefined when nothing needed doing. */
68
94
  commit?: string;
95
+ /** The branch the chunk was written to. Never `main`. */
96
+ branch?: string;
97
+ /** Where it can be looked at before it goes anywhere. */
98
+ preview?: string;
99
+ /** The pull request it is waiting in. */
100
+ pullRequest?: string;
69
101
  /** True when the chunk was already there and nothing changed. */
70
102
  already: boolean;
71
103
  }
@@ -84,6 +116,18 @@ export declare function readChunk(name: string, ctx: RunContext): Promise<{
84
116
  manifest: ChunkManifest;
85
117
  files: ChunkFile[];
86
118
  }>;
119
+ /**
120
+ * A chunk and everything it will not work without, dependencies first.
121
+ *
122
+ * Depth-first so a dependency is always written before the chunk that imports
123
+ * it, and cycle-aware because a graph that can be declared can be declared
124
+ * wrong. Returned as one flat list: the caller writes them in a single commit,
125
+ * so an app never exists in a state where half a chunk's imports resolve.
126
+ */
127
+ export declare function resolveChunk(name: string, ctx: RunContext, seen?: string[]): Promise<{
128
+ manifest: ChunkManifest;
129
+ files: ChunkFile[];
130
+ }[]>;
87
131
  /** The config file, written from the chunk's own declared defaults. */
88
132
  export declare function configFor(manifest: ChunkManifest): string | undefined;
89
133
  export interface AddWatcher {
@@ -97,6 +141,21 @@ export interface AddWatcher {
97
141
  * already there with the content it would be given, nothing is written and the
98
142
  * run says so. That is what makes it safe to ask twice.
99
143
  */
144
+ /**
145
+ * Register a chunk's stylesheets with the app.
146
+ *
147
+ * A stylesheet that lands in the repository and is imported by nothing styles
148
+ * nothing — the first chunk on the shelf shipped four components and none of
149
+ * their CSS, and no part of the pipeline noticed. `index.css` is where an app
150
+ * collects its imports, and it holds only imports, which is what the CSS rule
151
+ * that `@import` must precede every other rule requires.
152
+ *
153
+ * Returns the file to write, or undefined when every import is already there.
154
+ */
155
+ export declare function registerStyles(index: {
156
+ path: string;
157
+ content: string;
158
+ }, styles: string[], uiDir: string): ChunkFile | undefined;
100
159
  export declare function addChunk(opts: {
101
160
  chunk: string;
102
161
  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 });
110
- }
111
- watch?.done?.("read chunk", `${manifest.name} ${manifest.version} · ${all.length} files`);
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
+ }
213
+ }
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,17 +232,34 @@ 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
  }
133
244
  watch?.done?.("database", `${migrated} statement${migrated === 1 ? "" : "s"}`);
134
245
  }
246
+ // A branch of its own, never `main`. Every operator adding a change works
247
+ // this way — a developer, chunky, an agent chunky spun off — so that nothing
248
+ // reaches production without passing the two gates a person holds. Reused
249
+ // when it is already there, so a run that died after pushing can be repeated.
250
+ const branch = `chunk/${opts.chunk}`;
251
+ watch?.start?.("branch");
252
+ const existing = await gh.branches(opts.repo);
253
+ if (!existing.includes(branch)) {
254
+ await gh.createBranch(opts.repo, branch, DEFAULT_BRANCH);
255
+ watch?.done?.("branch", `${branch} · from ${DEFAULT_BRANCH}`);
256
+ }
257
+ else {
258
+ watch?.done?.("branch", `${branch} · already there`);
259
+ }
135
260
  watch?.start?.("write files");
136
261
  const commit = await gh.commitFiles(opts.repo, {
137
- branch: DEFAULT_BRANCH,
262
+ branch,
138
263
  message: `Add the ${manifest.name} chunk\n\n${manifest.summary}\n\nWritten by chunky, on behalf of the app's owner. The files are yours now —\nedit them freely, nothing here updates them later.`,
139
264
  files: all,
140
265
  });
@@ -142,27 +267,46 @@ export async function addChunk(opts, ctx, watch) {
142
267
  // Named, not filled. A chunk cannot know somebody's Resend key; what it can
143
268
  // do is say which are missing rather than let the app boot broken.
144
269
  const missing = [];
145
- if (manifest.env?.length) {
270
+ const wanted = resolved.flatMap((c) => c.manifest.env ?? []);
271
+ if (wanted.length) {
146
272
  watch?.start?.("settings");
147
273
  const have = new Set(await opts.envKeys());
148
- for (const e of manifest.env)
149
- if (!have.has(e.key))
274
+ for (const e of wanted)
275
+ if (!have.has(e.key) && !missing.some((m) => m.key === e.key))
150
276
  missing.push(e);
151
277
  watch?.done?.("settings", missing.length
152
278
  ? `${missing.length} still needed: ${missing.map((m) => m.key).join(", ")}`
153
279
  : "everything it needs is set");
154
280
  }
155
- watch?.start?.("deploy");
281
+ // A preview, not production. This is the whole point of the branch: the
282
+ // person who asked for the chunk gets a link they can click and look at,
283
+ // and the change reaches production only by being promoted through main and
284
+ // staging — never by having been installed.
285
+ watch?.start?.("preview");
156
286
  const built = await vc.deploy(opts.app, {
157
287
  repo: opts.repo,
158
- ref: DEFAULT_BRANCH,
159
- target: "production",
288
+ ref: branch,
160
289
  teamId: await vc.teamId(),
161
290
  });
162
- watch?.done?.("deploy", `${built.url} · building`);
291
+ const preview = `https://${built.url}`;
292
+ watch?.done?.("preview", `${preview} · building`);
293
+ watch?.start?.("pull request");
294
+ const pr = await gh.createPullRequest(opts.repo, {
295
+ title: `Add the ${manifest.name} chunk`,
296
+ body: `${manifest.summary}\n\nWritten by chunky. ${all.length} file${all.length === 1 ? "" : "s"}` +
297
+ `${migrated ? `, ${migrated} migration${migrated === 1 ? "" : "s"} already run against dev` : ""}.\n\n` +
298
+ `Preview: ${preview}\n\n` +
299
+ (missing.length
300
+ ? `Still needs setting before it will work: ${missing.map((m) => m.key).join(", ")}.\n`
301
+ : ""),
302
+ head: branch,
303
+ base: DEFAULT_BRANCH,
304
+ });
305
+ watch?.done?.("pull request", `#${pr.number}`);
163
306
  return {
164
307
  chunk: opts.chunk, app: opts.app,
165
- files: all.map((f) => f.path), commit, migrated, missing, already: false,
308
+ files: all.map((f) => f.path), commit, branch, preview,
309
+ pullRequest: pr.html_url, migrated, missing, already: false,
166
310
  };
167
311
  }
168
312
  //# sourceMappingURL=chunks.js.map
@@ -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"}