@procedures/vite 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +53 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/index.d.ts +8 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +8 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/module.d.ts +19 -0
  10. package/dist/module.d.ts.map +1 -0
  11. package/dist/module.js +85 -0
  12. package/dist/module.js.map +1 -0
  13. package/dist/procedures/vite/build.d.ts +8 -0
  14. package/dist/procedures/vite/build.d.ts.map +1 -0
  15. package/dist/procedures/vite/build.js +39 -0
  16. package/dist/procedures/vite/build.js.map +1 -0
  17. package/dist/procedures/vite/dev.d.ts +6 -0
  18. package/dist/procedures/vite/dev.d.ts.map +1 -0
  19. package/dist/procedures/vite/dev.js +18 -0
  20. package/dist/procedures/vite/dev.js.map +1 -0
  21. package/dist/procedures/vite/index.d.ts +5 -0
  22. package/dist/procedures/vite/index.d.ts.map +1 -0
  23. package/dist/procedures/vite/index.js +5 -0
  24. package/dist/procedures/vite/index.js.map +1 -0
  25. package/dist/procedures/vite/preview.d.ts +6 -0
  26. package/dist/procedures/vite/preview.d.ts.map +1 -0
  27. package/dist/procedures/vite/preview.js +13 -0
  28. package/dist/procedures/vite/preview.js.map +1 -0
  29. package/dist/procedures/vite/stop.d.ts +6 -0
  30. package/dist/procedures/vite/stop.d.ts.map +1 -0
  31. package/dist/procedures/vite/stop.js +10 -0
  32. package/dist/procedures/vite/stop.js.map +1 -0
  33. package/dist/register.d.ts +7 -0
  34. package/dist/register.d.ts.map +1 -0
  35. package/dist/register.js +9 -0
  36. package/dist/register.js.map +1 -0
  37. package/dist/server-manager.d.ts +28 -0
  38. package/dist/server-manager.d.ts.map +1 -0
  39. package/dist/server-manager.js +51 -0
  40. package/dist/server-manager.js.map +1 -0
  41. package/dist/types.d.ts +57 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +61 -0
  44. package/dist/types.js.map +1 -0
  45. package/dist/vite-cli.d.ts +11 -0
  46. package/dist/vite-cli.d.ts.map +1 -0
  47. package/dist/vite-cli.js +34 -0
  48. package/dist/vite-cli.js.map +1 -0
  49. package/package.json +77 -3
  50. package/src/index.ts +9 -0
  51. package/src/module.ts +109 -0
  52. package/src/procedures/vite/build.ts +44 -0
  53. package/src/procedures/vite/dev.ts +19 -0
  54. package/src/procedures/vite/index.ts +4 -0
  55. package/src/procedures/vite/preview.ts +16 -0
  56. package/src/procedures/vite/stop.ts +12 -0
  57. package/src/register.ts +11 -0
  58. package/src/server-manager.ts +61 -0
  59. package/src/types.ts +127 -0
  60. package/src/vite-cli.ts +35 -0
package/package.json CHANGED
@@ -1,6 +1,80 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package",
2
3
  "name": "@procedures/vite",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
4
+ "version": "0.2.0",
5
+ "description": "Vite as procedures: dev server, build, preview and stop, with no shell and managed processes.",
6
+ "keywords": [
7
+ "vite",
8
+ "build",
9
+ "dev-server",
10
+ "procedures"
11
+ ],
12
+ "homepage": "https://mark1russell7.github.io/client/",
13
+ "bugs": {
14
+ "url": "https://github.com/mark1russell7/client/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/mark1russell7/client.git",
19
+ "directory": "packages/client-vite"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Mark Russell (https://github.com/mark1russell7)",
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ },
31
+ "./module": {
32
+ "types": "./dist/module.d.ts",
33
+ "import": "./dist/module.js"
34
+ },
35
+ "./register": {
36
+ "types": "./dist/register.d.ts",
37
+ "import": "./dist/register.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "src",
43
+ "!src/**/*.test.ts",
44
+ "!src/**/*.test.tsx",
45
+ "!src/**/__tests__",
46
+ "CHANGELOG.md"
47
+ ],
48
+ "sideEffects": [
49
+ "./dist/register.js"
50
+ ],
51
+ "engines": {
52
+ "node": ">=22"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public",
56
+ "provenance": true
57
+ },
58
+ "dependencies": {
59
+ "@procedures/client": "0.2.0",
60
+ "@procedures/shell": "0.2.0",
61
+ "zod": "^4.6.5"
62
+ },
63
+ "devDependencies": {
64
+ "typescript": "^7.0.2",
65
+ "@types/node": "^22.0.0",
66
+ "@mark1russell7/cue": "^1.0.0",
67
+ "vitest": "^5.0.3",
68
+ "vite": "^6.4.4"
69
+ },
70
+ "client": {
71
+ "procedures": "./dist/register.js"
72
+ },
73
+ "scripts": {
74
+ "build": "tsc -b",
75
+ "typecheck": "tsc --noEmit",
76
+ "clean": "rm -rf dist .tsbuildinfo",
77
+ "test": "vitest run",
78
+ "test:watch": "vitest"
79
+ }
6
80
  }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * client-vite - Vite dev server management procedures
3
+ */
4
+
5
+ export * from "./module.js";
6
+
7
+ export * from "./types.js";
8
+ export * from "./procedures/vite/index.js";
9
+ export { serverManager } from "./server-manager.js";
package/src/module.ts ADDED
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Module (no side effects): the procedures of this package as data, for `createRegistry()`.
3
+ *
4
+ * Procedure Registration for Vite dev server management
5
+ */
6
+
7
+ import { createProcedure, zodAdapter, defineModule, type ProcedureModule, PROCEDURE_REGISTRY, registerModules, type ProcedureRegistry } from "@procedures/client";
8
+ import { viteDev } from "./procedures/vite/dev.js";
9
+ import { viteBuild } from "./procedures/vite/build.js";
10
+ import { vitePreview } from "./procedures/vite/preview.js";
11
+ import { viteStop } from "./procedures/vite/stop.js";
12
+ import {
13
+ ViteDevInputSchema,
14
+ ViteBuildInputSchema,
15
+ VitePreviewInputSchema,
16
+ ViteStopInputSchema,
17
+ type ViteDevInput,
18
+ type ViteDevOutput,
19
+ type ViteBuildInput,
20
+ type ViteBuildOutput,
21
+ type VitePreviewInput,
22
+ type VitePreviewOutput,
23
+ type ViteStopInput,
24
+ type ViteStopOutput,
25
+ ViteDevOutputSchema,
26
+ ViteBuildOutputSchema,
27
+ VitePreviewOutputSchema,
28
+ ViteStopOutputSchema,
29
+ } from "./types.js";
30
+
31
+ const viteDevProcedure = createProcedure()
32
+ .path(["vite", "dev"])
33
+ .input(zodAdapter<ViteDevInput>(ViteDevInputSchema))
34
+ .output(zodAdapter<ViteDevOutput>(ViteDevOutputSchema))
35
+ .meta({
36
+ description: "Start Vite dev server",
37
+ // vite runs the config and the plugins of the project, and the server listens on a port
38
+ effects: { reads: ["fs"], writes: ["network", "process", "server"] },
39
+ args: ["cwd"],
40
+ shorts: { port: "p", host: "h" },
41
+ output: "json",
42
+ })
43
+ .handler(async (input: ViteDevInput): Promise<ViteDevOutput> => viteDev(input))
44
+ .build();
45
+
46
+ const viteBuildProcedure = createProcedure()
47
+ .path(["vite", "build"])
48
+ .input(zodAdapter<ViteBuildInput>(ViteBuildInputSchema))
49
+ .output(zodAdapter<ViteBuildOutput>(ViteBuildOutputSchema))
50
+ .meta({
51
+ description: "Build for production",
52
+ // vite runs the config and the plugins of the project, and writes the output folder
53
+ effects: { reads: ["fs"], writes: ["fs", "process"] },
54
+ args: ["cwd"],
55
+ shorts: { outDir: "o", mode: "m" },
56
+ output: "json",
57
+ })
58
+ .handler(async (input: ViteBuildInput, ctx): Promise<ViteBuildOutput> => viteBuild(input, ctx))
59
+ .build();
60
+
61
+ const vitePreviewProcedure = createProcedure()
62
+ .path(["vite", "preview"])
63
+ .input(zodAdapter<VitePreviewInput>(VitePreviewInputSchema))
64
+ .output(zodAdapter<VitePreviewOutput>(VitePreviewOutputSchema))
65
+ .meta({
66
+ description: "Preview production build",
67
+ effects: { reads: ["fs"], writes: ["network", "process", "server"] },
68
+ args: ["cwd"],
69
+ shorts: { port: "p" },
70
+ output: "json",
71
+ })
72
+ .handler(async (input: VitePreviewInput): Promise<VitePreviewOutput> => vitePreview(input))
73
+ .build();
74
+
75
+ const viteStopProcedure = createProcedure()
76
+ .path(["vite", "stop"])
77
+ .input(zodAdapter<ViteStopInput>(ViteStopInputSchema))
78
+ .output(zodAdapter<ViteStopOutput>(ViteStopOutputSchema))
79
+ .meta({
80
+ description: "Stop a running Vite server",
81
+ effects: { reads: ["server"], writes: ["server"], idempotent: true },
82
+ args: ["serverId"],
83
+ shorts: {},
84
+ output: "json",
85
+ })
86
+ .handler(async (input: ViteStopInput): Promise<ViteStopOutput> => viteStop(input))
87
+ .build();
88
+
89
+ /**
90
+ * The module of this package, for `createRegistry()`: its procedures as data. Importing this
91
+ * file registers nothing. (`register.ts` registers the same procedures in the global registry.)
92
+ */
93
+ export const viteModule: ProcedureModule = defineModule("@procedures/vite", [
94
+ viteDevProcedure,
95
+ viteBuildProcedure,
96
+ vitePreviewProcedure,
97
+ viteStopProcedure,
98
+ ]);
99
+
100
+ export default viteModule;
101
+
102
+ /**
103
+ * This function registers the procedures of @procedures/vite, and of the modules that it requires, in
104
+ * a registry. The default is the global registry. Importing this file registers nothing: the
105
+ * `./register` entry starts this function (ARCHITECTURE-PROPOSALS-2026-10, P9).
106
+ */
107
+ export function registerViteProcedures(registry: ProcedureRegistry = PROCEDURE_REGISTRY): void {
108
+ registerModules(registry, [viteModule]);
109
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * vite.build procedure - Build for production
3
+ */
4
+
5
+ import { resolve } from "node:path";
6
+ import { runCommand } from "@procedures/shell/command";
7
+ import { resolveViteCli, viteArg } from "../../vite-cli.js";
8
+ import type { ViteBuildInput, ViteBuildOutput } from "../../types.js";
9
+
10
+ export async function viteBuild(
11
+ input: ViteBuildInput,
12
+ ctx?: { signal?: AbortSignal | undefined }
13
+ ): Promise<ViteBuildOutput> {
14
+ const { outDir, mode } = input;
15
+ // Without cwd, the build runs in the current folder. (Before, `resolve(undefined, ...)` threw.)
16
+ const cwd = input.cwd ?? process.cwd();
17
+
18
+ // The project's own vite, run with Node and an argument list: no shell (deep dive WRP-8)
19
+ const args = [resolveViteCli(cwd), "build"];
20
+ if (outDir) args.push("--outDir", viteArg("outDir", outDir));
21
+ if (mode) args.push("--mode", viteArg("mode", mode));
22
+
23
+ // The signal kills vite and the processes that it started (roadmap 2.2)
24
+ const result = await runCommand(process.execPath, {
25
+ args,
26
+ cwd,
27
+ env: { NO_COLOR: "1" },
28
+ signal: ctx?.signal,
29
+ keep: "tail",
30
+ maxOutputBytes: 1024 * 1024,
31
+ });
32
+ if (result.aborted) {
33
+ const error = new Error("vite.build was aborted");
34
+ error.name = "AbortError";
35
+ throw error;
36
+ }
37
+ if (!result.success) {
38
+ throw new Error(`Build failed with code ${result.exitCode}: ${result.error ?? result.stderr}`);
39
+ }
40
+ return {
41
+ success: true,
42
+ outDir: resolve(cwd, outDir ?? "dist"),
43
+ };
44
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * vite.dev procedure - Start Vite dev server
3
+ */
4
+
5
+ import { viteArg } from "../../vite-cli.js";
6
+ import type { ViteDevInput, ViteDevOutput } from "../../types.js";
7
+ import { serverManager } from "../../server-manager.js";
8
+
9
+ export async function viteDev(input: ViteDevInput): Promise<ViteDevOutput> {
10
+ const { cwd, port, host, open } = input;
11
+
12
+ // The project's own vite, run with Node and an argument list: no shell (deep dive WRP-8)
13
+ const args: string[] = [];
14
+ if (port) args.push("--port", String(port));
15
+ if (host) args.push("--host", viteArg("host", host));
16
+ if (open) args.push("--open");
17
+
18
+ return serverManager.start(args, cwd);
19
+ }
@@ -0,0 +1,4 @@
1
+ export { viteDev } from "./dev.js";
2
+ export { viteBuild } from "./build.js";
3
+ export { vitePreview } from "./preview.js";
4
+ export { viteStop } from "./stop.js";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * vite.preview procedure - Preview production build
3
+ */
4
+
5
+ import type { VitePreviewInput, VitePreviewOutput } from "../../types.js";
6
+ import { serverManager } from "../../server-manager.js";
7
+
8
+ export async function vitePreview(input: VitePreviewInput): Promise<VitePreviewOutput> {
9
+ const { cwd, port } = input;
10
+
11
+ // The project's own vite, run with Node and an argument list: no shell (deep dive WRP-8)
12
+ const args = ["preview"];
13
+ if (port) args.push("--port", String(port));
14
+
15
+ return serverManager.start(args, cwd);
16
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * vite.stop procedure - Stop a running server
3
+ */
4
+
5
+ import type { ViteStopInput, ViteStopOutput } from "../../types.js";
6
+ import { serverManager } from "../../server-manager.js";
7
+
8
+ export async function viteStop(input: ViteStopInput): Promise<ViteStopOutput> {
9
+ const { serverId } = input;
10
+ const success = await serverManager.stop(serverId);
11
+ return { success };
12
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Importing this file registers the procedures of @procedures/vite, and of the modules that it
3
+ * requires, in the global registry: `import "@procedures/vite/register"`. The package root and the
4
+ * `./module` entry register nothing (ARCHITECTURE-PROPOSALS-2026-10, P9).
5
+ */
6
+
7
+ import { registerViteProcedures } from "./module.js";
8
+
9
+ export * from "./module.js";
10
+
11
+ registerViteProcedures();
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Vite Server Manager - Manages running Vite servers
3
+ *
4
+ * The manager is a view of the process registry of client-shell, for the group "vite"
5
+ * (deep dive WRP-4, WRP-10): `stop` ends the whole process tree (vite and esbuild), the registry
6
+ * reads the output of each server, and the servers end when the host ends.
7
+ */
8
+
9
+ import { processes } from "@procedures/shell/command";
10
+ import { resolveViteCli } from "./vite-cli.js";
11
+
12
+ /** The group of the vite servers in the process registry. */
13
+ export const VITE_GROUP = "vite";
14
+
15
+ /** The line where vite prints the URL of a server that is ready. */
16
+ const READY = /Local:\s+(https?:\/\/\S+)/;
17
+
18
+ export interface StartedServer {
19
+ serverId: string;
20
+ url: string;
21
+ pid: number;
22
+ }
23
+
24
+ class ServerManager {
25
+ /**
26
+ * Start `vite <args>` with the project's own vite and no shell, and wait for its URL.
27
+ * When the server does not get ready, the manager stops it and throws.
28
+ */
29
+ async start(args: string[], cwd: string | undefined, timeout = 30000): Promise<StartedServer> {
30
+ const root = cwd ?? process.cwd();
31
+ const started = processes.start(process.execPath, {
32
+ args: [resolveViteCli(root), ...args],
33
+ cwd: root,
34
+ // No colors: the output stays plain text for the readers of the registry
35
+ env: { NO_COLOR: "1" },
36
+ group: VITE_GROUP,
37
+ label: `vite ${args.join(" ")}`.trim(),
38
+ });
39
+ try {
40
+ const match = await processes.waitFor(started.id, READY, timeout);
41
+ return { serverId: started.id, url: match[1]!, pid: started.pid };
42
+ } catch (error) {
43
+ await processes.stop(started.id);
44
+ throw error;
45
+ }
46
+ }
47
+
48
+ /** True when the server has a record and is running. */
49
+ running(serverId: string): boolean {
50
+ const info = processes.get(serverId);
51
+ return info?.group === VITE_GROUP && info.status === "running";
52
+ }
53
+
54
+ /** Stop a server and the processes that it started, and wait for its end. */
55
+ async stop(serverId: string): Promise<boolean> {
56
+ if (!this.running(serverId)) return false;
57
+ return (await processes.stop(serverId)).stopped;
58
+ }
59
+ }
60
+
61
+ export const serverManager: ServerManager = new ServerManager();
package/src/types.ts ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Type definitions for client-vite procedures
3
+ */
4
+
5
+ import { z } from "zod";
6
+
7
+ // ============================================================================
8
+ // vite.dev - Start Vite dev server
9
+ // ============================================================================
10
+
11
+ export const ViteDevInputSchema: z.ZodObject<{
12
+ cwd: z.ZodOptional<z.ZodString>;
13
+ port: z.ZodOptional<z.ZodNumber>;
14
+ host: z.ZodOptional<z.ZodString>;
15
+ open: z.ZodOptional<z.ZodBoolean>;
16
+ }> = z.object({
17
+ /** Working directory containing vite config (default: the current folder) */
18
+ cwd: z.string().optional().describe("Working directory containing vite config (default: the current folder)"),
19
+ /** Port to run on */
20
+ port: z.number().optional().describe("Port to run on"),
21
+ /** Host to bind to */
22
+ host: z.string().optional().describe("Host to bind to"),
23
+ /** Open browser automatically */
24
+ open: z.boolean().optional().describe("Open browser automatically"),
25
+ });
26
+
27
+ export type ViteDevInput = z.infer<typeof ViteDevInputSchema>;
28
+
29
+ export interface ViteDevOutput {
30
+ /** Server identifier for management */
31
+ serverId: string;
32
+ /** Server URL */
33
+ url: string;
34
+ /** Process ID */
35
+ pid: number;
36
+ }
37
+
38
+ // ============================================================================
39
+ // vite.build - Build for production
40
+ // ============================================================================
41
+
42
+ export const ViteBuildInputSchema: z.ZodObject<{
43
+ cwd: z.ZodOptional<z.ZodString>;
44
+ outDir: z.ZodOptional<z.ZodString>;
45
+ mode: z.ZodOptional<z.ZodString>;
46
+ }> = z.object({
47
+ /** Working directory containing vite config (default: the current folder) */
48
+ cwd: z.string().optional().describe("Working directory containing vite config (default: the current folder)"),
49
+ /** Output directory */
50
+ outDir: z.string().optional().describe("Output directory"),
51
+ /** Build mode */
52
+ mode: z.string().optional().describe("Build mode"),
53
+ });
54
+
55
+ export type ViteBuildInput = z.infer<typeof ViteBuildInputSchema>;
56
+
57
+ export interface ViteBuildOutput {
58
+ /** Whether build succeeded */
59
+ success: boolean;
60
+ /** Output directory path */
61
+ outDir: string;
62
+ }
63
+
64
+ // ============================================================================
65
+ // vite.preview - Preview production build
66
+ // ============================================================================
67
+
68
+ export const VitePreviewInputSchema: z.ZodObject<{
69
+ cwd: z.ZodOptional<z.ZodString>;
70
+ port: z.ZodOptional<z.ZodNumber>;
71
+ }> = z.object({
72
+ /** Working directory containing built output (default: the current folder) */
73
+ cwd: z.string().optional().describe("Working directory containing built output (default: the current folder)"),
74
+ /** Port to run on */
75
+ port: z.number().optional().describe("Port to run on"),
76
+ });
77
+
78
+ export type VitePreviewInput = z.infer<typeof VitePreviewInputSchema>;
79
+
80
+ export interface VitePreviewOutput {
81
+ /** Server identifier */
82
+ serverId: string;
83
+ /** Server URL */
84
+ url: string;
85
+ /** Process ID */
86
+ pid: number;
87
+ }
88
+
89
+ // ============================================================================
90
+ // vite.stop - Stop a running server
91
+ // ============================================================================
92
+
93
+ export const ViteStopInputSchema: z.ZodObject<{
94
+ serverId: z.ZodString;
95
+ }> = z.object({
96
+ /** Server ID to stop */
97
+ serverId: z.string().describe("Server ID to stop"),
98
+ });
99
+
100
+ export type ViteStopInput = z.infer<typeof ViteStopInputSchema>;
101
+
102
+ export interface ViteStopOutput {
103
+ /** Whether stop succeeded */
104
+ success: boolean;
105
+ }
106
+
107
+ // Output schemas (roadmap 2.1). Loose objects: a field that a schema does not name stays in the
108
+ // result (a strict schema would remove it when the output is validated).
109
+
110
+ const serverFields = {
111
+ serverId: z.string().describe("The id of the server: vite.stop takes it"),
112
+ url: z.string().describe("The URL of the server"),
113
+ pid: z.number().describe("The process id of vite"),
114
+ };
115
+
116
+ export const ViteDevOutputSchema: z.ZodType<ViteDevOutput> = z.looseObject(serverFields);
117
+
118
+ export const VitePreviewOutputSchema: z.ZodType<VitePreviewOutput> = z.looseObject(serverFields);
119
+
120
+ export const ViteBuildOutputSchema: z.ZodType<ViteBuildOutput> = z.looseObject({
121
+ success: z.boolean().describe("True when the build succeeded"),
122
+ outDir: z.string().describe("The output folder of the build"),
123
+ });
124
+
125
+ export const ViteStopOutputSchema: z.ZodType<ViteStopOutput> = z.looseObject({
126
+ success: z.boolean().describe("True when the server stopped"),
127
+ });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Locate the vite CLI of a project.
3
+ *
4
+ * The procedures run vite as `node <vite.js> ...args` with no shell. Before, they ran
5
+ * `npx vite` with `shell: true`: `host`, `mode` and `outDir` reached the shell unescaped
6
+ * (deep dive WRP-8), and npx could download vite when the project did not have it.
7
+ */
8
+
9
+ import { readFileSync } from "node:fs";
10
+ import { createRequire } from "node:module";
11
+ import { dirname, join, resolve } from "node:path";
12
+
13
+ export function resolveViteCli(cwd: string): string {
14
+ const require = createRequire(join(resolve(cwd), "package.json"));
15
+ let packageJsonPath: string;
16
+ try {
17
+ packageJsonPath = require.resolve("vite/package.json");
18
+ } catch {
19
+ throw new Error(`vite is not installed for ${cwd}. Add it as a devDependency.`);
20
+ }
21
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { bin?: string | Record<string, string> };
22
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["vite"];
23
+ if (!bin) {
24
+ throw new Error(`The vite package at ${dirname(packageJsonPath)} has no "vite" bin.`);
25
+ }
26
+ return join(dirname(packageJsonPath), bin);
27
+ }
28
+
29
+ /** A value that vite reads as an argument (a mode, a folder, a host): it must not start with "-". */
30
+ export function viteArg(name: string, value: string): string {
31
+ if (value.startsWith("-")) {
32
+ throw new Error(`Invalid ${name} (starts with "-"): ${value}`);
33
+ }
34
+ return value;
35
+ }