create-seedcord 0.2.0 → 0.3.1

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/index.mjs CHANGED
@@ -1922,7 +1922,7 @@ const chalk = createChalk();
1922
1922
  const chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
1923
1923
 
1924
1924
  //#endregion
1925
- //#region ../../packages/errors/dist/SeedcordError-DnV6q4mB.mjs
1925
+ //#region ../../packages/errors/dist/SeedcordError-C3HkJAhQ.mjs
1926
1926
  /**
1927
1927
  * All Seedcord error codes.
1928
1928
  */
@@ -1959,6 +1959,8 @@ let SeedcordErrorCode = /* @__PURE__ */ function(SeedcordErrorCode) {
1959
1959
  SeedcordErrorCode[SeedcordErrorCode["LifecycleTaskTimeout"] = 1106] = "LifecycleTaskTimeout";
1960
1960
  /** A host whose startup failed was started again. */
1961
1961
  SeedcordErrorCode[SeedcordErrorCode["LifecycleRestartAfterFailure"] = 1107] = "LifecycleRestartAfterFailure";
1962
+ /** The configured shutdown deadline is zero, negative, or not finite. */
1963
+ SeedcordErrorCode[SeedcordErrorCode["LifecycleInvalidShutdownDeadline"] = 1108] = "LifecycleInvalidShutdownDeadline";
1962
1964
  /** Multiple Seedcord instances were created simultaneously. */
1963
1965
  SeedcordErrorCode[SeedcordErrorCode["CoreSingletonViolation"] = 1201] = "CoreSingletonViolation";
1964
1966
  /** Plugins cannot be mutated after the core has finished initializing. */
@@ -1983,22 +1985,32 @@ let SeedcordErrorCode = /* @__PURE__ */ function(SeedcordErrorCode) {
1983
1985
  SeedcordErrorCode[SeedcordErrorCode["CoreLifecycleUnavailable"] = 1211] = "CoreLifecycleUnavailable";
1984
1986
  /** `emit` was called on the bus. It reaches listeners and skips every subscriber. */
1985
1987
  SeedcordErrorCode[SeedcordErrorCode["CoreBusEmitUnavailable"] = 1212] = "CoreBusEmitUnavailable";
1986
- /** Interaction middleware decorated with disallowed event filters. */
1987
- SeedcordErrorCode[SeedcordErrorCode["DecoratorInteractionEventFilter"] = 1301] = "DecoratorInteractionEventFilter";
1988
+ /** A command decorator passed `'config'` while `commands.guilds` is empty. */
1989
+ SeedcordErrorCode[SeedcordErrorCode["CoreCommandGuildsEmpty"] = 1213] = "CoreCommandGuildsEmpty";
1990
+ /** Discord refused the command deploy for one guild. */
1991
+ SeedcordErrorCode[SeedcordErrorCode["CoreCommandGuildDeployFailed"] = 1214] = "CoreCommandGuildDeployFailed";
1992
+ /** A plugin was attached under a group name the bot already uses. */
1993
+ SeedcordErrorCode[SeedcordErrorCode["CorePluginGroupTaken"] = 1215] = "CorePluginGroupTaken";
1994
+ /** A plugin was attached at a name that holds a group of plugins. */
1995
+ SeedcordErrorCode[SeedcordErrorCode["CorePluginKeyHoldsGroup"] = 1216] = "CorePluginKeyHoldsGroup";
1996
+ /** A plugin key is empty, has an empty part, or carries more than one dot. */
1997
+ SeedcordErrorCode[SeedcordErrorCode["CorePluginKeyMalformed"] = 1217] = "CorePluginKeyMalformed";
1988
1998
  /** A command decorator attempted to re-register an existing command scope. */
1989
- SeedcordErrorCode[SeedcordErrorCode["DecoratorCommandAlreadyRegistered"] = 1302] = "DecoratorCommandAlreadyRegistered";
1999
+ SeedcordErrorCode[SeedcordErrorCode["DecoratorCommandAlreadyRegistered"] = 1301] = "DecoratorCommandAlreadyRegistered";
1990
2000
  /** A global command decorator specified guild IDs, which is not allowed. */
1991
- SeedcordErrorCode[SeedcordErrorCode["DecoratorCommandGlobalWithGuilds"] = 1303] = "DecoratorCommandGlobalWithGuilds";
2001
+ SeedcordErrorCode[SeedcordErrorCode["DecoratorCommandGlobalWithGuilds"] = 1302] = "DecoratorCommandGlobalWithGuilds";
1992
2002
  /** A guild command decorator omitted the required guild ID list. */
1993
- SeedcordErrorCode[SeedcordErrorCode["DecoratorCommandGuildWithoutGuilds"] = 1304] = "DecoratorCommandGuildWithoutGuilds";
2003
+ SeedcordErrorCode[SeedcordErrorCode["DecoratorCommandGuildWithoutGuilds"] = 1303] = "DecoratorCommandGuildWithoutGuilds";
1994
2004
  /** Middleware priority provided by the decorator was not a finite number. */
1995
- SeedcordErrorCode[SeedcordErrorCode["DecoratorInvalidMiddlewarePriority"] = 1305] = "DecoratorInvalidMiddlewarePriority";
2005
+ SeedcordErrorCode[SeedcordErrorCode["DecoratorInvalidMiddlewarePriority"] = 1304] = "DecoratorInvalidMiddlewarePriority";
1996
2006
  /** A WebhookLog subclass is missing its `@WebhookUrl` decorator. */
1997
- SeedcordErrorCode[SeedcordErrorCode["DecoratorWebhookUrlMissing"] = 1306] = "DecoratorWebhookUrlMissing";
2007
+ SeedcordErrorCode[SeedcordErrorCode["DecoratorWebhookUrlMissing"] = 1305] = "DecoratorWebhookUrlMissing";
2008
+ /** A middleware decorator was given an empty filter array. */
2009
+ SeedcordErrorCode[SeedcordErrorCode["DecoratorEmptyMiddlewareFilter"] = 1306] = "DecoratorEmptyMiddlewareFilter";
1998
2010
  /** Two interaction handlers registered the same route within a scope. */
1999
2011
  SeedcordErrorCode[SeedcordErrorCode["InteractionDuplicateRoute"] = 1401] = "InteractionDuplicateRoute";
2000
- /** Two different interaction middleware classes share a class name. */
2001
- SeedcordErrorCode[SeedcordErrorCode["InteractionDuplicateMiddleware"] = 1402] = "InteractionDuplicateMiddleware";
2012
+ /** Two different middleware classes share a class name. */
2013
+ SeedcordErrorCode[SeedcordErrorCode["DuplicateMiddleware"] = 1402] = "DuplicateMiddleware";
2002
2014
  /** A route manifest row gives an export name its module does not have. */
2003
2015
  SeedcordErrorCode[SeedcordErrorCode["InteractionRouteExportMissing"] = 1403] = "InteractionRouteExportMissing";
2004
2016
  /** A subscriber manifest row specifies an export that does not extend `Subscriber`. */
@@ -2019,17 +2031,17 @@ let SeedcordErrorCode = /* @__PURE__ */ function(SeedcordErrorCode) {
2019
2031
  SeedcordErrorCode[SeedcordErrorCode["CustomIdInvalidPrefix"] = 1601] = "CustomIdInvalidPrefix";
2020
2032
  /** A customId field name is integer-like, which JS would silently reorder. */
2021
2033
  SeedcordErrorCode[SeedcordErrorCode["CustomIdReservedFieldName"] = 1602] = "CustomIdReservedFieldName";
2022
- /** A oneOf() field was declared with no choices. */
2034
+ /** A oneOf() or someOf() field was declared with no choices. */
2023
2035
  SeedcordErrorCode[SeedcordErrorCode["CustomIdEmptyChoices"] = 1603] = "CustomIdEmptyChoices";
2024
2036
  /** An int() field was declared with min greater than max. */
2025
2037
  SeedcordErrorCode[SeedcordErrorCode["CustomIdInvalidBounds"] = 1604] = "CustomIdInvalidBounds";
2026
- /** A value passed to encode() is outside its field's allowed range. */
2027
- SeedcordErrorCode[SeedcordErrorCode["CustomIdValueOutOfRange"] = 1605] = "CustomIdValueOutOfRange";
2038
+ /** A field rejected the value given to encode(). */
2039
+ SeedcordErrorCode[SeedcordErrorCode["CustomIdValueRejected"] = 1605] = "CustomIdValueRejected";
2028
2040
  /** An encoded customId exceeds Discord's 100-character limit. */
2029
2041
  SeedcordErrorCode[SeedcordErrorCode["CustomIdWireTooLong"] = 1606] = "CustomIdWireTooLong";
2030
2042
  /** A field name is declared more than once in the same customId chain. */
2031
2043
  SeedcordErrorCode[SeedcordErrorCode["CustomIdDuplicateFieldName"] = 1607] = "CustomIdDuplicateFieldName";
2032
- /** A component handler is missing its route decorator (\@ButtonRoute / \@ModalRoute / \@SelectMenuRoute). */
2044
+ /** A component handler is missing the route decorator that matches its base. */
2033
2045
  SeedcordErrorCode[SeedcordErrorCode["CustomIdHandlerRouteMissing"] = 1608] = "CustomIdHandlerRouteMissing";
2034
2046
  /** match() received a decoded route with no matching arm. */
2035
2047
  SeedcordErrorCode[SeedcordErrorCode["CustomIdMatchArmMissing"] = 1609] = "CustomIdMatchArmMissing";
@@ -2053,6 +2065,12 @@ let SeedcordErrorCode = /* @__PURE__ */ function(SeedcordErrorCode) {
2053
2065
  SeedcordErrorCode[SeedcordErrorCode["ModalFieldEmpty"] = 1618] = "ModalFieldEmpty";
2054
2066
  /** A channel select field picked a channel outside the types getSelectedChannels() allows. */
2055
2067
  SeedcordErrorCode[SeedcordErrorCode["ModalFieldChannelType"] = 1619] = "ModalFieldChannelType";
2068
+ /** A customId was minted under an older shape of the same definition. */
2069
+ SeedcordErrorCode[SeedcordErrorCode["CustomIdWireStale"] = 1620] = "CustomIdWireStale";
2070
+ /** A customId wire is corrupt, truncated, or was minted by a different definition. */
2071
+ SeedcordErrorCode[SeedcordErrorCode["CustomIdWireInvalid"] = 1621] = "CustomIdWireInvalid";
2072
+ /** `dispatch.require()` was called for a key nothing wrote on this dispatch. */
2073
+ SeedcordErrorCode[SeedcordErrorCode["DispatchStateMissing"] = 1622] = "DispatchStateMissing";
2056
2074
  /** A Cooldown gate was given a duration string that is not a well-formed positive duration. */
2057
2075
  SeedcordErrorCode[SeedcordErrorCode["GateInvalidCooldownDuration"] = 1701] = "GateInvalidCooldownDuration";
2058
2076
  /** A paginator source was given a perPage that is not a positive integer. */
@@ -2214,6 +2232,7 @@ const messages = {
2214
2232
  [1105]: (phase, failures) => `Phase ${phase} completed with ${failures} failed task${failures === 1 ? "" : "s"}.`,
2215
2233
  [1106]: (taskName, timeout) => `Task "${taskName}" timed out after ${timeout}ms.`,
2216
2234
  [1107]: () => "Startup failed and this host cannot start again. Construct a new instance.",
2235
+ [1108]: (declared) => `lifecycle.shutdownDeadline is ${declared}. Pass a positive number of milliseconds, or omit it for the default.`,
2217
2236
  [1201]: () => "Seedcord can only be instantiated once. Use the existing instance instead.",
2218
2237
  [1202]: () => "Cannot attach a plugin after initialization.",
2219
2238
  [1203]: (key) => `Plugin with key "${key}" already exists.`,
@@ -2221,19 +2240,24 @@ const messages = {
2221
2240
  [1205]: (controllerName, pathKind) => `${controllerName} was instantiated without a ${pathKind} path.`,
2222
2241
  [1206]: (file) => `${file} threw while importing.`,
2223
2242
  [1207]: (dir) => `${dir} could not be read.`,
2243
+ [1215]: (head, key) => `${paint.sky(head)} is already taken on this bot, so ${paint.sky(key)} cannot nest under it. Pick another group name.`,
2244
+ [1217]: (key, reason) => `${paint.sky(key)} ${reason} Write a group and a plugin name around one dot, like 'services.users'.`,
2245
+ [1216]: (key) => `${paint.sky(key)} already holds a group of plugins. Attach this one under a name of its own.`,
2224
2246
  [1208]: (key) => `Plugin key "${key}" is a channel the framework logs on. Pick another key.`,
2225
2247
  [1209]: () => "The bot's application id resolves during startup. You read it before that. Read it inside a handler, inside a plugin's ready(), or after start() resolves.",
2226
2248
  [1210]: (accessor, key) => `${accessor}.${key} has no value yet. ${accessor} fills during startup, and a read at the top of a file runs before that.`,
2227
2249
  [1211]: (accessor) => `core.${accessor}.addTask() does not work here. This bot was built with createSeedcord() whose build never runs startup or shutdown. Your task would never run. Do the work inside your handler instead. To use startup and shutdown, run the bot on node with new Seedcord(config).start().`,
2228
2250
  [1212]: (event) => `core.bus.emit('${event}') would reach your on() listeners and skip every Subscriber class. Call core.bus.publish('${event}', data) to run both.`,
2229
- [1301]: () => "Interaction middleware cannot specify event filters.",
2230
- [1302]: (commandName, existingScope, requestedScope) => `Command "${commandName}" is already registered as a "${existingScope}" command and cannot be re-registered as a "${requestedScope}" command.`,
2231
- [1303]: () => "RegisterCommand(\"global\") cannot have guilds specified.",
2232
- [1304]: () => "RegisterCommand(\"guild\") requires a non-empty guilds array.",
2233
- [1305]: () => "Middleware priority must be a finite number.",
2234
- [1306]: (className) => `${className} extends WebhookLog and needs a @WebhookUrl decorator naming its env var.`,
2251
+ [1213]: (commandName) => `${paint.sky(commandName)} registers to the 'config' guilds while commands.guilds is empty.\nList the ids under commands.guilds, or pass them to @RegisterCommand('guild', [...]).`,
2252
+ [1214]: (guildId) => `Discord refused the command deploy for guild ${paint.sky(guildId)}.\nCheck that the id is right, and that your bot is in that server.`,
2253
+ [1301]: (commandName, existingCall, requestedCall) => `${paint.sky(commandName)} is registered twice, first with ${existingCall}, then with ${requestedCall}. Keep one.`,
2254
+ [1302]: () => "RegisterCommand(\"global\") cannot have guilds specified.",
2255
+ [1303]: () => "RegisterCommand(\"guild\") requires a non-empty guilds array.",
2256
+ [1304]: () => "Middleware priority must be a finite number.",
2257
+ [1305]: (className) => `${className} extends WebhookLog and needs a @WebhookUrl decorator naming its env var.`,
2258
+ [1306]: (key) => `\`${key}\` was given an empty array. Drop the key to run the middleware on everything.`,
2235
2259
  [1401]: (route, first, second) => `Two interaction handlers resolve to the same route \`${route}\`. Registered by ${first} and ${second}. Rename one.`,
2236
- [1402]: (name) => `Two different interaction middleware classes share the name \`${name}\`. Rename one so they do not collide.`,
2260
+ [1402]: (name) => `Two different middleware classes share the name \`${name}\`. Rename one so they do not collide.`,
2237
2261
  [1403]: (route, exportName, from) => `Route \`${route}\` loads \`${exportName}\` from ${from}, which exports no such name.`,
2238
2262
  [1404]: (keys, exportName, from) => `Subscriber row for \`${keys}\` loads \`${exportName}\` from ${from}, which does not extend Subscriber.`,
2239
2263
  [1405]: (route, from) => `Route \`${route}\` failed to import ${from}.`,
@@ -2244,13 +2268,15 @@ const messages = {
2244
2268
  [1505]: (method, routeId) => `The interaction callback for ${paint.sky(`${method}()`)} returned no message. (route ${paint.mute(routeId)})`,
2245
2269
  [1601]: (prefix) => `customId prefix ${JSON.stringify(prefix)} must be a non-empty string without a colon or control character.`,
2246
2270
  [1602]: (field) => `customId field name ${JSON.stringify(field)} is integer-like, which JS reorders. Use a non-numeric name.`,
2247
- [1603]: (field) => `customId field ${JSON.stringify(field)} uses oneOf() with no choices.`,
2271
+ [1603]: (field, method) => `customId field ${JSON.stringify(field)} uses ${method}() with no choices. Make the field nullable or provide at least one choice.`,
2248
2272
  [1604]: (field, min, max) => `customId field ${JSON.stringify(field)} has min ${min} greater than max ${max}.`,
2249
- [1605]: (field, value) => `customId field ${JSON.stringify(field)} got value ${value} outside its allowed range.`,
2273
+ [1605]: (field, expected, value) => `customId field ${JSON.stringify(field)} expects ${expected}, got ${value}.`,
2250
2274
  [1606]: (length) => `Encoded customId is ${length} characters, Discord allows at most 100.`,
2251
2275
  [1607]: (field) => `customId field ${JSON.stringify(field)} is already defined in this chain.`,
2252
- [1608]: (className) => `${className} is missing its route decorator (@ButtonRoute, @ModalRoute, or @SelectMenuRoute).`,
2276
+ [1608]: (className) => `${className} is missing its route decorator. Add the one that matches its base, for example @ButtonRoute or @UserMenuRoute.`,
2253
2277
  [1609]: (prefix) => `match() has no arm for the decoded route ${JSON.stringify(prefix)}.`,
2278
+ [1620]: (prefix) => `customId ${JSON.stringify(prefix)} was minted under an older shape of this definition. Adding, removing, changing, or moving a field changes the layout hash.`,
2279
+ [1621]: (detail) => `customId could not be decoded. ${detail}.`,
2254
2280
  [1610]: (route) => `match() has no arm for the command route ${JSON.stringify(route)}.`,
2255
2281
  [1611]: (field) => `match() has no arm for the focused field ${JSON.stringify(field)}.`,
2256
2282
  [1612]: (event) => `match() has no arm for the event ${JSON.stringify(event)}.`,
@@ -2261,6 +2287,7 @@ const messages = {
2261
2287
  [1617]: (customId, kind, getter) => getter ? `Modal field ${JSON.stringify(customId)} holds ${kind}. Read it with ${getter}().` : `Modal field ${JSON.stringify(customId)} holds ${kind}. No getter reads that kind.`,
2262
2288
  [1618]: (customId) => `Modal field ${JSON.stringify(customId)} carries no selection. Build the component as required, or read it without the required argument.`,
2263
2289
  [1619]: (customId, picked, allowed) => `Modal field ${JSON.stringify(customId)} picked a ${picked} channel. This read allows ${allowed}.`,
2290
+ [1622]: (key) => `Nothing set \`${key}\` on this dispatch. Check that the middleware writing it is registered and that its filter covers this dispatch.`,
2264
2291
  [1701]: (input) => `Cooldown duration ${JSON.stringify(input)} is not valid. Pass a number of seconds or a duration string like '30m', '24h', or '500ms'.`,
2265
2292
  [1801]: (perPage) => `perPage must be a positive integer, got ${perPage}.`,
2266
2293
  [1802]: (count) => `A control row holds at most 5 buttons, got ${count}.`,
@@ -2348,8 +2375,8 @@ function resolveMessage(code, args) {
2348
2375
  function formatErrorName(name, _identifier, code) {
2349
2376
  return `${paint.coral.bold(name)}[${paint.mute(code)}]`;
2350
2377
  }
2351
- const kIdentifier = Symbol.for("seedcord.errors.identifier");
2352
- const CODED = Symbol.for("seedcord.errors.coded");
2378
+ const kIdentifier = Symbol.for("seedcord:errors:identifier");
2379
+ const CODED = Symbol.for("seedcord:errors:coded");
2353
2380
  function brand(prototype) {
2354
2381
  Object.defineProperty(prototype, CODED, { value: true });
2355
2382
  }
@@ -2438,7 +2465,7 @@ function isSeedcordError(error, type, code) {
2438
2465
 
2439
2466
  //#endregion
2440
2467
  //#region src/cli/banner.ts
2441
- function banner(version = "0.2.0") {
2468
+ function banner(version = "0.3.1") {
2442
2469
  const wordmark = `${paint.flesh.bold("seed")}${paint.rind.bold("cord")}${paint.mute(" create")}`;
2443
2470
  if (version === void 0) return wordmark;
2444
2471
  return `${wordmark}${paint.pith(` • v${version}`)}`;
@@ -3567,11 +3594,11 @@ const CANCELLED = {
3567
3594
  };
3568
3595
  function reportFailure(error) {
3569
3596
  if (isSeedcordError(error, void 0, SeedcordErrorCode.CreateCancelled)) return CANCELLED;
3570
- const removed = isSeedcordError(error, void 0, SeedcordErrorCode.CreateStepFailed);
3597
+ const kept = isSeedcordError(error, void 0, SeedcordErrorCode.CreateStepFailed);
3571
3598
  return {
3572
3599
  code: 1,
3573
3600
  message: isSeedcordError(error) || Error.isError(error) ? error.message : String(error),
3574
- closing: removed ? "Nothing was kept." : "Nothing was created."
3601
+ closing: kept ? "Project kept. Run the command manually." : "Nothing was created."
3575
3602
  };
3576
3603
  }
3577
3604
 
@@ -11160,6 +11187,7 @@ async function scaffold(input, run) {
11160
11187
  const parent = dirname(input.target);
11161
11188
  await mkdir(parent, { recursive: true });
11162
11189
  const plan = gitPlanFrom(await probeGit(parent), input.git);
11190
+ let written = false;
11163
11191
  try {
11164
11192
  const context = buildContext(input.answers, {
11165
11193
  developerUsername: plan.developerUsername,
@@ -11173,6 +11201,7 @@ async function scaffold(input, run) {
11173
11201
  await mkdir(input.target, { recursive: true });
11174
11202
  await writeTree(input.target, await renderTemplates(input.templatesRoot, context));
11175
11203
  });
11204
+ written = true;
11176
11205
  if (input.install) await runInstallSteps(input, run, context.isGateway);
11177
11206
  else {
11178
11207
  steps.skip("Dependencies installed");
@@ -11187,11 +11216,13 @@ async function scaffold(input, run) {
11187
11216
  gitNotice
11188
11217
  };
11189
11218
  } catch (error) {
11190
- await rm(input.target, {
11191
- recursive: true,
11192
- force: true
11193
- });
11194
- if (existed) await mkdir(input.target, { recursive: true });
11219
+ if (!written) {
11220
+ await rm(input.target, {
11221
+ recursive: true,
11222
+ force: true
11223
+ });
11224
+ if (existed) await mkdir(input.target, { recursive: true });
11225
+ }
11195
11226
  throw error;
11196
11227
  }
11197
11228
  }