ecopages 0.2.0-alpha.9 → 0.2.0-beta.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.
@@ -1,142 +1,84 @@
1
- import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
-
5
- const NODE_THIN_HOST_PATH = fileURLToPath(new URL('./node-thin-host.js', import.meta.url));
6
- const DEFAULT_INTERNAL_WORK_DIR = '.eco';
7
-
8
- export function buildEnvOverrides(options) {
9
- const env = {};
10
- if (options.port) env.ECOPAGES_PORT = String(options.port);
11
- if (options.hostname) env.ECOPAGES_HOSTNAME = options.hostname;
12
- if (options.baseUrl) env.ECOPAGES_BASE_URL = options.baseUrl;
13
- if (options.debug) env.ECOPAGES_LOGGER_DEBUG = 'true';
14
- if (options.nodeEnv) env.NODE_ENV = options.nodeEnv;
15
- return env;
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { parseEnv } from "node:util";
3
+ const nodeRequirePreload = import.meta.resolve("./node-require-preload.js");
4
+ const tsxLoader = import.meta.resolve("tsx/esm");
5
+ function getEnvFilePaths(nodeEnv) {
6
+ const envFiles = [".env", ".env.local"];
7
+ if (nodeEnv) {
8
+ envFiles.push(`.env.${nodeEnv}`, `.env.${nodeEnv}.local`);
9
+ }
10
+ return envFiles.filter((envFile) => existsSync(envFile));
16
11
  }
17
-
18
- export function detectRuntime(options = {}) {
19
- if (options.runtime === 'bun' || options.runtime === 'node' || options.runtime === 'node-experimental') {
20
- return options.runtime;
21
- }
22
-
23
- const userAgent = process.env.npm_config_user_agent || '';
24
-
25
- if (userAgent.startsWith('bun/')) {
26
- return 'bun';
27
- }
28
-
29
- if (typeof Bun !== 'undefined') {
30
- return 'bun';
31
- }
32
-
33
- return 'node';
12
+ function buildEnvOverrides(options) {
13
+ const env = {};
14
+ if (options.port) env.ECOPAGES_PORT = String(options.port);
15
+ if (options.hostname) env.ECOPAGES_HOSTNAME = options.hostname;
16
+ if (options.baseUrl) env.ECOPAGES_BASE_URL = options.baseUrl;
17
+ if (options.debug) env.ECOPAGES_LOGGER_DEBUG = "true";
18
+ if (options.nodeEnv) env.NODE_ENV = options.nodeEnv;
19
+ return env;
34
20
  }
35
-
36
- export function buildBunArgs(args, options, entryFile, hasConfig) {
37
- const bunArgs = [];
38
-
39
- if (options.watch) bunArgs.push('--watch');
40
- if (options.hot) bunArgs.push('--hot');
41
-
42
- bunArgs.push('run');
43
-
44
- if (hasConfig) {
45
- bunArgs.push('--preload', 'eco.config.ts');
46
- }
47
-
48
- bunArgs.push(entryFile, ...args);
49
-
50
- if (options.reactFastRefresh) {
51
- bunArgs.push('--react-fast-refresh');
52
- }
53
-
54
- return bunArgs;
21
+ function buildLaunchEnv(options) {
22
+ const envOverrides = buildEnvOverrides(options);
23
+ const envFileValues = getEnvFilePaths(options.nodeEnv).reduce((env, envFile) => {
24
+ return { ...env, ...parseEnv(readFileSync(envFile, "utf8")) };
25
+ }, {});
26
+ return {
27
+ envOverrides,
28
+ env: { ...envFileValues, ...process.env, ...envOverrides }
29
+ };
55
30
  }
56
-
57
- export function buildNodeArgs(args, options, entryFile) {
58
- const nodeArgs = [];
59
-
60
- if (options.watch) nodeArgs.push('--watch');
61
-
62
- nodeArgs.push(NODE_THIN_HOST_PATH, entryFile, ...args);
63
-
64
- if (options.reactFastRefresh) {
65
- nodeArgs.push('--react-fast-refresh');
66
- }
67
-
68
- return nodeArgs;
31
+ function detectRuntime(options = {}) {
32
+ if (options.runtime === "bun" || options.runtime === "node") {
33
+ return options.runtime;
34
+ }
35
+ const userAgent = process.env.npm_config_user_agent || "";
36
+ if (userAgent.startsWith("bun/")) {
37
+ return "bun";
38
+ }
39
+ if (typeof Bun !== "undefined") {
40
+ return "bun";
41
+ }
42
+ return "node";
69
43
  }
70
-
71
- export function resolveNodeRuntimeManifestPath(projectDir = process.cwd()) {
72
- return path.join(path.resolve(projectDir), DEFAULT_INTERNAL_WORK_DIR, 'runtime', 'node-runtime-manifest.json');
44
+ function buildBunArgs(args, options, entryFile, hasConfig) {
45
+ const bunArgs = [];
46
+ if (options.watch) bunArgs.push("--watch");
47
+ if (options.hot) bunArgs.push("--hot");
48
+ bunArgs.push("run");
49
+ if (hasConfig) {
50
+ bunArgs.push("--preload", `./eco.config.${"ts"}`);
51
+ }
52
+ bunArgs.push(entryFile, ...args);
53
+ if (options.reactFastRefresh) {
54
+ bunArgs.push("--react-fast-refresh");
55
+ }
56
+ return bunArgs;
73
57
  }
74
-
75
- export async function createNodeRuntimeManifestFile(
76
- entryFile,
77
- options = {
78
- cwd: process.cwd(),
79
- env: process.env,
80
- },
81
- ) {
82
- const projectDir = path.resolve(options.cwd ?? process.cwd());
83
- const configPath = path.join(projectDir, 'eco.config.ts');
84
- const manifestFilePath = options.manifestFilePath ?? resolveNodeRuntimeManifestPath(projectDir);
85
-
86
- if (!existsSync(configPath)) {
87
- throw new Error('The Node thin-host runtime requires eco.config.ts in the current project root.');
88
- }
89
-
90
- const manifest = {
91
- runtime: 'node',
92
- appRootDir: projectDir,
93
- sourceRootDir: path.join(projectDir, 'src'),
94
- distDir: path.join(projectDir, 'dist'),
95
- workDir: path.join(projectDir, DEFAULT_INTERNAL_WORK_DIR),
96
- modulePaths: {
97
- config: configPath,
98
- entry: path.resolve(projectDir, entryFile),
99
- },
100
- };
101
-
102
- mkdirSync(path.dirname(manifestFilePath), { recursive: true });
103
- writeFileSync(manifestFilePath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
104
-
105
- return manifestFilePath;
106
- }
107
-
108
- export async function createLaunchPlan(args, options = {}, entryFile = 'app.ts') {
109
- const hasConfig = existsSync('eco.config.ts');
110
- const envOverrides = buildEnvOverrides(options);
111
- const runtime = detectRuntime(options);
112
- const env = { ...process.env, ...envOverrides };
113
-
114
- if (runtime === 'node' || runtime === 'node-experimental') {
115
- const manifestFilePath = await createNodeRuntimeManifestFile(entryFile, { env });
116
-
117
- return {
118
- runtime,
119
- executionStrategy: 'node-thin-host',
120
- command: 'node',
121
- commandArgs: buildNodeArgs(args, options, entryFile),
122
- envOverrides,
123
- env: {
124
- ...env,
125
- ECOPAGES_NODE_RUNTIME_MANIFEST_PATH: manifestFilePath,
126
- },
127
- };
128
- }
129
-
130
- return {
131
- runtime,
132
- executionStrategy: 'direct-runtime',
133
- command: 'bun',
134
- commandArgs: buildBunArgs(args, options, entryFile, hasConfig),
135
- envOverrides,
136
- env,
137
- };
138
- }
139
-
140
- export function launchPlanRequiresExistingEntryFile(launchPlan) {
141
- return launchPlan.executionStrategy !== 'config-only-bootstrap';
58
+ function createLaunchPlan(args, options = {}, entryFile = "app.ts") {
59
+ const { envOverrides, env } = buildLaunchEnv(options);
60
+ const runtime = detectRuntime(options);
61
+ if (runtime === "node") {
62
+ return {
63
+ runtime,
64
+ command: process.execPath,
65
+ commandArgs: ["--import", nodeRequirePreload, "--import", tsxLoader, entryFile, ...args],
66
+ envOverrides,
67
+ env
68
+ };
69
+ }
70
+ return {
71
+ runtime,
72
+ command: "bun",
73
+ commandArgs: buildBunArgs(args, options, entryFile, existsSync("eco.config.ts")),
74
+ envOverrides,
75
+ env
76
+ };
142
77
  }
78
+ export {
79
+ buildBunArgs,
80
+ buildEnvOverrides,
81
+ buildLaunchEnv,
82
+ createLaunchPlan,
83
+ detectRuntime
84
+ };
@@ -0,0 +1,3 @@
1
+ import path from "node:path";
2
+ import { createRequire } from "node:module";
3
+ globalThis.require = createRequire(path.join(process.cwd(), "package.json"));
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "ecopages",
3
- "version": "0.2.0-alpha.9",
3
+ "version": "0.2.0-beta.0",
4
4
  "description": "CLI utilities for Ecopages",
5
5
  "type": "module",
6
+ "engines": {
7
+ "node": ">=24.0.0"
8
+ },
6
9
  "license": "MIT",
7
10
  "author": "Ecopages Team",
8
11
  "repository": {
@@ -28,17 +31,11 @@
28
31
  "bin": {
29
32
  "ecopages": "bin/cli.js"
30
33
  },
31
- "files": [
32
- "bin/",
33
- "css/",
34
- "README.md"
35
- ],
36
34
  "dependencies": {
37
- "@ecopages/core": "workspace:*",
38
- "esbuild": "^0.27.3",
39
- "commander": "^12.1.0",
40
- "tiged": "^2.12.7",
41
- "@ecopages/logger": "^0.2.2"
35
+ "@ecopages/core": "0.2.0-beta.0",
36
+ "@ecopages/logger": "^0.2.3",
37
+ "giget": "^2.0.0",
38
+ "tsx": "^4.22.3"
42
39
  },
43
40
  "peerDependencies": {
44
41
  "bun-types": "*",
@@ -1,316 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { tmpdir } from 'node:os';
4
- import { afterEach, describe, expect, it } from 'vitest';
5
- import {
6
- buildEnvOverrides,
7
- buildNodeArgs,
8
- buildBunArgs,
9
- createNodeRuntimeManifestFile,
10
- createLaunchPlan,
11
- detectRuntime,
12
- launchPlanRequiresExistingEntryFile,
13
- resolveNodeRuntimeManifestPath,
14
- } from './launch-plan.js';
15
-
16
- const originalUserAgent = process.env.npm_config_user_agent;
17
-
18
- afterEach(() => {
19
- if (originalUserAgent === undefined) {
20
- delete process.env.npm_config_user_agent;
21
- } else {
22
- process.env.npm_config_user_agent = originalUserAgent;
23
- }
24
- process.chdir('/Users/andeeplus/github/ecopages');
25
- });
26
-
27
- describe('launch-plan', () => {
28
- function writeExperimentalRuntimeConfig(tempDir) {
29
- fs.writeFileSync(
30
- path.join(tempDir, 'eco.config.ts'),
31
- [
32
- 'const rootDir = process.cwd();',
33
- 'export default {',
34
- '\trootDir,',
35
- '\tloaders: new Map(),',
36
- '\tabsolutePaths: {',
37
- '\t\tconfig: `${rootDir}/eco.config.ts`,',
38
- '\t\tsrcDir: `${rootDir}/src`,',
39
- '\t\tdistDir: `${rootDir}/dist`,',
40
- '\t\tworkDir: `${rootDir}/.eco`,',
41
- '\t},',
42
- '\truntime: {},',
43
- '};',
44
- ].join('\n'),
45
- 'utf8',
46
- );
47
- }
48
-
49
- function writeImportMetaRuntimeConfig(tempDir) {
50
- fs.writeFileSync(
51
- path.join(tempDir, 'eco.config.ts'),
52
- [
53
- "import path from 'node:path';",
54
- 'export default {',
55
- '\trootDir: import.meta.dirname,',
56
- '\tloaders: new Map(),',
57
- '\tabsolutePaths: {',
58
- "\t\tconfig: path.join(import.meta.dirname, 'eco.config.ts'),",
59
- "\t\tsrcDir: path.join(import.meta.dirname, 'src'),",
60
- "\t\tdistDir: path.join(import.meta.dirname, 'dist'),",
61
- "\t\tworkDir: path.join(import.meta.dirname, '.eco'),",
62
- '\t},',
63
- '\truntime: {},',
64
- '};',
65
- ].join('\n'),
66
- 'utf8',
67
- );
68
- }
69
-
70
- it('buildEnvOverrides maps CLI options onto environment variables', () => {
71
- expect(
72
- buildEnvOverrides({
73
- port: 4173,
74
- hostname: '127.0.0.1',
75
- baseUrl: 'https://example.test',
76
- debug: true,
77
- nodeEnv: 'production',
78
- }),
79
- ).toEqual({
80
- ECOPAGES_PORT: '4173',
81
- ECOPAGES_HOSTNAME: '127.0.0.1',
82
- ECOPAGES_BASE_URL: 'https://example.test',
83
- ECOPAGES_LOGGER_DEBUG: 'true',
84
- NODE_ENV: 'production',
85
- });
86
- });
87
-
88
- it('detectRuntime defaults to node unless bun is explicit', () => {
89
- process.env.npm_config_user_agent = 'pnpm/10.0.0 npm/? node/v24.0.0 darwin arm64';
90
- expect(detectRuntime()).toBe('node');
91
- expect(detectRuntime({ runtime: 'bun' })).toBe('bun');
92
- expect(detectRuntime({ runtime: 'node' })).toBe('node');
93
- expect(detectRuntime({ runtime: 'node-experimental' })).toBe('node-experimental');
94
- });
95
-
96
- it('buildNodeArgs preserves watch mode and fast refresh flags', () => {
97
- expect(buildNodeArgs(['--dev'], { watch: true, reactFastRefresh: true }, 'app.ts')).toEqual([
98
- '--watch',
99
- expect.stringMatching(/node-thin-host\.js$/),
100
- 'app.ts',
101
- '--dev',
102
- '--react-fast-refresh',
103
- ]);
104
- });
105
-
106
- it('buildNodeArgs routes stable Node through the thin launcher', () => {
107
- expect(buildNodeArgs(['--dev'], { watch: true }, 'app.ts')).toEqual([
108
- '--watch',
109
- expect.stringMatching(/node-thin-host\.js$/),
110
- 'app.ts',
111
- '--dev',
112
- ]);
113
- });
114
-
115
- it('buildBunArgs preloads eco.config.ts when present', () => {
116
- expect(buildBunArgs(['--dev'], { hot: true }, 'app.ts', true)).toEqual([
117
- '--hot',
118
- 'run',
119
- '--preload',
120
- 'eco.config.ts',
121
- 'app.ts',
122
- '--dev',
123
- ]);
124
- });
125
-
126
- it('createLaunchPlan routes node app launches through the thin host', async () => {
127
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
128
- try {
129
- process.env.npm_config_user_agent = 'pnpm/10.0.0 npm/? node/v24.0.0 darwin arm64';
130
- process.chdir(tempDir);
131
- writeExperimentalRuntimeConfig(tempDir);
132
- fs.writeFileSync(
133
- path.join(tempDir, 'app.ts'),
134
- [
135
- "import { EcopagesApp } from '@ecopages/core';",
136
- "import appConfig from './eco.config';",
137
- 'const app = new EcopagesApp({ appConfig });',
138
- 'await app.start();',
139
- ].join('\n'),
140
- 'utf8',
141
- );
142
- const plan = await createLaunchPlan(['--dev'], { watch: true, nodeEnv: 'development' }, 'app.ts');
143
-
144
- expect(plan).toMatchObject({
145
- runtime: 'node',
146
- executionStrategy: 'node-thin-host',
147
- command: 'node',
148
- envOverrides: { NODE_ENV: 'development' },
149
- });
150
- expect(plan.commandArgs).toEqual([
151
- '--watch',
152
- expect.stringMatching(/node-thin-host\.js$/),
153
- 'app.ts',
154
- '--dev',
155
- ]);
156
- } finally {
157
- fs.rmSync(tempDir, { recursive: true, force: true });
158
- }
159
- });
160
-
161
- it('createLaunchPlan preserves direct node entrypoints on the thin-host path', async () => {
162
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
163
- try {
164
- process.env.npm_config_user_agent = 'pnpm/10.0.0 npm/? node/v24.0.0 darwin arm64';
165
- process.chdir(tempDir);
166
- fs.writeFileSync(path.join(tempDir, 'server.ts'), 'await Promise.resolve();', 'utf8');
167
- writeExperimentalRuntimeConfig(tempDir);
168
-
169
- const plan = await createLaunchPlan(['--dev'], { watch: true }, 'server.ts');
170
-
171
- expect(plan).toMatchObject({
172
- runtime: 'node',
173
- executionStrategy: 'node-thin-host',
174
- command: 'node',
175
- });
176
- expect(plan.commandArgs).toEqual([
177
- '--watch',
178
- expect.stringMatching(/node-thin-host\.js$/),
179
- 'server.ts',
180
- '--dev',
181
- ]);
182
- } finally {
183
- fs.rmSync(tempDir, { recursive: true, force: true });
184
- }
185
- });
186
-
187
- it('createLaunchPlan uses bun direct runtime and preloads eco.config.ts', async () => {
188
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
189
- try {
190
- process.chdir(tempDir);
191
- fs.writeFileSync(path.join(tempDir, 'app.ts'), 'await Promise.resolve();', 'utf8');
192
- writeExperimentalRuntimeConfig(tempDir);
193
-
194
- const plan = await createLaunchPlan(['--preview'], { runtime: 'bun' }, 'app.ts');
195
-
196
- expect(plan).toMatchObject({
197
- runtime: 'bun',
198
- executionStrategy: 'direct-runtime',
199
- command: 'bun',
200
- });
201
- expect(plan.commandArgs).toEqual(['run', '--preload', 'eco.config.ts', 'app.ts', '--preview']);
202
- } finally {
203
- fs.rmSync(tempDir, { recursive: true, force: true });
204
- }
205
- });
206
-
207
- it('createNodeRuntimeManifestFile writes the core-owned manifest under .eco/runtime', async () => {
208
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
209
- try {
210
- process.chdir(tempDir);
211
- writeExperimentalRuntimeConfig(tempDir);
212
- const manifestFilePath = await createNodeRuntimeManifestFile('app.ts');
213
- const manifest = JSON.parse(fs.readFileSync(manifestFilePath, 'utf8'));
214
- const resolvedTempDir = fs.realpathSync(tempDir);
215
-
216
- expect(manifestFilePath).toBe(resolveNodeRuntimeManifestPath(resolvedTempDir));
217
- expect(manifest).toMatchObject({
218
- runtime: 'node',
219
- appRootDir: resolvedTempDir,
220
- sourceRootDir: path.join(resolvedTempDir, 'src'),
221
- distDir: path.join(resolvedTempDir, 'dist'),
222
- workDir: path.join(resolvedTempDir, '.eco'),
223
- modulePaths: {
224
- config: path.join(resolvedTempDir, 'eco.config.ts'),
225
- entry: path.join(resolvedTempDir, 'app.ts'),
226
- },
227
- });
228
- } finally {
229
- fs.rmSync(tempDir, { recursive: true, force: true });
230
- }
231
- });
232
-
233
- it('createNodeRuntimeManifestFile does not evaluate eco.config.ts while writing the manifest', async () => {
234
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
235
- try {
236
- process.chdir(tempDir);
237
- writeImportMetaRuntimeConfig(tempDir);
238
- const manifestFilePath = await createNodeRuntimeManifestFile('app.ts');
239
- const manifest = JSON.parse(fs.readFileSync(manifestFilePath, 'utf8'));
240
- const resolvedTempDir = fs.realpathSync(tempDir);
241
-
242
- expect(manifestFilePath).toBe(resolveNodeRuntimeManifestPath(resolvedTempDir));
243
- expect(manifest).toMatchObject({
244
- appRootDir: resolvedTempDir,
245
- sourceRootDir: path.join(resolvedTempDir, 'src'),
246
- distDir: path.join(resolvedTempDir, 'dist'),
247
- workDir: path.join(resolvedTempDir, '.eco'),
248
- modulePaths: {
249
- config: path.join(resolvedTempDir, 'eco.config.ts'),
250
- entry: path.join(resolvedTempDir, 'app.ts'),
251
- },
252
- });
253
- } finally {
254
- fs.rmSync(tempDir, { recursive: true, force: true });
255
- }
256
- });
257
-
258
- it('createLaunchPlan routes node-experimental through the thin host launcher', async () => {
259
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
260
- try {
261
- process.chdir(tempDir);
262
- writeExperimentalRuntimeConfig(tempDir);
263
- const resolvedTempDir = fs.realpathSync(tempDir);
264
- const plan = await createLaunchPlan(
265
- ['--dev'],
266
- { runtime: 'node-experimental', nodeEnv: 'development' },
267
- 'app.ts',
268
- );
269
-
270
- expect(plan).toMatchObject({
271
- runtime: 'node-experimental',
272
- executionStrategy: 'node-thin-host',
273
- command: 'node',
274
- envOverrides: { NODE_ENV: 'development' },
275
- });
276
- expect(plan.commandArgs).toEqual([expect.stringMatching(/node-thin-host\.js$/), 'app.ts', '--dev']);
277
- expect(plan.env.ECOPAGES_NODE_RUNTIME_MANIFEST_PATH).toBe(resolveNodeRuntimeManifestPath(resolvedTempDir));
278
- expect(JSON.parse(fs.readFileSync(plan.env.ECOPAGES_NODE_RUNTIME_MANIFEST_PATH, 'utf8'))).toMatchObject({
279
- runtime: 'node',
280
- modulePaths: {
281
- config: path.join(resolvedTempDir, 'eco.config.ts'),
282
- entry: path.join(resolvedTempDir, 'app.ts'),
283
- },
284
- });
285
- } finally {
286
- fs.rmSync(tempDir, { recursive: true, force: true });
287
- }
288
- });
289
-
290
- it('launchPlanRequiresExistingEntryFile requires a concrete entry on every runtime path', async () => {
291
- const tempDir = fs.mkdtempSync(path.join(tmpdir(), 'eco-cli-launch-plan-'));
292
- try {
293
- process.env.npm_config_user_agent = 'pnpm/10.0.0 npm/? node/v24.0.0 darwin arm64';
294
- process.chdir(tempDir);
295
- fs.writeFileSync(path.join(tempDir, 'app.ts'), 'await Promise.resolve();', 'utf8');
296
- writeExperimentalRuntimeConfig(tempDir);
297
-
298
- const nodePlan = await createLaunchPlan(['--dev'], { nodeEnv: 'development' }, 'app.ts');
299
- expect(nodePlan.executionStrategy).toBe('node-thin-host');
300
- expect(launchPlanRequiresExistingEntryFile(nodePlan)).toBe(true);
301
-
302
- fs.writeFileSync(path.join(tempDir, 'server.ts'), 'await Promise.resolve();', 'utf8');
303
- const directNodePlan = await createLaunchPlan(['--dev'], { nodeEnv: 'development' }, 'server.ts');
304
- expect(directNodePlan.executionStrategy).toBe('node-thin-host');
305
- expect(launchPlanRequiresExistingEntryFile(directNodePlan)).toBe(true);
306
-
307
- const bunPlan = await createLaunchPlan(['--dev'], { runtime: 'bun' }, 'app.ts');
308
- expect(launchPlanRequiresExistingEntryFile(bunPlan)).toBe(true);
309
-
310
- const experimentalNodePlan = await createLaunchPlan(['--dev'], { runtime: 'node-experimental' }, 'app.ts');
311
- expect(launchPlanRequiresExistingEntryFile(experimentalNodePlan)).toBe(true);
312
- } finally {
313
- fs.rmSync(tempDir, { recursive: true, force: true });
314
- }
315
- });
316
- });