alchemy 0.6.0 → 0.7.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.
@@ -1,243 +1,140 @@
1
1
  import type { Context } from "../context";
2
2
  import { Resource } from "../resource";
3
+ import type { Worker } from "./worker";
3
4
  /**
4
5
  * Properties for wrangler.json configuration file
5
6
  */
6
7
  export interface WranglerJsonProps {
8
+ name?: string;
7
9
  /**
8
- * The name of your worker
10
+ * The worker to generate the wrangler.json file for
9
11
  */
10
- name: string;
12
+ worker: Worker;
11
13
  /**
12
- * The directory containing your worker entry point
13
- * @default "src"
14
+ * Path to write the wrangler.json file to
15
+ *
16
+ * @default cwd/wrangler.json
14
17
  */
15
- main?: string;
18
+ path?: string;
19
+ }
20
+ /**
21
+ * Output returned after WranglerJson creation/update
22
+ */
23
+ export interface WranglerJson extends Resource<"cloudflare::WranglerJson">, WranglerJsonProps {
16
24
  /**
17
- * The entry point for your worker
18
- * @default "index.ts" or "index.js"
25
+ * Time at which the file was created
19
26
  */
20
- entrypoint?: string;
27
+ createdAt: number;
21
28
  /**
22
- * The directory to store build artifacts
23
- * @default "dist"
29
+ * Time at which the file was last updated
24
30
  */
25
- outdir?: string;
31
+ updatedAt: number;
26
32
  /**
27
- * The directory to serve static assets from
33
+ * Path to the wrangler.json file
28
34
  */
29
- assets?: string;
35
+ path: string;
36
+ }
37
+ /**
38
+ * Resource for managing wrangler.json configuration files
39
+ */
40
+ export declare const WranglerJson: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<WranglerJson>, id: string, props: WranglerJsonProps) => Promise<WranglerJson>);
41
+ /**
42
+ * Wrangler.json configuration specification based on Cloudflare's schema
43
+ */
44
+ export interface WranglerJsonSpec {
30
45
  /**
31
- * Minify the worker script
32
- * @default true
46
+ * The name of the worker
33
47
  */
34
- minify?: boolean;
48
+ name: string;
35
49
  /**
36
- * Node.js compatibility mode
37
- * @default false
50
+ * Main entry point for the worker
38
51
  */
39
- node_compat?: boolean;
52
+ main?: string;
40
53
  /**
41
- * First-party worker service bindings
54
+ * A date in the form yyyy-mm-dd used to determine Workers runtime version
42
55
  */
43
- services?: Array<{
44
- /**
45
- * Binding name
46
- */
47
- name: string;
48
- /**
49
- * Service environment
50
- */
51
- environment?: string;
52
- }>;
56
+ compatibility_date?: string;
53
57
  /**
54
- * Worker environment variables
58
+ * A list of flags that enable features from upcoming Workers runtime
55
59
  */
56
- vars?: Record<string, string>;
60
+ compatibility_flags?: string[];
57
61
  /**
58
- * KV Namespace bindings
62
+ * Whether to enable a workers.dev URL for this worker
59
63
  */
60
- kv_namespaces?: Array<{
61
- /**
62
- * Binding name
63
- */
64
- binding: string;
65
- /**
66
- * KV namespace ID
67
- */
68
- id: string;
69
- /**
70
- * Preview KV namespace ID
71
- */
72
- preview_id?: string;
73
- }>;
64
+ workers_dev?: boolean;
74
65
  /**
75
- * R2 bucket bindings
66
+ * Routes to attach to the worker
76
67
  */
77
- r2_buckets?: Array<{
78
- /**
79
- * Binding name
80
- */
81
- binding: string;
82
- /**
83
- * Bucket name
84
- */
85
- bucket_name: string;
86
- /**
87
- * Preview bucket name
88
- */
89
- preview_bucket_name?: string;
90
- }>;
91
- /**
92
- * D1 database bindings
93
- */
94
- d1_databases?: Array<{
95
- /**
96
- * Binding name
97
- */
68
+ routes?: string[];
69
+ /**
70
+ * KV Namespace bindings
71
+ */
72
+ kv_namespaces?: {
98
73
  binding: string;
99
- /**
100
- * Database name
101
- */
102
- database_name: string;
103
- /**
104
- * Database ID
105
- */
106
- database_id: string;
107
- /**
108
- * Preview database ID
109
- */
110
- preview_database_id?: string;
111
- }>;
74
+ id: string;
75
+ }[];
112
76
  /**
113
77
  * Durable Object bindings
114
78
  */
115
79
  durable_objects?: {
116
- /**
117
- * Durable Object bindings
118
- */
119
- bindings: Array<{
120
- /**
121
- * Binding name
122
- */
80
+ bindings: {
123
81
  name: string;
124
- /**
125
- * Class name
126
- */
127
82
  class_name: string;
128
- /**
129
- * Script name
130
- */
131
83
  script_name?: string;
132
- /**
133
- * Environment name
134
- */
135
84
  environment?: string;
136
- }>;
137
- };
138
- /**
139
- * Queue bindings
140
- */
141
- queues?: {
142
- /**
143
- * Producer bindings
144
- */
145
- producers?: Array<{
146
- /**
147
- * Binding name
148
- */
149
- binding: string;
150
- /**
151
- * Queue name
152
- */
153
- queue: string;
154
- }>;
155
- /**
156
- * Consumer configuration
157
- */
158
- consumers?: Array<{
159
- /**
160
- * Queue name
161
- */
162
- queue: string;
163
- /**
164
- * Maximum batch size
165
- */
166
- max_batch_size?: number;
167
- /**
168
- * Maximum batch timeout
169
- */
170
- max_batch_timeout?: number;
171
- /**
172
- * Maximum retries
173
- */
174
- max_retries?: number;
175
- /**
176
- * Dead letter queue
177
- */
178
- dead_letter_queue?: string;
179
- }>;
85
+ }[];
180
86
  };
181
87
  /**
182
- * Analytics Engine bindings
88
+ * R2 bucket bindings
183
89
  */
184
- analytics_engine_datasets?: Array<{
185
- /**
186
- * Binding name
187
- */
90
+ r2_buckets?: {
188
91
  binding: string;
189
- /**
190
- * Dataset name
191
- */
192
- dataset?: string;
193
- }>;
92
+ bucket_name: string;
93
+ }[];
194
94
  /**
195
- * Route configuration
95
+ * Queue bindings
196
96
  */
197
- routes?: Array<string>;
97
+ queues?: {
98
+ binding: string;
99
+ queue: string;
100
+ }[];
198
101
  /**
199
- * Triggers configuration
102
+ * Service bindings
200
103
  */
201
- triggers?: {
202
- /**
203
- * Cron triggers
204
- */
205
- crons: Array<string>;
206
- };
104
+ services?: {
105
+ binding: string;
106
+ service: string;
107
+ environment?: string;
108
+ }[];
207
109
  /**
208
- * Worker compatibility date
110
+ * Workflow bindings
209
111
  */
210
- compatibility_date?: string;
112
+ workflows?: {
113
+ name: string;
114
+ binding: string;
115
+ class_name: string;
116
+ }[];
211
117
  /**
212
- * Worker compatibility flags
118
+ * Plain text bindings (vars)
213
119
  */
214
- compatibility_flags?: Array<string>;
120
+ vars?: Record<string, string>;
215
121
  /**
216
- * Worker usage model
217
- * "bundled" - Includes resources like CPU and memory. Better for consistent workloads.
218
- * "unbound" - Pay only for what you use. Better for sporadic workloads.
122
+ * Assets bindings
219
123
  */
220
- usage_model?: "bundled" | "unbound";
124
+ assets?: {
125
+ directory: string;
126
+ binding: string;
127
+ };
221
128
  /**
222
- * Path to the wrangler.json file
223
- * @internal
129
+ * Workflow bindings
224
130
  */
225
- path?: string;
226
- }
227
- /**
228
- * Output returned after WranglerJson creation/update
229
- */
230
- export interface WranglerJson extends Resource<"cloudflare::WranglerJson">, WranglerJsonProps {
131
+ wasm_modules?: Record<string, string>;
231
132
  /**
232
- * Time at which the file was created
133
+ * Safe mode configuration
233
134
  */
234
- createdAt: number;
135
+ node_compat?: boolean;
235
136
  /**
236
- * Time at which the file was last updated
137
+ * Whether to minify the worker script
237
138
  */
238
- updatedAt: number;
139
+ minify?: boolean;
239
140
  }
240
- /**
241
- * Resource for managing wrangler.json configuration files
242
- */
243
- export declare const WranglerJson: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<WranglerJson>, id: string, props: WranglerJsonProps) => Promise<WranglerJson>);
@@ -1,4 +1,4 @@
1
- import * as fs from "fs/promises";
1
+ import { StaticJsonFile } from "../fs";
2
2
  import { Resource } from "../resource";
3
3
  /**
4
4
  * Resource for managing wrangler.json configuration files
@@ -7,29 +7,136 @@ export const WranglerJson = Resource("cloudflare::WranglerJson", async function
7
7
  // Default path is wrangler.json in current directory
8
8
  const filePath = props.path || "wrangler.json";
9
9
  if (this.phase === "delete") {
10
- try {
11
- await fs.unlink(filePath);
12
- }
13
- catch (error) {
14
- // Ignore errors if file doesn't exist
15
- if (error.code !== "ENOENT") {
16
- throw error;
17
- }
18
- }
19
10
  return this.destroy();
20
11
  }
21
- // Create or update the file
22
- const config = {
23
- ...props,
24
- // Remove internal path property
25
- path: undefined,
12
+ if (props.worker.entrypoint === undefined) {
13
+ throw new Error("Worker must have an entrypoint to generate a wrangler.json");
14
+ }
15
+ const worker = props.worker;
16
+ const spec = {
17
+ name: worker.name,
18
+ // Use entrypoint as main if it exists
19
+ main: worker.entrypoint,
20
+ // see: https://developers.cloudflare.com/workers/configuration/compatibility-dates/
21
+ compatibility_date: "2022-04-05",
26
22
  };
27
- // Write the file
28
- await fs.writeFile(filePath, JSON.stringify(config, null, 2));
23
+ // Process bindings if they exist
24
+ if (worker.bindings) {
25
+ processBindings(spec, worker.bindings);
26
+ }
27
+ // Add environment variables as vars
28
+ if (worker.env) {
29
+ spec.vars = { ...worker.env };
30
+ }
31
+ await StaticJsonFile("wrangler.json", spec);
29
32
  // Return the resource
30
33
  return this({
31
34
  ...props,
35
+ path: filePath,
32
36
  createdAt: Date.now(),
33
37
  updatedAt: Date.now(),
34
38
  });
35
39
  });
40
+ /**
41
+ * Process worker bindings into wrangler.json format
42
+ */
43
+ function processBindings(spec, bindings) {
44
+ // Arrays to collect different binding types
45
+ const kvNamespaces = [];
46
+ const durableObjects = [];
47
+ const r2Buckets = [];
48
+ const services = [];
49
+ const secrets = [];
50
+ const workflows = [];
51
+ const d1Databases = [];
52
+ const queues = [];
53
+ // Process each binding
54
+ for (const [bindingName, binding] of Object.entries(bindings)) {
55
+ if (typeof binding === "string") {
56
+ // Plain text binding - add to vars
57
+ if (!spec.vars) {
58
+ spec.vars = {};
59
+ }
60
+ spec.vars[bindingName] = binding;
61
+ }
62
+ else if (binding.type === "kv_namespace") {
63
+ // KV Namespace binding
64
+ kvNamespaces.push({
65
+ binding: bindingName,
66
+ id: binding.namespaceId,
67
+ });
68
+ }
69
+ else if (typeof binding === "object" &&
70
+ binding.type === "durable_object_namespace") {
71
+ // Durable Object binding
72
+ const doBinding = binding;
73
+ durableObjects.push({
74
+ name: bindingName,
75
+ class_name: doBinding.className,
76
+ script_name: doBinding.scriptName,
77
+ environment: doBinding.environment,
78
+ });
79
+ }
80
+ else if (binding.type === "r2_bucket") {
81
+ r2Buckets.push({
82
+ binding: bindingName,
83
+ bucket_name: binding.name,
84
+ });
85
+ }
86
+ else if (binding.type === "service") {
87
+ // Service binding
88
+ services.push({
89
+ binding: bindingName,
90
+ service: binding.id,
91
+ });
92
+ }
93
+ else if (binding.type === "secret") {
94
+ // Secret binding
95
+ secrets.push(bindingName);
96
+ }
97
+ else if (binding.type === "assets") {
98
+ spec.assets = {
99
+ directory: binding.path,
100
+ binding: bindingName,
101
+ };
102
+ }
103
+ else if (binding.type === "workflow") {
104
+ workflows.push({
105
+ name: bindingName,
106
+ binding: binding.id,
107
+ class_name: binding.className,
108
+ });
109
+ }
110
+ else if (binding.type === "d1") {
111
+ d1Databases.push({
112
+ binding: bindingName,
113
+ database_id: binding.id,
114
+ database_name: binding.name,
115
+ });
116
+ }
117
+ else if (binding.type === "queue") {
118
+ queues.push({
119
+ binding: bindingName,
120
+ queue: binding.name,
121
+ });
122
+ }
123
+ }
124
+ // Add collected bindings to the spec
125
+ if (kvNamespaces.length > 0) {
126
+ spec.kv_namespaces = kvNamespaces;
127
+ }
128
+ if (durableObjects.length > 0) {
129
+ spec.durable_objects = {
130
+ bindings: durableObjects,
131
+ };
132
+ }
133
+ if (r2Buckets.length > 0) {
134
+ spec.r2_buckets = r2Buckets;
135
+ }
136
+ if (services.length > 0) {
137
+ spec.services = services;
138
+ }
139
+ if (queues.length > 0) {
140
+ spec.queues = queues;
141
+ }
142
+ }
@@ -70,7 +70,7 @@ async function generateProviderDocs({ provider, outDir, parallel, }) {
70
70
  The ${provider} Service has the following resources:
71
71
  ${alchemy.files(files)}
72
72
 
73
- A file is considered a "Resource" if it contains a const <ResourceName> = Resource(...) call or if it is a function that calls a Resource function, e.g. const TypeScriptFile = () => File(...).
73
+ A file is considered a "Resource" if it contains a const <ResourceName> = Resource(...) call or if it is a function that calls a Resource function, e.g. const TypeScriptFile = () => File(...), or it is the Workflow or DurableObject classes.
74
74
  A file is considered a "Client" if it exposes a wrapper around creating a SDK client or fetch.
75
75
  A file is considered a "Utility" if it contains utility functions that are not resources or clients.
76
76
  A file is considered a "Types" if it contains just type definitions and maybe helpers around working with those types.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemy",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "module": "./lib/index.js",
6
6
  "scripts": {
@@ -6,9 +6,12 @@
6
6
  import type { Secret } from "../secret";
7
7
  import type { Assets } from "./assets";
8
8
  import type { R2Bucket } from "./bucket";
9
+ import type { D1Database } from "./d1-database";
9
10
  import type { DurableObjectNamespace } from "./durable-object-namespace";
10
11
  import type { KVNamespace } from "./kv-namespace";
12
+ import type { Queue } from "./queue";
11
13
  import type { Worker } from "./worker";
14
+ import type { Workflow } from "./workflow";
12
15
 
13
16
  export type Bindings = {
14
17
  [bindingName: string]: Binding;
@@ -18,28 +21,16 @@ export type Bindings = {
18
21
  * L2 Binding Resources.
19
22
  */
20
23
  export type Binding =
24
+ | Assets
25
+ | D1Database
21
26
  | DurableObjectNamespace
22
27
  | KVNamespace
23
- | Worker
28
+ | Queue
24
29
  | R2Bucket
25
30
  | Secret
26
31
  | string
27
- | Assets;
28
-
29
- export function isDurableObjectNamespace(
30
- binding: Binding
31
- ): binding is DurableObjectNamespace {
32
- return (
33
- typeof binding === "object" && binding.type === "durable_object_namespace"
34
- );
35
- }
36
-
37
- /**
38
- * Check if a binding is an Assets resource
39
- */
40
- export function isAssets(binding: Binding): binding is Assets {
41
- return typeof binding === "object" && binding.type === "assets";
42
- }
32
+ | Worker
33
+ | Workflow;
43
34
 
44
35
  /**
45
36
  * Union type for all Worker binding types (API spec)
@@ -65,7 +56,8 @@ export type WorkerBindingSpec =
65
56
  | WorkerBindingTailConsumer
66
57
  | WorkerBindingVectorize
67
58
  | WorkerBindingVersionMetadata
68
- | WorkerBindingWasmModule;
59
+ | WorkerBindingWasmModule
60
+ | WorkerBindingWorkflow;
69
61
 
70
62
  /**
71
63
  * AI binding type
@@ -326,3 +318,20 @@ export interface WorkerBindingStaticContent {
326
318
  /** Type identifier for Static Content binding */
327
319
  type: "static_content";
328
320
  }
321
+
322
+ export interface WorkerBindingWorkflow {
323
+ /** The name of the binding */
324
+ name: string;
325
+ /** Type identifier for Workflow binding */
326
+ type: "workflow";
327
+ /** Workflow name */
328
+ workflow_name: string;
329
+ /** Workflow class name */
330
+ class_name: string;
331
+ /**
332
+ * Workflow script name
333
+ *
334
+ * @default - the name of the script it is bound to
335
+ */
336
+ script_name?: string;
337
+ }
@@ -2,9 +2,12 @@ import type { Secret } from "../secret";
2
2
  import type { Assets } from "./assets";
3
3
  import type { Binding } from "./bindings";
4
4
  import type { R2Bucket as _R2Bucket } from "./bucket";
5
+ import type { D1Database as _D1Database } from "./d1-database";
5
6
  import type { DurableObjectNamespace as _DurableObjectNamespace } from "./durable-object-namespace";
6
7
  import type { KVNamespace as _KVNamespace } from "./kv-namespace";
8
+ import type { Queue as _Queue } from "./queue";
7
9
  import type { Worker as _Worker } from "./worker";
10
+ import type { Workflow as _Workflow } from "./workflow";
8
11
 
9
12
  export type Bound<T extends Binding> = T extends _DurableObjectNamespace
10
13
  ? DurableObjectNamespace
@@ -18,4 +21,10 @@ export type Bound<T extends Binding> = T extends _DurableObjectNamespace
18
21
  ? string
19
22
  : T extends Assets
20
23
  ? Service
21
- : Service;
24
+ : T extends _Workflow<infer P>
25
+ ? Workflow<P>
26
+ : T extends _D1Database
27
+ ? D1Database
28
+ : T extends _Queue
29
+ ? Queue
30
+ : Service;