devflare 1.0.0-next.20 → 1.0.0-next.21

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 (58) hide show
  1. package/LLM.md +9 -4
  2. package/README.md +10 -2
  3. package/dist/browser.js +3 -3
  4. package/dist/build-b1z6wqet.js +54 -0
  5. package/dist/build-x7maz3eb.js +54 -0
  6. package/dist/cli/commands/config.d.ts.map +1 -1
  7. package/dist/cli/commands/dev.d.ts +1 -0
  8. package/dist/cli/commands/dev.d.ts.map +1 -1
  9. package/dist/cli/commands/doctor.d.ts.map +1 -1
  10. package/dist/cli/help-pages/pages/core.d.ts.map +1 -1
  11. package/dist/cli/index.js +1 -1
  12. package/dist/config-qj5jw8km.js +93 -0
  13. package/dist/deploy-jf3yczsz.js +1055 -0
  14. package/dist/deploy-xqm869nf.js +1055 -0
  15. package/dist/dev-bgpxrwms.js +2551 -0
  16. package/dist/dev-kzs65xcr.js +2551 -0
  17. package/dist/dev-server/dev-server-state.d.ts +2 -0
  18. package/dist/dev-server/dev-server-state.d.ts.map +1 -1
  19. package/dist/dev-server/miniflare-dev-config.d.ts +4 -0
  20. package/dist/dev-server/miniflare-dev-config.d.ts.map +1 -1
  21. package/dist/dev-server/server.d.ts.map +1 -1
  22. package/dist/dev-zgx7fhe9.js +2553 -0
  23. package/dist/doctor-0a2brpyz.js +259 -0
  24. package/dist/index-05pbj4hy.js +1193 -0
  25. package/dist/index-3edvz3hs.js +124 -0
  26. package/dist/index-50em8s6c.js +898 -0
  27. package/dist/index-666tdx14.js +895 -0
  28. package/dist/index-8p7rxkbs.js +1426 -0
  29. package/dist/index-aqrwyy57.js +288 -0
  30. package/dist/index-bj5avaba.js +109 -0
  31. package/dist/index-dgww0ewn.js +574 -0
  32. package/dist/index-f1yshy4s.js +412 -0
  33. package/dist/index-hpwa6vsw.js +239 -0
  34. package/dist/index-kxc4gtyt.js +574 -0
  35. package/dist/index-nxkesg55.js +68 -0
  36. package/dist/index-p7q23nce.js +1031 -0
  37. package/dist/index-pt49cgjv.js +1426 -0
  38. package/dist/index-rp0aye39.js +1426 -0
  39. package/dist/index-tknbyxzn.js +2202 -0
  40. package/dist/index.js +4 -4
  41. package/dist/runtime/index.js +4 -4
  42. package/dist/sveltekit/index.js +2 -2
  43. package/dist/test/index.js +62 -440
  44. package/dist/test/resolve-service-bindings.d.ts +63 -3
  45. package/dist/test/resolve-service-bindings.d.ts.map +1 -1
  46. package/dist/types-vhvt4hvm.js +693 -0
  47. package/dist/utils/send-email.d.ts.map +1 -1
  48. package/dist/utils/send-email.js +1 -1
  49. package/dist/vite/index.js +4 -3
  50. package/dist/vite/plugin-context.d.ts +3 -1
  51. package/dist/vite/plugin-context.d.ts.map +1 -1
  52. package/dist/vite/plugin-programmatic.d.ts.map +1 -1
  53. package/dist/vite/plugin-service-bindings.d.ts +13 -0
  54. package/dist/vite/plugin-service-bindings.d.ts.map +1 -0
  55. package/dist/vite/plugin.d.ts +4 -2
  56. package/dist/vite/plugin.d.ts.map +1 -1
  57. package/dist/worker-entrypoint-3rmzd4c1.js +15 -0
  58. package/package.json +1 -1
@@ -0,0 +1,1193 @@
1
+ import {
2
+ discoverDurableObjectFiles,
3
+ discoverDurableObjects,
4
+ discoverRoutes,
5
+ resolveServiceBindings
6
+ } from "./index-p7q23nce.js";
7
+ import {
8
+ DEFAULT_DO_PATTERN
9
+ } from "./index-qwgr4q7s.js";
10
+ import {
11
+ SUPPORTED_WORKER_EXTENSIONS
12
+ } from "./index-aqrwyy57.js";
13
+ import {
14
+ compileBuildConfig,
15
+ compileConfig,
16
+ compileToProgrammaticConfig,
17
+ isolateViteBuildOutputPaths,
18
+ rebaseWranglerConfigPaths,
19
+ writeWranglerConfig
20
+ } from "./index-c3nxftnp.js";
21
+ import {
22
+ loadConfig,
23
+ loadResolvedConfig,
24
+ normalizeDOBinding,
25
+ resolveConfigForEnvironment,
26
+ resolveConfigPath,
27
+ resolveResources
28
+ } from "./index-syscwrjp.js";
29
+ import {
30
+ __require
31
+ } from "./index-37x76zdn.js";
32
+
33
+ // src/vite/plugin.ts
34
+ import { dirname as dirname2, resolve as resolve4 } from "pathe";
35
+
36
+ // src/vite/plugin-durable-objects.ts
37
+ var VIRTUAL_DO_ENTRY = "virtual:devflare-do-entry";
38
+ var RESOLVED_VIRTUAL_DO_ENTRY = "\x00" + VIRTUAL_DO_ENTRY;
39
+ function generateVirtualDOEntry(discovery) {
40
+ const lines = [
41
+ "// Auto-generated by devflare — DO entry module",
42
+ "// Re-exports all Durable Object classes discovered from files.durableObjects pattern",
43
+ ""
44
+ ];
45
+ for (const [filePath, classNames] of discovery.files) {
46
+ const normalizedPath = filePath.replace(/\\/g, "/");
47
+ lines.push(`export { ${classNames.join(", ")} } from '${normalizedPath}'`);
48
+ }
49
+ lines.push("");
50
+ lines.push("// Default fetch handler for DO worker");
51
+ lines.push("export default {");
52
+ lines.push("\tasync fetch(request: Request): Promise<Response> {");
53
+ lines.push('\t\treturn new Response("Devflare DO Worker", { status: 200 })');
54
+ lines.push("\t}");
55
+ lines.push("}");
56
+ return lines.join(`
57
+ `);
58
+ }
59
+ function createAuxiliaryWorkerConfig(wranglerConfig, discovery) {
60
+ const doBindings = wranglerConfig.durable_objects?.bindings?.map((binding) => ({
61
+ name: binding.name,
62
+ class_name: binding.class_name
63
+ })) ?? [];
64
+ return {
65
+ config: {
66
+ name: discovery.workerName,
67
+ main: VIRTUAL_DO_ENTRY,
68
+ compatibility_date: wranglerConfig.compatibility_date,
69
+ compatibility_flags: wranglerConfig.compatibility_flags,
70
+ durable_objects: { bindings: doBindings },
71
+ migrations: wranglerConfig.migrations,
72
+ kv_namespaces: wranglerConfig.kv_namespaces,
73
+ d1_databases: wranglerConfig.d1_databases,
74
+ r2_buckets: wranglerConfig.r2_buckets,
75
+ browser: wranglerConfig.browser
76
+ }
77
+ };
78
+ }
79
+ function logDiscoveredDurableObjects(projectRoot, discovery) {
80
+ if (!discovery || discovery.files.size === 0) {
81
+ return;
82
+ }
83
+ console.log(`[devflare] Discovered ${discovery.files.size} DO file(s):`);
84
+ for (const [filePath, classes] of discovery.files) {
85
+ console.log(` • ${filePath.replace(projectRoot, ".")} → ${classes.join(", ")}`);
86
+ }
87
+ }
88
+
89
+ // src/vite/plugin-service-bindings.ts
90
+ var VIRTUAL_SERVICE_WORKER_PREFIX = "virtual:devflare-service-worker/";
91
+ var RESOLVED_VIRTUAL_SERVICE_WORKER_PREFIX = "\x00" + VIRTUAL_SERVICE_WORKER_PREFIX;
92
+ function virtualServiceWorkerId(workerName) {
93
+ return `${VIRTUAL_SERVICE_WORKER_PREFIX}${encodeURIComponent(workerName)}`;
94
+ }
95
+ function resolvedVirtualServiceWorkerId(workerName) {
96
+ return `${RESOLVED_VIRTUAL_SERVICE_WORKER_PREFIX}${encodeURIComponent(workerName)}`;
97
+ }
98
+ function objectEntries(record) {
99
+ return record ? Object.entries(record) : [];
100
+ }
101
+ function toWranglerDurableObjectBinding(name, value) {
102
+ if (typeof value === "string") {
103
+ return { name, class_name: value };
104
+ }
105
+ return {
106
+ name,
107
+ class_name: value.className,
108
+ script_name: value.scriptName
109
+ };
110
+ }
111
+ function toWranglerWorkerConfig(worker) {
112
+ const queueProducers = worker.queueProducers ? objectEntries(worker.queueProducers).map(([binding, producer]) => ({
113
+ binding,
114
+ queue: producer.queueName
115
+ })) : undefined;
116
+ const queueConsumers = worker.queueConsumers ? objectEntries(worker.queueConsumers).map(([queue, consumer]) => ({
117
+ queue,
118
+ ...consumer.maxBatchSize !== undefined && { max_batch_size: consumer.maxBatchSize },
119
+ ...consumer.maxBatchTimeout !== undefined && { max_batch_timeout: consumer.maxBatchTimeout },
120
+ ...consumer.maxRetries !== undefined && { max_retries: consumer.maxRetries },
121
+ ...typeof consumer.deadLetterQueue === "string" && { dead_letter_queue: consumer.deadLetterQueue },
122
+ ...consumer.maxConcurrency !== undefined && { max_concurrency: consumer.maxConcurrency },
123
+ ...consumer.retryDelay !== undefined && { retry_delay: consumer.retryDelay }
124
+ })) : undefined;
125
+ const queues = queueProducers || queueConsumers ? {
126
+ ...queueProducers && { producers: queueProducers },
127
+ ...queueConsumers && { consumers: queueConsumers }
128
+ } : undefined;
129
+ const durableObjectBindings = worker.durableObjects ? objectEntries(worker.durableObjects).map(([name, value]) => toWranglerDurableObjectBinding(name, value)) : [];
130
+ const serviceBindings = worker.serviceBindings ? objectEntries(worker.serviceBindings).map(([binding, target]) => ({
131
+ binding,
132
+ service: target.name,
133
+ ...target.entrypoint && { entrypoint: target.entrypoint }
134
+ })) : [];
135
+ const config = {
136
+ name: worker.name,
137
+ main: virtualServiceWorkerId(worker.name),
138
+ compatibility_date: worker.compatibilityDate,
139
+ ...worker.compatibilityFlags && { compatibility_flags: worker.compatibilityFlags },
140
+ ...worker.bindings && { vars: worker.bindings },
141
+ ...worker.kvNamespaces && {
142
+ kv_namespaces: objectEntries(worker.kvNamespaces).map(([binding, id]) => ({
143
+ binding,
144
+ id
145
+ }))
146
+ },
147
+ ...worker.r2Buckets && {
148
+ r2_buckets: objectEntries(worker.r2Buckets).map(([binding, bucket_name]) => ({
149
+ binding,
150
+ bucket_name
151
+ }))
152
+ },
153
+ ...worker.d1Databases && {
154
+ d1_databases: objectEntries(worker.d1Databases).map(([binding, database_id]) => ({
155
+ binding,
156
+ database_id,
157
+ database_name: database_id
158
+ }))
159
+ },
160
+ ...durableObjectBindings.length > 0 && {
161
+ durable_objects: {
162
+ bindings: durableObjectBindings
163
+ }
164
+ },
165
+ ...serviceBindings.length > 0 && {
166
+ services: serviceBindings
167
+ },
168
+ ...queues && { queues }
169
+ };
170
+ return config;
171
+ }
172
+ function createAuxiliaryServiceWorkerConfigs(resolution) {
173
+ if (!resolution || resolution.workers.length === 0) {
174
+ return { auxiliaryWorkers: [], virtualModules: new Map };
175
+ }
176
+ const virtualModules = new Map;
177
+ const auxiliaryWorkers = resolution.workers.map((worker) => {
178
+ virtualModules.set(resolvedVirtualServiceWorkerId(worker.name), worker.script);
179
+ return {
180
+ config: toWranglerWorkerConfig(worker)
181
+ };
182
+ });
183
+ return { auxiliaryWorkers, virtualModules };
184
+ }
185
+
186
+ // src/vite/plugin-context.ts
187
+ import { isAbsolute, relative as relative2, resolve as resolve3 } from "pathe";
188
+
189
+ // src/worker-entry/composed-worker.ts
190
+ import { dirname, relative, resolve as resolve2 } from "pathe";
191
+
192
+ // src/worker-entry/surface-paths.ts
193
+ import { resolve } from "pathe";
194
+ var defaultEntriesFor = (surface) => SUPPORTED_WORKER_EXTENSIONS.map((ext) => `src/${surface}${ext}`);
195
+ var DEFAULT_FETCH_ENTRY_FILES = defaultEntriesFor("fetch");
196
+ var DEFAULT_QUEUE_ENTRY_FILES = defaultEntriesFor("queue");
197
+ var DEFAULT_SCHEDULED_ENTRY_FILES = defaultEntriesFor("scheduled");
198
+ var DEFAULT_EMAIL_ENTRY_FILES = defaultEntriesFor("email");
199
+ var DEFAULT_TAIL_ENTRY_FILES = defaultEntriesFor("tail");
200
+ var BUILD_OUTPUT_PATH_PREFIXES = [
201
+ ".svelte-kit/",
202
+ ".adapter-cloudflare/",
203
+ ".next/",
204
+ ".nuxt/",
205
+ ".output/",
206
+ ".vercel/",
207
+ "dist/",
208
+ "build/",
209
+ ".vinxi/",
210
+ ".solid/"
211
+ ];
212
+ function looksLikeBuildArtifactPath(configuredPath) {
213
+ const normalised = configuredPath.replace(/\\/g, "/").replace(/^\.\//, "");
214
+ return BUILD_OUTPUT_PATH_PREFIXES.some((prefix) => normalised.startsWith(prefix));
215
+ }
216
+ async function resolveWorkerHandlerPath(cwd, configuredPath, defaultEntries, surfaceName = "worker") {
217
+ if (configuredPath === false) {
218
+ return null;
219
+ }
220
+ const fs = await import("node:fs/promises");
221
+ if (typeof configuredPath === "string" && configuredPath) {
222
+ const absolutePath = resolve(cwd, configuredPath);
223
+ try {
224
+ await fs.access(absolutePath);
225
+ return absolutePath;
226
+ } catch {
227
+ if (looksLikeBuildArtifactPath(configuredPath)) {
228
+ throw new Error(`Configured ${surfaceName} handler "${configuredPath}" was not found.
229
+
230
+ This path looks like a framework build output (e.g. SvelteKit / Vite / Next).
231
+ Devflare resolves handler paths BEFORE your framework runs its build, so the file
232
+ does not exist yet at this stage.
233
+
234
+ ` + `Recommended fix — point devflare at the build artifact via wrangler passthrough
235
+ ` + `instead of files.${surfaceName}, so devflare skips composition and lets your
236
+ framework write the worker entry that wrangler/vite then picks up:
237
+
238
+ files: { ${surfaceName}: false },
239
+ wrangler: {
240
+ passthrough: { main: '${configuredPath}' }
241
+ }
242
+
243
+ Alternatively, run your framework build (e.g. \`vite build\`) before \`devflare build\`,
244
+ or move the handler to a source file that exists at config time.`);
245
+ }
246
+ throw new Error(`Configured ${surfaceName} handler "${configuredPath}" was not found`);
247
+ }
248
+ }
249
+ for (const defaultEntry of defaultEntries) {
250
+ const absolutePath = resolve(cwd, defaultEntry);
251
+ try {
252
+ await fs.access(absolutePath);
253
+ return absolutePath;
254
+ } catch {
255
+ continue;
256
+ }
257
+ }
258
+ return null;
259
+ }
260
+ async function resolveWorkerSurfacePaths(cwd, config) {
261
+ return {
262
+ fetch: await resolveWorkerHandlerPath(cwd, config.files?.fetch, DEFAULT_FETCH_ENTRY_FILES, "fetch"),
263
+ queue: await resolveWorkerHandlerPath(cwd, config.files?.queue, DEFAULT_QUEUE_ENTRY_FILES, "queue"),
264
+ scheduled: await resolveWorkerHandlerPath(cwd, config.files?.scheduled, DEFAULT_SCHEDULED_ENTRY_FILES, "scheduled"),
265
+ email: await resolveWorkerHandlerPath(cwd, config.files?.email, DEFAULT_EMAIL_ENTRY_FILES, "email"),
266
+ tail: await resolveWorkerHandlerPath(cwd, config.files?.tail, DEFAULT_TAIL_ENTRY_FILES, "tail")
267
+ };
268
+ }
269
+ function hasWorkerSurfacePaths(surfacePaths) {
270
+ return Object.values(surfacePaths).some((surfacePath) => typeof surfacePath === "string" && surfacePath.length > 0);
271
+ }
272
+
273
+ // src/worker-entry/composed-worker.ts
274
+ class CodeBuilder {
275
+ sections = [];
276
+ importStatement(specifiers, from) {
277
+ this.sections.push(`import { ${specifiers.join(", ")} } from '${from}'`);
278
+ return this;
279
+ }
280
+ importNamespace(identifier, from) {
281
+ this.sections.push(`import * as ${identifier} from '${from}'`);
282
+ return this;
283
+ }
284
+ reExport(names, from) {
285
+ this.sections.push(`export { ${names.join(", ")} } from '${from}'`);
286
+ return this;
287
+ }
288
+ constDeclaration(name, value) {
289
+ this.sections.push(`const ${name} = ${value}`);
290
+ return this;
291
+ }
292
+ classDeclaration(body) {
293
+ this.sections.push(body);
294
+ return this;
295
+ }
296
+ exportDefault(body) {
297
+ this.sections.push(`export default ${body}`);
298
+ return this;
299
+ }
300
+ raw(text) {
301
+ this.sections.push(text);
302
+ return this;
303
+ }
304
+ blank() {
305
+ this.sections.push("");
306
+ return this;
307
+ }
308
+ toString() {
309
+ return this.sections.join(`
310
+ `);
311
+ }
312
+ }
313
+ var DEV_ONLY_EMAIL_HOOKS_SOURCE = `
314
+ function __devflareCreateEmailHeaders(rawBody) {
315
+ const headers = new Headers()
316
+ const lines = rawBody.split(/\\r?\\n/)
317
+
318
+ for (const line of lines) {
319
+ if (line.trim() === '') {
320
+ break
321
+ }
322
+
323
+ const colonIndex = line.indexOf(':')
324
+ if (colonIndex <= 0) {
325
+ continue
326
+ }
327
+
328
+ headers.append(line.slice(0, colonIndex).trim(), line.slice(colonIndex + 1).trim())
329
+ }
330
+
331
+ return headers
332
+ }
333
+
334
+ function __devflareCreateEmailRawStream(rawBody) {
335
+ return new ReadableStream({
336
+ start(controller) {
337
+ controller.enqueue(new TextEncoder().encode(rawBody))
338
+ controller.close()
339
+ }
340
+ })
341
+ }
342
+
343
+ async function __devflareHandleInternalEmail(request, env, ctx) {
344
+ if (!__devflareEmailHandler) {
345
+ return new Response('Email handler not configured', { status: 501 })
346
+ }
347
+
348
+ const from = request.headers.get('x-devflare-email-from') || 'unknown@example.com'
349
+ const to = request.headers.get('x-devflare-email-to') || 'worker@example.com'
350
+ const rawBody = await request.text()
351
+ const emailMessage = {
352
+ from,
353
+ to,
354
+ headers: __devflareCreateEmailHeaders(rawBody),
355
+ raw: __devflareCreateEmailRawStream(rawBody),
356
+ rawSize: rawBody.length,
357
+ setReject(reason) {
358
+ console.warn('[Devflare email rejected]', reason)
359
+ },
360
+ async forward(rcptTo) {
361
+ console.log('[Devflare email forwarded]', rcptTo)
362
+ return Promise.resolve()
363
+ },
364
+ async reply(message) {
365
+ console.log('[Devflare email reply sent]', message?.from)
366
+ return Promise.resolve()
367
+ }
368
+ }
369
+
370
+ const __devflareEvent = createEmailEvent(emailMessage, env, ctx)
371
+
372
+ await runWithEventContext(
373
+ __devflareEvent,
374
+ () => __devflareEmailHandler(__devflareEvent, env, ctx)
375
+ )
376
+
377
+ return new Response(JSON.stringify({ ok: true, from, to }), {
378
+ headers: { 'Content-Type': 'application/json' }
379
+ })
380
+ }
381
+ `;
382
+ function emitDevOnlyEmailHooks(builder, options) {
383
+ if (!options.enabled) {
384
+ return;
385
+ }
386
+ builder.raw(DEV_ONLY_EMAIL_HOOKS_SOURCE);
387
+ }
388
+ var RESOLVE_HANDLER_DECLARATION = `const __devflareResolveHandler = (module, namedExport) => {
389
+ const defaultExport = module.default
390
+
391
+ if (typeof defaultExport === 'function') {
392
+ return defaultExport
393
+ }
394
+
395
+ if (defaultExport && typeof defaultExport[namedExport] === 'function') {
396
+ return defaultExport[namedExport].bind(defaultExport)
397
+ }
398
+
399
+ if (typeof module[namedExport] === 'function') {
400
+ return module[namedExport]
401
+ }
402
+
403
+ return null
404
+ }`;
405
+ function buildDefaultExportBody(options) {
406
+ const devOnlyEmailEntry = options.includeDevOnlyHooks ? `const url = new URL(request.url)
407
+
408
+ if (
409
+ request.headers.get('x-devflare-event') === 'email'
410
+ && url.pathname === '/_devflare/internal/email'
411
+ ) {
412
+ return __devflareHandleInternalEmail(request, env, ctx)
413
+ }
414
+
415
+ ` : "";
416
+ return `{
417
+ ...(${options.hasFetchDispatch ? "true" : "false"}
418
+ ? {
419
+ async fetch(request, env, ctx) {
420
+ ${devOnlyEmailEntry}const __devflareInitialRouteMatch = __devflareHasRoutes ? matchFetchRoute(__devflareRoutes, request) : null
421
+ const __devflareEvent = createFetchEvent(request, env, ctx, {
422
+ params: __devflareInitialRouteMatch?.params ?? {}
423
+ })
424
+ return runWithEventContext(
425
+ __devflareEvent,
426
+ () => invokeFetchModule(
427
+ __devflareFetchModule,
428
+ __devflareEvent,
429
+ __devflareHasRoutes
430
+ ? createRouteResolve(__devflareRoutes, __devflareEvent)
431
+ : undefined
432
+ )
433
+ )
434
+ }
435
+ }
436
+ : {}),
437
+ ...(__devflareQueueHandler
438
+ ? {
439
+ async queue(batch, env, ctx) {
440
+ assertExplicitQueueHandlerStyle(__devflareQueueHandler)
441
+ const __devflareEvent = createQueueEvent(batch, env, ctx)
442
+ return runWithEventContext(
443
+ __devflareEvent,
444
+ () => __devflareQueueHandler(__devflareEvent, env, ctx)
445
+ )
446
+ }
447
+ }
448
+ : {}),
449
+ ...(__devflareScheduledHandler
450
+ ? {
451
+ async scheduled(controller, env, ctx) {
452
+ assertExplicitScheduledHandlerStyle(__devflareScheduledHandler)
453
+ const __devflareEvent = createScheduledEvent(controller, env, ctx)
454
+ return runWithEventContext(
455
+ __devflareEvent,
456
+ () => __devflareScheduledHandler(__devflareEvent, env, ctx)
457
+ )
458
+ }
459
+ }
460
+ : {}),
461
+ ...(__devflareEmailHandler
462
+ ? {
463
+ async email(message, env, ctx) {
464
+ const __devflareEvent = createEmailEvent(message, env, ctx)
465
+ return runWithEventContext(
466
+ __devflareEvent,
467
+ () => __devflareEmailHandler(__devflareEvent, env, ctx)
468
+ )
469
+ }
470
+ }
471
+ : {}),
472
+ ...(__devflareTailHandler
473
+ ? {
474
+ async tail(events, env, ctx) {
475
+ const __devflareEvent = createTailEvent(events, env, ctx)
476
+ return runWithEventContext(
477
+ __devflareEvent,
478
+ () => __devflareTailHandler.length >= 2
479
+ ? __devflareTailHandler(events, env, ctx)
480
+ : __devflareTailHandler(__devflareEvent, env, ctx)
481
+ )
482
+ }
483
+ }
484
+ : {})
485
+ }`;
486
+ }
487
+ function getComposedWorkerEntrypointSource(surfaceImportPaths, configuredLocalSendEmailBindings = {}, durableObjectExports = [], routeImports = [], options = {}) {
488
+ const includeDevOnlyHooks = options.includeDevOnlyHooks ?? options.devInternalEmail === true;
489
+ const importsBuilder = new CodeBuilder;
490
+ importsBuilder.importStatement([
491
+ "assertExplicitQueueHandlerStyle",
492
+ "assertExplicitScheduledHandlerStyle",
493
+ "createEmailEvent",
494
+ "createFetchEvent",
495
+ "createQueueEvent",
496
+ "createRouteResolve",
497
+ "createScheduledEvent",
498
+ "createTailEvent",
499
+ "invokeFetchModule",
500
+ "matchFetchRoute",
501
+ "runWithEventContext",
502
+ "setLocalSendEmailBindings"
503
+ ], "devflare/runtime");
504
+ const fallbackModules = [
505
+ { identifier: "__devflareFetchModule", importPath: surfaceImportPaths.fetch },
506
+ { identifier: "__devflareQueueModule", importPath: surfaceImportPaths.queue },
507
+ { identifier: "__devflareScheduledModule", importPath: surfaceImportPaths.scheduled },
508
+ { identifier: "__devflareEmailModule", importPath: surfaceImportPaths.email },
509
+ { identifier: "__devflareTailModule", importPath: surfaceImportPaths.tail }
510
+ ];
511
+ const fallbacksBuilder = new CodeBuilder;
512
+ for (const { identifier, importPath } of fallbackModules) {
513
+ if (importPath) {
514
+ importsBuilder.importNamespace(identifier, importPath);
515
+ } else {
516
+ fallbacksBuilder.constDeclaration(identifier, "{}");
517
+ }
518
+ }
519
+ for (const routeImport of routeImports) {
520
+ importsBuilder.importNamespace(routeImport.identifier, routeImport.importPath);
521
+ }
522
+ const reExportsBuilder = new CodeBuilder;
523
+ for (const { classNames, importPath } of durableObjectExports) {
524
+ reExportsBuilder.reExport(classNames, importPath);
525
+ }
526
+ const routeManifestEntries = routeImports.map(({ identifier, filePath, routePath, segmentsJson }) => {
527
+ return ` { filePath: ${JSON.stringify(filePath)}, routePath: ${JSON.stringify(routePath)}, segments: ${segmentsJson}, module: ${identifier} }`;
528
+ });
529
+ const builder = new CodeBuilder;
530
+ builder.raw(importsBuilder.toString());
531
+ builder.raw(fallbacksBuilder.toString());
532
+ builder.raw(reExportsBuilder.toString());
533
+ builder.blank();
534
+ builder.raw(`setLocalSendEmailBindings(${JSON.stringify(configuredLocalSendEmailBindings)})`);
535
+ builder.blank();
536
+ builder.constDeclaration("__devflareHasFetchModule", surfaceImportPaths.fetch ? "true" : "false");
537
+ builder.raw(`const __devflareRoutes = [
538
+ ${routeManifestEntries.join(`,
539
+ `)}
540
+ ]`);
541
+ builder.constDeclaration("__devflareHasRoutes", "__devflareRoutes.length > 0");
542
+ builder.blank();
543
+ builder.raw(RESOLVE_HANDLER_DECLARATION);
544
+ builder.blank();
545
+ builder.constDeclaration("__devflareQueueHandler", "__devflareResolveHandler(__devflareQueueModule, 'queue')");
546
+ builder.constDeclaration("__devflareScheduledHandler", "__devflareResolveHandler(__devflareScheduledModule, 'scheduled')");
547
+ builder.constDeclaration("__devflareEmailHandler", "__devflareResolveHandler(__devflareEmailModule, 'email')");
548
+ builder.constDeclaration("__devflareTailHandler", "__devflareResolveHandler(__devflareTailModule, 'tail')");
549
+ emitDevOnlyEmailHooks(builder, { enabled: includeDevOnlyHooks });
550
+ builder.blank();
551
+ builder.exportDefault(buildDefaultExportBody({
552
+ hasFetchDispatch: Boolean(surfaceImportPaths.fetch) || routeImports.length > 0 || includeDevOnlyHooks,
553
+ includeDevOnlyHooks
554
+ }));
555
+ builder.raw("");
556
+ return builder.toString();
557
+ }
558
+ function toImportSpecifier(fromFilePath, toFilePath) {
559
+ const specifier = relative(dirname(fromFilePath), toFilePath).replace(/\\/g, "/");
560
+ return specifier.startsWith(".") ? specifier : `./${specifier}`;
561
+ }
562
+ function createGeneratedRouteModuleImports(entryPath, routeDiscovery) {
563
+ if (!routeDiscovery) {
564
+ return [];
565
+ }
566
+ return routeDiscovery.routes.map((route, index) => ({
567
+ identifier: `__devflareRouteModule${index}`,
568
+ importPath: toImportSpecifier(entryPath, route.absolutePath),
569
+ filePath: route.filePath,
570
+ routePath: route.routePath,
571
+ segmentsJson: JSON.stringify(route.segments)
572
+ }));
573
+ }
574
+ async function createGeneratedDurableObjectExports(entryPath, cwd, config) {
575
+ if (config.files?.durableObjects === false || !config.bindings?.durableObjects) {
576
+ return [];
577
+ }
578
+ const localClassNames = new Set(Object.values(config.bindings.durableObjects).map((binding) => normalizeDOBinding(binding)).filter((binding) => binding.kind === "local").map((binding) => binding.className));
579
+ if (localClassNames.size === 0) {
580
+ return [];
581
+ }
582
+ const pattern = typeof config.files?.durableObjects === "string" ? config.files.durableObjects : DEFAULT_DO_PATTERN;
583
+ const discoveredFiles = await discoverDurableObjectFiles(cwd, pattern);
584
+ const exports = [];
585
+ const discoveredClassNames = new Set;
586
+ for (const [filePath, allClassNames] of discoveredFiles) {
587
+ const classNames = allClassNames.filter((className) => localClassNames.has(className));
588
+ if (classNames.length === 0) {
589
+ continue;
590
+ }
591
+ for (const className of classNames) {
592
+ discoveredClassNames.add(className);
593
+ }
594
+ exports.push({
595
+ importPath: toImportSpecifier(entryPath, filePath),
596
+ filePath,
597
+ classNames
598
+ });
599
+ }
600
+ const missingClassNames = Array.from(localClassNames).filter((className) => !discoveredClassNames.has(className));
601
+ if (missingClassNames.length > 0) {
602
+ throw new Error(`Failed to discover local Durable Object class${missingClassNames.length === 1 ? "" : "es"} ${missingClassNames.join(", ")} for worker composition. ` + `Ensure files.durableObjects matches the source file pattern for your do.* files.`);
603
+ }
604
+ return exports;
605
+ }
606
+ function mayRequireCompositionBesidesFetch(config) {
607
+ const files = config.files ?? {};
608
+ if (typeof files.queue === "string" && files.queue)
609
+ return true;
610
+ if (typeof files.scheduled === "string" && files.scheduled)
611
+ return true;
612
+ if (typeof files.email === "string" && files.email)
613
+ return true;
614
+ if (typeof files.tail === "string" && files.tail)
615
+ return true;
616
+ if (files.durableObjects)
617
+ return true;
618
+ if (files.routes)
619
+ return true;
620
+ const bindings = config.bindings ?? {};
621
+ const doBindings = bindings.durableObjects;
622
+ if (doBindings && Object.keys(doBindings).length > 0)
623
+ return true;
624
+ const sendEmail = bindings.sendEmail;
625
+ if (sendEmail && Object.keys(sendEmail).length > 0)
626
+ return true;
627
+ return false;
628
+ }
629
+ function needsComposedWorkerEntrypoint(cwd, surfacePaths, config, routeDiscovery) {
630
+ const hasAdditionalWorkerSurfaces = Boolean(surfacePaths.queue || surfacePaths.scheduled || surfacePaths.email || surfacePaths.tail || routeDiscovery?.routes.length);
631
+ if (hasAdditionalWorkerSurfaces) {
632
+ return true;
633
+ }
634
+ if (!surfacePaths.fetch) {
635
+ return false;
636
+ }
637
+ const assetsDirectory = config.assets?.directory;
638
+ if (assetsDirectory) {
639
+ const generatedAssetsWorkerPath = resolve2(cwd, assetsDirectory, "_worker.js");
640
+ if (surfacePaths.fetch === generatedAssetsWorkerPath) {
641
+ return false;
642
+ }
643
+ }
644
+ return Boolean(surfacePaths.fetch);
645
+ }
646
+ async function prepareComposedWorkerEntrypoint(cwd, config, environment, options = {}) {
647
+ const resolvedConfig = resolveConfigForEnvironment(config, environment);
648
+ if (resolvedConfig.wrangler?.passthrough && Object.prototype.hasOwnProperty.call(resolvedConfig.wrangler.passthrough, "main")) {
649
+ return null;
650
+ }
651
+ const configuredFetch = resolvedConfig.files?.fetch;
652
+ if (typeof configuredFetch === "string" && looksLikeBuildArtifactPath(configuredFetch)) {
653
+ const fs2 = await import("node:fs/promises");
654
+ const fetchAbsolute = resolve2(cwd, configuredFetch);
655
+ let fetchExists = true;
656
+ try {
657
+ await fs2.access(fetchAbsolute);
658
+ } catch {
659
+ fetchExists = false;
660
+ }
661
+ if (!fetchExists && !mayRequireCompositionBesidesFetch(resolvedConfig)) {
662
+ return null;
663
+ }
664
+ }
665
+ const surfacePaths = await resolveWorkerSurfacePaths(cwd, resolvedConfig);
666
+ const routeDiscovery = await discoverRoutes(cwd, resolvedConfig);
667
+ if (!needsComposedWorkerEntrypoint(cwd, surfacePaths, resolvedConfig, routeDiscovery)) {
668
+ return null;
669
+ }
670
+ const fs = await import("node:fs/promises");
671
+ const entryDir = resolve2(cwd, ".devflare", "worker-entrypoints");
672
+ const entryPath = resolve2(entryDir, "main.ts");
673
+ await fs.mkdir(entryDir, { recursive: true });
674
+ const surfaceImportPaths = {
675
+ fetch: surfacePaths.fetch ? toImportSpecifier(entryPath, surfacePaths.fetch) : null,
676
+ queue: surfacePaths.queue ? toImportSpecifier(entryPath, surfacePaths.queue) : null,
677
+ scheduled: surfacePaths.scheduled ? toImportSpecifier(entryPath, surfacePaths.scheduled) : null,
678
+ email: surfacePaths.email ? toImportSpecifier(entryPath, surfacePaths.email) : null,
679
+ tail: surfacePaths.tail ? toImportSpecifier(entryPath, surfacePaths.tail) : null
680
+ };
681
+ const durableObjectExports = await createGeneratedDurableObjectExports(entryPath, cwd, resolvedConfig);
682
+ const routeImports = createGeneratedRouteModuleImports(entryPath, routeDiscovery);
683
+ await fs.writeFile(entryPath, getComposedWorkerEntrypointSource(surfaceImportPaths, resolvedConfig.bindings?.sendEmail ?? {}, durableObjectExports, routeImports, options));
684
+ return entryPath;
685
+ }
686
+
687
+ // src/vite/plugin-context.ts
688
+ var CONFIG_DIR = ".devflare";
689
+ function removeDevflareHandledServeBindings(config) {
690
+ const next = { ...config };
691
+ delete next.workflows;
692
+ delete next.media;
693
+ return next;
694
+ }
695
+ async function buildPluginContextState(projectRoot, devflareConfig, environment, mode = "serve", configDir = projectRoot) {
696
+ const effectiveConfig = mode === "build" ? await resolveResources(devflareConfig, { phase: "build", environment }) : await resolveResources(devflareConfig, { phase: "local", environment });
697
+ const compiledWranglerConfig = mode === "build" ? compileBuildConfig(effectiveConfig) : compileConfig(effectiveConfig);
698
+ const wranglerConfig = mode === "build" ? isolateViteBuildOutputPaths(projectRoot, compiledWranglerConfig) : removeDevflareHandledServeBindings(compiledWranglerConfig);
699
+ const cloudflareConfig = {
700
+ ...mode === "build" ? isolateViteBuildOutputPaths(projectRoot, compileToProgrammaticConfig(effectiveConfig, environment, { preserveNamedBindings: true })) : removeDevflareHandledServeBindings(compileToProgrammaticConfig(effectiveConfig, environment))
701
+ };
702
+ const composedMainEntry = mode === "build" ? null : await prepareComposedWorkerEntrypoint(projectRoot, effectiveConfig, environment);
703
+ if (composedMainEntry) {
704
+ const relativeMain = relative2(projectRoot, composedMainEntry);
705
+ wranglerConfig.main = relativeMain;
706
+ cloudflareConfig.main = relativeMain;
707
+ }
708
+ let durableObjects = null;
709
+ let auxiliaryWorkerConfig = null;
710
+ let serviceWorkerVirtualModules = new Map;
711
+ let serviceAuxiliaryWorkerConfigs = [];
712
+ const doPatternConfig = effectiveConfig.files?.durableObjects;
713
+ const doPattern = typeof doPatternConfig === "string" ? doPatternConfig : DEFAULT_DO_PATTERN;
714
+ if (doPatternConfig !== false) {
715
+ const doWorkerName = `${wranglerConfig.name}-do`;
716
+ const discovery = await discoverDurableObjects(projectRoot, doPattern, doWorkerName);
717
+ if (discovery.files.size > 0) {
718
+ durableObjects = discovery;
719
+ if (wranglerConfig.durable_objects?.bindings) {
720
+ for (const binding of wranglerConfig.durable_objects.bindings) {
721
+ binding.script_name = doWorkerName;
722
+ }
723
+ }
724
+ if (cloudflareConfig.durable_objects) {
725
+ const doConfig = cloudflareConfig.durable_objects;
726
+ for (const binding of doConfig.bindings) {
727
+ binding.script_name = doWorkerName;
728
+ }
729
+ }
730
+ auxiliaryWorkerConfig = createAuxiliaryWorkerConfig(wranglerConfig, discovery);
731
+ }
732
+ }
733
+ if (mode === "serve" && effectiveConfig.bindings?.services) {
734
+ const serviceBindingResolution = await resolveServiceBindings(effectiveConfig, configDir);
735
+ const serviceWorkers = createAuxiliaryServiceWorkerConfigs(serviceBindingResolution);
736
+ serviceAuxiliaryWorkerConfigs = serviceWorkers.auxiliaryWorkers;
737
+ serviceWorkerVirtualModules = serviceWorkers.virtualModules;
738
+ }
739
+ const auxiliaryWorkerConfigs = [
740
+ ...auxiliaryWorkerConfig ? [auxiliaryWorkerConfig] : [],
741
+ ...serviceAuxiliaryWorkerConfigs
742
+ ];
743
+ return {
744
+ wranglerConfig,
745
+ cloudflareConfig,
746
+ auxiliaryWorkerConfigs,
747
+ serviceWorkerVirtualModules,
748
+ durableObjects,
749
+ auxiliaryWorkerConfig
750
+ };
751
+ }
752
+ async function ensureGeneratedConfigDir(projectRoot) {
753
+ const configDir = resolve3(projectRoot, CONFIG_DIR);
754
+ const fs = await import("node:fs/promises");
755
+ await fs.mkdir(configDir, { recursive: true });
756
+ const gitignorePath = resolve3(configDir, ".gitignore");
757
+ try {
758
+ await fs.access(gitignorePath);
759
+ } catch {
760
+ await fs.writeFile(gitignorePath, `*
761
+ `, "utf-8");
762
+ }
763
+ return configDir;
764
+ }
765
+ async function writeGeneratedWranglerConfig(projectRoot, wranglerConfig) {
766
+ const configDir = await ensureGeneratedConfigDir(projectRoot);
767
+ const wranglerFileConfig = rebaseWranglerConfigPaths(projectRoot, configDir, wranglerConfig);
768
+ await writeWranglerConfig(configDir, wranglerFileConfig, "wrangler.jsonc");
769
+ }
770
+ async function resolvePluginConfigPath(projectRoot, configPath) {
771
+ if (configPath) {
772
+ return isAbsolute(configPath) ? configPath : resolve3(projectRoot, configPath);
773
+ }
774
+ return await resolveConfigPath(projectRoot) ?? null;
775
+ }
776
+
777
+ // src/vite/plugin-config-hook.ts
778
+ async function tryLoadDevflareConfig(cwd, configPath, command) {
779
+ try {
780
+ return await loadConfig({ cwd, configFile: configPath });
781
+ } catch (error) {
782
+ if (command === "build") {
783
+ console.warn("[devflare] Could not load config:", error);
784
+ }
785
+ return null;
786
+ }
787
+ }
788
+ function buildWorkerNameDefine(lfConfig, existing) {
789
+ const workerNameValue = lfConfig.name ?? "unknown";
790
+ return {
791
+ ...existing,
792
+ __DEVFLARE_WORKER_NAME__: JSON.stringify(workerNameValue)
793
+ };
794
+ }
795
+ function buildWebSocketProxyConfig(lfConfig, bridgePort, wsProxyPatterns) {
796
+ const patterns = [...wsProxyPatterns];
797
+ if (lfConfig.wsRoutes && lfConfig.wsRoutes.length > 0) {
798
+ for (const route of lfConfig.wsRoutes) {
799
+ if (!patterns.includes(route.pattern)) {
800
+ patterns.push(route.pattern);
801
+ }
802
+ }
803
+ }
804
+ if (patterns.length === 0)
805
+ return null;
806
+ const proxyConfig = {};
807
+ for (const pattern of patterns) {
808
+ proxyConfig[pattern] = {
809
+ target: `http://127.0.0.1:${bridgePort}`,
810
+ changeOrigin: true,
811
+ ws: true,
812
+ configure: (proxy) => {
813
+ proxy.on("error", (err) => {
814
+ console.error(`[devflare] Proxy error: ${err.message}`);
815
+ });
816
+ }
817
+ };
818
+ }
819
+ if (Object.keys(proxyConfig).length === 0)
820
+ return null;
821
+ console.log(`[devflare] WebSocket proxy configured for: ${patterns.join(", ")}`);
822
+ return proxyConfig;
823
+ }
824
+ async function buildPluginConfigHookResult(cwd, options, command, existingDefine) {
825
+ const lfConfig = await tryLoadDevflareConfig(cwd, options.configPath, command);
826
+ const returnConfig = {};
827
+ if (lfConfig) {
828
+ returnConfig.define = buildWorkerNameDefine(lfConfig, existingDefine);
829
+ }
830
+ if (command === "serve" && process.env.DEVFLARE_DEV && lfConfig) {
831
+ const port = options.bridgePort ?? 8787;
832
+ const proxyConfig = buildWebSocketProxyConfig(lfConfig, port, options.wsProxyPatterns);
833
+ if (proxyConfig) {
834
+ returnConfig.server = { proxy: proxyConfig };
835
+ }
836
+ }
837
+ return Object.keys(returnConfig).length > 0 ? returnConfig : undefined;
838
+ }
839
+
840
+ // src/vite/plugin-transform.ts
841
+ var TRANSFORMABLE_EXTENSIONS = [".ts", ".tsx", ".js"];
842
+ function isTransformCandidate(id) {
843
+ if (id.includes("node_modules"))
844
+ return false;
845
+ return TRANSFORMABLE_EXTENSIONS.some((ext) => id.endsWith(ext));
846
+ }
847
+ async function runWorkerEntryTransform(code, id) {
848
+ if (!id.endsWith("worker.ts") && !id.endsWith("worker.js")) {
849
+ return null;
850
+ }
851
+ const {
852
+ shouldTransformWorker,
853
+ transformWorkerEntrypoint
854
+ } = await import("./worker-entrypoint-3rmzd4c1.js");
855
+ if (!shouldTransformWorker(code, id)) {
856
+ return null;
857
+ }
858
+ const result = transformWorkerEntrypoint(code, id);
859
+ if (!result)
860
+ return null;
861
+ return {
862
+ code: result.code,
863
+ map: result.map
864
+ };
865
+ }
866
+ async function runDurableObjectTransform(code, id, options) {
867
+ if (!options.doTransforms)
868
+ return null;
869
+ if (!code.includes("DurableObject") && !code.includes("@durableObject")) {
870
+ return null;
871
+ }
872
+ const { transformDurableObject } = await import("./durable-object-v3gsnybk.js");
873
+ return transformDurableObject(code, id);
874
+ }
875
+ async function runDevflareTransform(code, id, options) {
876
+ if (!isTransformCandidate(id))
877
+ return null;
878
+ const workerResult = await runWorkerEntryTransform(code, id);
879
+ if (workerResult)
880
+ return workerResult;
881
+ return await runDurableObjectTransform(code, id, options);
882
+ }
883
+
884
+ // src/vite/plugin-programmatic.ts
885
+ import { relative as relative3 } from "pathe";
886
+ async function loadProgrammaticDevflareConfig(options) {
887
+ const cwd = options.cwd ?? process.cwd();
888
+ const strategy = options.resolve ?? "offline-local";
889
+ const devflareConfig = strategy === "remote" ? await loadResolvedConfig({
890
+ cwd,
891
+ configFile: options.configPath,
892
+ environment: options.environment
893
+ }) : await resolveResources(await loadConfig({ cwd, configFile: options.configPath }), { phase: "local", environment: options.environment });
894
+ return { cwd, devflareConfig };
895
+ }
896
+ async function buildProgrammaticArtifacts(options, mode) {
897
+ const { cwd, devflareConfig } = await loadProgrammaticDevflareConfig(options);
898
+ const composedMainEntry = await prepareComposedWorkerEntrypoint(cwd, devflareConfig);
899
+ const wranglerConfig = compileConfig(devflareConfig);
900
+ const cloudflareConfig = mode === "programmatic" ? compileToProgrammaticConfig(devflareConfig) : { ...wranglerConfig };
901
+ if (composedMainEntry) {
902
+ const relativeMain = relative3(cwd, composedMainEntry);
903
+ wranglerConfig.main = relativeMain;
904
+ cloudflareConfig.main = relativeMain;
905
+ }
906
+ const auxiliaryWorkers = [];
907
+ const doPatternConfig = devflareConfig.files?.durableObjects;
908
+ const doPattern = typeof doPatternConfig === "string" ? doPatternConfig : DEFAULT_DO_PATTERN;
909
+ if (doPatternConfig !== false) {
910
+ const doWorkerName = `${wranglerConfig.name}-do`;
911
+ const discovery = await discoverDurableObjects(cwd, doPattern, doWorkerName);
912
+ if (discovery.files.size > 0) {
913
+ if (cloudflareConfig.durable_objects) {
914
+ const doConfig = cloudflareConfig.durable_objects;
915
+ for (const binding of doConfig.bindings) {
916
+ binding.script_name = doWorkerName;
917
+ }
918
+ }
919
+ auxiliaryWorkers.push(createAuxiliaryWorkerConfig(wranglerConfig, discovery));
920
+ }
921
+ }
922
+ if (devflareConfig.bindings?.services) {
923
+ const serviceBindingResolution = await resolveServiceBindings(devflareConfig, cwd);
924
+ auxiliaryWorkers.push(...createAuxiliaryServiceWorkerConfigs(serviceBindingResolution).auxiliaryWorkers);
925
+ }
926
+ return { cwd, devflareConfig, composedMainEntry, wranglerConfig, cloudflareConfig, auxiliaryWorkers };
927
+ }
928
+ async function getCloudflareConfig(options = {}) {
929
+ const { cloudflareConfig } = await buildProgrammaticArtifacts(options, "programmatic");
930
+ return cloudflareConfig;
931
+ }
932
+ async function getDevflareConfigs(options = {}) {
933
+ const { cloudflareConfig, auxiliaryWorkers } = await buildProgrammaticArtifacts(options, "wrangler");
934
+ return { cloudflareConfig, auxiliaryWorkers };
935
+ }
936
+
937
+ // src/vite/plugin.ts
938
+ var CONFIG_DIR2 = ".devflare";
939
+ function createPluginState() {
940
+ return {
941
+ context: {
942
+ wranglerConfig: null,
943
+ cloudflareConfig: null,
944
+ projectRoot: process.cwd(),
945
+ auxiliaryWorkerConfig: null,
946
+ auxiliaryWorkerConfigs: [],
947
+ serviceWorkerVirtualModules: new Map,
948
+ durableObjects: null
949
+ },
950
+ projectRoot: process.cwd(),
951
+ devflareConfig: null,
952
+ resolvedPluginConfigPath: null
953
+ };
954
+ }
955
+ async function loadAndApplyConfig(state, options, mode, onContextUpdated) {
956
+ state.devflareConfig = await loadConfig({
957
+ cwd: state.projectRoot,
958
+ configFile: options.configPath
959
+ });
960
+ const pluginState = await buildPluginContextState(state.projectRoot, state.devflareConfig, options.environment, mode, state.resolvedPluginConfigPath ? dirname2(state.resolvedPluginConfigPath) : state.projectRoot);
961
+ Object.assign(state.context, {
962
+ projectRoot: state.projectRoot,
963
+ ...pluginState
964
+ });
965
+ onContextUpdated(state.context);
966
+ logDiscoveredDurableObjects(state.projectRoot, pluginState.durableObjects);
967
+ await writeGeneratedWranglerConfig(state.projectRoot, pluginState.wranglerConfig);
968
+ }
969
+ var lastPluginContext = createPluginState().context;
970
+ function getPluginContext() {
971
+ return lastPluginContext;
972
+ }
973
+ function devflarePlugin(options = {}) {
974
+ const {
975
+ configPath,
976
+ environment,
977
+ doTransforms = true,
978
+ watchConfig = true,
979
+ bridgePort = process.env.DEVFLARE_BRIDGE_PORT ? parseInt(process.env.DEVFLARE_BRIDGE_PORT, 10) : undefined,
980
+ wsProxyPatterns = []
981
+ } = options;
982
+ const state = createPluginState();
983
+ return {
984
+ name: "devflare",
985
+ enforce: "pre",
986
+ async config(config, { command }) {
987
+ const cwd = config.root ?? process.cwd();
988
+ return buildPluginConfigHookResult(cwd, { configPath, bridgePort, wsProxyPatterns }, command, config.define ?? {});
989
+ },
990
+ resolveId(id) {
991
+ if (id === VIRTUAL_DO_ENTRY) {
992
+ return RESOLVED_VIRTUAL_DO_ENTRY;
993
+ }
994
+ if (id.startsWith(VIRTUAL_SERVICE_WORKER_PREFIX)) {
995
+ return "\x00" + id;
996
+ }
997
+ return null;
998
+ },
999
+ async load(id) {
1000
+ if (id === RESOLVED_VIRTUAL_DO_ENTRY) {
1001
+ if (!state.context.durableObjects) {
1002
+ return `// No Durable Objects configured
1003
+ export default { fetch: () => new Response("No DOs") }`;
1004
+ }
1005
+ return generateVirtualDOEntry(state.context.durableObjects);
1006
+ }
1007
+ if (id.startsWith(RESOLVED_VIRTUAL_SERVICE_WORKER_PREFIX)) {
1008
+ return state.context.serviceWorkerVirtualModules.get(id) ?? null;
1009
+ }
1010
+ return null;
1011
+ },
1012
+ async configResolved(config) {
1013
+ state.projectRoot = config.root;
1014
+ state.context.projectRoot = state.projectRoot;
1015
+ state.resolvedPluginConfigPath = await resolvePluginConfigPath(state.projectRoot, configPath);
1016
+ try {
1017
+ await loadAndApplyConfig(state, { configPath, environment }, config.command === "build" ? "build" : "serve", (ctx) => {
1018
+ lastPluginContext = ctx;
1019
+ });
1020
+ if (config.command === "serve") {
1021
+ console.log("[devflare] Config generated to .devflare/wrangler.jsonc");
1022
+ if (state.context.auxiliaryWorkerConfig) {
1023
+ console.log("[devflare] ✓ Auxiliary DO worker configured");
1024
+ }
1025
+ }
1026
+ if (config.command === "build") {
1027
+ console.log(`[devflare] Generated ${CONFIG_DIR2}/wrangler.jsonc`);
1028
+ }
1029
+ } catch (error) {
1030
+ if (error instanceof Error) {
1031
+ console.error("[devflare] Config error:", error.message);
1032
+ }
1033
+ throw error;
1034
+ }
1035
+ },
1036
+ configureServer(server) {
1037
+ if (!watchConfig)
1038
+ return;
1039
+ const fullConfigPath = state.resolvedPluginConfigPath ?? resolve4(state.projectRoot, configPath || "devflare.config.ts");
1040
+ server.watcher.add(fullConfigPath);
1041
+ server.watcher.on("change", async (changedPath) => {
1042
+ if (changedPath === fullConfigPath) {
1043
+ console.log("[devflare] Config changed, reloading...");
1044
+ try {
1045
+ await loadAndApplyConfig(state, { configPath, environment }, "serve", (ctx) => {
1046
+ lastPluginContext = ctx;
1047
+ });
1048
+ console.log("[devflare] Config reloaded");
1049
+ server.ws.send({
1050
+ type: "full-reload",
1051
+ path: "*"
1052
+ });
1053
+ } catch (error) {
1054
+ console.error("[devflare] Failed to reload config:", error);
1055
+ }
1056
+ }
1057
+ });
1058
+ },
1059
+ async transform(code, id) {
1060
+ return runDevflareTransform(code, id, { doTransforms });
1061
+ }
1062
+ };
1063
+ }
1064
+ // src/vite/config-file.ts
1065
+ var CONFIG_DIR3 = ".devflare";
1066
+ var GENERATED_VITE_CONFIG_FILENAME = "vite.config.mjs";
1067
+ function hasInlineViteConfig(viteConfig) {
1068
+ return Boolean(viteConfig && Object.keys(viteConfig).length > 0);
1069
+ }
1070
+ function resolveEffectiveViteProject(detection, config, environment) {
1071
+ const resolvedConfig = resolveConfigForEnvironment(config, environment);
1072
+ const hasDevflareConfig = hasInlineViteConfig(resolvedConfig.vite);
1073
+ return {
1074
+ ...detection,
1075
+ hasDevflareViteConfig: hasDevflareConfig,
1076
+ shouldStartVite: detection.shouldStartVite || hasDevflareConfig,
1077
+ wantsViteIntegration: detection.wantsViteIntegration || hasDevflareConfig
1078
+ };
1079
+ }
1080
+ function isPromiseLike(value) {
1081
+ return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
1082
+ }
1083
+ function normalizePluginOptions(pluginOption) {
1084
+ if (typeof pluginOption === "undefined") {
1085
+ return [];
1086
+ }
1087
+ return Array.isArray(pluginOption) ? pluginOption : [pluginOption];
1088
+ }
1089
+ function removePluginByName(pluginOption, pluginName) {
1090
+ if (Array.isArray(pluginOption)) {
1091
+ const filteredPlugins = pluginOption.map((nestedPlugin) => removePluginByName(nestedPlugin, pluginName)).filter((nestedPlugin) => typeof nestedPlugin !== "undefined");
1092
+ return filteredPlugins.length > 0 ? filteredPlugins : undefined;
1093
+ }
1094
+ if (!pluginOption || typeof pluginOption === "boolean" || isPromiseLike(pluginOption)) {
1095
+ return pluginOption;
1096
+ }
1097
+ return pluginOption.name === pluginName ? undefined : pluginOption;
1098
+ }
1099
+ function withInjectedDevflarePlugin(config, pluginOptions) {
1100
+ const existingPlugins = normalizePluginOptions(config.plugins).map((pluginOption) => removePluginByName(pluginOption, "devflare")).filter((pluginOption) => typeof pluginOption !== "undefined");
1101
+ return {
1102
+ ...config,
1103
+ plugins: [devflarePlugin(pluginOptions), ...existingPlugins]
1104
+ };
1105
+ }
1106
+ async function resolveViteUserConfig(configEnv, options = {}) {
1107
+ const { loadConfigFromFile, mergeConfig } = await import("vite");
1108
+ const cwd = options.cwd ?? process.cwd();
1109
+ const devflareConfig = await loadConfig({
1110
+ cwd,
1111
+ configFile: options.configPath
1112
+ });
1113
+ const resolvedDevflareConfig = resolveConfigForEnvironment(devflareConfig, options.environment);
1114
+ const inlineViteConfig = resolvedDevflareConfig.vite ?? {};
1115
+ const localConfig = options.localConfigPath ? (await loadConfigFromFile(configEnv, options.localConfigPath, cwd))?.config ?? {} : {};
1116
+ const mergedConfig = mergeConfig(localConfig, inlineViteConfig);
1117
+ const normalizedConfig = mergedConfig.root ? mergedConfig : {
1118
+ ...mergedConfig,
1119
+ root: cwd
1120
+ };
1121
+ return withInjectedDevflarePlugin(normalizedConfig, {
1122
+ configPath: options.configPath,
1123
+ environment: options.environment,
1124
+ bridgePort: options.bridgePort
1125
+ });
1126
+ }
1127
+ async function ensureGeneratedConfigDir2(cwd) {
1128
+ const fs = await import("node:fs/promises");
1129
+ const { resolve: resolve5 } = await import("pathe");
1130
+ const configDir = resolve5(cwd, CONFIG_DIR3);
1131
+ await fs.mkdir(configDir, { recursive: true });
1132
+ const gitignorePath = resolve5(configDir, ".gitignore");
1133
+ try {
1134
+ await fs.access(gitignorePath);
1135
+ } catch {
1136
+ await fs.writeFile(gitignorePath, `*
1137
+ `, "utf-8");
1138
+ }
1139
+ return configDir;
1140
+ }
1141
+ async function resolveDevflarePackageRoot(currentFilePath) {
1142
+ const fs = await import("node:fs/promises");
1143
+ const { dirname: dirname3, resolve: resolve5 } = await import("pathe");
1144
+ let currentDir = dirname3(currentFilePath);
1145
+ while (true) {
1146
+ const packageJsonPath = resolve5(currentDir, "package.json");
1147
+ try {
1148
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
1149
+ if (packageJson.name === "devflare") {
1150
+ return currentDir;
1151
+ }
1152
+ } catch {}
1153
+ const parentDir = dirname3(currentDir);
1154
+ if (parentDir === currentDir) {
1155
+ break;
1156
+ }
1157
+ currentDir = parentDir;
1158
+ }
1159
+ throw new Error("Could not resolve the devflare package root for generated Vite config imports.");
1160
+ }
1161
+ async function resolveGeneratedViteImportPath(configDir) {
1162
+ const { fileURLToPath } = await import("node:url");
1163
+ const { extname, normalize, relative: relative4, resolve: resolve5 } = await import("pathe");
1164
+ const currentFilePath = normalize(fileURLToPath(import.meta.url));
1165
+ const currentExtension = extname(currentFilePath);
1166
+ const packageRoot = await resolveDevflarePackageRoot(currentFilePath);
1167
+ const viteEntryPath = currentFilePath.includes("/dist/") ? resolve5(packageRoot, "dist/vite/index.js") : resolve5(packageRoot, `src/vite/index${currentExtension}`);
1168
+ const relativeImportPath = relative4(configDir, viteEntryPath);
1169
+ return relativeImportPath.startsWith(".") ? relativeImportPath : `./${relativeImportPath}`;
1170
+ }
1171
+ async function writeGeneratedViteConfig(options) {
1172
+ const fs = await import("node:fs/promises");
1173
+ const { resolve: resolve5 } = await import("pathe");
1174
+ const configDir = await ensureGeneratedConfigDir2(options.cwd);
1175
+ const generatedConfigPath = resolve5(configDir, GENERATED_VITE_CONFIG_FILENAME);
1176
+ const viteImportPath = await resolveGeneratedViteImportPath(configDir);
1177
+ const content = `import { defineConfig } from 'vite'
1178
+ import { resolveViteUserConfig } from ${JSON.stringify(viteImportPath)}
1179
+
1180
+ export default defineConfig(async (env) => {
1181
+ return await resolveViteUserConfig(env, {
1182
+ cwd: ${JSON.stringify(options.cwd)},
1183
+ configPath: ${JSON.stringify(options.configPath)},
1184
+ environment: ${JSON.stringify(options.environment)},
1185
+ localConfigPath: ${JSON.stringify(options.localConfigPath)},
1186
+ bridgePort: ${JSON.stringify(options.bridgePort)}
1187
+ })
1188
+ })
1189
+ `;
1190
+ await fs.writeFile(generatedConfigPath, content, "utf-8");
1191
+ return generatedConfigPath;
1192
+ }
1193
+ export { DEFAULT_FETCH_ENTRY_FILES, DEFAULT_QUEUE_ENTRY_FILES, DEFAULT_SCHEDULED_ENTRY_FILES, DEFAULT_EMAIL_ENTRY_FILES, resolveWorkerSurfacePaths, hasWorkerSurfacePaths, prepareComposedWorkerEntrypoint, getCloudflareConfig, getDevflareConfigs, getPluginContext, devflarePlugin, hasInlineViteConfig, resolveEffectiveViteProject, resolveViteUserConfig, writeGeneratedViteConfig };