alchemy 0.12.21 → 0.14.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 (319) hide show
  1. package/lib/ai/client.d.ts.map +1 -1
  2. package/lib/ai/client.js +3 -5
  3. package/lib/ai/client.js.map +1 -1
  4. package/lib/alchemy.d.ts +2 -1
  5. package/lib/alchemy.d.ts.map +1 -1
  6. package/lib/alchemy.js +87 -92
  7. package/lib/alchemy.js.map +1 -1
  8. package/lib/apply.d.ts.map +1 -1
  9. package/lib/apply.js +6 -1
  10. package/lib/apply.js.map +1 -1
  11. package/lib/aws/bucket.d.ts.map +1 -1
  12. package/lib/aws/bucket.js +55 -57
  13. package/lib/aws/bucket.js.map +1 -1
  14. package/lib/aws/function.d.ts.map +1 -1
  15. package/lib/aws/function.js +250 -252
  16. package/lib/aws/function.js.map +1 -1
  17. package/lib/aws/policy-attachment.d.ts.map +1 -1
  18. package/lib/aws/policy-attachment.js +4 -6
  19. package/lib/aws/policy-attachment.js.map +1 -1
  20. package/lib/aws/policy.d.ts.map +1 -1
  21. package/lib/aws/policy.js +63 -65
  22. package/lib/aws/policy.js.map +1 -1
  23. package/lib/aws/queue.js +88 -90
  24. package/lib/aws/queue.js.map +1 -1
  25. package/lib/aws/table.d.ts.map +1 -1
  26. package/lib/aws/table.js +95 -99
  27. package/lib/aws/table.js.map +1 -1
  28. package/lib/cloudflare/account-api-token.d.ts +1 -1
  29. package/lib/cloudflare/account-api-token.d.ts.map +1 -1
  30. package/lib/cloudflare/account-api-token.js +0 -1
  31. package/lib/cloudflare/account-api-token.js.map +1 -1
  32. package/lib/cloudflare/ai-gateway.js.map +1 -1
  33. package/lib/cloudflare/ai.d.ts +1 -1
  34. package/lib/cloudflare/ai.d.ts.map +1 -1
  35. package/lib/cloudflare/ai.js.map +1 -1
  36. package/lib/cloudflare/api.d.ts +5 -5
  37. package/lib/cloudflare/api.d.ts.map +1 -1
  38. package/lib/cloudflare/api.js +52 -15
  39. package/lib/cloudflare/api.js.map +1 -1
  40. package/lib/cloudflare/auth.d.ts +24 -55
  41. package/lib/cloudflare/auth.d.ts.map +1 -1
  42. package/lib/cloudflare/auth.js +15 -72
  43. package/lib/cloudflare/auth.js.map +1 -1
  44. package/lib/cloudflare/bucket.d.ts +2 -2
  45. package/lib/cloudflare/bucket.d.ts.map +1 -1
  46. package/lib/cloudflare/bucket.js +22 -24
  47. package/lib/cloudflare/bucket.js.map +1 -1
  48. package/lib/cloudflare/bundle/alias-plugin.d.ts +6 -0
  49. package/lib/cloudflare/bundle/alias-plugin.d.ts.map +1 -0
  50. package/lib/cloudflare/bundle/alias-plugin.js +36 -0
  51. package/lib/cloudflare/bundle/alias-plugin.js.map +1 -0
  52. package/lib/cloudflare/bundle/build-failures.d.ts +12 -0
  53. package/lib/cloudflare/bundle/build-failures.d.ts.map +1 -0
  54. package/lib/cloudflare/bundle/build-failures.js +45 -0
  55. package/lib/cloudflare/bundle/build-failures.js.map +1 -0
  56. package/lib/cloudflare/bundle/bundle-worker.d.ts +7 -0
  57. package/lib/cloudflare/bundle/bundle-worker.d.ts.map +1 -0
  58. package/lib/cloudflare/bundle/bundle-worker.js +69 -0
  59. package/lib/cloudflare/bundle/bundle-worker.js.map +1 -0
  60. package/lib/cloudflare/bundle/external.d.ts +1 -0
  61. package/lib/cloudflare/bundle/external.d.ts.map +1 -1
  62. package/lib/cloudflare/bundle/external.js +8 -1
  63. package/lib/cloudflare/bundle/external.js.map +1 -1
  64. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts +1 -1
  65. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts.map +1 -1
  66. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js +6 -6
  67. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js.map +1 -1
  68. package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts +17 -0
  69. package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts.map +1 -0
  70. package/lib/cloudflare/bundle/nodejs-compat-mode.js +27 -0
  71. package/lib/cloudflare/bundle/nodejs-compat-mode.js.map +1 -0
  72. package/lib/cloudflare/bundle/{hybrid-nodejs-compat.d.ts → nodejs-compat.d.ts} +2 -2
  73. package/lib/cloudflare/bundle/nodejs-compat.d.ts.map +1 -0
  74. package/lib/cloudflare/bundle/{hybrid-nodejs-compat.js → nodejs-compat.js} +2 -2
  75. package/lib/cloudflare/bundle/nodejs-compat.js.map +1 -0
  76. package/lib/cloudflare/custom-domain.d.ts.map +1 -1
  77. package/lib/cloudflare/custom-domain.js +3 -5
  78. package/lib/cloudflare/custom-domain.js.map +1 -1
  79. package/lib/cloudflare/d1-database.d.ts +1 -1
  80. package/lib/cloudflare/d1-database.d.ts.map +1 -1
  81. package/lib/cloudflare/d1-database.js +70 -72
  82. package/lib/cloudflare/d1-database.js.map +1 -1
  83. package/lib/cloudflare/d1-migrations.d.ts +1 -1
  84. package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
  85. package/lib/cloudflare/d1-migrations.js +2 -3
  86. package/lib/cloudflare/d1-migrations.js.map +1 -1
  87. package/lib/cloudflare/dns-records.d.ts.map +1 -1
  88. package/lib/cloudflare/dns-records.js +2 -4
  89. package/lib/cloudflare/dns-records.js.map +1 -1
  90. package/lib/cloudflare/kv-namespace.d.ts +1 -1
  91. package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
  92. package/lib/cloudflare/kv-namespace.js +24 -27
  93. package/lib/cloudflare/kv-namespace.js.map +1 -1
  94. package/lib/cloudflare/pipeline.d.ts +1 -1
  95. package/lib/cloudflare/pipeline.d.ts.map +1 -1
  96. package/lib/cloudflare/pipeline.js +32 -34
  97. package/lib/cloudflare/pipeline.js.map +1 -1
  98. package/lib/cloudflare/queue-consumer.d.ts +1 -1
  99. package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
  100. package/lib/cloudflare/queue-consumer.js +27 -33
  101. package/lib/cloudflare/queue-consumer.js.map +1 -1
  102. package/lib/cloudflare/queue.d.ts +1 -1
  103. package/lib/cloudflare/queue.d.ts.map +1 -1
  104. package/lib/cloudflare/queue.js +36 -38
  105. package/lib/cloudflare/queue.js.map +1 -1
  106. package/lib/cloudflare/r2-rest-state-store.js +4 -8
  107. package/lib/cloudflare/r2-rest-state-store.js.map +1 -1
  108. package/lib/cloudflare/types.d.ts.map +1 -1
  109. package/lib/cloudflare/types.js +1 -3
  110. package/lib/cloudflare/types.js.map +1 -1
  111. package/lib/cloudflare/user.d.ts +51 -0
  112. package/lib/cloudflare/user.d.ts.map +1 -0
  113. package/lib/cloudflare/user.js +62 -0
  114. package/lib/cloudflare/user.js.map +1 -0
  115. package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
  116. package/lib/cloudflare/vectorize-index.js +37 -39
  117. package/lib/cloudflare/vectorize-index.js.map +1 -1
  118. package/lib/cloudflare/vectorize-metadata-index.d.ts +1 -1
  119. package/lib/cloudflare/vectorize-metadata-index.d.ts.map +1 -1
  120. package/lib/cloudflare/vectorize-metadata-index.js +10 -13
  121. package/lib/cloudflare/vectorize-metadata-index.js.map +1 -1
  122. package/lib/cloudflare/worker.d.ts +18 -3
  123. package/lib/cloudflare/worker.d.ts.map +1 -1
  124. package/lib/cloudflare/worker.js +11 -54
  125. package/lib/cloudflare/worker.js.map +1 -1
  126. package/lib/cloudflare/workflow.d.ts +1 -1
  127. package/lib/cloudflare/workflow.d.ts.map +1 -1
  128. package/lib/cloudflare/workflow.js.map +1 -1
  129. package/lib/cloudflare/zone.d.ts.map +1 -1
  130. package/lib/cloudflare/zone.js +48 -50
  131. package/lib/cloudflare/zone.js.map +1 -1
  132. package/lib/dns/godaddy.js +1 -1
  133. package/lib/dns/import-dns.js +1 -1
  134. package/lib/dns/import-dns.js.map +1 -1
  135. package/lib/env.js +7 -9
  136. package/lib/env.js.map +1 -1
  137. package/lib/esbuild/bundle.d.ts.map +1 -1
  138. package/lib/esbuild/bundle.js +8 -11
  139. package/lib/esbuild/bundle.js.map +1 -1
  140. package/lib/fs/copy-file.d.ts.map +1 -1
  141. package/lib/fs/copy-file.js +27 -29
  142. package/lib/fs/copy-file.js.map +1 -1
  143. package/lib/fs/file.d.ts +1 -1
  144. package/lib/fs/file.d.ts.map +1 -1
  145. package/lib/fs/file.js +1 -1
  146. package/lib/fs/file.js.map +1 -1
  147. package/lib/fs/folder.d.ts.map +1 -1
  148. package/lib/fs/folder.js +1 -3
  149. package/lib/fs/folder.js.map +1 -1
  150. package/lib/github/client.d.ts.map +1 -1
  151. package/lib/github/client.js +3 -5
  152. package/lib/github/client.js.map +1 -1
  153. package/lib/github/repository-environment.d.ts.map +1 -1
  154. package/lib/github/repository-environment.js +173 -176
  155. package/lib/github/repository-environment.js.map +1 -1
  156. package/lib/github/secret.d.ts.map +1 -1
  157. package/lib/github/secret.js +97 -99
  158. package/lib/github/secret.js.map +1 -1
  159. package/lib/internal/docs/providers.d.ts.map +1 -1
  160. package/lib/internal/docs/providers.js +5 -7
  161. package/lib/internal/docs/providers.js.map +1 -1
  162. package/lib/neon/api.js +1 -2
  163. package/lib/neon/api.js.map +1 -1
  164. package/lib/neon/project.js +2 -2
  165. package/lib/neon/project.js.map +1 -1
  166. package/lib/os/exec.d.ts +5 -0
  167. package/lib/os/exec.d.ts.map +1 -1
  168. package/lib/os/exec.js +88 -56
  169. package/lib/os/exec.js.map +1 -1
  170. package/lib/scope.d.ts +3 -0
  171. package/lib/scope.d.ts.map +1 -1
  172. package/lib/scope.js +10 -3
  173. package/lib/scope.js.map +1 -1
  174. package/lib/secret.d.ts.map +1 -1
  175. package/lib/secret.js +1 -3
  176. package/lib/secret.js.map +1 -1
  177. package/lib/serde.d.ts.map +1 -1
  178. package/lib/serde.js +13 -15
  179. package/lib/serde.js.map +1 -1
  180. package/lib/stripe/price.d.ts.map +1 -1
  181. package/lib/stripe/price.js +69 -73
  182. package/lib/stripe/price.js.map +1 -1
  183. package/lib/stripe/product.d.ts.map +1 -1
  184. package/lib/stripe/product.js +50 -52
  185. package/lib/stripe/product.js.map +1 -1
  186. package/lib/stripe/webhook.d.ts.map +1 -1
  187. package/lib/stripe/webhook.js +51 -53
  188. package/lib/stripe/webhook.js.map +1 -1
  189. package/lib/test/bun.d.ts +1 -1
  190. package/lib/test/bun.d.ts.map +1 -1
  191. package/lib/test/bun.js +3 -8
  192. package/lib/test/bun.js.map +1 -1
  193. package/lib/test/prune.d.ts.map +1 -1
  194. package/lib/test/prune.js.map +1 -1
  195. package/lib/util/dedent.js +4 -4
  196. package/lib/util/dedent.js.map +1 -1
  197. package/lib/web/astro.js +1 -1
  198. package/lib/web/shadcn.js +4 -4
  199. package/lib/web/shadcn.js.map +1 -1
  200. package/lib/web/tailwind.d.ts.map +1 -1
  201. package/lib/web/tailwind.js +0 -1
  202. package/lib/web/tailwind.js.map +1 -1
  203. package/lib/web/vite.js +3 -3
  204. package/lib/web/vitepress/home-page.d.ts.map +1 -1
  205. package/lib/web/vitepress/home-page.js +6 -8
  206. package/lib/web/vitepress/home-page.js.map +1 -1
  207. package/lib/web/vitepress/process-front-matter-files.js +1 -1
  208. package/lib/web/vitepress/process-front-matter-files.js.map +1 -1
  209. package/lib/web/vitepress/vitepress.js +2 -2
  210. package/lib/web/vitepress/vitepress.js.map +1 -1
  211. package/package.json +4 -1
  212. package/src/ai/astro-file.ts +4 -4
  213. package/src/ai/client.ts +4 -5
  214. package/src/ai/css-file.ts +4 -4
  215. package/src/ai/document.ts +3 -3
  216. package/src/ai/html-file.ts +4 -4
  217. package/src/ai/json-file.ts +1 -1
  218. package/src/ai/typescript-file.ts +4 -4
  219. package/src/ai/vue-file.ts +4 -4
  220. package/src/ai/yaml-file.ts +1 -1
  221. package/src/alchemy.ts +111 -104
  222. package/src/apply.ts +13 -6
  223. package/src/aws/bucket.ts +72 -75
  224. package/src/aws/function.ts +296 -297
  225. package/src/aws/oidc/github-oidc-provider.ts +1 -1
  226. package/src/aws/oidc/oidc-provider.ts +15 -15
  227. package/src/aws/policy-attachment.ts +10 -11
  228. package/src/aws/policy.ts +91 -94
  229. package/src/aws/queue.ts +111 -111
  230. package/src/aws/role.ts +24 -24
  231. package/src/aws/ses.ts +17 -17
  232. package/src/aws/table.ts +114 -115
  233. package/src/cloudflare/account-api-token.ts +11 -11
  234. package/src/cloudflare/ai-gateway.ts +4 -4
  235. package/src/cloudflare/ai.ts +1 -1
  236. package/src/cloudflare/api-error.ts +1 -1
  237. package/src/cloudflare/api.ts +70 -25
  238. package/src/cloudflare/assets.ts +4 -4
  239. package/src/cloudflare/auth.ts +49 -164
  240. package/src/cloudflare/bucket.ts +62 -63
  241. package/src/cloudflare/bundle/alias-plugin.ts +48 -0
  242. package/src/cloudflare/bundle/build-failures.ts +55 -0
  243. package/src/cloudflare/bundle/bundle-worker.ts +89 -0
  244. package/src/cloudflare/bundle/external.ts +9 -1
  245. package/src/cloudflare/bundle/local-dev-cloudflare-shim.ts +7 -6
  246. package/src/cloudflare/bundle/nodejs-compat-mode.ts +49 -0
  247. package/src/cloudflare/bundle/{hybrid-nodejs-compat.ts → nodejs-compat.ts} +10 -10
  248. package/src/cloudflare/custom-domain.ts +27 -28
  249. package/src/cloudflare/d1-database.ts +101 -102
  250. package/src/cloudflare/d1-migrations.ts +10 -10
  251. package/src/cloudflare/dns-records.ts +23 -24
  252. package/src/cloudflare/durable-object-namespace.ts +1 -1
  253. package/src/cloudflare/event-source.ts +1 -1
  254. package/src/cloudflare/hyperdrive.ts +3 -3
  255. package/src/cloudflare/kv-namespace.ts +36 -37
  256. package/src/cloudflare/nuxt.ts +1 -1
  257. package/src/cloudflare/permission-groups.ts +7 -7
  258. package/src/cloudflare/pipeline.ts +55 -56
  259. package/src/cloudflare/queue-consumer.ts +46 -53
  260. package/src/cloudflare/queue.ts +56 -57
  261. package/src/cloudflare/r2-rest-state-store.ts +11 -11
  262. package/src/cloudflare/redwood.ts +1 -1
  263. package/src/cloudflare/tanstack-start.ts +1 -1
  264. package/src/cloudflare/types.ts +1 -2
  265. package/src/cloudflare/user.ts +142 -0
  266. package/src/cloudflare/vectorize-index.ts +60 -61
  267. package/src/cloudflare/vectorize-metadata-index.ts +25 -25
  268. package/src/cloudflare/vite.ts +1 -1
  269. package/src/cloudflare/website.ts +3 -3
  270. package/src/cloudflare/worker.ts +83 -108
  271. package/src/cloudflare/workflow.ts +4 -4
  272. package/src/cloudflare/wrangler.json.ts +4 -4
  273. package/src/cloudflare/zone.ts +69 -70
  274. package/src/destroy.ts +4 -4
  275. package/src/dns/godaddy.ts +1 -1
  276. package/src/dns/import-dns.ts +5 -5
  277. package/src/encrypt.ts +6 -6
  278. package/src/env.ts +10 -10
  279. package/src/esbuild/bundle.ts +14 -15
  280. package/src/fs/copy-file.ts +35 -36
  281. package/src/fs/file-system-state-store.ts +4 -4
  282. package/src/fs/file.ts +9 -8
  283. package/src/fs/folder.ts +6 -7
  284. package/src/github/client.ts +15 -14
  285. package/src/github/repository-environment.ts +206 -210
  286. package/src/github/secret.ts +111 -116
  287. package/src/internal/docs/providers.ts +16 -17
  288. package/src/neon/api-error.ts +1 -1
  289. package/src/neon/api.ts +6 -6
  290. package/src/neon/project.ts +18 -17
  291. package/src/os/exec.ts +107 -66
  292. package/src/resource.ts +3 -3
  293. package/src/scope.ts +14 -4
  294. package/src/secret.ts +2 -3
  295. package/src/serde.ts +30 -22
  296. package/src/stripe/price.ts +74 -77
  297. package/src/stripe/product.ts +55 -56
  298. package/src/stripe/webhook.ts +56 -57
  299. package/src/test/bun.ts +9 -13
  300. package/src/test/prune.ts +4 -4
  301. package/src/util/dedent.ts +4 -4
  302. package/src/web/astro.ts +10 -10
  303. package/src/web/shadcn-component.ts +4 -4
  304. package/src/web/shadcn.ts +10 -10
  305. package/src/web/tailwind.ts +2 -3
  306. package/src/web/vite.ts +11 -11
  307. package/src/web/vitepress/config.ts +2 -2
  308. package/src/web/vitepress/custom-theme.ts +7 -7
  309. package/src/web/vitepress/dependencies.ts +4 -4
  310. package/src/web/vitepress/home-page.ts +8 -9
  311. package/src/web/vitepress/process-front-matter-files.ts +5 -5
  312. package/src/web/vitepress/vitepress.ts +7 -7
  313. package/lib/cloudflare/account-id.d.ts +0 -6
  314. package/lib/cloudflare/account-id.d.ts.map +0 -1
  315. package/lib/cloudflare/account-id.js +0 -6
  316. package/lib/cloudflare/account-id.js.map +0 -1
  317. package/lib/cloudflare/bundle/hybrid-nodejs-compat.d.ts.map +0 -1
  318. package/lib/cloudflare/bundle/hybrid-nodejs-compat.js.map +0 -1
  319. package/src/cloudflare/account-id.ts +0 -12
@@ -3,7 +3,7 @@ import type { Context } from "../context.js";
3
3
  import { Resource } from "../resource.js";
4
4
  import type { Secret } from "../secret.js";
5
5
  import { CloudflareApiError, handleApiError } from "./api-error.js";
6
- import { CloudflareApi, createCloudflareApi } from "./api.js";
6
+ import { type CloudflareApi, createCloudflareApi } from "./api.js";
7
7
 
8
8
  /**
9
9
  * Properties for creating or updating an R2 Bucket
@@ -162,7 +162,7 @@ export const R2Bucket = Resource(
162
162
  async function (
163
163
  this: Context<R2Bucket>,
164
164
  id: string,
165
- props: BucketProps = {}
165
+ props: BucketProps = {},
166
166
  ): Promise<R2Bucket> {
167
167
  const api = await createCloudflareApi(props);
168
168
  const bucketName = props.name || this.id;
@@ -184,38 +184,37 @@ export const R2Bucket = Resource(
184
184
 
185
185
  // Return void (a deleted bucket has no content)
186
186
  return this.destroy();
187
- } else {
188
- if (this.phase === "create") {
189
- try {
190
- await createBucket(api, bucketName, props);
191
- } catch (err) {
192
- if (err instanceof CloudflareApiError && err.status === 409) {
193
- if (!props.adopt) {
194
- throw err;
195
- }
196
- } else {
187
+ }
188
+ if (this.phase === "create") {
189
+ try {
190
+ await createBucket(api, bucketName, props);
191
+ } catch (err) {
192
+ if (err instanceof CloudflareApiError && err.status === 409) {
193
+ if (!props.adopt) {
197
194
  throw err;
198
195
  }
196
+ } else {
197
+ throw err;
199
198
  }
200
199
  }
200
+ }
201
201
 
202
- await updatePublicAccess(
203
- api,
204
- bucketName,
205
- props.allowPublicAccess === true,
206
- props.jurisdiction
207
- );
202
+ await updatePublicAccess(
203
+ api,
204
+ bucketName,
205
+ props.allowPublicAccess === true,
206
+ props.jurisdiction,
207
+ );
208
208
 
209
- return this({
210
- name: bucketName,
211
- location: props.locationHint || "default",
212
- creationDate: new Date(),
213
- jurisdiction: props.jurisdiction || "default",
214
- type: "r2_bucket",
215
- accountId: api.accountId,
216
- });
217
- }
218
- }
209
+ return this({
210
+ name: bucketName,
211
+ location: props.locationHint || "default",
212
+ creationDate: new Date(),
213
+ jurisdiction: props.jurisdiction || "default",
214
+ type: "r2_bucket",
215
+ accountId: api.accountId,
216
+ });
217
+ },
219
218
  );
220
219
 
221
220
  /**
@@ -248,7 +247,7 @@ export function createR2Client(config?: R2ClientConfig): Promise<R2Client> {
248
247
 
249
248
  if (!accessKeyId || !secretAccessKey) {
250
249
  throw new Error(
251
- "R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY environment variables are required"
250
+ "R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY environment variables are required",
252
251
  );
253
252
  }
254
253
 
@@ -287,8 +286,8 @@ interface CloudflareBucketResponse {
287
286
  * @returns Modified headers object
288
287
  */
289
288
  export function withJurisdiction(
290
- headers: Record<string, string> = {},
291
- props: BucketProps | { jurisdiction?: string } | string | undefined
289
+ headers: Record<string, string>,
290
+ props: BucketProps | { jurisdiction?: string } | string | undefined,
292
291
  ): Record<string, string> {
293
292
  // Clone the headers object to avoid modifying the original
294
293
  const result = { ...headers };
@@ -313,12 +312,12 @@ export function withJurisdiction(
313
312
  export async function getBucket(
314
313
  api: CloudflareApi,
315
314
  bucketName: string,
316
- props: BucketProps = {}
315
+ props: BucketProps = {},
317
316
  ): Promise<CloudflareBucketResponse> {
318
317
  const headers = withJurisdiction({}, props);
319
318
  const getResponse = await api.get(
320
319
  `/accounts/${api.accountId}/r2/buckets/${bucketName}`,
321
- { headers }
320
+ { headers },
322
321
  );
323
322
 
324
323
  if (!getResponse.ok) {
@@ -335,7 +334,7 @@ export async function getBucket(
335
334
 
336
335
  throw new CloudflareApiError(
337
336
  `Error getting R2 bucket '${bucketName}': ${errorData.errors?.[0]?.message || getResponse.statusText}`,
338
- getResponse
337
+ getResponse,
339
338
  );
340
339
  }
341
340
 
@@ -345,7 +344,7 @@ export async function getBucket(
345
344
  export async function createBucket(
346
345
  api: CloudflareApi,
347
346
  bucketName: string,
348
- props: BucketProps = {}
347
+ props: BucketProps = {},
349
348
  ): Promise<CloudflareBucketResponse> {
350
349
  // Create new R2 bucket
351
350
  const createPayload: any = {
@@ -361,7 +360,7 @@ export async function createBucket(
361
360
  const createResponse = await api.post(
362
361
  `/accounts/${api.accountId}/r2/buckets`,
363
362
  createPayload,
364
- { headers }
363
+ { headers },
365
364
  );
366
365
 
367
366
  if (!createResponse.ok) {
@@ -369,7 +368,7 @@ export async function createBucket(
369
368
  createResponse,
370
369
  "creating",
371
370
  "R2 bucket",
372
- bucketName
371
+ bucketName,
373
372
  );
374
373
  }
375
374
 
@@ -382,14 +381,14 @@ export async function createBucket(
382
381
  export async function deleteBucket(
383
382
  api: CloudflareApi,
384
383
  bucketName: string,
385
- props: BucketProps
384
+ props: BucketProps,
386
385
  ): Promise<void> {
387
386
  // Delete R2 bucket
388
387
  const headers = withJurisdiction({}, props);
389
388
 
390
389
  const deleteResponse = await api.delete(
391
390
  `/accounts/${api.accountId}/r2/buckets/${bucketName}`,
392
- { headers }
391
+ { headers },
393
392
  );
394
393
 
395
394
  if (!deleteResponse.ok && deleteResponse.status !== 404) {
@@ -398,7 +397,7 @@ export async function deleteBucket(
398
397
  }));
399
398
  throw new CloudflareApiError(
400
399
  `Error deleting R2 bucket '${bucketName}': ${errorData.errors?.[0]?.message || deleteResponse.statusText}`,
401
- deleteResponse
400
+ deleteResponse,
402
401
  );
403
402
  }
404
403
  }
@@ -416,11 +415,11 @@ export async function listObjects(
416
415
  r2: R2Client,
417
416
  bucketName: string,
418
417
  continuationToken?: string,
419
- jurisdiction?: string
418
+ jurisdiction?: string,
420
419
  ): Promise<{ objects: { Key: string }[]; continuationToken?: string }> {
421
420
  // List objects in the bucket
422
421
  const url = new URL(
423
- `https://${r2.accountId}.r2.cloudflarestorage.com/${bucketName}`
422
+ `https://${r2.accountId}.r2.cloudflarestorage.com/${bucketName}`,
424
423
  );
425
424
  if (continuationToken) {
426
425
  url.searchParams.set("continuation-token", continuationToken);
@@ -433,7 +432,7 @@ export async function listObjects(
433
432
  if (!listResponse.ok) {
434
433
  throw new CloudflareApiError(
435
434
  `Failed to list objects: ${listResponse.statusText}`,
436
- listResponse
435
+ listResponse,
437
436
  );
438
437
  }
439
438
 
@@ -450,7 +449,7 @@ export async function listObjects(
450
449
  // Get continuation token if present using regex
451
450
  const tokenMatch =
452
451
  /<NextContinuationToken>([^<]+)<\/NextContinuationToken>/.exec(
453
- responseText
452
+ responseText,
454
453
  );
455
454
  const nextContinuationToken = tokenMatch ? tokenMatch[1] : undefined;
456
455
 
@@ -463,7 +462,7 @@ export async function listObjects(
463
462
  export async function emptyBucket(
464
463
  r2: R2Client,
465
464
  bucketName: string,
466
- jurisdiction?: string
465
+ jurisdiction?: string,
467
466
  ): Promise<void> {
468
467
  let continuationToken: string | undefined;
469
468
  let totalDeleted = 0;
@@ -476,7 +475,7 @@ export async function emptyBucket(
476
475
  r2,
477
476
  bucketName,
478
477
  continuationToken,
479
- jurisdiction
478
+ jurisdiction,
480
479
  );
481
480
 
482
481
  continuationToken = nextToken;
@@ -497,16 +496,16 @@ export async function emptyBucket(
497
496
  `;
498
497
 
499
498
  const deleteUrl = new URL(
500
- `https://${r2.accountId}.r2.cloudflarestorage.com/${bucketName}?delete`
499
+ `https://${r2.accountId}.r2.cloudflarestorage.com/${bucketName}?delete`,
501
500
  );
502
501
 
503
502
  console.log(
504
- `Deleting ${batch.length} objects from bucket ${bucketName}`
503
+ `Deleting ${batch.length} objects from bucket ${bucketName}`,
505
504
  );
506
505
 
507
506
  const headers = withJurisdiction(
508
507
  { "Content-Type": "application/xml" },
509
- jurisdiction
508
+ jurisdiction,
510
509
  );
511
510
 
512
511
  const deleteResponse = await r2.fetch(deleteUrl.toString(), {
@@ -518,7 +517,7 @@ export async function emptyBucket(
518
517
  if (!deleteResponse.ok) {
519
518
  throw new CloudflareApiError(
520
519
  `Failed to delete objects: ${deleteResponse.statusText}`,
521
- deleteResponse
520
+ deleteResponse,
522
521
  );
523
522
  }
524
523
 
@@ -528,7 +527,7 @@ export async function emptyBucket(
528
527
  } while (continuationToken);
529
528
 
530
529
  console.log(
531
- `Successfully emptied bucket ${bucketName}, deleted ${totalDeleted} objects total`
530
+ `Successfully emptied bucket ${bucketName}, deleted ${totalDeleted} objects total`,
532
531
  );
533
532
  } catch (error) {
534
533
  if (error instanceof CloudflareApiError && error.status === 404) {
@@ -550,7 +549,7 @@ export async function updatePublicAccess(
550
549
  api: CloudflareApi,
551
550
  bucketName: string,
552
551
  allowPublicAccess: boolean,
553
- jurisdiction?: string
552
+ jurisdiction?: string,
554
553
  ): Promise<void> {
555
554
  const headers = withJurisdiction({}, jurisdiction);
556
555
 
@@ -559,7 +558,7 @@ export async function updatePublicAccess(
559
558
  {
560
559
  enabled: allowPublicAccess,
561
560
  },
562
- { headers }
561
+ { headers },
563
562
  );
564
563
 
565
564
  if (!response.ok) {
@@ -567,7 +566,7 @@ export async function updatePublicAccess(
567
566
  response,
568
567
  "updating public access for",
569
568
  "R2 bucket",
570
- bucketName
569
+ bucketName,
571
570
  );
572
571
  }
573
572
  }
@@ -581,8 +580,8 @@ export async function setCorsConfiguration(
581
580
  allowedOrigins: string[] = ["*"],
582
581
  allowedMethods: string[] = ["GET", "HEAD", "PUT", "POST", "DELETE"],
583
582
  allowedHeaders: string[] = ["*"],
584
- maxAgeSeconds: number = 3600,
585
- jurisdiction?: string
583
+ maxAgeSeconds = 3600,
584
+ jurisdiction?: string,
586
585
  ): Promise<void> {
587
586
  try {
588
587
  // Construct CORS XML configuration
@@ -599,12 +598,12 @@ export async function setCorsConfiguration(
599
598
  `;
600
599
 
601
600
  const url = new URL(
602
- `https://${r2.accountId}.r2.cloudflarestorage.com/${bucketName}?cors`
601
+ `https://${r2.accountId}.r2.cloudflarestorage.com/${bucketName}?cors`,
603
602
  );
604
603
 
605
604
  const headers = withJurisdiction(
606
605
  { "Content-Type": "application/xml" },
607
- jurisdiction
606
+ jurisdiction,
608
607
  );
609
608
 
610
609
  const response = await r2.fetch(url.toString(), {
@@ -616,7 +615,7 @@ export async function setCorsConfiguration(
616
615
  if (!response.ok) {
617
616
  throw new CloudflareApiError(
618
617
  `Failed to set CORS configuration: ${response.statusText}`,
619
- response
618
+ response,
620
619
  );
621
620
  }
622
621
 
@@ -624,7 +623,7 @@ export async function setCorsConfiguration(
624
623
  } catch (error) {
625
624
  console.error(
626
625
  `Failed to set CORS configuration for bucket ${bucketName}:`,
627
- error
626
+ error,
628
627
  );
629
628
  throw error;
630
629
  }
@@ -660,7 +659,7 @@ export async function listBuckets(
660
659
  cursor?: string;
661
660
  direction?: "asc" | "desc";
662
661
  jurisdiction?: string;
663
- } = {}
662
+ } = {},
664
663
  ): Promise<R2BucketInfo[]> {
665
664
  // Build query parameters
666
665
  const params = new URLSearchParams();
@@ -682,7 +681,7 @@ export async function listBuckets(
682
681
  }
683
682
 
684
683
  // Build URL with query parameters
685
- const path = `/accounts/${api.accountId}/r2/buckets${params.toString() ? "?" + params.toString() : ""}`;
684
+ const path = `/accounts/${api.accountId}/r2/buckets${params.toString() ? `?${params.toString()}` : ""}`;
686
685
 
687
686
  // Set jurisdiction header if provided
688
687
  const headers = withJurisdiction({}, options.jurisdiction);
@@ -693,7 +692,7 @@ export async function listBuckets(
693
692
  if (!response.ok) {
694
693
  throw new CloudflareApiError(
695
694
  `Failed to list buckets: ${response.statusText}`,
696
- response
695
+ response,
697
696
  );
698
697
  }
699
698
 
@@ -0,0 +1,48 @@
1
+ import type { Plugin } from "esbuild";
2
+
3
+ export const createAliasPlugin = ({
4
+ alias,
5
+ projectRoot,
6
+ }: {
7
+ alias: Record<string, string>;
8
+ projectRoot: string;
9
+ }): Plugin => ({
10
+ name: "alias",
11
+ setup(build) {
12
+ if (!alias) {
13
+ return;
14
+ }
15
+
16
+ // filter the hook calls to only those that match the alias keys
17
+ // this should avoid slowing down builds which don't use aliasing
18
+ const filter = new RegExp(
19
+ Object.keys(alias)
20
+ .map((key) => escapeRegex(key))
21
+ .join("|"),
22
+ );
23
+
24
+ // reimplement module aliasing as an esbuild plugin onResolve hook
25
+ build.onResolve({ filter }, (args) => {
26
+ const aliasPath = alias[args.path];
27
+ if (aliasPath) {
28
+ return {
29
+ // resolve with node resolution
30
+ path: require.resolve(aliasPath, {
31
+ // From the esbuild alias docs: "Note that when an import path is substituted using an alias, the resulting import path is resolved in the working directory instead of in the directory containing the source file with the import path."
32
+ // https://esbuild.github.io/api/#alias:~:text=Note%20that%20when%20an%20import%20path%20is%20substituted%20using%20an%20alias%2C%20the%20resulting%20import%20path%20is%20resolved%20in%20the%20working%20directory%20instead%20of%20in%20the%20directory%20containing%20the%20source%20file%20with%20the%20import%20path.
33
+ paths: [projectRoot],
34
+ }),
35
+ };
36
+ }
37
+ });
38
+ },
39
+ });
40
+
41
+ // Taken from https://stackoverflow.com/a/3561711
42
+ // which is everything from the tc39 proposal, plus the following two characters: ^/
43
+ // It's also everything included in the URLPattern escape (https://wicg.github.io/urlpattern/#escape-a-regexp-string), plus the following: -
44
+ // As the answer says, there's no downside to escaping these extra characters, so better safe than sorry
45
+ const ESCAPE_REGEX_CHARACTERS = /[-/\\^$*+?.()|[\]{}]/g;
46
+ const escapeRegex = (str: string) => {
47
+ return str.replace(ESCAPE_REGEX_CHARACTERS, "\\$&");
48
+ };
@@ -0,0 +1,55 @@
1
+ import type * as esbuild from "esbuild";
2
+ import type { NodeJSCompatMode } from "miniflare";
3
+ import { builtinModules } from "node:module";
4
+
5
+ /**
6
+ * RegExp matching against esbuild's error text when it is unable to resolve
7
+ * a Node built-in module. If we detect this when node_compat is disabled,
8
+ * we'll rewrite the error to suggest enabling it.
9
+ */
10
+ const nodeBuiltinResolveErrorText = new RegExp(
11
+ '^Could not resolve "(' +
12
+ builtinModules.join("|") +
13
+ "|" +
14
+ builtinModules.map((module) => `node:${module}`).join("|") +
15
+ ')"$',
16
+ );
17
+ /**
18
+ * Rewrites esbuild BuildFailures for failing to resolve Node built-in modules
19
+ * to suggest enabling Node compat as opposed to `platform: "node"`.
20
+ */
21
+ export function rewriteNodeCompatBuildFailure(
22
+ errors: esbuild.Message[],
23
+ compatMode: NodeJSCompatMode = null,
24
+ ) {
25
+ for (const error of errors) {
26
+ const match = nodeBuiltinResolveErrorText.exec(error.text);
27
+ if (match !== null) {
28
+ let text = `The package "${match[1]}" wasn't found on the file system but is built into node.\n`;
29
+
30
+ if (compatMode === null || compatMode === "als") {
31
+ text += `- Add the "nodejs_compat" compatibility flag to your project.\n`;
32
+ } else if (compatMode === "v1" && !match[1].startsWith("node:")) {
33
+ text += `- Make sure to prefix the module name with "node:" or update your compatibility_date to 2024-09-23 or later.\n`;
34
+ }
35
+
36
+ error.notes = [
37
+ {
38
+ location: null,
39
+ text,
40
+ },
41
+ ];
42
+ }
43
+ }
44
+ }
45
+ /**
46
+ * Returns true if the passed value looks like an esbuild BuildFailure object
47
+ */
48
+ export function isBuildFailure(err: unknown): err is esbuild.BuildFailure {
49
+ return (
50
+ typeof err === "object" &&
51
+ err !== null &&
52
+ "errors" in err &&
53
+ "warnings" in err
54
+ );
55
+ }
@@ -0,0 +1,89 @@
1
+ import fs from "node:fs/promises";
2
+ import { Bundle } from "../../esbuild/bundle.js";
3
+ import type { Bindings } from "../bindings.js";
4
+ import type { WorkerProps } from "../worker.js";
5
+ import { createAliasPlugin } from "./alias-plugin.js";
6
+ import {
7
+ isBuildFailure,
8
+ rewriteNodeCompatBuildFailure,
9
+ } from "./build-failures.js";
10
+ import { external, external_als } from "./external.js";
11
+ import { getNodeJSCompatMode } from "./nodejs-compat-mode.js";
12
+ import { nodeJsCompatPlugin } from "./nodejs-compat.js";
13
+
14
+ export async function bundleWorkerScript<B extends Bindings>(
15
+ props: WorkerProps<B> & {
16
+ compatibilityDate: string;
17
+ compatibilityFlags: string[];
18
+ },
19
+ ) {
20
+ const projectRoot = props.projectRoot ?? process.cwd();
21
+
22
+ const nodeJsCompatMode = getNodeJSCompatMode(
23
+ props.compatibilityDate,
24
+ props.compatibilityFlags,
25
+ );
26
+
27
+ if (nodeJsCompatMode === "v1") {
28
+ throw new Error(
29
+ "You must set your compatibilty date >= 2024-09-23 when using 'nodejs_compat' compatibility flag",
30
+ );
31
+ }
32
+
33
+ try {
34
+ const bundle = await Bundle("bundle", {
35
+ entryPoint: props.entrypoint!,
36
+ format: props.format === "cjs" ? "cjs" : "esm", // Use the specified format or default to ESM
37
+ target: "esnext",
38
+ platform: "node",
39
+ minify: false,
40
+ ...(props.bundle || {}),
41
+ conditions: ["workerd", "worker", "browser"],
42
+ options: {
43
+ absWorkingDir: projectRoot,
44
+ ...(props.bundle?.options || {}),
45
+ keepNames: true, // Important for Durable Object classes
46
+ loader: {
47
+ ".sql": "text",
48
+ ".json": "json",
49
+ },
50
+ plugins: [
51
+ ...(nodeJsCompatMode === "v2" ? [await nodeJsCompatPlugin()] : []),
52
+ ...(props.bundle?.alias
53
+ ? [
54
+ createAliasPlugin({
55
+ alias: props.bundle?.alias,
56
+ projectRoot,
57
+ }),
58
+ ]
59
+ : []),
60
+ ],
61
+ },
62
+ external: [
63
+ ...(nodeJsCompatMode === "als" ? external_als : external),
64
+ ...(props.bundle?.external ?? []),
65
+ ...(props.bundle?.options?.external ?? []),
66
+ ],
67
+ });
68
+ if (bundle.content) {
69
+ return bundle.content;
70
+ }
71
+ if (bundle.path) {
72
+ return await fs.readFile(bundle.path, "utf-8");
73
+ }
74
+ throw new Error("Failed to create bundle");
75
+ } catch (e: any) {
76
+ if (e.message?.includes("No such module 'node:")) {
77
+ throw new Error(
78
+ `${e.message}.\nMake sure to set 'nodejs_compat' compatibility flag and compatibilityDate > 2024-09-23`,
79
+ { cause: e },
80
+ );
81
+ }
82
+ if (isBuildFailure(e)) {
83
+ rewriteNodeCompatBuildFailure(e.errors, nodeJsCompatMode);
84
+ throw e;
85
+ }
86
+ console.error("Error reading bundle:", e);
87
+ throw new Error("Error reading bundle");
88
+ }
89
+ }
@@ -5,13 +5,14 @@ const nodejs_compat = [
5
5
  "node:buffer",
6
6
  "node:console",
7
7
  "node:crypto",
8
+ "node:debug",
8
9
  "node:diagnostics_channel",
9
10
  "node:dns",
10
11
  "node:events",
11
12
  "node:inspector",
12
13
  "node:net",
13
14
  "node:path",
14
- "node:perf_hooks",
15
+ "node:perf_hooks", // partially supported
15
16
  "node:process",
16
17
  "node:querystring",
17
18
  "node:stream",
@@ -30,3 +31,10 @@ export const external = [
30
31
  "cloudflare:workers",
31
32
  // "cloudflare:*",
32
33
  ];
34
+
35
+ export const external_als = [
36
+ //
37
+ "node:async_hooks",
38
+ "async_hooks",
39
+ "cloudflare:*",
40
+ ];
@@ -1,3 +1,5 @@
1
+ import { dedent } from "../../util/dedent.js";
2
+
1
3
  /**
2
4
  * TanStackStart server functions and middleware run in Node.js intead of Miniflare when using `vite dev`.
3
5
  *
@@ -13,12 +15,11 @@ export function cloudflareWorkersDevEnvironmentShim() {
13
15
  },
14
16
  load(id: string) {
15
17
  if (id === "cloudflare:workers")
16
- return `
17
- import { getPlatformProxy } from "wrangler";
18
- // TODO: should we export default cloudflare; ??
19
- const cloudflare = await getPlatformProxy();
20
- export const env = cloudflare.env;
21
- `;
18
+ return dedent`
19
+ import { getPlatformProxy } from "wrangler";
20
+ // TODO: should we export default cloudflare; ??
21
+ const cloudflare = await getPlatformProxy();
22
+ export const env = cloudflare.env;`;
22
23
  },
23
24
  } as const;
24
25
  }
@@ -0,0 +1,49 @@
1
+ import type { NodeJSCompatMode } from "miniflare";
2
+ import { getNodeCompat } from "miniflare";
3
+
4
+ /**
5
+ * Computes and validates the Node.js compatibility mode we are running.
6
+ *
7
+ * NOTES:
8
+ * - The v2 mode is configured via `nodejs_compat_v2` compat flag or via `nodejs_compat` plus a compatibility date of Sept 23rd. 2024 or later.
9
+ * - See `EnvironmentInheritable` for `noBundle`.
10
+ *
11
+ * @param compatibilityDateStr The compatibility date
12
+ * @param compatibilityFlags The compatibility flags
13
+ * @param noBundle Whether to skip internal build steps and directly deploy script
14
+ *
15
+ */
16
+ export function getNodeJSCompatMode(
17
+ compatibilityDateStr: string,
18
+ compatibilityFlags: string[],
19
+ props?: {
20
+ noBundle?: boolean;
21
+ },
22
+ ): NodeJSCompatMode {
23
+ const {
24
+ mode,
25
+ hasNodejsCompatFlag,
26
+ hasNodejsCompatV2Flag,
27
+ hasExperimentalNodejsCompatV2Flag,
28
+ } = getNodeCompat(compatibilityDateStr, compatibilityFlags);
29
+
30
+ if (hasExperimentalNodejsCompatV2Flag) {
31
+ throw new Error(
32
+ "The `experimental:` prefix on `nodejs_compat_v2` is no longer valid. Please remove it and try again.",
33
+ );
34
+ }
35
+
36
+ if (hasNodejsCompatFlag && hasNodejsCompatV2Flag) {
37
+ throw new Error(
38
+ "The `nodejs_compat` and `nodejs_compat_v2` compatibility flags cannot be used in together. Please select just one.",
39
+ );
40
+ }
41
+
42
+ if (props?.noBundle && hasNodejsCompatV2Flag) {
43
+ console.warn(
44
+ "`nodejs_compat_v2` compatibility flag and `--no-bundle` can't be used together. If you want to polyfill Node.js built-ins and disable Wrangler's bundling, please polyfill as part of your own bundling process.",
45
+ );
46
+ }
47
+
48
+ return mode;
49
+ }