@wolfstar/http-frameworkv4 → v5@wolfstar/http-frameworkv3 → v4@wolfstar/http-framework-i18n→@wolfstar/plugin-i18next@wolfstar/logger→@wolfstar/plugin-logger
Migrating from v4 to v5
::: info Current releases The v5 build defaults are stable in@wolfstar/http-framework@5.0.0. The matching developer tooling is
@wolfstar/cli@1.0.0.
:::
v5 is a small, mostly opt-in release. The only breaking change to the framework’s public API is the removal of the
previously-unannounced @wolfstar/http-framework/fetch submodule, replaced by a fetch() method on Client itself.
Everything else is either purely additive (experimental.enableNitro) or an internal error-handling change
(nostics diagnostics) that only matters to code that caught ConfigError/CliError by name.
Changes Included in v5
Upgrading the Packages
::: code-group[pnpm]
[npm]
[yarn]
[bun]
stars.config.* changes are required to move from v4 to v5 — the configuration shape is unchanged.
Replacing @wolfstar/http-framework/fetch with Client#fetch
The experimental, previously-unannounced @wolfstar/http-framework/fetch submodule is removed. Projects that imported
createFetchHandler, FetchHandler or FetchHandlerOptions from it to adapt Client to a Fetch-based runtime switch
to the new fetch() method on Client itself — a method on the instance you already have, rather than a separate
adapter module to import and wire up:
Client#fetch(request, options?) runs the exact same signature verification, routing and replies listen()’s
node:http server runs, without binding a port. The Discord public key given at construction is imported once and
reused across every call, the same lifetime listen() gives its own signing key — use it for anything that speaks
Fetch instead of node:http (Nitro, a Worker, Bun.serve, Deno.serve, Vite’s own dev middleware).
Building Through Nitro
experimental.enableNitro is now implemented: stars dev/stars build build and serve the bot through
Nitro v3’s own Vite plugin instead of refusing with EXPERIMENT_UNAVAILABLE. It is purely
opt-in and requires experimental.enableVite as well, since Nitro v3 is itself a Vite plugin rather than a separate
build step:
vite and nitro as devDependencies. stars build now produces build.outDir (.output by default
under Nitro, instead of dist) laid out for the configured preset rather than a node:http process; stars dev
rebuilds and restarts on every change, the same as the other build tools.
::: warning The entry’s default export changes
The generated Nitro server entry imports the entry file’s default export and calls .fetch(request) on it — the
entry must export the already-load()ed Client instance, not call listen():
resolve.tsconfigPaths is turned on automatically under Nitro (see
Nitro’s import alias guide), so a project’s own
tsconfig.json#paths/package.json imports aliases — including the ones stars prepare’s generated
.stars/tsconfig.json adds — keep working without a vite-tsconfig-paths plugin.
Catching Configuration and CLI Errors
ConfigError/ConfigErrorOptions (from @wolfstar/http-framework/config) and CliError/CliErrorOptions (from
@wolfstar/cli) are removed. Every stars.config.* validation and load failure, and every condition @wolfstar/cli
itself rejects, is now built from a catalog (configDiagnostics, cliDiagnostics, both still exported) and thrown as
a nostics Diagnostic — a stable, typed code with a why, an actionable
fix, and a docs link, instead of ad hoc code/hint/path/file fields:
.path is folded directly into the diagnostic’s message; the configuration file
that used to live on .file is now in .sources. @wolfstar/cli itself still renders these the same way it always
has (formatError/exitCodeOf keep their existing exports and behaviour) and still exits with code 2 for every
stars.config.* diagnostic and 3 for BUILD_FAILED, unchanged from v4 — this only matters for code that imported
ConfigError/CliError by name. See the configuration error reference and
CLI error reference for the full code catalogs.
Checklist
-
@wolfstar/http-frameworkupgraded to v5 and@wolfstar/cliupgraded to v1 -
createFetchHandler/FetchHandler/FetchHandlerOptionsimports from@wolfstar/http-framework/fetchreplaced withclient.fetch(request, options?) -
instanceof ConfigError/instanceof CliErrorchecks replaced withinstanceof Diagnostic(fromnostics) -
.path/.filereads on caught errors replaced with.message/.sources - Optional:
experimental.enableViteandexperimental.enableNitroconfigured,viteandnitroinstalled asdevDependencies, and the entry’s default export changed from callinglisten()to the loadedClientinstance
Migrating from v3 to v4
Current releasesThe v4 build defaults are stable in
@wolfstar/http-framework@4.0.1. The matching developer tooling is
@wolfstar/cli@0.6.0; projects generated by @wolfstar/create-http-framework@2.5.1 already use this layout.@wolfstar/http-framework are unchanged; the migration primarily consolidates development and build
configuration around stars.config.* and the stars CLI.
Changes Included in v4
Upgrade the Framework and Add the stars CLI
The developer workflow moves into a separate package, @wolfstar/cli, which ships the stars binary. The framework
itself keeps owning the configuration — the same split Nuxt has between nuxt/defineNuxtConfig and nuxi.
Creating stars.config.ts
Add a stars.config.{ts,mts,cts,js,mjs,cjs} file at the project root. defineConfig comes from the framework’s new
config subpath, not from the CLI:
entry falls back to the first of src/main.ts, src/main.js, src/index.ts,
src/index.js that exists. For a TypeScript entry, build.tool: 'auto' now selects tsdown; choose
build: { tool: 'tsc' } explicitly if the project must keep the TypeScript compiler as its emitter. A minimal v4
project can export defineConfig({}); future.compatibilityVersion: 4 is no longer necessary.
@wolfstar/http-framework/config is side-effect free — importing it, or a stars.config.ts that imports it, never
starts the bot. Invalid options raise a ConfigError carrying a stable code, the offending option path, the
file it came from, and an actionable hint; stars exits with code 2 on those.
The resolved configuration is readable from any tool, without depending on the CLI:
Replacing the package.json Scripts
The per-language, per-build-tool script wiring collapses into two commands that read stars.config.*:
tsc drop tsc-watch from their devDependencies — stars dev runs tsc -b --watch
itself. JavaScript projects drop node --watch src/main.js and keep no build script at all (build.tool: 'none').
start is unchanged: production still runs the built entry point directly, stars is a development-only tool.
Run stars prepare explicitly after installing development dependencies and before a standalone typecheck on a fresh
checkout. Do not put it in a root postinstall: production-only installs such as npm ci --omit=dev still run that
lifecycle script after omitting the development-only @wolfstar/cli, so the install would fail because stars is not
available. stars dev and stars build already regenerate the files they need.
Move tsdown Configuration into stars.config.ts
Compatibility version 4 uses stars.config.* as the only build configuration. A standalone tsdown.config.* or a
package.json#tsdown field now raises TSDOWN_CONFIG_FILE_UNSUPPORTED instead of being silently ignored.
Most bot projects can delete tsdown.config.ts: Stars supplies entries for every source file next to the main entry,
unbundled ESM output for Node, sourcemaps, treeshaking, external dependencies, the configured output directory and
extension, the project tsconfig, Nuxt-style aliases, auto imports, and a copy of src/locales in dist/locales.
Move only non-conventional overrides into the top-level tsdown block:
future: { compatibilityVersion: 3 }. In this legacy mode, Stars loads the standalone config and merges the
stars.config.ts tsdown block over it. Remove the old file and the compatibility override together when finished.
The New Framework Subpaths
v3 exposed a single entry point. The package now has three export subpaths:
No existing import changes: the root subpath keeps the same specifier and the same exports.
stars Commands
--config <file> points at a configuration file and --cwd <dir> changes the working directory; both work on every
command. stars --help and stars --version never load the configuration machinery, so they stay fast.
stars dev builds, starts the bot with STARS_DEV=1 and NODE_ENV=development, and restarts it after every successful build. Failed builds keep the previous
process alive and wait for the next change. On a terminal it renders an interactive UI (lifecycle, uptime, restart
reason, build state, URL, health, filtered logs, r restart, c clear, f/e filters, h help, q quit); it falls
back to plain prefixed lines with --no-tui, STARS_TUI=plain, in CI, or when stdout is not a TTY. Both modes honour
NO_COLOR and stop the bot cleanly on SIGINT/SIGTERM.
stars commands covers the gap the registry cannot: renamed or deleted commands stay deployed on Discord until
something removes them.
DISCORD_TOKEN and DISCORD_APPLICATION_ID (or APPLICATION_ID) from the environment or the project’s
.env, the same place the bot reads them from. Outside a terminal, clean refuses to run without --yes or --name.
Dev Loop Options
Threedev options round out the loop, all off by default except the log file:
dev.typecheckbrings back the type safety atsdownbuild skips.checkeristsc(watch mode),golar(golar tsc, watch mode),tsz(no watch mode, so re-run after every build), orauto— the default,golarwhen the project depends on it andtscotherwise. Type errors are reported without blocking builds or restarts.dev.tunnelexposes the interactions endpoint publicly:trueopens acloudflaredquick tunnel (a new hostname on every run), a string is an https URL you already serve and the CLI only probes.dev.tunnel.updateEndpointwrites that URL to the Discord application’sinteractions_endpoint_url— opt-in, because it edits a live application.dev.logFile(default.stars/dev.log) mirrors the session’s logs to disk, so a run can be read back once the terminal UI is gone.
dev.url needs no configuration: it is detected from HTTP_PORT (environment variable, src/.env*/.env*, or
dev.env) or 3000, the way Vite’s and Nuxt’s dev servers do, and localhost is swapped for 127.0.0.1 when that is
what is actually reachable. Set it explicitly only to override, e.g. dev: { url: 'http://192.168.1.5:3000' }.
Environment discovery now checks src/.env* as well as root .env* files. Conventional src/locales assets are
copied to dist/locales automatically and watched during development, so remove custom copy/watch hooks that only do
those jobs. In the TUI, press t to open or close a quick tunnel without setting dev.tunnel; keep dev.tunnel when
the tunnel should open automatically at startup.
Auto Imports
Nuxt-style auto imports make the framework’s exports and the project’s own modules usable without animport
statement. They are injected at build time by the autoImports() rolldown plugin, so they require the tsdown
build tool — tsc and none have no transform step to hook into. They are on by default with tsdown, and
imports: false turns them off.
Client, Message, Plugin and Store are never auto-imported, even when a preset exports them: the names are
generic enough that project code likely declares its own. Import them explicitly, as today.
Generated TypeScript Configuration
stars prepare now generates both the auto imports declaration and .stars/tsconfig.json. The generated config
contains the Sapphire base, extra-strict and decorator options, plus bundler settings aligned with Nitro. For tsdown
and Vite it also contains TypeScript paths matching ~/@ (the entry directory), ~~/@@ (the project root), and
custom filesystem aliases from stars.config.ts.
Replace manually duplicated compiler defaults, include entries and alias paths by extending it:
compilerOptions next to extends. An explicit include or compilerOptions.paths replaces
the inherited value, so remove those keys unless that is intentional. Do not edit .stars/tsconfig.json; stars dev
and stars build regenerate it. Run stars prepare explicitly before editor/typecheck use on a fresh checkout. Use
stars prepare --check in CI only after generation.
Plugin Registration and the Built-in Logger
Bundler builds now activate every@wolfstar/plugin-* package found in dependencies or optionalDependencies by
injecting its /register side-effect entry before the application entry. Remove matching manual imports such as:
tsdown and Vite builds. It deliberately ignores devDependencies; a runtime plugin must
be a runtime dependency. Projects using build.tool: 'tsc' or 'none' do not have a bundler transform and must keep
explicit /register imports.
The framework also provides container.logger without @wolfstar/logger. Remove the deprecated package and custom
setup module when it only installed the standard logger. Configure the built-in logger through the client when needed:
Ignoring .stars/
The CLI writes generated TypeScript configuration, the auto imports declaration and the dev log into a .stars/
directory at the project root. Add it to .gitignore:
Checklist
-
@wolfstar/http-frameworkupgraded to v4 and@wolfstar/cliadded as adevDependency - Development environment upgraded to Node.js 22 or newer
-
stars.config.tscreated withdefineConfigfrom@wolfstar/http-framework/config - Standalone
tsdown.config.*orpackage.json#tsdownremoved; custom options moved tostars.config.ts -
dev/buildscripts replaced withstars dev/stars build -
watch,watch:startand thetsc-watchdependency removed -
stars prepareruns before standalone typechecking on a fresh checkout, without a productionpostinstall -
generate:i18nreplaced withstars codegen, verified withstars codegen --check - The framework’s
hmrclient option disabled while developing withstars dev -
tsconfig.jsonextends./.stars/tsconfig.json; duplicated generated aliases/options removed - Redundant env discovery and
src/localescopy/watch hooks removed - Manual
@wolfstar/plugin-*/registerimports removed for bundler builds only - Deprecated
@wolfstar/loggersetup replaced with the built-incontainer.logger -
.stars/added to.gitignore -
stars infooutput reviewed — it prints the configuration exactly as the commands resolve it -
stars prepare, the project typecheck andstars buildpass - Optional:
dev.typecheck,dev.tunneland auto imports configured
Migrating to @wolfstar/plugin-i18next
@wolfstar/http-framework-i18n is deprecated. Its successor is
@wolfstar/plugin-i18next, an official plugin for
@wolfstar/http-framework that lives in the
wolfstar-project/plugins
repository. No further releases are planned for the old package.
The plugin keeps the same typed-key philosophy (T / FT, resolveKey, applyLocalizedBuilder) but replaces the
manual load() + init() bootstrap with the framework’s plugin lifecycle, and moves the loaded state onto
container.i18n.
Overview of the Changes
Swapping the Dependency
@wolfstar/http-framework is a peer dependency of the plugin, so keep it in your dependencies.
Bootstrap Moved to the Plugin Lifecycle
The old package required you to load the locales and initializei18next yourself, before registering commands:
register entrypoint before the client is created,
and move the configuration into the i18n client option:
Locales Directory Renamed to languages
The old package took whatever path you passed to load(); the plugin defaults to <root>/languages. Either rename the
directory or keep your own path via defaultLanguageDirectory.
The layout itself is unchanged: one directory per language, every nested .json file is a namespace.
Module Specifier Renamed
T, FT, resolveKey, resolveUserKey, getSupportedLanguageName, getSupportedUserLanguageName,
getSupportedLanguageT, getSupportedUserLanguageT, supportedLanguages, isSupportedDiscordLocale,
getLocalizedData, applyNameLocalizedBuilder, applyDescriptionLocalizedBuilder, applyLocalizedBuilder and
createSelectMenuChoiceName keep the same names and signatures. For most files the migration is a single
find-and-replace of the module specifier:
Removed APIs
New APIs
Per-Guild Languages
The old package could only read the locales Discord puts on the interaction payload. If you store a language per guild, you can now plug a resolver in and use the asynchronousfetch* helpers.
The resolver can be declared up-front as part of the i18n client option:
resolveKey and resolveUserKey stay synchronous and keep reading the interaction payload only, so existing call sites
do not change behaviour.
Hot Module Replacement
container.i18n.reloadResources() runs on every
change or deletion.
Upgrading i18next from 22 to 25
The plugin depends on i18next@^25. If your project pins i18next itself, bump it and review the
i18next migration notes. In practice the typed-key helpers absorb most
of the surface, but note that TFunction is now generic over namespace and key prefix, so explicitly annotated
TFunction variables may need their type arguments updated.
Checklist
-
@wolfstar/http-framework-i18nremoved frompackage.json -
@wolfstar/plugin-i18nextadded,@wolfstar/http-frameworkon^3.1.0or newer -
import '@wolfstar/plugin-i18next/register'is the first import of the entry point -
load()/init()/addFormatters()calls removed, options moved tonew Client({ i18n }) - Locales directory named
languages, ordefaultLanguageDirectoryset - Module specifiers updated across the codebase
-
getT/loadedLocalescall sites moved tocontainer.i18n
Migrating to @wolfstar/plugin-logger
@wolfstar/logger is deprecated. Replace it with
@wolfstar/plugin-logger, which
provides the same framework logger interface through the plugin lifecycle and adds support for multiple transports.
If console output is all you need, @wolfstar/http-framework already provides container.logger; remove the old
package without installing the plugin. Install @wolfstar/plugin-logger when you need transport configuration,
Sentry integration, or a Consola, Evlog, or Winston backend.
Overview of the Changes
The
ILogger methods and level ordering are unchanged: existing trace, debug, info, warn, error, and
fatal calls can keep their arguments.
Swapping the Dependency
dependencies, not devDependencies: it changes the logger at runtime. The backend integrations
are optional peer dependencies, so install only the ones used by your configured transports.
Moving Logger Setup into Client
Replace the manually constructed logger with the logger client option, and read the active instance from the
framework container:
preGenericsInitialization, before the rest of the client initializes. An
explicit logger.instance is preserved, so applications with their own ILogger implementation can keep it:
Registering the Plugin
The explicit side-effect import must run beforenew Client() when the application is built with tsc, uses
build.tool: 'none', or does not use the Stars CLI:
@wolfstar/cli@0.6.0 or newer and a tsdown build, installed @wolfstar/plugin-* packages are discovered from
runtime dependencies and their /register entrypoints are activated automatically. In that setup, remove the manual
import to avoid registering the plugin twice.
Configuring Transports
Without atransports option, the plugin uses ConsoleTransport. Pass an array to send every log payload to multiple
destinations:
level; messages below it are skipped for that destination. The Sentry SDK
and alternative logger backends are not installed automatically.
For example, a Winston transport is configured with the Winston logger instance you already own:
npm levels do not include fatal. On those adapters, trace is
mapped to debug and fatal to error.
Updating Colour Helper Imports
The old package re-exportedcolorette helpers. The plugin does not. If the application uses helpers such as red,
bold, or stripColor, depend on colorette directly and update the module specifier:
Checklist
-
@wolfstar/loggerremoved frompackage.json -
@wolfstar/plugin-loggeradded to runtime dependencies when custom transports are needed -
@wolfstar/http-frameworkon^3.4.0or newer and Node.js 20 or newer - Manual
new Logger(...)replaced with theloggerclient option - Logger call sites use
container.logger -
/registerimported beforenew Client(), or omitted when the Stars bundler auto-registers plugins - Optional backend peer dependencies installed for every configured transport
- Colour helpers imported directly from
colorette