alchemy 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/lib/alchemy.d.ts +6 -0
  2. package/lib/alchemy.d.ts.map +1 -1
  3. package/lib/alchemy.js +5 -0
  4. package/lib/alchemy.js.map +1 -1
  5. package/lib/apply.js +1 -1
  6. package/lib/apply.js.map +1 -1
  7. package/lib/build-date.d.ts +1 -1
  8. package/lib/build-date.js +1 -1
  9. package/lib/cloudflare/bucket.d.ts +10 -0
  10. package/lib/cloudflare/bucket.d.ts.map +1 -1
  11. package/lib/cloudflare/bucket.js +1 -0
  12. package/lib/cloudflare/bucket.js.map +1 -1
  13. package/lib/cloudflare/bundle/bundle-worker-dev.d.ts +25 -0
  14. package/lib/cloudflare/bundle/bundle-worker-dev.d.ts.map +1 -0
  15. package/lib/cloudflare/bundle/bundle-worker-dev.js +85 -0
  16. package/lib/cloudflare/bundle/bundle-worker-dev.js.map +1 -0
  17. package/lib/cloudflare/bundle/bundle-worker.d.ts.map +1 -1
  18. package/lib/cloudflare/bundle/bundle-worker.js +0 -3
  19. package/lib/cloudflare/bundle/bundle-worker.js.map +1 -1
  20. package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts +1 -2
  21. package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts.map +1 -1
  22. package/lib/cloudflare/bundle/nodejs-compat-mode.js +6 -1
  23. package/lib/cloudflare/bundle/nodejs-compat-mode.js.map +1 -1
  24. package/lib/cloudflare/d1-database.d.ts +10 -0
  25. package/lib/cloudflare/d1-database.d.ts.map +1 -1
  26. package/lib/cloudflare/d1-database.js +1 -0
  27. package/lib/cloudflare/d1-database.js.map +1 -1
  28. package/lib/cloudflare/do-state-store/internal.d.ts +1 -0
  29. package/lib/cloudflare/do-state-store/internal.d.ts.map +1 -1
  30. package/lib/cloudflare/do-state-store/internal.js +27 -29
  31. package/lib/cloudflare/do-state-store/internal.js.map +1 -1
  32. package/lib/cloudflare/do-state-store/store.d.ts.map +1 -1
  33. package/lib/cloudflare/do-state-store/store.js +7 -20
  34. package/lib/cloudflare/do-state-store/store.js.map +1 -1
  35. package/lib/cloudflare/images.d.ts +12 -0
  36. package/lib/cloudflare/images.d.ts.map +1 -1
  37. package/lib/cloudflare/images.js +4 -0
  38. package/lib/cloudflare/images.js.map +1 -1
  39. package/lib/cloudflare/kv-namespace.d.ts +10 -0
  40. package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
  41. package/lib/cloudflare/kv-namespace.js +1 -0
  42. package/lib/cloudflare/kv-namespace.js.map +1 -1
  43. package/lib/cloudflare/queue.d.ts +10 -0
  44. package/lib/cloudflare/queue.d.ts.map +1 -1
  45. package/lib/cloudflare/queue.js +1 -0
  46. package/lib/cloudflare/queue.js.map +1 -1
  47. package/lib/cloudflare/vite.d.ts.map +1 -1
  48. package/lib/cloudflare/vite.js +12 -0
  49. package/lib/cloudflare/vite.js.map +1 -1
  50. package/lib/cloudflare/website.d.ts +7 -0
  51. package/lib/cloudflare/website.d.ts.map +1 -1
  52. package/lib/cloudflare/website.js +16 -6
  53. package/lib/cloudflare/website.js.map +1 -1
  54. package/lib/cloudflare/worker/get-worker-template.d.ts +2 -0
  55. package/lib/cloudflare/worker/get-worker-template.d.ts.map +1 -0
  56. package/lib/cloudflare/worker/get-worker-template.js +12 -0
  57. package/lib/cloudflare/worker/get-worker-template.js.map +1 -0
  58. package/lib/cloudflare/worker/http-server.d.ts +14 -0
  59. package/lib/cloudflare/worker/http-server.d.ts.map +1 -0
  60. package/lib/cloudflare/worker/http-server.js +67 -0
  61. package/lib/cloudflare/worker/http-server.js.map +1 -0
  62. package/lib/cloudflare/worker/miniflare-worker-options.d.ts +13 -0
  63. package/lib/cloudflare/worker/miniflare-worker-options.d.ts.map +1 -0
  64. package/lib/cloudflare/worker/miniflare-worker-options.js +408 -0
  65. package/lib/cloudflare/worker/miniflare-worker-options.js.map +1 -0
  66. package/lib/cloudflare/worker/miniflare.d.ts +31 -0
  67. package/lib/cloudflare/worker/miniflare.d.ts.map +1 -0
  68. package/lib/cloudflare/worker/miniflare.js +150 -0
  69. package/lib/cloudflare/worker/miniflare.js.map +1 -0
  70. package/lib/cloudflare/worker/mixed-mode.d.ts +17 -0
  71. package/lib/cloudflare/worker/mixed-mode.d.ts.map +1 -0
  72. package/lib/cloudflare/worker/mixed-mode.js +145 -0
  73. package/lib/cloudflare/worker/mixed-mode.js.map +1 -0
  74. package/lib/cloudflare/worker/subdomain.d.ts +3 -0
  75. package/lib/cloudflare/worker/subdomain.d.ts.map +1 -0
  76. package/lib/cloudflare/worker/subdomain.js +10 -0
  77. package/lib/cloudflare/worker/subdomain.js.map +1 -0
  78. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  79. package/lib/cloudflare/worker-metadata.js +7 -3
  80. package/lib/cloudflare/worker-metadata.js.map +1 -1
  81. package/lib/cloudflare/worker.d.ts +23 -1
  82. package/lib/cloudflare/worker.d.ts.map +1 -1
  83. package/lib/cloudflare/worker.js +229 -8
  84. package/lib/cloudflare/worker.js.map +1 -1
  85. package/lib/cloudflare/workflow.d.ts +7 -0
  86. package/lib/cloudflare/workflow.d.ts.map +1 -1
  87. package/lib/cloudflare/workflow.js.map +1 -1
  88. package/lib/destroy.d.ts.map +1 -1
  89. package/lib/destroy.js +9 -5
  90. package/lib/destroy.js.map +1 -1
  91. package/lib/scope.d.ts +2 -0
  92. package/lib/scope.d.ts.map +1 -1
  93. package/lib/scope.js +10 -2
  94. package/lib/scope.js.map +1 -1
  95. package/lib/util/assert-never.d.ts +1 -1
  96. package/lib/util/assert-never.d.ts.map +1 -1
  97. package/lib/util/assert-never.js +2 -2
  98. package/lib/util/assert-never.js.map +1 -1
  99. package/lib/util/cli.d.ts +21 -7
  100. package/lib/util/cli.d.ts.map +1 -1
  101. package/lib/util/cli.js +8 -0
  102. package/lib/util/cli.js.map +1 -1
  103. package/lib/util/deferred-promise.d.ts +8 -0
  104. package/lib/util/deferred-promise.d.ts.map +1 -0
  105. package/lib/util/deferred-promise.js +16 -0
  106. package/lib/util/deferred-promise.js.map +1 -0
  107. package/lib/util/detect-package-manager.d.ts +3 -0
  108. package/lib/util/detect-package-manager.d.ts.map +1 -0
  109. package/lib/util/detect-package-manager.js +25 -0
  110. package/lib/util/detect-package-manager.js.map +1 -0
  111. package/lib/util/logger.d.ts.map +1 -1
  112. package/lib/util/logger.js +1 -0
  113. package/lib/util/logger.js.map +1 -1
  114. package/lib/util/memoize.d.ts +4 -0
  115. package/lib/util/memoize.d.ts.map +1 -0
  116. package/lib/util/memoize.js +17 -0
  117. package/lib/util/memoize.js.map +1 -0
  118. package/package.json +7 -5
  119. package/src/alchemy.ts +14 -0
  120. package/src/apply.ts +2 -1
  121. package/src/build-date.ts +1 -1
  122. package/src/cloudflare/bucket.ts +12 -0
  123. package/src/cloudflare/bundle/bundle-worker-dev.ts +126 -0
  124. package/src/cloudflare/bundle/bundle-worker.ts +0 -5
  125. package/src/cloudflare/bundle/nodejs-compat-mode.ts +12 -3
  126. package/src/cloudflare/d1-database.ts +11 -0
  127. package/src/cloudflare/do-state-store/internal.ts +30 -31
  128. package/src/cloudflare/do-state-store/store.ts +9 -26
  129. package/src/cloudflare/images.ts +14 -0
  130. package/src/cloudflare/kv-namespace.ts +12 -0
  131. package/src/cloudflare/queue.ts +12 -0
  132. package/src/cloudflare/vite.ts +12 -0
  133. package/src/cloudflare/website.ts +25 -6
  134. package/src/cloudflare/worker/get-worker-template.ts +14 -0
  135. package/src/cloudflare/worker/http-server.ts +80 -0
  136. package/src/cloudflare/worker/miniflare-worker-options.ts +531 -0
  137. package/src/cloudflare/worker/miniflare.ts +198 -0
  138. package/src/cloudflare/worker/mixed-mode.ts +220 -0
  139. package/src/cloudflare/worker/subdomain.ts +16 -0
  140. package/src/cloudflare/worker-metadata.ts +12 -4
  141. package/src/cloudflare/worker.ts +284 -18
  142. package/src/cloudflare/workflow.ts +7 -0
  143. package/src/destroy.ts +9 -5
  144. package/src/scope.ts +20 -1
  145. package/src/util/assert-never.ts +2 -2
  146. package/src/util/cli.ts +19 -7
  147. package/src/util/deferred-promise.ts +19 -0
  148. package/src/util/detect-package-manager.ts +23 -0
  149. package/src/util/logger.ts +1 -0
  150. package/src/util/memoize.ts +23 -0
  151. package/workers/do-state-store.js +826 -0
  152. package/{src/cloudflare/do-state-store/worker.ts → workers/do-state-store.ts} +55 -23
  153. package/workers/mixed-mode-proxy-worker.js +39 -0
  154. package/workers/mixed-mode-proxy-worker.ts +46 -0
  155. package/lib/cloudflare/do-state-store/worker.d.ts +0 -27
  156. package/lib/cloudflare/do-state-store/worker.d.ts.map +0 -1
  157. package/lib/cloudflare/do-state-store/worker.js +0 -179
  158. package/lib/cloudflare/do-state-store/worker.js.map +0 -1
@@ -0,0 +1,531 @@
1
+ import {
2
+ kCurrentWorker,
3
+ type RemoteProxyConnectionString,
4
+ type WorkerOptions,
5
+ } from "miniflare";
6
+ import assert from "node:assert";
7
+ import { assertNever } from "../../util/assert-never.ts";
8
+ import { logger } from "../../util/logger.ts";
9
+ import { Self, type Binding, type WorkerBindingSpec } from "../bindings.ts";
10
+ import type { WorkerProps } from "../worker.ts";
11
+
12
+ export type MiniflareWorkerOptions = Pick<
13
+ WorkerProps,
14
+ | "bindings"
15
+ | "eventSources"
16
+ | "compatibilityDate"
17
+ | "compatibilityFlags"
18
+ | "format"
19
+ > & {
20
+ name: string;
21
+ script: string;
22
+ port?: number;
23
+ };
24
+
25
+ type BindingType = Exclude<Binding, string | Self>["type"];
26
+
27
+ const REMOTE_ONLY_BINDING_TYPES = [
28
+ "ai",
29
+ "ai_gateway",
30
+ "browser",
31
+ "dispatch_namespace",
32
+ "vectorize",
33
+ ] satisfies BindingType[];
34
+ const REMOTE_OPTIONAL_BINDING_TYPES = [
35
+ "d1",
36
+ // "durable_object_namespace", This is supported in Miniflare but needs some wrangling to make it work with a remote proxy.
37
+ "images",
38
+ "kv_namespace",
39
+ "r2_bucket",
40
+ "queue",
41
+ "service",
42
+ // "workflow", same thing
43
+ ] satisfies BindingType[];
44
+
45
+ type RemoteBindingType =
46
+ | (typeof REMOTE_ONLY_BINDING_TYPES)[number]
47
+ | (typeof REMOTE_OPTIONAL_BINDING_TYPES)[number];
48
+
49
+ type RemoteBinding = Extract<Binding, { type: RemoteBindingType }>;
50
+
51
+ export function buildRemoteBindings(
52
+ input: Pick<MiniflareWorkerOptions, "bindings">,
53
+ ) {
54
+ const bindings: WorkerBindingSpec[] = [];
55
+ for (const [name, binding] of Object.entries(input.bindings ?? {})) {
56
+ if (isRemoteOnlyBinding(binding)) {
57
+ bindings.push(buildRemoteBinding(name, binding));
58
+ } else if (isRemoteOptionalBinding(binding) && isRemoteEnabled(binding)) {
59
+ bindings.push(buildRemoteBinding(name, binding));
60
+ }
61
+ }
62
+ return bindings;
63
+ }
64
+
65
+ function isRemoteOptionalBinding(binding: Binding): binding is RemoteBinding {
66
+ return (
67
+ typeof binding !== "string" &&
68
+ binding !== Self &&
69
+ typeof binding === "object" &&
70
+ "type" in binding &&
71
+ REMOTE_OPTIONAL_BINDING_TYPES.includes(binding.type as any)
72
+ );
73
+ }
74
+
75
+ function isRemoteOnlyBinding(binding: Binding): binding is RemoteBinding {
76
+ return (
77
+ typeof binding !== "string" &&
78
+ binding !== Self &&
79
+ typeof binding === "object" &&
80
+ "type" in binding &&
81
+ REMOTE_ONLY_BINDING_TYPES.includes(binding.type as any)
82
+ );
83
+ }
84
+
85
+ function isRemoteEnabled(binding: RemoteBinding): boolean {
86
+ return (
87
+ "dev" in binding &&
88
+ typeof binding.dev === "object" &&
89
+ "remote" in binding.dev &&
90
+ !!binding.dev.remote
91
+ );
92
+ }
93
+
94
+ function buildRemoteBinding(
95
+ name: string,
96
+ binding: RemoteBinding,
97
+ ): WorkerBindingSpec & { raw?: true } {
98
+ switch (binding.type) {
99
+ case "ai": {
100
+ return {
101
+ type: "ai",
102
+ name,
103
+ raw: true,
104
+ };
105
+ }
106
+ case "ai_gateway": {
107
+ return {
108
+ type: "ai",
109
+ name,
110
+ raw: true,
111
+ };
112
+ }
113
+ case "browser": {
114
+ return {
115
+ type: "browser",
116
+ name,
117
+ raw: true,
118
+ };
119
+ }
120
+ case "d1": {
121
+ return {
122
+ type: "d1",
123
+ name,
124
+ id: binding.id,
125
+ raw: true,
126
+ };
127
+ }
128
+ case "dispatch_namespace": {
129
+ return {
130
+ type: "dispatch_namespace",
131
+ name,
132
+ namespace: binding.namespace,
133
+ raw: true,
134
+ };
135
+ }
136
+ // case "durable_object_namespace": {
137
+ // return {
138
+ // type: "durable_object_namespace",
139
+ // name,
140
+ // class_name: binding.className,
141
+ // script_name: binding.scriptName,
142
+ // raw: true,
143
+ // };
144
+ // }
145
+ case "images": {
146
+ return {
147
+ type: "images",
148
+ name,
149
+ raw: true,
150
+ };
151
+ }
152
+ case "kv_namespace": {
153
+ return {
154
+ type: "kv_namespace",
155
+ name,
156
+ namespace_id:
157
+ "namespaceId" in binding ? binding.namespaceId : binding.id,
158
+ raw: true,
159
+ };
160
+ }
161
+ case "queue": {
162
+ return {
163
+ type: "queue",
164
+ name,
165
+ queue_name: binding.name,
166
+ raw: true,
167
+ };
168
+ }
169
+ case "r2_bucket": {
170
+ return {
171
+ type: "r2_bucket",
172
+ name,
173
+ bucket_name: binding.name,
174
+ raw: true,
175
+ };
176
+ }
177
+ case "service": {
178
+ return {
179
+ type: "service",
180
+ name,
181
+ service: "service" in binding ? binding.service : binding.name,
182
+ environment: "environment" in binding ? binding.environment : undefined,
183
+ };
184
+ }
185
+ case "vectorize": {
186
+ return {
187
+ type: "vectorize",
188
+ name,
189
+ index_name: binding.name,
190
+ raw: true,
191
+ };
192
+ }
193
+ // case "workflow": {
194
+ // return {
195
+ // type: "workflow",
196
+ // name,
197
+ // workflow_name: binding.workflowName,
198
+ // class_name: binding.className,
199
+ // script_name: binding.scriptName,
200
+ // raw: true,
201
+ // };
202
+ // }
203
+ default: {
204
+ assertNever(binding);
205
+ }
206
+ }
207
+ }
208
+
209
+ export function buildMiniflareWorkerOptions({
210
+ name: workerName,
211
+ script,
212
+ bindings,
213
+ format,
214
+ eventSources,
215
+ compatibilityDate,
216
+ compatibilityFlags,
217
+ remoteProxyConnectionString,
218
+ }: MiniflareWorkerOptions & {
219
+ remoteProxyConnectionString: RemoteProxyConnectionString | undefined;
220
+ }): WorkerOptions {
221
+ const options: WorkerOptions = {
222
+ name: workerName,
223
+ script,
224
+ modules: format !== "cjs",
225
+ compatibilityDate,
226
+ compatibilityFlags,
227
+ unsafeDirectSockets: [{ entrypoint: undefined, proxy: true }],
228
+ };
229
+ for (const [name, binding] of Object.entries(bindings ?? {})) {
230
+ if (typeof binding === "string") {
231
+ options.bindings = {
232
+ ...options.bindings,
233
+ [name]: binding,
234
+ };
235
+ continue;
236
+ }
237
+ if (binding === Self) {
238
+ options.serviceBindings = {
239
+ ...((options.serviceBindings as Record<string, string> | undefined) ??
240
+ {}),
241
+ [name]: kCurrentWorker,
242
+ };
243
+ continue;
244
+ }
245
+ switch (binding.type) {
246
+ case "ai": {
247
+ assert(
248
+ remoteProxyConnectionString,
249
+ `Binding "${name}" of type "${binding.type}" requires a remoteProxyConnectionString, but none was provided.`,
250
+ );
251
+ options.ai = {
252
+ binding: name,
253
+ remoteProxyConnectionString,
254
+ };
255
+ break;
256
+ }
257
+ case "ai_gateway": {
258
+ assert(
259
+ remoteProxyConnectionString,
260
+ `Binding "${name}" of type "${binding.type}" requires a remoteProxyConnectionString, but none was provided.`,
261
+ );
262
+ options.ai = {
263
+ binding: name,
264
+ remoteProxyConnectionString,
265
+ };
266
+ break;
267
+ }
268
+ case "analytics_engine": {
269
+ (options.analyticsEngineDatasets ??= {})[name] = {
270
+ dataset: binding.dataset,
271
+ };
272
+ break;
273
+ }
274
+ case "assets": {
275
+ options.assets = {
276
+ binding: name,
277
+ directory: binding.path,
278
+ };
279
+ break;
280
+ }
281
+ case "browser": {
282
+ assert(
283
+ remoteProxyConnectionString,
284
+ `Binding "${name}" of type "${binding.type}" requires a remoteProxyConnectionString, but none was provided.`,
285
+ );
286
+ options.browserRendering = {
287
+ binding: name,
288
+ remoteProxyConnectionString,
289
+ };
290
+ break;
291
+ }
292
+ case "d1": {
293
+ (
294
+ (options.d1Databases ??= {}) as Record<
295
+ string,
296
+ {
297
+ id: string;
298
+ remoteProxyConnectionString?: RemoteProxyConnectionString;
299
+ }
300
+ >
301
+ )[name] = {
302
+ id: binding.id,
303
+ remoteProxyConnectionString: binding.dev?.remote
304
+ ? remoteProxyConnectionString
305
+ : undefined,
306
+ };
307
+ break;
308
+ }
309
+ case "dispatch_namespace": {
310
+ assert(
311
+ remoteProxyConnectionString,
312
+ `Binding "${name}" of type "${binding.type}" requires a remoteProxyConnectionString, but none was provided.`,
313
+ );
314
+ (options.dispatchNamespaces ??= {})[name] = {
315
+ namespace: binding.namespace,
316
+ remoteProxyConnectionString,
317
+ };
318
+ break;
319
+ }
320
+ case "durable_object_namespace": {
321
+ (options.durableObjects ??= {})[name] = {
322
+ className: binding.className,
323
+ scriptName: binding.scriptName,
324
+ useSQLite: binding.sqlite,
325
+ // namespaceId: binding.namespaceId,
326
+ // unsafeUniqueKey?: string | typeof kUnsafeEphemeralUniqueKey | undefined;
327
+ // unsafePreventEviction?: boolean | undefined;
328
+ // remoteProxyConnectionString: binding.local
329
+ // ? undefined
330
+ // : remoteProxyConnectionString,
331
+ };
332
+ if (!binding.scriptName || binding.scriptName === workerName) {
333
+ options.unsafeDirectSockets!.push({
334
+ entrypoint: binding.className,
335
+ proxy: true,
336
+ });
337
+ }
338
+ break;
339
+ }
340
+ case "hyperdrive": {
341
+ if ("access_client_id" in binding.origin) {
342
+ throw new Error(
343
+ `Hyperdrive with Cloudflare Access is not supported for locally emulated workers. Worker "${name}" is locally emulated but is bound to Hyperdrive "${name}", which has Cloudflare Access enabled.`,
344
+ );
345
+ }
346
+ logger.warnOnce(
347
+ `Hyperdrive bindings in locally emulated workers are experimental and may not work as expected. Worker "${name}" is locally emulated and bound to Hyperdrive "${name}".`,
348
+ );
349
+ const {
350
+ scheme = "postgres",
351
+ port = 5432,
352
+ password,
353
+ database,
354
+ host,
355
+ user,
356
+ } = binding.origin;
357
+ const connectionString = new URL(
358
+ `${scheme}://${user}:${password.unencrypted}@${host}:${port}/${database}?sslmode=${binding.mtls?.sslmode ?? "verify-full"}`,
359
+ );
360
+ (options.bindings ??= {})[name] = {
361
+ connectionString: connectionString.toString(),
362
+ database,
363
+ host,
364
+ password: password.unencrypted,
365
+ port,
366
+ scheme,
367
+ user,
368
+ };
369
+ break;
370
+ }
371
+ case "images": {
372
+ options.images = {
373
+ binding: name,
374
+ remoteProxyConnectionString: binding.dev?.remote
375
+ ? remoteProxyConnectionString
376
+ : undefined,
377
+ };
378
+ break;
379
+ }
380
+ case "json": {
381
+ (options.bindings ??= {})[name] = binding.json;
382
+ break;
383
+ }
384
+ case "kv_namespace": {
385
+ const normalized =
386
+ "id" in binding
387
+ ? { id: binding.id }
388
+ : { id: binding.namespaceId, dev: binding.dev };
389
+ (
390
+ (options.kvNamespaces ??= {}) as Record<
391
+ string,
392
+ {
393
+ id: string;
394
+ remoteProxyConnectionString?: RemoteProxyConnectionString;
395
+ }
396
+ >
397
+ )[name] = {
398
+ id: normalized.id,
399
+ remoteProxyConnectionString: normalized.dev?.remote
400
+ ? remoteProxyConnectionString
401
+ : undefined,
402
+ };
403
+ break;
404
+ }
405
+ case "pipeline": {
406
+ ((options.pipelines ??= {}) as Record<string, string>)[name] =
407
+ binding.id;
408
+ break;
409
+ }
410
+ case "queue": {
411
+ (
412
+ (options.queueProducers ??= {}) as Record<
413
+ string,
414
+ {
415
+ queueName: string;
416
+ deliveryDelay?: number;
417
+ remoteProxyConnectionString?: RemoteProxyConnectionString;
418
+ }
419
+ >
420
+ )[name] = {
421
+ queueName: binding.name,
422
+ deliveryDelay: binding.settings?.deliveryDelay,
423
+ remoteProxyConnectionString: binding.dev?.remote
424
+ ? remoteProxyConnectionString
425
+ : undefined,
426
+ };
427
+ break;
428
+ }
429
+ case "r2_bucket": {
430
+ (
431
+ (options.r2Buckets ??= {}) as Record<
432
+ string,
433
+ {
434
+ id: string;
435
+ remoteProxyConnectionString?: RemoteProxyConnectionString;
436
+ }
437
+ >
438
+ )[name] = {
439
+ id: binding.name,
440
+ remoteProxyConnectionString: binding.dev?.remote
441
+ ? remoteProxyConnectionString
442
+ : undefined,
443
+ };
444
+ break;
445
+ }
446
+ case "secret": {
447
+ (options.bindings ??= {})[name] = binding.unencrypted;
448
+ break;
449
+ }
450
+ case "secrets_store_secret": {
451
+ options.secretsStoreSecrets = {
452
+ ...((options.secretsStoreSecrets as
453
+ | Record<string, { store_id: string; secret_name: string }>
454
+ | undefined) ?? {}),
455
+ [name]: {
456
+ store_id: binding.storeId,
457
+ secret_name: binding.name,
458
+ },
459
+ };
460
+ break;
461
+ }
462
+ case "secret_key": {
463
+ throw new Error(
464
+ `Secret key bindings are not supported for locally emulated workers. Worker "${name}" is locally emulated but is bound to secret key "${name}".`,
465
+ );
466
+ }
467
+ case "service": {
468
+ if (!("id" in binding)) {
469
+ throw new Error(
470
+ `Service bindings must have an id. Worker "${name}" is bound to service "${name}" but does not have an id.`,
471
+ );
472
+ }
473
+ if (isRemoteEnabled(binding)) {
474
+ (options.serviceBindings ??= {})[name] = {
475
+ name: binding.name,
476
+ remoteProxyConnectionString,
477
+ };
478
+ } else {
479
+ (options.serviceBindings ??= {})[name] = binding.name;
480
+ }
481
+ break;
482
+ }
483
+ case "vectorize": {
484
+ assert(
485
+ remoteProxyConnectionString,
486
+ `Binding "${name}" of type "${binding.type}" requires a remoteProxyConnectionString, but none was provided.`,
487
+ );
488
+ (options.vectorize ??= {})[name] = {
489
+ index_name: binding.name,
490
+ remoteProxyConnectionString,
491
+ };
492
+ break;
493
+ }
494
+ case "version_metadata": {
495
+ // This is how Wrangler does it:
496
+ // https://github.com/cloudflare/workers-sdk/blob/70ba9fbf905a9ba5fe158d0bc8d48f6bf31712a2/packages/wrangler/src/dev/miniflare.ts#L881
497
+ (options.bindings ??= {})[name] = {
498
+ id: crypto.randomUUID(),
499
+ tag: "",
500
+ timestamp: "0",
501
+ };
502
+ break;
503
+ }
504
+ case "workflow": {
505
+ (options.workflows ??= {})[name] = {
506
+ name: binding.workflowName,
507
+ className: binding.className,
508
+ scriptName: binding.scriptName,
509
+ // remoteProxyConnectionString:
510
+ // "local" in binding && binding.local
511
+ // ? undefined
512
+ // : remoteProxyConnectionString,
513
+ };
514
+ break;
515
+ }
516
+ default: {
517
+ assertNever(binding);
518
+ }
519
+ }
520
+ }
521
+ for (const eventSource of eventSources ?? []) {
522
+ const queue = "queue" in eventSource ? eventSource.queue : eventSource;
523
+ if (queue.dev?.remote !== false) {
524
+ throw new Error(
525
+ `Locally emulated workers cannot consume remote queues. Worker "${workerName}" is locally emulated but is consuming remote queue "${queue.name}".`,
526
+ );
527
+ }
528
+ ((options.queueConsumers ??= []) as string[]).push(queue.name);
529
+ }
530
+ return options;
531
+ }