seedcord 0.21.3 → 0.21.5

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/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  <div align="center">
19
19
 
20
- [![npm](https://img.shields.io/npm/v/seedcord?style=flat-square&logo=npm&logoColor=c8341f&label=&labelColor=1f1f1f&color=c8341f)](https://www.npmjs.com/package/seedcord) [![node](https://img.shields.io/node/v/seedcord?style=flat-square&label=node&labelColor=1f1f1f&color=4d7d33)](https://nodejs.org) [![license](https://img.shields.io/npm/l/seedcord?style=flat-square&label=license&labelColor=1f1f1f&color=f8f6e8)](LICENSE)
20
+ [![npm](https://img.shields.io/npm/v/seedcord?style=flat-square&label=npm&labelColor=1f1f1f&color=c8341f)](https://www.npmjs.com/package/seedcord) [![node](https://img.shields.io/node/v/seedcord?style=flat-square&label=node&labelColor=1f1f1f&color=4d7d33)](https://nodejs.org) [![bun](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fseedcord%2Fseedcord%2Fnext%2Fcli%2Fseedcord%2Fpackage.json&query=%24.engines.bun&style=flat-square&label=bun&labelColor=1f1f1f&color=fbf0df)](https://bun.com) [![license](https://img.shields.io/npm/l/seedcord?style=flat-square&label=license&labelColor=1f1f1f&color=f8f6e8)](LICENSE)
21
21
 
22
22
  </div>
23
23
 
package/bin/seedcord.mjs CHANGED
@@ -5,28 +5,49 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
5
5
 
6
6
  const here = dirname(fileURLToPath(import.meta.url));
7
7
 
8
- function declaredNodeRange() {
8
+ function declaredEngines() {
9
9
  try {
10
10
  const pkg = JSON.parse(readFileSync(resolve(here, '../package.json'), 'utf8'));
11
- return pkg.engines?.node ?? '';
11
+ return pkg.engines ?? {};
12
12
  } catch {
13
- return '';
13
+ return {};
14
14
  }
15
15
  }
16
16
 
17
- // importing core's own check here would load the code this guards
18
- function unsupportedNodeRange() {
19
- const range = declaredNodeRange();
17
+ function parseVersion(text) {
18
+ const [withoutBuild = ''] = text.replace(/^v/, '').split('+');
19
+ const [release = '', ...prerelease] = withoutBuild.split('-');
20
+ const parts = release.split('.').map(Number);
21
+ return parts.every(Number.isInteger) ? { parts, prerelease: prerelease.length > 0 } : undefined;
22
+ }
23
+
24
+ // semver ranks 1.4.2-canary.1 below 1.4.2
25
+ function meetsMinimum(required, running) {
26
+ const length = Math.max(required.parts.length, running.parts.length);
27
+ for (let index = 0; index < length; index++) {
28
+ const wanted = required.parts[index] ?? 0;
29
+ const got = running.parts[index] ?? 0;
30
+ if (got !== wanted) return got > wanted;
31
+ }
32
+ return !running.prerelease;
33
+ }
34
+
35
+ // importing core's assertDeclaredRuntime here would load the code this guards
36
+ function unsupportedRuntime() {
37
+ const engines = declaredEngines();
38
+ const { bun, node } = process.versions;
39
+ const runtime =
40
+ bun === undefined
41
+ ? { name: 'Node', range: engines.node ?? '', running: node }
42
+ : { name: 'Bun', range: engines.bun ?? '', running: bun };
20
43
 
21
- const required = new RegExp(String.raw`^>=(\d+)(?:\.(\d+))?`).exec(range.replaceAll(/\s/g, ''));
22
- const current = /^v?(\d+)\.(\d+)/.exec(process.version);
23
- if (!required || !current) return null;
44
+ const range = runtime.range.replaceAll(/\s/g, '');
45
+ if (!range.startsWith('>=')) return undefined;
24
46
 
25
- const requiredMinor = required[2] ?? '0';
26
- const meets =
27
- Number(current[1]) > Number(required[1]) ||
28
- (Number(current[1]) === Number(required[1]) && Number(current[2]) >= Number(requiredMinor));
29
- return meets ? null : range;
47
+ const required = parseVersion(range.slice('>='.length));
48
+ const running = parseVersion(runtime.running);
49
+ if (!required || !running || meetsMinimum(required, running)) return undefined;
50
+ return runtime;
30
51
  }
31
52
 
32
53
  async function run() {
@@ -41,10 +62,12 @@ async function run() {
41
62
  await import(pathToFileURL(srcEntry).href);
42
63
  }
43
64
 
44
- const unsupported = unsupportedNodeRange();
65
+ const unsupported = unsupportedRuntime();
45
66
  if (unsupported) {
46
67
  // eslint-disable-next-line no-console -- the bin has no logger
47
- console.error(`seedcord requires Node ${unsupported} and this process runs ${process.version}.`);
68
+ console.error(
69
+ `seedcord requires ${unsupported.name} ${unsupported.range} but this process runs ${unsupported.running}.`
70
+ );
48
71
  process.exit(1);
49
72
  }
50
73
 
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { n as SEEDCORD_CONFIG_FILENAMES, t as version } from "./src-CUR3x9pA.mjs";
2
- import { createRequire, findPackageJSON } from "node:module";
1
+ import { n as SEEDCORD_CONFIG_FILENAMES, t as version } from "./src-B41FGgG4.mjs";
2
+ import { createRequire } from "node:module";
3
3
  import { Command } from "@commander-js/extra-typings";
4
4
  import { LEVEL_COLOR, Logger, LoggerChannelRegistry } from "@seedcord/logger";
5
5
  import { formatBody, installNodeDefaults } from "@seedcord/logger/node";
@@ -31,8 +31,6 @@ import process$1 from "node:process";
31
31
  import { assertNever } from "@seedcord/utils";
32
32
  import { settleWithin } from "@seedcord/core/node/internal";
33
33
  import { createServer, createServerModuleRunner, defineConfig, mergeConfig } from "vite";
34
- import { EvaluatedModules } from "vite/module-runner";
35
- import tsconfigPaths from "vite-tsconfig-paths";
36
34
  import { minimatch } from "minimatch";
37
35
  import { createServer as createServer$1 } from "node:net";
38
36
 
@@ -967,17 +965,17 @@ var CleanRunner = class CleanRunner {
967
965
  async fetchBotGuilds(rest) {
968
966
  const guilds = [];
969
967
  let after;
970
- for (;;) {
968
+ let page;
969
+ do {
971
970
  const query = new URLSearchParams({ limit: String(GUILD_PAGE) });
972
971
  if (after) query.set("after", after);
973
- const page = await rest.get(Routes.userGuilds(), { query });
972
+ page = await rest.get(Routes.userGuilds(), { query });
974
973
  for (const guild of page) guilds.push({
975
974
  id: guild.id,
976
975
  name: guild.name
977
976
  });
978
977
  after = page.at(-1)?.id;
979
- if (page.length < GUILD_PAGE || !after) break;
980
- }
978
+ } while (page.length === GUILD_PAGE && after);
981
979
  return guilds;
982
980
  }
983
981
  async fetchGlobalNames(rest, appId) {
@@ -2887,7 +2885,6 @@ var DevStore = class extends TypedEventEmitter {
2887
2885
  case "module-loading":
2888
2886
  case "module-loaded":
2889
2887
  case "module-error":
2890
- case "file-change":
2891
2888
  case "ready": break;
2892
2889
  default: assertNever(event);
2893
2890
  }
@@ -3080,11 +3077,17 @@ var DevSession = class {
3080
3077
  //#endregion
3081
3078
  //#region src/commands/dev/runtime/HmrPlugin.ts
3082
3079
  const DEBOUNCE_MS = 250;
3080
+ const TYPE_COLOR = {
3081
+ create: paint.mint,
3082
+ createDir: paint.mint,
3083
+ update: paint.sky,
3084
+ delete: paint.coral,
3085
+ deleteDir: paint.coral
3086
+ };
3083
3087
  var HmrPlugin = class extends TypedEventEmitter {
3084
3088
  config;
3085
3089
  logger;
3086
3090
  lastUpdate = /* @__PURE__ */ new Map();
3087
- awaitingCreateEcho = /* @__PURE__ */ new Set();
3088
3091
  server = null;
3089
3092
  dynamicRestartPatterns = /* @__PURE__ */ new Set();
3090
3093
  get hot() {
@@ -3099,10 +3102,13 @@ var HmrPlugin = class extends TypedEventEmitter {
3099
3102
  this.logger = new Logger("HMR", { channel: "hmr" });
3100
3103
  }
3101
3104
  get plugin() {
3105
+ const onHotUpdate = this.hotUpdate.bind(this);
3102
3106
  return {
3103
3107
  name: "seedcord:hmr",
3104
3108
  configureServer: this.configureServer.bind(this),
3105
- hotUpdate: this.hotUpdate.bind(this)
3109
+ hotUpdate(ctx) {
3110
+ return onHotUpdate(this.environment, ctx);
3111
+ }
3106
3112
  };
3107
3113
  }
3108
3114
  sendRefreshCommands(shouldRefresh) {
@@ -3110,10 +3116,8 @@ var HmrPlugin = class extends TypedEventEmitter {
3110
3116
  }
3111
3117
  configureServer(server) {
3112
3118
  this.server = server;
3113
- server.watcher.on("add", (file) => this.handleFileEvent(file, "create"));
3114
- server.watcher.on("unlink", (file) => this.handleFileEvent(file, "delete"));
3115
- server.watcher.on("addDir", (file) => this.handleFileEvent(file, "createDir"));
3116
- server.watcher.on("unlinkDir", (file) => this.handleFileEvent(file, "deleteDir"));
3119
+ server.watcher.on("addDir", (dir) => this.handleDirEvent(dir, "createDir"));
3120
+ server.watcher.on("unlinkDir", (dir) => this.handleDirEvent(dir, "deleteDir"));
3117
3121
  server.watcher.add(this.config.configFile);
3118
3122
  server.watcher.on("change", (file) => this.handleChange(file));
3119
3123
  this.dev?.on("seedcord:commands-update-prompt", (data) => {
@@ -3134,14 +3138,12 @@ var HmrPlugin = class extends TypedEventEmitter {
3134
3138
  });
3135
3139
  }
3136
3140
  isDebounced(file, type) {
3137
- if (this.justSaw(file, type)) return true;
3138
- this.lastUpdate.set(`${file}::${type}`, Date.now());
3141
+ const key = `${file}::${type}`;
3142
+ const last = this.lastUpdate.get(key);
3143
+ if (last !== void 0 && Date.now() - last < DEBOUNCE_MS) return true;
3144
+ this.lastUpdate.set(key, Date.now());
3139
3145
  return false;
3140
3146
  }
3141
- justSaw(file, type) {
3142
- const last = this.lastUpdate.get(`${file}::${type}`);
3143
- return last !== void 0 && Date.now() - last < DEBOUNCE_MS;
3144
- }
3145
3147
  handleChange(file) {
3146
3148
  if (!this.isCriticalFile(file) || this.isDebounced(file, "update")) return;
3147
3149
  this.reportRestartRequired(file);
@@ -3151,78 +3153,56 @@ var HmrPlugin = class extends TypedEventEmitter {
3151
3153
  this.logger.warn(`${paint.coral("Critical file changed:")} ${paint.sky.bold(relPath)}. Restart required.`);
3152
3154
  this.emit("event", { type: "restart-required" });
3153
3155
  }
3154
- handleFileEvent(file, type) {
3155
- if (this.isDebounced(file, type)) return;
3156
- if (type === "create") this.awaitingCreateEcho.add(file);
3157
- const relPath = relative(process.cwd(), file);
3158
- const typeColor = type === "create" || type === "createDir" ? paint.mint : type === "delete" || type === "deleteDir" ? paint.coral : paint.sky;
3159
- this.logger.trace(`${typeColor(type.toUpperCase())} ${paint.mute(relPath)}`);
3160
- const payload = {
3161
- file,
3162
- type,
3156
+ handleDirEvent(dir, type) {
3157
+ if (this.isDebounced(dir, type)) return;
3158
+ this.send({
3159
+ file: dir,
3160
+ type
3161
+ });
3162
+ }
3163
+ send(event) {
3164
+ const relPath = relative(process.cwd(), event.file);
3165
+ this.logger.trace(`${TYPE_COLOR[event.type](event.type.toUpperCase())} ${paint.mute(relPath)}`);
3166
+ this.dev?.send("seedcord:hmr", {
3167
+ ...event,
3163
3168
  rollback: this.config.hmr?.rollback ?? true
3164
- };
3165
- this.dev?.send("seedcord:hmr", payload);
3169
+ });
3166
3170
  }
3167
- hotUpdate(ctx) {
3168
- const { file, modules, server } = ctx;
3169
- const type = "update";
3170
- if (this.awaitingCreateEcho.delete(file) && this.justSaw(file, "create") || this.isDebounced(file, type)) return [];
3171
- const relPath = relative(process.cwd(), file);
3172
- this.logger.trace(`${paint.sky(type.toUpperCase())} ${paint.mute(relPath)}`);
3171
+ hotUpdate(environment, ctx) {
3172
+ const { type, file, modules } = ctx;
3173
+ if (environment.name !== "ssr" || this.isDebounced(file, type)) return [];
3173
3174
  if (this.isCriticalFile(file)) {
3174
3175
  this.reportRestartRequired(file);
3175
3176
  return [];
3176
3177
  }
3177
- const moduleGraph = server.moduleGraph;
3178
- const fileModules = moduleGraph.getModulesByFile(file);
3179
- const allModules = fileModules ? [...fileModules] : [];
3180
- const combinedModules = /* @__PURE__ */ new Set([...modules, ...allModules]);
3181
- const affectedModules = this.getAffectedModules([...combinedModules]);
3182
- const filesToInvalidate = /* @__PURE__ */ new Set([file, ...affectedModules]);
3183
- for (const fileToInvalidate of filesToInvalidate) {
3184
- const mods = moduleGraph.getModulesByFile(fileToInvalidate);
3185
- if (mods) for (const mod of mods) moduleGraph.invalidateModule(mod);
3186
- }
3187
- this.emit("event", {
3188
- type: "file-change",
3189
- path: file
3190
- });
3191
- const payload = {
3178
+ const { moduleGraph } = environment;
3179
+ const affectedModules = affectedFiles(file, modules);
3180
+ for (const target of affectedModules) for (const mod of moduleGraph.getModulesByFile(target) ?? []) moduleGraph.invalidateModule(mod);
3181
+ this.send({
3192
3182
  file,
3193
3183
  type,
3194
- affectedModules,
3195
- rollback: this.config.hmr?.rollback ?? true
3196
- };
3197
- this.dev?.send("seedcord:hmr", payload);
3184
+ affectedModules
3185
+ });
3198
3186
  return [];
3199
3187
  }
3200
3188
  isCriticalFile(file) {
3201
- const root = this.config.root;
3189
+ const { root, configFile, entry, instance } = this.config;
3202
3190
  const relPath = relative(root, file);
3203
- if (this.config.hmr?.restart) {
3204
- for (const pattern of this.config.hmr.restart) if (minimatch(relPath, pattern)) return true;
3205
- }
3206
- for (const pattern of this.dynamicRestartPatterns) if (minimatch(relPath, pattern)) return true;
3207
- if (file === this.config.configFile || file.endsWith("package.json") || file.endsWith("tsconfig.json") || file.endsWith(".env")) return true;
3208
- const entryPath = resolve(root, this.config.entry);
3209
- const instancePath = resolve(root, this.config.instance);
3210
- if (file === entryPath || file === instancePath) return true;
3211
- return false;
3212
- }
3213
- getAffectedModules(modules) {
3214
- const affected = /* @__PURE__ */ new Set();
3215
- const seen = /* @__PURE__ */ new Set();
3216
- const traverse = (mod) => {
3217
- if (!mod.file || seen.has(mod.file)) return;
3218
- seen.add(mod.file);
3219
- affected.add(mod.file);
3220
- mod.importers.forEach(traverse);
3221
- };
3222
- modules.forEach(traverse);
3223
- return [...affected];
3191
+ return [...this.config.hmr?.restart ?? [], ...this.dynamicRestartPatterns].some((pattern) => minimatch(relPath, pattern)) || file === configFile || file.endsWith("package.json") || file.endsWith("tsconfig.json") || file.endsWith(".env") || file === resolve(root, entry) || file === resolve(root, instance);
3224
3192
  }
3225
3193
  };
3194
+ function affectedFiles(file, modules) {
3195
+ const files = /* @__PURE__ */ new Set([file]);
3196
+ const visited = /* @__PURE__ */ new Set();
3197
+ const visit = (mod) => {
3198
+ if (visited.has(mod)) return;
3199
+ visited.add(mod);
3200
+ if (mod.file) files.add(mod.file);
3201
+ mod.importers.forEach(visit);
3202
+ };
3203
+ modules.forEach(visit);
3204
+ return [...files];
3205
+ }
3226
3206
 
3227
3207
  //#endregion
3228
3208
  //#region src/commands/dev/runtime/seedcordDependents.ts
@@ -3241,12 +3221,14 @@ function dependencyNames(manifestPath, fields) {
3241
3221
  });
3242
3222
  }
3243
3223
  function installedManifest(name, fromManifest) {
3244
- try {
3245
- return findPackageJSON(name, pathToFileURL(fromManifest));
3246
- } catch (error) {
3247
- if (Error.isError(error) && "code" in error && error.code === "ERR_MODULE_NOT_FOUND") return void 0;
3248
- throw error;
3249
- }
3224
+ let dir = dirname(fromManifest);
3225
+ let checked;
3226
+ do {
3227
+ const candidate = join(dir, "node_modules", name, "package.json");
3228
+ if (existsSync(candidate)) return realpathSync(candidate);
3229
+ checked = dir;
3230
+ dir = dirname(dir);
3231
+ } while (dir !== checked);
3250
3232
  }
3251
3233
  function isSeedcordPackage(name) {
3252
3234
  return name.startsWith("@seedcord/");
@@ -3295,6 +3277,7 @@ function logsIgnore(root) {
3295
3277
  return (path) => path === logs || path.startsWith(logs + sep);
3296
3278
  }
3297
3279
  var vite_config_default = defineConfig({
3280
+ resolve: { tsconfigPaths: true },
3298
3281
  server: {
3299
3282
  middlewareMode: true,
3300
3283
  hmr: true,
@@ -3353,7 +3336,6 @@ var ViteDevRuntime = class {
3353
3336
  viteServer = null;
3354
3337
  moduleRunner = null;
3355
3338
  eventHandler = null;
3356
- evaluatedModules = null;
3357
3339
  hmrPlugin = null;
3358
3340
  async start(context) {
3359
3341
  this.context = context;
@@ -3372,29 +3354,17 @@ var ViteDevRuntime = class {
3372
3354
  configFile: false,
3373
3355
  server: { watch: { ignored: [logsIgnore(projectRoot)] } },
3374
3356
  ssr: { noExternal: seedcordDependents(projectDir) },
3375
- plugins: [tsconfigPaths({ root: projectDir }), hmrPlugin.plugin]
3357
+ plugins: [hmrPlugin.plugin]
3376
3358
  });
3377
3359
  this.viteServer = await createServer(config);
3378
- this.evaluatedModules = new EvaluatedModules();
3379
- this.moduleRunner = createServerModuleRunner(this.viteServer.environments.ssr, { evaluatedModules: this.evaluatedModules });
3380
- hmrPlugin.on("event", this.handleHmrEvent.bind(this));
3360
+ this.moduleRunner = createServerModuleRunner(this.viteServer.environments.ssr);
3361
+ hmrPlugin.on("event", this.emit.bind(this));
3381
3362
  this.emit({
3382
3363
  type: "module-loaded",
3383
3364
  path: projectRoot
3384
3365
  });
3385
3366
  this.emit({ type: "ready" });
3386
3367
  }
3387
- handleHmrEvent(event) {
3388
- if (event.type === "file-change") this.invalidateModule(event.path);
3389
- this.emit(event);
3390
- }
3391
- invalidateModule(file) {
3392
- const projectRoot = this.context?.config.root;
3393
- if (!projectRoot || !this.evaluatedModules) return;
3394
- const moduleId = toModuleId(projectRoot, file);
3395
- const moduleNode = this.evaluatedModules.getModuleById(moduleId);
3396
- if (moduleNode) this.evaluatedModules.invalidateModule(moduleNode);
3397
- }
3398
3368
  refreshCommands(shouldRefresh) {
3399
3369
  this.hmrPlugin?.sendRefreshCommands(shouldRefresh);
3400
3370
  }
@@ -3430,7 +3400,6 @@ var ViteDevRuntime = class {
3430
3400
  this.viteServer = null;
3431
3401
  }
3432
3402
  this.moduleRunner = null;
3433
- this.evaluatedModules = null;
3434
3403
  this.hmrPlugin = null;
3435
3404
  this.context = null;
3436
3405
  this.eventHandler = null;