devflare 1.0.0-next.10 → 1.0.0-next.12
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/LLM.md +683 -13
- package/README.md +33 -5
- package/dist/{build-k36xrzvy.js → build-rfh8cgh3.js} +40 -11
- package/dist/bundler/index.d.ts +1 -0
- package/dist/bundler/index.d.ts.map +1 -1
- package/dist/bundler/worker-bundler.d.ts +14 -0
- package/dist/bundler/worker-bundler.d.ts.map +1 -0
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/config/compiler.d.ts.map +1 -1
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/resolve.d.ts +3 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/schema.d.ts +37 -31
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/{deploy-dbvfq8vq.js → deploy-k0fcgt3d.js} +40 -11
- package/dist/{dev-rk8p6pse.js → dev-d4wabqyf.js} +73 -470
- package/dist/dev-server/server.d.ts.map +1 -1
- package/dist/{doctor-06y8nxd4.js → doctor-z4ffybce.js} +2 -2
- package/dist/{index-jht2j546.js → index-0kzg8wed.js} +26 -6
- package/dist/index-1xqeptt2.js +623 -0
- package/dist/{index-pwgyy2q9.js → index-dr6sbp8d.js} +1 -1
- package/dist/{index-6v3wjg1r.js → index-rfhx0yd5.js} +11 -7
- package/dist/{index-05fyzwne.js → index-twpgq9k9.js} +5 -5
- package/dist/{index-1phx14av.js → index-wyf3s77s.js} +1 -1
- package/dist/{index-vs49yxn4.js → index-xxwbb2nt.js} +1 -1
- package/dist/index-zbvmtcn2.js +795 -0
- package/dist/src/browser.js +1 -1
- package/dist/src/cli/index.js +1 -1
- package/dist/src/index.js +12 -13
- package/dist/src/sveltekit/index.js +4 -5
- package/dist/src/test/index.js +6 -7
- package/dist/src/vite/index.js +19 -399
- package/dist/test/simple-context.d.ts.map +1 -1
- package/dist/{types-x9q7t491.js → types-sffr9681.js} +7 -8
- package/dist/vite/config-file.d.ts +25 -0
- package/dist/vite/config-file.d.ts.map +1 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/worker-entry/composed-worker.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/index-k7r18na8.js +0 -0
- package/dist/index-ws68xvq2.js +0 -311
|
@@ -1,442 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bundleWorkerEntry,
|
|
3
|
+
createDOBundler
|
|
4
|
+
} from "./index-1xqeptt2.js";
|
|
1
5
|
import {
|
|
2
6
|
detectViteProject,
|
|
3
7
|
stopSpawnedProcessTree,
|
|
4
8
|
waitForViteReady
|
|
5
9
|
} from "./index-y1d8za14.js";
|
|
6
10
|
import {
|
|
7
|
-
prepareComposedWorkerEntrypoint
|
|
8
|
-
|
|
11
|
+
prepareComposedWorkerEntrypoint,
|
|
12
|
+
resolveEffectiveViteProject,
|
|
13
|
+
writeGeneratedViteConfig
|
|
14
|
+
} from "./index-zbvmtcn2.js";
|
|
9
15
|
import {
|
|
10
16
|
discoverRoutes,
|
|
11
17
|
getRouteDirectoryCandidate
|
|
12
18
|
} from "./index-1p814k7s.js";
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
transformDurableObject
|
|
16
|
-
} from "./index-9wt9x09k.js";
|
|
17
|
-
import {
|
|
18
|
-
findFiles
|
|
19
|
-
} from "./index-rbht7m9r.js";
|
|
19
|
+
import"./index-rbht7m9r.js";
|
|
20
|
+
import"./index-9wt9x09k.js";
|
|
20
21
|
import {
|
|
21
22
|
clearLocalSendEmailBindings,
|
|
22
23
|
setLocalSendEmailBindings
|
|
23
24
|
} from "./index-fef08w43.js";
|
|
25
|
+
import"./index-rfhx0yd5.js";
|
|
24
26
|
import {
|
|
25
27
|
loadConfig,
|
|
26
28
|
resolveConfigPath
|
|
27
|
-
} from "./index-
|
|
29
|
+
} from "./index-wyf3s77s.js";
|
|
30
|
+
import"./index-v8vvsn9x.js";
|
|
28
31
|
import {
|
|
29
32
|
__require
|
|
30
33
|
} from "./index-37x76zdn.js";
|
|
31
34
|
|
|
32
35
|
// src/cli/commands/dev.ts
|
|
33
36
|
import { createConsola } from "consola";
|
|
34
|
-
import { relative
|
|
37
|
+
import { relative, resolve as resolve2 } from "pathe";
|
|
35
38
|
|
|
36
39
|
// src/dev-server/server.ts
|
|
37
|
-
import { dirname
|
|
38
|
-
|
|
39
|
-
// src/bundler/do-bundler.ts
|
|
40
|
-
import { resolve, dirname, relative } from "pathe";
|
|
41
|
-
import picomatch from "picomatch";
|
|
42
|
-
function classToBindingName(className) {
|
|
43
|
-
return className.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toUpperCase();
|
|
44
|
-
}
|
|
45
|
-
async function discoverDOs(cwd, pattern) {
|
|
46
|
-
const fs = await import("node:fs/promises");
|
|
47
|
-
const discovered = [];
|
|
48
|
-
const files = await findFiles(pattern, { cwd });
|
|
49
|
-
for (const filePath of files) {
|
|
50
|
-
try {
|
|
51
|
-
const code = await fs.readFile(filePath, "utf-8");
|
|
52
|
-
const classNames = findDurableObjectClasses(code);
|
|
53
|
-
for (const className of classNames) {
|
|
54
|
-
discovered.push({
|
|
55
|
-
filePath,
|
|
56
|
-
className,
|
|
57
|
-
bindingName: classToBindingName(className)
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
} catch {}
|
|
61
|
-
}
|
|
62
|
-
return discovered;
|
|
63
|
-
}
|
|
64
|
-
function stripDecoratorSyntax(code) {
|
|
65
|
-
let result = code;
|
|
66
|
-
result = result.replace(/@durableObject\s*\([^)]*\)\s*\n?\s*(?=export\s+class)/g, "");
|
|
67
|
-
result = result.replace(/import\s*\{([^}]*)\bdurableObject\b[^}]*\}\s*from\s*['"]devflare\/runtime['"]\s*;?/g, (match, imports) => {
|
|
68
|
-
const cleanedImports = imports.split(",").map((s) => s.trim()).filter((s) => !s.startsWith("durableObject")).join(", ");
|
|
69
|
-
if (cleanedImports.trim() === "") {
|
|
70
|
-
return "";
|
|
71
|
-
}
|
|
72
|
-
return `import { ${cleanedImports} } from 'devflare/runtime'`;
|
|
73
|
-
});
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
function toArray(value) {
|
|
77
|
-
return Array.isArray(value) ? value : [value];
|
|
78
|
-
}
|
|
79
|
-
function matchesExternalPattern(pattern, id) {
|
|
80
|
-
if (pattern instanceof RegExp) {
|
|
81
|
-
pattern.lastIndex = 0;
|
|
82
|
-
return pattern.test(id);
|
|
83
|
-
}
|
|
84
|
-
return pattern === id;
|
|
85
|
-
}
|
|
86
|
-
function matchesExternalOption(option, id, parentId, isResolved) {
|
|
87
|
-
if (!option) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
if (typeof option === "function") {
|
|
91
|
-
return option(id, parentId, isResolved) ?? false;
|
|
92
|
-
}
|
|
93
|
-
return toArray(option).some((pattern) => matchesExternalPattern(pattern, id));
|
|
94
|
-
}
|
|
95
|
-
function mergeExternalOptions(base, user) {
|
|
96
|
-
if (!base) {
|
|
97
|
-
return user;
|
|
98
|
-
}
|
|
99
|
-
if (!user) {
|
|
100
|
-
return base;
|
|
101
|
-
}
|
|
102
|
-
if (typeof base !== "function" && typeof user !== "function") {
|
|
103
|
-
return [...toArray(base), ...toArray(user)];
|
|
104
|
-
}
|
|
105
|
-
return (id, parentId, isResolved) => {
|
|
106
|
-
return matchesExternalOption(base, id, parentId, isResolved) || matchesExternalOption(user, id, parentId, isResolved) || false;
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
function mergePluginOptions(base, user) {
|
|
110
|
-
if (!base) {
|
|
111
|
-
return user;
|
|
112
|
-
}
|
|
113
|
-
if (!user) {
|
|
114
|
-
return base;
|
|
115
|
-
}
|
|
116
|
-
return [base, user];
|
|
117
|
-
}
|
|
118
|
-
function mergeResolveOptions(base, user) {
|
|
119
|
-
if (!base) {
|
|
120
|
-
return user;
|
|
121
|
-
}
|
|
122
|
-
if (!user) {
|
|
123
|
-
return base;
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
...user,
|
|
127
|
-
...base,
|
|
128
|
-
alias: {
|
|
129
|
-
...user.alias ?? {},
|
|
130
|
-
...base.alias ?? {}
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
function resolveDOBundleRolldownConfig(options) {
|
|
135
|
-
const {
|
|
136
|
-
output: userOutputOptions,
|
|
137
|
-
input: _ignoredInput,
|
|
138
|
-
cwd: _ignoredCwd,
|
|
139
|
-
platform: _ignoredPlatform,
|
|
140
|
-
watch: _ignoredWatch,
|
|
141
|
-
external: userExternal,
|
|
142
|
-
plugins: userPlugins,
|
|
143
|
-
resolve: userResolve,
|
|
144
|
-
tsconfig: userTsconfig,
|
|
145
|
-
...userInputOptions
|
|
146
|
-
} = options.rolldownOptions ?? {};
|
|
147
|
-
const {
|
|
148
|
-
codeSplitting: _ignoredCodeSplitting,
|
|
149
|
-
dir: _ignoredDir,
|
|
150
|
-
file: _ignoredFile,
|
|
151
|
-
format: _ignoredFormat,
|
|
152
|
-
inlineDynamicImports: _ignoredInlineDynamicImports,
|
|
153
|
-
...safeUserOutputOptions
|
|
154
|
-
} = userOutputOptions ?? {};
|
|
155
|
-
const defaultExternalModules = [
|
|
156
|
-
/^cloudflare:/,
|
|
157
|
-
/^node:/,
|
|
158
|
-
"buffer",
|
|
159
|
-
"crypto",
|
|
160
|
-
"events",
|
|
161
|
-
"http",
|
|
162
|
-
"https",
|
|
163
|
-
"net",
|
|
164
|
-
"os",
|
|
165
|
-
"path",
|
|
166
|
-
"stream",
|
|
167
|
-
"tls",
|
|
168
|
-
"url",
|
|
169
|
-
"util",
|
|
170
|
-
"zlib",
|
|
171
|
-
"fs",
|
|
172
|
-
"child_process",
|
|
173
|
-
"async_hooks",
|
|
174
|
-
"querystring",
|
|
175
|
-
"string_decoder",
|
|
176
|
-
"assert",
|
|
177
|
-
"dns"
|
|
178
|
-
];
|
|
179
|
-
return {
|
|
180
|
-
inputOptions: {
|
|
181
|
-
...userInputOptions,
|
|
182
|
-
input: options.inputFile,
|
|
183
|
-
cwd: options.cwd,
|
|
184
|
-
platform: "neutral",
|
|
185
|
-
tsconfig: userTsconfig ?? resolve(options.cwd, "tsconfig.json"),
|
|
186
|
-
external: mergeExternalOptions(defaultExternalModules, userExternal),
|
|
187
|
-
plugins: mergePluginOptions(undefined, userPlugins),
|
|
188
|
-
resolve: mergeResolveOptions({
|
|
189
|
-
alias: {
|
|
190
|
-
debug: options.debugShimPath
|
|
191
|
-
}
|
|
192
|
-
}, userResolve)
|
|
193
|
-
},
|
|
194
|
-
outputOptions: {
|
|
195
|
-
...safeUserOutputOptions,
|
|
196
|
-
file: options.outFile,
|
|
197
|
-
format: "esm",
|
|
198
|
-
sourcemap: safeUserOutputOptions.sourcemap ?? options.sourcemap ?? false,
|
|
199
|
-
minify: safeUserOutputOptions.minify ?? options.minify,
|
|
200
|
-
codeSplitting: false
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
async function bundleDOFile(sourcePath, className, outDir, cwd, bundleOptions) {
|
|
205
|
-
const { rolldown } = await import("rolldown");
|
|
206
|
-
const fs = await import("node:fs/promises");
|
|
207
|
-
await fs.mkdir(outDir, { recursive: true });
|
|
208
|
-
const sourceCode = await fs.readFile(sourcePath, "utf-8");
|
|
209
|
-
const transformedCode = (await transformDurableObject(sourceCode, sourcePath))?.code ?? stripDecoratorSyntax(sourceCode);
|
|
210
|
-
const entryCode = `${transformedCode}
|
|
40
|
+
import { dirname, resolve } from "pathe";
|
|
211
41
|
|
|
212
|
-
// Default export for worker (required by Miniflare)
|
|
213
|
-
export default {
|
|
214
|
-
async fetch(request) {
|
|
215
|
-
return new Response('DO Worker for ${className}', { status: 200 });
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
`;
|
|
219
|
-
const tempFilePath = resolve(dirname(sourcePath), `.devflare-temp-${className}.ts`);
|
|
220
|
-
await fs.writeFile(tempFilePath, entryCode, "utf-8");
|
|
221
|
-
const classOutDir = resolve(outDir, className);
|
|
222
|
-
try {
|
|
223
|
-
await fs.rm(classOutDir, { recursive: true, force: true });
|
|
224
|
-
} catch {}
|
|
225
|
-
await fs.mkdir(classOutDir, { recursive: true });
|
|
226
|
-
const debugShimCode = `
|
|
227
|
-
// Debug module shim for local development
|
|
228
|
-
const createDebug = (namespace) => {
|
|
229
|
-
const logger = (...args) => {
|
|
230
|
-
if (createDebug.enabled) console.debug(\`[\${namespace}]\`, ...args)
|
|
231
|
-
}
|
|
232
|
-
logger.enabled = false
|
|
233
|
-
logger.namespace = namespace
|
|
234
|
-
logger.extend = (sub) => createDebug(\`\${namespace}:\${sub}\`)
|
|
235
|
-
return logger
|
|
236
|
-
}
|
|
237
|
-
createDebug.enabled = false
|
|
238
|
-
createDebug.formatters = {}
|
|
239
|
-
export default createDebug
|
|
240
|
-
`;
|
|
241
|
-
const debugShimPath = resolve(outDir, "_debug_shim.js");
|
|
242
|
-
await fs.writeFile(debugShimPath, debugShimCode, "utf-8");
|
|
243
|
-
const outFile = resolve(classOutDir, "index.js");
|
|
244
|
-
const { inputOptions, outputOptions } = resolveDOBundleRolldownConfig({
|
|
245
|
-
cwd,
|
|
246
|
-
inputFile: tempFilePath,
|
|
247
|
-
outFile,
|
|
248
|
-
debugShimPath,
|
|
249
|
-
rolldownOptions: bundleOptions?.rolldownOptions,
|
|
250
|
-
sourcemap: bundleOptions?.sourcemap,
|
|
251
|
-
minify: bundleOptions?.minify
|
|
252
|
-
});
|
|
253
|
-
const bundle = await rolldown(inputOptions);
|
|
254
|
-
await bundle.write(outputOptions);
|
|
255
|
-
await bundle.close();
|
|
256
|
-
try {
|
|
257
|
-
await fs.unlink(tempFilePath);
|
|
258
|
-
} catch {}
|
|
259
|
-
return resolve(classOutDir, "index.js");
|
|
260
|
-
}
|
|
261
|
-
async function bundleAllDOs(discovered, outDir, cwd, logger, bundleOptions) {
|
|
262
|
-
const fs = await import("node:fs/promises");
|
|
263
|
-
const bundles = new Map;
|
|
264
|
-
const classes = new Map;
|
|
265
|
-
const sourceFiles = new Map;
|
|
266
|
-
const errors = [];
|
|
267
|
-
for (const do_ of discovered) {
|
|
268
|
-
const existing = sourceFiles.get(do_.filePath) || [];
|
|
269
|
-
existing.push(do_.className);
|
|
270
|
-
sourceFiles.set(do_.filePath, existing);
|
|
271
|
-
}
|
|
272
|
-
for (const do_ of discovered) {
|
|
273
|
-
try {
|
|
274
|
-
logger?.debug(`Bundling ${do_.className} from ${do_.filePath}`);
|
|
275
|
-
const outFile = await bundleDOFile(do_.filePath, do_.className, outDir, cwd, bundleOptions);
|
|
276
|
-
bundles.set(do_.bindingName, outFile);
|
|
277
|
-
classes.set(do_.bindingName, do_.className);
|
|
278
|
-
logger?.debug(` → ${outFile}`);
|
|
279
|
-
} catch (error) {
|
|
280
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
281
|
-
errors.push(err);
|
|
282
|
-
logger?.error(`Failed to bundle ${do_.className}:`, err.message);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return { bundles, classes, sourceFiles, errors };
|
|
286
|
-
}
|
|
287
|
-
function createDOBundler(options) {
|
|
288
|
-
const { cwd, pattern, outDir, logger, onRebuild, rolldownOptions, sourcemap, minify } = options;
|
|
289
|
-
let result = {
|
|
290
|
-
bundles: new Map,
|
|
291
|
-
classes: new Map,
|
|
292
|
-
sourceFiles: new Map,
|
|
293
|
-
errors: []
|
|
294
|
-
};
|
|
295
|
-
let watcher = null;
|
|
296
|
-
let chokidarWatcher = null;
|
|
297
|
-
async function build() {
|
|
298
|
-
const discovered = await discoverDOs(cwd, pattern);
|
|
299
|
-
if (discovered.length === 0) {
|
|
300
|
-
logger?.debug("No DOs found matching pattern:", pattern);
|
|
301
|
-
return result;
|
|
302
|
-
}
|
|
303
|
-
logger?.info(`Found ${discovered.length} Durable Object(s)`);
|
|
304
|
-
for (const do_ of discovered) {
|
|
305
|
-
logger?.info(` • ${do_.className} → ${do_.bindingName}`);
|
|
306
|
-
}
|
|
307
|
-
result = await bundleAllDOs(discovered, outDir, cwd, logger, {
|
|
308
|
-
rolldownOptions,
|
|
309
|
-
sourcemap,
|
|
310
|
-
minify
|
|
311
|
-
});
|
|
312
|
-
if (result.errors.length === 0) {
|
|
313
|
-
logger?.success(`Bundled ${result.bundles.size} DO(s) to ${outDir}`);
|
|
314
|
-
}
|
|
315
|
-
return result;
|
|
316
|
-
}
|
|
317
|
-
async function watch() {
|
|
318
|
-
const chokidar = await import("chokidar");
|
|
319
|
-
const files = await findFiles(pattern, { cwd });
|
|
320
|
-
let dirsToWatch;
|
|
321
|
-
if (files.length > 0) {
|
|
322
|
-
dirsToWatch = [...new Set(files.map((f) => dirname(f)))];
|
|
323
|
-
} else {
|
|
324
|
-
const patternDir = dirname(pattern);
|
|
325
|
-
const absolutePatternDir = resolve(cwd, patternDir === "." ? "" : patternDir) || cwd;
|
|
326
|
-
dirsToWatch = [absolutePatternDir];
|
|
327
|
-
logger?.debug(`No DO files yet, watching pattern directory: ${absolutePatternDir}`);
|
|
328
|
-
}
|
|
329
|
-
logger?.info(`Watching ${files.length} DO file(s) in ${dirsToWatch.length} director(ies)...`);
|
|
330
|
-
const isWindows = process.platform === "win32";
|
|
331
|
-
chokidarWatcher = chokidar.watch(dirsToWatch, {
|
|
332
|
-
ignoreInitial: true,
|
|
333
|
-
usePolling: isWindows,
|
|
334
|
-
interval: isWindows ? 300 : undefined,
|
|
335
|
-
awaitWriteFinish: {
|
|
336
|
-
stabilityThreshold: 100,
|
|
337
|
-
pollInterval: 50
|
|
338
|
-
},
|
|
339
|
-
depth: 0
|
|
340
|
-
});
|
|
341
|
-
const normalizePath = (p) => {
|
|
342
|
-
let normalized = p.replace(/\\/g, "/");
|
|
343
|
-
if (isWindows && /^[a-zA-Z]:/.test(normalized)) {
|
|
344
|
-
normalized = normalized[0].toLowerCase() + normalized.slice(1);
|
|
345
|
-
}
|
|
346
|
-
return normalized;
|
|
347
|
-
};
|
|
348
|
-
const isMatch = picomatch(pattern, {
|
|
349
|
-
cwd,
|
|
350
|
-
dot: true,
|
|
351
|
-
matchBase: false
|
|
352
|
-
});
|
|
353
|
-
const matchesPattern = (filePath) => {
|
|
354
|
-
const normalizedPath = normalizePath(filePath);
|
|
355
|
-
const relativePath = relative(normalizePath(cwd), normalizedPath);
|
|
356
|
-
return isMatch(relativePath);
|
|
357
|
-
};
|
|
358
|
-
let isRebuilding = false;
|
|
359
|
-
let pendingRebuild = null;
|
|
360
|
-
let rebuildTimeout = null;
|
|
361
|
-
const scheduleRebuild = (changedPath) => {
|
|
362
|
-
if (rebuildTimeout) {
|
|
363
|
-
clearTimeout(rebuildTimeout);
|
|
364
|
-
}
|
|
365
|
-
rebuildTimeout = setTimeout(() => {
|
|
366
|
-
triggerRebuild(changedPath);
|
|
367
|
-
}, 150);
|
|
368
|
-
};
|
|
369
|
-
const triggerRebuild = async (changedPath) => {
|
|
370
|
-
if (isRebuilding) {
|
|
371
|
-
pendingRebuild = changedPath;
|
|
372
|
-
logger?.debug(`Rebuild already in progress, queuing: ${changedPath}`);
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
isRebuilding = true;
|
|
376
|
-
try {
|
|
377
|
-
logger?.info(`DO file changed: ${changedPath}`);
|
|
378
|
-
logger?.info("Rebuilding DOs...");
|
|
379
|
-
const startTime = Date.now();
|
|
380
|
-
result = await build();
|
|
381
|
-
const elapsed = Date.now() - startTime;
|
|
382
|
-
logger?.success(`DO rebuild complete (${elapsed}ms)`);
|
|
383
|
-
await onRebuild?.(result);
|
|
384
|
-
} catch (error) {
|
|
385
|
-
logger?.error("DO rebuild failed:", error);
|
|
386
|
-
} finally {
|
|
387
|
-
isRebuilding = false;
|
|
388
|
-
if (pendingRebuild) {
|
|
389
|
-
const nextPath = pendingRebuild;
|
|
390
|
-
pendingRebuild = null;
|
|
391
|
-
triggerRebuild(nextPath);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
chokidarWatcher.on("change", (filePath) => {
|
|
396
|
-
if (matchesPattern(filePath)) {
|
|
397
|
-
logger?.debug(`File changed: ${filePath}`);
|
|
398
|
-
scheduleRebuild(filePath);
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
chokidarWatcher.on("add", (filePath) => {
|
|
402
|
-
if (matchesPattern(filePath)) {
|
|
403
|
-
logger?.debug(`File added: ${filePath}`);
|
|
404
|
-
scheduleRebuild(filePath);
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
chokidarWatcher.on("unlink", (filePath) => {
|
|
408
|
-
if (matchesPattern(filePath)) {
|
|
409
|
-
logger?.debug(`File removed: ${filePath}`);
|
|
410
|
-
scheduleRebuild(filePath);
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
chokidarWatcher.on("ready", () => {
|
|
414
|
-
logger?.info("DO file watcher ready");
|
|
415
|
-
});
|
|
416
|
-
chokidarWatcher.on("error", (error) => {
|
|
417
|
-
logger?.error("DO file watcher error:", error);
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
async function close() {
|
|
421
|
-
if (watcher) {
|
|
422
|
-
await watcher.close();
|
|
423
|
-
watcher = null;
|
|
424
|
-
}
|
|
425
|
-
if (chokidarWatcher) {
|
|
426
|
-
await chokidarWatcher.close();
|
|
427
|
-
chokidarWatcher = null;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
function getResult() {
|
|
431
|
-
return result;
|
|
432
|
-
}
|
|
433
|
-
return {
|
|
434
|
-
build,
|
|
435
|
-
watch,
|
|
436
|
-
close,
|
|
437
|
-
getResult
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
42
|
// src/browser-shim/server.ts
|
|
441
43
|
import { homedir } from "node:os";
|
|
442
44
|
import { join } from "node:path";
|
|
@@ -658,10 +260,10 @@ function createBrowserShim(options = {}) {
|
|
|
658
260
|
res.end("Not found");
|
|
659
261
|
}
|
|
660
262
|
function readBody(req) {
|
|
661
|
-
return new Promise((
|
|
263
|
+
return new Promise((resolve, reject) => {
|
|
662
264
|
const chunks = [];
|
|
663
265
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
664
|
-
req.on("end", () =>
|
|
266
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
665
267
|
req.on("error", reject);
|
|
666
268
|
});
|
|
667
269
|
}
|
|
@@ -802,10 +404,10 @@ function createBrowserShim(options = {}) {
|
|
|
802
404
|
});
|
|
803
405
|
});
|
|
804
406
|
}
|
|
805
|
-
await new Promise((
|
|
407
|
+
await new Promise((resolve, reject) => {
|
|
806
408
|
server.on("error", reject);
|
|
807
409
|
server.listen(port, host, () => {
|
|
808
|
-
|
|
410
|
+
resolve();
|
|
809
411
|
});
|
|
810
412
|
});
|
|
811
413
|
logger?.success(`Browser shim server ready on http://${host}:${port}`);
|
|
@@ -815,8 +417,8 @@ function createBrowserShim(options = {}) {
|
|
|
815
417
|
await closeSession(sessionId, 3, "ServerShutdown");
|
|
816
418
|
}
|
|
817
419
|
if (server) {
|
|
818
|
-
await new Promise((
|
|
819
|
-
server.close(() =>
|
|
420
|
+
await new Promise((resolve) => {
|
|
421
|
+
server.close(() => resolve());
|
|
820
422
|
});
|
|
821
423
|
server = null;
|
|
822
424
|
}
|
|
@@ -1298,6 +900,12 @@ var DEFAULT_EMAIL_ENTRY_FILES = [
|
|
|
1298
900
|
"src/email.mts",
|
|
1299
901
|
"src/email.mjs"
|
|
1300
902
|
];
|
|
903
|
+
var DEFAULT_TRANSPORT_ENTRY_FILES = [
|
|
904
|
+
"src/transport.ts",
|
|
905
|
+
"src/transport.js",
|
|
906
|
+
"src/transport.mts",
|
|
907
|
+
"src/transport.mjs"
|
|
908
|
+
];
|
|
1301
909
|
var INTERNAL_APP_SERVICE_BINDING = "__DEVFLARE_APP";
|
|
1302
910
|
function formatErrorMessage(error) {
|
|
1303
911
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -1315,7 +923,7 @@ async function resolveWorkerHandlerPath(cwd, configuredPath, defaultEntries) {
|
|
|
1315
923
|
candidates.add(defaultEntry);
|
|
1316
924
|
}
|
|
1317
925
|
for (const candidate of candidates) {
|
|
1318
|
-
const absolutePath =
|
|
926
|
+
const absolutePath = resolve(cwd, candidate);
|
|
1319
927
|
try {
|
|
1320
928
|
await fs.access(absolutePath);
|
|
1321
929
|
return absolutePath;
|
|
@@ -1337,35 +945,29 @@ function hasWorkerSurfacePaths(surfacePaths) {
|
|
|
1337
945
|
return Object.values(surfacePaths).some((surfacePath) => typeof surfacePath === "string" && surfacePath.length > 0);
|
|
1338
946
|
}
|
|
1339
947
|
function addWorkerWatchRoots(roots, cwd, configuredPath, defaultEntries) {
|
|
1340
|
-
if (configuredPath === false) {
|
|
948
|
+
if (configuredPath === false || configuredPath === null) {
|
|
1341
949
|
return;
|
|
1342
950
|
}
|
|
1343
951
|
if (typeof configuredPath === "string" && configuredPath) {
|
|
1344
|
-
roots.add(
|
|
952
|
+
roots.add(dirname(resolve(cwd, configuredPath)));
|
|
1345
953
|
return;
|
|
1346
954
|
}
|
|
1347
955
|
for (const defaultEntry of defaultEntries) {
|
|
1348
|
-
roots.add(
|
|
956
|
+
roots.add(dirname(resolve(cwd, defaultEntry)));
|
|
1349
957
|
}
|
|
1350
958
|
}
|
|
1351
959
|
function collectWorkerWatchRoots(cwd, config, mainWorkerSurfacePaths) {
|
|
1352
960
|
const roots = new Set;
|
|
1353
|
-
const addFileParent = (filePath) => {
|
|
1354
|
-
if (typeof filePath !== "string" || !filePath) {
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
roots.add(dirname2(resolve2(cwd, filePath)));
|
|
1358
|
-
};
|
|
1359
961
|
for (const surfacePath of Object.values(mainWorkerSurfacePaths)) {
|
|
1360
962
|
if (surfacePath) {
|
|
1361
|
-
roots.add(
|
|
963
|
+
roots.add(dirname(surfacePath));
|
|
1362
964
|
}
|
|
1363
965
|
}
|
|
1364
966
|
addWorkerWatchRoots(roots, cwd, config.files?.fetch, DEFAULT_FETCH_ENTRY_FILES);
|
|
1365
967
|
addWorkerWatchRoots(roots, cwd, config.files?.queue, DEFAULT_QUEUE_ENTRY_FILES);
|
|
1366
968
|
addWorkerWatchRoots(roots, cwd, config.files?.scheduled, DEFAULT_SCHEDULED_ENTRY_FILES);
|
|
1367
969
|
addWorkerWatchRoots(roots, cwd, config.files?.email, DEFAULT_EMAIL_ENTRY_FILES);
|
|
1368
|
-
|
|
970
|
+
addWorkerWatchRoots(roots, cwd, config.files?.transport, DEFAULT_TRANSPORT_ENTRY_FILES);
|
|
1369
971
|
const routeDirectory = getRouteDirectoryCandidate(cwd, config);
|
|
1370
972
|
if (routeDirectory) {
|
|
1371
973
|
roots.add(routeDirectory.absoluteDir);
|
|
@@ -1957,36 +1559,23 @@ function createDevServer(options) {
|
|
|
1957
1559
|
let bundledMainWorkerScriptPath = null;
|
|
1958
1560
|
let currentDoResult = null;
|
|
1959
1561
|
let mainWorkerRoutes = null;
|
|
1562
|
+
let generatedViteConfigPath = null;
|
|
1960
1563
|
let reloadChain = Promise.resolve();
|
|
1961
1564
|
async function bundleMainWorker() {
|
|
1962
|
-
if (!mainWorkerScriptPath) {
|
|
1565
|
+
if (!mainWorkerScriptPath || !config) {
|
|
1963
1566
|
bundledMainWorkerScriptPath = null;
|
|
1964
1567
|
return;
|
|
1965
1568
|
}
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
outdir: outDir,
|
|
1976
|
-
target: "browser",
|
|
1977
|
-
conditions: ["browser"],
|
|
1978
|
-
format: "esm",
|
|
1979
|
-
minify: false,
|
|
1980
|
-
splitting: false,
|
|
1981
|
-
external: ["cloudflare:workers", "cloudflare:*", "node:*"]
|
|
1569
|
+
bundledMainWorkerScriptPath = await bundleWorkerEntry({
|
|
1570
|
+
cwd,
|
|
1571
|
+
inputFile: mainWorkerScriptPath,
|
|
1572
|
+
outFile: resolve(cwd, ".devflare", "worker-entrypoints", "main.js"),
|
|
1573
|
+
rolldownOptions: config.rolldown?.options,
|
|
1574
|
+
sourcemap: config.rolldown?.sourcemap,
|
|
1575
|
+
minify: config.rolldown?.minify,
|
|
1576
|
+
target: config.rolldown?.target,
|
|
1577
|
+
logger
|
|
1982
1578
|
});
|
|
1983
|
-
if (!result.success || result.outputs.length === 0) {
|
|
1984
|
-
const logs = result.logs.map((log) => ("message" in log) ? log.message : String(log)).join(`
|
|
1985
|
-
`);
|
|
1986
|
-
throw new Error(`Failed to bundle main worker:
|
|
1987
|
-
${logs}`);
|
|
1988
|
-
}
|
|
1989
|
-
bundledMainWorkerScriptPath = result.outputs[0].path;
|
|
1990
1579
|
logger?.debug(`Bundled main worker → ${bundledMainWorkerScriptPath}`);
|
|
1991
1580
|
}
|
|
1992
1581
|
function buildMiniflareConfig(doResult) {
|
|
@@ -1994,7 +1583,7 @@ ${logs}`);
|
|
|
1994
1583
|
throw new Error("Config not loaded");
|
|
1995
1584
|
const loadedConfig = config;
|
|
1996
1585
|
const bindings = loadedConfig.bindings ?? {};
|
|
1997
|
-
const persistPath =
|
|
1586
|
+
const persistPath = resolve(cwd, ".devflare/data");
|
|
1998
1587
|
const appWorkerName = loadedConfig.name;
|
|
1999
1588
|
const shouldRunMainWorker = !enableVite && (hasWorkerSurfacePaths(mainWorkerSurfacePaths) || Boolean(mainWorkerRoutes?.routes.length));
|
|
2000
1589
|
const queueProducers = (() => {
|
|
@@ -2253,7 +1842,7 @@ ${logs}`);
|
|
|
2253
1842
|
}
|
|
2254
1843
|
async function resolveWorkerConfigWatchPath() {
|
|
2255
1844
|
if (configPath) {
|
|
2256
|
-
const explicitPath =
|
|
1845
|
+
const explicitPath = resolve(cwd, configPath);
|
|
2257
1846
|
const fs = await import("node:fs/promises");
|
|
2258
1847
|
try {
|
|
2259
1848
|
await fs.access(explicitPath);
|
|
@@ -2271,7 +1860,7 @@ ${logs}`);
|
|
|
2271
1860
|
const composedMainEntry = await prepareComposedWorkerEntrypoint(cwd, config, undefined, {
|
|
2272
1861
|
devInternalEmail: true
|
|
2273
1862
|
});
|
|
2274
|
-
mainWorkerScriptPath = composedMainEntry ?
|
|
1863
|
+
mainWorkerScriptPath = composedMainEntry ? resolve(cwd, composedMainEntry) : null;
|
|
2275
1864
|
if (mainWorkerScriptPath) {
|
|
2276
1865
|
await bundleMainWorker();
|
|
2277
1866
|
} else {
|
|
@@ -2407,7 +1996,7 @@ ${logs}`);
|
|
|
2407
1996
|
if (!miniflare || !config?.bindings?.d1)
|
|
2408
1997
|
return;
|
|
2409
1998
|
const { existsSync: existsSync2, readdirSync, readFileSync } = await import("node:fs");
|
|
2410
|
-
const migrationsDir =
|
|
1999
|
+
const migrationsDir = resolve(cwd, "migrations");
|
|
2411
2000
|
if (!existsSync2(migrationsDir)) {
|
|
2412
2001
|
logger?.debug("No migrations/ directory found, skipping D1 migrations");
|
|
2413
2002
|
return;
|
|
@@ -2420,7 +2009,7 @@ ${logs}`);
|
|
|
2420
2009
|
logger?.info(`Running ${files.length} D1 migration(s)...`);
|
|
2421
2010
|
const allStatements = [];
|
|
2422
2011
|
for (const file of files) {
|
|
2423
|
-
const sql = readFileSync(
|
|
2012
|
+
const sql = readFileSync(resolve(migrationsDir, file), "utf-8");
|
|
2424
2013
|
const cleanedSql = sql.split(`
|
|
2425
2014
|
`).filter((line) => !line.trim().startsWith("--")).join(`
|
|
2426
2015
|
`);
|
|
@@ -2459,6 +2048,9 @@ ${logs}`);
|
|
|
2459
2048
|
async function startVite() {
|
|
2460
2049
|
const { spawn } = await import("node:child_process");
|
|
2461
2050
|
const args = ["vite", "dev", "--port", String(vitePort)];
|
|
2051
|
+
if (generatedViteConfigPath) {
|
|
2052
|
+
args.push("--config", generatedViteConfigPath);
|
|
2053
|
+
}
|
|
2462
2054
|
viteProcess = spawn("bunx", args, {
|
|
2463
2055
|
cwd,
|
|
2464
2056
|
stdio: ["inherit", "pipe", "pipe"],
|
|
@@ -2490,6 +2082,16 @@ ${logs}`);
|
|
|
2490
2082
|
setLocalSendEmailBindings(config.bindings?.sendEmail ?? {});
|
|
2491
2083
|
resolvedWorkerConfigPath = await resolveWorkerConfigWatchPath();
|
|
2492
2084
|
logger?.debug("Loaded config:", config.name);
|
|
2085
|
+
if (enableVite) {
|
|
2086
|
+
const viteProject = await detectViteProject(cwd);
|
|
2087
|
+
generatedViteConfigPath = await writeGeneratedViteConfig({
|
|
2088
|
+
cwd,
|
|
2089
|
+
configPath,
|
|
2090
|
+
localConfigPath: viteProject.viteConfigPath,
|
|
2091
|
+
bridgePort: miniflarePort
|
|
2092
|
+
});
|
|
2093
|
+
logger?.debug(`Generated Vite config → ${generatedViteConfigPath}`);
|
|
2094
|
+
}
|
|
2493
2095
|
await refreshWorkerOnlySurfaceState();
|
|
2494
2096
|
if (!enableVite && (hasWorkerSurfacePaths(mainWorkerSurfacePaths) || Boolean(mainWorkerRoutes?.routes.length))) {
|
|
2495
2097
|
const detectedWorkerHandlers = Object.entries(mainWorkerSurfacePaths).filter(([, surfacePath]) => !!surfacePath).map(([surfaceName, surfacePath]) => `${surfaceName}=${surfacePath}`);
|
|
@@ -2537,7 +2139,7 @@ ${logs}`);
|
|
|
2537
2139
|
const doPattern = config.files?.durableObjects;
|
|
2538
2140
|
let doResult = null;
|
|
2539
2141
|
if (typeof doPattern === "string" && doPattern) {
|
|
2540
|
-
const outDir =
|
|
2142
|
+
const outDir = resolve(cwd, ".devflare/do-bundles");
|
|
2541
2143
|
doBundler = createDOBundler({
|
|
2542
2144
|
cwd,
|
|
2543
2145
|
pattern: doPattern,
|
|
@@ -2560,7 +2162,7 @@ ${logs}`);
|
|
|
2560
2162
|
if (enableVite) {
|
|
2561
2163
|
await startVite();
|
|
2562
2164
|
} else {
|
|
2563
|
-
logger?.info("Vite startup skipped (no
|
|
2165
|
+
logger?.info("Vite startup skipped (no effective Vite config found for this package)");
|
|
2564
2166
|
}
|
|
2565
2167
|
await new Promise((r) => setTimeout(r, 1000));
|
|
2566
2168
|
await runD1Migrations();
|
|
@@ -2605,11 +2207,11 @@ async function createLogWriter(cwd, options) {
|
|
|
2605
2207
|
const fs = await import("node:fs");
|
|
2606
2208
|
let logPath;
|
|
2607
2209
|
if (options.logTemp) {
|
|
2608
|
-
logPath =
|
|
2210
|
+
logPath = resolve2(cwd, ".log");
|
|
2609
2211
|
} else {
|
|
2610
2212
|
const now = new Date;
|
|
2611
2213
|
const timestamp = now.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
2612
|
-
logPath =
|
|
2214
|
+
logPath = resolve2(cwd, `.log-${timestamp}`);
|
|
2613
2215
|
}
|
|
2614
2216
|
const fileStream = fs.createWriteStream(logPath, { flags: "w" });
|
|
2615
2217
|
const ansiRegex = /\x1b\[[0-9;]*m/g;
|
|
@@ -2640,13 +2242,14 @@ async function runDevCommand(parsed, logger, options) {
|
|
|
2640
2242
|
const persistEnabled = parsed.options.persist === true;
|
|
2641
2243
|
const debugEnabled = parsed.options.debug === true || process.env.DEVFLARE_DEBUG === "true";
|
|
2642
2244
|
const verbose = parsed.options.verbose === true || debugEnabled;
|
|
2643
|
-
const
|
|
2245
|
+
const config = await loadConfig({ cwd, configFile: configPath });
|
|
2246
|
+
const viteProject = resolveEffectiveViteProject(await detectViteProject(cwd), config);
|
|
2644
2247
|
const logWriter = await createLogWriter(cwd, {
|
|
2645
2248
|
log: logEnabled,
|
|
2646
2249
|
logTemp: logTempEnabled
|
|
2647
2250
|
});
|
|
2648
2251
|
if (logWriter) {
|
|
2649
|
-
const logFile =
|
|
2252
|
+
const logFile = relative(cwd, logWriter.path) || ".log";
|
|
2650
2253
|
logger.info(`\uD83D\uDCDD Logging enabled → ${logFile}`);
|
|
2651
2254
|
}
|
|
2652
2255
|
const devLogger = createConsola({
|
|
@@ -2673,15 +2276,15 @@ async function runDevCommand(parsed, logger, options) {
|
|
|
2673
2276
|
logger.info("\uD83D\uDE80 Devflare Unified Dev Server");
|
|
2674
2277
|
logger.info(" ├─ Vite: Full HMR for frontend");
|
|
2675
2278
|
logger.info(" ├─ Miniflare: All Cloudflare bindings");
|
|
2676
|
-
logger.info(" ├─ Rolldown:
|
|
2279
|
+
logger.info(" ├─ Rolldown: Worker + DO bundling with watch");
|
|
2677
2280
|
logger.info(" └─ Bridge: WebSocket RPC connection");
|
|
2678
2281
|
} else {
|
|
2679
2282
|
logger.info("\uD83D\uDE80 Devflare Worker Dev Server");
|
|
2680
2283
|
logger.info(" ├─ Miniflare: All Cloudflare bindings");
|
|
2681
|
-
logger.info(" ├─ Rolldown:
|
|
2682
|
-
logger.info(" └─ Vite: Disabled (no
|
|
2284
|
+
logger.info(" ├─ Rolldown: Worker + DO bundling with watch");
|
|
2285
|
+
logger.info(" └─ Vite: Disabled (no effective Vite config found)");
|
|
2683
2286
|
if (viteProject.wantsViteIntegration) {
|
|
2684
|
-
logger.warn("Vite-related
|
|
2287
|
+
logger.warn("Vite-related settings were detected, but no effective Vite config was available");
|
|
2685
2288
|
logger.warn("Skipping Vite startup and running in worker-only mode");
|
|
2686
2289
|
}
|
|
2687
2290
|
}
|