alchemy 0.57.2 → 0.59.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 (136) hide show
  1. package/bin/alchemy.js +1 -1
  2. package/lib/apply.js +3 -3
  3. package/lib/apply.js.map +1 -1
  4. package/lib/cloudflare/api-error.js +1 -1
  5. package/lib/cloudflare/api-error.js.map +1 -1
  6. package/lib/cloudflare/api-response.d.ts +19 -0
  7. package/lib/cloudflare/api-response.d.ts.map +1 -1
  8. package/lib/cloudflare/api-response.js.map +1 -1
  9. package/lib/cloudflare/api.d.ts.map +1 -1
  10. package/lib/cloudflare/api.js +10 -2
  11. package/lib/cloudflare/api.js.map +1 -1
  12. package/lib/cloudflare/assets.d.ts +1 -1
  13. package/lib/cloudflare/assets.d.ts.map +1 -1
  14. package/lib/cloudflare/bucket.d.ts +21 -3
  15. package/lib/cloudflare/bucket.d.ts.map +1 -1
  16. package/lib/cloudflare/bucket.js +83 -53
  17. package/lib/cloudflare/bucket.js.map +1 -1
  18. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  19. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  20. package/lib/cloudflare/container.d.ts +8 -0
  21. package/lib/cloudflare/container.d.ts.map +1 -1
  22. package/lib/cloudflare/container.js +7 -1
  23. package/lib/cloudflare/container.js.map +1 -1
  24. package/lib/cloudflare/custom-domain.d.ts +8 -0
  25. package/lib/cloudflare/custom-domain.d.ts.map +1 -1
  26. package/lib/cloudflare/custom-domain.js +11 -0
  27. package/lib/cloudflare/custom-domain.js.map +1 -1
  28. package/lib/cloudflare/d1-database.d.ts +15 -1
  29. package/lib/cloudflare/d1-database.d.ts.map +1 -1
  30. package/lib/cloudflare/d1-database.js +24 -17
  31. package/lib/cloudflare/d1-database.js.map +1 -1
  32. package/lib/cloudflare/d1-import.d.ts.map +1 -1
  33. package/lib/cloudflare/d1-import.js.map +1 -1
  34. package/lib/cloudflare/hyperdrive.d.ts +37 -9
  35. package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
  36. package/lib/cloudflare/hyperdrive.js +91 -5
  37. package/lib/cloudflare/hyperdrive.js.map +1 -1
  38. package/lib/cloudflare/index.d.ts +1 -0
  39. package/lib/cloudflare/index.d.ts.map +1 -1
  40. package/lib/cloudflare/index.js +1 -0
  41. package/lib/cloudflare/index.js.map +1 -1
  42. package/lib/cloudflare/kv-namespace.d.ts +23 -4
  43. package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
  44. package/lib/cloudflare/kv-namespace.js +70 -58
  45. package/lib/cloudflare/kv-namespace.js.map +1 -1
  46. package/lib/cloudflare/miniflare/build-worker-options.d.ts +2 -0
  47. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
  48. package/lib/cloudflare/miniflare/build-worker-options.js +9 -7
  49. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
  50. package/lib/cloudflare/miniflare/delete.d.ts +21 -0
  51. package/lib/cloudflare/miniflare/delete.d.ts.map +1 -0
  52. package/lib/cloudflare/miniflare/delete.js +91 -0
  53. package/lib/cloudflare/miniflare/delete.js.map +1 -0
  54. package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -1
  55. package/lib/cloudflare/miniflare/miniflare-controller.js +26 -9
  56. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -1
  57. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts +2 -0
  58. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  59. package/lib/cloudflare/miniflare/remote-binding-proxy.js +3 -4
  60. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  61. package/lib/cloudflare/pipeline.d.ts +3 -0
  62. package/lib/cloudflare/pipeline.d.ts.map +1 -1
  63. package/lib/cloudflare/pipeline.js +14 -1
  64. package/lib/cloudflare/pipeline.js.map +1 -1
  65. package/lib/cloudflare/queue-consumer.d.ts +8 -0
  66. package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
  67. package/lib/cloudflare/queue-consumer.js +15 -4
  68. package/lib/cloudflare/queue-consumer.js.map +1 -1
  69. package/lib/cloudflare/queue.d.ts +22 -4
  70. package/lib/cloudflare/queue.d.ts.map +1 -1
  71. package/lib/cloudflare/queue.js +32 -9
  72. package/lib/cloudflare/queue.js.map +1 -1
  73. package/lib/cloudflare/route.d.ts +8 -0
  74. package/lib/cloudflare/route.d.ts.map +1 -1
  75. package/lib/cloudflare/route.js +13 -0
  76. package/lib/cloudflare/route.js.map +1 -1
  77. package/lib/cloudflare/tunnel.d.ts +448 -0
  78. package/lib/cloudflare/tunnel.d.ts.map +1 -0
  79. package/lib/cloudflare/tunnel.js +467 -0
  80. package/lib/cloudflare/tunnel.js.map +1 -0
  81. package/lib/cloudflare/worker-subdomain.d.ts +8 -0
  82. package/lib/cloudflare/worker-subdomain.d.ts.map +1 -1
  83. package/lib/cloudflare/worker-subdomain.js +9 -1
  84. package/lib/cloudflare/worker-subdomain.js.map +1 -1
  85. package/lib/cloudflare/worker.d.ts +7 -1
  86. package/lib/cloudflare/worker.d.ts.map +1 -1
  87. package/lib/cloudflare/worker.js +405 -375
  88. package/lib/cloudflare/worker.js.map +1 -1
  89. package/lib/cloudflare/wrangler.json.d.ts +1 -1
  90. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  91. package/lib/cloudflare/wrangler.json.js +24 -12
  92. package/lib/cloudflare/wrangler.json.js.map +1 -1
  93. package/lib/destroy.d.ts.map +1 -1
  94. package/lib/destroy.js +4 -8
  95. package/lib/destroy.js.map +1 -1
  96. package/lib/esbuild/bundle.d.ts +1 -1
  97. package/lib/secret.d.ts +18 -1
  98. package/lib/secret.d.ts.map +1 -1
  99. package/lib/secret.js +25 -0
  100. package/lib/secret.js.map +1 -1
  101. package/package.json +1 -1
  102. package/src/apply.ts +5 -6
  103. package/src/cloudflare/api-error.ts +2 -2
  104. package/src/cloudflare/api-response.ts +22 -0
  105. package/src/cloudflare/api.ts +13 -2
  106. package/src/cloudflare/bucket.ts +126 -68
  107. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  108. package/src/cloudflare/container.ts +18 -1
  109. package/src/cloudflare/custom-domain.ts +22 -0
  110. package/src/cloudflare/d1-database.ts +44 -19
  111. package/src/cloudflare/d1-import.ts +1 -14
  112. package/src/cloudflare/hyperdrive.ts +170 -14
  113. package/src/cloudflare/index.ts +1 -0
  114. package/src/cloudflare/kv-namespace.ts +117 -73
  115. package/src/cloudflare/miniflare/build-worker-options.ts +12 -8
  116. package/src/cloudflare/miniflare/delete.ts +136 -0
  117. package/src/cloudflare/miniflare/miniflare-controller.ts +26 -9
  118. package/src/cloudflare/miniflare/remote-binding-proxy.ts +5 -4
  119. package/src/cloudflare/pipeline.ts +17 -1
  120. package/src/cloudflare/queue-consumer.ts +27 -5
  121. package/src/cloudflare/queue.ts +62 -12
  122. package/src/cloudflare/route.ts +24 -0
  123. package/src/cloudflare/tunnel.ts +911 -0
  124. package/src/cloudflare/worker-subdomain.ts +29 -6
  125. package/src/cloudflare/worker.ts +484 -465
  126. package/src/cloudflare/wrangler.json.ts +34 -13
  127. package/src/destroy.ts +4 -8
  128. package/src/secret.ts +30 -1
  129. package/templates/astro/README.md +2 -0
  130. package/templates/nuxt/README.md +2 -0
  131. package/templates/react-router/README.md +2 -0
  132. package/templates/rwsdk/README.md +2 -0
  133. package/templates/sveltekit/README.md +2 -0
  134. package/templates/tanstack-start/README.md +2 -0
  135. package/templates/typescript/README.md +2 -0
  136. package/templates/vite/README.md +2 -0
@@ -1,6 +1,7 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
2
  import type { Context } from "../context.ts";
3
3
  import { Resource, ResourceKind } from "../resource.ts";
4
+ import { Scope } from "../scope.ts";
4
5
  import { withExponentialBackoff } from "../util/retry.ts";
5
6
  import { CloudflareApiError } from "./api-error.ts";
6
7
  import {
@@ -12,6 +13,7 @@ import {
12
13
  type CloudflareApi,
13
14
  type CloudflareApiOptions,
14
15
  } from "./api.ts";
16
+ import { deleteMiniflareBinding } from "./miniflare/delete.ts";
15
17
 
16
18
  /**
17
19
  * Properties for creating or updating an R2 Bucket
@@ -83,6 +85,12 @@ export interface BucketProps extends CloudflareApiOptions {
83
85
  * @default false
84
86
  */
85
87
  remote?: boolean;
88
+
89
+ /**
90
+ * Set when `Scope.local` is true to force update to the bucket even if it was already deployed live.
91
+ * @internal
92
+ */
93
+ force?: boolean;
86
94
  };
87
95
  }
88
96
 
@@ -127,7 +135,7 @@ interface R2BucketCORSRule {
127
135
  * Output returned after R2 Bucket creation/update
128
136
  */
129
137
  export type R2Bucket = Resource<"cloudflare::R2Bucket"> &
130
- Omit<BucketProps, "delete"> & {
138
+ Omit<BucketProps, "delete" | "dev"> & {
131
139
  /**
132
140
  * Resource type identifier
133
141
  */
@@ -152,6 +160,22 @@ export type R2Bucket = Resource<"cloudflare::R2Bucket"> &
152
160
  * The `r2.dev` subdomain for the bucket, if `allowPublicAccess` is true
153
161
  */
154
162
  domain: string | undefined;
163
+
164
+ /**
165
+ * Development mode properties
166
+ * @internal
167
+ */
168
+ dev: {
169
+ /**
170
+ * The ID of the bucket in development mode
171
+ */
172
+ id: string;
173
+
174
+ /**
175
+ * Whether the bucket is running remotely
176
+ */
177
+ remote: boolean;
178
+ };
155
179
  };
156
180
 
157
181
  export function isBucket(resource: Resource): resource is R2Bucket {
@@ -202,88 +226,122 @@ export function isBucket(resource: Resource): resource is R2Bucket {
202
226
  *
203
227
  * @see https://developers.cloudflare.com/r2/buckets/
204
228
  */
205
- export const R2Bucket = Resource(
229
+ export async function R2Bucket(
230
+ id: string,
231
+ props: BucketProps = {},
232
+ ): Promise<R2Bucket> {
233
+ return await _R2Bucket(id, {
234
+ ...props,
235
+ dev: {
236
+ ...(props.dev ?? {}),
237
+ force: Scope.current.local,
238
+ },
239
+ });
240
+ }
241
+
242
+ const _R2Bucket = Resource(
206
243
  "cloudflare::R2Bucket",
207
244
  async function (
208
245
  this: Context<R2Bucket>,
209
- _id: string,
246
+ id: string,
210
247
  props: BucketProps = {},
211
248
  ): Promise<R2Bucket> {
212
- const api = await createCloudflareApi(props);
213
- const bucketName = props.name || this.id;
249
+ const bucketName = props.name || id;
214
250
  const allowPublicAccess = props.allowPublicAccess === true;
251
+ const dev = {
252
+ id: this.output?.dev?.id ?? bucketName,
253
+ remote: props.dev?.remote ?? false,
254
+ };
255
+
256
+ if (this.scope.local && !props.dev?.remote) {
257
+ return this({
258
+ name: this.output?.name ?? "",
259
+ location: this.output?.location ?? "",
260
+ creationDate: this.output?.creationDate ?? new Date(),
261
+ jurisdiction: this.output?.jurisdiction ?? "default",
262
+ allowPublicAccess,
263
+ domain: this.output?.domain,
264
+ type: "r2_bucket",
265
+ accountId: this.output?.accountId ?? "",
266
+ cors: props.cors,
267
+ dev,
268
+ });
269
+ }
270
+
271
+ const api = await createCloudflareApi(props);
272
+
273
+ if (this.phase === "delete") {
274
+ if (props.delete !== false) {
275
+ if (this.output.dev?.id) {
276
+ await deleteMiniflareBinding("r2", this.output.dev.id);
277
+ }
278
+ if (props.empty) {
279
+ await emptyBucket(api, bucketName, props);
280
+ }
281
+ await deleteBucket(api, bucketName, props);
282
+ }
283
+ return this.destroy();
284
+ }
215
285
 
216
- switch (this.phase) {
217
- case "create": {
218
- const bucket = await createBucket(api, bucketName, props).catch(
219
- async (err) => {
220
- if (
221
- err instanceof CloudflareApiError &&
222
- err.status === 409 &&
223
- props.adopt
224
- ) {
225
- return await getBucket(api, bucketName, props);
226
- }
227
- throw err;
228
- },
286
+ if (this.phase === "create" || !this.output?.name) {
287
+ const bucket = await createBucket(api, bucketName, props).catch(
288
+ async (err) => {
289
+ if (
290
+ err instanceof CloudflareApiError &&
291
+ err.status === 409 &&
292
+ props.adopt
293
+ ) {
294
+ return await getBucket(api, bucketName, props);
295
+ }
296
+ throw err;
297
+ },
298
+ );
299
+ const domain = await putManagedDomain(
300
+ api,
301
+ bucketName,
302
+ allowPublicAccess,
303
+ props.jurisdiction,
304
+ );
305
+ if (props.cors?.length) {
306
+ await putBucketCORS(api, bucketName, props);
307
+ }
308
+ return this({
309
+ name: bucketName,
310
+ location: bucket.location,
311
+ creationDate: new Date(bucket.creation_date),
312
+ jurisdiction: bucket.jurisdiction,
313
+ allowPublicAccess,
314
+ domain,
315
+ type: "r2_bucket",
316
+ accountId: api.accountId,
317
+ cors: props.cors,
318
+ dev,
319
+ });
320
+ } else {
321
+ if (bucketName !== this.output.name) {
322
+ throw new Error(
323
+ `Cannot update R2Bucket name after creation. Bucket name is immutable. Before: ${this.output.name}, After: ${bucketName}`,
229
324
  );
230
- const domain = await putManagedDomain(
325
+ }
326
+ let domain = this.output.domain;
327
+ if (!!domain !== allowPublicAccess) {
328
+ domain = await putManagedDomain(
231
329
  api,
232
330
  bucketName,
233
331
  allowPublicAccess,
234
332
  props.jurisdiction,
235
333
  );
236
- if (props.cors?.length) {
237
- await putBucketCORS(api, bucketName, props);
238
- }
239
- return this({
240
- name: bucketName,
241
- location: bucket.location,
242
- creationDate: new Date(bucket.creation_date),
243
- jurisdiction: bucket.jurisdiction,
244
- allowPublicAccess,
245
- domain,
246
- type: "r2_bucket",
247
- accountId: api.accountId,
248
- cors: props.cors,
249
- dev: props.dev,
250
- });
251
334
  }
252
- case "update": {
253
- if (bucketName !== this.output.name) {
254
- throw new Error(
255
- `Cannot update R2Bucket name after creation. Bucket name is immutable. Before: ${this.output.name}, After: ${bucketName}`,
256
- );
257
- }
258
- let domain = this.output.domain;
259
- if (!!domain !== allowPublicAccess) {
260
- domain = await putManagedDomain(
261
- api,
262
- bucketName,
263
- allowPublicAccess,
264
- props.jurisdiction,
265
- );
266
- }
267
- if (!isDeepStrictEqual(this.output.cors ?? [], props.cors ?? [])) {
268
- await putBucketCORS(api, bucketName, props);
269
- }
270
- return this({
271
- ...this.output,
272
- allowPublicAccess,
273
- dev: props.dev,
274
- cors: props.cors,
275
- domain,
276
- });
277
- }
278
- case "delete": {
279
- if (props.delete !== false) {
280
- if (props.empty) {
281
- await emptyBucket(api, bucketName, props);
282
- }
283
- await deleteBucket(api, bucketName, props);
284
- }
285
- return this.destroy();
335
+ if (!isDeepStrictEqual(this.output.cors ?? [], props.cors ?? [])) {
336
+ await putBucketCORS(api, bucketName, props);
286
337
  }
338
+ return this({
339
+ ...this.output,
340
+ allowPublicAccess,
341
+ dev,
342
+ cors: props.cors,
343
+ domain,
344
+ });
287
345
  }
288
346
  },
289
347
  );
@@ -4,4 +4,4 @@
4
4
  /**
5
5
  * The default Cloudflare Workers compatibility date, set based on the latest workerd release at the time of build.
6
6
  */
7
- export const DEFAULT_COMPATIBILITY_DATE = "2025-08-06";
7
+ export const DEFAULT_COMPATIBILITY_DATE = "2025-08-07";
@@ -368,6 +368,15 @@ export interface ContainerApplicationProps extends CloudflareApiOptions {
368
368
  * @default false
369
369
  */
370
370
  adopt?: boolean;
371
+
372
+ /**
373
+ * If true, the container application will not be created, but will be retained if it already exists.
374
+ * This is used for local development.
375
+ *
376
+ * @default `false`
377
+ * @internal
378
+ */
379
+ dev?: boolean;
371
380
  }
372
381
 
373
382
  /**
@@ -495,6 +504,13 @@ export const ContainerApplication = Resource(
495
504
  _id: string,
496
505
  props: ContainerApplicationProps,
497
506
  ): Promise<ContainerApplication> {
507
+ if (this.scope.local && props.dev) {
508
+ return this({
509
+ id: this.output?.id ?? "",
510
+ name: props.name,
511
+ });
512
+ }
513
+
498
514
  const api = await createCloudflareApi(props);
499
515
  if (this.phase === "delete") {
500
516
  if (this.output?.id) {
@@ -503,6 +519,7 @@ export const ContainerApplication = Resource(
503
519
  }
504
520
  return this.destroy();
505
521
  }
522
+
506
523
  // Prefer the immutable repo digest if present. Falls back to the tag reference.
507
524
  const imageReference = props.image.repoDigest ?? props.image.imageRef;
508
525
 
@@ -518,7 +535,7 @@ export const ContainerApplication = Resource(
518
535
  },
519
536
  },
520
537
  };
521
- if (this.phase === "update") {
538
+ if (this.phase === "update" && this.output?.id) {
522
539
  const application = await updateContainerApplication(
523
540
  api,
524
541
  this.output.id,
@@ -43,6 +43,15 @@ export interface CustomDomainProps extends CloudflareApiOptions {
43
43
  * @default false
44
44
  */
45
45
  adopt?: boolean;
46
+
47
+ /**
48
+ * If true, the custom domain will not be created, but will be retained if it already exists.
49
+ * This is used for local development.
50
+ *
51
+ * @default `Scope.local`
52
+ * @internal
53
+ */
54
+ dev?: boolean;
46
55
  }
47
56
 
48
57
  /**
@@ -114,6 +123,18 @@ export const CustomDomain = Resource(
114
123
  logicalId: string, // Changed param name from id to logicalId for clarity
115
124
  props: CustomDomainProps,
116
125
  ): Promise<CustomDomain> {
126
+ if (this.scope.local && props.dev) {
127
+ const now = Date.now();
128
+ return this({
129
+ ...props,
130
+ id: this.output?.id ?? "noop-domain",
131
+ zoneId: props.zoneId ?? "noop-zone",
132
+ environment: props.environment ?? "production",
133
+ createdAt: this.output?.createdAt ?? now,
134
+ updatedAt: now,
135
+ });
136
+ }
137
+
117
138
  // Create Cloudflare API client with automatic account discovery
118
139
  const api = await createCloudflareApi(props);
119
140
 
@@ -121,6 +142,7 @@ export const CustomDomain = Resource(
121
142
  await deleteCustomDomain(this, api, logicalId, props);
122
143
  return this.destroy();
123
144
  }
145
+
124
146
  // Create or Update phase
125
147
  return await ensureCustomDomain(this, api, logicalId, {
126
148
  ...props,
@@ -11,6 +11,7 @@ import {
11
11
  import { cloneD1Database } from "./d1-clone.ts";
12
12
  import { applyLocalD1Migrations } from "./d1-local-migrations.ts";
13
13
  import { applyMigrations, listMigrationsFiles } from "./d1-migrations.ts";
14
+ import { deleteMiniflareBinding } from "./miniflare/delete.ts";
14
15
 
15
16
  const DEFAULT_MIGRATIONS_TABLE = "d1_migrations";
16
17
 
@@ -126,7 +127,6 @@ export function isD1Database(resource: Resource): resource is D1Database {
126
127
  export type D1Database = Resource<"cloudflare::D1Database"> &
127
128
  Pick<
128
129
  D1DatabaseProps,
129
- | "dev"
130
130
  | "migrationsDir"
131
131
  | "migrationsTable"
132
132
  | "primaryLocationHint"
@@ -142,6 +142,22 @@ export type D1Database = Resource<"cloudflare::D1Database"> &
142
142
  * The name of the database
143
143
  */
144
144
  name: string;
145
+
146
+ /**
147
+ * Development mode properties
148
+ * @internal
149
+ */
150
+ dev: {
151
+ /**
152
+ * The ID of the database in development mode
153
+ */
154
+ id: string;
155
+
156
+ /**
157
+ * Whether the database is running remotely
158
+ */
159
+ remote: boolean;
160
+ };
145
161
  };
146
162
 
147
163
  /**
@@ -247,19 +263,14 @@ const _D1Database = Resource(
247
263
  id: string,
248
264
  props: D1DatabaseProps = {},
249
265
  ): Promise<D1Database> {
250
- const api = await createCloudflareApi(props);
251
266
  const databaseName = props.name ?? id;
267
+ const local = this.scope.local && !props.dev?.remote;
268
+ const dev = {
269
+ id: this.output?.dev?.id ?? this.output?.id ?? id,
270
+ remote: props.dev?.remote ?? false,
271
+ };
252
272
 
253
- if (this.phase === "delete") {
254
- if (props.delete !== false && this.output?.id !== id) {
255
- await deleteDatabase(api, this.output?.id);
256
- }
257
- // Return void (a deleted database has no content)
258
- return this.destroy();
259
- }
260
- let dbData: CloudflareD1Response;
261
-
262
- if (this.scope.local && !props.dev?.remote) {
273
+ if (local) {
263
274
  if (props.migrationsFiles && props.migrationsFiles.length > 0) {
264
275
  await applyLocalD1Migrations({
265
276
  databaseId: this.output?.id ?? id,
@@ -269,22 +280,36 @@ const _D1Database = Resource(
269
280
  }
270
281
  return this({
271
282
  type: "d1",
272
- // we may not have an ID yet if we're creating a new database locally first
273
- // so set it to the resource ID which we can later use to detect that a DB needs to be created during an `update`
274
- id: this.output?.id ?? id,
283
+ id: this.output?.id ?? "",
275
284
  name: databaseName,
276
285
  readReplication: props.readReplication,
277
286
  primaryLocationHint: props.primaryLocationHint,
278
287
  migrationsDir: props.migrationsDir,
279
288
  migrationsTable: props.migrationsTable ?? DEFAULT_MIGRATIONS_TABLE,
280
- dev: props.dev,
289
+ dev,
281
290
  });
282
- } else if (
291
+ }
292
+
293
+ const api = await createCloudflareApi(props);
294
+
295
+ if (this.phase === "delete") {
296
+ if (this.output.dev?.id) {
297
+ await deleteMiniflareBinding("d1", this.output.dev.id);
298
+ }
299
+ if (props.delete !== false && this.output?.id) {
300
+ await deleteDatabase(api, this.output.id);
301
+ }
302
+ // Return void (a deleted database has no content)
303
+ return this.destroy();
304
+ }
305
+ let dbData: CloudflareD1Response;
306
+
307
+ if (
283
308
  this.phase === "create" ||
284
309
  // this is true IFF the database was created locally before any live deployment
285
310
  // in that case, we should still go through the create flow for "update"
286
311
  // after that, the ID will remain the UUID for the lifetime of the database
287
- this.output.id === id
312
+ !this.output?.id
288
313
  ) {
289
314
  logger.log("Creating D1 database:", databaseName);
290
315
  try {
@@ -387,7 +412,7 @@ const _D1Database = Resource(
387
412
  name: databaseName,
388
413
  readReplication: dbData.result.read_replication,
389
414
  primaryLocationHint: props.primaryLocationHint,
390
- dev: props.dev,
415
+ dev,
391
416
  migrationsDir: props.migrationsDir,
392
417
  migrationsTable: props.migrationsTable ?? DEFAULT_MIGRATIONS_TABLE,
393
418
  });
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { logger } from "../util/logger.ts";
3
+ import type { CloudflareApiResponse } from "./api-response.ts";
3
4
  import type { CloudflareApi } from "./api.ts";
4
5
 
5
6
  /**
@@ -194,20 +195,6 @@ interface ImportPollingResponse {
194
195
  upload_url?: string;
195
196
  }
196
197
 
197
- /**
198
- * Cloudflare API response structure
199
- */
200
- interface CloudflareApiResponse<T> {
201
- result: T;
202
- success: boolean;
203
- errors: Array<{
204
- message: string;
205
- }>;
206
- messages: Array<{
207
- message: string;
208
- }>;
209
- }
210
-
211
198
  /**
212
199
  * Calculates MD5 hash for a string
213
200
  */