alchemy 0.1.18 → 0.2.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.
Files changed (330) hide show
  1. package/README.md +506 -0
  2. package/lib/alchemy.d.ts +67 -0
  3. package/lib/alchemy.js +48 -0
  4. package/lib/apply.d.ts +3 -20
  5. package/lib/apply.js +95 -82
  6. package/lib/aws/account-id.d.ts +0 -1
  7. package/lib/aws/account-id.js +0 -1
  8. package/lib/aws/bucket.d.ts +4 -7
  9. package/lib/aws/bucket.js +8 -12
  10. package/lib/aws/function.d.ts +4 -7
  11. package/lib/aws/function.js +9 -30
  12. package/lib/aws/index.d.ts +1 -1
  13. package/lib/aws/index.js +1 -1
  14. package/lib/aws/oidc/github-oidc-provider.d.ts +2 -6
  15. package/lib/aws/oidc/github-oidc-provider.js +10 -15
  16. package/lib/aws/oidc/index.d.ts +0 -1
  17. package/lib/aws/oidc/index.js +0 -1
  18. package/lib/aws/oidc/oidc-provider.d.ts +4 -6
  19. package/lib/aws/oidc/oidc-provider.js +9 -11
  20. package/lib/aws/policy-attachment.d.ts +9 -0
  21. package/lib/aws/policy-attachment.js +20 -0
  22. package/lib/aws/policy.d.ts +4 -16
  23. package/lib/aws/policy.js +9 -40
  24. package/lib/aws/queue.d.ts +4 -34
  25. package/lib/aws/queue.js +10 -20
  26. package/lib/aws/role.d.ts +4 -7
  27. package/lib/aws/role.js +17 -26
  28. package/lib/aws/ses.d.ts +4 -10
  29. package/lib/aws/ses.js +118 -131
  30. package/lib/aws/table.d.ts +4 -7
  31. package/lib/aws/table.js +8 -11
  32. package/lib/cloudflare/api.d.ts +0 -1
  33. package/lib/cloudflare/api.js +0 -1
  34. package/lib/cloudflare/asset-manifest.d.ts +0 -1
  35. package/lib/cloudflare/asset-manifest.js +0 -1
  36. package/lib/cloudflare/auth.d.ts +0 -1
  37. package/lib/cloudflare/auth.js +0 -1
  38. package/lib/cloudflare/bindings.d.ts +1 -1
  39. package/lib/cloudflare/bindings.js +3 -2
  40. package/lib/cloudflare/bound.d.ts +0 -1
  41. package/lib/cloudflare/bound.js +0 -1
  42. package/lib/cloudflare/bucket.d.ts +7 -15
  43. package/lib/cloudflare/bucket.js +12 -19
  44. package/lib/cloudflare/durable-object-namespace.d.ts +0 -3
  45. package/lib/cloudflare/durable-object-namespace.js +0 -4
  46. package/lib/cloudflare/generate-asset-manifest.d.ts +0 -1
  47. package/lib/cloudflare/generate-asset-manifest.js +1 -2
  48. package/lib/cloudflare/index.d.ts +2 -1
  49. package/lib/cloudflare/index.js +2 -1
  50. package/lib/cloudflare/kv-namespace.d.ts +6 -9
  51. package/lib/cloudflare/kv-namespace.js +16 -20
  52. package/lib/cloudflare/state.d.ts +0 -1
  53. package/lib/cloudflare/state.js +0 -1
  54. package/lib/cloudflare/static-site-router.d.ts +0 -1
  55. package/lib/cloudflare/static-site-router.js +0 -4
  56. package/lib/cloudflare/static-site.d.ts +5 -11
  57. package/lib/cloudflare/static-site.js +25 -37
  58. package/lib/cloudflare/types.d.ts +0 -1
  59. package/lib/cloudflare/types.js +0 -1
  60. package/lib/cloudflare/upload-asset-manifest.d.ts +0 -1
  61. package/lib/cloudflare/upload-asset-manifest.js +0 -1
  62. package/lib/cloudflare/worker-metadata.d.ts +0 -1
  63. package/lib/cloudflare/worker-metadata.js +0 -1
  64. package/lib/cloudflare/worker-migration.d.ts +0 -1
  65. package/lib/cloudflare/worker-migration.js +0 -1
  66. package/lib/cloudflare/worker.d.ts +8 -14
  67. package/lib/cloudflare/worker.js +38 -50
  68. package/lib/cloudflare/wrangler.json.d.ts +243 -0
  69. package/lib/cloudflare/wrangler.json.js +35 -0
  70. package/lib/cloudflare/zone-settings.d.ts +301 -0
  71. package/lib/cloudflare/zone-settings.js +1 -0
  72. package/lib/cloudflare/zone.d.ts +196 -0
  73. package/lib/cloudflare/zone.js +175 -0
  74. package/lib/context.d.ts +58 -0
  75. package/lib/context.js +36 -0
  76. package/lib/destroy.d.ts +10 -13
  77. package/lib/destroy.js +104 -43
  78. package/lib/{esbuild.d.ts → esbuild/bundle.d.ts} +4 -18
  79. package/lib/{esbuild.js → esbuild/bundle.js} +10 -24
  80. package/lib/esbuild/index.d.ts +1 -0
  81. package/lib/esbuild/index.js +1 -0
  82. package/lib/fs/file.d.ts +13 -0
  83. package/lib/fs/file.js +20 -0
  84. package/lib/fs/folder.d.ts +10 -0
  85. package/lib/fs/folder.js +16 -0
  86. package/lib/fs/index.d.ts +2 -0
  87. package/lib/fs/index.js +2 -0
  88. package/lib/github/client.d.ts +0 -1
  89. package/lib/github/client.js +0 -1
  90. package/lib/github/index.d.ts +0 -1
  91. package/lib/github/index.js +0 -1
  92. package/lib/github/secret.d.ts +4 -6
  93. package/lib/github/secret.js +10 -12
  94. package/lib/index.d.ts +6 -10
  95. package/lib/index.js +5 -9
  96. package/lib/project/index.d.ts +1 -0
  97. package/lib/project/index.js +1 -0
  98. package/lib/project/vite.d.ts +39 -0
  99. package/lib/project/vite.js +68 -0
  100. package/lib/resource.d.ts +34 -62
  101. package/lib/resource.js +29 -270
  102. package/lib/scope.d.ts +37 -14
  103. package/lib/scope.js +97 -23
  104. package/lib/secret.d.ts +2 -7
  105. package/lib/secret.js +7 -20
  106. package/lib/state.d.ts +14 -10
  107. package/lib/state.js +20 -14
  108. package/lib/stripe/index.d.ts +0 -1
  109. package/lib/stripe/index.js +0 -1
  110. package/lib/stripe/price.d.ts +4 -5
  111. package/lib/stripe/price.js +10 -20
  112. package/lib/stripe/product.d.ts +4 -5
  113. package/lib/stripe/product.js +10 -20
  114. package/lib/stripe/webhook.d.ts +4 -6
  115. package/lib/stripe/webhook.js +12 -25
  116. package/lib/test/bun.d.ts +19 -0
  117. package/lib/test/bun.js +55 -0
  118. package/lib/{utils → util}/content-type.d.ts +0 -1
  119. package/lib/{utils → util}/content-type.js +0 -1
  120. package/lib/{encrypt.d.ts → util/encrypt.d.ts} +0 -1
  121. package/lib/{encrypt.js → util/encrypt.js} +0 -1
  122. package/lib/{error.d.ts → util/ignore.d.ts} +0 -1
  123. package/lib/{error.js → util/ignore.js} +0 -1
  124. package/lib/{utils → util}/retry.d.ts +0 -1
  125. package/lib/{utils → util}/retry.js +0 -1
  126. package/lib/util/rm.d.ts +1 -0
  127. package/lib/util/rm.js +11 -0
  128. package/lib/util/serde.d.ts +3 -0
  129. package/lib/{serde.js → util/serde.js} +19 -10
  130. package/lib/util/slugify.d.ts +1 -0
  131. package/lib/util/slugify.js +3 -0
  132. package/package.json +7 -5
  133. package/src/alchemy.ts +127 -0
  134. package/src/apply.ts +116 -115
  135. package/src/aws/bucket.ts +11 -14
  136. package/src/aws/function.ts +13 -33
  137. package/src/aws/index.ts +1 -0
  138. package/src/aws/oidc/github-oidc-provider.ts +14 -19
  139. package/src/aws/oidc/oidc-provider.ts +19 -12
  140. package/src/aws/policy-attachment.ts +51 -0
  141. package/src/aws/policy.ts +15 -60
  142. package/src/aws/queue.ts +17 -21
  143. package/src/aws/role.ts +25 -28
  144. package/src/aws/ses.ts +150 -164
  145. package/src/aws/table.ts +15 -15
  146. package/src/cloudflare/bindings.ts +8 -0
  147. package/src/cloudflare/bucket.ts +39 -47
  148. package/src/cloudflare/durable-object-namespace.ts +0 -10
  149. package/src/cloudflare/generate-asset-manifest.ts +1 -1
  150. package/src/cloudflare/index.ts +2 -0
  151. package/src/cloudflare/kv-namespace.ts +35 -33
  152. package/src/cloudflare/static-site-router.ts +0 -3
  153. package/src/cloudflare/static-site.ts +55 -71
  154. package/src/cloudflare/worker.ts +106 -112
  155. package/src/cloudflare/wrangler.json.ts +309 -0
  156. package/src/cloudflare/zone-settings.ts +368 -0
  157. package/src/cloudflare/zone.ts +491 -0
  158. package/src/context.ts +122 -0
  159. package/src/destroy.ts +124 -73
  160. package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
  161. package/src/esbuild/index.ts +1 -0
  162. package/src/fs/file.ts +39 -0
  163. package/src/fs/folder.ts +32 -0
  164. package/src/fs/index.ts +2 -0
  165. package/src/github/secret.ts +19 -16
  166. package/src/index.ts +7 -15
  167. package/src/project/index.ts +1 -0
  168. package/src/project/vite.ts +152 -0
  169. package/src/resource.ts +101 -462
  170. package/src/scope.ts +125 -36
  171. package/src/secret.ts +9 -32
  172. package/src/state.ts +38 -21
  173. package/src/stripe/price.ts +17 -22
  174. package/src/stripe/product.ts +17 -22
  175. package/src/stripe/webhook.ts +21 -27
  176. package/src/test/bun.ts +105 -0
  177. package/src/util/rm.ts +11 -0
  178. package/src/util/serde.ts +53 -0
  179. package/src/util/slugify.ts +3 -0
  180. package/lib/$.d.ts +0 -12
  181. package/lib/$.d.ts.map +0 -1
  182. package/lib/$.js +0 -42
  183. package/lib/$.js.map +0 -1
  184. package/lib/alchemize.d.ts +0 -47
  185. package/lib/alchemize.d.ts.map +0 -1
  186. package/lib/alchemize.js +0 -116
  187. package/lib/alchemize.js.map +0 -1
  188. package/lib/apply.d.ts.map +0 -1
  189. package/lib/apply.js.map +0 -1
  190. package/lib/aws/account-id.d.ts.map +0 -1
  191. package/lib/aws/account-id.js.map +0 -1
  192. package/lib/aws/bucket.d.ts.map +0 -1
  193. package/lib/aws/bucket.js.map +0 -1
  194. package/lib/aws/function.d.ts.map +0 -1
  195. package/lib/aws/function.js.map +0 -1
  196. package/lib/aws/index.d.ts.map +0 -1
  197. package/lib/aws/index.js.map +0 -1
  198. package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
  199. package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
  200. package/lib/aws/oidc/index.d.ts.map +0 -1
  201. package/lib/aws/oidc/index.js.map +0 -1
  202. package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
  203. package/lib/aws/oidc/oidc-provider.js.map +0 -1
  204. package/lib/aws/policy.d.ts.map +0 -1
  205. package/lib/aws/policy.js.map +0 -1
  206. package/lib/aws/queue.d.ts.map +0 -1
  207. package/lib/aws/queue.js.map +0 -1
  208. package/lib/aws/role.d.ts.map +0 -1
  209. package/lib/aws/role.js.map +0 -1
  210. package/lib/aws/ses.d.ts.map +0 -1
  211. package/lib/aws/ses.js.map +0 -1
  212. package/lib/aws/table.d.ts.map +0 -1
  213. package/lib/aws/table.js.map +0 -1
  214. package/lib/cloudflare/api.d.ts.map +0 -1
  215. package/lib/cloudflare/api.js.map +0 -1
  216. package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
  217. package/lib/cloudflare/asset-manifest.js.map +0 -1
  218. package/lib/cloudflare/auth.d.ts.map +0 -1
  219. package/lib/cloudflare/auth.js.map +0 -1
  220. package/lib/cloudflare/bindings.d.ts.map +0 -1
  221. package/lib/cloudflare/bindings.js.map +0 -1
  222. package/lib/cloudflare/bound.d.ts.map +0 -1
  223. package/lib/cloudflare/bound.js.map +0 -1
  224. package/lib/cloudflare/bucket.d.ts.map +0 -1
  225. package/lib/cloudflare/bucket.js.map +0 -1
  226. package/lib/cloudflare/durable-object-namespace.d.ts.map +0 -1
  227. package/lib/cloudflare/durable-object-namespace.js.map +0 -1
  228. package/lib/cloudflare/generate-asset-manifest.d.ts.map +0 -1
  229. package/lib/cloudflare/generate-asset-manifest.js.map +0 -1
  230. package/lib/cloudflare/index.d.ts.map +0 -1
  231. package/lib/cloudflare/index.js.map +0 -1
  232. package/lib/cloudflare/kv-namespace.d.ts.map +0 -1
  233. package/lib/cloudflare/kv-namespace.js.map +0 -1
  234. package/lib/cloudflare/state.d.ts.map +0 -1
  235. package/lib/cloudflare/state.js.map +0 -1
  236. package/lib/cloudflare/static-site-router.d.ts.map +0 -1
  237. package/lib/cloudflare/static-site-router.js.map +0 -1
  238. package/lib/cloudflare/static-site.d.ts.map +0 -1
  239. package/lib/cloudflare/static-site.js.map +0 -1
  240. package/lib/cloudflare/types.d.ts.map +0 -1
  241. package/lib/cloudflare/types.js.map +0 -1
  242. package/lib/cloudflare/upload-asset-manifest.d.ts.map +0 -1
  243. package/lib/cloudflare/upload-asset-manifest.js.map +0 -1
  244. package/lib/cloudflare/worker-metadata.d.ts.map +0 -1
  245. package/lib/cloudflare/worker-metadata.js.map +0 -1
  246. package/lib/cloudflare/worker-migration.d.ts.map +0 -1
  247. package/lib/cloudflare/worker-migration.js.map +0 -1
  248. package/lib/cloudflare/worker.d.ts.map +0 -1
  249. package/lib/cloudflare/worker.js.map +0 -1
  250. package/lib/destroy.d.ts.map +0 -1
  251. package/lib/destroy.js.map +0 -1
  252. package/lib/encrypt.d.ts.map +0 -1
  253. package/lib/encrypt.js.map +0 -1
  254. package/lib/error.d.ts.map +0 -1
  255. package/lib/error.js.map +0 -1
  256. package/lib/esbuild.d.ts.map +0 -1
  257. package/lib/esbuild.js.map +0 -1
  258. package/lib/fs.d.ts +0 -12
  259. package/lib/fs.d.ts.map +0 -1
  260. package/lib/fs.js +0 -41
  261. package/lib/fs.js.map +0 -1
  262. package/lib/github/client.d.ts.map +0 -1
  263. package/lib/github/client.js.map +0 -1
  264. package/lib/github/index.d.ts.map +0 -1
  265. package/lib/github/index.js.map +0 -1
  266. package/lib/github/secret.d.ts.map +0 -1
  267. package/lib/github/secret.js.map +0 -1
  268. package/lib/global.d.ts +0 -16
  269. package/lib/global.d.ts.map +0 -1
  270. package/lib/global.js +0 -42
  271. package/lib/global.js.map +0 -1
  272. package/lib/index.d.ts.map +0 -1
  273. package/lib/index.js.map +0 -1
  274. package/lib/input.d.ts +0 -7
  275. package/lib/input.d.ts.map +0 -1
  276. package/lib/input.js +0 -2
  277. package/lib/input.js.map +0 -1
  278. package/lib/main.d.ts +0 -3
  279. package/lib/main.d.ts.map +0 -1
  280. package/lib/main.js +0 -32
  281. package/lib/main.js.map +0 -1
  282. package/lib/output.d.ts +0 -25
  283. package/lib/output.d.ts.map +0 -1
  284. package/lib/output.js +0 -23
  285. package/lib/output.js.map +0 -1
  286. package/lib/print.d.ts +0 -7
  287. package/lib/print.d.ts.map +0 -1
  288. package/lib/print.js +0 -10
  289. package/lib/print.js.map +0 -1
  290. package/lib/resource.d.ts.map +0 -1
  291. package/lib/resource.js.map +0 -1
  292. package/lib/scope.d.ts.map +0 -1
  293. package/lib/scope.js.map +0 -1
  294. package/lib/secret.d.ts.map +0 -1
  295. package/lib/secret.js.map +0 -1
  296. package/lib/serde.d.ts +0 -3
  297. package/lib/serde.d.ts.map +0 -1
  298. package/lib/serde.js.map +0 -1
  299. package/lib/slug.d.ts +0 -2
  300. package/lib/slug.d.ts.map +0 -1
  301. package/lib/slug.js +0 -4
  302. package/lib/slug.js.map +0 -1
  303. package/lib/state.d.ts.map +0 -1
  304. package/lib/state.js.map +0 -1
  305. package/lib/stripe/index.d.ts.map +0 -1
  306. package/lib/stripe/index.js.map +0 -1
  307. package/lib/stripe/price.d.ts.map +0 -1
  308. package/lib/stripe/price.js.map +0 -1
  309. package/lib/stripe/product.d.ts.map +0 -1
  310. package/lib/stripe/product.js.map +0 -1
  311. package/lib/stripe/webhook.d.ts.map +0 -1
  312. package/lib/stripe/webhook.js.map +0 -1
  313. package/lib/utils/content-type.d.ts.map +0 -1
  314. package/lib/utils/content-type.js.map +0 -1
  315. package/lib/utils/retry.d.ts.map +0 -1
  316. package/lib/utils/retry.js.map +0 -1
  317. package/src/$.ts +0 -69
  318. package/src/alchemize.ts +0 -195
  319. package/src/fs.ts +0 -47
  320. package/src/global.ts +0 -63
  321. package/src/input.ts +0 -19
  322. package/src/main.ts +0 -34
  323. package/src/output.ts +0 -75
  324. package/src/print.ts +0 -18
  325. package/src/serde.ts +0 -46
  326. package/src/slug.ts +0 -3
  327. /package/src/{utils → util}/content-type.ts +0 -0
  328. /package/src/{encrypt.ts → util/encrypt.ts} +0 -0
  329. /package/src/{error.ts → util/ignore.ts} +0 -0
  330. /package/src/{utils → util}/retry.ts +0 -0
@@ -1,17 +1,18 @@
1
1
  import * as fs from "fs/promises";
2
- import { apply } from "../apply";
3
- import { Bundle, type BundleProps } from "../esbuild";
4
- import type { Input } from "../input";
5
- import type { Resolved } from "../output";
6
- import { type Context, Resource } from "../resource";
7
- import { Secret } from "../secret";
8
- import { withExponentialBackoff } from "../utils/retry";
2
+ import type { Context } from "../context";
3
+ import { Bundle, type BundleProps } from "../esbuild/bundle";
4
+ import { Resource } from "../resource";
5
+ import { isSecret } from "../secret";
6
+ import { withExponentialBackoff } from "../util/retry";
7
+ import { slugify } from "../util/slugify";
9
8
  import { type CloudflareApi, createCloudflareApi } from "./api";
10
- import type { Bindings, WorkerBindingSpec } from "./bindings";
9
+ import {
10
+ type Bindings,
11
+ type WorkerBindingSpec,
12
+ isDurableObjectNamespace,
13
+ } from "./bindings";
11
14
  import type { Bound } from "./bound";
12
- import { isBucket } from "./bucket";
13
15
  import type { DurableObjectNamespace } from "./durable-object-namespace";
14
- import { isDurableObjectNamespace } from "./durable-object-namespace";
15
16
  import { isKVNamespace } from "./kv-namespace";
16
17
  import type { WorkerScriptMetadata } from "./worker-metadata";
17
18
  import type { SingleStepMigration } from "./worker-migration";
@@ -100,8 +101,9 @@ export interface WorkerProps<B extends Bindings = Bindings> {
100
101
  /**
101
102
  * Output returned after Worker creation/update
102
103
  */
103
- export interface WorkerOutput<B extends Bindings = Bindings>
104
- extends Omit<WorkerProps<B>, "url"> {
104
+ export interface Worker<B extends Bindings = Bindings>
105
+ extends Resource<"cloudflare::Worker">,
106
+ Omit<WorkerProps<B>, "url"> {
105
107
  type: "service";
106
108
 
107
109
  /**
@@ -128,94 +130,95 @@ export interface WorkerOutput<B extends Bindings = Bindings>
128
130
  /**
129
131
  * The bindings that were created
130
132
  */
131
- bindings: B;
132
- }
133
+ bindings: B | undefined;
133
134
 
134
- export function isWorker(resource: any): resource is Resolved<Worker> {
135
- return resource && typeof resource === "object" && resource.type === "worker";
135
+ // phantom property (for typeof myWorker.Env)
136
+ Env: {
137
+ [bindingName in keyof B]: Bound<B[bindingName]>;
138
+ };
136
139
  }
137
140
 
138
- export class Worker<B extends Bindings = Bindings> extends Resource(
141
+ export const Worker = Resource(
139
142
  "cloudflare::Worker",
140
143
  {
141
144
  alwaysUpdate: true,
142
145
  },
143
- applyWorker,
144
- ) {
145
- public declare readonly Env: {
146
- [bindingName in keyof B]: Bound<B[bindingName]>;
147
- };
148
- constructor(id: string, input: Input<WorkerProps<B>>, ...inputs: any[]) {
149
- super(id, input as any, ...inputs);
150
- }
151
- }
152
-
153
- async function applyWorker(ctx: Context<WorkerOutput>, props: WorkerProps) {
154
- // Create Cloudflare API client with automatic account discovery
155
- const api = await createCloudflareApi();
156
-
157
- // Use the provided name
158
- const workerName = props.name;
159
-
160
- // Validate input - we need either script, entryPoint, or bundle
161
- if (!props.script && !props.entrypoint) {
162
- throw new Error("One of script or entryPoint must be provided");
163
- }
164
-
165
- if (ctx.event === "delete") {
166
- return deleteWorker(ctx, api, workerName);
167
- } else if (ctx.event === "create") {
168
- await assertWorkerDoesNotExist(ctx, api, workerName);
169
- }
146
+ async function <const B extends Bindings>(
147
+ this: Context<Worker<NoInfer<B>>>,
148
+ id: string,
149
+ props: WorkerProps<B>,
150
+ ): Promise<Worker<B>> {
151
+ // Create Cloudflare API client with automatic account discovery
152
+ const api = await createCloudflareApi();
153
+
154
+ // Use the provided name
155
+ const workerName = props.name;
156
+
157
+ // Validate input - we need either script, entryPoint, or bundle
158
+ if (!props.script && !props.entrypoint) {
159
+ throw new Error("One of script or entryPoint must be provided");
160
+ }
170
161
 
171
- const oldBindings = await ctx.get<Bindings>("bindings");
162
+ if (this.phase === "delete") {
163
+ await deleteWorker(this, api, workerName);
164
+ return this.destroy();
165
+ } else if (this.phase === "create") {
166
+ await assertWorkerDoesNotExist(this, api, workerName);
167
+ }
172
168
 
173
- const scriptMetadata = await prepareWorkerMetadata(ctx, oldBindings, props);
169
+ const oldBindings = await this.get<Bindings>("bindings");
174
170
 
175
- // Get the script content - either from props.script, or by bundling
176
- const scriptContent = props.script ?? (await bundleWorkerScript(ctx, props));
171
+ const scriptMetadata = await prepareWorkerMetadata(
172
+ this,
173
+ oldBindings,
174
+ props,
175
+ );
177
176
 
178
- // Upload the worker script
179
- await putWorker(ctx, api, workerName, scriptContent, scriptMetadata);
177
+ // Get the script content - either from props.script, or by bundling
178
+ const scriptContent = props.script ?? (await bundleWorkerScript(props));
180
179
 
181
- // TODO: it is less than ideal that this can fail, resulting in state problem
182
- await ctx.set("bindings", props.bindings);
180
+ // Upload the worker script
181
+ await putWorker(api, workerName, scriptContent, scriptMetadata);
183
182
 
184
- // Handle routes if requested
185
- await setupRoutes(api, workerName, props.routes || []);
183
+ // TODO: it is less than ideal that this can fail, resulting in state problem
184
+ await this.set("bindings", props.bindings);
186
185
 
187
- // Handle worker URL if requested
188
- const workerUrl = await configureURL(
189
- ctx,
190
- api,
191
- workerName,
192
- props.url ?? false,
193
- );
186
+ // Handle routes if requested
187
+ await setupRoutes(api, workerName, props.routes || []);
194
188
 
195
- // Get current timestamp
196
- const now = Date.now();
197
-
198
- // Construct the output
199
- const output: WorkerOutput = {
200
- type: "service",
201
- id: workerName,
202
- name: workerName,
203
- script: scriptContent,
204
- format: props.format || "esm", // Include format in the output
205
- routes: props.routes || [],
206
- bindings: props.bindings ?? {},
207
- env: props.env,
208
- observability: scriptMetadata.observability,
209
- createdAt: now,
210
- updatedAt: now,
211
- url: workerUrl,
212
- };
189
+ // Handle worker URL if requested
190
+ const workerUrl = await configureURL(
191
+ this,
192
+ api,
193
+ workerName,
194
+ props.url ?? false,
195
+ );
213
196
 
214
- return output;
215
- }
197
+ // Get current timestamp
198
+ const now = Date.now();
199
+
200
+ // Construct the output
201
+ return this({
202
+ type: "service",
203
+ id,
204
+ name: workerName,
205
+ script: scriptContent,
206
+ format: props.format || "esm", // Include format in the output
207
+ routes: props.routes || [],
208
+ bindings: props.bindings ?? ({} as B),
209
+ env: props.env,
210
+ observability: scriptMetadata.observability,
211
+ createdAt: now,
212
+ updatedAt: now,
213
+ url: workerUrl,
214
+ // phantom property
215
+ Env: undefined!,
216
+ });
217
+ },
218
+ );
216
219
 
217
- async function deleteWorker(
218
- ctx: Context<WorkerOutput>,
220
+ async function deleteWorker<B extends Bindings>(
221
+ ctx: Context<Worker<B>>,
219
222
  api: CloudflareApi,
220
223
  workerName: string,
221
224
  ) {
@@ -284,7 +287,6 @@ async function deleteWorker(
284
287
  }
285
288
 
286
289
  async function putWorker(
287
- ctx: Context<WorkerOutput>,
288
290
  api: CloudflareApi,
289
291
  workerName: string,
290
292
  scriptContent: string,
@@ -309,8 +311,6 @@ async function putWorker(
309
311
  scriptName,
310
312
  );
311
313
 
312
- // console.log("Script Metadata:", JSON.stringify(scriptMetadata, null, 2));
313
-
314
314
  // Add metadata as JSON
315
315
  formData.append(
316
316
  "metadata",
@@ -375,8 +375,8 @@ interface WorkerMetadata {
375
375
  tags?: string[];
376
376
  }
377
377
 
378
- async function prepareWorkerMetadata(
379
- ctx: Context<WorkerOutput>,
378
+ async function prepareWorkerMetadata<B extends Bindings>(
379
+ ctx: Context<Worker<B>>,
380
380
  oldBindings: Bindings | undefined,
381
381
  props: WorkerProps,
382
382
  ): Promise<WorkerMetadata> {
@@ -386,7 +386,8 @@ async function prepareWorkerMetadata(
386
386
  observability: {
387
387
  enabled: props.observability?.enabled !== false,
388
388
  },
389
- tags: [`alchemy:id:${ctx.resourceFQN}`],
389
+ // TODO(sam): base64 encode instead? 0 collision risk vs readability.
390
+ tags: [`alchemy:id:${slugify(ctx.fqn)}`],
390
391
  migrations: {
391
392
  new_classes: props.migrations?.new_classes ?? [],
392
393
  deleted_classes: props.migrations?.deleted_classes ?? [],
@@ -396,7 +397,7 @@ async function prepareWorkerMetadata(
396
397
  },
397
398
  };
398
399
 
399
- const bindings = (props.bindings ?? {}) as Resolved<Bindings>;
400
+ const bindings = (props.bindings ?? {}) as Bindings;
400
401
 
401
402
  // Convert bindings to the format expected by the API
402
403
  for (const [bindingName, binding] of Object.entries(bindings)) {
@@ -406,7 +407,7 @@ async function prepareWorkerMetadata(
406
407
  meta.bindings.push({
407
408
  type: "kv_namespace",
408
409
  name: bindingName,
409
- namespace_id: binding.id,
410
+ namespace_id: binding.namespaceId,
410
411
  });
411
412
  } else if (typeof binding === "string") {
412
413
  meta.bindings.push({
@@ -420,7 +421,7 @@ async function prepareWorkerMetadata(
420
421
  name: bindingName,
421
422
  service: binding.id,
422
423
  });
423
- } else if (isDurableObjectNamespace(binding)) {
424
+ } else if (binding.type === "durable_object_namespace") {
424
425
  const stableId = binding.id;
425
426
  const className = binding.className;
426
427
 
@@ -451,13 +452,13 @@ async function prepareWorkerMetadata(
451
452
  to: className,
452
453
  });
453
454
  }
454
- } else if (isBucket(binding)) {
455
+ } else if (binding.type === "r2_bucket") {
455
456
  meta.bindings.push({
456
457
  type: "r2_bucket",
457
458
  name: bindingName,
458
- bucket_name: binding.name || binding.id,
459
+ bucket_name: binding.name,
459
460
  });
460
- } else if (binding instanceof Secret) {
461
+ } else if (isSecret(binding)) {
461
462
  meta.bindings.push({
462
463
  type: "secret_text",
463
464
  name: bindingName,
@@ -494,8 +495,8 @@ async function prepareWorkerMetadata(
494
495
  return meta;
495
496
  }
496
497
 
497
- async function assertWorkerDoesNotExist(
498
- ctx: Context<WorkerOutput>,
498
+ async function assertWorkerDoesNotExist<B extends Bindings>(
499
+ ctx: Context<Worker<B>>,
499
500
  api: CloudflareApi,
500
501
  workerName: string,
501
502
  ) {
@@ -516,7 +517,7 @@ async function assertWorkerDoesNotExist(
516
517
 
517
518
  if (
518
519
  metadata.default_environment?.script.tags.includes(
519
- `alchemy:id:${ctx.resourceFQN}`,
520
+ `alchemy:id:${slugify(ctx.fqn)}`,
520
521
  )
521
522
  ) {
522
523
  return true;
@@ -527,15 +528,12 @@ async function assertWorkerDoesNotExist(
527
528
  );
528
529
  } else {
529
530
  throw new Error(
530
- `Error checking if worker exists: ${response.status} ${response.statusText}`,
531
+ `Error checking if worker exists: ${response.status} ${response.statusText} ${await response.text()}`,
531
532
  );
532
533
  }
533
534
  }
534
535
 
535
- async function bundleWorkerScript(
536
- ctx: Context<WorkerOutput>,
537
- props: WorkerProps,
538
- ) {
536
+ async function bundleWorkerScript<B extends Bindings>(props: WorkerProps) {
539
537
  // Get the script content - either from props.script, or by bundling
540
538
 
541
539
  // Create and use a Bundle resource with worker-optimized configuration
@@ -556,18 +554,14 @@ async function bundleWorkerScript(
556
554
  };
557
555
 
558
556
  // Create the bundle
559
- const bundle = new Bundle("bundle", {
557
+ const bundle = await Bundle("bundle", {
560
558
  entryPoint: props.entrypoint!,
561
559
  ...bundleOptions,
562
560
  external: [...(bundleOptions.external ?? []), "cloudflare:workers"],
563
561
  });
564
562
 
565
- // Get the bundled content
566
- const bundleOutput = await apply(bundle, {
567
- quiet: ctx.quiet,
568
- });
569
563
  try {
570
- return await fs.readFile(bundleOutput.path, "utf-8");
564
+ return await fs.readFile(bundle.path, "utf-8");
571
565
  } catch (error) {
572
566
  console.error("Error reading bundle:", error);
573
567
  throw new Error("Error reading bundle");
@@ -635,8 +629,8 @@ async function setupRoutes(
635
629
  }
636
630
  }
637
631
 
638
- async function configureURL(
639
- ctx: Context<WorkerOutput>,
632
+ async function configureURL<B extends Bindings>(
633
+ ctx: Context<Worker<B>>,
640
634
  api: CloudflareApi,
641
635
  workerName: string,
642
636
  url: boolean,
@@ -675,7 +669,7 @@ async function configureURL(
675
669
  // Add a delay when the subdomain is first created.
676
670
  // This is to prevent an issue where a negative cache-hit
677
671
  // causes the subdomain to be unavailable for 30 seconds.
678
- if (ctx.event === "create" || !ctx.output?.url) {
672
+ if (ctx.phase === "create" || !ctx.output?.url) {
679
673
  await new Promise((resolve) => setTimeout(resolve, 3000));
680
674
  }
681
675
  }
@@ -0,0 +1,309 @@
1
+ import * as fs from "fs/promises";
2
+ import type { Context } from "../context";
3
+ import { Resource } from "../resource";
4
+
5
+ /**
6
+ * Properties for wrangler.json configuration file
7
+ */
8
+ export interface WranglerJsonProps {
9
+ /**
10
+ * The name of your worker
11
+ */
12
+ name: string;
13
+
14
+ /**
15
+ * The directory containing your worker entry point
16
+ * @default "src"
17
+ */
18
+ main?: string;
19
+
20
+ /**
21
+ * The entry point for your worker
22
+ * @default "index.ts" or "index.js"
23
+ */
24
+ entrypoint?: string;
25
+
26
+ /**
27
+ * The directory to store build artifacts
28
+ * @default "dist"
29
+ */
30
+ outdir?: string;
31
+
32
+ /**
33
+ * The directory to serve static assets from
34
+ */
35
+ assets?: string;
36
+
37
+ /**
38
+ * Minify the worker script
39
+ * @default true
40
+ */
41
+ minify?: boolean;
42
+
43
+ /**
44
+ * Node.js compatibility mode
45
+ * @default false
46
+ */
47
+ node_compat?: boolean;
48
+
49
+ /**
50
+ * First-party worker service bindings
51
+ */
52
+ services?: Array<{
53
+ /**
54
+ * Binding name
55
+ */
56
+ name: string;
57
+ /**
58
+ * Service environment
59
+ */
60
+ environment?: string;
61
+ }>;
62
+
63
+ /**
64
+ * Worker environment variables
65
+ */
66
+ vars?: Record<string, string>;
67
+
68
+ /**
69
+ * KV Namespace bindings
70
+ */
71
+ kv_namespaces?: Array<{
72
+ /**
73
+ * Binding name
74
+ */
75
+ binding: string;
76
+ /**
77
+ * KV namespace ID
78
+ */
79
+ id: string;
80
+ /**
81
+ * Preview KV namespace ID
82
+ */
83
+ preview_id?: string;
84
+ }>;
85
+
86
+ /**
87
+ * R2 bucket bindings
88
+ */
89
+ r2_buckets?: Array<{
90
+ /**
91
+ * Binding name
92
+ */
93
+ binding: string;
94
+ /**
95
+ * Bucket name
96
+ */
97
+ bucket_name: string;
98
+ /**
99
+ * Preview bucket name
100
+ */
101
+ preview_bucket_name?: string;
102
+ }>;
103
+
104
+ /**
105
+ * D1 database bindings
106
+ */
107
+ d1_databases?: Array<{
108
+ /**
109
+ * Binding name
110
+ */
111
+ binding: string;
112
+ /**
113
+ * Database name
114
+ */
115
+ database_name: string;
116
+ /**
117
+ * Database ID
118
+ */
119
+ database_id: string;
120
+ /**
121
+ * Preview database ID
122
+ */
123
+ preview_database_id?: string;
124
+ }>;
125
+
126
+ /**
127
+ * Durable Object bindings
128
+ */
129
+ durable_objects?: {
130
+ /**
131
+ * Durable Object bindings
132
+ */
133
+ bindings: Array<{
134
+ /**
135
+ * Binding name
136
+ */
137
+ name: string;
138
+ /**
139
+ * Class name
140
+ */
141
+ class_name: string;
142
+ /**
143
+ * Script name
144
+ */
145
+ script_name?: string;
146
+ /**
147
+ * Environment name
148
+ */
149
+ environment?: string;
150
+ }>;
151
+ };
152
+
153
+ /**
154
+ * Queue bindings
155
+ */
156
+ queues?: {
157
+ /**
158
+ * Producer bindings
159
+ */
160
+ producers?: Array<{
161
+ /**
162
+ * Binding name
163
+ */
164
+ binding: string;
165
+ /**
166
+ * Queue name
167
+ */
168
+ queue: string;
169
+ }>;
170
+ /**
171
+ * Consumer configuration
172
+ */
173
+ consumers?: Array<{
174
+ /**
175
+ * Queue name
176
+ */
177
+ queue: string;
178
+ /**
179
+ * Maximum batch size
180
+ */
181
+ max_batch_size?: number;
182
+ /**
183
+ * Maximum batch timeout
184
+ */
185
+ max_batch_timeout?: number;
186
+ /**
187
+ * Maximum retries
188
+ */
189
+ max_retries?: number;
190
+ /**
191
+ * Dead letter queue
192
+ */
193
+ dead_letter_queue?: string;
194
+ }>;
195
+ };
196
+
197
+ /**
198
+ * Analytics Engine bindings
199
+ */
200
+ analytics_engine_datasets?: Array<{
201
+ /**
202
+ * Binding name
203
+ */
204
+ binding: string;
205
+ /**
206
+ * Dataset name
207
+ */
208
+ dataset?: string;
209
+ }>;
210
+
211
+ /**
212
+ * Route configuration
213
+ */
214
+ routes?: Array<string>;
215
+
216
+ /**
217
+ * Triggers configuration
218
+ */
219
+ triggers?: {
220
+ /**
221
+ * Cron triggers
222
+ */
223
+ crons: Array<string>;
224
+ };
225
+
226
+ /**
227
+ * Worker compatibility date
228
+ */
229
+ compatibility_date?: string;
230
+
231
+ /**
232
+ * Worker compatibility flags
233
+ */
234
+ compatibility_flags?: Array<string>;
235
+
236
+ /**
237
+ * Worker usage model
238
+ * "bundled" - Includes resources like CPU and memory. Better for consistent workloads.
239
+ * "unbound" - Pay only for what you use. Better for sporadic workloads.
240
+ */
241
+ usage_model?: "bundled" | "unbound";
242
+
243
+ /**
244
+ * Path to the wrangler.json file
245
+ * @internal
246
+ */
247
+ path?: string;
248
+ }
249
+
250
+ /**
251
+ * Output returned after WranglerJson creation/update
252
+ */
253
+ export interface WranglerJson
254
+ extends Resource<"cloudflare::WranglerJson">,
255
+ WranglerJsonProps {
256
+ /**
257
+ * Time at which the file was created
258
+ */
259
+ createdAt: number;
260
+
261
+ /**
262
+ * Time at which the file was last updated
263
+ */
264
+ updatedAt: number;
265
+ }
266
+
267
+ /**
268
+ * Resource for managing wrangler.json configuration files
269
+ */
270
+ export const WranglerJson = Resource(
271
+ "cloudflare::WranglerJson",
272
+ async function (
273
+ this: Context<WranglerJson>,
274
+ id: string,
275
+ props: WranglerJsonProps,
276
+ ): Promise<WranglerJson> {
277
+ // Default path is wrangler.json in current directory
278
+ const filePath = props.path || "wrangler.json";
279
+
280
+ if (this.phase === "delete") {
281
+ try {
282
+ await fs.unlink(filePath);
283
+ } catch (error) {
284
+ // Ignore errors if file doesn't exist
285
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
286
+ throw error;
287
+ }
288
+ }
289
+ return this.destroy();
290
+ }
291
+
292
+ // Create or update the file
293
+ const config = {
294
+ ...props,
295
+ // Remove internal path property
296
+ path: undefined,
297
+ };
298
+
299
+ // Write the file
300
+ await fs.writeFile(filePath, JSON.stringify(config, null, 2));
301
+
302
+ // Return the resource
303
+ return this({
304
+ ...props,
305
+ createdAt: Date.now(),
306
+ updatedAt: Date.now(),
307
+ });
308
+ },
309
+ );