alchemy 0.30.0 → 0.30.1

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 (53) hide show
  1. package/lib/cloudflare/bindings.d.ts +24 -4
  2. package/lib/cloudflare/bindings.d.ts.map +1 -1
  3. package/lib/cloudflare/bindings.js.map +1 -1
  4. package/lib/cloudflare/bound.d.ts +3 -2
  5. package/lib/cloudflare/bound.d.ts.map +1 -1
  6. package/lib/cloudflare/index.d.ts +1 -0
  7. package/lib/cloudflare/index.d.ts.map +1 -1
  8. package/lib/cloudflare/index.js +1 -0
  9. package/lib/cloudflare/index.js.map +1 -1
  10. package/lib/cloudflare/queue.d.ts +24 -0
  11. package/lib/cloudflare/queue.d.ts.map +1 -1
  12. package/lib/cloudflare/queue.js +24 -0
  13. package/lib/cloudflare/queue.js.map +1 -1
  14. package/lib/cloudflare/secret-key.d.ts +120 -0
  15. package/lib/cloudflare/secret-key.d.ts.map +1 -0
  16. package/lib/cloudflare/secret-key.js +92 -0
  17. package/lib/cloudflare/secret-key.js.map +1 -0
  18. package/lib/cloudflare/secret.d.ts +9 -5
  19. package/lib/cloudflare/secret.d.ts.map +1 -1
  20. package/lib/cloudflare/secret.js +13 -5
  21. package/lib/cloudflare/secret.js.map +1 -1
  22. package/lib/cloudflare/secrets-store.d.ts +3 -0
  23. package/lib/cloudflare/secrets-store.d.ts.map +1 -1
  24. package/lib/cloudflare/secrets-store.js +3 -3
  25. package/lib/cloudflare/secrets-store.js.map +1 -1
  26. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  27. package/lib/cloudflare/worker-metadata.js +11 -0
  28. package/lib/cloudflare/worker-metadata.js.map +1 -1
  29. package/lib/cloudflare/worker.d.ts +30 -2
  30. package/lib/cloudflare/worker.d.ts.map +1 -1
  31. package/lib/cloudflare/worker.js.map +1 -1
  32. package/lib/cloudflare/wrangler.json.js +3 -0
  33. package/lib/cloudflare/wrangler.json.js.map +1 -1
  34. package/lib/secret.d.ts +5 -5
  35. package/lib/secret.d.ts.map +1 -1
  36. package/lib/secret.js.map +1 -1
  37. package/lib/serde.d.ts +5 -1
  38. package/lib/serde.d.ts.map +1 -1
  39. package/lib/serde.js +9 -2
  40. package/lib/serde.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/cloudflare/bindings.ts +34 -2
  43. package/src/cloudflare/bound.ts +36 -33
  44. package/src/cloudflare/index.ts +1 -0
  45. package/src/cloudflare/queue.ts +24 -0
  46. package/src/cloudflare/secret-key.ts +143 -0
  47. package/src/cloudflare/secret.ts +55 -41
  48. package/src/cloudflare/secrets-store.ts +4 -5
  49. package/src/cloudflare/worker-metadata.ts +10 -0
  50. package/src/cloudflare/worker.ts +30 -2
  51. package/src/cloudflare/wrangler.json.ts +2 -0
  52. package/src/secret.ts +7 -7
  53. package/src/serde.ts +40 -20
@@ -15,16 +15,17 @@ import type { D1DatabaseResource } from "./d1-database.ts";
15
15
  import type { DispatchNamespaceResource } from "./dispatch-namespace.ts";
16
16
  import type { DurableObjectNamespace } from "./durable-object-namespace.ts";
17
17
  import type { HyperdriveResource } from "./hyperdrive.ts";
18
+ import type { Images } from "./images.ts";
18
19
  import type { KVNamespaceResource } from "./kv-namespace.ts";
19
20
  import type { PipelineResource } from "./pipeline.ts";
20
21
  import type { QueueResource } from "./queue.ts";
22
+ import type { SecretKey } from "./secret-key.ts";
23
+ import type { Secret as CloudflareSecret } from "./secret.ts";
21
24
  import type { VectorizeIndexResource } from "./vectorize-index.ts";
22
25
  import type { VersionMetadata } from "./version-metadata.ts";
23
26
  import type { WorkerStub } from "./worker-stub.ts";
24
27
  import type { Worker, WorkerRef } from "./worker.ts";
25
28
  import type { Workflow } from "./workflow.ts";
26
- import type { Images } from "./images.ts";
27
- import type { Secret as CloudflareSecret } from "./secret.ts";
28
29
 
29
30
  export type Bindings = {
30
31
  [bindingName: string]: Binding;
@@ -59,6 +60,7 @@ export type Binding =
59
60
  id: string;
60
61
  }
61
62
  | Secret
63
+ | SecretKey
62
64
  | string
63
65
  | VectorizeIndexResource
64
66
  | Worker
@@ -105,6 +107,7 @@ export type WorkerBindingSpec =
105
107
  | WorkerBindingPlainText
106
108
  | WorkerBindingQueue
107
109
  | WorkerBindingR2Bucket
110
+ | WorkerBindingSecretKey
108
111
  | WorkerBindingSecretText
109
112
  | WorkerBindingSecretsStore
110
113
  | WorkerBindingSecretsStoreSecret
@@ -291,6 +294,35 @@ export interface WorkerBindingR2Bucket {
291
294
  bucket_name: string;
292
295
  }
293
296
 
297
+ /**
298
+ * Secret Key binding type
299
+ */
300
+ export interface WorkerBindingSecretKey {
301
+ /** The name of the binding */
302
+ name: string;
303
+ /** Type identifier for Secret Key binding */
304
+ type: "secret_key";
305
+ /** Algorithm-specific key parameters */
306
+ algorithm: unknown;
307
+ /** Data format of the key */
308
+ format: "raw" | "pkcs8" | "spki" | "jwk";
309
+ /** Allowed operations with the key */
310
+ usages: Array<
311
+ | "encrypt"
312
+ | "decrypt"
313
+ | "sign"
314
+ | "verify"
315
+ | "deriveKey"
316
+ | "deriveBits"
317
+ | "wrapKey"
318
+ | "unwrapKey"
319
+ >;
320
+ /** Base64-encoded key data. Required if format is "raw", "pkcs8", or "spki" */
321
+ key_base64?: string;
322
+ /** Key data in JSON Web Key format. Required if format is "jwk" */
323
+ key_jwk?: unknown;
324
+ }
325
+
294
326
  /**
295
327
  * Secret Text binding type
296
328
  */
@@ -1,6 +1,5 @@
1
1
  import type { Pipeline } from "cloudflare:pipelines";
2
2
  import type { Secret } from "../secret.ts";
3
- import type { Secret as CloudflareSecret } from "./secret.ts";
4
3
  import type { AiGatewayResource as _AiGateway } from "./ai-gateway.ts";
5
4
  import type { Ai as _Ai } from "./ai.ts";
6
5
  import type { AnalyticsEngineDataset as _AnalyticsEngineDataset } from "./analytics-engine.ts";
@@ -15,6 +14,8 @@ import type { HyperdriveResource as _Hyperdrive } from "./hyperdrive.ts";
15
14
  import type { Images as _Images } from "./images.ts";
16
15
  import type { PipelineResource as _Pipeline } from "./pipeline.ts";
17
16
  import type { QueueResource as _Queue } from "./queue.ts";
17
+ import type { SecretKey } from "./secret-key.ts";
18
+ import type { Secret as CloudflareSecret } from "./secret.ts";
18
19
  import type { VectorizeIndexResource as _VectorizeIndex } from "./vectorize-index.ts";
19
20
  import type { VersionMetadata as _VersionMetadata } from "./version-metadata.ts";
20
21
  import type { Worker as _Worker, WorkerRef } from "./worker.ts";
@@ -46,35 +47,37 @@ export type Bound<T extends Binding> = T extends _DurableObjectNamespace<
46
47
  : T extends Secret
47
48
  ? string
48
49
  : T extends CloudflareSecret
49
- ? string
50
- : T extends Assets
51
- ? Service
52
- : T extends _Workflow<infer P>
53
- ? Workflow<P>
54
- : T extends D1DatabaseResource
55
- ? D1Database
56
- : T extends DispatchNamespaceResource
57
- ? { get(name: string): Fetcher }
58
- : T extends _VectorizeIndex
59
- ? VectorizeIndex
60
- : T extends _Queue<infer Body>
61
- ? Queue<Body>
62
- : T extends _AnalyticsEngineDataset
63
- ? AnalyticsEngineDataset
64
- : T extends _Pipeline<infer R>
65
- ? Pipeline<R>
66
- : T extends string
67
- ? string
68
- : T extends BrowserRendering
69
- ? Fetcher
70
- : T extends _Ai<infer M>
71
- ? Ai<M>
72
- : T extends _Images
73
- ? ImagesBinding
74
- : T extends _VersionMetadata
75
- ? WorkerVersionMetadata
76
- : T extends Self
77
- ? Service
78
- : T extends Json<infer T>
79
- ? T
80
- : Service;
50
+ ? SecretsStoreSecret
51
+ : T extends SecretKey
52
+ ? CryptoKey
53
+ : T extends Assets
54
+ ? Service
55
+ : T extends _Workflow<infer P>
56
+ ? Workflow<P>
57
+ : T extends D1DatabaseResource
58
+ ? D1Database
59
+ : T extends DispatchNamespaceResource
60
+ ? { get(name: string): Fetcher }
61
+ : T extends _VectorizeIndex
62
+ ? VectorizeIndex
63
+ : T extends _Queue<infer Body>
64
+ ? Queue<Body>
65
+ : T extends _AnalyticsEngineDataset
66
+ ? AnalyticsEngineDataset
67
+ : T extends _Pipeline<infer R>
68
+ ? Pipeline<R>
69
+ : T extends string
70
+ ? string
71
+ : T extends BrowserRendering
72
+ ? Fetcher
73
+ : T extends _Ai<infer M>
74
+ ? Ai<M>
75
+ : T extends _Images
76
+ ? ImagesBinding
77
+ : T extends _VersionMetadata
78
+ ? WorkerVersionMetadata
79
+ : T extends Self
80
+ ? Service
81
+ : T extends Json<infer T>
82
+ ? T
83
+ : Service;
@@ -39,6 +39,7 @@ export * from "./react-router.ts";
39
39
  export * from "./redwood.ts";
40
40
  export * from "./route.ts";
41
41
  export * from "./secret.ts";
42
+ export * from "./secret-key.ts";
42
43
  export * from "./secrets-store.ts";
43
44
  export * from "./sveltekit.ts";
44
45
  export * from "./tanstack-start.ts";
@@ -176,6 +176,30 @@ export type Queue<Body = unknown> = QueueResource<Body> &
176
176
  * dlq: dlqQueue
177
177
  * });
178
178
  *
179
+ * @example
180
+ * // Create a queue and configure Worker consumer with custom settings
181
+ * const processingQueue = await Queue("processing-queue", {
182
+ * name: "processing-queue"
183
+ * });
184
+ *
185
+ * const processingWorker = await Worker("processor", {
186
+ * entrypoint: "./src/processor.ts",
187
+ * bindings: {
188
+ * QUEUE: processingQueue // Producer: bind queue for sending messages
189
+ * },
190
+ * eventSources: [{ // Consumer: configure processing settings
191
+ * queue: processingQueue,
192
+ * settings: {
193
+ * batchSize: 25, // Process 25 messages at once
194
+ * maxConcurrency: 5, // Allow 5 concurrent invocations
195
+ * maxRetries: 3, // Retry failed messages up to 3 times
196
+ * maxWaitTimeMs: 1500, // Wait up to 1.5 seconds to fill a batch
197
+ * retryDelay: 45, // Wait 45 seconds before retrying failed messages
198
+ * deadLetterQueue: "failed-processing" // Send failed messages to DLQ
199
+ * }
200
+ * }]
201
+ * });
202
+ *
179
203
  * @see https://developers.cloudflare.com/queues/
180
204
  */
181
205
  export async function Queue<Body = unknown>(
@@ -0,0 +1,143 @@
1
+ /**
2
+ * SecretKey binding for Cloudflare Workers
3
+ *
4
+ * A data class that represents a secret key binding with cryptographic properties.
5
+ * Keys are securely stored and exposed as CryptoKey objects for use with the Web Crypto API.
6
+ *
7
+ * @example
8
+ * // Create an RSA signing key from a JWK format:
9
+ * const keyPair = await crypto.subtle.generateKey(
10
+ * {
11
+ * name: "RSA-PSS",
12
+ * modulusLength: 2048,
13
+ * publicExponent: new Uint8Array([1, 0, 1]),
14
+ * hash: "SHA-256",
15
+ * },
16
+ * true,
17
+ * ["sign", "verify"]
18
+ * );
19
+ *
20
+ * const privateKeyJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
21
+ *
22
+ * const signingKey = new SecretKey({
23
+ * algorithm: { name: "RSA-PSS", hash: "SHA-256" },
24
+ * format: "jwk",
25
+ * usages: ["sign"],
26
+ * key_jwk: secret(privateKeyJwk),
27
+ * });
28
+ *
29
+ * @example
30
+ * // Create an AES encryption key from raw bytes:
31
+ * const aesKey = await crypto.subtle.generateKey(
32
+ * { name: "AES-GCM", length: 256 },
33
+ * true,
34
+ * ["encrypt", "decrypt"]
35
+ * );
36
+ *
37
+ * const keyData = await crypto.subtle.exportKey("raw", aesKey);
38
+ * const keyBase64 = btoa(String.fromCharCode(...new Uint8Array(keyData)));
39
+ *
40
+ * const encryptionKey = new SecretKey({
41
+ * algorithm: { name: "AES-GCM" },
42
+ * format: "raw",
43
+ * usages: ["encrypt", "decrypt"],
44
+ * key_base64: secret(keyBase64),
45
+ * });
46
+ *
47
+ * @example
48
+ * // Create an ECDSA key from PKCS#8 format:
49
+ * const ecdsaKey = new SecretKey({
50
+ * algorithm: { name: "ECDSA", namedCurve: "P-256" },
51
+ * format: "pkcs8",
52
+ * usages: ["sign"],
53
+ * key_base64: secret("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg..."),
54
+ * });
55
+ *
56
+ * @example
57
+ * // Create an HMAC key for message authentication:
58
+ * const hmacKey = await crypto.subtle.generateKey(
59
+ * { name: "HMAC", hash: "SHA-256" },
60
+ * true,
61
+ * ["sign", "verify"]
62
+ * );
63
+ *
64
+ * const keyData = await crypto.subtle.exportKey("raw", hmacKey);
65
+ * const keyBase64 = btoa(String.fromCharCode(...new Uint8Array(keyData)));
66
+ *
67
+ * const macKey = new SecretKey({
68
+ * algorithm: { name: "HMAC", hash: "SHA-256" },
69
+ * format: "raw",
70
+ * usages: ["sign", "verify"],
71
+ * key_base64: secret(keyBase64),
72
+ * });
73
+ *
74
+ * @see https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/update/
75
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#keyusages
76
+ */
77
+
78
+ import type { Secret } from "../secret.ts";
79
+
80
+ /**
81
+ * Data format of the key
82
+ */
83
+ export type SecretKeyFormat = "raw" | "pkcs8" | "spki" | "jwk";
84
+
85
+ /**
86
+ * Allowed operations with the key
87
+ */
88
+ export type SecretKeyUsage =
89
+ | "encrypt"
90
+ | "decrypt"
91
+ | "sign"
92
+ | "verify"
93
+ | "deriveKey"
94
+ | "deriveBits"
95
+ | "wrapKey"
96
+ | "unwrapKey";
97
+
98
+ /**
99
+ * SecretKey binding properties
100
+ */
101
+ export interface SecretKeyProps {
102
+ /**
103
+ * Algorithm-specific key parameters
104
+ */
105
+ algorithm: unknown;
106
+
107
+ /**
108
+ * Data format of the key
109
+ */
110
+ format: SecretKeyFormat;
111
+
112
+ /**
113
+ * Allowed operations with the key
114
+ */
115
+ usages: SecretKeyUsage[];
116
+
117
+ /**
118
+ * Base64-encoded key data. Required if format is "raw", "pkcs8", or "spki"
119
+ */
120
+ key_base64?: Secret;
121
+
122
+ /**
123
+ * Key data in JSON Web Key format. Required if format is "jwk"
124
+ */
125
+ key_jwk?: Secret<JsonWebKey>;
126
+ }
127
+
128
+ export class SecretKey {
129
+ readonly type = "secret_key";
130
+ readonly algorithm: unknown;
131
+ readonly format: SecretKeyFormat;
132
+ readonly usages: SecretKeyUsage[];
133
+ readonly key_base64?: Secret;
134
+ readonly key_jwk?: Secret<JsonWebKey>;
135
+
136
+ constructor(props: SecretKeyProps) {
137
+ this.algorithm = props.algorithm;
138
+ this.format = props.format;
139
+ this.usages = props.usages;
140
+ this.key_base64 = props.key_base64;
141
+ this.key_jwk = props.key_jwk;
142
+ }
143
+ }
@@ -10,7 +10,7 @@ import {
10
10
  type CloudflareApi,
11
11
  type CloudflareApiOptions,
12
12
  } from "./api.ts";
13
- import type { SecretsStore } from "./secrets-store.ts";
13
+ import { findSecretsStoreByName, SecretsStore } from "./secrets-store.ts";
14
14
 
15
15
  /**
16
16
  * Properties for creating or updating a Secret in a Secrets Store (internal interface)
@@ -18,8 +18,10 @@ import type { SecretsStore } from "./secrets-store.ts";
18
18
  interface _SecretProps extends CloudflareApiOptions {
19
19
  /**
20
20
  * The secrets store to add this secret to
21
+ *
22
+ * @default - the default-secret-store
21
23
  */
22
- store: SecretsStore<any>;
24
+ store?: SecretsStore<any>;
23
25
 
24
26
  /**
25
27
  * The secret value to store (must be an AlchemySecret for security)
@@ -41,8 +43,10 @@ interface _SecretProps extends CloudflareApiOptions {
41
43
  export interface SecretProps extends CloudflareApiOptions {
42
44
  /**
43
45
  * The secrets store to add this secret to
46
+ *
47
+ * @default - the default-secret-store
44
48
  */
45
- store: SecretsStore<any>;
49
+ store?: SecretsStore<any>;
46
50
 
47
51
  /**
48
52
  * The secret value to store
@@ -71,39 +75,38 @@ export function isSecret(resource: Resource): resource is Secret {
71
75
  return resource[ResourceKind] === "cloudflare::Secret";
72
76
  }
73
77
 
74
- export interface Secret
75
- extends Resource<"cloudflare::Secret">,
76
- Omit<_SecretProps, "delete"> {
77
- /**
78
- * The binding type for Cloudflare Workers
79
- */
80
- type: "secrets_store_secret";
81
-
82
- /**
83
- * The name of the secret
84
- */
85
- name: string;
86
-
87
- /**
88
- * The unique identifier of the secrets store this secret belongs to
89
- */
90
- storeId: string;
91
-
92
- /**
93
- * The secret value (as an alchemy Secret instance)
94
- */
95
- value: AlchemySecret;
96
-
97
- /**
98
- * Timestamp when the secret was created
99
- */
100
- createdAt: number;
101
-
102
- /**
103
- * Timestamp when the secret was last modified
104
- */
105
- modifiedAt: number;
106
- }
78
+ export type Secret = Resource<"cloudflare::Secret"> &
79
+ Omit<_SecretProps, "delete"> & {
80
+ /**
81
+ * The binding type for Cloudflare Workers
82
+ */
83
+ type: "secrets_store_secret";
84
+
85
+ /**
86
+ * The name of the secret
87
+ */
88
+ name: string;
89
+
90
+ /**
91
+ * The unique identifier of the secrets store this secret belongs to
92
+ */
93
+ storeId: string;
94
+
95
+ /**
96
+ * The secret value (as an alchemy Secret instance)
97
+ */
98
+ value: AlchemySecret;
99
+
100
+ /**
101
+ * Timestamp when the secret was created
102
+ */
103
+ createdAt: number;
104
+
105
+ /**
106
+ * Timestamp when the secret was last modified
107
+ */
108
+ modifiedAt: number;
109
+ };
107
110
 
108
111
  /**
109
112
  * A Cloudflare Secret represents an individual secret stored in a Secrets Store.
@@ -179,9 +182,20 @@ const _Secret = Resource(
179
182
  ): Promise<Secret> {
180
183
  const api = await createCloudflareApi(props);
181
184
 
185
+ const storeId =
186
+ props.store?.id ??
187
+ (await findSecretsStoreByName(api, SecretsStore.Default))?.id ??
188
+ (
189
+ await SecretsStore("default-store", {
190
+ name: SecretsStore.Default,
191
+ adopt: true,
192
+ delete: false,
193
+ })
194
+ )?.id!;
195
+
182
196
  if (this.phase === "delete") {
183
197
  if (props.delete !== false) {
184
- await deleteSecret(api, props.store.id, name);
198
+ await deleteSecret(api, storeId, name);
185
199
  }
186
200
  return this.destroy();
187
201
  }
@@ -192,12 +206,12 @@ const _Secret = Resource(
192
206
  : Date.now();
193
207
 
194
208
  // Insert or update the secret
195
- await insertSecret(api, props.store.id, name, props.value);
209
+ await insertSecret(api, storeId, name, props.value);
196
210
 
197
211
  return this({
198
212
  type: "secrets_store_secret",
199
213
  name,
200
- storeId: props.store.id,
214
+ storeId,
201
215
  store: props.store,
202
216
  value: props.value,
203
217
  createdAt,
@@ -317,10 +331,10 @@ export async function deleteSecret(
317
331
  storeId: string,
318
332
  secretName: string,
319
333
  ): Promise<void> {
334
+ const secretId = await getSecretId(api, storeId, secretName);
320
335
  const response = await api.delete(
321
- `/accounts/${api.accountId}/secrets_store/stores/${storeId}/secrets`,
336
+ `/accounts/${api.accountId}/secrets_store/stores/${storeId}/secrets/${secretId}`,
322
337
  {
323
- body: JSON.stringify([secretName]),
324
338
  headers: {
325
339
  "Content-Type": "application/json",
326
340
  },
@@ -168,6 +168,10 @@ export async function SecretsStore<
168
168
  return _SecretsStore(name, normalizedProps);
169
169
  }
170
170
 
171
+ export namespace SecretsStore {
172
+ export const Default = "default_secrets_store";
173
+ }
174
+
171
175
  const _SecretsStore = Resource("cloudflare::SecretsStore", async function <
172
176
  S extends Record<string, Secret> | undefined = undefined,
173
177
  >(this: Context<SecretsStore<S>>, id: string, props: SecretsStoreProps<S>): Promise<
@@ -206,17 +210,12 @@ const _SecretsStore = Resource("cloudflare::SecretsStore", async function <
206
210
  } else {
207
211
  // If adopt is true, first check if a store with this name already exists
208
212
  if (props.adopt) {
209
- console.log(`Checking for existing secrets store '${name}' to adopt`);
210
213
  const existingStore = await findSecretsStoreByName(api, name);
211
214
 
212
215
  if (existingStore) {
213
- console.log(`Found existing secrets store '${name}', adopting it`);
214
216
  storeId = existingStore.id;
215
217
  createdAt = existingStore.createdAt || Date.now();
216
218
  } else {
217
- console.log(
218
- `No existing secrets store '${name}' found, creating new one`,
219
- );
220
219
  const { id } = await createSecretsStore(api, {
221
220
  ...props,
222
221
  name,
@@ -484,6 +484,16 @@ export async function prepareWorkerMetadata<B extends Bindings>(
484
484
  name: bindingName,
485
485
  namespace: binding.namespaceName,
486
486
  });
487
+ } else if (binding.type === "secret_key") {
488
+ meta.bindings.push({
489
+ type: "secret_key",
490
+ name: bindingName,
491
+ algorithm: binding.algorithm,
492
+ format: binding.format,
493
+ usages: binding.usages,
494
+ key_base64: binding.key_base64?.unencrypted,
495
+ key_jwk: binding.key_jwk?.unencrypted,
496
+ });
487
497
  } else {
488
498
  // @ts-expect-error - we should never reach here
489
499
  throw new Error(`Unsupported binding type: ${binding.type}`);
@@ -599,8 +599,36 @@ export function WorkerRef<
599
599
  * }
600
600
  * });
601
601
  *
602
- * @see
603
- * https://developers.cloudflare.com/workers/
602
+ * @example
603
+ * // Create a worker with queue event sources and custom consumer settings:
604
+ * const taskQueue = await Queue("task-queue", {
605
+ * name: "task-queue"
606
+ * });
607
+ *
608
+ * const dlq = await Queue("failed-tasks", {
609
+ * name: "failed-tasks"
610
+ * });
611
+ *
612
+ * const queueWorker = await Worker("queue-processor", {
613
+ * name: "queue-processor",
614
+ * entrypoint: "./src/processor.ts",
615
+ * bindings: {
616
+ * TASK_QUEUE: taskQueue // Producer: bind queue for sending messages
617
+ * },
618
+ * eventSources: [{ // Consumer: configure processing settings
619
+ * queue: taskQueue,
620
+ * settings: {
621
+ * batchSize: 15, // Process 15 messages at once
622
+ * maxConcurrency: 3, // Allow 3 concurrent invocations
623
+ * maxRetries: 5, // Retry failed messages up to 5 times
624
+ * maxWaitTimeMs: 2500, // Wait up to 2.5 seconds to fill a batch
625
+ * retryDelay: 60, // Wait 60 seconds before retrying failed messages
626
+ * deadLetterQueue: dlq // Send failed messages to dead letter queue
627
+ * }
628
+ * }]
629
+ * });
630
+ *
631
+ * @see https://developers.cloudflare.com/workers/
604
632
  */
605
633
  export function Worker<
606
634
  const B extends Bindings,
@@ -607,6 +607,8 @@ function processBindings(
607
607
  binding: bindingName,
608
608
  namespace: binding.namespaceName,
609
609
  });
610
+ } else if (binding.type === "secret_key") {
611
+ // no-op
610
612
  } else {
611
613
  // biome-ignore lint/correctness/noVoidTypeReturn: it returns never
612
614
  return assertNever(binding);
package/src/secret.ts CHANGED
@@ -8,7 +8,7 @@ declare global {
8
8
 
9
9
  // a global registry of all secrets that we will use when serializing an application
10
10
  const globalSecrets: {
11
- [name: string]: Secret;
11
+ [name: string]: Secret<any>;
12
12
  } = (globalThis.__ALCHEMY_SECRETS__ ??= {});
13
13
 
14
14
  let i = 0;
@@ -53,19 +53,19 @@ const SecretSymbol = Symbol.for("alchemy::Secret");
53
53
  * }
54
54
  * }
55
55
  */
56
- export class Secret {
56
+ export class Secret<T = string> {
57
57
  [SecretSymbol] = true;
58
58
 
59
59
  /**
60
60
  * @internal
61
61
  */
62
- public static all(): Secret[] {
62
+ public static all(): Secret<any>[] {
63
63
  return Object.values(globalSecrets);
64
64
  }
65
65
 
66
66
  public readonly type = "secret";
67
67
  constructor(
68
- readonly unencrypted: string,
68
+ readonly unencrypted: T,
69
69
  readonly name: string = nextName(),
70
70
  ) {
71
71
  globalSecrets[name] = this;
@@ -111,10 +111,10 @@ export function isSecret(binding: any): binding is Secret {
111
111
  * @throws {Error} If the value is undefined
112
112
  * @throws {Error} If no password is set in the alchemy application options or current scope
113
113
  */
114
- export function secret<S extends string | undefined>(
115
- unencrypted: S,
114
+ export function secret<S = string>(
115
+ unencrypted: S | undefined,
116
116
  name?: string,
117
- ): Secret {
117
+ ): Secret<S> {
118
118
  if (unencrypted === undefined) {
119
119
  throw new Error("Secret cannot be undefined");
120
120
  }