create-riebeckite 0.0.15 → 0.0.16

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.
@@ -5,6 +5,7 @@ export type CreateRiebeckiteOptions = {
5
5
  readonly preset: ScaffoldPresetName;
6
6
  readonly listPresets: boolean;
7
7
  readonly githubActions: boolean;
8
+ readonly cloudflareWorkers: boolean;
8
9
  readonly contentRepository?: string;
9
10
  readonly siteRepository?: string;
10
11
  };
package/dist/src/index.js CHANGED
@@ -71,6 +71,7 @@ function parseArguments(arguments_) {
71
71
  preset: preset ?? "starter",
72
72
  listPresets,
73
73
  githubActions,
74
+ cloudflareWorkers: false,
74
75
  contentRepository,
75
76
  siteRepository
76
77
  };
@@ -90,6 +91,7 @@ import {
90
91
  scaffoldPresets as scaffoldPresets2
91
92
  } from "@riebeckite/honox";
92
93
  var DEFAULT_DIRECTORY = "my-riebeckite-site";
94
+ var DEFAULT_INTERACTIVE_DEPLOYMENT = "none";
93
95
  function interactiveAnswersToOptions(answers) {
94
96
  const external = answers.contentSource === "external";
95
97
  return {
@@ -98,6 +100,7 @@ function interactiveAnswersToOptions(answers) {
98
100
  preset: answers.preset,
99
101
  listPresets: false,
100
102
  githubActions: external || answers.deployment === "github-actions",
103
+ cloudflareWorkers: !external && answers.deployment === "cloudflare",
101
104
  contentRepository: external ? answers.contentRepository : void 0,
102
105
  siteRepository: external ? answers.siteRepository : void 0
103
106
  };
@@ -131,6 +134,9 @@ async function promptInteractiveAnswers() {
131
134
  if (isCancel(contentSource)) return null;
132
135
  let answers;
133
136
  if (contentSource === "external") {
137
+ log.info(
138
+ "Separate repositories use GitHub Actions so content updates can trigger site deployments."
139
+ );
134
140
  const contentRepository = await text({
135
141
  message: "Content repository",
136
142
  placeholder: "OWNER/notes"
@@ -152,11 +158,17 @@ async function promptInteractiveAnswers() {
152
158
  } else {
153
159
  const deployment = await select({
154
160
  message: "Set up deployment?",
155
- initialValue: "github-actions",
161
+ initialValue: DEFAULT_INTERACTIVE_DEPLOYMENT,
156
162
  options: [
163
+ {
164
+ value: "cloudflare",
165
+ label: "Cloudflare Workers",
166
+ hint: "Publish from this machine"
167
+ },
157
168
  {
158
169
  value: "github-actions",
159
- label: "GitHub Actions + Cloudflare Workers"
170
+ label: "GitHub Actions",
171
+ hint: "Deploy on every push"
160
172
  },
161
173
  { value: "none", label: "Not now" }
162
174
  ]
@@ -167,51 +179,149 @@ async function promptInteractiveAnswers() {
167
179
  log.step("Creating Riebeckite site...");
168
180
  return answers;
169
181
  }
182
+ async function promptDeployNow() {
183
+ const answer = await select({
184
+ message: "Deploy now?",
185
+ initialValue: "yes",
186
+ options: [
187
+ { value: "yes", label: "Yes" },
188
+ { value: "later", label: "Later" }
189
+ ]
190
+ });
191
+ if (isCancel(answer)) return false;
192
+ return answer === "yes";
193
+ }
170
194
  function capitalize(value) {
171
195
  return value.charAt(0).toUpperCase() + value.slice(1);
172
196
  }
173
197
 
174
- // src/index.ts
175
- async function runCreateRiebeckite(arguments_) {
176
- let options;
177
- if (arguments_.length === 0) {
178
- const answers = await promptInteractiveAnswers();
179
- if (answers === null) {
180
- console.log("Operation cancelled.");
181
- return;
182
- }
183
- options = interactiveAnswersToOptions(answers);
184
- } else {
185
- try {
186
- options = parseArguments(arguments_);
187
- } catch (error) {
188
- console.error(error instanceof Error ? error.message : String(error));
189
- process.exitCode = 1;
190
- return;
198
+ // src/package-manager.ts
199
+ import { PACKAGE_MANAGER } from "@riebeckite/honox";
200
+ function packageManagerCommands(name = PACKAGE_MANAGER) {
201
+ if (name === "pnpm") {
202
+ return {
203
+ name,
204
+ install: { command: "pnpm", args: ["install"], label: "pnpm install" },
205
+ build: { command: "pnpm", args: ["build"], label: "pnpm build" },
206
+ deploy: {
207
+ command: "pnpm",
208
+ args: ["exec", "riebeckite", "deploy"],
209
+ label: "pnpm exec riebeckite deploy"
210
+ }
211
+ };
212
+ }
213
+ return {
214
+ name: "npm",
215
+ install: { command: "npm", args: ["install"], label: "npm install" },
216
+ build: { command: "npm", args: ["run", "build"], label: "npm run build" },
217
+ deploy: {
218
+ command: "npm",
219
+ args: ["exec", "riebeckite", "deploy"],
220
+ label: "npm exec riebeckite deploy"
191
221
  }
222
+ };
223
+ }
224
+
225
+ // src/publish.ts
226
+ var DeploymentFailure = class extends Error {
227
+ phase;
228
+ constructor(phase, message) {
229
+ super(message);
230
+ this.name = "DeploymentFailure";
231
+ this.phase = phase;
232
+ }
233
+ };
234
+ async function installDependencies(directory, commands, run) {
235
+ await runCommand("install", commands.install, directory, run);
236
+ }
237
+ async function buildAndDeploy(directory, commands, run) {
238
+ await runCommand("build", commands.build, directory, run);
239
+ await runCommand("deploy", commands.deploy, directory, run);
240
+ }
241
+ function formatCloudflareNextSteps(relativeDirectory, commands) {
242
+ const lines = ["Next steps:"];
243
+ if (relativeDirectory !== ".") {
244
+ lines.push(` cd ${relativeDirectory}`);
245
+ }
246
+ lines.push(` ${commands.build.label}`);
247
+ lines.push(` ${commands.deploy.label}`);
248
+ return lines.join("\n");
249
+ }
250
+ function formatDeploymentFailure(relativeDirectory, commands, failure) {
251
+ const lines = [
252
+ "Project created successfully.",
253
+ deploymentFailureSummary(failure.phase),
254
+ failure.message,
255
+ "You can retry with:"
256
+ ];
257
+ if (relativeDirectory !== ".") {
258
+ lines.push(` cd ${relativeDirectory}`);
259
+ }
260
+ if (failure.phase === "install") {
261
+ lines.push(` ${commands.install.label}`);
262
+ }
263
+ lines.push(` ${commands.build.label}`);
264
+ lines.push(` ${commands.deploy.label}`);
265
+ return lines.join("\n");
266
+ }
267
+ function deploymentFailureSummary(phase) {
268
+ if (phase === "install") return "Installing dependencies failed.";
269
+ if (phase === "build") return "Build failed.";
270
+ return "Deployment failed.";
271
+ }
272
+ async function runCommand(phase, command, directory, run) {
273
+ let exitCode;
274
+ try {
275
+ exitCode = await run(command.command, command.args, directory);
276
+ } catch (error) {
277
+ throw new DeploymentFailure(
278
+ phase,
279
+ error instanceof Error ? error.message : String(error)
280
+ );
281
+ }
282
+ if (exitCode !== 0) {
283
+ throw new DeploymentFailure(
284
+ phase,
285
+ `${command.label} exited with code ${exitCode}.`
286
+ );
192
287
  }
288
+ }
289
+
290
+ // src/run-commands.ts
291
+ import { spawn } from "node:child_process";
292
+ function spawnCommand(command, args, cwd) {
293
+ return new Promise((resolve, reject) => {
294
+ const child = spawn(command, [...args], {
295
+ cwd,
296
+ stdio: "inherit",
297
+ shell: process.platform === "win32"
298
+ });
299
+ child.on("error", reject);
300
+ child.on("exit", (code) => resolve(code ?? 1));
301
+ });
302
+ }
303
+
304
+ // src/index.ts
305
+ async function runCreateRiebeckite(arguments_) {
306
+ const resolved = await resolveOptions(arguments_);
307
+ if (resolved === null) return;
308
+ const { options, interactive } = resolved;
193
309
  if (options.listPresets) {
194
310
  printPresets();
195
311
  return;
196
312
  }
197
313
  const targetDirectory = path.resolve(process.cwd(), options.directory);
314
+ let result;
198
315
  try {
199
- const result = await scaffoldRiebeckiteSite({
316
+ result = await scaffoldRiebeckiteSite({
200
317
  targetDirectory,
201
318
  overwrite: options.force,
202
319
  preset: options.preset,
203
320
  githubActions: options.githubActions,
321
+ cloudflareWorkers: options.cloudflareWorkers,
204
322
  contentRepository: options.contentRepository,
205
323
  siteRepository: options.siteRepository
206
324
  });
207
- const relative = path.relative(process.cwd(), result.targetDirectory) || ".";
208
- console.log(`Created a ${options.preset} Riebeckite site in ${relative}`);
209
- console.log("");
210
- const externalContent = options.contentRepository !== void 0;
211
- const editFile = !externalContent && result.files.includes("content/index.md") ? "content/index.md" : void 0;
212
- console.log(
213
- formatScaffoldNextSteps(relative, { editFile, externalContent })
214
- );
215
325
  } catch (error) {
216
326
  if (error instanceof ScaffoldSiteError) {
217
327
  console.error(error.message);
@@ -220,6 +330,68 @@ async function runCreateRiebeckite(arguments_) {
220
330
  }
221
331
  throw error;
222
332
  }
333
+ const relative = path.relative(process.cwd(), result.targetDirectory) || ".";
334
+ console.log(`Created a ${options.preset} Riebeckite site in ${relative}`);
335
+ console.log("");
336
+ if (interactive && options.cloudflareWorkers) {
337
+ await publishCloudflareSite(targetDirectory, relative);
338
+ return;
339
+ }
340
+ printScaffoldNextSteps(options, result, relative);
341
+ }
342
+ async function resolveOptions(arguments_) {
343
+ if (arguments_.length === 0) {
344
+ const answers = await promptInteractiveAnswers();
345
+ if (answers === null) {
346
+ console.log("Operation cancelled.");
347
+ return null;
348
+ }
349
+ return { options: interactiveAnswersToOptions(answers), interactive: true };
350
+ }
351
+ try {
352
+ return { options: parseArguments(arguments_), interactive: false };
353
+ } catch (error) {
354
+ console.error(error instanceof Error ? error.message : String(error));
355
+ process.exitCode = 1;
356
+ return null;
357
+ }
358
+ }
359
+ function printScaffoldNextSteps(options, result, relative) {
360
+ const externalContent = options.contentRepository !== void 0;
361
+ const editFile = !externalContent && result.files.includes("content/index.md") ? "content/index.md" : void 0;
362
+ console.log(formatScaffoldNextSteps(relative, { editFile, externalContent }));
363
+ }
364
+ async function publishCloudflareSite(targetDirectory, relative) {
365
+ const commands = packageManagerCommands();
366
+ console.log(`Installing dependencies with ${commands.name}...`);
367
+ try {
368
+ await installDependencies(targetDirectory, commands, spawnCommand);
369
+ } catch (error) {
370
+ if (!(error instanceof DeploymentFailure)) throw error;
371
+ reportDeploymentFailure(error, relative);
372
+ return;
373
+ }
374
+ const deployNow = await promptDeployNow();
375
+ if (!deployNow) {
376
+ console.log("");
377
+ console.log(formatCloudflareNextSteps(relative, commands));
378
+ return;
379
+ }
380
+ try {
381
+ await buildAndDeploy(targetDirectory, commands, spawnCommand);
382
+ } catch (error) {
383
+ if (!(error instanceof DeploymentFailure)) throw error;
384
+ reportDeploymentFailure(error, relative);
385
+ return;
386
+ }
387
+ console.log("");
388
+ console.log("Deployment complete.");
389
+ }
390
+ function reportDeploymentFailure(error, relative) {
391
+ const commands = packageManagerCommands();
392
+ console.error("");
393
+ console.error(formatDeploymentFailure(relative, commands, error));
394
+ process.exitCode = 1;
223
395
  }
224
396
  export {
225
397
  runCreateRiebeckite
@@ -1,7 +1,8 @@
1
1
  import { type ScaffoldPresetName } from "@riebeckite/honox";
2
2
  import type { CreateRiebeckiteOptions } from "./arguments.js";
3
+ export declare const DEFAULT_INTERACTIVE_DEPLOYMENT: InteractiveDeployment;
3
4
  export type InteractiveContentSource = "local" | "external";
4
- export type InteractiveDeployment = "github-actions" | "none";
5
+ export type InteractiveDeployment = "cloudflare" | "github-actions" | "none";
5
6
  export type InteractiveAnswers = {
6
7
  readonly directory: string;
7
8
  readonly preset: ScaffoldPresetName;
@@ -22,3 +23,4 @@ export declare function interactiveAnswersToOptions(answers: InteractiveAnswers)
22
23
  * `owner/repository` shape is validated by the existing scaffold.
23
24
  */
24
25
  export declare function promptInteractiveAnswers(): Promise<InteractiveAnswers | null>;
26
+ export declare function promptDeployNow(): Promise<boolean>;
@@ -0,0 +1,13 @@
1
+ export type PackageManagerName = "npm" | "pnpm";
2
+ export type PackageManagerCommand = {
3
+ readonly command: string;
4
+ readonly args: readonly string[];
5
+ readonly label: string;
6
+ };
7
+ export type PackageManagerCommands = {
8
+ readonly name: PackageManagerName;
9
+ readonly install: PackageManagerCommand;
10
+ readonly build: PackageManagerCommand;
11
+ readonly deploy: PackageManagerCommand;
12
+ };
13
+ export declare function packageManagerCommands(name?: PackageManagerName): PackageManagerCommands;
@@ -0,0 +1,11 @@
1
+ import type { PackageManagerCommands } from "./package-manager.js";
2
+ import type { CommandRunner } from "./run-commands.js";
3
+ export type DeploymentPhase = "install" | "build" | "deploy";
4
+ export declare class DeploymentFailure extends Error {
5
+ readonly phase: DeploymentPhase;
6
+ constructor(phase: DeploymentPhase, message: string);
7
+ }
8
+ export declare function installDependencies(directory: string, commands: PackageManagerCommands, run: CommandRunner): Promise<void>;
9
+ export declare function buildAndDeploy(directory: string, commands: PackageManagerCommands, run: CommandRunner): Promise<void>;
10
+ export declare function formatCloudflareNextSteps(relativeDirectory: string, commands: PackageManagerCommands): string;
11
+ export declare function formatDeploymentFailure(relativeDirectory: string, commands: PackageManagerCommands, failure: DeploymentFailure): string;
@@ -0,0 +1,2 @@
1
+ export type CommandRunner = (command: string, args: readonly string[], cwd: string) => Promise<number>;
2
+ export declare function spawnCommand(command: string, args: readonly string[], cwd: string): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-riebeckite",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@clack/prompts": "^1.8.1",
31
- "@riebeckite/honox": "0.0.15"
31
+ "@riebeckite/honox": "0.0.16"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",