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.
@@ -6,25 +6,23 @@
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
  export type Bindings = {
13
16
  [bindingName: string]: Binding;
14
17
  };
15
18
  /**
16
19
  * L2 Binding Resources.
17
20
  */
18
- export type Binding = DurableObjectNamespace | KVNamespace | Worker | R2Bucket | Secret | string | Assets;
19
- export declare function isDurableObjectNamespace(binding: Binding): binding is DurableObjectNamespace;
20
- /**
21
- * Check if a binding is an Assets resource
22
- */
23
- export declare function isAssets(binding: Binding): binding is Assets;
21
+ export type Binding = Assets | D1Database | DurableObjectNamespace | KVNamespace | Queue | R2Bucket | Secret | string | Worker | Workflow;
24
22
  /**
25
23
  * Union type for all Worker binding types (API spec)
26
24
  */
27
- export type WorkerBindingSpec = WorkerBindingAI | WorkerBindingAnalyticsEngine | WorkerBindingAssets | WorkerBindingBrowserRendering | WorkerBindingD1 | WorkerBindingDispatchNamespace | WorkerBindingDurableObjectNamespace | WorkerBindingHyperdrive | WorkerBindingJson | WorkerBindingKVNamespace | WorkerBindingMTLSCertificate | WorkerBindingPlainText | WorkerBindingQueue | WorkerBindingR2Bucket | WorkerBindingSecretText | WorkerBindingService | WorkerBindingStaticContent | WorkerBindingTailConsumer | WorkerBindingVectorize | WorkerBindingVersionMetadata | WorkerBindingWasmModule;
25
+ export type WorkerBindingSpec = WorkerBindingAI | WorkerBindingAnalyticsEngine | WorkerBindingAssets | WorkerBindingBrowserRendering | WorkerBindingD1 | WorkerBindingDispatchNamespace | WorkerBindingDurableObjectNamespace | WorkerBindingHyperdrive | WorkerBindingJson | WorkerBindingKVNamespace | WorkerBindingMTLSCertificate | WorkerBindingPlainText | WorkerBindingQueue | WorkerBindingR2Bucket | WorkerBindingSecretText | WorkerBindingService | WorkerBindingStaticContent | WorkerBindingTailConsumer | WorkerBindingVectorize | WorkerBindingVersionMetadata | WorkerBindingWasmModule | WorkerBindingWorkflow;
28
26
  /**
29
27
  * AI binding type
30
28
  */
@@ -264,3 +262,19 @@ export interface WorkerBindingStaticContent {
264
262
  /** Type identifier for Static Content binding */
265
263
  type: "static_content";
266
264
  }
265
+ export interface WorkerBindingWorkflow {
266
+ /** The name of the binding */
267
+ name: string;
268
+ /** Type identifier for Workflow binding */
269
+ type: "workflow";
270
+ /** Workflow name */
271
+ workflow_name: string;
272
+ /** Workflow class name */
273
+ class_name: string;
274
+ /**
275
+ * Workflow script name
276
+ *
277
+ * @default - the name of the script it is bound to
278
+ */
279
+ script_name?: string;
280
+ }
@@ -1,9 +0,0 @@
1
- export function isDurableObjectNamespace(binding) {
2
- return (typeof binding === "object" && binding.type === "durable_object_namespace");
3
- }
4
- /**
5
- * Check if a binding is an Assets resource
6
- */
7
- export function isAssets(binding) {
8
- return typeof binding === "object" && binding.type === "assets";
9
- }
@@ -2,7 +2,10 @@ 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";
8
- export type Bound<T extends Binding> = T extends _DurableObjectNamespace ? DurableObjectNamespace : T extends _KVNamespace ? KVNamespace : T extends _Worker ? Worker : T extends _R2Bucket ? R2Bucket : T extends Secret ? string : T extends Assets ? Service : Service;
10
+ import type { Workflow as _Workflow } from "./workflow";
11
+ export type Bound<T extends Binding> = T extends _DurableObjectNamespace ? DurableObjectNamespace : T extends _KVNamespace ? KVNamespace : T extends _Worker ? Worker : T extends _R2Bucket ? R2Bucket : T extends Secret ? string : T extends Assets ? Service : T extends _Workflow<infer P> ? Workflow<P> : T extends _D1Database ? D1Database : T extends _Queue ? Queue : Service;
@@ -0,0 +1,134 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ import { CloudflareApi, type CloudflareApiOptions } from "./api";
4
+ /**
5
+ * Properties for creating or updating a D1 Database
6
+ */
7
+ export interface D1DatabaseProps extends CloudflareApiOptions {
8
+ /**
9
+ * Name of the database
10
+ */
11
+ name: string;
12
+ /**
13
+ * Optional primary location hint for the database
14
+ * Indicates the primary geographical location data will be stored
15
+ */
16
+ primaryLocationHint?: "wnam" | "enam" | "weur" | "eeur" | "apac" | "auto" | string;
17
+ /**
18
+ * Read replication configuration
19
+ * Only mutable property during updates
20
+ */
21
+ readReplication?: {
22
+ /**
23
+ * Read replication mode
24
+ * - auto: Automatic read replication
25
+ * - disabled: No read replication
26
+ */
27
+ mode: "auto" | "disabled";
28
+ };
29
+ /**
30
+ * Whether to delete the database.
31
+ * If set to false, the database will remain but the resource will be removed from state
32
+ *
33
+ * @default true
34
+ */
35
+ delete?: boolean;
36
+ }
37
+ /**
38
+ * Output returned after D1 Database creation/update
39
+ */
40
+ export interface D1Database extends Resource<"cloudflare::D1Database">, D1DatabaseProps {
41
+ type: "d1";
42
+ /**
43
+ * The unique ID of the database (UUID)
44
+ */
45
+ id: string;
46
+ /**
47
+ * File size of the database
48
+ */
49
+ fileSize: number;
50
+ /**
51
+ * Number of tables in the database
52
+ */
53
+ numTables: number;
54
+ /**
55
+ * Version of the database
56
+ */
57
+ version: string;
58
+ /**
59
+ * Read replication configuration
60
+ */
61
+ readReplication?: {
62
+ /**
63
+ * Read replication mode
64
+ */
65
+ mode: "auto" | "disabled";
66
+ };
67
+ }
68
+ /**
69
+ * Creates and manages Cloudflare D1 Databases.
70
+ *
71
+ * D1 Databases provide serverless SQL databases built on SQLite with
72
+ * automatic data replication for high availability.
73
+ *
74
+ * @example
75
+ * // Create a basic D1 database with default settings
76
+ * const basicDatabase = await D1Database("my-app-db", {
77
+ * name: "my-app-db"
78
+ * });
79
+ *
80
+ * @example
81
+ * // Create a database with location hint for optimal performance
82
+ * const westUsDatabase = await D1Database("west-us-db", {
83
+ * name: "west-us-db",
84
+ * primaryLocationHint: "wnam"
85
+ * });
86
+ *
87
+ * @see https://developers.cloudflare.com/d1/
88
+ */
89
+ export declare const D1Database: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<D1Database>, id: string, props: D1DatabaseProps) => Promise<D1Database>);
90
+ interface CloudflareD1Response {
91
+ result: {
92
+ uuid?: string;
93
+ name: string;
94
+ file_size: number;
95
+ num_tables: number;
96
+ version: string;
97
+ primary_location_hint?: string;
98
+ read_replication?: {
99
+ mode: "auto" | "disabled";
100
+ };
101
+ };
102
+ success: boolean;
103
+ errors: Array<{
104
+ code: number;
105
+ message: string;
106
+ }>;
107
+ messages: string[];
108
+ }
109
+ /**
110
+ * Create a new D1 database
111
+ */
112
+ export declare function createDatabase(api: CloudflareApi, databaseName: string, props: D1DatabaseProps): Promise<CloudflareD1Response>;
113
+ /**
114
+ * Get a D1 database
115
+ */
116
+ export declare function getDatabase(api: CloudflareApi, databaseId?: string): Promise<CloudflareD1Response>;
117
+ /**
118
+ * Delete a D1 database
119
+ */
120
+ export declare function deleteDatabase(api: CloudflareApi, databaseId?: string): Promise<void>;
121
+ /**
122
+ * List all D1 databases in an account
123
+ */
124
+ export declare function listDatabases(api: CloudflareApi): Promise<{
125
+ name: string;
126
+ id: string;
127
+ }[]>;
128
+ /**
129
+ * Update a D1 database
130
+ *
131
+ * Note: According to Cloudflare API, only read_replication.mode can be modified during updates.
132
+ */
133
+ export declare function updateDatabase(api: CloudflareApi, databaseId: string, props: D1DatabaseProps): Promise<CloudflareD1Response>;
134
+ export {};
@@ -0,0 +1,161 @@
1
+ import { Resource } from "../resource";
2
+ import { CloudflareApi, createCloudflareApi, } from "./api";
3
+ import { CloudflareApiError, handleApiError } from "./api-error";
4
+ /**
5
+ * Creates and manages Cloudflare D1 Databases.
6
+ *
7
+ * D1 Databases provide serverless SQL databases built on SQLite with
8
+ * automatic data replication for high availability.
9
+ *
10
+ * @example
11
+ * // Create a basic D1 database with default settings
12
+ * const basicDatabase = await D1Database("my-app-db", {
13
+ * name: "my-app-db"
14
+ * });
15
+ *
16
+ * @example
17
+ * // Create a database with location hint for optimal performance
18
+ * const westUsDatabase = await D1Database("west-us-db", {
19
+ * name: "west-us-db",
20
+ * primaryLocationHint: "wnam"
21
+ * });
22
+ *
23
+ * @see https://developers.cloudflare.com/d1/
24
+ */
25
+ export const D1Database = Resource("cloudflare::D1Database", async function (id, props) {
26
+ const api = await createCloudflareApi(props);
27
+ const databaseName = props.name || id;
28
+ if (this.phase === "delete") {
29
+ console.log("Deleting D1 database:", databaseName);
30
+ if (props.delete !== false) {
31
+ // Delete D1 database
32
+ console.log("Deleting D1 database:", databaseName);
33
+ await deleteDatabase(api, this.output?.id);
34
+ }
35
+ // Return void (a deleted database has no content)
36
+ return this.destroy();
37
+ }
38
+ else {
39
+ let dbData;
40
+ if (this.phase === "create") {
41
+ console.log("Creating D1 database:", databaseName);
42
+ dbData = await createDatabase(api, databaseName, props);
43
+ }
44
+ else {
45
+ // Update operation
46
+ if (this.output?.id) {
47
+ console.log("Updating D1 database:", databaseName);
48
+ // Update the database with new properties
49
+ dbData = await updateDatabase(api, this.output.id, props);
50
+ }
51
+ else {
52
+ // If no ID exists, fall back to creating a new database
53
+ console.log("No existing database ID found, creating new D1 database:", databaseName);
54
+ dbData = await createDatabase(api, databaseName, props);
55
+ }
56
+ }
57
+ return this({
58
+ type: "d1",
59
+ id: dbData.result.uuid || "",
60
+ name: databaseName,
61
+ fileSize: dbData.result.file_size,
62
+ numTables: dbData.result.num_tables,
63
+ version: dbData.result.version,
64
+ readReplication: dbData.result.read_replication,
65
+ primaryLocationHint: props.primaryLocationHint,
66
+ accountId: api.accountId,
67
+ });
68
+ }
69
+ });
70
+ /**
71
+ * Create a new D1 database
72
+ */
73
+ export async function createDatabase(api, databaseName, props) {
74
+ // Create new D1 database
75
+ const createPayload = {
76
+ name: databaseName,
77
+ };
78
+ if (props.primaryLocationHint) {
79
+ createPayload.primary_location_hint = props.primaryLocationHint;
80
+ }
81
+ const createResponse = await api.post(`/accounts/${api.accountId}/d1/database`, createPayload);
82
+ if (!createResponse.ok) {
83
+ return await handleApiError(createResponse, "creating", "D1 database", databaseName);
84
+ }
85
+ return (await createResponse.json());
86
+ }
87
+ /**
88
+ * Get a D1 database
89
+ */
90
+ export async function getDatabase(api, databaseId) {
91
+ if (!databaseId) {
92
+ throw new Error("Database ID is required");
93
+ }
94
+ const response = await api.get(`/accounts/${api.accountId}/d1/database/${databaseId}`);
95
+ if (!response.ok) {
96
+ return await handleApiError(response, "getting", "D1 database", databaseId);
97
+ }
98
+ return (await response.json());
99
+ }
100
+ /**
101
+ * Delete a D1 database
102
+ */
103
+ export async function deleteDatabase(api, databaseId) {
104
+ if (!databaseId) {
105
+ console.log("No database ID provided, skipping delete");
106
+ return;
107
+ }
108
+ // Delete D1 database
109
+ const deleteResponse = await api.delete(`/accounts/${api.accountId}/d1/database/${databaseId}`);
110
+ if (!deleteResponse.ok && deleteResponse.status !== 404) {
111
+ const errorData = await deleteResponse.json().catch(() => ({
112
+ errors: [{ message: deleteResponse.statusText }],
113
+ }));
114
+ throw new CloudflareApiError(`Error deleting D1 database '${databaseId}': ${errorData.errors?.[0]?.message || deleteResponse.statusText}`, deleteResponse);
115
+ }
116
+ }
117
+ /**
118
+ * List all D1 databases in an account
119
+ */
120
+ export async function listDatabases(api) {
121
+ const response = await api.get(`/accounts/${api.accountId}/d1/database`);
122
+ if (!response.ok) {
123
+ throw new CloudflareApiError(`Failed to list databases: ${response.statusText}`, response);
124
+ }
125
+ const data = (await response.json());
126
+ if (!data.success) {
127
+ const errorMessage = data.errors?.[0]?.message || "Unknown error";
128
+ throw new Error(`Failed to list databases: ${errorMessage}`);
129
+ }
130
+ // Transform API response
131
+ return (data.result || []).map((db) => ({
132
+ name: db.name,
133
+ id: db.uuid,
134
+ }));
135
+ }
136
+ /**
137
+ * Update a D1 database
138
+ *
139
+ * Note: According to Cloudflare API, only read_replication.mode can be modified during updates.
140
+ */
141
+ export async function updateDatabase(api, databaseId, props) {
142
+ // Get current database state to check for non-mutable changes
143
+ const currentDB = await getDatabase(api, databaseId);
144
+ // Only read_replication can be modified in update
145
+ if (props.primaryLocationHint &&
146
+ props.primaryLocationHint !== currentDB.result.primary_location_hint) {
147
+ throw new Error("Cannot update primaryLocationHint after database creation. Only readReplication.mode can be modified.");
148
+ }
149
+ const updatePayload = {};
150
+ // Only include read_replication in update payload
151
+ if (props.readReplication) {
152
+ updatePayload.read_replication = {
153
+ mode: props.readReplication.mode,
154
+ };
155
+ }
156
+ const updateResponse = await api.patch(`/accounts/${api.accountId}/d1/database/${databaseId}`, updatePayload);
157
+ if (!updateResponse.ok) {
158
+ return await handleApiError(updateResponse, "updating", "D1 database", databaseId);
159
+ }
160
+ return (await updateResponse.json());
161
+ }
@@ -1,14 +1,18 @@
1
1
  export * from "./account-api-token";
2
2
  export * from "./api";
3
+ export * from "./api-error";
3
4
  export * from "./assets";
4
5
  export * from "./bindings";
5
6
  export * from "./bucket";
6
7
  export * from "./custom-domain";
8
+ export * from "./d1-database";
7
9
  export * from "./dns-records";
8
10
  export * from "./durable-object-namespace";
9
11
  export * from "./kv-namespace";
10
12
  export * from "./permission-groups";
13
+ export * from "./queue";
11
14
  export * from "./r2-rest-state-store";
12
15
  export * from "./worker";
16
+ export { Workflow } from "./workflow";
13
17
  export * from "./wrangler.json";
14
18
  export * from "./zone";
@@ -1,14 +1,18 @@
1
1
  export * from "./account-api-token";
2
2
  export * from "./api";
3
+ export * from "./api-error";
3
4
  export * from "./assets";
4
5
  export * from "./bindings";
5
6
  export * from "./bucket";
6
7
  export * from "./custom-domain";
8
+ export * from "./d1-database";
7
9
  export * from "./dns-records";
8
10
  export * from "./durable-object-namespace";
9
11
  export * from "./kv-namespace";
10
12
  export * from "./permission-groups";
13
+ export * from "./queue";
11
14
  export * from "./r2-rest-state-store";
12
15
  export * from "./worker";
16
+ export { Workflow } from "./workflow";
13
17
  export * from "./wrangler.json";
14
18
  export * from "./zone";
@@ -1,7 +1,6 @@
1
1
  import type { Context } from "../context";
2
2
  import { Resource } from "../resource";
3
3
  import { CloudflareApi, type CloudflareApiOptions } from "./api";
4
- export declare function isKVNamespace(resource: any): resource is KVNamespace;
5
4
  /**
6
5
  * Properties for creating or updating a KV Namespace
7
6
  */
@@ -2,9 +2,6 @@ import { Resource } from "../resource";
2
2
  import { withExponentialBackoff } from "../util/retry";
3
3
  import { CloudflareApi, createCloudflareApi, } from "./api";
4
4
  import { handleApiError } from "./api-error";
5
- export function isKVNamespace(resource) {
6
- return (resource && typeof resource === "object" && resource.type === "kv_namespace");
7
- }
8
5
  /**
9
6
  * A Cloudflare KV Namespace is a key-value store that can be used to store data for your application.
10
7
  *
@@ -0,0 +1,147 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ import { CloudflareApi, type CloudflareApiOptions } from "./api";
4
+ /**
5
+ * Settings for a Cloudflare Queue
6
+ */
7
+ export interface QueueSettings {
8
+ /**
9
+ * Delay in seconds before message delivery
10
+ * Queue will not deliver messages until this time has elapsed
11
+ */
12
+ deliveryDelay?: number;
13
+ /**
14
+ * Whether delivery is paused
15
+ * If true, the queue will not deliver messages to consumers
16
+ */
17
+ deliveryPaused?: boolean;
18
+ /**
19
+ * Period in seconds to retain messages
20
+ * Messages will be automatically deleted after this time
21
+ */
22
+ messageRetentionPeriod?: number;
23
+ }
24
+ /**
25
+ * Properties for creating or updating a Cloudflare Queue
26
+ */
27
+ export interface QueueProps extends CloudflareApiOptions {
28
+ /**
29
+ * Name of the queue
30
+ * Required during creation
31
+ * Cannot be changed after creation
32
+ */
33
+ name: string;
34
+ /**
35
+ * Settings for the queue
36
+ * These can be updated after queue creation
37
+ */
38
+ settings?: QueueSettings;
39
+ /**
40
+ * Whether to delete the queue.
41
+ * If set to false, the queue will remain but the resource will be removed from state
42
+ *
43
+ * @default true
44
+ */
45
+ delete?: boolean;
46
+ }
47
+ /**
48
+ * Output returned after Cloudflare Queue creation/update
49
+ */
50
+ export interface Queue extends Resource<"cloudflare::Queue">, QueueProps {
51
+ /**
52
+ * Type identifier for Cloudflare Queue
53
+ */
54
+ type: "queue";
55
+ /**
56
+ * The unique ID of the queue
57
+ */
58
+ id: string;
59
+ /**
60
+ * Time when the queue was created
61
+ */
62
+ createdOn: string;
63
+ /**
64
+ * Modified timestamp
65
+ */
66
+ modifiedOn: string;
67
+ }
68
+ interface CloudflareQueueResponse {
69
+ result: {
70
+ queue_id?: string;
71
+ queue_name: string;
72
+ created_on?: string;
73
+ modified_on?: string;
74
+ settings?: {
75
+ delivery_delay?: number;
76
+ delivery_paused?: boolean;
77
+ message_retention_period?: number;
78
+ };
79
+ };
80
+ success: boolean;
81
+ errors: Array<{
82
+ code: number;
83
+ message: string;
84
+ }>;
85
+ messages: string[];
86
+ }
87
+ /**
88
+ * Creates and manages Cloudflare Queues.
89
+ *
90
+ * Queues provide a managed queue system for reliable message delivery
91
+ * between workers and other systems.
92
+ *
93
+ * @example
94
+ * // Create a basic queue with default settings
95
+ * const basicQueue = await Queue("my-app-queue", {
96
+ * name: "my-app-queue"
97
+ * });
98
+ *
99
+ * @example
100
+ * // Create a queue with custom settings
101
+ * const customQueue = await Queue("delayed-queue", {
102
+ * name: "delayed-queue",
103
+ * settings: {
104
+ * deliveryDelay: 30, // 30 second delay before message delivery
105
+ * messageRetentionPeriod: 86400 // Store messages for 1 day
106
+ * }
107
+ * });
108
+ *
109
+ * @example
110
+ * // Create a paused queue for later activation
111
+ * const pausedQueue = await Queue("paused-queue", {
112
+ * name: "paused-queue",
113
+ * settings: {
114
+ * deliveryPaused: true
115
+ * }
116
+ * });
117
+ *
118
+ * @see https://developers.cloudflare.com/queues/
119
+ */
120
+ export declare const Queue: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Queue>, id: string, props: QueueProps) => Promise<Queue>);
121
+ /**
122
+ * Create a new Cloudflare Queue
123
+ */
124
+ export declare function createQueue(api: CloudflareApi, queueName: string, props: QueueProps): Promise<CloudflareQueueResponse>;
125
+ /**
126
+ * Get a Cloudflare Queue
127
+ */
128
+ export declare function getQueue(api: CloudflareApi, queueId: string): Promise<CloudflareQueueResponse>;
129
+ /**
130
+ * Delete a Cloudflare Queue
131
+ */
132
+ export declare function deleteQueue(api: CloudflareApi, queueId?: string): Promise<void>;
133
+ /**
134
+ * Update a Cloudflare Queue
135
+ *
136
+ * Note: According to Cloudflare API, the queue name cannot be changed after creation.
137
+ * Only the settings can be updated.
138
+ */
139
+ export declare function updateQueue(api: CloudflareApi, queueId: string, props: QueueProps): Promise<CloudflareQueueResponse>;
140
+ /**
141
+ * List all Cloudflare Queues in an account
142
+ */
143
+ export declare function listQueues(api: CloudflareApi): Promise<{
144
+ name: string;
145
+ id: string;
146
+ }[]>;
147
+ export {};