alchemy 0.93.12 → 0.94.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 (75) hide show
  1. package/README.md +1 -1
  2. package/bin/alchemy.js +4 -4
  3. package/lib/aws/control/client.d.ts.map +1 -1
  4. package/lib/aws/control/client.js +2 -1
  5. package/lib/aws/control/client.js.map +1 -1
  6. package/lib/aws/control/resource.d.ts.map +1 -1
  7. package/lib/aws/control/resource.js +46 -5
  8. package/lib/aws/control/resource.js.map +1 -1
  9. package/lib/aws/ec2/utils.d.ts.map +1 -1
  10. package/lib/aws/ec2/utils.js +5 -3
  11. package/lib/aws/ec2/utils.js.map +1 -1
  12. package/lib/aws/utils.d.ts +8 -1
  13. package/lib/aws/utils.d.ts.map +1 -1
  14. package/lib/aws/utils.js +14 -1
  15. package/lib/aws/utils.js.map +1 -1
  16. package/lib/cloudflare/artifacts.d.ts +54 -0
  17. package/lib/cloudflare/artifacts.d.ts.map +1 -0
  18. package/lib/cloudflare/artifacts.js +14 -0
  19. package/lib/cloudflare/artifacts.js.map +1 -0
  20. package/lib/cloudflare/bindings.d.ts +16 -4
  21. package/lib/cloudflare/bindings.d.ts.map +1 -1
  22. package/lib/cloudflare/bindings.js.map +1 -1
  23. package/lib/cloudflare/bound.d.ts +2 -1
  24. package/lib/cloudflare/bound.d.ts.map +1 -1
  25. package/lib/cloudflare/d1-database.d.ts.map +1 -1
  26. package/lib/cloudflare/d1-database.js +8 -2
  27. package/lib/cloudflare/d1-database.js.map +1 -1
  28. package/lib/cloudflare/hyperdrive.d.ts +8 -0
  29. package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
  30. package/lib/cloudflare/hyperdrive.js +3 -1
  31. package/lib/cloudflare/hyperdrive.js.map +1 -1
  32. package/lib/cloudflare/index.d.ts +1 -0
  33. package/lib/cloudflare/index.d.ts.map +1 -1
  34. package/lib/cloudflare/index.js +1 -0
  35. package/lib/cloudflare/index.js.map +1 -1
  36. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
  37. package/lib/cloudflare/miniflare/build-worker-options.js +3 -0
  38. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
  39. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
  40. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +3 -1
  41. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
  42. package/lib/cloudflare/worker-metadata.d.ts +11 -0
  43. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  44. package/lib/cloudflare/worker-metadata.js +20 -1
  45. package/lib/cloudflare/worker-metadata.js.map +1 -1
  46. package/lib/cloudflare/worker.d.ts +37 -0
  47. package/lib/cloudflare/worker.d.ts.map +1 -1
  48. package/lib/cloudflare/worker.js +1 -1
  49. package/lib/cloudflare/worker.js.map +1 -1
  50. package/lib/cloudflare/wrangler.json.js +11 -0
  51. package/lib/cloudflare/wrangler.json.js.map +1 -1
  52. package/lib/cloudflare/zone.js +1 -1
  53. package/lib/cloudflare/zone.js.map +1 -1
  54. package/lib/scope.js +2 -2
  55. package/lib/scope.js.map +1 -1
  56. package/package.json +4 -4
  57. package/src/aws/control/client.ts +2 -1
  58. package/src/aws/control/resource.ts +67 -8
  59. package/src/aws/ec2/utils.ts +5 -3
  60. package/src/aws/utils.ts +20 -2
  61. package/src/cloudflare/artifacts.ts +69 -0
  62. package/src/cloudflare/bindings.ts +17 -2
  63. package/src/cloudflare/bound.ts +68 -65
  64. package/src/cloudflare/d1-database.ts +12 -2
  65. package/src/cloudflare/hyperdrive.ts +13 -1
  66. package/src/cloudflare/index.ts +1 -0
  67. package/src/cloudflare/miniflare/build-worker-options.ts +5 -0
  68. package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +3 -1
  69. package/src/cloudflare/worker-metadata.ts +33 -1
  70. package/src/cloudflare/worker.ts +41 -1
  71. package/src/cloudflare/wrangler.json.ts +19 -0
  72. package/src/cloudflare/zone.ts +1 -1
  73. package/src/scope.ts +2 -2
  74. package/workers/cloudflare-state-store.js +57 -57
  75. package/workers/tunnel-proxy.js +1 -1
@@ -6,7 +6,7 @@ import { logger } from "../../util/logger.ts";
6
6
  import { flattenParams } from "../../util/params.ts";
7
7
  import type { AwsClientProps } from "../client-props.ts";
8
8
  import { resolveAwsCredentials } from "../credentials.ts";
9
- import { getRegion } from "../utils.ts";
9
+ import { awsEndpoint, getRegion } from "../utils.ts";
10
10
 
11
11
  /**
12
12
  * Shared EC2 utilities for all EC2 resources
@@ -100,8 +100,10 @@ export async function callEC2Api<T>(
100
100
  // Try the API call, and retry once with fresh credentials on auth failure
101
101
  for (let attempt = 1; attempt <= 2; attempt++) {
102
102
  try {
103
- // Use the client's region instead of the global region
104
- const url = `https://ec2.${client.region}.amazonaws.com/`;
103
+ // Use the client's region instead of the global region.
104
+ // Honour AWS_ENDPOINT_URL / AWS_ENDPOINT_URL_EC2 for emulators
105
+ // (LocalStack, moto, etc.) — matches AWS SDK v3 behaviour.
106
+ const url = `${awsEndpoint("ec2", client.region ?? "us-east-1")}/`;
105
107
 
106
108
  const body = new URLSearchParams({
107
109
  Action: action,
package/src/aws/utils.ts CHANGED
@@ -14,13 +14,29 @@ export const getRegion: Provider<string> = loadConfig({
14
14
  default: "us-east-1",
15
15
  });
16
16
 
17
+ /**
18
+ * Resolve the endpoint URL for an aws4fetch service request, honouring the
19
+ * same `AWS_ENDPOINT_URL_<SERVICE>` / `AWS_ENDPOINT_URL` env vars as the AWS
20
+ * SDK / CLI so aws4fetch-based resources can be pointed at LocalStack, moto,
21
+ * or any other emulator.
22
+ */
23
+ export function awsEndpoint(service: string, region: string): string {
24
+ return (
25
+ process.env[
26
+ `AWS_ENDPOINT_URL_${service.toUpperCase().replace(/-/g, "_")}`
27
+ ] ??
28
+ process.env.AWS_ENDPOINT_URL ??
29
+ `https://${service}.${region}.amazonaws.com`
30
+ ).replace(/\/+$/, "");
31
+ }
32
+
17
33
  /**
18
34
  * AWS Service Configuration
19
35
  */
20
36
  export interface AwsServiceConfig {
21
37
  service: string;
22
38
  version: string;
23
- endpoint: (region: string) => string;
39
+ endpoint?: (region: string) => string;
24
40
  }
25
41
 
26
42
  /**
@@ -63,7 +79,9 @@ export function getAwsApiCaller<T = any>(
63
79
  for (let attempt = 1; attempt <= 2; attempt++) {
64
80
  try {
65
81
  const region = await getRegion();
66
- const url = config.endpoint(region);
82
+ const url = config.endpoint
83
+ ? config.endpoint(region)
84
+ : `${awsEndpoint(config.service, region)}/`;
67
85
 
68
86
  const body = new URLSearchParams({
69
87
  Action: action,
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Properties for creating an Artifacts binding.
3
+ *
4
+ * Artifacts namespaces are created implicitly by Cloudflare when the first
5
+ * repository is created in the namespace, so this binding does not provision
6
+ * or delete a namespace resource.
7
+ */
8
+ export interface ArtifactsProps {
9
+ /**
10
+ * Artifacts namespace name.
11
+ */
12
+ namespace: string;
13
+
14
+ dev?: {
15
+ /**
16
+ * Whether to run the Artifacts binding remotely in local development.
17
+ *
18
+ * Artifacts do not have a local emulator, so generated Wrangler config
19
+ * defaults this binding to remote mode.
20
+ *
21
+ * @default true
22
+ */
23
+ remote?: boolean;
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Cloudflare Artifacts binding.
29
+ *
30
+ * Artifacts namespaces are implicit containers for repositories. Use this
31
+ * helper to bind a Worker to a namespace; repository lifecycle should be
32
+ * managed through the Artifacts runtime API, REST API, or Git endpoint.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { Artifacts, Worker } from "alchemy/cloudflare";
37
+ *
38
+ * await Worker("site-editor", {
39
+ * entrypoint: "./src/worker.ts",
40
+ * bindings: {
41
+ * SITE_ARTIFACTS: Artifacts({ namespace: "my-sites" }),
42
+ * },
43
+ * });
44
+ * ```
45
+ *
46
+ * @see https://developers.cloudflare.com/artifacts/
47
+ */
48
+ export interface Artifacts {
49
+ type: "artifacts";
50
+ namespace: string;
51
+ dev?: {
52
+ remote?: boolean;
53
+ };
54
+ }
55
+
56
+ export function Artifacts(props: string | ArtifactsProps): Artifacts {
57
+ if (typeof props === "string") {
58
+ return {
59
+ type: "artifacts",
60
+ namespace: props,
61
+ };
62
+ }
63
+
64
+ return {
65
+ type: "artifacts",
66
+ namespace: props.namespace,
67
+ dev: props.dev,
68
+ };
69
+ }
@@ -8,6 +8,7 @@ import type { Ai } from "./ai.ts";
8
8
  import type { AiSearchNamespace } from "./ai-search-namespace.ts";
9
9
  import type { AiSearch } from "./ai-search.ts";
10
10
  import type { AnalyticsEngineDataset } from "./analytics-engine.ts";
11
+ import type { Artifacts } from "./artifacts.ts";
11
12
  import type { Assets } from "./assets.ts";
12
13
  import type { Bound } from "./bound.ts";
13
14
  import type { BrowserRendering } from "./browser-rendering.ts";
@@ -54,6 +55,7 @@ export type Binding =
54
55
  | AiSearch
55
56
  | AiSearchNamespace
56
57
  | Assets
58
+ | Artifacts
57
59
  | Container
58
60
  | CloudflareSecret
59
61
  | CloudflareSecretRef
@@ -127,6 +129,7 @@ export type WorkerBindingSpec =
127
129
  | WorkerBindingAiSearch
128
130
  | WorkerBindingAiSearchNamespace
129
131
  | WorkerBindingAnalyticsEngine
132
+ | WorkerBindingArtifacts
130
133
  | WorkerBindingAssets
131
134
  | WorkerBindingBrowserRendering
132
135
  | WorkerBindingD1
@@ -206,6 +209,18 @@ export interface WorkerBindingAnalyticsEngine {
206
209
  dataset: string;
207
210
  }
208
211
 
212
+ /**
213
+ * Artifacts binding type
214
+ */
215
+ export interface WorkerBindingArtifacts {
216
+ /** The name of the binding */
217
+ name: string;
218
+ /** Type identifier for Artifacts binding */
219
+ type: "artifacts";
220
+ /** Artifacts namespace name */
221
+ namespace: string;
222
+ }
223
+
209
224
  /**
210
225
  * Assets binding type
211
226
  */
@@ -295,8 +310,8 @@ export interface WorkerBindingJson {
295
310
  name: string;
296
311
  /** Type identifier for JSON binding */
297
312
  type: "json";
298
- /** JSON value */
299
- json: string;
313
+ /** JSON value, sent raw (not stringified) so the runtime injects native types */
314
+ json: unknown;
300
315
  }
301
316
 
302
317
  /**
@@ -5,6 +5,7 @@ import type { Ai as _Ai } from "./ai.ts";
5
5
  import type { AiSearchNamespace as _AiSearchNamespace } from "./ai-search-namespace.ts";
6
6
  import type { AiSearch as _AiSearch } from "./ai-search.ts";
7
7
  import type { AnalyticsEngineDataset as _AnalyticsEngineDataset } from "./analytics-engine.ts";
8
+ import type { Artifacts as _Artifacts } from "./artifacts.ts";
8
9
  import type { Assets } from "./assets.ts";
9
10
  import type { Binding, Json, Self } from "./bindings.ts";
10
11
  import type { BrowserRendering } from "./browser-rendering.ts";
@@ -61,69 +62,71 @@ export type Bound<T extends Binding> = T extends _AiSearch
61
62
  ? BoundWorker<RPC>
62
63
  : T extends _Worker<any, infer RPC> | WorkerRef<infer RPC>
63
64
  ? BoundWorker<RPC>
64
- : T extends { type: "service" }
65
- ? Service
66
- : T extends _R2Bucket
67
- ? R2Bucket
68
- : T extends _Hyperdrive | HyperdriveRef
69
- ? Hyperdrive
70
- : T extends Secret
71
- ? string
72
- : T extends CloudflareSecret | CloudflareSecretRef
73
- ? SecretsStoreSecret
74
- : T extends _EmailSender
75
- ? SendEmail
76
- : T extends SecretKey
77
- ? CryptoKey
78
- : T extends Assets
79
- ? Service
80
- : T extends _Workflow<infer P>
81
- ? Workflow<P>
82
- : T extends _D1Database
83
- ? D1Database
84
- : T extends DispatchNamespace
85
- ? DispatchNamespace
86
- : T extends _WorkerLoader
87
- ? WorkerLoader
88
- : T extends _VectorizeIndex
89
- ? VectorizeIndex
90
- : T extends _Queue<infer Body>
91
- ? Queue<Body>
92
- : T extends _AnalyticsEngineDataset
93
- ? AnalyticsEngineDataset
94
- : T extends _Pipeline<infer R>
95
- ? Pipeline<R>
96
- : T extends _RateLimit
97
- ? RateLimit
98
- : T extends string
99
- ? T
100
- : T extends BrowserRendering
101
- ? BrowserRun
102
- : T extends _Ai<infer M>
103
- ? Ai<M>
104
- : T extends _Images
105
- ? ImagesBinding
106
- : T extends _VersionMetadata
107
- ? WorkerVersionMetadata
108
- : T extends
109
- | _Worker.DevDomain
110
- | _Worker.DevUrl
111
- ? string
112
- : T extends Self
113
- ? Service
114
- : T extends Json<
115
- infer T
116
- >
117
- ? T
118
- : T extends _Container<
119
- infer Obj
65
+ : T extends _Artifacts
66
+ ? Artifacts
67
+ : T extends { type: "service" }
68
+ ? Service
69
+ : T extends _R2Bucket
70
+ ? R2Bucket
71
+ : T extends _Hyperdrive | HyperdriveRef
72
+ ? Hyperdrive
73
+ : T extends Secret
74
+ ? string
75
+ : T extends CloudflareSecret | CloudflareSecretRef
76
+ ? SecretsStoreSecret
77
+ : T extends _EmailSender
78
+ ? SendEmail
79
+ : T extends SecretKey
80
+ ? CryptoKey
81
+ : T extends Assets
82
+ ? Service
83
+ : T extends _Workflow<infer P>
84
+ ? Workflow<P>
85
+ : T extends _D1Database
86
+ ? D1Database
87
+ : T extends DispatchNamespace
88
+ ? DispatchNamespace
89
+ : T extends _WorkerLoader
90
+ ? WorkerLoader
91
+ : T extends _VectorizeIndex
92
+ ? VectorizeIndex
93
+ : T extends _Queue<infer Body>
94
+ ? Queue<Body>
95
+ : T extends _AnalyticsEngineDataset
96
+ ? AnalyticsEngineDataset
97
+ : T extends _Pipeline<infer R>
98
+ ? Pipeline<R>
99
+ : T extends _RateLimit
100
+ ? RateLimit
101
+ : T extends string
102
+ ? T
103
+ : T extends BrowserRendering
104
+ ? BrowserRun
105
+ : T extends _Ai<infer M>
106
+ ? Ai<M>
107
+ : T extends _Images
108
+ ? ImagesBinding
109
+ : T extends _VersionMetadata
110
+ ? WorkerVersionMetadata
111
+ : T extends
112
+ | _Worker.DevDomain
113
+ | _Worker.DevUrl
114
+ ? string
115
+ : T extends Self
116
+ ? Service
117
+ : T extends Json<
118
+ infer T
120
119
  >
121
- ? DurableObjectNamespace<
122
- Obj &
123
- Rpc.DurableObjectBranded
124
- >
125
- : T extends _VpcService
126
- ? Fetcher
127
- : T extends undefined
128
- ? undefined
129
- : Service;
120
+ ? T
121
+ : T extends _Container<
122
+ infer Obj
123
+ >
124
+ ? DurableObjectNamespace<
125
+ Obj &
126
+ Rpc.DurableObjectBranded
127
+ >
128
+ : T extends _VpcService
129
+ ? Fetcher
130
+ : T extends undefined
131
+ ? undefined
132
+ : Service;
@@ -307,11 +307,21 @@ const _D1Database = Resource(
307
307
 
308
308
  if (local) {
309
309
  if (props.migrationsFiles?.length || props.importFiles?.length) {
310
+ const localMigrationsFiles = props.migrationsDir
311
+ ? await listSqlFiles(props.migrationsDir)
312
+ : [];
313
+ const localImportFiles = props.importFiles?.length
314
+ ? await Promise.all(
315
+ props.importFiles.map((file) =>
316
+ readSqlFile(this.scope.rootDir, file.id),
317
+ ),
318
+ )
319
+ : [];
310
320
  await applyLocalD1Migrations({
311
321
  databaseId: dev.id,
312
322
  migrationsTable: props.migrationsTable ?? DEFAULT_MIGRATIONS_TABLE,
313
- migrations: props.migrationsFiles ?? [],
314
- imports: props.importFiles ?? [],
323
+ migrations: localMigrationsFiles,
324
+ imports: localImportFiles,
315
325
  rootDir: this.scope.rootDir,
316
326
  });
317
327
  }
@@ -47,6 +47,11 @@ export interface HyperdrivePublicOrigin {
47
47
  */
48
48
  scheme?: "postgres" | "mysql";
49
49
 
50
+ /**
51
+ * Connection query string, without the leading "?"
52
+ */
53
+ query?: string;
54
+
50
55
  /**
51
56
  * Database user
52
57
  */
@@ -90,6 +95,11 @@ export interface HyperdriveOriginWithAccess {
90
95
  */
91
96
  scheme?: "postgres" | "mysql";
92
97
 
98
+ /**
99
+ * Connection query string, without the leading "?"
100
+ */
101
+ query?: string;
102
+
93
103
  /**
94
104
  * Database user
95
105
  */
@@ -610,6 +620,7 @@ export const normalizeHyperdriveOrigin = (
610
620
  host: url.hostname,
611
621
  port: normalizePort(scheme, url.port),
612
622
  database: url.pathname.slice(1),
623
+ query: url.search?.slice(1) ?? "",
613
624
  };
614
625
  }
615
626
  const scheme = normalizeScheme(origin.scheme);
@@ -623,6 +634,7 @@ export const normalizeHyperdriveOrigin = (
623
634
  }),
624
635
  scheme,
625
636
  port: normalizePort(scheme, origin.port),
637
+ query: origin.query ?? "",
626
638
  };
627
639
  };
628
640
 
@@ -660,6 +672,6 @@ const toConnectionString = (
660
672
  "password" in origin ? origin.password : origin.access_client_secret,
661
673
  );
662
674
  return new Secret(
663
- `${origin.scheme}://${origin.user}:${password}@${origin.host}:${origin.port}/${origin.database}`,
675
+ `${origin.scheme}://${origin.user}:${password}@${origin.host}:${origin.port}/${origin.database}${origin.query ? `?${origin.query}` : ""}`,
664
676
  );
665
677
  };
@@ -20,6 +20,7 @@ export * from "./api-gateway-operation.ts";
20
20
  export * from "./api-schema.ts";
21
21
  export * from "./api-shield.ts";
22
22
  export * from "./api.ts";
23
+ export * from "./artifacts.ts";
23
24
  export * from "./assets.ts";
24
25
  export * from "./astro/astro.ts";
25
26
  export * from "./bindings.ts";
@@ -167,6 +167,11 @@ export const buildWorkerOptions = async (
167
167
  };
168
168
  break;
169
169
  }
170
+ case "artifacts": {
171
+ throw new Error(
172
+ "Artifacts bindings are not supported in Alchemy local dev yet. Deploy the Worker or use generated Wrangler config with remote Artifacts bindings.",
173
+ );
174
+ }
170
175
  case "assets": {
171
176
  options.assets = {
172
177
  binding: key,
@@ -249,7 +249,9 @@ const writeMiniflareResponseToNode = (
249
249
  });
250
250
 
251
251
  if (res.body) {
252
- Readable.fromWeb(res.body).pipe(out, { end: true });
252
+ const body = Readable.fromWeb(res.body);
253
+ body.on("error", () => out.destroy());
254
+ body.pipe(out, { end: true });
253
255
  } else {
254
256
  out.end();
255
257
  }
@@ -206,6 +206,17 @@ export interface WorkerMetadata {
206
206
  };
207
207
  };
208
208
  logpush?: boolean;
209
+ /**
210
+ * Workers Cache configuration.
211
+ *
212
+ * The wire shape matches what wrangler (>= 4.69) uploads.
213
+ *
214
+ * @see https://developers.cloudflare.com/workers/cache/configuration/
215
+ */
216
+ cache_options?: {
217
+ enabled: boolean;
218
+ cross_version_cache?: boolean;
219
+ };
209
220
  migrations?: SingleStepMigration;
210
221
  main_module?: string;
211
222
  body_part?: string;
@@ -355,6 +366,19 @@ export async function prepareWorkerMetadata(
355
366
  enabled: observability?.enabled !== false,
356
367
  },
357
368
  logpush: props.logpush ?? false,
369
+ cache_options:
370
+ props.cache != null
371
+ ? {
372
+ enabled:
373
+ typeof props.cache === "boolean"
374
+ ? props.cache
375
+ : (props.cache.enabled ?? true),
376
+ cross_version_cache:
377
+ typeof props.cache === "object"
378
+ ? props.cache.crossVersionCache
379
+ : undefined,
380
+ }
381
+ : undefined,
358
382
  // TODO(sam): base64 encode instead? 0 collision risk vs readability.
359
383
  tags: [
360
384
  // encode a mapping table of Durable Object stable ID -> binding name
@@ -516,6 +540,12 @@ export async function prepareWorkerMetadata(
516
540
  jurisdiction:
517
541
  binding.jurisdiction === "default" ? undefined : binding.jurisdiction,
518
542
  });
543
+ } else if (binding.type === "artifacts") {
544
+ meta.bindings.push({
545
+ type: "artifacts",
546
+ name: bindingName,
547
+ namespace: binding.namespace,
548
+ });
519
549
  } else if (binding.type === "send_email") {
520
550
  meta.bindings.push({
521
551
  type: "send_email",
@@ -597,7 +627,9 @@ export async function prepareWorkerMetadata(
597
627
  meta.bindings.push({
598
628
  type: "json",
599
629
  name: bindingName,
600
- json: JSON.stringify(binding.json),
630
+ // send the raw value (like wrangler does) so the runtime injects the
631
+ // native type; stringifying here would inject a string instead
632
+ json: binding.json,
601
633
  });
602
634
  } else if (binding.type === "analytics_engine") {
603
635
  meta.bindings.push({
@@ -249,6 +249,21 @@ export interface BaseWorkerProps<
249
249
  */
250
250
  assets?: AssetsConfig;
251
251
 
252
+ /**
253
+ * Enable Workers Cache — a Worker-owned edge cache in front of this Worker.
254
+ *
255
+ * When enabled, Cloudflare checks the cache before invoking the Worker and
256
+ * serves matching responses directly from the edge. Caching is controlled
257
+ * with standard response headers (`Cache-Control`, `Cache-Tag`, `Vary`) and
258
+ * entries can be purged at runtime with `ctx.cache.purge()`.
259
+ *
260
+ * Pass `true` as shorthand for `{ enabled: true }`.
261
+ *
262
+ * @see https://developers.cloudflare.com/workers/cache/
263
+ * @default undefined - Workers Cache is disabled
264
+ */
265
+ cache?: boolean | WorkerCacheOptions;
266
+
252
267
  /**
253
268
  * Cron expressions for the trigger.
254
269
  *
@@ -431,6 +446,31 @@ export interface BaseWorkerProps<
431
446
  tailConsumers?: Array<Worker | { service: string }>;
432
447
  }
433
448
 
449
+ /**
450
+ * Configuration for Workers Cache — the edge cache that sits in front of a
451
+ * Worker's `fetch()` invocations.
452
+ *
453
+ * @see https://developers.cloudflare.com/workers/cache/configuration/
454
+ */
455
+ export interface WorkerCacheOptions {
456
+ /**
457
+ * If Workers Cache is enabled for this Worker
458
+ *
459
+ * @default true
460
+ */
461
+ enabled?: boolean;
462
+
463
+ /**
464
+ * Whether cached responses may be reused across Worker versions.
465
+ *
466
+ * By default the cache is scoped to a single Worker version, so every
467
+ * deployment starts cold. Enable this when responses are version-agnostic.
468
+ *
469
+ * @default false
470
+ */
471
+ crossVersionCache?: boolean;
472
+ }
473
+
434
474
  export interface WorkerObservability {
435
475
  /**
436
476
  * If observability is enabled for this Worker
@@ -1601,7 +1641,7 @@ async function provisionResources<B extends Bindings>(
1601
1641
  // In local dev mode, queue.id is "" (no Cloudflare API call).
1602
1642
  // Use queue.dev.id (resource ID, e.g. "email-queue") to avoid
1603
1643
  // all consumers colliding on the same "-consumer" resource ID.
1604
- // See: https://github.com/alchemy-run/alchemy/issues/1363
1644
+ // See: https://github.com/alchemy-run/alchemy-async/issues/1363
1605
1645
  const queueConsumerId = options.local
1606
1646
  ? eventSource.queue.dev?.id || eventSource.queue.id
1607
1647
  : eventSource.queue.id;
@@ -264,6 +264,11 @@ async function processBindings(
264
264
  const kvNamespaces: WranglerJsonConfig["kv_namespaces"] = [];
265
265
  const durableObjects: WranglerJsonConfig["durable_objects"]["bindings"] = [];
266
266
  const r2Buckets: WranglerJsonConfig["r2_buckets"] = [];
267
+ const artifacts: {
268
+ binding: string;
269
+ namespace: string;
270
+ remote?: boolean;
271
+ }[] = [];
267
272
  const services: WranglerJsonConfig["services"] = [];
268
273
  const sendEmailBindings: WranglerJsonConfig["send_email"] = [];
269
274
  const secrets: string[] = [];
@@ -422,6 +427,12 @@ async function processBindings(
422
427
  allowed_sender_addresses: binding.allowedSenderAddresses,
423
428
  ...(binding.dev?.remote ? { remote: true } : {}),
424
429
  });
430
+ } else if (binding.type === "artifacts") {
431
+ artifacts.push({
432
+ binding: bindingName,
433
+ namespace: binding.namespace,
434
+ remote: binding.dev?.remote ?? true,
435
+ });
425
436
  } else if (binding.type === "secret") {
426
437
  // Secret binding
427
438
  secrets.push(bindingName);
@@ -598,6 +609,14 @@ async function processBindings(
598
609
  spec.r2_buckets = r2Buckets;
599
610
  }
600
611
 
612
+ if (artifacts.length > 0) {
613
+ (
614
+ spec as WranglerJsonSpec & {
615
+ artifacts?: typeof artifacts;
616
+ }
617
+ ).artifacts = artifacts;
618
+ }
619
+
601
620
  if (services.length > 0) {
602
621
  spec.services = services;
603
622
  }
@@ -415,7 +415,7 @@ export const Zone = Resource(
415
415
 
416
416
  // Add a small delay to ensure settings are propagated
417
417
  // TODO(michael): do we need this?
418
- // https://github.com/alchemy-run/alchemy/issues/681
418
+ // https://github.com/alchemy-run/alchemy-async/issues/681
419
419
  await new Promise((resolve) => setTimeout(resolve, 2000));
420
420
 
421
421
  // Update Bot Management configuration if provided
package/src/scope.ts CHANGED
@@ -324,7 +324,7 @@ export class Scope {
324
324
  destroyStrategy ?? this.parent?.destroyStrategy ?? "sequential";
325
325
  if (this.local) {
326
326
  this.logger.warnOnce(
327
- "Development mode is in beta. Please report any issues to https://github.com/alchemy-run/alchemy/issues.",
327
+ "Development mode is in beta. Please report any issues to https://github.com/alchemy-run/alchemy-async/issues.",
328
328
  );
329
329
  }
330
330
 
@@ -652,7 +652,7 @@ export class Scope {
652
652
  throw e;
653
653
  })) ?? [];
654
654
 
655
- //todo(michael): remove once we deprecate doss; see: https://github.com/alchemy-run/alchemy/issues/585
655
+ //todo(michael): remove once we deprecate doss; see: https://github.com/alchemy-run/alchemy-async/issues/585
656
656
  let hasCorruptedResources = false;
657
657
  if (pendingDeletions) {
658
658
  for (const { resource, oldProps } of pendingDeletions) {