devflare 1.0.0-next.1 → 1.0.0-next.10

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 (123) hide show
  1. package/LLM.md +775 -637
  2. package/R2.md +200 -0
  3. package/README.md +285 -514
  4. package/bin/devflare.js +8 -8
  5. package/dist/{account-rvrj687w.js → account-8psavtg6.js} +27 -4
  6. package/dist/bridge/miniflare.d.ts +6 -0
  7. package/dist/bridge/miniflare.d.ts.map +1 -1
  8. package/dist/bridge/proxy.d.ts +5 -6
  9. package/dist/bridge/proxy.d.ts.map +1 -1
  10. package/dist/bridge/server.d.ts.map +1 -1
  11. package/dist/browser.d.ts +50 -0
  12. package/dist/browser.d.ts.map +1 -0
  13. package/dist/{build-mnf6v8gd.js → build-k36xrzvy.js} +26 -7
  14. package/dist/bundler/do-bundler.d.ts +7 -0
  15. package/dist/bundler/do-bundler.d.ts.map +1 -1
  16. package/dist/cli/commands/account.d.ts.map +1 -1
  17. package/dist/cli/commands/build.d.ts.map +1 -1
  18. package/dist/cli/commands/deploy.d.ts.map +1 -1
  19. package/dist/cli/commands/dev.d.ts.map +1 -1
  20. package/dist/cli/commands/doctor.d.ts.map +1 -1
  21. package/dist/cli/commands/init.d.ts.map +1 -1
  22. package/dist/cli/commands/types.d.ts.map +1 -1
  23. package/dist/cli/config-path.d.ts +5 -0
  24. package/dist/cli/config-path.d.ts.map +1 -0
  25. package/dist/cli/index.d.ts.map +1 -1
  26. package/dist/cli/package-metadata.d.ts +16 -0
  27. package/dist/cli/package-metadata.d.ts.map +1 -0
  28. package/dist/config/compiler.d.ts +7 -0
  29. package/dist/config/compiler.d.ts.map +1 -1
  30. package/dist/config/index.d.ts +1 -1
  31. package/dist/config/index.d.ts.map +1 -1
  32. package/dist/config/schema.d.ts +2575 -1221
  33. package/dist/config/schema.d.ts.map +1 -1
  34. package/dist/{deploy-nhceck39.js → deploy-dbvfq8vq.js} +33 -15
  35. package/dist/{dev-qnxet3j9.js → dev-rk8p6pse.js} +900 -234
  36. package/dist/dev-server/miniflare-log.d.ts +12 -0
  37. package/dist/dev-server/miniflare-log.d.ts.map +1 -0
  38. package/dist/dev-server/runtime-stdio.d.ts +8 -0
  39. package/dist/dev-server/runtime-stdio.d.ts.map +1 -0
  40. package/dist/dev-server/server.d.ts +2 -0
  41. package/dist/dev-server/server.d.ts.map +1 -1
  42. package/dist/dev-server/vite-utils.d.ts +37 -0
  43. package/dist/dev-server/vite-utils.d.ts.map +1 -0
  44. package/dist/{doctor-e8fy6fj5.js → doctor-06y8nxd4.js} +73 -50
  45. package/dist/{durable-object-t4kbb0yt.js → durable-object-yt8v1dyn.js} +1 -1
  46. package/dist/index-05fyzwne.js +195 -0
  47. package/dist/index-1p814k7s.js +227 -0
  48. package/dist/{index-hcex3rgh.js → index-1phx14av.js} +84 -7
  49. package/dist/{index-tk6ej9dj.js → index-2q3pmzrx.js} +12 -16
  50. package/dist/{index-pf5s73n9.js → index-59df49vn.js} +11 -281
  51. package/dist/index-5yxg30va.js +304 -0
  52. package/dist/index-62b3gt2g.js +12 -0
  53. package/dist/index-6h8xbs75.js +44 -0
  54. package/dist/{index-67qcae0f.js → index-6v3wjg1r.js} +16 -1
  55. package/dist/index-8gtqgb3q.js +529 -0
  56. package/dist/{index-gz1gndna.js → index-9wt9x09k.js} +42 -62
  57. package/dist/index-fef08w43.js +231 -0
  58. package/dist/{index-ep3445yc.js → index-jht2j546.js} +393 -170
  59. package/dist/index-k7r18na8.js +0 -0
  60. package/dist/{index-m2q41jwa.js → index-n932ytmq.js} +9 -1
  61. package/dist/index-pwgyy2q9.js +39 -0
  62. package/dist/{index-07q6yxyc.js → index-v8vvsn9x.js} +1 -0
  63. package/dist/index-vky23txa.js +70 -0
  64. package/dist/index-vs49yxn4.js +322 -0
  65. package/dist/{index-z14anrqp.js → index-wfbfz02q.js} +14 -15
  66. package/dist/index-ws68xvq2.js +311 -0
  67. package/dist/index-y1d8za14.js +196 -0
  68. package/dist/{init-f9mgmew3.js → init-na2atvz2.js} +42 -55
  69. package/dist/router/types.d.ts +24 -0
  70. package/dist/router/types.d.ts.map +1 -0
  71. package/dist/runtime/context.d.ts +249 -8
  72. package/dist/runtime/context.d.ts.map +1 -1
  73. package/dist/runtime/exports.d.ts +50 -55
  74. package/dist/runtime/exports.d.ts.map +1 -1
  75. package/dist/runtime/index.d.ts +8 -1
  76. package/dist/runtime/index.d.ts.map +1 -1
  77. package/dist/runtime/middleware.d.ts +77 -60
  78. package/dist/runtime/middleware.d.ts.map +1 -1
  79. package/dist/runtime/router.d.ts +7 -0
  80. package/dist/runtime/router.d.ts.map +1 -0
  81. package/dist/runtime/validation.d.ts +1 -1
  82. package/dist/runtime/validation.d.ts.map +1 -1
  83. package/dist/src/browser.js +150 -0
  84. package/dist/src/cli/index.js +10 -0
  85. package/dist/{cloudflare → src/cloudflare}/index.js +3 -3
  86. package/dist/{decorators → src/decorators}/index.js +2 -2
  87. package/dist/src/index.js +132 -0
  88. package/dist/src/runtime/index.js +111 -0
  89. package/dist/{sveltekit → src/sveltekit}/index.js +14 -6
  90. package/dist/{test → src/test}/index.js +22 -13
  91. package/dist/{vite → src/vite}/index.js +128 -59
  92. package/dist/sveltekit/platform.d.ts.map +1 -1
  93. package/dist/test/bridge-context.d.ts +5 -2
  94. package/dist/test/bridge-context.d.ts.map +1 -1
  95. package/dist/test/cf.d.ts +25 -11
  96. package/dist/test/cf.d.ts.map +1 -1
  97. package/dist/test/email.d.ts +16 -7
  98. package/dist/test/email.d.ts.map +1 -1
  99. package/dist/test/queue.d.ts.map +1 -1
  100. package/dist/test/resolve-service-bindings.d.ts.map +1 -1
  101. package/dist/test/scheduled.d.ts.map +1 -1
  102. package/dist/test/simple-context.d.ts +1 -1
  103. package/dist/test/simple-context.d.ts.map +1 -1
  104. package/dist/test/tail.d.ts +2 -1
  105. package/dist/test/tail.d.ts.map +1 -1
  106. package/dist/test/worker.d.ts +6 -0
  107. package/dist/test/worker.d.ts.map +1 -1
  108. package/dist/transform/durable-object.d.ts.map +1 -1
  109. package/dist/transform/worker-entrypoint.d.ts.map +1 -1
  110. package/dist/{types-5nyrz1sz.js → types-x9q7t491.js} +30 -16
  111. package/dist/utils/entrypoint-discovery.d.ts +6 -3
  112. package/dist/utils/entrypoint-discovery.d.ts.map +1 -1
  113. package/dist/utils/send-email.d.ts +15 -0
  114. package/dist/utils/send-email.d.ts.map +1 -0
  115. package/dist/vite/plugin.d.ts.map +1 -1
  116. package/dist/worker-entry/composed-worker.d.ts +13 -0
  117. package/dist/worker-entry/composed-worker.d.ts.map +1 -0
  118. package/dist/worker-entry/routes.d.ts +22 -0
  119. package/dist/worker-entry/routes.d.ts.map +1 -0
  120. package/dist/{worker-entrypoint-m9th0rg0.js → worker-entrypoint-c259fmfs.js} +1 -1
  121. package/package.json +21 -19
  122. package/dist/index.js +0 -298
  123. package/dist/runtime/index.js +0 -111
File without changes
@@ -9,7 +9,10 @@ import {
9
9
  parseJsonMsg,
10
10
  serializeValue,
11
11
  stringifyJsonMsg
12
- } from "./index-pf5s73n9.js";
12
+ } from "./index-59df49vn.js";
13
+ import {
14
+ normalizeSendEmailMessage
15
+ } from "./index-fef08w43.js";
13
16
 
14
17
  // src/bridge/server.ts
15
18
  var server_default = {
@@ -176,6 +179,8 @@ async function executeRpcMethod(method, params, env, ctx) {
176
179
  return executeDoFetch(env, params[0], params[1], params[2]);
177
180
  case "stub.rpc":
178
181
  return executeDoRpc(env, params[0], params[1], params[2], params[3]);
182
+ case "email.send":
183
+ return executeSendEmail(binding, params[0]);
179
184
  case "send":
180
185
  return binding.send(params[0], params[1]);
181
186
  case "sendBatch":
@@ -189,6 +194,9 @@ async function executeRpcMethod(method, params, env, ctx) {
189
194
  throw new Error(`Unknown operation: ${method}`);
190
195
  }
191
196
  }
197
+ async function executeSendEmail(binding, message) {
198
+ return binding.send(normalizeSendEmailMessage(message));
199
+ }
192
200
  function serializeR2Object(obj) {
193
201
  if (!obj)
194
202
  return null;
@@ -0,0 +1,39 @@
1
+ import {
2
+ resolveConfigPath
3
+ } from "./index-1phx14av.js";
4
+
5
+ // src/cli/config-path.ts
6
+ import { stat } from "node:fs/promises";
7
+ var CONFIG_FILE_EXTENSIONS = [".ts", ".mts", ".js", ".mjs"];
8
+ var SUPPORTED_CONFIG_FILENAMES = CONFIG_FILE_EXTENSIONS.map((extension) => `devflare.config${extension}`);
9
+ function hasKnownConfigExtension(filePath) {
10
+ return CONFIG_FILE_EXTENSIONS.some((extension) => filePath.endsWith(extension));
11
+ }
12
+ async function getExistingFilePath(filePath) {
13
+ try {
14
+ const fileStat = await stat(filePath);
15
+ return fileStat.isFile() ? filePath : null;
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ async function resolveConfigCandidatePath(candidatePath) {
21
+ const candidates = [candidatePath];
22
+ if (!hasKnownConfigExtension(candidatePath)) {
23
+ for (const extension of CONFIG_FILE_EXTENSIONS) {
24
+ candidates.push(`${candidatePath}${extension}`);
25
+ }
26
+ }
27
+ for (const candidate of candidates) {
28
+ const existingFilePath = await getExistingFilePath(candidate);
29
+ if (existingFilePath) {
30
+ return existingFilePath;
31
+ }
32
+ }
33
+ return await resolveConfigPath(candidatePath) ?? null;
34
+ }
35
+ function formatSupportedConfigFilenames() {
36
+ return SUPPORTED_CONFIG_FILENAMES.join(", ");
37
+ }
38
+
39
+ export { resolveConfigCandidatePath, formatSupportedConfigFilenames };
@@ -165,4 +165,5 @@ function serviceBinding(refOrLegacy, options) {
165
165
  __ref: refOrLegacy
166
166
  };
167
167
  }
168
+
168
169
  export { defineConfig, ref, resolveRef, serviceBinding };
@@ -0,0 +1,70 @@
1
+ import {
2
+ getContextOrNull
3
+ } from "./index-5yxg30va.js";
4
+ import {
5
+ bridgeEnv
6
+ } from "./index-59df49vn.js";
7
+
8
+ // src/env.ts
9
+ var testContextEnv = null;
10
+ var testContextDispose = null;
11
+ function __setTestContext(envBindings, dispose) {
12
+ testContextEnv = envBindings;
13
+ testContextDispose = dispose;
14
+ }
15
+ function __clearTestContext() {
16
+ testContextEnv = null;
17
+ testContextDispose = null;
18
+ }
19
+ var env = new Proxy({}, {
20
+ get(_target, prop) {
21
+ if (prop === "dispose") {
22
+ return async () => {
23
+ if (testContextDispose) {
24
+ await testContextDispose();
25
+ __clearTestContext();
26
+ }
27
+ };
28
+ }
29
+ const ctx = getContextOrNull();
30
+ if (ctx?.env) {
31
+ return ctx.env[prop];
32
+ }
33
+ if (testContextEnv) {
34
+ return testContextEnv[prop];
35
+ }
36
+ return bridgeEnv[prop];
37
+ },
38
+ has(_target, prop) {
39
+ if (prop === "dispose")
40
+ return true;
41
+ const ctx = getContextOrNull();
42
+ if (ctx?.env) {
43
+ return prop in ctx.env;
44
+ }
45
+ if (testContextEnv) {
46
+ return prop in testContextEnv;
47
+ }
48
+ return prop in bridgeEnv;
49
+ },
50
+ ownKeys(_target) {
51
+ const ctx = getContextOrNull();
52
+ if (ctx?.env) {
53
+ return Reflect.ownKeys(ctx.env);
54
+ }
55
+ if (testContextEnv) {
56
+ return Reflect.ownKeys(testContextEnv);
57
+ }
58
+ return Reflect.ownKeys(bridgeEnv);
59
+ },
60
+ getOwnPropertyDescriptor(_target, prop) {
61
+ if (prop === "dispose") {
62
+ return { configurable: true, enumerable: false, writable: false };
63
+ }
64
+ const ctx = getContextOrNull();
65
+ const source = ctx?.env ?? testContextEnv ?? bridgeEnv;
66
+ return Reflect.getOwnPropertyDescriptor(source, prop);
67
+ }
68
+ });
69
+
70
+ export { __setTestContext, __clearTestContext, env };
@@ -0,0 +1,322 @@
1
+ import {
2
+ normalizeDOBinding
3
+ } from "./index-1phx14av.js";
4
+ import {
5
+ __require
6
+ } from "./index-37x76zdn.js";
7
+
8
+ // src/bridge/miniflare.ts
9
+ function generateGatewayScript() {
10
+ return `
11
+ // Gateway Worker — Provides RPC access to all bindings
12
+ export default {
13
+ async fetch(request, env, ctx) {
14
+ const url = new URL(request.url)
15
+
16
+ // Health check
17
+ if (url.pathname === '/_devflare/health') {
18
+ return new Response(JSON.stringify({ status: 'ok', bindings: Object.keys(env) }), {
19
+ headers: { 'Content-Type': 'application/json' }
20
+ })
21
+ }
22
+
23
+ // RPC endpoint
24
+ if (url.pathname === '/_devflare/rpc' && request.method === 'POST') {
25
+ try {
26
+ const { method, params } = await request.json()
27
+ const result = await executeRpc(env, method, params)
28
+ return new Response(JSON.stringify({ ok: true, result }), {
29
+ headers: { 'Content-Type': 'application/json' }
30
+ })
31
+ } catch (error) {
32
+ return new Response(JSON.stringify({
33
+ ok: false,
34
+ error: { code: 'RPC_ERROR', message: error.message }
35
+ }), {
36
+ status: 500,
37
+ headers: { 'Content-Type': 'application/json' }
38
+ })
39
+ }
40
+ }
41
+
42
+ return new Response('Devflare Gateway', { status: 200 })
43
+ }
44
+ }
45
+
46
+ async function executeRpc(env, method, params) {
47
+ const [bindingName, ...methodPath] = method.split('.')
48
+ const binding = env[bindingName]
49
+ const RAW_EMAIL = 'EmailMessage::raw'
50
+
51
+ if (!binding) {
52
+ throw new Error(\`Binding "\${bindingName}" not found\`)
53
+ }
54
+
55
+ const methodName = methodPath.join('.')
56
+
57
+ // KV operations
58
+ if (methodName === 'get') return binding.get(params[0], params[1])
59
+ if (methodName === 'put') return binding.put(params[0], params[1], params[2])
60
+ if (methodName === 'delete') return binding.delete(params[0])
61
+ if (methodName === 'list') return binding.list(params[0])
62
+ if (methodName === 'getWithMetadata') return binding.getWithMetadata(params[0], params[1])
63
+
64
+ // R2 operations
65
+ if (methodName === 'head') return binding.head(params[0])
66
+ if (methodName === 'r2.get') return serializeR2Object(await binding.get(params[0], params[1]))
67
+ if (methodName === 'r2.put') return serializeR2Object(await binding.put(params[0], params[1], params[2]))
68
+ if (methodName === 'r2.delete') return binding.delete(params[0])
69
+ if (methodName === 'r2.list') return serializeR2Objects(await binding.list(params[0]))
70
+
71
+ // D1 operations
72
+ if (methodName === 'exec') return binding.exec(params[0])
73
+ if (methodName === 'batch') {
74
+ const statements = params[0].map(s => binding.prepare(s.sql).bind(...(s.bindings || [])))
75
+ return binding.batch(statements)
76
+ }
77
+ if (methodName.startsWith('stmt.')) {
78
+ const [, stmtMethod] = methodName.split('.')
79
+ const [sql, ...bindings] = params
80
+ const stmt = binding.prepare(sql).bind(...bindings.slice(0, -1))
81
+
82
+ if (stmtMethod === 'first') return stmt.first(bindings[bindings.length - 1])
83
+ if (stmtMethod === 'all') return stmt.all()
84
+ if (stmtMethod === 'run') return stmt.run()
85
+ if (stmtMethod === 'raw') return stmt.raw(bindings[bindings.length - 1])
86
+ }
87
+
88
+ // DO operations
89
+ if (methodName === 'idFromName') {
90
+ const id = binding.idFromName(params[0])
91
+ return { __type: 'DOId', hex: id.toString() }
92
+ }
93
+ if (methodName === 'idFromString') {
94
+ const id = binding.idFromString(params[0])
95
+ return { __type: 'DOId', hex: id.toString() }
96
+ }
97
+ if (methodName === 'newUniqueId') {
98
+ const id = binding.newUniqueId(params[0])
99
+ return { __type: 'DOId', hex: id.toString() }
100
+ }
101
+ if (methodName === 'stub.fetch') {
102
+ const [, doId, serializedReq] = params
103
+ const id = binding.idFromString(doId.hex)
104
+ const stub = binding.get(id)
105
+ const response = await stub.fetch(new Request(serializedReq.url, {
106
+ method: serializedReq.method,
107
+ headers: serializedReq.headers,
108
+ body: serializedReq.body?.type === 'bytes' ? atob(serializedReq.body.data) : undefined
109
+ }))
110
+ return serializeResponse(response)
111
+ }
112
+ if (methodName === 'stub.rpc') {
113
+ // DO RPC: Call a method on the DO instance
114
+ const [, doId, rpcMethod, rpcParams] = params
115
+ const id = binding.idFromString(doId.hex)
116
+ const stub = binding.get(id)
117
+
118
+ // Use fetch to call the RPC endpoint
119
+ const response = await stub.fetch(new Request('http://do/_rpc', {
120
+ method: 'POST',
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify({ method: rpcMethod, params: rpcParams })
123
+ }))
124
+
125
+ const result = await response.json()
126
+ if (!result.ok) throw new Error(result.error?.message || 'RPC failed')
127
+ return result.result
128
+ }
129
+
130
+ // Queue operations
131
+ if (methodName === 'send') return binding.send(params[0], params[1])
132
+ if (methodName === 'sendBatch') return binding.sendBatch(params[0], params[1])
133
+
134
+ // Send Email operations
135
+ if (methodName === 'email.send') {
136
+ const message = params[0]
137
+ if (message && typeof message === 'object' && 'from' in message && 'to' in message && 'raw' in message) {
138
+ return binding.send({
139
+ from: message.from,
140
+ to: message.to,
141
+ [RAW_EMAIL]: createEmailMessageRaw(message.raw)
142
+ })
143
+ }
144
+ return binding.send(message)
145
+ }
146
+
147
+ // Generic fallback
148
+ if (typeof binding[methodName] === 'function') {
149
+ return binding[methodName](...params)
150
+ }
151
+
152
+ throw new Error(\`Unknown method: \${method}\`)
153
+ }
154
+
155
+ function createEmailMessageRaw(raw) {
156
+ if (typeof raw === 'string' || raw instanceof ReadableStream) {
157
+ return raw
158
+ }
159
+ if (raw instanceof ArrayBuffer || raw instanceof Uint8Array) {
160
+ return new Response(raw).body
161
+ }
162
+ throw new Error('Unsupported EmailMessage raw payload')
163
+ }
164
+
165
+ function serializeResponse(response) {
166
+ return {
167
+ status: response.status,
168
+ statusText: response.statusText,
169
+ headers: [...response.headers.entries()],
170
+ body: null // Will be streamed separately for large bodies
171
+ }
172
+ }
173
+
174
+ function serializeR2Object(obj) {
175
+ if (!obj) return null
176
+ return {
177
+ key: obj.key,
178
+ version: obj.version,
179
+ size: obj.size,
180
+ etag: obj.etag,
181
+ httpEtag: obj.httpEtag,
182
+ uploaded: obj.uploaded?.toISOString(),
183
+ httpMetadata: obj.httpMetadata,
184
+ customMetadata: obj.customMetadata
185
+ }
186
+ }
187
+
188
+ function serializeR2Objects(result) {
189
+ if (!result) return null
190
+ return {
191
+ objects: result.objects.map(serializeR2Object),
192
+ truncated: result.truncated,
193
+ cursor: result.cursor,
194
+ delimitedPrefixes: result.delimitedPrefixes
195
+ }
196
+ }
197
+ `;
198
+ }
199
+ async function startMiniflare(options = {}) {
200
+ const { Miniflare, Log, LogLevel } = await import("miniflare");
201
+ const port = options.port ?? 8787;
202
+ const persistPath = options.persistPath ?? ".devflare/data";
203
+ const mfConfig = {
204
+ modules: true,
205
+ script: generateGatewayScript(),
206
+ port,
207
+ host: "127.0.0.1",
208
+ log: options.verbose ? new Log(LogLevel.DEBUG) : new Log(LogLevel.WARN),
209
+ compatibilityDate: options.compatibilityDate ?? "2024-01-01",
210
+ compatibilityFlags: options.compatibilityFlags ?? []
211
+ };
212
+ const hasBindings = (val) => {
213
+ if (!val)
214
+ return false;
215
+ if (Array.isArray(val))
216
+ return val.length > 0;
217
+ return Object.keys(val).length > 0;
218
+ };
219
+ if (hasBindings(options.kvNamespaces)) {
220
+ mfConfig.kvNamespaces = options.kvNamespaces;
221
+ if (options.persist) {
222
+ mfConfig.kvPersist = `${persistPath}/kv`;
223
+ }
224
+ }
225
+ if (hasBindings(options.r2Buckets)) {
226
+ mfConfig.r2Buckets = options.r2Buckets;
227
+ if (options.persist) {
228
+ mfConfig.r2Persist = `${persistPath}/r2`;
229
+ }
230
+ }
231
+ if (hasBindings(options.d1Databases)) {
232
+ mfConfig.d1Databases = options.d1Databases;
233
+ if (options.persist) {
234
+ mfConfig.d1Persist = `${persistPath}/d1`;
235
+ }
236
+ }
237
+ if (options.durableObjects) {
238
+ mfConfig.durableObjects = options.durableObjects;
239
+ if (options.persist) {
240
+ mfConfig.durableObjectsPersist = `${persistPath}/do`;
241
+ }
242
+ }
243
+ if (options.sendEmail) {
244
+ mfConfig.email = {
245
+ send_email: Object.entries(options.sendEmail).map(([name, config]) => ({
246
+ name,
247
+ ...config.destinationAddress && {
248
+ destination_address: config.destinationAddress
249
+ },
250
+ ...config.allowedDestinationAddresses && {
251
+ allowed_destination_addresses: config.allowedDestinationAddresses
252
+ },
253
+ ...config.allowedSenderAddresses && {
254
+ allowed_sender_addresses: config.allowedSenderAddresses
255
+ }
256
+ }))
257
+ };
258
+ }
259
+ if (options.bindings && Object.keys(options.bindings).length > 0) {
260
+ mfConfig.bindings = options.bindings;
261
+ }
262
+ if (options.queues?.length) {
263
+ mfConfig.queueProducers = Object.fromEntries(options.queues.map((q) => [q, { queueName: q }]));
264
+ }
265
+ const mf = new Miniflare(mfConfig);
266
+ await mf.ready;
267
+ return {
268
+ ready: Promise.resolve(),
269
+ async dispose() {
270
+ await mf.dispose();
271
+ },
272
+ async getBindings() {
273
+ return mf.getBindings();
274
+ },
275
+ getKVNamespace: mf.getKVNamespace.bind(mf),
276
+ getR2Bucket: mf.getR2Bucket.bind(mf),
277
+ getD1Database: mf.getD1Database.bind(mf),
278
+ getDurableObjectNamespace: mf.getDurableObjectNamespace.bind(mf),
279
+ dispatchFetch: mf.dispatchFetch.bind(mf),
280
+ _mf: mf
281
+ };
282
+ }
283
+ async function startMiniflareFromConfig(config, options = {}) {
284
+ const bindings = config.bindings ?? {};
285
+ const mfOptions = {
286
+ ...options,
287
+ compatibilityDate: config.compatibilityDate,
288
+ compatibilityFlags: config.compatibilityFlags,
289
+ kvNamespaces: bindings.kv ? bindings.kv : undefined,
290
+ r2Buckets: bindings.r2 ? bindings.r2 : undefined,
291
+ d1Databases: bindings.d1 ? bindings.d1 : undefined,
292
+ queues: bindings.queues?.consumers?.map((c) => c.queue),
293
+ sendEmail: bindings.sendEmail ? bindings.sendEmail : undefined,
294
+ bindings: config.vars,
295
+ durableObjects: bindings.durableObjects ? Object.fromEntries(Object.entries(bindings.durableObjects).map(([bindingName, doConfig]) => {
296
+ const normalized = normalizeDOBinding(doConfig);
297
+ return [
298
+ bindingName,
299
+ {
300
+ className: normalized.className,
301
+ scriptPath: normalized.scriptName
302
+ }
303
+ ];
304
+ })) : undefined
305
+ };
306
+ return startMiniflare(mfOptions);
307
+ }
308
+ var globalMiniflare = null;
309
+ async function getMiniflare(options) {
310
+ if (!globalMiniflare) {
311
+ globalMiniflare = await startMiniflare(options);
312
+ }
313
+ return globalMiniflare;
314
+ }
315
+ async function stopMiniflare() {
316
+ if (globalMiniflare) {
317
+ await globalMiniflare.dispose();
318
+ globalMiniflare = null;
319
+ }
320
+ }
321
+
322
+ export { startMiniflare, startMiniflareFromConfig, getMiniflare, stopMiniflare };
@@ -95,11 +95,16 @@ function transformWorkerEntrypoint(code, id, options = {}) {
95
95
  }
96
96
  const fetchFn = functions.find((f) => f.name === "fetch");
97
97
  const rpcMethods = functions.filter((f) => f.name !== "fetch");
98
+ const needsFetchHelpers = Boolean(fetchFn);
98
99
  const s = new MagicString(code);
99
100
  const importStatement = `import { WorkerEntrypoint } from 'cloudflare:workers'
100
101
  `;
101
- if (injectContext) {
102
- s.prepend(`import { runWithContext } from 'devflare/runtime'
102
+ if (needsFetchHelpers) {
103
+ const runtimeImports = ["createFetchEvent", "invokeFetchHandler"];
104
+ if (injectContext) {
105
+ runtimeImports.push("runWithEventContext");
106
+ }
107
+ s.prepend(`import { ${runtimeImports.join(", ")} } from 'devflare/runtime'
103
108
  `);
104
109
  }
105
110
  s.prepend(importStatement);
@@ -123,29 +128,23 @@ function transformWorkerEntrypoint(code, id, options = {}) {
123
128
  class ${className} extends WorkerEntrypoint {
124
129
  `;
125
130
  if (fetchFn) {
126
- if (injectContext) {
127
- classBody += ` async fetch(request: Request): Promise<Response> {
128
- `;
129
- classBody += ` return runWithContext(
131
+ classBody += ` async fetch(request: Request): Promise<Response> {
130
132
  `;
131
- classBody += ` this.env,
133
+ classBody += ` const __devflareEvent = createFetchEvent(request, this.env, this.ctx)
132
134
  `;
133
- classBody += ` this.ctx,
134
- `;
135
- classBody += ` request,
135
+ if (injectContext) {
136
+ classBody += ` return runWithEventContext(
136
137
  `;
137
- classBody += ` () => __originalFetch(request, this.env, this.ctx),
138
+ classBody += ` __devflareEvent,
138
139
  `;
139
- classBody += ` 'fetch'
140
+ classBody += ` () => invokeFetchHandler(__originalFetch, __devflareEvent)
140
141
  `;
141
142
  classBody += ` )
142
143
  `;
143
144
  classBody += ` }
144
145
  `;
145
146
  } else {
146
- classBody += ` async fetch(request: Request): Promise<Response> {
147
- `;
148
- classBody += ` return __originalFetch(request, this.env, this.ctx)
147
+ classBody += ` return invokeFetchHandler(__originalFetch, __devflareEvent)
149
148
  `;
150
149
  classBody += ` }
151
150
  `;