seedcord 0.23.0-next.0 → 0.23.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as SEEDCORD_CONFIG_FILENAMES, t as version } from "./src-RLphadYM.mjs";
1
+ import { n as SEEDCORD_CONFIG_FILENAMES, t as version } from "./version-Cmdvyxh7.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { Command, Option } from "@commander-js/extra-typings";
4
4
  import { SeedcordErrorCode, isSeedcordError, paint } from "@seedcord/errors";
@@ -29,8 +29,6 @@ import { ApplicationCommandOptionType, ApplicationCommandType, InteractionContex
29
29
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
30
30
  import { assertNever, filterCirculars } from "@seedcord/utils";
31
31
  import { TypedEventEmitter } from "@seedcord/event-emitter";
32
- import { Console } from "node:console";
33
- import { Writable } from "node:stream";
34
32
  import { cpus, tmpdir, totalmem } from "node:os";
35
33
  import process$1 from "node:process";
36
34
  import { settleWithin } from "@seedcord/core/node/internal";
@@ -39,8 +37,10 @@ import { minimatch } from "minimatch";
39
37
  import { once } from "node:events";
40
38
  import { createServer as createServer$1 } from "node:http";
41
39
  import { createServer as createServer$2 } from "node:net";
40
+ import { Console } from "node:console";
41
+ import { Writable } from "node:stream";
42
+ import { camelCase, debounce, kebabCase, pascalCase, snakeCase } from "es-toolkit";
42
43
  import Handlebars from "handlebars";
43
- import { camelCase, kebabCase, pascalCase, snakeCase } from "es-toolkit";
44
44
 
45
45
  //#region src/core/output/wrapLines.ts
46
46
  function wrapLines(text, width, prefix) {
@@ -994,10 +994,10 @@ var ProjectFiles = class {
994
994
  return this.layout.modulesUnder(folder);
995
995
  }
996
996
  async foldersIncludingEmpty() {
997
- return (await this.entries()).filter(({ isFolder }) => isFolder).map(({ path }) => this.layout.keyOf(path)).toSorted();
997
+ return (await this.entries()).flatMap(({ isFolder, path }) => isFolder ? [this.layout.keyOf(path)] : []).toSorted();
998
998
  }
999
999
  async pathsWithHash() {
1000
- return (await this.entries()).map(({ path }) => path).filter((path) => basename(path).includes("#") && !relative(this.layout.root, dirname(path)).includes("#")).toSorted();
1000
+ return (await this.entries()).flatMap(({ path }) => basename(path).includes("#") && !relative(this.layout.root, dirname(path)).includes("#") ? [path] : []).toSorted();
1001
1001
  }
1002
1002
  async entries() {
1003
1003
  const besideRoot = this.layout.listedBesideRoot().map(async (folder) => [{
@@ -2653,8 +2653,11 @@ function importMetaPaths(program) {
2653
2653
  }
2654
2654
  const FILE_URL = "__seedcordPathToFileURL";
2655
2655
  const FILE_URL_IMPORT = `import { pathToFileURL as ${FILE_URL} } from 'node:url';`;
2656
+ const BUILT_ROOT = "__seedcordBuiltRoot";
2656
2657
  function pinModulePaths(layout) {
2657
- const builtRoot = `${BOT_FILES_SLOT}.root`;
2658
+ const utilsPath = fileURLToPath(import.meta.resolve("@seedcord/utils/internal"));
2659
+ const builtRootImport = `import { builtRoot as ${BUILT_ROOT} } from ${JSON.stringify(utilsPath)};`;
2660
+ const builtRoot = `${BUILT_ROOT}()`;
2658
2661
  return {
2659
2662
  name: "seedcord:pin-module-paths",
2660
2663
  transform(code, id) {
@@ -2671,6 +2674,7 @@ function pinModulePaths(layout) {
2671
2674
  };
2672
2675
  let rewritten = code;
2673
2676
  for (const { start, end, key } of rewrites.toReversed()) rewritten = rewritten.slice(0, start) + values[key] + rewritten.slice(end);
2677
+ rewritten = builtRootImport + rewritten;
2674
2678
  if (rewrites.some(({ key }) => key === "url")) rewritten = FILE_URL_IMPORT + rewritten;
2675
2679
  return {
2676
2680
  code: rewritten,
@@ -2932,7 +2936,10 @@ var EdgeBuild = class extends TargetBuild {
2932
2936
  await bootWorker({
2933
2937
  root: this.target.viteRoot,
2934
2938
  mode: this.project.config.viteMode,
2935
- plugins: [cloudflare.plugins({ persistState: false })],
2939
+ plugins: [cloudflare.plugins({
2940
+ persistState: false,
2941
+ remoteBindings: false
2942
+ })],
2936
2943
  environments: workerEnvironment()
2937
2944
  });
2938
2945
  }
@@ -2970,6 +2977,7 @@ function assertOutDirSafe(outDir) {
2970
2977
  const ENTRY_ID = "seedcord:entry";
2971
2978
  const RESOLVED_ENTRY_ID = `\0${ENTRY_ID}`;
2972
2979
  const ROOT_EXPRESSION = `import.meta.dirname ?? ${JSON.stringify(PLACEHOLDER_ROOT)}`;
2980
+ const ONLY_EXPORTS_WARNING = "This build only exports your bot, so running it doesn't start your bot. Set build.start in seedcord.config.ts and build again, or import this file from your app.";
2973
2981
  function isServerEntry(moduleId) {
2974
2982
  return moduleId === RESOLVED_ENTRY_ID;
2975
2983
  }
@@ -2977,7 +2985,11 @@ function runStartFile(startKey) {
2977
2985
  return [`await import(${JSON.stringify(startKey)});`];
2978
2986
  }
2979
2987
  function exportInstance(instanceKey) {
2980
- return [`const { default: bot } = await import(${JSON.stringify(instanceKey)});`, "export default bot;"];
2988
+ return [
2989
+ `const { default: bot } = await import(${JSON.stringify(instanceKey)});`,
2990
+ `if (import.meta.main) console.warn(${JSON.stringify(ONLY_EXPORTS_WARNING)});`,
2991
+ "export default bot;"
2992
+ ];
2981
2993
  }
2982
2994
  function serverEntry(builtFiles, importBot) {
2983
2995
  const source = [
@@ -3079,7 +3091,7 @@ const DECLARATIONS_NAME = "types";
3079
3091
  const ENTRY_DECLARATIONS_NAME = ENTRY_FILE_NAME.replace(/\.mjs$/, ".d.mts");
3080
3092
  var ExportBuild = class extends ServerBuild {
3081
3093
  nextCommands() {
3082
- return [];
3094
+ return [["start", "this build only exports your bot. set build.start to run it with node"]];
3083
3095
  }
3084
3096
  bundle() {
3085
3097
  const { config, configDir } = this.project;
@@ -3396,7 +3408,7 @@ var AugmentationBuilder = class {
3396
3408
  menus.set(json.name, { cache: cacheStateOf(json.contexts) });
3397
3409
  }
3398
3410
  warnEmptyGroups(json) {
3399
- for (const option of json.options ?? []) if (option.type === ApplicationCommandOptionType.SubcommandGroup && (option.options ?? []).length === 0) this.logger.warn(`Slash group \`${json.name}/${option.name}\` has no subcommands and will not deploy.`);
3411
+ for (const option of json.options ?? []) if (option.type === ApplicationCommandOptionType.SubcommandGroup && (option.options ?? []).length === 0) this.logger.warn(`Slash group \`${json.name}/${option.name}\` doesn't have any subcommands, so it won't deploy.`);
3400
3412
  }
3401
3413
  mapOptions(options) {
3402
3414
  const table = {};
@@ -3864,10 +3876,13 @@ var CleanMode = class extends RemoveMode {
3864
3876
  }
3865
3877
  select(scan) {
3866
3878
  const globalKeys = new Set(scan.global.map(commandKey));
3867
- return scan.guilds.map(({ scope, commands }) => ({
3868
- scope,
3869
- commands: commands.filter((c) => globalKeys.has(commandKey(c)))
3870
- })).filter(({ commands }) => commands.length > 0);
3879
+ return scan.guilds.flatMap(({ scope, commands }) => {
3880
+ const alsoGlobal = commands.filter((c) => globalKeys.has(commandKey(c)));
3881
+ return alsoGlobal.length > 0 ? [{
3882
+ scope,
3883
+ commands: alsoGlobal
3884
+ }] : [];
3885
+ });
3871
3886
  }
3872
3887
  remove(session, selected) {
3873
3888
  return session.deleteCommands(selected);
@@ -4803,28 +4818,6 @@ var ChangeStore = class extends TypedEventEmitter {
4803
4818
  };
4804
4819
  };
4805
4820
 
4806
- //#endregion
4807
- //#region src/ui/stores/routeConsole.ts
4808
- function routeConsoleToLogs() {
4809
- let level = "info";
4810
- const toLogs = new Writable({ write(chunk, _encoding, done) {
4811
- LoggerChannelRegistry.instance.dispatch(consoleRecord(level, chunk.toString().replace(/\n$/, "")));
4812
- done();
4813
- } });
4814
- const formatter = new Console({
4815
- stdout: toLogs,
4816
- stderr: toLogs
4817
- });
4818
- return routeConsole(CONSOLE_METHODS, (method, args, invoked) => {
4819
- level = CONSOLE_LEVEL[method];
4820
- if (method === "trace") {
4821
- LoggerChannelRegistry.instance.dispatch(consoleRecord(level, "", [traceError(format(...args), invoked)]));
4822
- return;
4823
- }
4824
- Reflect.apply(formatter[method], formatter, args);
4825
- });
4826
- }
4827
-
4828
4821
  //#endregion
4829
4822
  //#region src/ui/stores/LogStore.ts
4830
4823
  const STACK_FRAME = /^\s+at\s/;
@@ -4837,7 +4830,6 @@ var LogStore = class LogStore extends ChangeStore {
4837
4830
  buffer = [];
4838
4831
  nextId = 1;
4839
4832
  sinkHandle = null;
4840
- restoreConsole = null;
4841
4833
  pendingUpdate = false;
4842
4834
  flushTimer = null;
4843
4835
  MAX_LOGS = 1e3;
@@ -4851,12 +4843,9 @@ var LogStore = class LogStore extends ChangeStore {
4851
4843
  mount() {
4852
4844
  if (this.sinkHandle) return;
4853
4845
  this.sinkHandle = LoggerChannelRegistry.instance.installSink(this, { muteConsole: true });
4854
- this.restoreConsole = routeConsoleToLogs();
4855
4846
  }
4856
4847
  unmount() {
4857
4848
  if (!this.sinkHandle) return;
4858
- this.restoreConsole?.();
4859
- this.restoreConsole = null;
4860
4849
  this.sinkHandle.dispose();
4861
4850
  this.sinkHandle = null;
4862
4851
  }
@@ -5755,11 +5744,11 @@ function acceptsSessionKeys(state) {
5755
5744
  function dispatchHotkey(ctx) {
5756
5745
  const found = BINDINGS.get(keyIdOf(ctx.input, ctx.key));
5757
5746
  const binding = found && isLive(found, ctx) ? found : void 0;
5758
- if (binding?.confirm && ctx.state.armed !== binding.confirm) {
5759
- ctx.store.setArmed(binding.confirm);
5747
+ if (binding?.confirm && ctx.state.pendingConfirm !== binding.confirm) {
5748
+ ctx.store.setPendingConfirm(binding.confirm);
5760
5749
  return;
5761
5750
  }
5762
- if (ctx.state.armed !== null) ctx.store.setArmed(null);
5751
+ if (ctx.state.pendingConfirm !== null) ctx.store.setPendingConfirm(null);
5763
5752
  binding?.run(ctx);
5764
5753
  }
5765
5754
 
@@ -5991,6 +5980,9 @@ var SiteAddress = class {
5991
5980
  get path() {
5992
5981
  return new URL(this.url).pathname.replace(/\/$/, "");
5993
5982
  }
5983
+ get exportDir() {
5984
+ return `dist${this.path}`;
5985
+ }
5994
5986
  at(path) {
5995
5987
  if (path === "") return this.url;
5996
5988
  return `${this.url}/${path.replace(/^\/+/, "")}`;
@@ -6414,7 +6406,7 @@ function RestartRequiredCard() {
6414
6406
  }, /* @__PURE__ */ React.createElement(Text, {
6415
6407
  color: ui.warn,
6416
6408
  bold: true
6417
- }, "Restart required"), /* @__PURE__ */ React.createElement(Text, null, "A change needs a full restart. press", " ", /* @__PURE__ */ React.createElement(Text, {
6409
+ }, "Restart required"), /* @__PURE__ */ React.createElement(Text, null, "A change needs a full restart. Press", " ", /* @__PURE__ */ React.createElement(Text, {
6418
6410
  color: ui.warn,
6419
6411
  bold: true
6420
6412
  }, "r"), " ", "to restart"));
@@ -6460,11 +6452,11 @@ function openingPhase(status) {
6460
6452
  /** Every pending notice, ranked with the one that blocks a decision first. */
6461
6453
  function noticesOf(state) {
6462
6454
  const notices = [];
6463
- if (state.armed) notices.push({
6464
- key: state.armed,
6465
- summary: CONFIRMS[state.armed].title,
6466
- action: `press ${confirmKeyLabel(state.armed)} again`,
6467
- card: /* @__PURE__ */ React.createElement(ConfirmCard, { confirm: state.armed })
6455
+ if (state.pendingConfirm) notices.push({
6456
+ key: state.pendingConfirm,
6457
+ summary: CONFIRMS[state.pendingConfirm].title,
6458
+ action: `press ${confirmKeyLabel(state.pendingConfirm)} again`,
6459
+ card: /* @__PURE__ */ React.createElement(ConfirmCard, { confirm: state.pendingConfirm })
6468
6460
  });
6469
6461
  if (state.commandUpdatePrompt) {
6470
6462
  const count = state.commandUpdatePrompt.length;
@@ -6699,7 +6691,7 @@ const INITIAL = {
6699
6691
  commandUpdatePrompt: null,
6700
6692
  port: null,
6701
6693
  tunnel: null,
6702
- armed: null,
6694
+ pendingConfirm: null,
6703
6695
  idleAnimation: true,
6704
6696
  liveSinceMs: null
6705
6697
  };
@@ -6726,8 +6718,8 @@ var DevStore = class extends ChangeStore {
6726
6718
  setTunnel(tunnel) {
6727
6719
  this.patch({ tunnel });
6728
6720
  }
6729
- setArmed(armed) {
6730
- this.patch({ armed });
6721
+ setPendingConfirm(pendingConfirm) {
6722
+ this.patch({ pendingConfirm });
6731
6723
  }
6732
6724
  setIdleAnimation(idleAnimation) {
6733
6725
  this.patch({ idleAnimation });
@@ -6789,11 +6781,11 @@ var DevStore = class extends ChangeStore {
6789
6781
  ...next
6790
6782
  };
6791
6783
  const liveSinceMs = isSessionLive(merged.phase) ? this.state.liveSinceMs ?? Date.now() : null;
6792
- const armed = merged.phase === this.state.phase ? merged.armed : null;
6784
+ const pendingConfirm = merged.phase === this.state.phase ? merged.pendingConfirm : null;
6793
6785
  this.state = {
6794
6786
  ...merged,
6795
6787
  liveSinceMs,
6796
- armed
6788
+ pendingConfirm
6797
6789
  };
6798
6790
  this.emit("change");
6799
6791
  }
@@ -7343,6 +7335,7 @@ var BaseDevRuntime = class {
7343
7335
  async openWithCleanup(context) {
7344
7336
  const resources = new AsyncDisposableStack();
7345
7337
  try {
7338
+ resources.defer(() => LoggerChannelRegistry.instance.configure({}));
7346
7339
  resources.use(setDevFiles(context.files.layout.toJSON()));
7347
7340
  return await this.open(context, resources);
7348
7341
  } catch (error) {
@@ -7583,10 +7576,6 @@ function invokeErrorsAsJson() {
7583
7576
  }
7584
7577
  };
7585
7578
  }
7586
- function installCliLogSinks(stack) {
7587
- installNodeDefaults();
7588
- stack.defer(() => LoggerChannelRegistry.instance.configure({}));
7589
- }
7590
7579
  var EdgeDevRuntime = class extends BaseDevRuntime {
7591
7580
  target;
7592
7581
  settleStart;
@@ -7599,7 +7588,7 @@ var EdgeDevRuntime = class extends BaseDevRuntime {
7599
7588
  const { files } = context;
7600
7589
  const { viteRoot } = this.target;
7601
7590
  resources.use(fenceSignals());
7602
- installCliLogSinks(resources);
7591
+ installNodeDefaults();
7603
7592
  this.emit(context, {
7604
7593
  type: "progress",
7605
7594
  status: "Loading Cloudflare plugin…"
@@ -7951,6 +7940,7 @@ async function write(rest, endpoint) {
7951
7940
  function superseded(attempt) {
7952
7941
  return attempt.signal.aborted;
7953
7942
  }
7943
+ const TUNNEL_FAILED = "Tunnel setup failed, so the bot runs without a public endpoint";
7954
7944
  function elapsedSince(startedAt) {
7955
7945
  return () => paint.mute(`+${formatUptime(Date.now() - startedAt)}`);
7956
7946
  }
@@ -8018,7 +8008,7 @@ var TunnelCoordinator = class {
8018
8008
  }
8019
8009
  reportFailure(error, patched) {
8020
8010
  this.deps.onStatus(null);
8021
- this.deps.logger.error("Tunnel setup failed, the bot runs without a public endpoint", error);
8011
+ this.deps.logger.error(TUNNEL_FAILED, error);
8022
8012
  const hint = this.deps.kind.failureHint(patched);
8023
8013
  if (hint) this.deps.logger.info(hint);
8024
8014
  }
@@ -8046,7 +8036,7 @@ var TunnelCoordinator = class {
8046
8036
  //#region src/commands/dev/tunnel/createTunnelCoordinator.ts
8047
8037
  const PASTE_HINT = "The tunnel is still up, so try pasting that URL into the dashboard.";
8048
8038
  const RESTART_HINT = "Restart for a fresh hostname, or set `tunnel` to an https URL you already serve.";
8049
- const NO_PORT_HINT = `No tunnel, since the bot runs with ${paint.bold("port: false")} and cloudflared has no port to forward to. Give the bot a port while you develop, or set ${paint.amber("tunnel")} to the url of the server that serves it: ${paint.sky(PRODUCTION_SITES.guide.at("build/embed"))}`;
8039
+ const NO_PORT_HINT = `seedcord didn't start a tunnel, since the bot runs with ${paint.bold("port: false")} and cloudflared doesn't have a port to forward to. Give the bot a port while you develop, or set ${paint.amber("tunnel")} to the URL of the server that serves your bot: ${paint.sky(PRODUCTION_SITES.guide.at("build/embed"))}`;
8050
8040
  function missingCloudflaredHint(platform) {
8051
8041
  const arrow = paint.mute("→");
8052
8042
  return [
@@ -8121,7 +8111,7 @@ var TunnelRouter = class {
8121
8111
  }
8122
8112
  route(tunnel, port, instance) {
8123
8113
  return this.routeTo(tunnel, port, instance).catch((error) => {
8124
- this.logger.error("Tunnel setup failed, the bot runs without a public endpoint", error);
8114
+ this.logger.error(TUNNEL_FAILED, error);
8125
8115
  });
8126
8116
  }
8127
8117
  async routeTo(tunnel, port, instance) {
@@ -8225,6 +8215,7 @@ var DevRunner = class DevRunner {
8225
8215
  store.setBusy(true);
8226
8216
  await this.currentSession.stop();
8227
8217
  this.currentSession = null;
8218
+ store.clearPrompt();
8228
8219
  }
8229
8220
  } catch (_) {
8230
8221
  _usingCtx$4.e = _;
@@ -8272,11 +8263,35 @@ var DevRunner = class DevRunner {
8272
8263
  }
8273
8264
  };
8274
8265
 
8266
+ //#endregion
8267
+ //#region src/commands/dev/routeConsoleToLogs.ts
8268
+ function routeConsoleToLogs() {
8269
+ let level = "info";
8270
+ const toLogs = new Writable({ write(chunk, _encoding, done) {
8271
+ LoggerChannelRegistry.instance.dispatch(consoleRecord(level, chunk.toString().replace(/\n$/, "")));
8272
+ done();
8273
+ } });
8274
+ const formatter = new Console({
8275
+ stdout: toLogs,
8276
+ stderr: toLogs
8277
+ });
8278
+ return routeConsole(CONSOLE_METHODS, (method, args, invoked) => {
8279
+ level = CONSOLE_LEVEL[method];
8280
+ if (method === "trace") {
8281
+ LoggerChannelRegistry.instance.dispatch(consoleRecord(level, "", [traceError(format(...args), invoked)]));
8282
+ return;
8283
+ }
8284
+ Reflect.apply(formatter[method], formatter, args);
8285
+ });
8286
+ }
8287
+
8275
8288
  //#endregion
8276
8289
  //#region src/commands/dev/runPlain.ts
8277
8290
  const logger = cliLogger("Dev");
8291
+ const COMMAND_SAVES_QUIET_MS = 2e3;
8278
8292
  const COMMANDS = /* @__PURE__ */ new Map([
8279
8293
  ["restart", (runner) => runner.restart()],
8294
+ ["codegen", (runner) => runner.writeTypes()],
8280
8295
  ["disconnect", (runner) => runner.disconnect()],
8281
8296
  ["quit", (runner) => runner.quit()]
8282
8297
  ]);
@@ -8288,15 +8303,21 @@ function commandOn(line) {
8288
8303
  }
8289
8304
  }
8290
8305
  function leaveToRun(command) {
8291
- command.catch(() => void 0);
8306
+ Promise.resolve(command).catch(() => void 0);
8292
8307
  }
8293
8308
  async function runPlain(store, runner, input) {
8294
8309
  try {
8295
8310
  var _usingCtx$3 = _usingCtx();
8311
+ const refreshCommands = debounce(() => runner.refreshCommands(true), COMMAND_SAVES_QUIET_MS);
8312
+ let promptedFiles = null;
8296
8313
  let failure;
8297
8314
  const answer = () => {
8298
8315
  const { phase, commandUpdatePrompt, error } = store.getState();
8299
- if (commandUpdatePrompt !== null) runner.refreshCommands(true);
8316
+ if (commandUpdatePrompt !== promptedFiles) {
8317
+ promptedFiles = commandUpdatePrompt;
8318
+ if (promptedFiles) refreshCommands();
8319
+ else refreshCommands.cancel();
8320
+ }
8300
8321
  if (phase === "restart-required") {
8301
8322
  logger.info("Restarting to pick up the change");
8302
8323
  leaveToRun(runner.restart());
@@ -8317,6 +8338,7 @@ async function runPlain(store, runner, input) {
8317
8338
  try {
8318
8339
  await runner.run();
8319
8340
  } finally {
8341
+ refreshCommands.cancel();
8320
8342
  store.off("change", answer);
8321
8343
  }
8322
8344
  if (failure) throw failure;
@@ -8344,6 +8366,7 @@ var DevCommand = class extends BaseCommand {
8344
8366
  try {
8345
8367
  var _usingCtx$2 = _usingCtx();
8346
8368
  _usingCtx$2.u(DevSignals.own(() => void runner.quit()));
8369
+ _usingCtx$2.u(routeConsoleToLogs());
8347
8370
  await (isInteractive() ? this.runDevApp(store, runner, stateFolder) : runPlain(store, runner, process.stdin));
8348
8371
  } catch (_) {
8349
8372
  _usingCtx$2.e = _;
@@ -8358,17 +8381,13 @@ var DevCommand = class extends BaseCommand {
8358
8381
  process.exit();
8359
8382
  });
8360
8383
  }
8361
- async write(text) {
8362
- return new Promise((resolve) => {
8363
- process.stdout.write(text, () => {
8364
- resolve();
8365
- });
8366
- });
8367
- }
8368
8384
  async printLogLocation() {
8369
- await this.write(`${WORDMARK} dev stopped. logs: logs/\n`);
8385
+ this.logger.info(`${WORDMARK} dev stopped. logs: logs/`);
8370
8386
  const report = profileReport();
8371
- if (report !== null) await this.write(`${report}\n`);
8387
+ if (report !== null) this.logger.info(report);
8388
+ await new Promise((resolve) => {
8389
+ process.stdout.write("", resolve);
8390
+ });
8372
8391
  }
8373
8392
  async runDevApp(store, runner, stateFolder) {
8374
8393
  let failure;
@@ -8917,7 +8936,7 @@ var MakeRunner = class MakeRunner {
8917
8936
  const output = template.output(name, project);
8918
8937
  const files = output.render(await new InputQuestions(prompter, answered).ask(output.inputs()));
8919
8938
  await steps.step("write", async () => {
8920
- for (const file of files) await writeNew(file);
8939
+ await Promise.all(files.map((file) => writeNew(file)));
8921
8940
  }, () => paint.mute(plural(files.length, "file")), () => files.map((file) => paint.path(file.path)));
8922
8941
  steps.line();
8923
8942
  steps.line(paint.mute(`Run ${paint.bold("seedcord codegen")}, or keep ${paint.bold("seedcord dev")} running, to type new routes.`));