From 69a9aa365097a2b70a18ef8994b25661d2af2394 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 14:38:36 +0200 Subject: [PATCH 01/22] fix(cli-plugin-vitest): migrate configuration to vitest v8 --- .../src/CliPluginVitestModule.ts | 4 +--- .../src/templates/vitest.config.template.ts | 19 +++++-------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/cli-plugin-vitest/src/CliPluginVitestModule.ts b/packages/cli-plugin-vitest/src/CliPluginVitestModule.ts index 3b5618da5..faf034926 100644 --- a/packages/cli-plugin-vitest/src/CliPluginVitestModule.ts +++ b/packages/cli-plugin-vitest/src/CliPluginVitestModule.ts @@ -23,9 +23,7 @@ export class CliPluginVitestModule implements AlterInitSubTasks, AlterPackageJso }); packageJson.addDevDependencies({ vitest: "latest", - "unplugin-swc": "latest", - "@vitest/coverage-v8": "latest", - "@swc/core": "latest" + "@vitest/coverage-v8": "latest" }); } diff --git a/packages/cli-plugin-vitest/src/templates/vitest.config.template.ts b/packages/cli-plugin-vitest/src/templates/vitest.config.template.ts index acaf1f18d..800171137 100644 --- a/packages/cli-plugin-vitest/src/templates/vitest.config.template.ts +++ b/packages/cli-plugin-vitest/src/templates/vitest.config.template.ts @@ -9,26 +9,17 @@ export default defineTemplate({ hidden: true, render() { - return `import swc from "unplugin-swc"; -import {defineConfig} from "vitest/config"; + return `import {defineConfig} from "vitest/config"; export default defineConfig({ + resolve: { + tsconfigPaths: true + }, test: { globals: true, root: "./" }, - plugins: [ - // This is required to build the test files with SWC - swc.vite({ - // Explicitly set the module type to avoid inheriting this value from a \`.swcrc\` config file - module: {type: "es6"}, - jsc: { - transform: { - useDefineForClassFields: false - } - } - }) - ] + plugins: [] });`; } }); From 10b0b799c3d8a4db4d4926d0853c372f6489320b Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 14:47:07 +0200 Subject: [PATCH 02/22] feat(cli): add BuildCmd and DevCmd for Vite integration commands --- .../packageManagers/PackageManagersModule.ts | 2 +- .../cli/src/commands/build/BuildCmd.spec.ts | 34 ++++ packages/cli/src/commands/build/BuildCmd.ts | 28 ++++ packages/cli/src/commands/dev/DevCmd.spec.ts | 21 +++ packages/cli/src/commands/dev/DevCmd.ts | 151 ++++++++++++++++++ packages/cli/src/commands/index.ts | 4 +- packages/cli/src/commands/init/InitCmd.ts | 4 +- .../commands/init/config/FeaturesPrompt.ts | 18 ++- .../src/commands/init/config/InitSchema.ts | 4 + .../init/prompts/getFeaturesPrompt.spec.ts | 19 +++ .../init/prompts/getFeaturesPrompt.ts | 10 +- .../mcp/schema/ProjectPreferencesSchema.ts | 4 +- packages/cli/src/commands/run/RunCmd.ts | 1 - .../cli/src/interfaces/RenderDataContext.ts | 1 + packages/cli/src/interfaces/RuntimeTypes.ts | 2 +- packages/cli/src/runtimes/RuntimesModule.ts | 3 +- packages/cli/src/runtimes/index.ts | 1 + .../cli/src/runtimes/supports/ViteRuntime.ts | 35 ++++ packages/cli/templates/vite.config.ts | 21 +++ 19 files changed, 346 insertions(+), 17 deletions(-) create mode 100644 packages/cli/src/commands/build/BuildCmd.spec.ts create mode 100644 packages/cli/src/commands/build/BuildCmd.ts create mode 100644 packages/cli/src/commands/dev/DevCmd.spec.ts create mode 100644 packages/cli/src/commands/dev/DevCmd.ts create mode 100644 packages/cli/src/runtimes/supports/ViteRuntime.ts create mode 100644 packages/cli/templates/vite.config.ts diff --git a/packages/cli-core/src/packageManagers/PackageManagersModule.ts b/packages/cli-core/src/packageManagers/PackageManagersModule.ts index de0211d8f..b6d3c0d23 100644 --- a/packages/cli-core/src/packageManagers/PackageManagersModule.ts +++ b/packages/cli-core/src/packageManagers/PackageManagersModule.ts @@ -163,4 +163,4 @@ export class PackageManagersModule { } } -injectable(PackageManagersModule).imports([YarnBerryManager, YarnManager, NpmManager, PNpmManager, BunManager]); +injectable(PackageManagersModule).imports([NpmManager, YarnBerryManager, PNpmManager, BunManager, YarnManager]); diff --git a/packages/cli/src/commands/build/BuildCmd.spec.ts b/packages/cli/src/commands/build/BuildCmd.spec.ts new file mode 100644 index 000000000..c61ab4ea3 --- /dev/null +++ b/packages/cli/src/commands/build/BuildCmd.spec.ts @@ -0,0 +1,34 @@ +// @ts-ignore +import {CliPlatformTest} from "@tsed/cli-testing"; + +import {CliRunScript} from "../../services/CliRunScript.js"; +import {BuildCmd} from "./BuildCmd.js"; + +describe("BuildCmd", () => { + beforeEach(() => CliPlatformTest.create()); + afterEach(() => CliPlatformTest.reset()); + + it("should run vite build and forward args for vite runtime", async () => { + const runScript = { + run: vi.fn() + }; + + const command = await CliPlatformTest.invoke(BuildCmd, [ + { + token: CliRunScript, + use: runScript + } + ]); + + await command.$exec({ + rawArgs: ["--mode", "production"] + }); + + expect(runScript.run).toHaveBeenCalledTimes(1); + expect(runScript.run).toHaveBeenNthCalledWith(1, "vite build", ["--mode", "production"], { + env: { + ...process.env + } + }); + }); +}); diff --git a/packages/cli/src/commands/build/BuildCmd.ts b/packages/cli/src/commands/build/BuildCmd.ts new file mode 100644 index 000000000..e63fe7a7a --- /dev/null +++ b/packages/cli/src/commands/build/BuildCmd.ts @@ -0,0 +1,28 @@ +import {command, type CommandProvider, inject} from "@tsed/cli-core"; +import {taskLogger} from "@tsed/cli-tasks"; + +import {CliRunScript} from "../../services/CliRunScript.js"; + +export interface BuildCmdContext { + rawArgs: string[]; +} + +export class BuildCmd implements CommandProvider { + protected runScript = inject(CliRunScript); + + async $exec(ctx: BuildCmdContext) { + const command = "vite build"; + + taskLogger().info(`Run ${[command, ...ctx.rawArgs].join(" ")}`); + await this.runScript.run(command, ctx.rawArgs, { + env: process.env + }); + } +} + +command({ + token: BuildCmd, + name: "build", + description: "Build the project", + allowUnknownOption: true +}); diff --git a/packages/cli/src/commands/dev/DevCmd.spec.ts b/packages/cli/src/commands/dev/DevCmd.spec.ts new file mode 100644 index 000000000..75e6c1b4b --- /dev/null +++ b/packages/cli/src/commands/dev/DevCmd.spec.ts @@ -0,0 +1,21 @@ +// @ts-ignore +import {CliPlatformTest} from "@tsed/cli-testing"; + +import {DevCmd} from "./DevCmd.js"; + +describe("DevCmd", () => { + beforeEach(() => CliPlatformTest.create()); + afterEach(() => CliPlatformTest.reset()); + + it("should delegate to vite runtime runner", async () => { + const command = await CliPlatformTest.invoke(DevCmd); + + const runViteDev = vi.spyOn(command as any, "runViteDev").mockResolvedValue(undefined); + + await command.$exec({ + rawArgs: ["--watch=false"] + }); + + expect(runViteDev).toHaveBeenCalledWith(["--watch=false"]); + }); +}); diff --git a/packages/cli/src/commands/dev/DevCmd.ts b/packages/cli/src/commands/dev/DevCmd.ts new file mode 100644 index 000000000..d282cb45c --- /dev/null +++ b/packages/cli/src/commands/dev/DevCmd.ts @@ -0,0 +1,151 @@ +import {spawn} from "node:child_process"; +import process from "node:process"; + +import {command, type CommandProvider, normalizePath} from "@tsed/cli-core"; +import {taskLogger} from "@tsed/cli-tasks"; + +export interface DevCmdContext { + rawArgs: string[]; +} + +export class DevCmd implements CommandProvider { + async $exec(ctx: DevCmdContext) { + await this.runViteDev(ctx.rawArgs); + } + + protected parseWatchValue(args: string[]) { + const watchArg = args.find((arg) => arg === "--watch" || arg.startsWith("--watch=")); + + if (!watchArg) { + return true; + } + + if (watchArg === "--watch") { + return true; + } + + return watchArg !== "--watch=false"; + } + + protected async createViteDevServer() { + const {createServer} = await import("vite"); + + return createServer({ + configFile: normalizePath("vite.config.ts"), + server: { + middlewareMode: true, + hmr: false, + ws: false + } + }); + } + + protected async runViteApp() { + const vite = await this.createViteDevServer(); + + const shutdown = async () => { + await vite.close(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + await vite.ssrLoadModule(`/src/index.ts?t=${Date.now()}`); + await new Promise(() => {}); + } + + protected async runViteController(rawArgs: string[]) { + const watch = this.parseWatchValue(rawArgs); + const vite = await this.createViteDevServer(); + let childProcess: ReturnType | undefined; + let restarting = false; + let queued = false; + + const startChild = () => { + const [, scriptPath] = process.argv; + const args = scriptPath ? [scriptPath, "dev", ...rawArgs] : ["dev", ...rawArgs]; + + childProcess = spawn(process.execPath, args, { + env: { + ...process.env, + TSED_VITE_RUN_MODE: "app" + }, + stdio: "inherit" + }); + }; + + const stopChild = async () => { + if (!childProcess || childProcess.killed) { + return; + } + + await new Promise((resolve) => { + childProcess!.once("exit", resolve); + childProcess!.kill("SIGTERM"); + }); + }; + + const restartChild = async (reason: string, file = "") => { + if (restarting) { + queued = true; + return; + } + + restarting = true; + const suffix = file ? `: ${file}` : ""; + taskLogger().info(`[tsed-dev] restart (${reason})${suffix}`); + await stopChild(); + startChild(); + restarting = false; + + if (queued) { + queued = false; + await restartChild("queued"); + } + }; + + if (watch) { + vite.watcher.on("all", async (event, file) => { + if (!file || file.includes("node_modules") || file.includes(".git") || file.includes("/dist/")) { + return; + } + + if (["add", "change", "unlink"].includes(event)) { + await restartChild(event, file); + } + }); + } + + vite.watcher.once("ready", () => { + startChild(); + }); + + const shutdown = async () => { + await stopChild(); + await vite.close(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + await new Promise(() => {}); + } + + protected async runViteDev(rawArgs: string[]) { + if (process.env.TSED_VITE_RUN_MODE === "app") { + await this.runViteApp(); + return; + } + + await this.runViteController(rawArgs); + } +} + +command({ + token: DevCmd, + name: "dev", + description: "Run the project in development mode", + allowUnknownOption: true +}); diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 0fb792c78..00bf1d664 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -1,4 +1,6 @@ import {AddCmd} from "./add/AddCmd.js"; +import {BuildCmd} from "./build/BuildCmd.js"; +import {DevCmd} from "./dev/DevCmd.js"; import {GenerateCmd} from "./generate/GenerateCmd.js"; import {InitCmd} from "./init/InitCmd.js"; import {InitOptionsCommand} from "./init/InitOptionsCmd.js"; @@ -7,4 +9,4 @@ import {RunCmd} from "./run/RunCmd.js"; import {CreateTemplateCommand} from "./template/CreateTemplateCommand.js"; import {UpdateCmd} from "./update/UpdateCmd.js"; -export default [AddCmd, InitCmd, InitOptionsCommand, GenerateCmd, UpdateCmd, RunCmd, CreateTemplateCommand, McpCommand]; +export default [AddCmd, InitCmd, InitOptionsCommand, GenerateCmd, UpdateCmd, RunCmd, DevCmd, BuildCmd, CreateTemplateCommand, McpCommand]; diff --git a/packages/cli/src/commands/init/InitCmd.ts b/packages/cli/src/commands/init/InitCmd.ts index 437e84b3d..293d328f9 100644 --- a/packages/cli/src/commands/init/InitCmd.ts +++ b/packages/cli/src/commands/init/InitCmd.ts @@ -33,6 +33,7 @@ import {PlatformsModule} from "../../platforms/PlatformsModule.js"; import {RuntimesModule} from "../../runtimes/RuntimesModule.js"; import {BunRuntime} from "../../runtimes/supports/BunRuntime.js"; import {NodeRuntime} from "../../runtimes/supports/NodeRuntime.js"; +import {ViteRuntime} from "../../runtimes/supports/ViteRuntime.js"; import {CliProjectService} from "../../services/CliProjectService.js"; import type {TemplateRenderOptions} from "../../services/CliTemplatesService.js"; import {anonymizePaths} from "../../services/mappers/anonymizePaths.js"; @@ -188,7 +189,8 @@ export class InitCmd implements CommandProvider { ...ctx, node: runtime instanceof NodeRuntime, bun: runtime instanceof BunRuntime, - compiled: runtime instanceof NodeRuntime && runtime.isCompiled() + vite: runtime instanceof ViteRuntime, + compiled: runtime.isCompiled() }; return [ diff --git a/packages/cli/src/commands/init/config/FeaturesPrompt.ts b/packages/cli/src/commands/init/config/FeaturesPrompt.ts index d3faf9d22..a98236a33 100644 --- a/packages/cli/src/commands/init/config/FeaturesPrompt.ts +++ b/packages/cli/src/commands/init/config/FeaturesPrompt.ts @@ -362,6 +362,10 @@ export const FeaturesMap: Record = { name: "Lint on commit" }, + vite: { + name: "Node.js + Vite", + checked: false + }, node: { name: "Node.js + SWC", checked: true @@ -378,17 +382,17 @@ export const FeaturesMap: Record = { name: "Bun.js", checked: false }, - yarn: { - name: "Yarn", - checked: true + npm: { + name: "NPM", + checked: false }, yarn_berry: { name: "Yarn Berry", checked: false }, - npm: { - name: "NPM", - checked: false + yarn: { + name: "Yarn", + checked: true }, pnpm: { name: "PNPM", @@ -549,7 +553,7 @@ export const FeaturesPrompt = (availableRuntimes: string[], availablePackageMana message: "Choose the package manager:", type: "list", name: "packageManager", - when: hasValue("runtime", ["node", "babel", "swc", "webpack"]), + when: hasValue("runtime", ["vite", "node", "babel", "swc", "webpack"]), choices: availablePackageManagers } ] satisfies PromptQuestion[]; diff --git a/packages/cli/src/commands/init/config/InitSchema.ts b/packages/cli/src/commands/init/config/InitSchema.ts index 5a57fb5f2..ba997119f 100644 --- a/packages/cli/src/commands/init/config/InitSchema.ts +++ b/packages/cli/src/commands/init/config/InitSchema.ts @@ -278,6 +278,10 @@ export const InitSchema = () => { .prompt("Choose the runtime:") .choices( [ + { + label: "Node.js + Vite", + value: "vite" + }, { label: "Node.js + SWC", value: "node" diff --git a/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts b/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts index f2e4f9833..b2c6b778f 100644 --- a/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts +++ b/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts @@ -1,6 +1,25 @@ import {getFeaturesPrompt} from "./getFeaturesPrompt.js"; describe("getFeaturesPrompt", () => { + it("should throw with an explicit message when a choice is unknown", () => { + expect(() => getFeaturesPrompt(["unknown-runtime"], ["yarn"], {})).toThrowError( + 'Unknown init prompt choice "unknown-runtime" for prompt "runtime"' + ); + }); + + it("should map vite runtime choice without throwing", () => { + const prompt = getFeaturesPrompt(["node", "vite"], ["yarn", "npm"], {}); + const runtimePrompt = prompt.find((item: any) => item.name === "runtime"); + + expect(runtimePrompt).toBeDefined(); + expect((runtimePrompt as any).choices).toEqual( + expect.arrayContaining([ + expect.objectContaining({value: "node", name: "Node.js + SWC"}), + expect.objectContaining({value: "vite", name: "Node.js + Vite"}) + ]) + ); + }); + it("should add a provider info", () => { const prompt = getFeaturesPrompt(["node", "bun"], ["yarn", "npm", "pnpm", "bun"], {}); diff --git a/packages/cli/src/commands/init/prompts/getFeaturesPrompt.ts b/packages/cli/src/commands/init/prompts/getFeaturesPrompt.ts index 4c7ce959b..38f126254 100644 --- a/packages/cli/src/commands/init/prompts/getFeaturesPrompt.ts +++ b/packages/cli/src/commands/init/prompts/getFeaturesPrompt.ts @@ -5,10 +5,16 @@ import {FeaturesMap, FeaturesPrompt} from "../config/FeaturesPrompt.js"; function mapChoices(item: any, options: Partial) { return item.choices.map((choice: string) => { - const {checked} = FeaturesMap[choice]; + const config = FeaturesMap[choice]; + + if (!config) { + throw new Error(`Unknown init prompt choice "${choice}" for prompt "${item.name}"`); + } + + const {checked} = config; return cleanObject({ - ...FeaturesMap[choice], + ...config, value: choice, checked: isFunction(checked) ? checked(options) : checked }); diff --git a/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts b/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts index 9559af0d0..5c0368eab 100644 --- a/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts +++ b/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts @@ -10,8 +10,8 @@ export const ProjectPreferenceSchema = s packageManager: s.string().enum(PackageManager).description("Used project manager to install dependencies"), runtime: s .string() - .enum("node", "babel", "swc", "webpack", "bun") - .description("The javascript runtime used to start application (node, node + webpack, node + swc, node + babel, bun)"), + .enum("vite", "node", "babel", "swc", "webpack", "bun") + .description("The javascript runtime used to start application (node, node + webpack, node + swc, node + babel, bun, vite)"), platform: s.string().enum(PlatformType).description("Node.js framework used to run server (Express, Koa, Fastify)") }) .optional() diff --git a/packages/cli/src/commands/run/RunCmd.ts b/packages/cli/src/commands/run/RunCmd.ts index eb59b18cc..fa2a41217 100644 --- a/packages/cli/src/commands/run/RunCmd.ts +++ b/packages/cli/src/commands/run/RunCmd.ts @@ -1,6 +1,5 @@ import {CliFs, command, type CommandProvider, inject, normalizePath, ProjectPackageJson} from "@tsed/cli-core"; import {taskLogger} from "@tsed/cli-tasks"; -import {logger} from "@tsed/di"; import {CliRunScript} from "../../services/CliRunScript.js"; diff --git a/packages/cli/src/interfaces/RenderDataContext.ts b/packages/cli/src/interfaces/RenderDataContext.ts index 3e712b181..61ad0840f 100644 --- a/packages/cli/src/interfaces/RenderDataContext.ts +++ b/packages/cli/src/interfaces/RenderDataContext.ts @@ -50,6 +50,7 @@ export interface RenderDataContext extends CommandData, TsED.RenderDataContext { configPostgres?: boolean; barrels?: string; bun?: boolean; + vite?: boolean; node?: boolean; compiled?: boolean; testing?: boolean; diff --git a/packages/cli/src/interfaces/RuntimeTypes.ts b/packages/cli/src/interfaces/RuntimeTypes.ts index 72acfeb0c..92f32765f 100644 --- a/packages/cli/src/interfaces/RuntimeTypes.ts +++ b/packages/cli/src/interfaces/RuntimeTypes.ts @@ -1,4 +1,4 @@ -export type RuntimeTypes = "node" | "babel" | "swc" | "webpack" | "bun"; +export type RuntimeTypes = "node" | "babel" | "swc" | "webpack" | "bun" | "vite"; declare global { namespace TsED { diff --git a/packages/cli/src/runtimes/RuntimesModule.ts b/packages/cli/src/runtimes/RuntimesModule.ts index 62e381f64..791f8bc40 100644 --- a/packages/cli/src/runtimes/RuntimesModule.ts +++ b/packages/cli/src/runtimes/RuntimesModule.ts @@ -5,6 +5,7 @@ import {BabelRuntime} from "./supports/BabelRuntime.js"; import {BaseRuntime} from "./supports/BaseRuntime.js"; import {BunRuntime} from "./supports/BunRuntime.js"; import {NodeRuntime} from "./supports/NodeRuntime.js"; +import {ViteRuntime} from "./supports/ViteRuntime.js"; import {WebpackRuntime} from "./supports/WebpackRuntime.js"; export interface RuntimeInitOptions { @@ -62,4 +63,4 @@ export class RuntimesModule { } } -injectable(RuntimesModule).imports([NodeRuntime, BabelRuntime, WebpackRuntime, BunRuntime]); +injectable(RuntimesModule).imports([ViteRuntime, NodeRuntime, BabelRuntime, WebpackRuntime, , BunRuntime]); diff --git a/packages/cli/src/runtimes/index.ts b/packages/cli/src/runtimes/index.ts index 175fae2a5..1378c58a0 100644 --- a/packages/cli/src/runtimes/index.ts +++ b/packages/cli/src/runtimes/index.ts @@ -3,4 +3,5 @@ export * from "./supports/BabelRuntime.js"; export * from "./supports/BaseRuntime.js"; export * from "./supports/BunRuntime.js"; export * from "./supports/NodeRuntime.js"; +export * from "./supports/ViteRuntime.js"; export * from "./supports/WebpackRuntime.js"; diff --git a/packages/cli/src/runtimes/supports/ViteRuntime.ts b/packages/cli/src/runtimes/supports/ViteRuntime.ts new file mode 100644 index 000000000..8e6713605 --- /dev/null +++ b/packages/cli/src/runtimes/supports/ViteRuntime.ts @@ -0,0 +1,35 @@ +import {injectable} from "@tsed/di"; + +import {BaseRuntime} from "./BaseRuntime.js"; + +export class ViteRuntime extends BaseRuntime { + readonly name = "vite"; + readonly cmd = "node"; + readonly order: number = -1; + + files() { + return ["vite.config.ts"]; + } + + compile(): string { + return "tsed build"; + } + + startDev(): string { + return "tsed dev"; + } + + startProd(args: string): string { + return `node ${args}`; + } + + devDependencies(): Record { + return { + "@tsed/cli": "{{cliVersion}}", + typescript: "latest", + vite: "latest" + }; + } +} + +injectable(ViteRuntime).type("runtime"); diff --git a/packages/cli/templates/vite.config.ts b/packages/cli/templates/vite.config.ts new file mode 100644 index 000000000..13996661f --- /dev/null +++ b/packages/cli/templates/vite.config.ts @@ -0,0 +1,21 @@ +import {builtinModules} from "node:module"; + +import {defineConfig} from "vite"; + +export default defineConfig({ + appType: "custom", + build: { + outDir: "dist", + target: "node24", + ssr: "src/index.ts", + sourcemap: true, + minify: false, + rollupOptions: { + external: [...builtinModules, ...builtinModules.map((module) => `node:${module}`)], + output: { + entryFileNames: "index.js", + format: "es" + } + } + } +}); From 8636af3cdce0f7383b3e25cc42fafef00c44d123 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Apr 2026 12:57:32 +0000 Subject: [PATCH 03/22] Github CI build: __run_2 v7.5.0-rc.1 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 841abb197..1b95d7fe7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.4.0", + "version": "7.5.0-rc.1", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 4548d1340e50c21319e2bb2d6987f398a91426a6 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 15:33:59 +0200 Subject: [PATCH 04/22] fix(cli): bypass bootstrap when command is dev or build --- packages/cli/src/bin/boot.ts | 46 +++++ packages/cli/src/bin/tsed-build.ts | 27 +++ packages/cli/src/bin/tsed-dev.ts | 167 ++++++++++++++++++ packages/cli/src/bin/tsed.ts | 75 +++----- .../cli/src/commands/build/BuildCmd.spec.ts | 34 ---- packages/cli/src/commands/build/BuildCmd.ts | 28 --- packages/cli/src/commands/dev/DevCmd.spec.ts | 21 --- packages/cli/src/commands/dev/DevCmd.ts | 151 ---------------- packages/cli/src/commands/index.ts | 4 +- packages/cli/src/runtimes/RuntimesModule.ts | 2 +- 10 files changed, 269 insertions(+), 286 deletions(-) create mode 100644 packages/cli/src/bin/boot.ts create mode 100644 packages/cli/src/bin/tsed-build.ts create mode 100644 packages/cli/src/bin/tsed-dev.ts delete mode 100644 packages/cli/src/commands/build/BuildCmd.spec.ts delete mode 100644 packages/cli/src/commands/build/BuildCmd.ts delete mode 100644 packages/cli/src/commands/dev/DevCmd.spec.ts delete mode 100644 packages/cli/src/commands/dev/DevCmd.ts diff --git a/packages/cli/src/bin/boot.ts b/packages/cli/src/bin/boot.ts new file mode 100644 index 000000000..2fc047e31 --- /dev/null +++ b/packages/cli/src/bin/boot.ts @@ -0,0 +1,46 @@ +import {register} from "node:module"; +import {join} from "node:path"; +import {pathToFileURL} from "node:url"; + +const EXT = process.env.CLI_MODE === "ts" ? "ts" : "js"; + +register(pathToFileURL(join(import.meta.dirname, `../loaders/alias.hook.${EXT}`)), { + parentURL: import.meta.dirname, + data: { + "@tsed/core": import.meta.resolve("@tsed/core"), + "@tsed/di": import.meta.resolve("@tsed/di"), + "@tsed/schema": import.meta.resolve("@tsed/schema"), + "@tsed/cli-core": import.meta.resolve("@tsed/cli-core"), + "@tsed/cli": import.meta.resolve("@tsed/cli") + }, + transferList: [] +}); + +const {tools, commands, resources, CliCore, PKG, TEMPLATE_DIR, ArchitectureConvention, ProjectConvention} = await import("../index.js"); + +CliCore.bootstrap({ + name: "tsed", + pkg: PKG as any, + templateDir: TEMPLATE_DIR, + plugins: true, + updateNotifier: true, + checkPrecondition: true, + commands, + tools, + resources, + defaultProjectPreferences() { + return { + convention: ProjectConvention.DEFAULT, + architecture: ArchitectureConvention.DEFAULT + }; + }, + project: { + reinstallAfterRun: true + }, + logger: { + level: "info" + } +}).catch((error) => { + console.error(error); + process.exit(-1); +}); diff --git a/packages/cli/src/bin/tsed-build.ts b/packages/cli/src/bin/tsed-build.ts new file mode 100644 index 000000000..e05e71540 --- /dev/null +++ b/packages/cli/src/bin/tsed-build.ts @@ -0,0 +1,27 @@ +import {spawn} from "node:child_process"; +import process from "node:process"; +import {fileURLToPath} from "node:url"; + +function runNode(cmd: string, args: string[]) { + return new Promise((resolve, reject) => { + const child = spawn(cmd, args, { + env: process.env, + stdio: "inherit" + }); + + child.on("error", reject); + child.on("exit", (code) => { + if (code === 0) { + resolve(); + return; + } + + reject(new Error(`vite build exited with code ${code}`)); + }); + }); +} + +export async function build(rawArgs: string[] = process.argv.slice(2)) { + const viteBin = fileURLToPath(import.meta.resolve("vite/bin/vite.js")); + await runNode(process.execPath, [viteBin, "build", ...rawArgs]); +} diff --git a/packages/cli/src/bin/tsed-dev.ts b/packages/cli/src/bin/tsed-dev.ts new file mode 100644 index 000000000..b7fb57504 --- /dev/null +++ b/packages/cli/src/bin/tsed-dev.ts @@ -0,0 +1,167 @@ +import {spawn} from "node:child_process"; +import {existsSync} from "node:fs"; +import process from "node:process"; +import {fileURLToPath} from "node:url"; + +import {normalizePath} from "@tsed/cli-core"; +import {logger} from "@tsed/di"; + +const RUN_MODE = "TSED_VITE_RUN_MODE"; + +function parseWatchValue(args: string[]) { + if (args.includes("--no-watch")) { + return false; + } + + const watchIndex = args.findIndex((arg) => arg === "--watch" || arg.startsWith("--watch=")); + + if (watchIndex === -1) { + return true; + } + + const watchArg = args[watchIndex]; + + if (watchArg === "--watch") { + const nextValue = args[watchIndex + 1]; + + if (!nextValue || nextValue.startsWith("-")) { + return true; + } + + return nextValue !== "false"; + } + + if (watchArg === "--watch=false") { + return false; + } + + if (watchArg === "--watch=true") { + return true; + } + + return true; +} + +function assertViteProject() { + const configFile = normalizePath("vite.config.ts"); + + if (!existsSync(configFile)) { + throw new Error("tsed dev is only available for ViteRuntime projects. Missing vite.config.ts in the current directory."); + } +} + +async function createViteDevServer() { + // @ts-ignore + const {createServer} = await import("vite"); + + return createServer({ + configFile: normalizePath("vite.config.ts"), + server: { + middlewareMode: true, + hmr: false, + ws: false + } + }); +} + +async function runViteApp() { + const vite = await createViteDevServer(); + + const shutdown = async () => { + await vite.close(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + await vite.ssrLoadModule("/src/index.ts"); + await new Promise(() => {}); +} + +async function runViteController(rawArgs: string[]) { + const runnerFile = fileURLToPath(import.meta.url); + const watch = parseWatchValue(rawArgs); + const vite = await createViteDevServer(); + let childProcess: ReturnType | undefined; + let restarting = false; + let queued = false; + + const startChild = () => { + childProcess = spawn(process.execPath, [runnerFile, ...rawArgs], { + env: { + ...process.env, + [RUN_MODE]: "app" + }, + stdio: "inherit" + }); + }; + + const stopChild = async () => { + if (!childProcess || childProcess.killed) { + return; + } + + await new Promise((resolve) => { + childProcess!.once("exit", resolve); + childProcess!.kill("SIGTERM"); + }); + }; + + const restartChild = async (reason: string, file = "") => { + if (restarting) { + queued = true; + return; + } + + restarting = true; + const suffix = file ? `: ${file}` : ""; + + logger().info(`[tsed-dev] restart (${reason})${suffix}`); + + await stopChild(); + startChild(); + restarting = false; + + if (queued) { + queued = false; + await restartChild("queued"); + } + }; + + if (watch) { + vite.watcher.on("all", async (event, file) => { + if (!file || file.includes("node_modules") || file.includes(".git") || file.includes("/dist/")) { + return; + } + + if (["add", "change", "unlink"].includes(event)) { + await restartChild(event, file); + } + }); + } + + vite.watcher.once("ready", () => { + startChild(); + }); + + const shutdown = async () => { + await stopChild(); + await vite.close(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + await new Promise(() => {}); +} + +export async function dev(rawArgs: string[] = process.argv.slice(2)) { + if (process.env[RUN_MODE] === "app") { + await runViteApp(); + return; + } + + await runViteController(rawArgs); +} diff --git a/packages/cli/src/bin/tsed.ts b/packages/cli/src/bin/tsed.ts index 13af88778..d7720d8d7 100644 --- a/packages/cli/src/bin/tsed.ts +++ b/packages/cli/src/bin/tsed.ts @@ -1,51 +1,30 @@ #!/usr/bin/env node -import "./ts-mode.js"; - -import {register} from "node:module"; -import {join} from "node:path"; -import {pathToFileURL} from "node:url"; - -import type {PackageJson} from "@tsed/cli-core"; - const EXT = process.env.CLI_MODE === "ts" ? "ts" : "js"; +const [, , commandName, ...rawArgs] = process.argv; -register(pathToFileURL(join(import.meta.dirname, `../loaders/alias.hook.${EXT}`)), { - parentURL: import.meta.dirname, - data: { - "@tsed/core": import.meta.resolve("@tsed/core"), - "@tsed/di": import.meta.resolve("@tsed/di"), - "@tsed/schema": import.meta.resolve("@tsed/schema"), - "@tsed/cli-core": import.meta.resolve("@tsed/cli-core"), - "@tsed/cli": import.meta.resolve("@tsed/cli") - }, - transferList: [] -}); - -const {tools, commands, resources, CliCore, PKG, TEMPLATE_DIR, ArchitectureConvention, ProjectConvention} = await import("../index.js"); - -CliCore.bootstrap({ - name: "tsed", - pkg: PKG as PackageJson, - templateDir: TEMPLATE_DIR, - plugins: true, - updateNotifier: true, - checkPrecondition: true, - commands, - tools, - resources, - defaultProjectPreferences() { - return { - convention: ProjectConvention.DEFAULT, - architecture: ArchitectureConvention.DEFAULT - }; - }, - project: { - reinstallAfterRun: true - }, - logger: { - level: "info" - } -}).catch((error) => { - console.error(error); - process.exit(-1); -}); +switch (commandName) { + case "dev": + try { + const {dev} = await import("./tsed-dev.js"); + await dev(rawArgs); + process.exit(0); + } catch (error) { + console.error(error); + process.exit(1); + } + break; + case "build": + try { + const {build} = await import("./tsed-build.js"); + await build(rawArgs); + process.exit(0); + } catch (error) { + console.error(error); + process.exit(1); + } + break; + default: + await import("./ts-mode.js"); + await import(`./boot.${EXT}`); + break; +} diff --git a/packages/cli/src/commands/build/BuildCmd.spec.ts b/packages/cli/src/commands/build/BuildCmd.spec.ts deleted file mode 100644 index c61ab4ea3..000000000 --- a/packages/cli/src/commands/build/BuildCmd.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -// @ts-ignore -import {CliPlatformTest} from "@tsed/cli-testing"; - -import {CliRunScript} from "../../services/CliRunScript.js"; -import {BuildCmd} from "./BuildCmd.js"; - -describe("BuildCmd", () => { - beforeEach(() => CliPlatformTest.create()); - afterEach(() => CliPlatformTest.reset()); - - it("should run vite build and forward args for vite runtime", async () => { - const runScript = { - run: vi.fn() - }; - - const command = await CliPlatformTest.invoke(BuildCmd, [ - { - token: CliRunScript, - use: runScript - } - ]); - - await command.$exec({ - rawArgs: ["--mode", "production"] - }); - - expect(runScript.run).toHaveBeenCalledTimes(1); - expect(runScript.run).toHaveBeenNthCalledWith(1, "vite build", ["--mode", "production"], { - env: { - ...process.env - } - }); - }); -}); diff --git a/packages/cli/src/commands/build/BuildCmd.ts b/packages/cli/src/commands/build/BuildCmd.ts deleted file mode 100644 index e63fe7a7a..000000000 --- a/packages/cli/src/commands/build/BuildCmd.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {command, type CommandProvider, inject} from "@tsed/cli-core"; -import {taskLogger} from "@tsed/cli-tasks"; - -import {CliRunScript} from "../../services/CliRunScript.js"; - -export interface BuildCmdContext { - rawArgs: string[]; -} - -export class BuildCmd implements CommandProvider { - protected runScript = inject(CliRunScript); - - async $exec(ctx: BuildCmdContext) { - const command = "vite build"; - - taskLogger().info(`Run ${[command, ...ctx.rawArgs].join(" ")}`); - await this.runScript.run(command, ctx.rawArgs, { - env: process.env - }); - } -} - -command({ - token: BuildCmd, - name: "build", - description: "Build the project", - allowUnknownOption: true -}); diff --git a/packages/cli/src/commands/dev/DevCmd.spec.ts b/packages/cli/src/commands/dev/DevCmd.spec.ts deleted file mode 100644 index 75e6c1b4b..000000000 --- a/packages/cli/src/commands/dev/DevCmd.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -// @ts-ignore -import {CliPlatformTest} from "@tsed/cli-testing"; - -import {DevCmd} from "./DevCmd.js"; - -describe("DevCmd", () => { - beforeEach(() => CliPlatformTest.create()); - afterEach(() => CliPlatformTest.reset()); - - it("should delegate to vite runtime runner", async () => { - const command = await CliPlatformTest.invoke(DevCmd); - - const runViteDev = vi.spyOn(command as any, "runViteDev").mockResolvedValue(undefined); - - await command.$exec({ - rawArgs: ["--watch=false"] - }); - - expect(runViteDev).toHaveBeenCalledWith(["--watch=false"]); - }); -}); diff --git a/packages/cli/src/commands/dev/DevCmd.ts b/packages/cli/src/commands/dev/DevCmd.ts deleted file mode 100644 index d282cb45c..000000000 --- a/packages/cli/src/commands/dev/DevCmd.ts +++ /dev/null @@ -1,151 +0,0 @@ -import {spawn} from "node:child_process"; -import process from "node:process"; - -import {command, type CommandProvider, normalizePath} from "@tsed/cli-core"; -import {taskLogger} from "@tsed/cli-tasks"; - -export interface DevCmdContext { - rawArgs: string[]; -} - -export class DevCmd implements CommandProvider { - async $exec(ctx: DevCmdContext) { - await this.runViteDev(ctx.rawArgs); - } - - protected parseWatchValue(args: string[]) { - const watchArg = args.find((arg) => arg === "--watch" || arg.startsWith("--watch=")); - - if (!watchArg) { - return true; - } - - if (watchArg === "--watch") { - return true; - } - - return watchArg !== "--watch=false"; - } - - protected async createViteDevServer() { - const {createServer} = await import("vite"); - - return createServer({ - configFile: normalizePath("vite.config.ts"), - server: { - middlewareMode: true, - hmr: false, - ws: false - } - }); - } - - protected async runViteApp() { - const vite = await this.createViteDevServer(); - - const shutdown = async () => { - await vite.close(); - process.exit(0); - }; - - process.on("SIGINT", shutdown); - process.on("SIGTERM", shutdown); - - await vite.ssrLoadModule(`/src/index.ts?t=${Date.now()}`); - await new Promise(() => {}); - } - - protected async runViteController(rawArgs: string[]) { - const watch = this.parseWatchValue(rawArgs); - const vite = await this.createViteDevServer(); - let childProcess: ReturnType | undefined; - let restarting = false; - let queued = false; - - const startChild = () => { - const [, scriptPath] = process.argv; - const args = scriptPath ? [scriptPath, "dev", ...rawArgs] : ["dev", ...rawArgs]; - - childProcess = spawn(process.execPath, args, { - env: { - ...process.env, - TSED_VITE_RUN_MODE: "app" - }, - stdio: "inherit" - }); - }; - - const stopChild = async () => { - if (!childProcess || childProcess.killed) { - return; - } - - await new Promise((resolve) => { - childProcess!.once("exit", resolve); - childProcess!.kill("SIGTERM"); - }); - }; - - const restartChild = async (reason: string, file = "") => { - if (restarting) { - queued = true; - return; - } - - restarting = true; - const suffix = file ? `: ${file}` : ""; - taskLogger().info(`[tsed-dev] restart (${reason})${suffix}`); - await stopChild(); - startChild(); - restarting = false; - - if (queued) { - queued = false; - await restartChild("queued"); - } - }; - - if (watch) { - vite.watcher.on("all", async (event, file) => { - if (!file || file.includes("node_modules") || file.includes(".git") || file.includes("/dist/")) { - return; - } - - if (["add", "change", "unlink"].includes(event)) { - await restartChild(event, file); - } - }); - } - - vite.watcher.once("ready", () => { - startChild(); - }); - - const shutdown = async () => { - await stopChild(); - await vite.close(); - process.exit(0); - }; - - process.on("SIGINT", shutdown); - process.on("SIGTERM", shutdown); - - await new Promise(() => {}); - } - - protected async runViteDev(rawArgs: string[]) { - if (process.env.TSED_VITE_RUN_MODE === "app") { - await this.runViteApp(); - return; - } - - await this.runViteController(rawArgs); - } -} - -command({ - token: DevCmd, - name: "dev", - description: "Run the project in development mode", - allowUnknownOption: true -}); diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 00bf1d664..0fb792c78 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -1,6 +1,4 @@ import {AddCmd} from "./add/AddCmd.js"; -import {BuildCmd} from "./build/BuildCmd.js"; -import {DevCmd} from "./dev/DevCmd.js"; import {GenerateCmd} from "./generate/GenerateCmd.js"; import {InitCmd} from "./init/InitCmd.js"; import {InitOptionsCommand} from "./init/InitOptionsCmd.js"; @@ -9,4 +7,4 @@ import {RunCmd} from "./run/RunCmd.js"; import {CreateTemplateCommand} from "./template/CreateTemplateCommand.js"; import {UpdateCmd} from "./update/UpdateCmd.js"; -export default [AddCmd, InitCmd, InitOptionsCommand, GenerateCmd, UpdateCmd, RunCmd, DevCmd, BuildCmd, CreateTemplateCommand, McpCommand]; +export default [AddCmd, InitCmd, InitOptionsCommand, GenerateCmd, UpdateCmd, RunCmd, CreateTemplateCommand, McpCommand]; diff --git a/packages/cli/src/runtimes/RuntimesModule.ts b/packages/cli/src/runtimes/RuntimesModule.ts index 791f8bc40..36cebec44 100644 --- a/packages/cli/src/runtimes/RuntimesModule.ts +++ b/packages/cli/src/runtimes/RuntimesModule.ts @@ -63,4 +63,4 @@ export class RuntimesModule { } } -injectable(RuntimesModule).imports([ViteRuntime, NodeRuntime, BabelRuntime, WebpackRuntime, , BunRuntime]); +injectable(RuntimesModule).imports([ViteRuntime, NodeRuntime, BabelRuntime, WebpackRuntime, BunRuntime]); From 866c76a847d6af1b27f2c1177e0e72738a191c02 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Apr 2026 13:38:09 +0000 Subject: [PATCH 05/22] Github CI build: __run_2 v7.5.0-rc.2 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b95d7fe7..3a2159e20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.1", + "version": "7.5.0-rc.2", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 53649f6c28dfd8a22756c491e6058de1e377fb4d Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 16:14:26 +0200 Subject: [PATCH 06/22] fix(cli): improve error handling and adjust child process spawning logic --- packages/cli-core/src/CliCore.ts | 1 - .../src/services/CliHttpClient.spec.ts | 18 +++++-- .../cli-core/src/services/CliHttpClient.ts | 50 +++++++++++++------ .../cli-core/src/services/CliProxyAgent.ts | 12 ++--- packages/cli/src/bin/tsed-dev.ts | 4 +- 5 files changed, 54 insertions(+), 31 deletions(-) diff --git a/packages/cli-core/src/CliCore.ts b/packages/cli-core/src/CliCore.ts index a9c295086..5f2da24ba 100644 --- a/packages/cli-core/src/CliCore.ts +++ b/packages/cli-core/src/CliCore.ts @@ -109,7 +109,6 @@ export class CliCore { const cliService = inject(CliService); constant("plugins") && (await loadPlugins()); - await $asyncEmit("$beforeInit"); await injector().load(); await $asyncEmit("$afterInit"); diff --git a/packages/cli-core/src/services/CliHttpClient.spec.ts b/packages/cli-core/src/services/CliHttpClient.spec.ts index be095758f..153667c60 100644 --- a/packages/cli-core/src/services/CliHttpClient.spec.ts +++ b/packages/cli-core/src/services/CliHttpClient.spec.ts @@ -9,10 +9,12 @@ describe("CliHttpClient", () => { beforeEach(() => DITest.create()); afterEach(() => DITest.reset()); - describe("$afterInit()", () => { - it("should call $afterInit method", async () => { + describe("proxy settings", () => { + it("should resolve proxy settings once for non-local HTTP endpoints", async () => { const cliProxyAgent = { - resolveProxySettings: vi.fn() + resolveProxySettings: vi.fn().mockResolvedValue(undefined), + hasProxy: vi.fn().mockReturnValue(false), + get: vi.fn().mockReturnValue(null) }; const client = await DITest.invoke(CliHttpClient, [ { @@ -21,9 +23,15 @@ describe("CliHttpClient", () => { } ]); - await client.$afterInit(); + (axios as any).mockResolvedValue({ + headers: {}, + data: {} + }); + + await client.get("https://api.tsed.dev/test"); + await client.get("https://api.tsed.dev/test"); - expect(cliProxyAgent.resolveProxySettings).toHaveBeenCalled(); + expect(cliProxyAgent.resolveProxySettings).toHaveBeenCalledTimes(1); }); }); describe("head()", () => { diff --git a/packages/cli-core/src/services/CliHttpClient.ts b/packages/cli-core/src/services/CliHttpClient.ts index 536f7a900..f62100b01 100644 --- a/packages/cli-core/src/services/CliHttpClient.ts +++ b/packages/cli-core/src/services/CliHttpClient.ts @@ -15,56 +15,55 @@ export interface CliHttpClientOptions extends AxiosRequestConfig, Record; static getParamsSerializer(params: any) { return stringify(cleanObject(params)); } - async $afterInit() { - await this.cliProxyAgent.resolveProxySettings(); - } - async head>(endpoint: string, options: CliHttpClientOptions = {}): Promise { - const {headers} = await axios(this.getRequestParameters("HEAD", endpoint, options)); + const {headers} = await axios(await this.getRequestParameters("HEAD", endpoint, options)); return headers as any; } async get(endpoint: string, options: CliHttpClientOptions = {}): Promise { - const result = await this.send(this.getRequestParameters("GET", endpoint, options)); + const result = await this.send(await this.getRequestParameters("GET", endpoint, options)); return this.mapResponse(result, options); } async post(endpoint: string, options: CliHttpClientOptions = {}): Promise { - const result = await this.send(this.getRequestParameters("POST", endpoint, options)); + const result = await this.send(await this.getRequestParameters("POST", endpoint, options)); return this.mapResponse(result, options); } async put(endpoint: string, options: CliHttpClientOptions = {}): Promise { - const result = await this.send(this.getRequestParameters("PUT", endpoint, options)); + const result = await this.send(await this.getRequestParameters("PUT", endpoint, options)); return this.mapResponse(result, options); } async patch(endpoint: string, options: CliHttpClientOptions = {}): Promise { - const result = await this.send(this.getRequestParameters("PATCH", endpoint, options)); + const result = await this.send(await this.getRequestParameters("PATCH", endpoint, options)); return this.mapResponse(result, options); } async delete(endpoint: string, options: CliHttpClientOptions = {}): Promise { - const result = await this.send(this.getRequestParameters("DELETE", endpoint, options)); + const result = await this.send(await this.getRequestParameters("DELETE", endpoint, options)); return this.mapResponse(result, options); } - protected getRequestParameters(method: Method, endpoint: string, options: CliHttpClientOptions) { + protected async getRequestParameters(method: Method, endpoint: string, options: CliHttpClientOptions) { const url = (this.host || "") + endpoint.replace(this.host || "", ""); + await this.resolveProxySettingsOnce(); + options = { method, ...options, @@ -78,23 +77,42 @@ export class CliHttpClient extends CliHttpLogClient { } }; - this.configureProxy(url, options); + await this.configureProxy(url, options); return options; } - protected configureProxy(endpoint: string, options: CliHttpClientOptions) { + private async resolveProxySettingsOnce() { + if (this.proxySettingsInitialized) { + return; + } + + if (!this.proxySettingsPromise) { + this.proxySettingsPromise = this.cliProxyAgent + .resolveProxySettings() + .catch(() => { + return; + }) + .finally(() => { + this.proxySettingsInitialized = true; + }); + } + + await this.proxySettingsPromise; + } + + protected async configureProxy(endpoint: string, options: CliHttpClientOptions) { const url = new URL(endpoint); if (this.cliProxyAgent.hasProxy()) { const protocol = url.protocol.replace(":", ""); switch (protocol) { case "https": - options.httpsAgent = this.cliProxyAgent.get(protocol); + options.httpsAgent = await this.cliProxyAgent.get(protocol); options.proxy = false; break; case "http": - options.httpAgent = this.cliProxyAgent.get(protocol); + options.httpAgent = await this.cliProxyAgent.get(protocol); options.proxy = false; break; default: diff --git a/packages/cli-core/src/services/CliProxyAgent.ts b/packages/cli-core/src/services/CliProxyAgent.ts index 5c381e02f..7873647d7 100644 --- a/packages/cli-core/src/services/CliProxyAgent.ts +++ b/packages/cli-core/src/services/CliProxyAgent.ts @@ -16,18 +16,14 @@ export class CliProxyAgent { readonly proxySettings = refValue("proxy", {} as never); protected projectPackageJson = inject(ProjectPackageJson); protected cliExeca = inject(CliExeca); - protected tunnel: typeof import("tunnel"); - - async $onInit() { - this.tunnel = await import("tunnel"); - } hasProxy() { return !!this.proxySettings.value.url; } - get(type: "http" | "https") { + async get(type: "http" | "https") { if (this.hasProxy()) { + const tunnel = await import("tunnel"); const {strictSsl = true} = this.proxySettings.value; const url = new URL(this.proxySettings.value.url); const protocol = url.protocol.replace(":", ""); @@ -43,8 +39,8 @@ export class CliProxyAgent { const method = camelCase([type, "over", protocol].join(" ")); - if ((this.tunnel as any)[method]) { - return (this.tunnel as any)[method](options); + if ((tunnel as any)[method]) { + return (tunnel as any)[method](options); } } diff --git a/packages/cli/src/bin/tsed-dev.ts b/packages/cli/src/bin/tsed-dev.ts index b7fb57504..5685521dd 100644 --- a/packages/cli/src/bin/tsed-dev.ts +++ b/packages/cli/src/bin/tsed-dev.ts @@ -88,7 +88,9 @@ async function runViteController(rawArgs: string[]) { let queued = false; const startChild = () => { - childProcess = spawn(process.execPath, [runnerFile, ...rawArgs], { + const cliEntry = process.argv[1]; + + childProcess = spawn(process.execPath, cliEntry ? [cliEntry, "dev", ...rawArgs] : [runnerFile, ...rawArgs], { env: { ...process.env, [RUN_MODE]: "app" From f51d35d7f0feccc313f30aa59b9408a25d003d69 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Apr 2026 14:22:07 +0000 Subject: [PATCH 07/22] Github CI build: __run_2 v7.5.0-rc.3 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a2159e20..8a3b0c77d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.2", + "version": "7.5.0-rc.3", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 54c49dffaa8fc496372bd1e166d5f0cf3ccf7f1c Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 17:17:16 +0200 Subject: [PATCH 08/22] fix(cli): configure Vite server to disable dependency discovery --- packages/cli/src/bin/tsed-dev.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/bin/tsed-dev.ts b/packages/cli/src/bin/tsed-dev.ts index 5685521dd..e59d2824c 100644 --- a/packages/cli/src/bin/tsed-dev.ts +++ b/packages/cli/src/bin/tsed-dev.ts @@ -56,6 +56,10 @@ async function createViteDevServer() { return createServer({ configFile: normalizePath("vite.config.ts"), + optimizeDeps: { + noDiscovery: true, + include: [] + }, server: { middlewareMode: true, hmr: false, @@ -84,10 +88,16 @@ async function runViteController(rawArgs: string[]) { const watch = parseWatchValue(rawArgs); const vite = await createViteDevServer(); let childProcess: ReturnType | undefined; + let childStarted = false; let restarting = false; let queued = false; const startChild = () => { + if (childStarted) { + return; + } + + childStarted = true; const cliEntry = process.argv[1]; childProcess = spawn(process.execPath, cliEntry ? [cliEntry, "dev", ...rawArgs] : [runnerFile, ...rawArgs], { @@ -97,10 +107,17 @@ async function runViteController(rawArgs: string[]) { }, stdio: "inherit" }); + + childProcess.once("exit", () => { + childStarted = false; + childProcess = undefined; + }); }; const stopChild = async () => { - if (!childProcess || childProcess.killed) { + if (!childProcess || childProcess.killed || childProcess.exitCode !== null || childProcess.signalCode !== null) { + childStarted = false; + childProcess = undefined; return; } @@ -108,6 +125,8 @@ async function runViteController(rawArgs: string[]) { childProcess!.once("exit", resolve); childProcess!.kill("SIGTERM"); }); + + childStarted = false; }; const restartChild = async (reason: string, file = "") => { @@ -143,9 +162,7 @@ async function runViteController(rawArgs: string[]) { }); } - vite.watcher.once("ready", () => { - startChild(); - }); + startChild(); const shutdown = async () => { await stopChild(); From c2faa3a4d1607b9bcdb1a4399607c9aa6f240cd8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Apr 2026 15:22:36 +0000 Subject: [PATCH 09/22] Github CI build: __run_2 v7.5.0-rc.4 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a3b0c77d..e63c06448 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.3", + "version": "7.5.0-rc.4", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 9dea2f38fe21e3d4f60464301230aa34e04ae1a6 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 17:30:34 +0200 Subject: [PATCH 10/22] fix(cli): refactor Vite server configuration and improve child process handling --- packages/cli/src/bin/tsed-dev.ts | 44 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/cli/src/bin/tsed-dev.ts b/packages/cli/src/bin/tsed-dev.ts index e59d2824c..7c7463463 100644 --- a/packages/cli/src/bin/tsed-dev.ts +++ b/packages/cli/src/bin/tsed-dev.ts @@ -1,11 +1,11 @@ import {spawn} from "node:child_process"; import {existsSync} from "node:fs"; +import path from "node:path"; import process from "node:process"; -import {fileURLToPath} from "node:url"; - -import {normalizePath} from "@tsed/cli-core"; -import {logger} from "@tsed/di"; +import {fileURLToPath, pathToFileURL} from "node:url"; +const runnerFile = fileURLToPath(import.meta.url); +const configFile = path.resolve(path.dirname(runnerFile), "../../vite.config.ts"); const RUN_MODE = "TSED_VITE_RUN_MODE"; function parseWatchValue(args: string[]) { @@ -43,8 +43,6 @@ function parseWatchValue(args: string[]) { } function assertViteProject() { - const configFile = normalizePath("vite.config.ts"); - if (!existsSync(configFile)) { throw new Error("tsed dev is only available for ViteRuntime projects. Missing vite.config.ts in the current directory."); } @@ -55,13 +53,9 @@ async function createViteDevServer() { const {createServer} = await import("vite"); return createServer({ - configFile: normalizePath("vite.config.ts"), - optimizeDeps: { - noDiscovery: true, - include: [] - }, + configFile, server: { - middlewareMode: true, + middlewareMode: "ssr" as any, hmr: false, ws: false } @@ -84,7 +78,6 @@ async function runViteApp() { } async function runViteController(rawArgs: string[]) { - const runnerFile = fileURLToPath(import.meta.url); const watch = parseWatchValue(rawArgs); const vite = await createViteDevServer(); let childProcess: ReturnType | undefined; @@ -98,9 +91,7 @@ async function runViteController(rawArgs: string[]) { } childStarted = true; - const cliEntry = process.argv[1]; - - childProcess = spawn(process.execPath, cliEntry ? [cliEntry, "dev", ...rawArgs] : [runnerFile, ...rawArgs], { + childProcess = spawn(process.execPath, [runnerFile, ...rawArgs], { env: { ...process.env, [RUN_MODE]: "app" @@ -137,8 +128,7 @@ async function runViteController(rawArgs: string[]) { restarting = true; const suffix = file ? `: ${file}` : ""; - - logger().info(`[tsed-dev] restart (${reason})${suffix}`); + vite.config.logger.info(`[tsed-dev] restart (${reason})${suffix}`); await stopChild(); startChild(); @@ -162,7 +152,16 @@ async function runViteController(rawArgs: string[]) { }); } - startChild(); + vite.watcher.once("ready", () => { + startChild(); + }); + + // Fallback: some environments can miss/lag watcher "ready" when Vite re-optimizes deps. + setTimeout(() => { + if (!childStarted) { + startChild(); + } + }, 2500); const shutdown = async () => { await stopChild(); @@ -184,3 +183,10 @@ export async function dev(rawArgs: string[] = process.argv.slice(2)) { await runViteController(rawArgs); } + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + dev().catch((error) => { + console.error(error); + process.exit(1); + }); +} From 1b271a5229038175fabd2af1654277eae5ecfdf8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Apr 2026 15:35:30 +0000 Subject: [PATCH 11/22] Github CI build: __run_2 v7.5.0-rc.5 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e63c06448..487794575 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.4", + "version": "7.5.0-rc.5", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 9ca12bed2cb26152b1b9382e5dfa2a17eafea85e Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Wed, 8 Apr 2026 17:43:02 +0200 Subject: [PATCH 12/22] fix(cli): update config file path to use current working directory --- packages/cli/src/bin/tsed-dev.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/bin/tsed-dev.ts b/packages/cli/src/bin/tsed-dev.ts index 7c7463463..16499adba 100644 --- a/packages/cli/src/bin/tsed-dev.ts +++ b/packages/cli/src/bin/tsed-dev.ts @@ -4,9 +4,9 @@ import path from "node:path"; import process from "node:process"; import {fileURLToPath, pathToFileURL} from "node:url"; -const runnerFile = fileURLToPath(import.meta.url); -const configFile = path.resolve(path.dirname(runnerFile), "../../vite.config.ts"); const RUN_MODE = "TSED_VITE_RUN_MODE"; +const runnerFile = fileURLToPath(import.meta.url); +const configFile = path.resolve(process.cwd(), "vite.config.ts"); function parseWatchValue(args: string[]) { if (args.includes("--no-watch")) { From 17ac96995f7c0e4c813b7e4bcfe34af3010a3c4e Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Thu, 9 Apr 2026 10:06:19 +0200 Subject: [PATCH 13/22] feat(cli): add support for Bun + Vite runtime and update related configurations --- .../cli/src/commands/init/InitCmd.spec.ts | 20 +++++++++-- packages/cli/src/commands/init/InitCmd.ts | 10 +++--- .../commands/init/config/FeaturesPrompt.ts | 4 +++ .../src/commands/init/config/InitSchema.ts | 8 +++-- .../init/prompts/getFeaturesPrompt.spec.ts | 13 +++++++ .../mcp/schema/ProjectPreferencesSchema.ts | 6 ++-- .../cli/src/interfaces/RenderDataContext.ts | 1 + packages/cli/src/interfaces/RuntimeTypes.ts | 2 +- packages/cli/src/runtimes/RuntimesModule.ts | 5 +-- packages/cli/src/runtimes/index.ts | 1 + .../src/runtimes/supports/BunViteRuntime.ts | 35 +++++++++++++++++++ 11 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 packages/cli/src/runtimes/supports/BunViteRuntime.ts diff --git a/packages/cli/src/commands/init/InitCmd.spec.ts b/packages/cli/src/commands/init/InitCmd.spec.ts index ba1354176..6a5707f80 100644 --- a/packages/cli/src/commands/init/InitCmd.spec.ts +++ b/packages/cli/src/commands/init/InitCmd.spec.ts @@ -67,7 +67,7 @@ describe("InitCmd", () => { vi.stubGlobal("Bun", {}); const command = await CliPlatformTest.invoke(InitCmd); - vi.spyOn((command as any).runtimes, "list").mockReturnValue(["node", "bun"]); + vi.spyOn((command as any).runtimes, "list").mockReturnValue(["node", "bun", "bun-vite"]); vi.spyOn((command as any).packageManagers, "list").mockReturnValue(["yarn", "npm", "pnpm", "bun"]); const prompts = await command.$prompt({ @@ -79,7 +79,7 @@ describe("InitCmd", () => { expect(runtime).toBeDefined(); expect(packageManager).toBeDefined(); - expect((runtime as any).choices.map((choice: any) => choice.value)).toEqual(["bun"]); + expect((runtime as any).choices.map((choice: any) => choice.value)).toEqual(["bun", "bun-vite"]); expect((packageManager as any).choices.map((choice: any) => choice.value)).toEqual(["bun"]); }); @@ -99,6 +99,22 @@ describe("InitCmd", () => { expect(mapped.packageManager).toEqual("bun"); }); + it("should preserve bun-vite runtime in bunx mode", async () => { + vi.stubGlobal("Bun", {}); + + const command = await CliPlatformTest.invoke(InitCmd); + const mapped = command.$mapContext({ + root: ".", + projectName: "project", + features: [], + runtime: "bun-vite", + packageManager: "npm" + }); + + expect(mapped.runtime).toEqual("bun-vite"); + expect(mapped.packageManager).toEqual("bun"); + }); + it("should write premium RC files without returning task-like results", async () => { const command = await CliPlatformTest.invoke(InitCmd); const createFromTemplate = vi.spyOn((command as any).project, "createFromTemplate").mockResolvedValue({rendered: true}); diff --git a/packages/cli/src/commands/init/InitCmd.ts b/packages/cli/src/commands/init/InitCmd.ts index 293d328f9..07db0a188 100644 --- a/packages/cli/src/commands/init/InitCmd.ts +++ b/packages/cli/src/commands/init/InitCmd.ts @@ -32,6 +32,7 @@ import type {InitOptions} from "../../interfaces/InitCmdOptions.js"; import {PlatformsModule} from "../../platforms/PlatformsModule.js"; import {RuntimesModule} from "../../runtimes/RuntimesModule.js"; import {BunRuntime} from "../../runtimes/supports/BunRuntime.js"; +import {BunViteRuntime} from "../../runtimes/supports/BunViteRuntime.js"; import {NodeRuntime} from "../../runtimes/supports/NodeRuntime.js"; import {ViteRuntime} from "../../runtimes/supports/ViteRuntime.js"; import {CliProjectService} from "../../services/CliProjectService.js"; @@ -102,7 +103,7 @@ export class InitCmd implements CommandProvider { ctx = mapToContext(ctx); if (this.isLaunchedWithBunx()) { - ctx.runtime = "bun"; + ctx.runtime ??= "bun"; ctx.packageManager = "bun"; } @@ -128,7 +129,7 @@ export class InitCmd implements CommandProvider { } protected filterOnlyBun(values: string[]) { - const filtered = values.filter((value) => value === "bun"); + const filtered = values.filter((value) => ["bun", "bun-vite"].includes(value)); return filtered.length ? filtered : values; } @@ -188,8 +189,9 @@ export class InitCmd implements CommandProvider { ctx = { ...ctx, node: runtime instanceof NodeRuntime, - bun: runtime instanceof BunRuntime, - vite: runtime instanceof ViteRuntime, + bun: runtime instanceof BunRuntime || runtime instanceof BunViteRuntime, + bunVite: runtime instanceof BunViteRuntime, + vite: runtime instanceof ViteRuntime || runtime instanceof BunViteRuntime, compiled: runtime.isCompiled() }; diff --git a/packages/cli/src/commands/init/config/FeaturesPrompt.ts b/packages/cli/src/commands/init/config/FeaturesPrompt.ts index a98236a33..939709938 100644 --- a/packages/cli/src/commands/init/config/FeaturesPrompt.ts +++ b/packages/cli/src/commands/init/config/FeaturesPrompt.ts @@ -366,6 +366,10 @@ export const FeaturesMap: Record = { name: "Node.js + Vite", checked: false }, + "bun-vite": { + name: "Bun + Vite", + checked: false + }, node: { name: "Node.js + SWC", checked: true diff --git a/packages/cli/src/commands/init/config/InitSchema.ts b/packages/cli/src/commands/init/config/InitSchema.ts index ba997119f..da94b7a52 100644 --- a/packages/cli/src/commands/init/config/InitSchema.ts +++ b/packages/cli/src/commands/init/config/InitSchema.ts @@ -282,6 +282,10 @@ export const InitSchema = () => { label: "Node.js + Vite", value: "vite" }, + { + label: "Bun.js + Vite", + value: "bun-vite" + }, { label: "Node.js + SWC", value: "node" @@ -295,7 +299,7 @@ export const InitSchema = () => { value: "webpack" }, { - label: "Bun", + label: "Bun.js", value: "bun" } ].filter((o) => availableRuntimes.includes(o.value)) @@ -306,7 +310,7 @@ export const InitSchema = () => { packageManager: s .enums(availablePackageManagers as any[]) .prompt("Choose the package manager:") - .when((answers) => answers.runtime !== "bun") + .when((answers) => !["bun", "bun-vite"].includes(answers.runtime)) .default(PackageManager.NPM) .choices( [ diff --git a/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts b/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts index b2c6b778f..34a2bc806 100644 --- a/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts +++ b/packages/cli/src/commands/init/prompts/getFeaturesPrompt.spec.ts @@ -20,6 +20,19 @@ describe("getFeaturesPrompt", () => { ); }); + it("should map bun-vite runtime choice without throwing", () => { + const prompt = getFeaturesPrompt(["bun", "bun-vite"], ["bun"], {}); + const runtimePrompt = prompt.find((item: any) => item.name === "runtime"); + + expect(runtimePrompt).toBeDefined(); + expect((runtimePrompt as any).choices).toEqual( + expect.arrayContaining([ + expect.objectContaining({value: "bun", name: "Bun.js"}), + expect.objectContaining({value: "bun-vite", name: "Bun + Vite"}) + ]) + ); + }); + it("should add a provider info", () => { const prompt = getFeaturesPrompt(["node", "bun"], ["yarn", "npm", "pnpm", "bun"], {}); diff --git a/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts b/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts index 5c0368eab..047f9e12b 100644 --- a/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts +++ b/packages/cli/src/commands/mcp/schema/ProjectPreferencesSchema.ts @@ -10,8 +10,10 @@ export const ProjectPreferenceSchema = s packageManager: s.string().enum(PackageManager).description("Used project manager to install dependencies"), runtime: s .string() - .enum("vite", "node", "babel", "swc", "webpack", "bun") - .description("The javascript runtime used to start application (node, node + webpack, node + swc, node + babel, bun, vite)"), + .enum("vite", "bun-vite", "node", "babel", "swc", "webpack", "bun") + .description( + "The javascript runtime used to start application (node + vite, bun + vite, node + webpack, node + swc, node + babel, bun)" + ), platform: s.string().enum(PlatformType).description("Node.js framework used to run server (Express, Koa, Fastify)") }) .optional() diff --git a/packages/cli/src/interfaces/RenderDataContext.ts b/packages/cli/src/interfaces/RenderDataContext.ts index 61ad0840f..7162dec67 100644 --- a/packages/cli/src/interfaces/RenderDataContext.ts +++ b/packages/cli/src/interfaces/RenderDataContext.ts @@ -50,6 +50,7 @@ export interface RenderDataContext extends CommandData, TsED.RenderDataContext { configPostgres?: boolean; barrels?: string; bun?: boolean; + bunVite?: boolean; vite?: boolean; node?: boolean; compiled?: boolean; diff --git a/packages/cli/src/interfaces/RuntimeTypes.ts b/packages/cli/src/interfaces/RuntimeTypes.ts index 92f32765f..5d2a2a3ff 100644 --- a/packages/cli/src/interfaces/RuntimeTypes.ts +++ b/packages/cli/src/interfaces/RuntimeTypes.ts @@ -1,4 +1,4 @@ -export type RuntimeTypes = "node" | "babel" | "swc" | "webpack" | "bun" | "vite"; +export type RuntimeTypes = "node" | "babel" | "swc" | "webpack" | "bun" | "vite" | "bun-vite"; declare global { namespace TsED { diff --git a/packages/cli/src/runtimes/RuntimesModule.ts b/packages/cli/src/runtimes/RuntimesModule.ts index 36cebec44..ed9821191 100644 --- a/packages/cli/src/runtimes/RuntimesModule.ts +++ b/packages/cli/src/runtimes/RuntimesModule.ts @@ -4,6 +4,7 @@ import {inject, injectable, injectMany} from "@tsed/di"; import {BabelRuntime} from "./supports/BabelRuntime.js"; import {BaseRuntime} from "./supports/BaseRuntime.js"; import {BunRuntime} from "./supports/BunRuntime.js"; +import {BunViteRuntime} from "./supports/BunViteRuntime.js"; import {NodeRuntime} from "./supports/NodeRuntime.js"; import {ViteRuntime} from "./supports/ViteRuntime.js"; import {WebpackRuntime} from "./supports/WebpackRuntime.js"; @@ -24,7 +25,7 @@ export class RuntimesModule { init(ctx: RuntimeInitOptions) { ctx.runtime = ctx.runtime || this.get().name; - if (ctx.runtime === "bun") { + if (ctx.runtime.startsWith("bun")) { ctx.packageManager = "bun"; } } @@ -63,4 +64,4 @@ export class RuntimesModule { } } -injectable(RuntimesModule).imports([ViteRuntime, NodeRuntime, BabelRuntime, WebpackRuntime, BunRuntime]); +injectable(RuntimesModule).imports([ViteRuntime, BunViteRuntime, NodeRuntime, BabelRuntime, WebpackRuntime, BunRuntime]); diff --git a/packages/cli/src/runtimes/index.ts b/packages/cli/src/runtimes/index.ts index 1378c58a0..6fc0663ad 100644 --- a/packages/cli/src/runtimes/index.ts +++ b/packages/cli/src/runtimes/index.ts @@ -2,6 +2,7 @@ export * from "./RuntimesModule.js"; export * from "./supports/BabelRuntime.js"; export * from "./supports/BaseRuntime.js"; export * from "./supports/BunRuntime.js"; +export * from "./supports/BunViteRuntime.js"; export * from "./supports/NodeRuntime.js"; export * from "./supports/ViteRuntime.js"; export * from "./supports/WebpackRuntime.js"; diff --git a/packages/cli/src/runtimes/supports/BunViteRuntime.ts b/packages/cli/src/runtimes/supports/BunViteRuntime.ts new file mode 100644 index 000000000..3b6dd4aba --- /dev/null +++ b/packages/cli/src/runtimes/supports/BunViteRuntime.ts @@ -0,0 +1,35 @@ +import {injectable} from "@tsed/di"; + +import {BaseRuntime} from "./BaseRuntime.js"; + +export class BunViteRuntime extends BaseRuntime { + readonly name = "bun-vite"; + readonly cmd = "bun"; + readonly order: number = 1; + + files() { + return ["vite.config.ts"]; + } + + compile(): string { + return "tsed build"; + } + + startDev(): string { + return "tsed dev"; + } + + startProd(args: string): string { + return `bun ${args}`; + } + + devDependencies(): Record { + return { + "@tsed/cli": "{{cliVersion}}", + typescript: "latest", + vite: "latest" + }; + } +} + +injectable(BunViteRuntime).type("runtime"); From e753ff1bab661708180dcf546aac9ceb5789402b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 9 Apr 2026 09:12:47 +0000 Subject: [PATCH 14/22] Github CI build: __run_2 v7.5.0-rc.6 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 487794575..2a48c19af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.5", + "version": "7.5.0-rc.6", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 1df5024920df428479a81ad62a6a47aaf4450fa9 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Thu, 16 Apr 2026 11:11:03 +0200 Subject: [PATCH 15/22] fix(cli): implement Vite binary resolution and add corresponding tests --- packages/cli/src/bin/tsed-build.spec.ts | 53 ++++++++ packages/cli/src/bin/tsed-build.ts | 20 ++- scripts/vite/vite-runner.js | 162 ++++++++++++++++++++++++ 3 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 packages/cli/src/bin/tsed-build.spec.ts create mode 100644 scripts/vite/vite-runner.js diff --git a/packages/cli/src/bin/tsed-build.spec.ts b/packages/cli/src/bin/tsed-build.spec.ts new file mode 100644 index 000000000..f67af6d81 --- /dev/null +++ b/packages/cli/src/bin/tsed-build.spec.ts @@ -0,0 +1,53 @@ +import {mkdtemp, rm, writeFile} from "node:fs/promises"; +import {tmpdir} from "node:os"; +import path from "node:path"; +import {pathToFileURL} from "node:url"; + +import {describe, expect, it} from "vitest"; + +import {resolveViteBin} from "./tsed-build.js"; + +async function withTempDir(run: (cwd: string) => Promise) { + const cwd = await mkdtemp(path.join(tmpdir(), "tsed-build-")); + + try { + await run(cwd); + } finally { + await rm(cwd, {recursive: true, force: true}); + } +} + +describe("tsed-build", () => { + it("should resolve vite binary from vite/package.json bin object", async () => { + await withTempDir(async (cwd) => { + const packageJsonPath = path.join(cwd, "package.json"); + await writeFile(packageJsonPath, JSON.stringify({bin: {vite: "bin/vite.js"}})); + + const viteBin = await resolveViteBin(async () => pathToFileURL(packageJsonPath).href); + + expect(viteBin).toEqual(path.join(cwd, "bin/vite.js")); + }); + }); + + it("should resolve vite binary from vite/package.json string bin", async () => { + await withTempDir(async (cwd) => { + const packageJsonPath = path.join(cwd, "package.json"); + await writeFile(packageJsonPath, JSON.stringify({bin: "bin/vite.js"})); + + const viteBin = await resolveViteBin(async () => pathToFileURL(packageJsonPath).href); + + expect(viteBin).toEqual(path.join(cwd, "bin/vite.js")); + }); + }); + + it("should throw when vite binary cannot be resolved", async () => { + await withTempDir(async (cwd) => { + const packageJsonPath = path.join(cwd, "package.json"); + await writeFile(packageJsonPath, JSON.stringify({name: "vite"})); + + await expect(resolveViteBin(async () => pathToFileURL(packageJsonPath).href)).rejects.toThrowError( + "Unable to resolve Vite CLI binary from vite/package.json" + ); + }); + }); +}); diff --git a/packages/cli/src/bin/tsed-build.ts b/packages/cli/src/bin/tsed-build.ts index e05e71540..0b63e7964 100644 --- a/packages/cli/src/bin/tsed-build.ts +++ b/packages/cli/src/bin/tsed-build.ts @@ -1,4 +1,6 @@ import {spawn} from "node:child_process"; +import {readFile} from "node:fs/promises"; +import path from "node:path"; import process from "node:process"; import {fileURLToPath} from "node:url"; @@ -21,7 +23,23 @@ function runNode(cmd: string, args: string[]) { }); } +type ResolveFn = (specifier: string) => string | Promise; + +export async function resolveViteBin(resolve: ResolveFn = import.meta.resolve) { + const packageJsonPath = fileURLToPath(await resolve("vite/package.json")); + const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8")) as { + bin?: string | Record; + }; + const binRelativePath = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.vite; + + if (!binRelativePath) { + throw new Error("Unable to resolve Vite CLI binary from vite/package.json"); + } + + return path.resolve(path.dirname(packageJsonPath), binRelativePath); +} + export async function build(rawArgs: string[] = process.argv.slice(2)) { - const viteBin = fileURLToPath(import.meta.resolve("vite/bin/vite.js")); + const viteBin = await resolveViteBin(); await runNode(process.execPath, [viteBin, "build", ...rawArgs]); } diff --git a/scripts/vite/vite-runner.js b/scripts/vite/vite-runner.js new file mode 100644 index 000000000..c4a9760af --- /dev/null +++ b/scripts/vite/vite-runner.js @@ -0,0 +1,162 @@ +import {spawn} from "node:child_process"; +import path from "node:path"; +import process from "node:process"; +import {fileURLToPath} from "node:url"; + +import {createServer} from "vite"; + +const RUN_MODE = process.env.TSED_VITE_RUN_MODE || "controller"; +const runnerFile = fileURLToPath(import.meta.url); +const configFile = path.resolve(path.dirname(runnerFile), "../../vite.config.ts"); + +function parseWatchValue(args) { + if (args.includes("--no-watch")) return false; + + const watchIndex = args.findIndex((arg) => arg === "--watch" || arg.startsWith("--watch=")); + if (watchIndex === -1) return true; + + const watchArg = args[watchIndex]; + if (watchArg === "--watch") { + const nextValue = args[watchIndex + 1]; + if (!nextValue || nextValue.startsWith("-")) return true; + return nextValue !== "false"; + } + + if (watchArg === "--watch=false") return false; + if (watchArg === "--watch=true") return true; + return true; +} + +async function createViteDevServer() { + return createServer({ + configFile, + server: { + middlewareMode: "ssr", + hmr: false, + ws: false + } + }); +} + +async function runApp() { + const vite = await createViteDevServer(); + + const shutdown = async () => { + await vite.close(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + await vite.ssrLoadModule("/src/index.ts"); + await new Promise(() => {}); +} + +async function runController(rawArgs) { + const watch = parseWatchValue(rawArgs); + const vite = await createViteDevServer(); + + let childProcess; + let childStarted = false; + let restarting = false; + let queued = false; + + const startChild = () => { + if (childStarted) return; + + childStarted = true; + childProcess = spawn(process.execPath, [runnerFile, ...rawArgs], { + env: { + ...process.env, + TSED_VITE_RUN_MODE: "app" + }, + stdio: "inherit" + }); + + childProcess.once("exit", () => { + childStarted = false; + childProcess = undefined; + }); + }; + + const stopChild = async () => { + if (!childProcess || childProcess.killed || childProcess.exitCode !== null || childProcess.signalCode !== null) { + childStarted = false; + childProcess = undefined; + return; + } + + await new Promise((resolve) => { + childProcess.once("exit", resolve); + childProcess.kill("SIGTERM"); + }); + + childStarted = false; + }; + + const restartChild = async (reason, file = "") => { + if (restarting) { + queued = true; + return; + } + + restarting = true; + const suffix = file ? `: ${file}` : ""; + vite.config.logger.info(`[tsed-dev] restart (${reason})${suffix}`); + + await stopChild(); + startChild(); + + restarting = false; + + if (queued) { + queued = false; + await restartChild("queued"); + } + }; + + if (watch) { + vite.watcher.on("all", async (event, file) => { + if (!file || file.includes("node_modules") || file.includes(".git") || file.includes("/dist/")) return; + if (["add", "change", "unlink"].includes(event)) { + await restartChild(event, file); + } + }); + } + + vite.watcher.once("ready", () => { + startChild(); + }); + + setTimeout(() => { + if (!childStarted) startChild(); + }, 2500); + + const shutdown = async () => { + await stopChild(); + await vite.close(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + await new Promise(() => {}); +} + +async function run() { + const rawArgs = process.argv.slice(2); + + if (RUN_MODE === "app") { + await runApp(); + return; + } + + await runController(rawArgs); +} + +run().catch((error) => { + console.error(error); + process.exit(1); +}); From f0eef006a7b906565692d691e68683c8a93dc256 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Thu, 16 Apr 2026 11:11:25 +0200 Subject: [PATCH 16/22] docs: update dependencies and improve theme integration --- docs/.vitepress/theme/index.ts | 3 +- docs/package.json | 4 +- docs/yarn.lock | 507 +++++++++++++++++---------------- 3 files changed, 265 insertions(+), 249 deletions(-) diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index c2a8d04b4..b8ac726ad 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,7 +1,7 @@ // https://vitepress.dev/guide/custom-theme import "./style.css"; -import {DefaultTheme} from "@tsed/vitepress-theme"; +import {DefaultTheme, DocActions} from "@tsed/vitepress-theme"; import HomeBanner from "@tsed/vitepress-theme/organisms/home/HomeBanner.vue"; import HomeBeforeFeatures from "@tsed/vitepress-theme/organisms/home/HomeBeforeFeatures.vue"; import HomeBody from "@tsed/vitepress-theme/organisms/home/HomeBody.vue"; @@ -17,6 +17,7 @@ export default { extends: DefaultTheme, Layout: () => { return h(DefaultTheme.Layout, null, { + "doc-before": () => h(DocActions), "home-hero-image": () => h(HomeBanner, null, { default: () => diff --git a/docs/package.json b/docs/package.json index d45f1ee72..ff55eb418 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@clack/prompts": "^1.0.0-alpha.10", - "@tsed/vitepress-theme": "1.5.7", + "@tsed/vitepress-theme": "^1.7.0", "@vueuse/core": "10.11.0", "axios": "1.12.0", "fs-extra": "^11.2.0", @@ -21,7 +21,7 @@ "remark-parse": "^9.0.0", "remark-stringify": "^9.0.1", "unified": "^9.2.2", - "vitepress": "1.5.0" + "vitepress": "1.6.4" }, "devDependencies": { "autoprefixer": "^10.4.19", diff --git a/docs/yarn.lock b/docs/yarn.lock index 28cdcdeba..1834fb34c 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -17,46 +17,46 @@ __metadata: languageName: node linkType: hard -"@algolia/autocomplete-core@npm:1.17.9": - version: 1.17.9 - resolution: "@algolia/autocomplete-core@npm:1.17.9" +"@algolia/autocomplete-core@npm:1.17.7": + version: 1.17.7 + resolution: "@algolia/autocomplete-core@npm:1.17.7" dependencies: - "@algolia/autocomplete-plugin-algolia-insights": "npm:1.17.9" - "@algolia/autocomplete-shared": "npm:1.17.9" - checksum: 10/cf4f0f1d9e0ca4e7f1ea25291b270e47315385cbda4a01bbc0c56c3659d21f2357ec2026a1b828f063d4cd1d13509b6f76960f0bfd51acafd76a487a752eec3c + "@algolia/autocomplete-plugin-algolia-insights": "npm:1.17.7" + "@algolia/autocomplete-shared": "npm:1.17.7" + checksum: 10/ff92dd5b4f5c91db8b388efd99f07dc856b27e3560146ff59cea6dadd637b0e12dd6701280fab12401ef1122abdd966e8645e4034812bcafa2b987733bda1217 languageName: node linkType: hard -"@algolia/autocomplete-plugin-algolia-insights@npm:1.17.9": - version: 1.17.9 - resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.17.9" +"@algolia/autocomplete-plugin-algolia-insights@npm:1.17.7": + version: 1.17.7 + resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.17.7" dependencies: - "@algolia/autocomplete-shared": "npm:1.17.9" + "@algolia/autocomplete-shared": "npm:1.17.7" peerDependencies: search-insights: ">= 1 < 3" - checksum: 10/5cd16d91aff4e5eb0823387d480d04d4cc0e8f1ebf9970f91f0c0bc88a358b09112218d6c9762e35f444a22251a3bbe0934a82fcd55eab32fc2701c9399f3baf + checksum: 10/8061d865d836c5aae142f747d0441cbe341ea7a6565c724cb26e11321117e998df4a1782caa89f579858285e5d98d5afd55e1a77de11cffe822aebe8d0925d98 languageName: node linkType: hard -"@algolia/autocomplete-preset-algolia@npm:1.17.9": - version: 1.17.9 - resolution: "@algolia/autocomplete-preset-algolia@npm:1.17.9" +"@algolia/autocomplete-preset-algolia@npm:1.17.7": + version: 1.17.7 + resolution: "@algolia/autocomplete-preset-algolia@npm:1.17.7" dependencies: - "@algolia/autocomplete-shared": "npm:1.17.9" + "@algolia/autocomplete-shared": "npm:1.17.7" peerDependencies: "@algolia/client-search": ">= 4.9.1 < 6" algoliasearch: ">= 4.9.1 < 6" - checksum: 10/7343b54aa6a7d9a75acf4dfbcc007bf328d1ae991f6bb4a92893bf5492b64ba52b331e9edd2da05008db080aaa6c91889d7ea2ccf0cc99ef44d55440bf22de38 + checksum: 10/8f0cf9a10ea0704d15cec6ecc97b625b395b6d388b4b440145b0560f92e36ff39af9446df6b2b1831bbdf79d0fcb54a3ad58fc6d1fd7838cb049faa1326a37b2 languageName: node linkType: hard -"@algolia/autocomplete-shared@npm:1.17.9": - version: 1.17.9 - resolution: "@algolia/autocomplete-shared@npm:1.17.9" +"@algolia/autocomplete-shared@npm:1.17.7": + version: 1.17.7 + resolution: "@algolia/autocomplete-shared@npm:1.17.7" peerDependencies: "@algolia/client-search": ">= 4.9.1 < 6" algoliasearch: ">= 4.9.1 < 6" - checksum: 10/32f74fa2efb0a67def376a0a040b553c9109fb0891f6d4dd525048388b613a6ea1440aeff672b7b67da47b0b584f40c37826c34b5346f0a35bd64c08d559acb6 + checksum: 10/5ca9452c7d0273e7a4beded682473f5c523fc9e382a9817335985973aba036bbd52cd5121daf6bc809fc7c68878b68b2f7a534436b4bb898ba560f6a52846172 languageName: node linkType: hard @@ -223,14 +223,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.28.5": - version: 7.29.0 - resolution: "@babel/parser@npm:7.29.0" +"@babel/parser@npm:^7.29.2": + version: 7.29.2 + resolution: "@babel/parser@npm:7.29.2" dependencies: "@babel/types": "npm:^7.29.0" bin: parser: ./bin/babel-parser.js - checksum: 10/b1576dca41074997a33ee740d87b330ae2e647f4b7da9e8d2abd3772b18385d303b0cee962b9b88425e0f30d58358dbb8d63792c1a2d005c823d335f6a029747 + checksum: 10/45d050bf75aa5194b3255f156173e8553d615ff5a2434674cc4a10cdc7c261931befb8618c996a1c449b87f0ef32a3407879af2ac967d95dc7b4fdbae7037efa languageName: node linkType: hard @@ -265,35 +265,35 @@ __metadata: languageName: node linkType: hard -"@docsearch/css@npm:3.9.0, @docsearch/css@npm:^3.6.2": - version: 3.9.0 - resolution: "@docsearch/css@npm:3.9.0" - checksum: 10/088a05f7e7d5192feee1f5c8bfffcba13c87de2c45588080513be238ee974406ca9ad2fe7434082ad0ca23f54c0d39d486903da780904a03cbbfbe05db488cfe +"@docsearch/css@npm:3.8.2": + version: 3.8.2 + resolution: "@docsearch/css@npm:3.8.2" + checksum: 10/033f324b8a25d8e13af52174ef95a4a767466da4f621a39d2b6c1704d612414d60678900e3883d96093bea7e0945b86ab302cc1f6addd6b4d0e4f74a253e389a languageName: node linkType: hard -"@docsearch/js@npm:^3.6.2": - version: 3.9.0 - resolution: "@docsearch/js@npm:3.9.0" +"@docsearch/js@npm:3.8.2": + version: 3.8.2 + resolution: "@docsearch/js@npm:3.8.2" dependencies: - "@docsearch/react": "npm:3.9.0" + "@docsearch/react": "npm:3.8.2" preact: "npm:^10.0.0" - checksum: 10/806ae98ffd0958de3f597b62b740a3a8a5922d7cf5d061550beaa46e1e42d3e3c468e41cb8ec76bdc1dbb6115a53664fcec8aa8fee01bf6b64bb1069918347f0 + checksum: 10/06fdd8130168289b439ece4ff67ba70dea84746a1e124005c3a4fb64cf9c12e1c6eaafc1e1505b85412974698128a82a44b22302d555bc28a15ad9d93c86b8be languageName: node linkType: hard -"@docsearch/react@npm:3.9.0": - version: 3.9.0 - resolution: "@docsearch/react@npm:3.9.0" +"@docsearch/react@npm:3.8.2": + version: 3.8.2 + resolution: "@docsearch/react@npm:3.8.2" dependencies: - "@algolia/autocomplete-core": "npm:1.17.9" - "@algolia/autocomplete-preset-algolia": "npm:1.17.9" - "@docsearch/css": "npm:3.9.0" + "@algolia/autocomplete-core": "npm:1.17.7" + "@algolia/autocomplete-preset-algolia": "npm:1.17.7" + "@docsearch/css": "npm:3.8.2" algoliasearch: "npm:^5.14.2" peerDependencies: - "@types/react": ">= 16.8.0 < 20.0.0" - react: ">= 16.8.0 < 20.0.0" - react-dom: ">= 16.8.0 < 20.0.0" + "@types/react": ">= 16.8.0 < 19.0.0" + react: ">= 16.8.0 < 19.0.0" + react-dom: ">= 16.8.0 < 19.0.0" search-insights: ">= 1 < 3" peerDependenciesMeta: "@types/react": @@ -304,7 +304,7 @@ __metadata: optional: true search-insights: optional: true - checksum: 10/26f8dbb7bb88ac2b07c41104ab4f13054495feaea613eb8274ba637435eadce9d192f6b52526ef1d3d36da740015b1f213aeb94cc58497718bd4ac32c1ed974b + checksum: 10/ac543830700dcefb09da962b7fd0e3daff8269cdfdf455f2de0c78370776700a7b8e55c4c65fc497dc66a25d81f41f9d0417833bc5478ed7ecef71eaf81a16d3 languageName: node linkType: hard @@ -469,12 +469,12 @@ __metadata: languageName: node linkType: hard -"@iconify-json/simple-icons@npm:^1.2.10": - version: 1.2.69 - resolution: "@iconify-json/simple-icons@npm:1.2.69" +"@iconify-json/simple-icons@npm:^1.2.21": + version: 1.2.78 + resolution: "@iconify-json/simple-icons@npm:1.2.78" dependencies: "@iconify/types": "npm:*" - checksum: 10/1ad8bd4018ab3307c579cde9d9ca501ba7b709f7166bdaeb06fcec0f600ec83467af906785f292045dc7f1c33f73c9813f810feb64b2de4099ebe2654f732382 + checksum: 10/f2b265647392e99368c913f82ed910b820151b93f201a6b020761ce756d79b7f951edb35804f5411e7234dd961de6ec9b870b53fb8387e0443e19a63eb8884dd languageName: node linkType: hard @@ -716,80 +716,80 @@ __metadata: languageName: node linkType: hard -"@shikijs/core@npm:1.29.2, @shikijs/core@npm:^1.22.2": - version: 1.29.2 - resolution: "@shikijs/core@npm:1.29.2" +"@shikijs/core@npm:2.5.0, @shikijs/core@npm:^2.1.0": + version: 2.5.0 + resolution: "@shikijs/core@npm:2.5.0" dependencies: - "@shikijs/engine-javascript": "npm:1.29.2" - "@shikijs/engine-oniguruma": "npm:1.29.2" - "@shikijs/types": "npm:1.29.2" - "@shikijs/vscode-textmate": "npm:^10.0.1" + "@shikijs/engine-javascript": "npm:2.5.0" + "@shikijs/engine-oniguruma": "npm:2.5.0" + "@shikijs/types": "npm:2.5.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" "@types/hast": "npm:^3.0.4" hast-util-to-html: "npm:^9.0.4" - checksum: 10/83dc5e86efc587d513268175ff43e8273567d2c6616d725bff15b08cf243d90f9371d6fa76ba49bb0e9823fc9947c8d8c650c81cfb19c3eb726178326f639a55 + checksum: 10/de45cd5c38a375443e88107b4ef0892c764d485021665a22a52d429500d20a9c77464d50dd8cdf8b5bdd6f0082a0ca50e048f1ccca9241e6e087ad7d7e906cbb languageName: node linkType: hard -"@shikijs/engine-javascript@npm:1.29.2": - version: 1.29.2 - resolution: "@shikijs/engine-javascript@npm:1.29.2" +"@shikijs/engine-javascript@npm:2.5.0": + version: 2.5.0 + resolution: "@shikijs/engine-javascript@npm:2.5.0" dependencies: - "@shikijs/types": "npm:1.29.2" - "@shikijs/vscode-textmate": "npm:^10.0.1" - oniguruma-to-es: "npm:^2.2.0" - checksum: 10/b49461ff7152650ffdbd77332d1c70e24a2ff1abe869e1038694b410194c6403fe5e8fce104fdd305d10c18702a50c1edbdb87172aa09f11340bc1203ed38488 + "@shikijs/types": "npm:2.5.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + oniguruma-to-es: "npm:^3.1.0" + checksum: 10/30f4dd19150cf1f61f7fca1f58f8d35ad4e32dcd49726b49eb37da1f2c133ca49c01ca506551ce3782cbcaf2e528bc0f350176ae2a0f90a55fb7eb74c7e02094 languageName: node linkType: hard -"@shikijs/engine-oniguruma@npm:1.29.2": - version: 1.29.2 - resolution: "@shikijs/engine-oniguruma@npm:1.29.2" +"@shikijs/engine-oniguruma@npm:2.5.0": + version: 2.5.0 + resolution: "@shikijs/engine-oniguruma@npm:2.5.0" dependencies: - "@shikijs/types": "npm:1.29.2" - "@shikijs/vscode-textmate": "npm:^10.0.1" - checksum: 10/bb3e2c01da84d573251ebc289b1ecf815261024dea5bddb93ad56c3504a71cde3630db070be401ed3bbcd23a8a839ec78984a82317f9c9d0bba58daed935b781 + "@shikijs/types": "npm:2.5.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + checksum: 10/53e85030f4d3992eb5f8bc32af234e33fac0abe017475572f7d41df40327fce8450ec0253002100187139ac1b8b100759059cd880c426cdff257ed0b2bc9f41a languageName: node linkType: hard -"@shikijs/langs@npm:1.29.2": - version: 1.29.2 - resolution: "@shikijs/langs@npm:1.29.2" +"@shikijs/langs@npm:2.5.0": + version: 2.5.0 + resolution: "@shikijs/langs@npm:2.5.0" dependencies: - "@shikijs/types": "npm:1.29.2" - checksum: 10/01f62d31c653c718a992918357e54d2d312c8da407997565fc19056fbf47f0fadc0f9f4b5fe1e1ba7b7d08e3984fb1f962159503ef0edd81fab5ee8bfdbf9080 + "@shikijs/types": "npm:2.5.0" + checksum: 10/6d50b5080e6d521a021221f32b93be07eb007e6806ba4d149cbc5fb6566b71145a3edcc49fbdc6fc9a10eeef543d4e0088916bd01b29eeddb054f13b89c86710 languageName: node linkType: hard -"@shikijs/themes@npm:1.29.2": - version: 1.29.2 - resolution: "@shikijs/themes@npm:1.29.2" +"@shikijs/themes@npm:2.5.0": + version: 2.5.0 + resolution: "@shikijs/themes@npm:2.5.0" dependencies: - "@shikijs/types": "npm:1.29.2" - checksum: 10/b81606dd882136e3fd751d0829133b5e66b10b8e32bd52ce16e7eac8755891c23e43f3ce06e65b97a75d2bc3b17e7fdb9115e9812679bb820ab163915868fd8b + "@shikijs/types": "npm:2.5.0" + checksum: 10/0f979e58df8a363dd965cd0aba9106a020a21d90d261f037a3b9d433c896fa748d5defa761f5916eb8c89bf7fd41ba53d53e520cfaecbf307bdde17aefce33ed languageName: node linkType: hard -"@shikijs/transformers@npm:^1.22.2": - version: 1.29.2 - resolution: "@shikijs/transformers@npm:1.29.2" +"@shikijs/transformers@npm:^2.1.0": + version: 2.5.0 + resolution: "@shikijs/transformers@npm:2.5.0" dependencies: - "@shikijs/core": "npm:1.29.2" - "@shikijs/types": "npm:1.29.2" - checksum: 10/ee26b670087f1be960b0fbf2b86b9cb9ea33342fceddf3c2b0e30252d576710ed482f8bdd1ef50c4e041b3f0b32542fea28e264069cd613897c3f54b7bebde86 + "@shikijs/core": "npm:2.5.0" + "@shikijs/types": "npm:2.5.0" + checksum: 10/f69c01d6c6c233031c1fceb597bcdadaa5cdf3316728ae21fa2ab6b5ca6dc4d76b70e17d579923e1eeab572bdf4322cdbc62a34e4e083f5f95e1f73bd478201e languageName: node linkType: hard -"@shikijs/types@npm:1.29.2, @shikijs/types@npm:^1.22.2": - version: 1.29.2 - resolution: "@shikijs/types@npm:1.29.2" +"@shikijs/types@npm:2.5.0, @shikijs/types@npm:^2.1.0": + version: 2.5.0 + resolution: "@shikijs/types@npm:2.5.0" dependencies: - "@shikijs/vscode-textmate": "npm:^10.0.1" + "@shikijs/vscode-textmate": "npm:^10.0.2" "@types/hast": "npm:^3.0.4" - checksum: 10/579e64b6e8cb83023232b8060b08f51cff3909b199d0d1a0c58ed500c898dd34b74bf0457336fa2e6bee1005889e198d7d924347ad616eee30c6ae4c89a67ab8 + checksum: 10/d285f7422fc8eca0d92b5d2438f8fa6a74423b000ef9e2abdd15dd85fb0062e8fe8db6ea6af7a9f21a7d322845c5ad39a9ab7e272ff240358ad4a533a7e4df1d languageName: node linkType: hard -"@shikijs/vscode-textmate@npm:^10.0.1": +"@shikijs/vscode-textmate@npm:^10.0.2": version: 10.0.2 resolution: "@shikijs/vscode-textmate@npm:10.0.2" checksum: 10/d924cba8a01cd9ca12f56ba097d628fdb81455abb85884c8d8a5ae85b628a37dd5907e7691019b97107bd6608c866adf91ba04a1c3bba391281c88e386c044ea @@ -808,7 +808,7 @@ __metadata: resolution: "@tsed/docs-new@workspace:." dependencies: "@clack/prompts": "npm:^1.0.0-alpha.10" - "@tsed/vitepress-theme": "npm:1.5.7" + "@tsed/vitepress-theme": "npm:^1.7.0" "@vueuse/core": "npm:10.11.0" autoprefixer: "npm:^10.4.19" axios: "npm:1.12.0" @@ -821,18 +821,18 @@ __metadata: remark-stringify: "npm:^9.0.1" tailwindcss: "npm:3.4.4" unified: "npm:^9.2.2" - vitepress: "npm:1.5.0" + vitepress: "npm:1.6.4" languageName: unknown linkType: soft -"@tsed/vitepress-theme@npm:1.5.7": - version: 1.5.7 - resolution: "@tsed/vitepress-theme@npm:1.5.7" +"@tsed/vitepress-theme@npm:^1.7.0": + version: 1.7.0 + resolution: "@tsed/vitepress-theme@npm:1.7.0" dependencies: "@vueuse/core": "npm:10.11.0" axios: "npm:1.7.7" - lucide-vue-next: "npm:^0.436.0" - checksum: 10/d75abb09ed8ba18b44a24530379350d564b5c26a858e36dae1d700f9fcc51f3fdb27cdc00091921419f3349d4099570615239fde0787497bdf80aedc768d1f7d + lucide-vue-next: "npm:0.577.0" + checksum: 10/e8bf5e42fb04f32dcf6cac977dc58faa85a19fec4bd3a5de9a1c37b7e5c81829c9a89200d3c892d30cc008a6ac5c0718478941fd59713aea34cf591651b05327 languageName: node linkType: hard @@ -915,6 +915,13 @@ __metadata: languageName: node linkType: hard +"@types/web-bluetooth@npm:^0.0.21": + version: 0.0.21 + resolution: "@types/web-bluetooth@npm:0.0.21" + checksum: 10/f8796dc9f67ee556a2c895ee7d6c4f62b2a8c52963c3d5e81a2938d3313130f9f7330ff82a6a3dceb63217ba615020e1d4cca8842d469ba6d8ac782853d47d0d + languageName: node + linkType: hard + "@ungap/structured-clone@npm:^1.0.0": version: 1.2.0 resolution: "@ungap/structured-clone@npm:1.2.0" @@ -922,7 +929,7 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-vue@npm:^5.1.4": +"@vitejs/plugin-vue@npm:^5.2.1": version: 5.2.4 resolution: "@vitejs/plugin-vue@npm:5.2.4" peerDependencies: @@ -932,57 +939,57 @@ __metadata: languageName: node linkType: hard -"@vue/compiler-core@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/compiler-core@npm:3.5.27" +"@vue/compiler-core@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/compiler-core@npm:3.5.32" dependencies: - "@babel/parser": "npm:^7.28.5" - "@vue/shared": "npm:3.5.27" - entities: "npm:^7.0.0" + "@babel/parser": "npm:^7.29.2" + "@vue/shared": "npm:3.5.32" + entities: "npm:^7.0.1" estree-walker: "npm:^2.0.2" source-map-js: "npm:^1.2.1" - checksum: 10/1bb121293a1193822c664e55b150dec78a21c9519571b15fcd9c2720b2d3f5b6d4a1f462667bdb544387059d43031b6646cd931168fe2bd40d3b9033179edc72 + checksum: 10/93f6a610ffe4d54ebeb07e54c7efefe47669e1f73d6bd07c0c3cb7b5d44d1292d32e57afdaaa745ead69fbd161804f3757e705e976095eff43484883f57c083c languageName: node linkType: hard -"@vue/compiler-dom@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/compiler-dom@npm:3.5.27" +"@vue/compiler-dom@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/compiler-dom@npm:3.5.32" dependencies: - "@vue/compiler-core": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" - checksum: 10/11907f9521f442f12caaac64b2d01e1111d45d89f9c1b03ece275b1b7890421dee5b8a834d9f9be95e489504c9f217697d70617d739c91bed2e1d07317db3e42 + "@vue/compiler-core": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" + checksum: 10/e9a254ecd4e13d8ba16715cdbe8984654556224339feba8bd6bc4a6d4a39bf55a152dbdaf89a1c1c40bc233ec4bca89d7cfaa7b9172b6f249d2c9666ce0865ce languageName: node linkType: hard -"@vue/compiler-sfc@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/compiler-sfc@npm:3.5.27" +"@vue/compiler-sfc@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/compiler-sfc@npm:3.5.32" dependencies: - "@babel/parser": "npm:^7.28.5" - "@vue/compiler-core": "npm:3.5.27" - "@vue/compiler-dom": "npm:3.5.27" - "@vue/compiler-ssr": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" + "@babel/parser": "npm:^7.29.2" + "@vue/compiler-core": "npm:3.5.32" + "@vue/compiler-dom": "npm:3.5.32" + "@vue/compiler-ssr": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" estree-walker: "npm:^2.0.2" magic-string: "npm:^0.30.21" - postcss: "npm:^8.5.6" + postcss: "npm:^8.5.8" source-map-js: "npm:^1.2.1" - checksum: 10/3406aba914498586984acc00cb8a6c4ca7301209aa4dadc18cb8e92c120a571417df5d4595bfe3ab27d96f977dd6cdc2bd247ed5863f70ac083c3a78202270b7 + checksum: 10/92d8c900c4d8abf81991d4cd065a99d534f3795c99f90a69e43fcaaa7886eeb8b7d00e6d4effb5d511908e49be0b4364260670bf009678b7c7031dd8d7e0a1b4 languageName: node linkType: hard -"@vue/compiler-ssr@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/compiler-ssr@npm:3.5.27" +"@vue/compiler-ssr@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/compiler-ssr@npm:3.5.32" dependencies: - "@vue/compiler-dom": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" - checksum: 10/99d0bb40601e4e77797ed289ab9b839628fd0841ccc5c61eac938153f318226488774ead2feee265ea1d9ada0e69c6248f9f27809c76c8f190ae559328046e60 + "@vue/compiler-dom": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" + checksum: 10/6e0e8079607fd4c9e3c249f4e75e411ababbc5bfddd1b3cf0ccb056254f0d8ac36e14f0a59a793eaa30835049e867f6a168ebdd0e19776ab50247796b711088a languageName: node linkType: hard -"@vue/devtools-api@npm:^7.5.4": +"@vue/devtools-api@npm:^7.7.0": version: 7.7.9 resolution: "@vue/devtools-api@npm:7.7.9" dependencies: @@ -1015,53 +1022,53 @@ __metadata: languageName: node linkType: hard -"@vue/reactivity@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/reactivity@npm:3.5.27" +"@vue/reactivity@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/reactivity@npm:3.5.32" dependencies: - "@vue/shared": "npm:3.5.27" - checksum: 10/d5894c2825e60e96b53be9a486d1ed8314a3101dacdcf5542b1153ea416ceb914be57194894479bb4c1c63ea0064723b93b02133666e6aa8879fdc5dde0e9c48 + "@vue/shared": "npm:3.5.32" + checksum: 10/115e5d45936e374f7ca5ee121c799295801791e4d8c82b107ec94507cfc011110b8d9cc346be9aa4b0204b9ce291b873e43f32206b9b9c6d4b6c56e03cfee0ad languageName: node linkType: hard -"@vue/runtime-core@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/runtime-core@npm:3.5.27" +"@vue/runtime-core@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/runtime-core@npm:3.5.32" dependencies: - "@vue/reactivity": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" - checksum: 10/107b057006c5b54ed5d58845f6135fbf498a9c8bea20542af3e4d46781fc9d4a90437b97a5979b726a6d320699ce41399b692054c374646feb48da881c30bf20 + "@vue/reactivity": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" + checksum: 10/ff7cfef943a55e6195335780e41cb4931f14255f12c58bf085927e23b6d9593dd489945cc29ffbbeab3401e8a1382b830c1b5368f50f769c0ff952c5bb33d12a languageName: node linkType: hard -"@vue/runtime-dom@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/runtime-dom@npm:3.5.27" +"@vue/runtime-dom@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/runtime-dom@npm:3.5.32" dependencies: - "@vue/reactivity": "npm:3.5.27" - "@vue/runtime-core": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" + "@vue/reactivity": "npm:3.5.32" + "@vue/runtime-core": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" csstype: "npm:^3.2.3" - checksum: 10/79702e0e9e0035829be700c5c41cc4e810e9cb8a1e830c450446f93b5d7e3c2945ca3e29f5c64c093abc181597b0663d5015a8dabfd85b78306c286beac775a9 + checksum: 10/f44bfc59333ddcdf8c4bfcfa625fe705fac7506ad0a21c667d96c300b132f6dbb2c236501183d4aac1b46ac0c90843dded45dc0c9611ba60f309224696c83146 languageName: node linkType: hard -"@vue/server-renderer@npm:3.5.27": - version: 3.5.27 - resolution: "@vue/server-renderer@npm:3.5.27" +"@vue/server-renderer@npm:3.5.32": + version: 3.5.32 + resolution: "@vue/server-renderer@npm:3.5.32" dependencies: - "@vue/compiler-ssr": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" + "@vue/compiler-ssr": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" peerDependencies: - vue: 3.5.27 - checksum: 10/df4ad9ffd2cf8b43192350ddd55ee50cd5f624009807ce63882e4dd886e9a62ce9fba92284dbb94449f185464f7869dd7ea82df5cd1ab10cbb4e9d0f7cf53736 + vue: 3.5.32 + checksum: 10/b86dd62fd046a395376fb9233555b12bbc574c121a2cc58b460d4ada00433eba5dc9dfa0232b621826636894ba2ffb9924b508c211f479873ee8d236e4d15626 languageName: node linkType: hard -"@vue/shared@npm:3.5.27, @vue/shared@npm:^3.5.12": - version: 3.5.27 - resolution: "@vue/shared@npm:3.5.27" - checksum: 10/e5aa70da479cfaff39c9f139bd0ca366aa9f764aa8399acb4859c2ff904a86619fe6184accb470e2bd8f7e826115db8083a94c7ebca814a69bab0b5cccea3552 +"@vue/shared@npm:3.5.32, @vue/shared@npm:^3.5.13": + version: 3.5.32 + resolution: "@vue/shared@npm:3.5.32" + checksum: 10/1dd5d16acc08856640bb76c815a6f6b507e42470f4898ba90cd275152a8103094dd7f0e4c27611562b694f2a7f0506b180a6b65a348ebca7da9455e783d562b1 languageName: node linkType: hard @@ -1077,25 +1084,25 @@ __metadata: languageName: node linkType: hard -"@vueuse/core@npm:11.3.0, @vueuse/core@npm:^11.1.0": - version: 11.3.0 - resolution: "@vueuse/core@npm:11.3.0" +"@vueuse/core@npm:12.8.2, @vueuse/core@npm:^12.4.0": + version: 12.8.2 + resolution: "@vueuse/core@npm:12.8.2" dependencies: - "@types/web-bluetooth": "npm:^0.0.20" - "@vueuse/metadata": "npm:11.3.0" - "@vueuse/shared": "npm:11.3.0" - vue-demi: "npm:>=0.14.10" - checksum: 10/d68ed84004dd229a8d5136af0863534697f9cfa80d56e5732b91245e493462db172e701bebb7d9d1c509f97b22bc4169ac358a05c57d4cffa2e56c31f968afee + "@types/web-bluetooth": "npm:^0.0.21" + "@vueuse/metadata": "npm:12.8.2" + "@vueuse/shared": "npm:12.8.2" + vue: "npm:^3.5.13" + checksum: 10/66af78b3164294dc08b83d9a254602cc03a84c2dd99691001719426fd06badd4b565dabd77e4cb2654214b13b49f5dc08bd71f823f928d8bb7d353f148a6fd40 languageName: node linkType: hard -"@vueuse/integrations@npm:^11.1.0": - version: 11.3.0 - resolution: "@vueuse/integrations@npm:11.3.0" +"@vueuse/integrations@npm:^12.4.0": + version: 12.8.2 + resolution: "@vueuse/integrations@npm:12.8.2" dependencies: - "@vueuse/core": "npm:11.3.0" - "@vueuse/shared": "npm:11.3.0" - vue-demi: "npm:>=0.14.10" + "@vueuse/core": "npm:12.8.2" + "@vueuse/shared": "npm:12.8.2" + vue: "npm:^3.5.13" peerDependencies: async-validator: ^4 axios: ^1 @@ -1134,7 +1141,7 @@ __metadata: optional: true universal-cookie: optional: true - checksum: 10/4cab5328216d9912c48ccad95b1cc32efd4a32e11590f2e3aca04d5aa0b7a4be6bdf68a2a0a1931a16a58fcc09bf99efd03cca944aa59d8269f0d7f7e384e555 + checksum: 10/2a4a55e7b994abbb752540ad9525b78b4239d88cb6af07c756f597a467264bbbf3a9565ab907b9fec3b220655a0700e13addaac5d9f3a362905894066e4ac307 languageName: node linkType: hard @@ -1145,10 +1152,10 @@ __metadata: languageName: node linkType: hard -"@vueuse/metadata@npm:11.3.0": - version: 11.3.0 - resolution: "@vueuse/metadata@npm:11.3.0" - checksum: 10/d8b6976896d2bc9924fcbcdaa2f3ffd6f60ff3a13355c92136ed6ad83ee6188d308064f0a8e56d07060b8829b29e41958ec3df9248231859e487a0af0f5e6b2f +"@vueuse/metadata@npm:12.8.2": + version: 12.8.2 + resolution: "@vueuse/metadata@npm:12.8.2" + checksum: 10/ad7299346dbbf2f6256c631f70801cc86a2b58b53a83cc978f48f6a452a92b52e47966a631f5c35b667b3307a4a817eb6a8421f76b0b5ae4e9a2e12dc2c2b3ca languageName: node linkType: hard @@ -1161,12 +1168,12 @@ __metadata: languageName: node linkType: hard -"@vueuse/shared@npm:11.3.0": - version: 11.3.0 - resolution: "@vueuse/shared@npm:11.3.0" +"@vueuse/shared@npm:12.8.2": + version: 12.8.2 + resolution: "@vueuse/shared@npm:12.8.2" dependencies: - vue-demi: "npm:>=0.14.10" - checksum: 10/b4463ab36bad4db582f5145ea1c24da22784c5c2a0b2b76d23090daa1a91551c5542b427a04d8c7dbd9cd2c2ebe2db9585021a813688748bfdad89f73a80a962 + vue: "npm:^3.5.13" + checksum: 10/2cbb24706e43e0dd02074997d6833973a333ed4a1cc1df5fc0b6f7dcba14450aafb3bba7fbf4caf9294be4c1dfde54dbc68961e43a8f40b127e7b533f4698830 languageName: node linkType: hard @@ -1689,7 +1696,7 @@ __metadata: languageName: node linkType: hard -"entities@npm:^7.0.0": +"entities@npm:^7.0.1": version: 7.0.1 resolution: "entities@npm:7.0.1" checksum: 10/3c0c58d869c45148463e96d21dee2d1b801bd3fe4cf47aa470cd26dfe81d59e9e0a9be92ae083fa02fa441283c883a471486e94538dcfb8544428aa80a55271b @@ -1897,7 +1904,7 @@ __metadata: languageName: node linkType: hard -"focus-trap@npm:^7.6.0": +"focus-trap@npm:^7.6.4": version: 7.8.0 resolution: "focus-trap@npm:7.8.0" dependencies: @@ -2443,6 +2450,15 @@ __metadata: languageName: node linkType: hard +"lucide-vue-next@npm:0.577.0": + version: 0.577.0 + resolution: "lucide-vue-next@npm:0.577.0" + peerDependencies: + vue: ">=3.0.1" + checksum: 10/b95fc849593702a01af76dafe93457f7a81bfa78a54f8d1e32acad84cffd585659bf409af4f5aa5df25891a863accc383406e901c7044fffd3759bb1d44cf7d0 + languageName: node + linkType: hard + "lucide-vue-next@npm:^0.436.0": version: 0.436.0 resolution: "lucide-vue-next@npm:0.436.0" @@ -2714,7 +2730,7 @@ __metadata: languageName: node linkType: hard -"minisearch@npm:^7.1.0": +"minisearch@npm:^7.1.1": version: 7.2.0 resolution: "minisearch@npm:7.2.0" checksum: 10/784eef4476442d2c2da2d61ffb3893850fc6c99fc475daa6dceb2c9a224fd6ff030bed7112e01ca8c801f2aeb1692addb1bd0ffd2602666b931110f468fb435d @@ -2856,14 +2872,14 @@ __metadata: languageName: node linkType: hard -"oniguruma-to-es@npm:^2.2.0": - version: 2.3.0 - resolution: "oniguruma-to-es@npm:2.3.0" +"oniguruma-to-es@npm:^3.1.0": + version: 3.1.1 + resolution: "oniguruma-to-es@npm:3.1.1" dependencies: emoji-regex-xs: "npm:^1.0.0" - regex: "npm:^5.1.1" - regex-recursion: "npm:^5.1.1" - checksum: 10/7ac89fe04791650c21a146e58c985de394597e0ab3eb7d7c46699d09f87d6aca63d9f2470f1473c5adfa16961c360df6858e6a24b2429ebd7c73620ca68aec98 + regex: "npm:^6.0.1" + regex-recursion: "npm:^6.0.2" + checksum: 10/e832f72a79847230f80bb9c4cf4fe7717a5ae1394668c8d91e0d0ccba45a1ec4a9a88a39fcd0714adfc63fa8a40cbb404cc796ecf2a7824a6e1ccac3a56b581b languageName: node linkType: hard @@ -3044,14 +3060,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.6": - version: 8.5.6 - resolution: "postcss@npm:8.5.6" +"postcss@npm:^8.5.8": + version: 8.5.10 + resolution: "postcss@npm:8.5.10" dependencies: nanoid: "npm:^3.3.11" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/9e4fbe97574091e9736d0e82a591e29aa100a0bf60276a926308f8c57249698935f35c5d2f4e80de778d0cbb8dcffab4f383d85fd50c5649aca421c3df729b86 + checksum: 10/7eac6169e535b63c8412e94d4f6047fc23efa3e9dde804b541940043c831b25f1cd867d83cd2c4371ad2450c8abcb42c208aa25668c1f0f3650d7f72faf711a8 languageName: node linkType: hard @@ -3118,13 +3134,12 @@ __metadata: languageName: node linkType: hard -"regex-recursion@npm:^5.1.1": - version: 5.1.1 - resolution: "regex-recursion@npm:5.1.1" +"regex-recursion@npm:^6.0.2": + version: 6.0.2 + resolution: "regex-recursion@npm:6.0.2" dependencies: - regex: "npm:^5.1.1" regex-utilities: "npm:^2.3.0" - checksum: 10/9ec7e677743e00c14c3d5c63de1d15e5126a69c58da43e60b2c49abf940981f0269442c919e03f66d6837d0ac55ccf7981581e9d1be2a332a968c016edee226e + checksum: 10/ce25d54bdf79e38ae663c26a7f265754047b918e8b771b4ed3c871e9a926b85b195dcd0dd7a6444c82d2c9db9b2cbcaf51a353a807b469a3ad7a2172f27f21d4 languageName: node linkType: hard @@ -3135,12 +3150,12 @@ __metadata: languageName: node linkType: hard -"regex@npm:^5.1.1": - version: 5.1.1 - resolution: "regex@npm:5.1.1" +"regex@npm:^6.0.1": + version: 6.1.0 + resolution: "regex@npm:6.1.0" dependencies: regex-utilities: "npm:^2.3.0" - checksum: 10/956d0f34afa8086551dc9a0e2c575cb6d7ed5122d6d440a72cfbcd1f9adb5a3dcce4dcb61ec69eaecfcbc508cfd25075ac60d011bab5f28f1b2a36220e09a245 + checksum: 10/553bac92b7ddcea99187aea1bd5cd50f31a923b45ff0bb2ae3876387df01957eb074931613c8a1f6471bb8fea1e0ba1e52f12b8257a5602900e52dd1abb5e436 languageName: node linkType: hard @@ -3320,19 +3335,19 @@ __metadata: languageName: node linkType: hard -"shiki@npm:^1.22.2": - version: 1.29.2 - resolution: "shiki@npm:1.29.2" +"shiki@npm:^2.1.0": + version: 2.5.0 + resolution: "shiki@npm:2.5.0" dependencies: - "@shikijs/core": "npm:1.29.2" - "@shikijs/engine-javascript": "npm:1.29.2" - "@shikijs/engine-oniguruma": "npm:1.29.2" - "@shikijs/langs": "npm:1.29.2" - "@shikijs/themes": "npm:1.29.2" - "@shikijs/types": "npm:1.29.2" - "@shikijs/vscode-textmate": "npm:^10.0.1" + "@shikijs/core": "npm:2.5.0" + "@shikijs/engine-javascript": "npm:2.5.0" + "@shikijs/engine-oniguruma": "npm:2.5.0" + "@shikijs/langs": "npm:2.5.0" + "@shikijs/themes": "npm:2.5.0" + "@shikijs/types": "npm:2.5.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" "@types/hast": "npm:^3.0.4" - checksum: 10/93de1ebc768ff497ba36720f3b385bff65a853248fdfc0afcb2aea81a43560b1bdc7db9e8417df11a87e106b0de0943989c6301daf62a43d09bd9ac7bc776bf3 + checksum: 10/2397c19958f6b1aeb17f65aa014a3c2e05c01c69c152b85c1eeeb9a3b66d0df35e9702a935077207a13a1be39bdcc4e55076e59fabfb155cd513f47007500dcc languageName: node linkType: hard @@ -3774,7 +3789,7 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.4.10": +"vite@npm:^5.4.14": version: 5.4.21 resolution: "vite@npm:5.4.21" dependencies: @@ -3817,28 +3832,28 @@ __metadata: languageName: node linkType: hard -"vitepress@npm:1.5.0": - version: 1.5.0 - resolution: "vitepress@npm:1.5.0" - dependencies: - "@docsearch/css": "npm:^3.6.2" - "@docsearch/js": "npm:^3.6.2" - "@iconify-json/simple-icons": "npm:^1.2.10" - "@shikijs/core": "npm:^1.22.2" - "@shikijs/transformers": "npm:^1.22.2" - "@shikijs/types": "npm:^1.22.2" +"vitepress@npm:1.6.4": + version: 1.6.4 + resolution: "vitepress@npm:1.6.4" + dependencies: + "@docsearch/css": "npm:3.8.2" + "@docsearch/js": "npm:3.8.2" + "@iconify-json/simple-icons": "npm:^1.2.21" + "@shikijs/core": "npm:^2.1.0" + "@shikijs/transformers": "npm:^2.1.0" + "@shikijs/types": "npm:^2.1.0" "@types/markdown-it": "npm:^14.1.2" - "@vitejs/plugin-vue": "npm:^5.1.4" - "@vue/devtools-api": "npm:^7.5.4" - "@vue/shared": "npm:^3.5.12" - "@vueuse/core": "npm:^11.1.0" - "@vueuse/integrations": "npm:^11.1.0" - focus-trap: "npm:^7.6.0" + "@vitejs/plugin-vue": "npm:^5.2.1" + "@vue/devtools-api": "npm:^7.7.0" + "@vue/shared": "npm:^3.5.13" + "@vueuse/core": "npm:^12.4.0" + "@vueuse/integrations": "npm:^12.4.0" + focus-trap: "npm:^7.6.4" mark.js: "npm:8.11.1" - minisearch: "npm:^7.1.0" - shiki: "npm:^1.22.2" - vite: "npm:^5.4.10" - vue: "npm:^3.5.12" + minisearch: "npm:^7.1.1" + shiki: "npm:^2.1.0" + vite: "npm:^5.4.14" + vue: "npm:^3.5.13" peerDependencies: markdown-it-mathjax3: ^4 postcss: ^8 @@ -3849,11 +3864,11 @@ __metadata: optional: true bin: vitepress: bin/vitepress.js - checksum: 10/51f564333ca94bfff59fb00bd8fab4623b51d2fd058b58952b3b1cdb353cd77e445f928006ac5d98a2446994345c5d4ff9689bc4ef023c2d14af144e52d54242 + checksum: 10/e1ac4a01e40bbaf9a66b1b96a05e2cfdca2a33580428c23d65fe74a607e2ebcaf1d367511f70d3fae821fde933fcf9a4b94fea1a02d422a865cc9e5fe0702133 languageName: node linkType: hard -"vue-demi@npm:>=0.14.10, vue-demi@npm:>=0.14.8": +"vue-demi@npm:>=0.14.8": version: 0.14.10 resolution: "vue-demi@npm:0.14.10" peerDependencies: @@ -3869,21 +3884,21 @@ __metadata: languageName: node linkType: hard -"vue@npm:^3.5.12": - version: 3.5.27 - resolution: "vue@npm:3.5.27" +"vue@npm:^3.5.13": + version: 3.5.32 + resolution: "vue@npm:3.5.32" dependencies: - "@vue/compiler-dom": "npm:3.5.27" - "@vue/compiler-sfc": "npm:3.5.27" - "@vue/runtime-dom": "npm:3.5.27" - "@vue/server-renderer": "npm:3.5.27" - "@vue/shared": "npm:3.5.27" + "@vue/compiler-dom": "npm:3.5.32" + "@vue/compiler-sfc": "npm:3.5.32" + "@vue/runtime-dom": "npm:3.5.32" + "@vue/server-renderer": "npm:3.5.32" + "@vue/shared": "npm:3.5.32" peerDependencies: typescript: "*" peerDependenciesMeta: typescript: optional: true - checksum: 10/4ee45d08b6ada6cbb8811045aa26c1c14847723da6139a547d6d9c4ace21ac699675ba65a2e6aa668819545e414621d8847ec0971ef579168ad7acdb84326034 + checksum: 10/00d7427efa08b7e30e03921b477ee26e646b7512d573cd069e46debc51727303244320a2bd642b7e1ef68502de6d95d47bb8391b9b2eac6b12b3f0b23ce25b82 languageName: node linkType: hard From e6c4f31ee139213fd1dba24d98b4f772e0d50d2f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Apr 2026 09:15:35 +0000 Subject: [PATCH 17/22] Github CI build: __run_2 v7.5.0-rc.7 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2a48c19af..5e08fa754 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.6", + "version": "7.5.0-rc.7", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 297c3eba380394408079a107a889ed8fd521e73d Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Mon, 20 Apr 2026 11:51:49 +0200 Subject: [PATCH 18/22] docs: add siteUrl to theme configuration and update @tsed/vitepress-theme to 1.7.2 --- docs/.vitepress/config.mts | 1 + docs/package.json | 2 +- docs/yarn.lock | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index b0584ff9f..6bfd23f14 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -113,6 +113,7 @@ export default defineConfig({ themeConfig: { logo: "https://tsed.dev/tsed.svg", siteTitle: "CLI", + siteUrl: "https://cli.tsed.dev", apiUrl: "/api.json", team, apiRedirectUrl: "", diff --git a/docs/package.json b/docs/package.json index ff55eb418..f5a0e68a7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@clack/prompts": "^1.0.0-alpha.10", - "@tsed/vitepress-theme": "^1.7.0", + "@tsed/vitepress-theme": "1.7.2", "@vueuse/core": "10.11.0", "axios": "1.12.0", "fs-extra": "^11.2.0", diff --git a/docs/yarn.lock b/docs/yarn.lock index 1834fb34c..2275bcea3 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -808,7 +808,7 @@ __metadata: resolution: "@tsed/docs-new@workspace:." dependencies: "@clack/prompts": "npm:^1.0.0-alpha.10" - "@tsed/vitepress-theme": "npm:^1.7.0" + "@tsed/vitepress-theme": "npm:1.7.2" "@vueuse/core": "npm:10.11.0" autoprefixer: "npm:^10.4.19" axios: "npm:1.12.0" @@ -825,14 +825,14 @@ __metadata: languageName: unknown linkType: soft -"@tsed/vitepress-theme@npm:^1.7.0": - version: 1.7.0 - resolution: "@tsed/vitepress-theme@npm:1.7.0" +"@tsed/vitepress-theme@npm:1.7.2": + version: 1.7.2 + resolution: "@tsed/vitepress-theme@npm:1.7.2" dependencies: "@vueuse/core": "npm:10.11.0" axios: "npm:1.7.7" lucide-vue-next: "npm:0.577.0" - checksum: 10/e8bf5e42fb04f32dcf6cac977dc58faa85a19fec4bd3a5de9a1c37b7e5c81829c9a89200d3c892d30cc008a6ac5c0718478941fd59713aea34cf591651b05327 + checksum: 10/65bfb8b508e065767b436f3883ebd97ceb4b68b737cb9628e26f4da2189fc7807a5be260daab67947f1c936393fdaa1ee700ae3054ae4bbc373159cf769b3ecd languageName: node linkType: hard From d5b448d1beb375dc5f06efd43c6b0eb7665d2f85 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Mon, 20 Apr 2026 17:29:15 +0200 Subject: [PATCH 19/22] fix(cli): rename resolveViteBin to resolveViteBinFromPackageJsonPath and update related usages --- packages/cli/src/bin/tsed-build.spec.ts | 9 ++++----- packages/cli/src/bin/tsed-build.ts | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/bin/tsed-build.spec.ts b/packages/cli/src/bin/tsed-build.spec.ts index f67af6d81..0745d2646 100644 --- a/packages/cli/src/bin/tsed-build.spec.ts +++ b/packages/cli/src/bin/tsed-build.spec.ts @@ -1,11 +1,10 @@ import {mkdtemp, rm, writeFile} from "node:fs/promises"; import {tmpdir} from "node:os"; import path from "node:path"; -import {pathToFileURL} from "node:url"; import {describe, expect, it} from "vitest"; -import {resolveViteBin} from "./tsed-build.js"; +import {resolveViteBinFromPackageJsonPath} from "./tsed-build.js"; async function withTempDir(run: (cwd: string) => Promise) { const cwd = await mkdtemp(path.join(tmpdir(), "tsed-build-")); @@ -23,7 +22,7 @@ describe("tsed-build", () => { const packageJsonPath = path.join(cwd, "package.json"); await writeFile(packageJsonPath, JSON.stringify({bin: {vite: "bin/vite.js"}})); - const viteBin = await resolveViteBin(async () => pathToFileURL(packageJsonPath).href); + const viteBin = await resolveViteBinFromPackageJsonPath(packageJsonPath); expect(viteBin).toEqual(path.join(cwd, "bin/vite.js")); }); @@ -34,7 +33,7 @@ describe("tsed-build", () => { const packageJsonPath = path.join(cwd, "package.json"); await writeFile(packageJsonPath, JSON.stringify({bin: "bin/vite.js"})); - const viteBin = await resolveViteBin(async () => pathToFileURL(packageJsonPath).href); + const viteBin = await resolveViteBinFromPackageJsonPath(packageJsonPath); expect(viteBin).toEqual(path.join(cwd, "bin/vite.js")); }); @@ -45,7 +44,7 @@ describe("tsed-build", () => { const packageJsonPath = path.join(cwd, "package.json"); await writeFile(packageJsonPath, JSON.stringify({name: "vite"})); - await expect(resolveViteBin(async () => pathToFileURL(packageJsonPath).href)).rejects.toThrowError( + await expect(resolveViteBinFromPackageJsonPath(packageJsonPath)).rejects.toThrowError( "Unable to resolve Vite CLI binary from vite/package.json" ); }); diff --git a/packages/cli/src/bin/tsed-build.ts b/packages/cli/src/bin/tsed-build.ts index 0b63e7964..df3f55f72 100644 --- a/packages/cli/src/bin/tsed-build.ts +++ b/packages/cli/src/bin/tsed-build.ts @@ -23,10 +23,15 @@ function runNode(cmd: string, args: string[]) { }); } -type ResolveFn = (specifier: string) => string | Promise; +function toPath(value: string) { + if (value.startsWith("file://")) { + return fileURLToPath(value); + } + + return value; +} -export async function resolveViteBin(resolve: ResolveFn = import.meta.resolve) { - const packageJsonPath = fileURLToPath(await resolve("vite/package.json")); +export async function resolveViteBinFromPackageJsonPath(packageJsonPath: string) { const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8")) as { bin?: string | Record; }; @@ -39,6 +44,12 @@ export async function resolveViteBin(resolve: ResolveFn = import.meta.resolve) { return path.resolve(path.dirname(packageJsonPath), binRelativePath); } +export async function resolveViteBin() { + const packageJsonPath = toPath(await import.meta.resolve("vite/package.json")); + + return resolveViteBinFromPackageJsonPath(packageJsonPath); +} + export async function build(rawArgs: string[] = process.argv.slice(2)) { const viteBin = await resolveViteBin(); await runNode(process.execPath, [viteBin, "build", ...rawArgs]); From cc1a1813f65eeec7e98d44edc8358f0f60816342 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 20 Apr 2026 15:33:36 +0000 Subject: [PATCH 20/22] Github CI build: __run_2 v7.5.0-rc.8 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5e08fa754..1b7045b81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.7", + "version": "7.5.0-rc.8", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module", From 16ab7634b43f07af793d53bae535b56e442f0cb0 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Mon, 18 May 2026 09:43:40 +0200 Subject: [PATCH 21/22] fix(cli-tasks): guard undefined tasks in isEnabled --- packages/cli-tasks/src/tasks.spec.ts | 20 ++++++++++++++++++++ packages/cli-tasks/src/tasks.ts | 6 +++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/cli-tasks/src/tasks.spec.ts b/packages/cli-tasks/src/tasks.spec.ts index 86c3fab94..2e18c7011 100644 --- a/packages/cli-tasks/src/tasks.spec.ts +++ b/packages/cli-tasks/src/tasks.spec.ts @@ -238,6 +238,26 @@ describe("tasks()", () => { expect(getLevelLabel(diLogger.level)).toBe("WARN"); diLogger.level = originalLevel; }); + + it("ignores undefined tasks from a list", async () => { + const activeSpy = vi.fn(); + const ctx = DITest.createDIContext(); + + await runInContext(ctx, () => + tasks( + [ + undefined as unknown as Task, + { + title: "Active task", + task: activeSpy + } + ], + {} + ) + ); + + expect(activeSpy).toHaveBeenCalledTimes(1); + }); }); describe("concat()", () => { diff --git a/packages/cli-tasks/src/tasks.ts b/packages/cli-tasks/src/tasks.ts index 506232dd9..25a58be2a 100644 --- a/packages/cli-tasks/src/tasks.ts +++ b/packages/cli-tasks/src/tasks.ts @@ -113,7 +113,11 @@ export async function concat(...args: (Task[] | void | undefined)[]) { return tasks; } -function isEnabled(item: Task) { +function isEnabled(item: Task | undefined | null) { + if (!item) { + return false; + } + return isBoolean(item.enabled) ? item.enabled : true; } From 2d837d5fdec96547cfc5f95d7d8066b7aba9fffe Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 May 2026 07:47:44 +0000 Subject: [PATCH 22/22] Github CI build: __run_2 v7.5.0-rc.9 [ci skip] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b7045b81..eb5cdb068 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsed/cli-root", - "version": "7.5.0-rc.8", + "version": "7.5.0-rc.9", "description": "CLI to bootstrap your Ts.ED project", "private": true, "type": "module",