@astralarium/repo-dev 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +17 -2
- package/dist/allocation.d.ts +15 -0
- package/dist/allocation.js +28 -0
- package/dist/bin/db-image.d.ts +2 -0
- package/dist/bin/db-image.js +29 -0
- package/dist/bin/run-dev.d.ts +2 -0
- package/dist/bin/run-dev.js +15 -0
- package/dist/bin/siblings-inputs.d.ts +2 -0
- package/dist/bin/siblings-inputs.js +20 -0
- package/dist/config.d.ts +240 -0
- package/dist/config.js +90 -0
- package/dist/environment.d.ts +19 -0
- package/dist/environment.js +45 -0
- package/dist/exec.d.ts +4 -0
- package/dist/exec.js +14 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/launcher/hosts.d.ts +26 -0
- package/dist/launcher/hosts.js +152 -0
- package/dist/launcher/launcher.d.ts +23 -0
- package/dist/launcher/launcher.js +452 -0
- package/dist/launcher/servers.d.ts +39 -0
- package/dist/launcher/servers.js +154 -0
- package/dist/load-config.d.ts +3 -0
- package/dist/load-config.js +6 -0
- package/dist/ports.d.ts +3 -0
- package/dist/ports.js +32 -0
- package/dist/process.d.ts +43 -0
- package/dist/process.js +172 -0
- package/dist/resources.d.ts +23 -0
- package/dist/resources.js +74 -0
- package/dist/sibling-inputs.d.ts +5 -0
- package/dist/sibling-inputs.js +32 -0
- package/dist/source-hash.d.ts +2 -0
- package/dist/source-hash.js +29 -0
- package/dist/testkit/built-worker.d.ts +29 -0
- package/dist/testkit/built-worker.js +48 -0
- package/dist/testkit/env-template.d.ts +8 -0
- package/dist/testkit/env-template.js +14 -0
- package/dist/testkit/index.d.ts +8 -0
- package/dist/testkit/index.js +8 -0
- package/dist/testkit/ports.d.ts +8 -0
- package/dist/testkit/ports.js +20 -0
- package/dist/testkit/temp.d.ts +2 -0
- package/dist/testkit/temp.js +10 -0
- package/dist/testkit/test-cache.d.ts +14 -0
- package/dist/testkit/test-cache.js +174 -0
- package/dist/testkit/worker-build.d.ts +26 -0
- package/dist/testkit/worker-build.js +46 -0
- package/dist/vite.d.ts +96 -0
- package/dist/vite.js +254 -0
- package/dist/wait.d.ts +9 -0
- package/dist/wait.js +38 -0
- package/package.json +71 -3
package/dist/vite.js
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugins and config: the launcher's listener, Cloudflare plugin
|
|
3
|
+
* options, the build guard, the Tailwind dev-source exclusion, the
|
|
4
|
+
* prerender runtime and worker config, and rename recovery.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, globSync, readFileSync, realpathSync } from "node:fs";
|
|
7
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
8
|
+
import { parseLocalOrigins, parseOrigin } from "@astralarium/repo-env";
|
|
9
|
+
import { isDevFile, isServerFile, isTestFile, workspacePackageDirs, workspaceRoot, } from "@astralarium/repo-package-files";
|
|
10
|
+
import { ExpectedError } from "@astralarium/repo-telemetry";
|
|
11
|
+
import { normalizePath, } from "vite";
|
|
12
|
+
/**
|
|
13
|
+
* Listener of a launched app (`listenerEnv`): dev servers serve on
|
|
14
|
+
* `SITE_ORIGIN`'s port, over HTTPS with `SSL_KEY` / `SSL_CERT`; every
|
|
15
|
+
* server binds `DEV_SERVER_HOST` (default `localhost`) on a strict port
|
|
16
|
+
* and allows the `LOCAL_ORIGINS` hostnames. Config comes from process env:
|
|
17
|
+
* Vite reads no dot-env file.
|
|
18
|
+
*/
|
|
19
|
+
export function devListener({ command, isPreview, mode }, env = process.env) {
|
|
20
|
+
// Vitest runs in mode `test`.
|
|
21
|
+
const development = command === "serve" && !isPreview && mode !== "test";
|
|
22
|
+
const origin = development
|
|
23
|
+
? new URL(parseOrigin(env.SITE_ORIGIN))
|
|
24
|
+
: undefined;
|
|
25
|
+
const key = development && env.SSL_KEY;
|
|
26
|
+
const cert = development && env.SSL_CERT;
|
|
27
|
+
return {
|
|
28
|
+
envDir: false,
|
|
29
|
+
server: {
|
|
30
|
+
port: origin
|
|
31
|
+
? Number(origin.port || (origin.protocol === "https:" ? 443 : 80))
|
|
32
|
+
: undefined,
|
|
33
|
+
// Blank from `appProcessEnv` outside a `host` server.
|
|
34
|
+
host: env.DEV_SERVER_HOST === undefined || env.DEV_SERVER_HOST === ""
|
|
35
|
+
? "localhost"
|
|
36
|
+
: env.DEV_SERVER_HOST,
|
|
37
|
+
strictPort: true,
|
|
38
|
+
https: key && cert
|
|
39
|
+
? { key: readFileSync(key, "utf8"), cert: readFileSync(cert, "utf8") }
|
|
40
|
+
: undefined,
|
|
41
|
+
allowedHosts: parseLocalOrigins(env.LOCAL_ORIGINS).hostnames,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Cloudflare Vite plugin options of a launched app: a `testEnv` build
|
|
47
|
+
* (`CLOUDFLARE_ENV`, the Vitest fixtures') keeps no state and opens no
|
|
48
|
+
* inspector; other servers open `DEV_INSPECTOR_PORT` (`listenerEnv`), or
|
|
49
|
+
* none when it is blank or unset.
|
|
50
|
+
*/
|
|
51
|
+
export function cloudflareDevOptions({ testEnv = "test", env = process.env, } = {}) {
|
|
52
|
+
if (env.CLOUDFLARE_ENV === testEnv)
|
|
53
|
+
return { persistState: false, inspectorPort: false };
|
|
54
|
+
return {
|
|
55
|
+
inspectorPort: env.DEV_INSPECTOR_PORT
|
|
56
|
+
? Number(env.DEV_INSPECTOR_PORT)
|
|
57
|
+
: false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Inline limits the check set, across instances: a config may evaluate
|
|
61
|
+
* and resolve more than once. */
|
|
62
|
+
const inlineLimits = new WeakSet();
|
|
63
|
+
/**
|
|
64
|
+
* Fails a build shipping dev files or test support, or server-only
|
|
65
|
+
* modules in a client environment (`isDevFile`, `isTestFile`,
|
|
66
|
+
* `isServerFile` from `@astralarium/repo-package-files`). Dev assets never inline,
|
|
67
|
+
* so they emit and fail; library builds inline every asset, skipping
|
|
68
|
+
* the check.
|
|
69
|
+
*/
|
|
70
|
+
export function buildGuard() {
|
|
71
|
+
let config;
|
|
72
|
+
let configured = false;
|
|
73
|
+
return {
|
|
74
|
+
name: "repo:build-guard",
|
|
75
|
+
apply: "build",
|
|
76
|
+
config(user) {
|
|
77
|
+
const limit = user.build?.assetsInlineLimit;
|
|
78
|
+
const inlineLimit = (file, content) => {
|
|
79
|
+
if (isDevFile(file))
|
|
80
|
+
return false;
|
|
81
|
+
if (typeof limit === "function")
|
|
82
|
+
return limit(file, content);
|
|
83
|
+
return limit === undefined ? undefined : content.length < limit;
|
|
84
|
+
};
|
|
85
|
+
inlineLimits.add(inlineLimit);
|
|
86
|
+
configured = true;
|
|
87
|
+
return {
|
|
88
|
+
build: { assetsInlineLimit: inlineLimit },
|
|
89
|
+
// Vite appends these to the user's worker plugins.
|
|
90
|
+
worker: { plugins: () => [buildGuard()] },
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
configResolved(resolved) {
|
|
94
|
+
config = resolved;
|
|
95
|
+
// Worker builds inherit the main build's limit, checked there.
|
|
96
|
+
const limit = resolved.build.assetsInlineLimit;
|
|
97
|
+
if (configured &&
|
|
98
|
+
!resolved.isWorker &&
|
|
99
|
+
!(typeof limit === "function" && inlineLimits.has(limit)))
|
|
100
|
+
throw new ExpectedError("repo:build-guard: a later plugin replaced build.assetsInlineLimit; dev assets could inline unchecked");
|
|
101
|
+
if (resolved.publicDir && isDevFile(join(resolved.publicDir, "_")))
|
|
102
|
+
throw new ExpectedError(`repo:build-guard: publicDir ${resolved.publicDir} is a dev folder`);
|
|
103
|
+
},
|
|
104
|
+
generateBundle(_, bundle) {
|
|
105
|
+
const assets = Object.values(bundle).flatMap((output) => output.type === "asset"
|
|
106
|
+
? output.originalFileNames.map((name) => resolve(config.root, name))
|
|
107
|
+
: []);
|
|
108
|
+
const modules = [...this.getModuleIds()];
|
|
109
|
+
const found = (files, test) => [
|
|
110
|
+
...new Set(files
|
|
111
|
+
.filter(test)
|
|
112
|
+
.map((id) => relative(config.root, id.replace(/^\0/, "").split("?")[0] ?? id))),
|
|
113
|
+
].sort();
|
|
114
|
+
const failures = [];
|
|
115
|
+
const dev = found([...modules, ...assets], isDevFile);
|
|
116
|
+
if (dev.length > 0)
|
|
117
|
+
failures.push(`dev-only files in the build${config.isProduction ? "" : " (build with NODE_ENV=production)"}: ${dev.join(", ")}`);
|
|
118
|
+
const test = found(modules, isTestFile);
|
|
119
|
+
if (test.length > 0)
|
|
120
|
+
failures.push(`test support in the build: ${test.join(", ")}`);
|
|
121
|
+
// Web workers build apart from the environment that starts them.
|
|
122
|
+
const client = config.isWorker || this.environment.config.consumer === "client";
|
|
123
|
+
const server = client ? found(modules, isServerFile) : [];
|
|
124
|
+
if (server.length > 0)
|
|
125
|
+
failures.push(`server-only modules in the client build: ${server.join(", ")}`);
|
|
126
|
+
if (failures.length > 0)
|
|
127
|
+
this.error(failures.join("\n"));
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Keeps dev classes out of built CSS: appends `@source not` for each
|
|
133
|
+
* workspace package's dev folders (`isDevFile`) to every Tailwind entry
|
|
134
|
+
* (CSS importing `tailwindcss`). Precedes `tailwindcss()`. Skips
|
|
135
|
+
* `?url`/`?raw`, which wrap the CSS as JS.
|
|
136
|
+
*/
|
|
137
|
+
export function tailwindDevSources() {
|
|
138
|
+
let devDirs = [];
|
|
139
|
+
return {
|
|
140
|
+
name: "repo:tailwind-dev-sources",
|
|
141
|
+
apply: "build",
|
|
142
|
+
enforce: "pre",
|
|
143
|
+
configResolved(resolved) {
|
|
144
|
+
devDirs = workspaceDevDirs(resolved.root);
|
|
145
|
+
},
|
|
146
|
+
transform: {
|
|
147
|
+
filter: {
|
|
148
|
+
id: { include: /\.css(?:\?|$)/, exclude: /[?&](?:url|raw)\b/ },
|
|
149
|
+
code: /@import\s+["']tailwindcss["']/,
|
|
150
|
+
},
|
|
151
|
+
handler(code, id) {
|
|
152
|
+
const dir = dirname(id.split("?")[0] ?? id);
|
|
153
|
+
const sources = devDirs.map((devDir) => `@source not "${normalizePath(relative(dir, devDir))}";`);
|
|
154
|
+
return `${code}\n${sources.join("\n")}\n`;
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/** Dev folders of the packages in `root`'s pnpm workspace, at any depth;
|
|
160
|
+
* `root` alone outside one. */
|
|
161
|
+
function workspaceDevDirs(root) {
|
|
162
|
+
const workspace = workspaceRoot(realpathSync(root));
|
|
163
|
+
const packages = workspace ? workspacePackageDirs(workspace) : [root];
|
|
164
|
+
return packages.flatMap((dir) => globSync("**/dev", { cwd: dir, exclude: ["**/node_modules/**"] })
|
|
165
|
+
.sort()
|
|
166
|
+
.map((path) => join(dir, path))
|
|
167
|
+
.filter((path) => isDevFile(join(path, "_"))));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Reuses the compiled SSR bundle inside an isolated prerender worker: the
|
|
171
|
+
* prerender environment's `entry` re-exports the SSR build's
|
|
172
|
+
* `wrangler.json` `main`, emitted under `runtime/`. Requires the Cloudflare
|
|
173
|
+
* Vite plugin: its entry worker builds as the `ssr` environment (TanStack
|
|
174
|
+
* Start's server) and writes `wrangler.json`; its
|
|
175
|
+
* `experimental.prerenderWorker` builds as `environment`.
|
|
176
|
+
*/
|
|
177
|
+
export function prerenderRuntime({ entry, environment = "prerender", }) {
|
|
178
|
+
let entryPath;
|
|
179
|
+
let runtime;
|
|
180
|
+
return {
|
|
181
|
+
name: "repo:prerender-runtime",
|
|
182
|
+
apply: "build",
|
|
183
|
+
enforce: "pre",
|
|
184
|
+
applyToEnvironment: ({ name }) => name === environment,
|
|
185
|
+
configEnvironment(name) {
|
|
186
|
+
// Server environments drop emitted assets by default.
|
|
187
|
+
if (name === environment)
|
|
188
|
+
return { build: { emitAssets: true } };
|
|
189
|
+
},
|
|
190
|
+
configResolved(config) {
|
|
191
|
+
const server = config.environments.ssr;
|
|
192
|
+
if (!server)
|
|
193
|
+
throw new ExpectedError("repo:prerender-runtime: prerender requires the ssr environment");
|
|
194
|
+
// Module ids are normalized paths, `/`-separated on every platform.
|
|
195
|
+
entryPath = normalizePath(resolve(config.root, entry));
|
|
196
|
+
runtime = resolve(config.root, server.build.outDir);
|
|
197
|
+
},
|
|
198
|
+
resolveId(source) {
|
|
199
|
+
if (source !== "virtual:prerender-runtime")
|
|
200
|
+
return;
|
|
201
|
+
const config = join(runtime, "wrangler.json");
|
|
202
|
+
if (!existsSync(config))
|
|
203
|
+
this.error(`${config} is missing: prerender needs the Cloudflare Vite plugin's entry worker as the ssr environment`);
|
|
204
|
+
const { main } = JSON.parse(readFileSync(config, "utf8"));
|
|
205
|
+
return { id: `./runtime/${main}`, external: true };
|
|
206
|
+
},
|
|
207
|
+
load(id) {
|
|
208
|
+
if (id === entryPath)
|
|
209
|
+
return 'export { default } from "virtual:prerender-runtime";';
|
|
210
|
+
},
|
|
211
|
+
generateBundle() {
|
|
212
|
+
for (const file of globSync("**/*.{js,mjs,wasm}", { cwd: runtime }))
|
|
213
|
+
this.emitFile({
|
|
214
|
+
type: "asset",
|
|
215
|
+
fileName: `runtime/${file}`,
|
|
216
|
+
source: readFileSync(join(runtime, file)),
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Isolates the prerender worker from runtime bindings and secrets: the
|
|
223
|
+
* Cloudflare Vite plugin's `experimental.prerenderWorker.config`. The
|
|
224
|
+
* worker runs the entry worker's bundle (`main`, compatibility date and
|
|
225
|
+
* flags) with `vars` as its whole environment; the entry worker's
|
|
226
|
+
* bindings, other vars, and required secrets stay behind.
|
|
227
|
+
*/
|
|
228
|
+
export function prerenderWorkerConfig({ name, vars, }) {
|
|
229
|
+
return (_, { entryWorkerConfig }) => ({
|
|
230
|
+
name,
|
|
231
|
+
main: entryWorkerConfig.main,
|
|
232
|
+
compatibility_date: entryWorkerConfig.compatibility_date,
|
|
233
|
+
compatibility_flags: entryWorkerConfig.compatibility_flags,
|
|
234
|
+
secrets: { required: [] },
|
|
235
|
+
vars: vars(entryWorkerConfig.vars),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Re-transforms a deleted file's importers, so a rename reaches them.
|
|
240
|
+
* Vite soft-invalidates them: their code keeps the deleted import path.
|
|
241
|
+
*/
|
|
242
|
+
export function renameRecovery() {
|
|
243
|
+
return {
|
|
244
|
+
name: "repo:rename-recovery",
|
|
245
|
+
apply: "serve",
|
|
246
|
+
hotUpdate({ type, modules }) {
|
|
247
|
+
if (type !== "delete")
|
|
248
|
+
return;
|
|
249
|
+
const importers = modules.flatMap((mod) => [...mod.importers]);
|
|
250
|
+
if (importers.length > 0)
|
|
251
|
+
return [...modules, ...importers];
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
}
|
package/dist/wait.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Default `waitFor` deadline. */
|
|
2
|
+
export declare const READY_TIMEOUT_MS = 120000;
|
|
3
|
+
/** TCP connect succeeds within 1s. */
|
|
4
|
+
export declare function isPortOpen(port: number, host?: string): Promise<boolean>;
|
|
5
|
+
/** Polls `probe` each second until true; rejects with `message` at the deadline. */
|
|
6
|
+
export declare function waitFor(probe: () => boolean | Promise<boolean>, message: string, timeoutMs?: number, signal?: AbortSignal): Promise<void>;
|
|
7
|
+
/** Polls until localhost `port` refuses connections; rejects with
|
|
8
|
+
* `message` after 15s. */
|
|
9
|
+
export declare function waitForPortClose(port: number, message: string, signal?: AbortSignal): Promise<void>;
|
package/dist/wait.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Readiness polling: TCP probes and a deadline loop. */
|
|
2
|
+
import { connect } from "node:net";
|
|
3
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
4
|
+
import { ExpectedError } from "@astralarium/repo-telemetry";
|
|
5
|
+
/** Default `waitFor` deadline. */
|
|
6
|
+
export const READY_TIMEOUT_MS = 120_000;
|
|
7
|
+
/** TCP connect succeeds within 1s. */
|
|
8
|
+
export function isPortOpen(port, host = "127.0.0.1") {
|
|
9
|
+
return new Promise((done) => {
|
|
10
|
+
const sock = connect({ host, port, timeout: 1_000 });
|
|
11
|
+
sock.once("connect", () => {
|
|
12
|
+
sock.destroy();
|
|
13
|
+
done(true);
|
|
14
|
+
});
|
|
15
|
+
sock.once("error", () => done(false));
|
|
16
|
+
sock.once("timeout", () => {
|
|
17
|
+
sock.destroy();
|
|
18
|
+
done(false);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** Polls `probe` each second until true; rejects with `message` at the deadline. */
|
|
23
|
+
export async function waitFor(probe, message, timeoutMs = READY_TIMEOUT_MS, signal) {
|
|
24
|
+
const deadline = Date.now() + timeoutMs;
|
|
25
|
+
for (;;) {
|
|
26
|
+
signal?.throwIfAborted();
|
|
27
|
+
if (await probe())
|
|
28
|
+
return;
|
|
29
|
+
if (Date.now() > deadline)
|
|
30
|
+
throw new ExpectedError(message);
|
|
31
|
+
await sleep(1_000, undefined, { signal });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Polls until localhost `port` refuses connections; rejects with
|
|
35
|
+
* `message` after 15s. */
|
|
36
|
+
export function waitForPortClose(port, message, signal) {
|
|
37
|
+
return waitFor(async () => !(await isPortOpen(port, "localhost")), message, 15_000, signal);
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astralarium/repo-dev",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"homepage": "https://github.com/astralarium/repo/tree/main/packages/repo-dev#readme",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/astralarium/repo.git",
|
|
9
|
+
"directory": "packages/repo-dev"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./dist/index.js",
|
|
17
|
+
"./launcher": "./dist/launcher/launcher.js",
|
|
18
|
+
"./testkit": "./dist/testkit/index.js",
|
|
19
|
+
"./vite": "./dist/vite.js"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"db-image": "./dist/bin/db-image.js",
|
|
23
|
+
"run-dev": "./dist/bin/run-dev.js",
|
|
24
|
+
"siblings-inputs": "./dist/bin/siblings-inputs.js"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"json5": "^2.2.3",
|
|
31
|
+
"undici": "^7.29.0",
|
|
32
|
+
"zod": "^4.6.7",
|
|
33
|
+
"@astralarium/repo-deploy-info": "^0.1.1",
|
|
34
|
+
"@astralarium/repo-telemetry": "^0.2.0",
|
|
35
|
+
"@astralarium/repo-package-files": "^0.1.0",
|
|
36
|
+
"@astralarium/repo-env": "^0.2.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@cloudflare/vite-plugin": "^1.54.10",
|
|
40
|
+
"@types/node": "^24.2.0",
|
|
41
|
+
"eslint": "^10.2.1",
|
|
42
|
+
"turbo": "^2.10.13",
|
|
43
|
+
"typescript": "^6.0.3",
|
|
44
|
+
"vite": "^8.3.4",
|
|
45
|
+
"vitest": "^5.0.3",
|
|
46
|
+
"wrangler": "^4.132.0",
|
|
47
|
+
"@astralarium/repo-config-typescript": "^0.1.0",
|
|
48
|
+
"@astralarium/repo-config-eslint": "^0.3.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"turbo": "^2.10.13",
|
|
52
|
+
"vite": "^8.3.4",
|
|
53
|
+
"vitest": "^5.0.3"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"turbo": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"vite": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"vitest": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=24.2"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"check-types": "tsc --noEmit && tsc -p tsconfig.build.json --noEmit",
|
|
71
|
+
"lint": "eslint",
|
|
72
|
+
"test": "vitest"
|
|
73
|
+
}
|
|
6
74
|
}
|