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,898 @@
1
+ import {
2
+ bundleWorkerEntry
3
+ } from "./index-gq39t0rx.js";
4
+ import {
5
+ discoverEntrypointsSync
6
+ } from "./index-gj5qh491.js";
7
+ import {
8
+ resolvePackageSpecifier
9
+ } from "./index-t4fhcx1n.js";
10
+ import {
11
+ transformWorkerEntrypoint
12
+ } from "./index-7k278fgz.js";
13
+ import {
14
+ DEFAULT_DO_PATTERN,
15
+ DEFAULT_WORKFLOW_PATTERN,
16
+ findFiles,
17
+ findFilesSync
18
+ } from "./index-qwgr4q7s.js";
19
+ import {
20
+ findDurableObjectClasses
21
+ } from "./index-vhqww6tt.js";
22
+ import {
23
+ configSchema,
24
+ getLocalD1DatabaseIdentifier,
25
+ getLocalKVNamespaceIdentifier,
26
+ normalizeArtifactsBinding,
27
+ normalizeDOBinding,
28
+ normalizeDispatchNamespaceBinding,
29
+ normalizeHyperdriveBinding,
30
+ normalizeImagesBinding,
31
+ normalizeMediaBinding,
32
+ normalizeMtlsCertificateBinding,
33
+ normalizePipelineBinding,
34
+ normalizeSecretsStoreBinding,
35
+ normalizeWorkflowBinding
36
+ } from "./index-syscwrjp.js";
37
+ import {
38
+ __require
39
+ } from "./index-37x76zdn.js";
40
+
41
+ // src/test/resolve-service-bindings.ts
42
+ import { dirname, join, resolve } from "path";
43
+ import { existsSync, readFileSync } from "fs";
44
+
45
+ // src/dev-server/miniflare-bindings.ts
46
+ function buildQueueProducers(bindings) {
47
+ if (!bindings.queues?.producers) {
48
+ return;
49
+ }
50
+ const producers = {};
51
+ for (const [bindingName, queueName] of Object.entries(bindings.queues.producers)) {
52
+ producers[bindingName] = { queueName };
53
+ }
54
+ return producers;
55
+ }
56
+ function buildQueueConsumers(bindings) {
57
+ if (!bindings.queues?.consumers || bindings.queues.consumers.length === 0) {
58
+ return;
59
+ }
60
+ const consumers = {};
61
+ for (const consumer of bindings.queues.consumers) {
62
+ consumers[consumer.queue] = {
63
+ ...consumer.maxBatchSize !== undefined && { maxBatchSize: consumer.maxBatchSize },
64
+ ...consumer.maxBatchTimeout !== undefined && { maxBatchTimeout: consumer.maxBatchTimeout },
65
+ ...consumer.maxRetries !== undefined && { maxRetries: consumer.maxRetries },
66
+ ...consumer.deadLetterQueue && { deadLetterQueue: consumer.deadLetterQueue },
67
+ ...consumer.maxConcurrency !== undefined && { maxConcurrency: consumer.maxConcurrency },
68
+ ...consumer.retryDelay !== undefined && { retryDelay: consumer.retryDelay }
69
+ };
70
+ }
71
+ return consumers;
72
+ }
73
+ function buildRateLimitsConfig(bindings) {
74
+ if (!bindings.rateLimits) {
75
+ return;
76
+ }
77
+ return Object.fromEntries(Object.entries(bindings.rateLimits).map(([name, binding]) => [
78
+ name,
79
+ {
80
+ simple: {
81
+ limit: binding.simple.limit,
82
+ period: binding.simple.period
83
+ }
84
+ }
85
+ ]));
86
+ }
87
+ function buildVersionMetadataConfig(bindings) {
88
+ return bindings.versionMetadata?.binding;
89
+ }
90
+ function buildWorkerLoadersConfig(bindings) {
91
+ if (!bindings.workerLoaders) {
92
+ return;
93
+ }
94
+ return Object.fromEntries(Object.keys(bindings.workerLoaders).map((bindingName) => [bindingName, {}]));
95
+ }
96
+ function buildMtlsCertificatesConfig(bindings) {
97
+ if (!bindings.mtlsCertificates) {
98
+ return;
99
+ }
100
+ return Object.fromEntries(Object.entries(bindings.mtlsCertificates).map(([bindingName, binding]) => {
101
+ const normalized = normalizeMtlsCertificateBinding(binding);
102
+ return [
103
+ bindingName,
104
+ {
105
+ certificate_id: normalized.certificateId
106
+ }
107
+ ];
108
+ }));
109
+ }
110
+ function buildDispatchNamespacesConfig(bindings) {
111
+ if (!bindings.dispatchNamespaces) {
112
+ return;
113
+ }
114
+ return Object.fromEntries(Object.entries(bindings.dispatchNamespaces).map(([bindingName, binding]) => {
115
+ const normalized = normalizeDispatchNamespaceBinding(binding);
116
+ return [
117
+ bindingName,
118
+ {
119
+ namespace: normalized.namespace
120
+ }
121
+ ];
122
+ }));
123
+ }
124
+ function buildWorkflowsConfig(bindings) {
125
+ if (!bindings.workflows) {
126
+ return;
127
+ }
128
+ return Object.fromEntries(Object.entries(bindings.workflows).map(([bindingName, binding]) => {
129
+ const normalized = normalizeWorkflowBinding(binding);
130
+ return [
131
+ bindingName,
132
+ {
133
+ name: normalized.name,
134
+ className: normalized.className,
135
+ ...normalized.scriptName && { scriptName: normalized.scriptName },
136
+ ...normalized.limits && { stepLimit: normalized.limits.steps }
137
+ }
138
+ ];
139
+ }));
140
+ }
141
+ function buildPipelinesConfig(bindings) {
142
+ if (!bindings.pipelines) {
143
+ return;
144
+ }
145
+ return Object.fromEntries(Object.entries(bindings.pipelines).map(([bindingName, binding]) => {
146
+ const normalized = normalizePipelineBinding(binding);
147
+ return [
148
+ bindingName,
149
+ typeof binding === "string" ? normalized.pipeline : { pipeline: normalized.pipeline }
150
+ ];
151
+ }));
152
+ }
153
+ function getHyperdriveLocalConnectionString(bindingName, binding) {
154
+ const cloudflareEnvName = `CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_${bindingName}`;
155
+ const wranglerEnvName = `WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_${bindingName}`;
156
+ const envValue = process.env[cloudflareEnvName] ?? process.env[wranglerEnvName];
157
+ if (envValue?.trim()) {
158
+ return envValue;
159
+ }
160
+ const normalized = normalizeHyperdriveBinding(binding);
161
+ return normalized.localConnectionString;
162
+ }
163
+ function buildHyperdrivesConfig(bindings) {
164
+ if (!bindings.hyperdrive) {
165
+ return;
166
+ }
167
+ const hyperdrives = Object.fromEntries(Object.entries(bindings.hyperdrive).map(([bindingName, binding]) => {
168
+ const localConnectionString = getHyperdriveLocalConnectionString(bindingName, binding);
169
+ return localConnectionString ? [bindingName, localConnectionString] : null;
170
+ }).filter((entry) => entry !== null));
171
+ return Object.keys(hyperdrives).length > 0 ? hyperdrives : undefined;
172
+ }
173
+ function buildImagesConfig(bindings) {
174
+ if (!bindings.images) {
175
+ return;
176
+ }
177
+ const [entry] = Object.entries(bindings.images);
178
+ if (!entry) {
179
+ return;
180
+ }
181
+ const [bindingName, binding] = entry;
182
+ const normalized = normalizeImagesBinding(bindingName, binding);
183
+ return {
184
+ binding: normalized.binding
185
+ };
186
+ }
187
+ function buildMediaConfig(bindings) {
188
+ if (!bindings.media) {
189
+ return;
190
+ }
191
+ const [entry] = Object.entries(bindings.media);
192
+ if (!entry) {
193
+ return;
194
+ }
195
+ const [bindingName, binding] = entry;
196
+ const normalized = normalizeMediaBinding(bindingName, binding);
197
+ return {
198
+ binding: normalized.binding
199
+ };
200
+ }
201
+ function buildArtifactsConfig(bindings) {
202
+ if (!bindings.artifacts) {
203
+ return;
204
+ }
205
+ return Object.fromEntries(Object.entries(bindings.artifacts).map(([bindingName, binding]) => {
206
+ const normalized = normalizeArtifactsBinding(binding);
207
+ return [
208
+ bindingName,
209
+ {
210
+ namespace: normalized.namespace
211
+ }
212
+ ];
213
+ }));
214
+ }
215
+ function buildAiSearchNamespacesConfig(bindings) {
216
+ if (!bindings.aiSearchNamespaces) {
217
+ return;
218
+ }
219
+ return Object.fromEntries(Object.entries(bindings.aiSearchNamespaces).map(([bindingName, binding]) => [
220
+ bindingName,
221
+ {
222
+ namespace: binding.namespace
223
+ }
224
+ ]));
225
+ }
226
+ function buildAiSearchInstancesConfig(bindings) {
227
+ if (!bindings.aiSearch) {
228
+ return;
229
+ }
230
+ return Object.fromEntries(Object.entries(bindings.aiSearch).map(([bindingName, binding]) => [
231
+ bindingName,
232
+ {
233
+ instance_name: binding.instanceName
234
+ }
235
+ ]));
236
+ }
237
+ function buildSecretsStoreConfig(bindings, defaultSecretsStoreId, excludedBindingNames = new Set) {
238
+ if (!bindings.secretsStore) {
239
+ return;
240
+ }
241
+ const entries = Object.entries(bindings.secretsStore).flatMap(([bindingName, binding]) => {
242
+ if (excludedBindingNames.has(bindingName)) {
243
+ return [];
244
+ }
245
+ const normalized = normalizeSecretsStoreBinding(binding, defaultSecretsStoreId, bindingName);
246
+ return [[
247
+ bindingName,
248
+ {
249
+ store_id: normalized.storeId,
250
+ secret_name: normalized.secretName
251
+ }
252
+ ]];
253
+ });
254
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
255
+ }
256
+ function buildSendEmailConfig(bindings) {
257
+ if (!bindings.sendEmail) {
258
+ return;
259
+ }
260
+ return {
261
+ send_email: Object.entries(bindings.sendEmail).map(([name, binding]) => ({
262
+ name,
263
+ ...binding.destinationAddress && {
264
+ destination_address: binding.destinationAddress
265
+ },
266
+ ...binding.allowedDestinationAddresses && {
267
+ allowed_destination_addresses: binding.allowedDestinationAddresses
268
+ },
269
+ ...binding.allowedSenderAddresses && {
270
+ allowed_sender_addresses: binding.allowedSenderAddresses
271
+ }
272
+ }))
273
+ };
274
+ }
275
+
276
+ // src/test/resolve-service-bindings.ts
277
+ function getBunRuntime() {
278
+ const g = globalThis;
279
+ if (typeof g.Bun === "object" && g.Bun !== null) {
280
+ return g.Bun;
281
+ }
282
+ return;
283
+ }
284
+ function discoverDOFilesSync(dir, pattern = DEFAULT_DO_PATTERN) {
285
+ const classToPath = new Map;
286
+ try {
287
+ const files = findFilesSync(pattern, { cwd: dir });
288
+ for (const filePath of files) {
289
+ try {
290
+ const code = readFileSync(filePath, "utf-8");
291
+ const classNames = findDurableObjectClasses(code);
292
+ for (const className of classNames) {
293
+ if (!classToPath.has(className)) {
294
+ classToPath.set(className, filePath);
295
+ }
296
+ }
297
+ } catch {}
298
+ }
299
+ } catch {}
300
+ return classToPath;
301
+ }
302
+ var bundleCache = new Map;
303
+ function clearBundleCache() {
304
+ bundleCache.clear();
305
+ }
306
+ function findDefaultServiceWorkerEntrypoint(refConfigDir) {
307
+ for (const candidate of ["src/worker.ts", "src/worker.js"]) {
308
+ const absolutePath = resolve(refConfigDir, candidate);
309
+ if (existsSync(absolutePath)) {
310
+ return absolutePath;
311
+ }
312
+ }
313
+ return null;
314
+ }
315
+ function buildRawServiceBindings(services) {
316
+ if (!services || Object.keys(services).length === 0) {
317
+ return;
318
+ }
319
+ return Object.fromEntries(Object.entries(services).map(([bindingName, binding]) => [
320
+ bindingName,
321
+ {
322
+ name: binding.service,
323
+ ...binding.entrypoint && { entrypoint: binding.entrypoint }
324
+ }
325
+ ]));
326
+ }
327
+ function buildReferencedWorkerRuntimeConfig(config) {
328
+ const bindings = config.bindings ?? {};
329
+ const queueProducers = buildQueueProducers(bindings);
330
+ const queueConsumers = buildQueueConsumers(bindings);
331
+ const rateLimits = buildRateLimitsConfig(bindings);
332
+ const versionMetadata = buildVersionMetadataConfig(bindings);
333
+ const workerLoaders = buildWorkerLoadersConfig(bindings);
334
+ const mtlsCertificates = buildMtlsCertificatesConfig(bindings);
335
+ const dispatchNamespaces = buildDispatchNamespacesConfig(bindings);
336
+ const workflows = buildWorkflowsConfig(bindings);
337
+ const pipelines = buildPipelinesConfig(bindings);
338
+ const hyperdrives = buildHyperdrivesConfig(bindings);
339
+ const media = buildMediaConfig(bindings);
340
+ const artifacts = buildArtifactsConfig(bindings);
341
+ const aiSearchNamespaces = buildAiSearchNamespacesConfig(bindings);
342
+ const aiSearchInstances = buildAiSearchInstancesConfig(bindings);
343
+ const secretsStoreSecrets = buildSecretsStoreConfig(bindings, config.secretsStoreId);
344
+ const email = buildSendEmailConfig(bindings);
345
+ const serviceBindings = buildRawServiceBindings(bindings.services);
346
+ return {
347
+ ...config.compatibilityFlags && { compatibilityFlags: config.compatibilityFlags },
348
+ ...config.vars && { bindings: config.vars },
349
+ ...bindings.kv && {
350
+ kvNamespaces: Object.fromEntries(Object.entries(bindings.kv).map(([bindingName, bindingConfig]) => [
351
+ bindingName,
352
+ getLocalKVNamespaceIdentifier(bindingConfig)
353
+ ]))
354
+ },
355
+ ...bindings.r2 && { r2Buckets: bindings.r2 },
356
+ ...bindings.d1 && {
357
+ d1Databases: Object.fromEntries(Object.entries(bindings.d1).map(([bindingName, bindingConfig]) => [
358
+ bindingName,
359
+ getLocalD1DatabaseIdentifier(bindingConfig)
360
+ ]))
361
+ },
362
+ ...queueProducers && { queueProducers },
363
+ ...queueConsumers && { queueConsumers },
364
+ ...rateLimits && { ratelimits: rateLimits },
365
+ ...versionMetadata && { versionMetadata },
366
+ ...workerLoaders && { workerLoaders },
367
+ ...mtlsCertificates && { mtlsCertificates },
368
+ ...dispatchNamespaces && { dispatchNamespaces },
369
+ ...workflows && { workflows },
370
+ ...pipelines && { pipelines },
371
+ ...hyperdrives && { hyperdrives },
372
+ ...media && { media },
373
+ ...artifacts && { artifacts },
374
+ ...aiSearchNamespaces && { aiSearchNamespaces },
375
+ ...aiSearchInstances && { aiSearchInstances },
376
+ ...secretsStoreSecrets && { secretsStoreSecrets },
377
+ ...email && { email },
378
+ ...serviceBindings && { serviceBindings }
379
+ };
380
+ }
381
+ function normalizeReferencedConfig(config) {
382
+ return configSchema.parse(config);
383
+ }
384
+ function resolveReferencedConfigDir(ref, parentConfigDir) {
385
+ const configPath = ref.configPath;
386
+ if (!configPath || configPath === "<resolved>") {
387
+ return null;
388
+ }
389
+ return dirname(resolvePackageSpecifier(configPath, parentConfigDir));
390
+ }
391
+ async function resolveReferencedLocalDurableObjects(config, configDir, workerName, serviceBindings = {}) {
392
+ const doPattern = config.files?.durableObjects;
393
+ const dosConfig = config.bindings?.durableObjects;
394
+ if (typeof doPattern !== "string" || !dosConfig || Object.keys(dosConfig).length === 0) {
395
+ return { workers: [], bindings: {} };
396
+ }
397
+ const discoveredDOs = discoverDOFilesSync(configDir, doPattern);
398
+ const doClasses = [];
399
+ for (const [bindingName, rawDoConfig] of Object.entries(dosConfig)) {
400
+ const doConfig = normalizeDOBinding(rawDoConfig);
401
+ if (doConfig.kind !== "local") {
402
+ continue;
403
+ }
404
+ const scriptPath = discoveredDOs.get(doConfig.className);
405
+ if (!scriptPath) {
406
+ console.warn(`[devflare] DO "${bindingName}" (class: ${doConfig.className}) not found in files.durableObjects for "${workerName}"`);
407
+ continue;
408
+ }
409
+ doClasses.push({ bindingName, className: doConfig.className, scriptPath });
410
+ }
411
+ if (doClasses.length === 0) {
412
+ return { workers: [], bindings: {} };
413
+ }
414
+ const doWorkerName = `${workerName}-durable-objects`;
415
+ const script = await bundleDOClasses(doClasses, doWorkerName);
416
+ if (!script) {
417
+ return { workers: [], bindings: {} };
418
+ }
419
+ const durableObjects = Object.fromEntries(doClasses.map((do_) => [do_.bindingName, do_.className]));
420
+ const runtimeConfig = buildReferencedWorkerRuntimeConfig(config);
421
+ const mergedServiceBindings = {
422
+ ...runtimeConfig.serviceBindings ?? {},
423
+ ...serviceBindings
424
+ };
425
+ return {
426
+ workers: [{
427
+ name: doWorkerName,
428
+ script,
429
+ modules: true,
430
+ compatibilityDate: config.compatibilityDate,
431
+ ...runtimeConfig,
432
+ ...Object.keys(mergedServiceBindings).length > 0 && {
433
+ serviceBindings: mergedServiceBindings
434
+ },
435
+ durableObjects
436
+ }],
437
+ bindings: Object.fromEntries(doClasses.map((do_) => [
438
+ do_.bindingName,
439
+ {
440
+ className: do_.className,
441
+ scriptName: doWorkerName
442
+ }
443
+ ]))
444
+ };
445
+ }
446
+ function hasServiceBindings(config) {
447
+ const services = config.bindings?.services;
448
+ if (!services)
449
+ return false;
450
+ return Object.keys(services).length > 0;
451
+ }
452
+ async function resolveServiceBindings(config, configDir, seenWorkers = new Set) {
453
+ const services = config.bindings?.services;
454
+ if (!services) {
455
+ return { workers: [], primaryServiceBindings: {} };
456
+ }
457
+ const workersByName = new Map;
458
+ const primaryServiceBindings = {};
459
+ for (const [bindingName, binding] of Object.entries(services)) {
460
+ const workerBinding = binding;
461
+ const ref = workerBinding.__ref;
462
+ if (ref) {
463
+ if ("__import" in ref && typeof ref.__import === "function") {
464
+ await ref.resolve();
465
+ }
466
+ const workerName = ref.name;
467
+ const entrypoint = workerBinding.entrypoint;
468
+ if (!workersByName.has(workerName) && !seenWorkers.has(workerName)) {
469
+ const refConfig = normalizeReferencedConfig(ref.config);
470
+ const worker = await resolveRefWorker(ref, entrypoint, configDir, refConfig);
471
+ if (worker) {
472
+ const refConfigDir = resolveReferencedConfigDir(ref, configDir);
473
+ if (ref.config && refConfigDir) {
474
+ const nested = await resolveServiceBindings(refConfig, refConfigDir, new Set([...seenWorkers, workerName]));
475
+ worker.serviceBindings = {
476
+ ...worker.serviceBindings ?? {},
477
+ ...nested.primaryServiceBindings
478
+ };
479
+ for (const nestedWorker of nested.workers) {
480
+ if (!workersByName.has(nestedWorker.name)) {
481
+ workersByName.set(nestedWorker.name, nestedWorker);
482
+ }
483
+ }
484
+ const localDOs = await resolveReferencedLocalDurableObjects(refConfig, refConfigDir, workerName, nested.primaryServiceBindings);
485
+ worker.durableObjects = {
486
+ ...worker.durableObjects ?? {},
487
+ ...localDOs.bindings
488
+ };
489
+ for (const doWorker of localDOs.workers) {
490
+ if (!workersByName.has(doWorker.name)) {
491
+ workersByName.set(doWorker.name, doWorker);
492
+ }
493
+ }
494
+ }
495
+ workersByName.set(workerName, worker);
496
+ }
497
+ }
498
+ primaryServiceBindings[bindingName] = {
499
+ name: workerName,
500
+ ...entrypoint && { entrypoint }
501
+ };
502
+ } else {
503
+ primaryServiceBindings[bindingName] = {
504
+ name: workerBinding.service,
505
+ ...workerBinding.entrypoint && { entrypoint: workerBinding.entrypoint }
506
+ };
507
+ }
508
+ }
509
+ return {
510
+ workers: [...workersByName.values()],
511
+ primaryServiceBindings
512
+ };
513
+ }
514
+ async function resolveRefWorker(ref, _entrypoint, parentConfigDir, resolvedConfig) {
515
+ const config = resolvedConfig ?? normalizeReferencedConfig(ref.config);
516
+ if (!config)
517
+ return null;
518
+ const refConfigDir = resolveReferencedConfigDir(ref, parentConfigDir);
519
+ if (!refConfigDir) {
520
+ console.warn(`[devflare] Cannot resolve worker "${ref.name}" - configPath not available`);
521
+ return null;
522
+ }
523
+ const entrypoints = [];
524
+ const workerEntrypointPath = findDefaultServiceWorkerEntrypoint(refConfigDir);
525
+ if (workerEntrypointPath) {
526
+ entrypoints.push({
527
+ path: workerEntrypointPath,
528
+ className: "Worker",
529
+ isWorkerTs: true
530
+ });
531
+ }
532
+ if (config.files?.entrypoints !== false) {
533
+ const discoveredEntrypoints = discoverEntrypointsSync(refConfigDir, typeof config.files?.entrypoints === "string" ? config.files.entrypoints : undefined);
534
+ for (const ep of discoveredEntrypoints) {
535
+ entrypoints.push({
536
+ path: ep.filePath,
537
+ className: ep.className,
538
+ isWorkerTs: false
539
+ });
540
+ }
541
+ }
542
+ if (entrypoints.length === 0) {
543
+ console.warn(`[devflare] Worker "${ref.name}" has no entry points`);
544
+ return null;
545
+ }
546
+ const script = await bundleAllEntrypoints(entrypoints, ref.name);
547
+ if (!script)
548
+ return null;
549
+ return {
550
+ name: ref.name,
551
+ script,
552
+ modules: true,
553
+ compatibilityDate: config.compatibilityDate ?? "2025-01-01",
554
+ ...buildReferencedWorkerRuntimeConfig(config)
555
+ };
556
+ }
557
+ async function bundleAllEntrypoints(entrypoints, workerName) {
558
+ const cacheKey = entrypoints.map((ep) => `${ep.path}::${ep.className}`).join("|");
559
+ const cached = bundleCache.get(cacheKey);
560
+ if (cached) {
561
+ return cached;
562
+ }
563
+ const bun = getBunRuntime();
564
+ if (!bun) {
565
+ console.warn("[devflare] Bun runtime required for bundling worker scripts");
566
+ return null;
567
+ }
568
+ try {
569
+ const { readFileSync: readFileSync2, writeFileSync, mkdirSync, unlinkSync } = await import("fs");
570
+ const imports = [];
571
+ const exports = [];
572
+ let defaultExportClass = null;
573
+ for (let i = 0;i < entrypoints.length; i++) {
574
+ const ep = entrypoints[i];
575
+ const sourceCode = readFileSync2(ep.path, "utf-8");
576
+ if (ep.isWorkerTs) {
577
+ const result = transformWorkerEntrypoint(sourceCode, ep.path, {
578
+ className: ep.className,
579
+ injectContext: false
580
+ });
581
+ if (result) {
582
+ const tempDir2 = join(dirname(ep.path), ".devflare");
583
+ mkdirSync(tempDir2, { recursive: true });
584
+ const tempPath = join(tempDir2, `__${ep.className}_${i}.ts`);
585
+ writeFileSync(tempPath, result.code);
586
+ imports.push(`import { ${ep.className} } from '${tempPath.replace(/\\/g, "/")}'`);
587
+ exports.push(ep.className);
588
+ if (!defaultExportClass) {
589
+ defaultExportClass = ep.className;
590
+ }
591
+ }
592
+ } else {
593
+ imports.push(`import { ${ep.className} } from '${ep.path.replace(/\\/g, "/")}'`);
594
+ exports.push(ep.className);
595
+ }
596
+ }
597
+ const defaultExport = defaultExportClass ? `
598
+ export default ${defaultExportClass}` : "";
599
+ const entryCode = `
600
+ ${imports.join(`
601
+ `)}
602
+ export { ${exports.join(", ")} }${defaultExport}
603
+ `;
604
+ const tempDir = join(dirname(entrypoints[0].path), ".devflare");
605
+ mkdirSync(tempDir, { recursive: true });
606
+ const entryPath = join(tempDir, `__entry_${workerName}.ts`);
607
+ writeFileSync(entryPath, entryCode);
608
+ try {
609
+ const result = await bun.build({
610
+ entrypoints: [entryPath],
611
+ target: "browser",
612
+ format: "esm",
613
+ minify: false,
614
+ external: ["cloudflare:workers", "cloudflare:*"]
615
+ });
616
+ if (!result.success) {
617
+ console.warn(`[devflare] Failed to bundle worker "${workerName}": ${result.logs.join(`
618
+ `)}`);
619
+ return null;
620
+ }
621
+ const bundledCode = await result.outputs[0].text();
622
+ bundleCache.set(cacheKey, bundledCode);
623
+ return bundledCode;
624
+ } finally {
625
+ try {
626
+ unlinkSync(entryPath);
627
+ } catch {}
628
+ }
629
+ } catch (error) {
630
+ console.warn(`[devflare] Error bundling worker "${workerName}":`, error);
631
+ return null;
632
+ }
633
+ }
634
+ function hasCrossWorkerDOs(config) {
635
+ const dos = config.bindings?.durableObjects;
636
+ if (!dos)
637
+ return false;
638
+ for (const doConfig of Object.values(dos)) {
639
+ const normalized = normalizeDOBinding(doConfig);
640
+ if (normalized.__ref)
641
+ return true;
642
+ }
643
+ return false;
644
+ }
645
+ async function resolveDOBindings(config, configDir) {
646
+ const dos = config.bindings?.durableObjects;
647
+ if (!dos) {
648
+ return { workers: [], crossWorkerDOBindings: {} };
649
+ }
650
+ const workersByName = new Map;
651
+ const crossWorkerDOBindings = {};
652
+ for (const [bindingName, rawDoConfig] of Object.entries(dos)) {
653
+ const hasRef = typeof rawDoConfig === "object" && "__ref" in rawDoConfig;
654
+ if (!hasRef) {
655
+ continue;
656
+ }
657
+ const ref = rawDoConfig.__ref;
658
+ if ("__import" in ref && typeof ref.__import === "function") {
659
+ await ref.resolve();
660
+ }
661
+ const doConfig = normalizeDOBinding(rawDoConfig);
662
+ const workerName = ref.name;
663
+ if (!workersByName.has(workerName)) {
664
+ const worker = await resolveDORefWorker(ref, configDir);
665
+ if (worker) {
666
+ workersByName.set(workerName, worker);
667
+ }
668
+ }
669
+ crossWorkerDOBindings[bindingName] = {
670
+ className: doConfig.className,
671
+ scriptName: workerName
672
+ };
673
+ }
674
+ return {
675
+ workers: [...workersByName.values()],
676
+ crossWorkerDOBindings
677
+ };
678
+ }
679
+ async function resolveDORefWorker(ref, parentConfigDir) {
680
+ const config = ref.config;
681
+ if (!config)
682
+ return null;
683
+ const configPath = ref.configPath;
684
+ if (!configPath || configPath === "<resolved>") {
685
+ console.warn(`[devflare] Cannot resolve DO worker "${ref.name}" - configPath not available`);
686
+ return null;
687
+ }
688
+ const resolvedConfigPath = resolvePackageSpecifier(configPath, parentConfigDir);
689
+ const refConfigDir = dirname(resolvedConfigPath);
690
+ const dosConfig = config.bindings?.durableObjects;
691
+ if (!dosConfig || Object.keys(dosConfig).length === 0) {
692
+ console.warn(`[devflare] Referenced worker "${ref.name}" has no Durable Objects`);
693
+ return null;
694
+ }
695
+ const discoveredDOs = discoverDOFilesSync(refConfigDir);
696
+ const doClasses = [];
697
+ for (const [bindingName, rawDoConfig] of Object.entries(dosConfig)) {
698
+ const doConfig = normalizeDOBinding(rawDoConfig);
699
+ const className = doConfig.className;
700
+ const scriptName = doConfig.scriptName;
701
+ if (scriptName) {
702
+ const scriptPath = resolve(refConfigDir, "src", scriptName);
703
+ if (!existsSync(scriptPath)) {
704
+ const altPath = resolve(refConfigDir, scriptName);
705
+ if (!existsSync(altPath)) {
706
+ console.warn(`[devflare] DO script not found: ${scriptPath} or ${altPath}`);
707
+ continue;
708
+ }
709
+ doClasses.push({ bindingName, className, scriptPath: altPath });
710
+ } else {
711
+ doClasses.push({ bindingName, className, scriptPath });
712
+ }
713
+ } else {
714
+ const discoveredPath = discoveredDOs.get(className);
715
+ if (discoveredPath) {
716
+ doClasses.push({ bindingName, className, scriptPath: discoveredPath });
717
+ } else {
718
+ console.warn(`[devflare] DO "${bindingName}" (class: ${className}) not found in do.*.ts files in "${ref.name}"`);
719
+ continue;
720
+ }
721
+ }
722
+ }
723
+ if (doClasses.length === 0) {
724
+ console.warn(`[devflare] No valid DO classes found in "${ref.name}"`);
725
+ return null;
726
+ }
727
+ const script = await bundleDOClasses(doClasses, ref.name);
728
+ if (!script)
729
+ return null;
730
+ const durableObjects = {};
731
+ for (const do_ of doClasses) {
732
+ durableObjects[do_.bindingName] = do_.className;
733
+ }
734
+ return {
735
+ name: ref.name,
736
+ script,
737
+ modules: true,
738
+ compatibilityDate: config.compatibilityDate ?? "2025-01-01",
739
+ durableObjects
740
+ };
741
+ }
742
+ async function bundleDOClasses(doClasses, workerName) {
743
+ const cacheKey = `do:${doClasses.map((d) => `${d.scriptPath}::${d.className}`).join("|")}`;
744
+ const cached = bundleCache.get(cacheKey);
745
+ if (cached)
746
+ return cached;
747
+ const bun = getBunRuntime();
748
+ if (!bun) {
749
+ console.warn("[devflare] Bun runtime required for bundling DO classes");
750
+ return null;
751
+ }
752
+ try {
753
+ const { writeFileSync, mkdirSync, unlinkSync } = await import("fs");
754
+ const imports = doClasses.map((d) => `import { ${d.className} } from '${d.scriptPath.replace(/\\/g, "/")}'`).join(`
755
+ `);
756
+ const exports = doClasses.map((d) => d.className).join(", ");
757
+ const entryCode = `
758
+ ${imports}
759
+
760
+ // Re-export DO classes for Miniflare binding
761
+ export { ${exports} }
762
+
763
+ // Default export with fetch handler
764
+ export default {
765
+ async fetch(request, env) {
766
+ return new Response('DO Worker: ${workerName}')
767
+ }
768
+ }
769
+ `;
770
+ const tempDir = join(dirname(doClasses[0].scriptPath), ".devflare");
771
+ mkdirSync(tempDir, { recursive: true });
772
+ const entryPath = join(tempDir, `__do_entry_${workerName}.ts`);
773
+ writeFileSync(entryPath, entryCode);
774
+ try {
775
+ const result = await bun.build({
776
+ entrypoints: [entryPath],
777
+ target: "browser",
778
+ format: "esm",
779
+ minify: false,
780
+ external: ["cloudflare:workers", "cloudflare:*"]
781
+ });
782
+ if (!result.success) {
783
+ console.warn(`[devflare] Failed to bundle DO worker "${workerName}": ${result.logs.join(`
784
+ `)}`);
785
+ return null;
786
+ }
787
+ const bundledCode = await result.outputs[0].text();
788
+ bundleCache.set(cacheKey, bundledCode);
789
+ return bundledCode;
790
+ } finally {
791
+ try {
792
+ unlinkSync(entryPath);
793
+ } catch {}
794
+ }
795
+ } catch (error) {
796
+ console.warn(`[devflare] Error bundling DO worker "${workerName}":`, error);
797
+ return null;
798
+ }
799
+ }
800
+
801
+ // src/workflows/local-workflow-entrypoints.ts
802
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
803
+ import { join as join2, relative, resolve as resolve2 } from "pathe";
804
+ function findExportedClasses(code) {
805
+ const classes = [];
806
+ const classPattern = /export\s+class\s+(\w+)/g;
807
+ let match;
808
+ while ((match = classPattern.exec(code)) !== null) {
809
+ classes.push(match[1]);
810
+ }
811
+ return classes;
812
+ }
813
+ function toImportSpecifier(fromDir, filePath) {
814
+ const relativePath = relative(fromDir, filePath).replace(/\\/g, "/");
815
+ return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
816
+ }
817
+ async function discoverWorkflowClasses(config, configDir) {
818
+ const classToFilePath = new Map;
819
+ const workflowPatternConfig = config.files?.workflows;
820
+ const workflowPattern = typeof workflowPatternConfig === "string" ? workflowPatternConfig : DEFAULT_WORKFLOW_PATTERN;
821
+ if (workflowPatternConfig === false) {
822
+ return classToFilePath;
823
+ }
824
+ const files = await findFiles(workflowPattern, { cwd: configDir });
825
+ for (const filePath of files) {
826
+ try {
827
+ const code = await readFile(filePath, "utf-8");
828
+ for (const className of findExportedClasses(code)) {
829
+ classToFilePath.set(className, filePath);
830
+ }
831
+ } catch {}
832
+ }
833
+ return classToFilePath;
834
+ }
835
+ async function resolveLocalWorkflowEntrypoints(config, configDir) {
836
+ const workflows = config.bindings?.workflows;
837
+ if (!workflows || Object.keys(workflows).length === 0) {
838
+ return [];
839
+ }
840
+ const classToFilePath = await discoverWorkflowClasses(config, configDir);
841
+ const entrypoints = [];
842
+ for (const [bindingName, binding] of Object.entries(workflows)) {
843
+ const normalized = normalizeWorkflowBinding(binding);
844
+ if (normalized.scriptName) {
845
+ continue;
846
+ }
847
+ const scriptPath = classToFilePath.get(normalized.className);
848
+ if (!scriptPath) {
849
+ throw new Error(`Workflow binding ${bindingName} (className: '${normalized.className}') not found.
850
+ ` + `Either set files.workflows to match the workflow source file, or set scriptName when the workflow lives in another worker.`);
851
+ }
852
+ entrypoints.push({
853
+ bindingName,
854
+ className: normalized.className,
855
+ scriptPath
856
+ });
857
+ }
858
+ return entrypoints;
859
+ }
860
+ function buildWorkflowVirtualEntry(entrypoints, entryDir) {
861
+ const imports = entrypoints.map((entrypoint, index) => {
862
+ const importName = `__DevflareWorkflow${index}`;
863
+ const importPath = toImportSpecifier(entryDir, entrypoint.scriptPath);
864
+ return {
865
+ importName,
866
+ className: entrypoint.className,
867
+ line: `import { ${entrypoint.className} as ${importName} } from '${importPath}'`
868
+ };
869
+ });
870
+ const exports = imports.map((entrypoint) => {
871
+ return `export { ${entrypoint.importName} as ${entrypoint.className} }`;
872
+ });
873
+ return [...imports.map((entrypoint) => entrypoint.line), "", ...exports].join(`
874
+ `);
875
+ }
876
+ async function bundleWorkflowEntrypointScript(config, configDir, options = {}) {
877
+ const entrypoints = await resolveLocalWorkflowEntrypoints(config, configDir);
878
+ if (entrypoints.length === 0) {
879
+ return "";
880
+ }
881
+ const entryDir = resolve2(configDir, ".devflare", "workflow-entrypoints");
882
+ const entryPath = join2(entryDir, "__entry.ts");
883
+ const outFile = join2(entryDir, "index.js");
884
+ await mkdir(entryDir, { recursive: true });
885
+ await writeFile(entryPath, buildWorkflowVirtualEntry(entrypoints, entryDir));
886
+ await bundleWorkerEntry({
887
+ cwd: configDir,
888
+ inputFile: entryPath,
889
+ outFile,
890
+ rolldownOptions: config.rolldown?.options,
891
+ sourcemap: config.rolldown?.sourcemap,
892
+ minify: config.rolldown?.minify,
893
+ logger: options.logger
894
+ });
895
+ return await readFile(outFile, "utf-8");
896
+ }
897
+
898
+ export { buildQueueProducers, buildQueueConsumers, buildRateLimitsConfig, buildVersionMetadataConfig, buildWorkerLoadersConfig, buildMtlsCertificatesConfig, buildDispatchNamespacesConfig, buildWorkflowsConfig, buildPipelinesConfig, buildHyperdrivesConfig, buildImagesConfig, buildMediaConfig, buildArtifactsConfig, buildAiSearchNamespacesConfig, buildAiSearchInstancesConfig, buildSecretsStoreConfig, buildSendEmailConfig, bundleWorkflowEntrypointScript, clearBundleCache, hasServiceBindings, resolveServiceBindings, hasCrossWorkerDOs, resolveDOBindings };