alchemy 0.1.12 → 0.1.14

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 (168) hide show
  1. package/README.md +12 -2
  2. package/lib/$.d.ts +12 -0
  3. package/lib/$.d.ts.map +1 -0
  4. package/lib/$.js +42 -0
  5. package/lib/$.js.map +1 -0
  6. package/lib/alchemize.d.ts.map +1 -1
  7. package/lib/alchemize.js +7 -0
  8. package/lib/alchemize.js.map +1 -1
  9. package/lib/apply.d.ts +2 -2
  10. package/lib/apply.d.ts.map +1 -1
  11. package/lib/apply.js +1 -1
  12. package/lib/apply.js.map +1 -1
  13. package/lib/aws/account-id.d.ts +5 -0
  14. package/lib/aws/account-id.d.ts.map +1 -0
  15. package/lib/aws/account-id.js +10 -0
  16. package/lib/aws/account-id.js.map +1 -0
  17. package/lib/aws/index.d.ts +1 -0
  18. package/lib/aws/index.d.ts.map +1 -1
  19. package/lib/aws/index.js +1 -0
  20. package/lib/aws/index.js.map +1 -1
  21. package/lib/aws/oidc/github-oidc-provider.d.ts +11 -0
  22. package/lib/aws/oidc/github-oidc-provider.d.ts.map +1 -0
  23. package/lib/aws/oidc/github-oidc-provider.js +22 -0
  24. package/lib/aws/oidc/github-oidc-provider.js.map +1 -0
  25. package/lib/aws/oidc/index.d.ts +3 -0
  26. package/lib/aws/oidc/index.d.ts.map +1 -0
  27. package/lib/aws/oidc/index.js +3 -0
  28. package/lib/aws/oidc/index.js.map +1 -0
  29. package/lib/aws/oidc/oidc-provider.d.ts +60 -0
  30. package/lib/aws/oidc/oidc-provider.d.ts.map +1 -0
  31. package/lib/aws/oidc/oidc-provider.js +140 -0
  32. package/lib/aws/oidc/oidc-provider.js.map +1 -0
  33. package/lib/aws/queue.d.ts +24 -0
  34. package/lib/aws/queue.d.ts.map +1 -1
  35. package/lib/aws/queue.js +6 -1
  36. package/lib/aws/queue.js.map +1 -1
  37. package/lib/aws/role.d.ts.map +1 -1
  38. package/lib/aws/role.js +49 -1
  39. package/lib/aws/role.js.map +1 -1
  40. package/lib/aws/ses.d.ts.map +1 -1
  41. package/lib/aws/ses.js +20 -28
  42. package/lib/aws/ses.js.map +1 -1
  43. package/lib/aws/table.d.ts.map +1 -1
  44. package/lib/aws/table.js +95 -73
  45. package/lib/aws/table.js.map +1 -1
  46. package/lib/cloudflare/api.d.ts +4 -0
  47. package/lib/cloudflare/api.d.ts.map +1 -1
  48. package/lib/cloudflare/api.js +6 -0
  49. package/lib/cloudflare/api.js.map +1 -1
  50. package/lib/cloudflare/bindings.d.ts +19 -4
  51. package/lib/cloudflare/bindings.d.ts.map +1 -1
  52. package/lib/cloudflare/bindings.js +0 -5
  53. package/lib/cloudflare/bindings.js.map +1 -1
  54. package/lib/cloudflare/durable-object-namespace.d.ts +20 -0
  55. package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -0
  56. package/lib/cloudflare/durable-object-namespace.js +21 -0
  57. package/lib/cloudflare/durable-object-namespace.js.map +1 -0
  58. package/lib/cloudflare/index.d.ts +1 -0
  59. package/lib/cloudflare/index.d.ts.map +1 -1
  60. package/lib/cloudflare/index.js +1 -0
  61. package/lib/cloudflare/index.js.map +1 -1
  62. package/lib/cloudflare/kv-namespace.d.ts +3 -0
  63. package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
  64. package/lib/cloudflare/kv-namespace.js +5 -1
  65. package/lib/cloudflare/kv-namespace.js.map +1 -1
  66. package/lib/cloudflare/static-site-router.d.ts +11 -2
  67. package/lib/cloudflare/static-site-router.d.ts.map +1 -1
  68. package/lib/cloudflare/static-site-router.js +98 -76
  69. package/lib/cloudflare/static-site-router.js.map +1 -1
  70. package/lib/cloudflare/static-site.d.ts +15 -15
  71. package/lib/cloudflare/static-site.d.ts.map +1 -1
  72. package/lib/cloudflare/static-site.js +45 -47
  73. package/lib/cloudflare/static-site.js.map +1 -1
  74. package/lib/cloudflare/worker-metadata.d.ts +130 -0
  75. package/lib/cloudflare/worker-metadata.d.ts.map +1 -0
  76. package/lib/cloudflare/worker-metadata.js +2 -0
  77. package/lib/cloudflare/worker-metadata.js.map +1 -0
  78. package/lib/cloudflare/worker-migration.d.ts +110 -0
  79. package/lib/cloudflare/worker-migration.d.ts.map +1 -0
  80. package/lib/cloudflare/worker-migration.js +11 -0
  81. package/lib/cloudflare/worker-migration.js.map +1 -0
  82. package/lib/cloudflare/worker.d.ts +34 -13
  83. package/lib/cloudflare/worker.d.ts.map +1 -1
  84. package/lib/cloudflare/worker.js +341 -321
  85. package/lib/cloudflare/worker.js.map +1 -1
  86. package/lib/destroy.d.ts +1 -1
  87. package/lib/destroy.d.ts.map +1 -1
  88. package/lib/destroy.js +2 -1
  89. package/lib/destroy.js.map +1 -1
  90. package/lib/esbuild.d.ts +1 -1
  91. package/lib/esbuild.d.ts.map +1 -1
  92. package/lib/esbuild.js +3 -1
  93. package/lib/esbuild.js.map +1 -1
  94. package/lib/github/client.d.ts +34 -0
  95. package/lib/github/client.d.ts.map +1 -0
  96. package/lib/github/client.js +91 -0
  97. package/lib/github/client.js.map +1 -0
  98. package/lib/github/index.d.ts +2 -0
  99. package/lib/github/index.d.ts.map +1 -0
  100. package/lib/github/index.js +2 -0
  101. package/lib/github/index.js.map +1 -0
  102. package/lib/github/secret.d.ts +46 -0
  103. package/lib/github/secret.d.ts.map +1 -0
  104. package/lib/github/secret.js +103 -0
  105. package/lib/github/secret.js.map +1 -0
  106. package/lib/global.d.ts +0 -2
  107. package/lib/global.d.ts.map +1 -1
  108. package/lib/global.js +0 -2
  109. package/lib/global.js.map +1 -1
  110. package/lib/index.d.ts +2 -0
  111. package/lib/index.d.ts.map +1 -1
  112. package/lib/index.js +2 -0
  113. package/lib/index.js.map +1 -1
  114. package/lib/output.d.ts +4 -3
  115. package/lib/output.d.ts.map +1 -1
  116. package/lib/output.js +10 -3
  117. package/lib/output.js.map +1 -1
  118. package/lib/print.d.ts +7 -0
  119. package/lib/print.d.ts.map +1 -0
  120. package/lib/print.js +10 -0
  121. package/lib/print.js.map +1 -0
  122. package/lib/resource.d.ts +8 -4
  123. package/lib/resource.d.ts.map +1 -1
  124. package/lib/resource.js +125 -91
  125. package/lib/resource.js.map +1 -1
  126. package/lib/scope.d.ts +3 -0
  127. package/lib/scope.d.ts.map +1 -1
  128. package/lib/scope.js +4 -12
  129. package/lib/scope.js.map +1 -1
  130. package/lib/utils/retry.d.ts +13 -0
  131. package/lib/utils/retry.d.ts.map +1 -0
  132. package/lib/utils/retry.js +31 -0
  133. package/lib/utils/retry.js.map +1 -0
  134. package/package.json +12 -3
  135. package/src/$.ts +69 -0
  136. package/src/alchemize.ts +12 -0
  137. package/src/apply.ts +4 -4
  138. package/src/aws/account-id.ts +11 -0
  139. package/src/aws/index.ts +1 -0
  140. package/src/aws/oidc/github-oidc-provider.ts +34 -0
  141. package/src/aws/oidc/index.ts +2 -0
  142. package/src/aws/oidc/oidc-provider.ts +253 -0
  143. package/src/aws/queue.ts +23 -1
  144. package/src/aws/role.ts +69 -0
  145. package/src/aws/ses.ts +27 -31
  146. package/src/aws/table.ts +113 -82
  147. package/src/cloudflare/api.ts +6 -0
  148. package/src/cloudflare/bindings.ts +43 -26
  149. package/src/cloudflare/durable-object-namespace.ts +37 -0
  150. package/src/cloudflare/index.ts +1 -0
  151. package/src/cloudflare/kv-namespace.ts +12 -1
  152. package/src/cloudflare/static-site-router.ts +124 -82
  153. package/src/cloudflare/static-site.ts +66 -69
  154. package/src/cloudflare/worker-metadata.ts +154 -0
  155. package/src/cloudflare/worker-migration.ts +145 -0
  156. package/src/cloudflare/worker.ts +557 -429
  157. package/src/destroy.ts +2 -2
  158. package/src/esbuild.ts +3 -0
  159. package/src/github/client.ts +115 -0
  160. package/src/github/index.ts +1 -0
  161. package/src/github/secret.ts +172 -0
  162. package/src/global.ts +0 -3
  163. package/src/index.ts +2 -1
  164. package/src/output.ts +24 -8
  165. package/src/print.ts +18 -0
  166. package/src/resource.ts +156 -115
  167. package/src/scope.ts +7 -12
  168. package/src/utils/retry.ts +36 -0
package/src/aws/ses.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import {
2
- AlreadyExistsException,
3
2
  CreateConfigurationSetCommand,
4
3
  CreateEmailIdentityCommand,
5
4
  DeleteConfigurationSetCommand,
@@ -8,6 +7,11 @@ import {
8
7
  GetConfigurationSetCommand,
9
8
  GetEmailIdentityCommand,
10
9
  NotFoundException,
10
+ PutConfigurationSetDeliveryOptionsCommand,
11
+ PutConfigurationSetReputationOptionsCommand,
12
+ PutConfigurationSetSendingOptionsCommand,
13
+ PutConfigurationSetSuppressionOptionsCommand,
14
+ PutConfigurationSetTrackingOptionsCommand,
11
15
  PutEmailIdentityDkimAttributesCommand,
12
16
  type ReputationOptions,
13
17
  SESv2Client,
@@ -103,7 +107,7 @@ export interface SESOutput extends SESProps {
103
107
  */
104
108
  export class SES extends Resource(
105
109
  "aws::SES",
106
- async (ctx: Context<SESOutput>, props: SESProps): Promise<SESOutput> => {
110
+ async (ctx: Context<SESOutput>, props: SESProps) => {
107
111
  // Create SES client
108
112
  const client = new SESv2Client({});
109
113
 
@@ -138,10 +142,7 @@ export class SES extends Resource(
138
142
  }
139
143
 
140
144
  // Return empty output for delete
141
- return {
142
- ...props,
143
- id,
144
- };
145
+ return;
145
146
  }
146
147
 
147
148
  // Created resources
@@ -154,66 +155,68 @@ export class SES extends Resource(
154
155
  if (props.configurationSetName) {
155
156
  try {
156
157
  // Check if configuration set exists
157
- let getConfigResult;
158
+ let configSetExists = false;
158
159
  try {
159
- getConfigResult = await client.send(
160
+ await client.send(
160
161
  new GetConfigurationSetCommand({
161
162
  ConfigurationSetName: props.configurationSetName,
162
163
  }),
163
164
  );
165
+ configSetExists = true;
164
166
  } catch (error) {
165
167
  if (error instanceof NotFoundException) {
166
- getConfigResult = null;
168
+ configSetExists = false;
167
169
  } else {
168
170
  throw error;
169
171
  }
170
172
  }
171
173
 
172
- if (getConfigResult) {
173
- // For updating configuration set, we need to use individual commands
174
- // since there's no unified UpdateConfigurationSetCommand
175
-
174
+ if (configSetExists) {
175
+ // Update existing configuration set using appropriate update commands
176
176
  if (props.sendingOptions) {
177
177
  await client.send(
178
- new CreateConfigurationSetCommand({
178
+ new PutConfigurationSetSendingOptionsCommand({
179
179
  ConfigurationSetName: props.configurationSetName,
180
- SendingOptions: props.sendingOptions,
180
+ SendingEnabled: props.sendingOptions.SendingEnabled,
181
181
  }),
182
182
  );
183
183
  }
184
184
 
185
185
  if (props.reputationOptions) {
186
186
  await client.send(
187
- new CreateConfigurationSetCommand({
187
+ new PutConfigurationSetReputationOptionsCommand({
188
188
  ConfigurationSetName: props.configurationSetName,
189
- ReputationOptions: props.reputationOptions,
189
+ ReputationMetricsEnabled:
190
+ props.reputationOptions.ReputationMetricsEnabled,
190
191
  }),
191
192
  );
192
193
  }
193
194
 
194
195
  if (props.trackingOptions) {
195
196
  await client.send(
196
- new CreateConfigurationSetCommand({
197
+ new PutConfigurationSetTrackingOptionsCommand({
197
198
  ConfigurationSetName: props.configurationSetName,
198
- TrackingOptions: props.trackingOptions,
199
+ CustomRedirectDomain:
200
+ props.trackingOptions.CustomRedirectDomain,
199
201
  }),
200
202
  );
201
203
  }
202
204
 
203
205
  if (props.suppressionOptions) {
204
206
  await client.send(
205
- new CreateConfigurationSetCommand({
207
+ new PutConfigurationSetSuppressionOptionsCommand({
206
208
  ConfigurationSetName: props.configurationSetName,
207
- SuppressionOptions: props.suppressionOptions,
209
+ SuppressedReasons: props.suppressionOptions.SuppressedReasons,
208
210
  }),
209
211
  );
210
212
  }
211
213
 
212
214
  if (props.deliveryOptions) {
213
215
  await client.send(
214
- new CreateConfigurationSetCommand({
216
+ new PutConfigurationSetDeliveryOptionsCommand({
215
217
  ConfigurationSetName: props.configurationSetName,
216
- DeliveryOptions: props.deliveryOptions,
218
+ TlsPolicy: props.deliveryOptions.TlsPolicy,
219
+ SendingPoolName: props.deliveryOptions.SendingPoolName,
217
220
  }),
218
221
  );
219
222
  }
@@ -241,14 +244,7 @@ export class SES extends Resource(
241
244
  configurationSetArn = `arn:aws:ses:${process.env.AWS_REGION}:${process.env.AWS_ACCOUNT_ID}:configuration-set/${props.configurationSetName}`;
242
245
  }
243
246
  } catch (error: any) {
244
- if (error instanceof AlreadyExistsException) {
245
- // If it already exists but we couldn't get it (permissions issue), continue
246
- console.warn(
247
- `Configuration set ${props.configurationSetName} already exists but cannot be retrieved`,
248
- );
249
- } else {
250
- throw error;
251
- }
247
+ throw error;
252
248
  }
253
249
  }
254
250
 
package/src/aws/table.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  } from "@aws-sdk/client-dynamodb";
10
10
  import { ignore } from "../error";
11
11
  import { type Context, Resource } from "../resource";
12
+ import { withExponentialBackoff } from "../utils/retry";
12
13
 
13
14
  export interface TableProps {
14
15
  tableName: string;
@@ -38,7 +39,7 @@ export class Table extends Resource(
38
39
  async (
39
40
  ctx: Context<TableOutput>,
40
41
  props: TableProps,
41
- ): Promise<TableOutput> => {
42
+ ): Promise<TableOutput | void> => {
42
43
  const client = new DynamoDBClient({});
43
44
 
44
45
  if (ctx.event === "delete") {
@@ -70,103 +71,133 @@ export class Table extends Resource(
70
71
  }
71
72
  }
72
73
 
73
- return {
74
- ...props,
75
- id: props.tableName,
76
- arn: `arn:aws:dynamodb:${client.config.region}:${process.env.AWS_ACCOUNT_ID}:table/${props.tableName}`,
77
- tableId: "",
78
- };
74
+ return;
79
75
  } else {
80
- try {
81
- const attributeDefinitions = [
82
- {
83
- AttributeName: props.partitionKey.name,
84
- AttributeType: props.partitionKey.type,
85
- },
86
- ];
87
-
88
- const keySchema: KeySchemaElement[] = [
89
- {
90
- AttributeName: props.partitionKey.name,
91
- KeyType: "HASH",
92
- },
93
- ];
94
-
95
- if (props.sortKey) {
96
- attributeDefinitions.push({
97
- AttributeName: props.sortKey.name,
98
- AttributeType: props.sortKey.type,
99
- });
100
- keySchema.push({
101
- AttributeName: props.sortKey.name,
102
- KeyType: "RANGE",
103
- });
104
- }
76
+ // Setup for table creation
77
+ const attributeDefinitions = [
78
+ {
79
+ AttributeName: props.partitionKey.name,
80
+ AttributeType: props.partitionKey.type,
81
+ },
82
+ ];
105
83
 
106
- await client.send(
107
- new CreateTableCommand({
108
- TableName: props.tableName,
109
- AttributeDefinitions: attributeDefinitions,
110
- KeySchema: keySchema,
111
- BillingMode: props.billingMode || "PAY_PER_REQUEST",
112
- ProvisionedThroughput:
113
- props.billingMode === "PROVISIONED"
114
- ? {
115
- ReadCapacityUnits: props.readCapacity || 5,
116
- WriteCapacityUnits: props.writeCapacity || 5,
117
- }
118
- : undefined,
119
- Tags: props.tags
120
- ? Object.entries(props.tags).map(([Key, Value]) => ({
121
- Key,
122
- Value,
123
- }))
124
- : undefined,
125
- }),
126
- );
84
+ const keySchema: KeySchemaElement[] = [
85
+ {
86
+ AttributeName: props.partitionKey.name,
87
+ KeyType: "HASH",
88
+ },
89
+ ];
90
+
91
+ if (props.sortKey) {
92
+ attributeDefinitions.push({
93
+ AttributeName: props.sortKey.name,
94
+ AttributeType: props.sortKey.type,
95
+ });
96
+ keySchema.push({
97
+ AttributeName: props.sortKey.name,
98
+ KeyType: "RANGE",
99
+ });
100
+ }
101
+
102
+ // Attempt to create the table with exponential backoff for ResourceInUseException
103
+ await withExponentialBackoff(
104
+ async () => {
105
+ try {
106
+ // First check if table already exists
107
+ const describeResponse = await client.send(
108
+ new DescribeTableCommand({
109
+ TableName: props.tableName,
110
+ }),
111
+ );
112
+
113
+ // If table exists and is ACTIVE, no need to create it
114
+ if (describeResponse.Table?.TableStatus === "ACTIVE") {
115
+ return;
116
+ }
127
117
 
128
- // Wait for table to be active
129
- let tableActive = false;
130
- let tableDescription;
131
- while (!tableActive) {
118
+ // If table exists but not ACTIVE, wait for it in the polling loop below
119
+ if (describeResponse.Table) {
120
+ return;
121
+ }
122
+ } catch (error) {
123
+ if (error instanceof ResourceNotFoundException) {
124
+ // Table doesn't exist, try to create it
125
+ await client.send(
126
+ new CreateTableCommand({
127
+ TableName: props.tableName,
128
+ AttributeDefinitions: attributeDefinitions,
129
+ KeySchema: keySchema,
130
+ BillingMode: props.billingMode || "PAY_PER_REQUEST",
131
+ ProvisionedThroughput:
132
+ props.billingMode === "PROVISIONED"
133
+ ? {
134
+ ReadCapacityUnits: props.readCapacity || 5,
135
+ WriteCapacityUnits: props.writeCapacity || 5,
136
+ }
137
+ : undefined,
138
+ Tags: props.tags
139
+ ? Object.entries(props.tags).map(([Key, Value]) => ({
140
+ Key,
141
+ Value,
142
+ }))
143
+ : undefined,
144
+ }),
145
+ );
146
+ } else {
147
+ throw error;
148
+ }
149
+ }
150
+ },
151
+ (error) => error instanceof ResourceInUseException,
152
+ 10, // Max attempts
153
+ 200, // Initial delay in ms
154
+ );
155
+
156
+ // Wait for table to be active with timeout
157
+ let tableActive = false;
158
+ let tableDescription;
159
+ let retryCount = 0;
160
+ const maxRetries = 60; // Wait up to 60 seconds
161
+
162
+ while (!tableActive && retryCount < maxRetries) {
163
+ try {
132
164
  const response = await client.send(
133
165
  new DescribeTableCommand({
134
166
  TableName: props.tableName,
135
167
  }),
136
168
  );
169
+
137
170
  tableActive = response.Table?.TableStatus === "ACTIVE";
138
171
  if (tableActive) {
139
172
  tableDescription = response.Table;
140
173
  } else {
141
- await new Promise((resolve) => setTimeout(resolve, 1000));
174
+ retryCount++;
175
+ // Increasing delay for each retry with some jitter
176
+ const delay = Math.min(1000 * (1 + 0.1 * Math.random()), 5000);
177
+ await new Promise((resolve) => setTimeout(resolve, delay));
142
178
  }
179
+ } catch (error) {
180
+ retryCount++;
181
+ if (!(error instanceof ResourceNotFoundException)) {
182
+ throw error;
183
+ }
184
+ await new Promise((resolve) => setTimeout(resolve, 1000));
143
185
  }
186
+ }
144
187
 
145
- return {
146
- ...props,
147
- id: props.tableName,
148
- arn: tableDescription!.TableArn!,
149
- streamArn: tableDescription!.LatestStreamArn,
150
- tableId: tableDescription!.TableId!,
151
- };
152
- } catch (error) {
153
- if (error instanceof ResourceInUseException) {
154
- // Table already exists, get its details
155
- const response = await client.send(
156
- new DescribeTableCommand({
157
- TableName: props.tableName,
158
- }),
159
- );
160
- return {
161
- ...props,
162
- id: props.tableName,
163
- arn: response.Table!.TableArn!,
164
- streamArn: response.Table!.LatestStreamArn,
165
- tableId: response.Table!.TableId!,
166
- };
167
- }
168
- throw error;
188
+ if (!tableActive) {
189
+ throw new Error(
190
+ `Timed out waiting for table ${props.tableName} to become active`,
191
+ );
169
192
  }
193
+
194
+ return {
195
+ ...props,
196
+ id: props.tableName,
197
+ arn: tableDescription!.TableArn!,
198
+ streamArn: tableDescription!.LatestStreamArn,
199
+ tableId: tableDescription!.TableId!,
200
+ };
170
201
  }
171
202
  },
172
203
  ) {}
@@ -183,6 +183,12 @@ export class CloudflareApi {
183
183
  return this.fetch(path, { ...init, method: "GET" });
184
184
  }
185
185
 
186
+ /**
187
+ * Helper for HEAD requests
188
+ */
189
+ async head(path: string, init: RequestInit = {}): Promise<Response> {
190
+ return this.fetch(path, { ...init, method: "HEAD" });
191
+ }
186
192
  /**
187
193
  * Helper for POST requests
188
194
  */
@@ -3,6 +3,44 @@
3
3
  * Based on Cloudflare API documentation:
4
4
  * https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/update/
5
5
  */
6
+ import type { DurableObjectNamespace } from "./durable-object-namespace";
7
+ import type { KVNamespace } from "./kv-namespace";
8
+ import type { Worker } from "./worker";
9
+
10
+ export type Bindings = {
11
+ [bindingName: string]: Binding;
12
+ };
13
+
14
+ /**
15
+ * L2 Binding Resources.
16
+ */
17
+ export type Binding = DurableObjectNamespace | KVNamespace | Worker | string;
18
+
19
+ /**
20
+ * Union type for all Worker binding types (API spec)
21
+ */
22
+ export type WorkerBindingSpec =
23
+ | WorkerBindingAI
24
+ | WorkerBindingAnalyticsEngine
25
+ | WorkerBindingAssets
26
+ | WorkerBindingBrowserRendering
27
+ | WorkerBindingD1
28
+ | WorkerBindingDispatchNamespace
29
+ | WorkerBindingDurableObjectNamespace
30
+ | WorkerBindingHyperdrive
31
+ | WorkerBindingJson
32
+ | WorkerBindingKVNamespace
33
+ | WorkerBindingMTLSCertificate
34
+ | WorkerBindingPlainText
35
+ | WorkerBindingQueue
36
+ | WorkerBindingR2Bucket
37
+ | WorkerBindingSecretText
38
+ | WorkerBindingService
39
+ | WorkerBindingStaticContent
40
+ | WorkerBindingTailConsumer
41
+ | WorkerBindingVectorize
42
+ | WorkerBindingVersionMetadata
43
+ | WorkerBindingWasmModule;
6
44
 
7
45
  /**
8
46
  * AI binding type
@@ -76,6 +114,11 @@ export interface WorkerBindingDispatchNamespace {
76
114
  * Durable Object Namespace binding type
77
115
  */
78
116
  export interface WorkerBindingDurableObjectNamespace {
117
+ /**
118
+ * The stable ID of the binding
119
+ * @internal
120
+ */
121
+ stableId?: string;
79
122
  /** The name of the binding */
80
123
  name: string;
81
124
  /** Type identifier for Durable Object Namespace binding */
@@ -258,29 +301,3 @@ export interface WorkerBindingStaticContent {
258
301
  /** Type identifier for Static Content binding */
259
302
  type: "static_content";
260
303
  }
261
-
262
- /**
263
- * Union type for all Worker binding types
264
- */
265
- export type WorkerBinding =
266
- | WorkerBindingAI
267
- | WorkerBindingAnalyticsEngine
268
- | WorkerBindingAssets
269
- | WorkerBindingBrowserRendering
270
- | WorkerBindingD1
271
- | WorkerBindingDispatchNamespace
272
- | WorkerBindingDurableObjectNamespace
273
- | WorkerBindingHyperdrive
274
- | WorkerBindingJson
275
- | WorkerBindingKVNamespace
276
- | WorkerBindingMTLSCertificate
277
- | WorkerBindingPlainText
278
- | WorkerBindingQueue
279
- | WorkerBindingR2Bucket
280
- | WorkerBindingSecretText
281
- | WorkerBindingService
282
- | WorkerBindingStaticContent
283
- | WorkerBindingTailConsumer
284
- | WorkerBindingVectorize
285
- | WorkerBindingVersionMetadata
286
- | WorkerBindingWasmModule;
@@ -0,0 +1,37 @@
1
+ import type { Resolved } from "../output";
2
+
3
+ export interface DurableObjectNamespaceInput {
4
+ className: string;
5
+ scriptName?: string | undefined;
6
+ environment?: string | undefined;
7
+ sqlite?: boolean | undefined;
8
+ namespaceId?: string | undefined;
9
+ }
10
+
11
+ export function isDurableObjectNamespace(
12
+ binding: any,
13
+ ): binding is Resolved<DurableObjectNamespace> {
14
+ return (
15
+ typeof binding === "object" && binding.type === "durable_object_namespace"
16
+ );
17
+ }
18
+
19
+ export class DurableObjectNamespace implements DurableObjectNamespaceInput {
20
+ public readonly type = "durable_object_namespace" as const;
21
+ // alias for bindingName to be consistent with other bindings
22
+ public readonly className: string;
23
+ public readonly scriptName?: string | undefined;
24
+ public readonly environment?: string | undefined;
25
+ public readonly sqlite?: boolean | undefined;
26
+ public readonly namespaceId?: string | undefined;
27
+
28
+ constructor(
29
+ public readonly id: string,
30
+ input: DurableObjectNamespaceInput,
31
+ ) {
32
+ this.className = input.className;
33
+ this.scriptName = input.scriptName;
34
+ this.environment = input.environment;
35
+ this.sqlite = input.sqlite;
36
+ }
37
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./bindings";
2
+ export * from "./durable-object-namespace";
2
3
  export * from "./kv-namespace";
3
4
  export * from "./state";
4
5
  export * from "./static-site";
@@ -1,3 +1,4 @@
1
+ import type { Resolved } from "../output";
1
2
  import { type Context, Resource } from "../resource";
2
3
  import { createCloudflareApi } from "./api";
3
4
 
@@ -51,6 +52,7 @@ export interface KVPair {
51
52
  * Output returned after KV Namespace creation/update
52
53
  */
53
54
  export interface KVNamespaceOutput extends KVNamespaceProps {
55
+ type: "kv_namespace";
54
56
  /**
55
57
  * The ID of the namespace
56
58
  */
@@ -67,6 +69,14 @@ export interface KVNamespaceOutput extends KVNamespaceProps {
67
69
  modifiedAt: number;
68
70
  }
69
71
 
72
+ export function isKVNamespace(
73
+ resource: any,
74
+ ): resource is Resolved<KVNamespace> {
75
+ return (
76
+ resource && typeof resource === "object" && resource.type === "kv_namespace"
77
+ );
78
+ }
79
+
70
80
  export class KVNamespace extends Resource(
71
81
  "cloudflare::KVNamespace",
72
82
  async (ctx: Context<KVNamespaceOutput>, props: KVNamespaceProps) => {
@@ -121,7 +131,7 @@ export class KVNamespace extends Resource(
121
131
  errors: [{ message: createResponse.statusText }],
122
132
  }));
123
133
  throw new Error(
124
- `Error creating KV namespace: ${errorData.errors?.[0]?.message || createResponse.statusText}`,
134
+ `Error creating KV namespace '${props.title}': ${errorData.errors?.[0]?.message || createResponse.statusText}`,
125
135
  );
126
136
  }
127
137
 
@@ -182,6 +192,7 @@ export class KVNamespace extends Resource(
182
192
 
183
193
  // Construct the output
184
194
  const output: KVNamespaceOutput = {
195
+ type: "kv_namespace",
185
196
  id: namespaceId,
186
197
  title: props.title,
187
198
  values: props.values,