alchemy 0.55.3 → 0.57.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 (293) hide show
  1. package/bin/alchemy.js +14245 -14406
  2. package/bin/commands/create.ts +7 -7
  3. package/bin/commands/deploy.ts +2 -2
  4. package/bin/commands/destroy.ts +2 -2
  5. package/bin/commands/dev.ts +2 -2
  6. package/bin/commands/init.ts +6 -6
  7. package/bin/commands/login.ts +3 -3
  8. package/bin/commands/run.ts +2 -2
  9. package/bin/services/execute-alchemy.ts +3 -3
  10. package/bin/trpc.ts +49 -0
  11. package/lib/alchemy.d.ts.map +1 -1
  12. package/lib/alchemy.js +7 -0
  13. package/lib/alchemy.js.map +1 -1
  14. package/lib/apply.d.ts.map +1 -1
  15. package/lib/apply.js +3 -4
  16. package/lib/apply.js.map +1 -1
  17. package/lib/cloudflare/{astro.d.ts → astro/astro.d.ts} +6 -5
  18. package/lib/cloudflare/astro/astro.d.ts.map +1 -0
  19. package/lib/cloudflare/astro/astro.js +91 -0
  20. package/lib/cloudflare/astro/astro.js.map +1 -0
  21. package/lib/cloudflare/astro/plugin.d.ts +4 -0
  22. package/lib/cloudflare/astro/plugin.d.ts.map +1 -0
  23. package/lib/cloudflare/astro/plugin.js +10 -0
  24. package/lib/cloudflare/astro/plugin.js.map +1 -0
  25. package/lib/cloudflare/bundle/plugin-hot-reload.d.ts +1 -3
  26. package/lib/cloudflare/bundle/plugin-hot-reload.d.ts.map +1 -1
  27. package/lib/cloudflare/bundle/plugin-hot-reload.js +4 -1
  28. package/lib/cloudflare/bundle/plugin-hot-reload.js.map +1 -1
  29. package/lib/cloudflare/cloudflare-env-proxy.d.ts +4 -0
  30. package/lib/cloudflare/cloudflare-env-proxy.d.ts.map +1 -0
  31. package/lib/cloudflare/cloudflare-env-proxy.js +34 -0
  32. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -0
  33. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  34. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  35. package/lib/cloudflare/compatibility-presets.d.ts +1 -1
  36. package/lib/cloudflare/compatibility-presets.js +1 -1
  37. package/lib/cloudflare/compatibility-presets.js.map +1 -1
  38. package/lib/cloudflare/d1-local-migrations.js +1 -1
  39. package/lib/cloudflare/d1-local-migrations.js.map +1 -1
  40. package/lib/cloudflare/index.d.ts +8 -8
  41. package/lib/cloudflare/index.d.ts.map +1 -1
  42. package/lib/cloudflare/index.js +8 -8
  43. package/lib/cloudflare/index.js.map +1 -1
  44. package/lib/cloudflare/miniflare/build-worker-options.d.ts +22 -0
  45. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -0
  46. package/lib/cloudflare/miniflare/build-worker-options.js +394 -0
  47. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -0
  48. package/lib/cloudflare/miniflare/miniflare-controller.d.ts +23 -0
  49. package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -0
  50. package/lib/cloudflare/miniflare/miniflare-controller.js +111 -0
  51. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -0
  52. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
  53. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +5 -15
  54. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
  55. package/lib/cloudflare/miniflare/paths.d.ts +5 -0
  56. package/lib/cloudflare/miniflare/paths.d.ts.map +1 -0
  57. package/lib/cloudflare/miniflare/paths.js +35 -0
  58. package/lib/cloudflare/miniflare/paths.js.map +1 -0
  59. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts +1 -5
  60. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  61. package/lib/cloudflare/miniflare/remote-binding-proxy.js +17 -22
  62. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  63. package/lib/cloudflare/{nuxt.d.ts → nuxt/nuxt.d.ts} +4 -4
  64. package/lib/cloudflare/nuxt/nuxt.d.ts.map +1 -0
  65. package/lib/cloudflare/{nuxt.js → nuxt/nuxt.js} +8 -13
  66. package/lib/cloudflare/nuxt/nuxt.js.map +1 -0
  67. package/lib/cloudflare/nuxt/plugin.d.ts +4 -0
  68. package/lib/cloudflare/nuxt/plugin.d.ts.map +1 -0
  69. package/lib/cloudflare/nuxt/plugin.js +14 -0
  70. package/lib/cloudflare/nuxt/plugin.js.map +1 -0
  71. package/lib/cloudflare/oauth.js +2 -2
  72. package/lib/cloudflare/oauth.js.map +1 -1
  73. package/lib/cloudflare/orange.d.ts +3 -3
  74. package/lib/cloudflare/orange.d.ts.map +1 -1
  75. package/lib/cloudflare/orange.js +11 -21
  76. package/lib/cloudflare/orange.js.map +1 -1
  77. package/lib/cloudflare/react-router/plugin.d.ts +4 -0
  78. package/lib/cloudflare/react-router/plugin.d.ts.map +1 -0
  79. package/lib/cloudflare/react-router/plugin.js +11 -0
  80. package/lib/cloudflare/react-router/plugin.js.map +1 -0
  81. package/lib/cloudflare/react-router/react-router.d.ts +17 -0
  82. package/lib/cloudflare/react-router/react-router.d.ts.map +1 -0
  83. package/lib/cloudflare/react-router/react-router.js +21 -0
  84. package/lib/cloudflare/react-router/react-router.js.map +1 -0
  85. package/lib/cloudflare/redwood/plugin.d.ts +4 -0
  86. package/lib/cloudflare/redwood/plugin.d.ts.map +1 -0
  87. package/lib/cloudflare/redwood/plugin.js +19 -0
  88. package/lib/cloudflare/redwood/plugin.js.map +1 -0
  89. package/lib/cloudflare/{redwood.d.ts → redwood/redwood.d.ts} +5 -5
  90. package/lib/cloudflare/redwood/redwood.d.ts.map +1 -0
  91. package/lib/cloudflare/{redwood.js → redwood/redwood.js} +12 -13
  92. package/lib/cloudflare/redwood/redwood.js.map +1 -0
  93. package/lib/cloudflare/sveltekit/plugin.d.ts +4 -0
  94. package/lib/cloudflare/sveltekit/plugin.d.ts.map +1 -0
  95. package/lib/cloudflare/sveltekit/plugin.js +11 -0
  96. package/lib/cloudflare/sveltekit/plugin.js.map +1 -0
  97. package/lib/cloudflare/{sveltekit.d.ts → sveltekit/sveltekit.d.ts} +5 -5
  98. package/lib/cloudflare/sveltekit/sveltekit.d.ts.map +1 -0
  99. package/lib/cloudflare/{sveltekit.js → sveltekit/sveltekit.js} +4 -4
  100. package/lib/cloudflare/sveltekit/sveltekit.js.map +1 -0
  101. package/lib/cloudflare/tanstack-start/plugin.d.ts +16 -0
  102. package/lib/cloudflare/tanstack-start/plugin.d.ts.map +1 -0
  103. package/lib/cloudflare/tanstack-start/plugin.js +28 -0
  104. package/lib/cloudflare/tanstack-start/plugin.js.map +1 -0
  105. package/lib/cloudflare/{tanstack-start.d.ts → tanstack-start/tanstack-start.d.ts} +5 -5
  106. package/lib/cloudflare/tanstack-start/tanstack-start.d.ts.map +1 -0
  107. package/lib/cloudflare/tanstack-start/tanstack-start.js +11 -0
  108. package/lib/cloudflare/tanstack-start/tanstack-start.js.map +1 -0
  109. package/lib/cloudflare/vite/plugin.d.ts +4 -0
  110. package/lib/cloudflare/vite/plugin.d.ts.map +1 -0
  111. package/lib/cloudflare/vite/plugin.js +23 -0
  112. package/lib/cloudflare/vite/plugin.js.map +1 -0
  113. package/lib/cloudflare/{vite.d.ts → vite/vite.d.ts} +4 -4
  114. package/lib/cloudflare/vite/vite.d.ts.map +1 -0
  115. package/lib/cloudflare/vite/vite.js +19 -0
  116. package/lib/cloudflare/vite/vite.js.map +1 -0
  117. package/lib/cloudflare/website.d.ts +92 -70
  118. package/lib/cloudflare/website.d.ts.map +1 -1
  119. package/lib/cloudflare/website.js +225 -94
  120. package/lib/cloudflare/website.js.map +1 -1
  121. package/lib/cloudflare/worker-bundle.d.ts +3 -1
  122. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  123. package/lib/cloudflare/worker-bundle.js +42 -16
  124. package/lib/cloudflare/worker-bundle.js.map +1 -1
  125. package/lib/cloudflare/worker-stub.d.ts.map +1 -1
  126. package/lib/cloudflare/worker-stub.js +3 -6
  127. package/lib/cloudflare/worker-stub.js.map +1 -1
  128. package/lib/cloudflare/worker.d.ts +2 -7
  129. package/lib/cloudflare/worker.d.ts.map +1 -1
  130. package/lib/cloudflare/worker.js +17 -157
  131. package/lib/cloudflare/worker.js.map +1 -1
  132. package/lib/cloudflare/wrangler.json.d.ts +6 -0
  133. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  134. package/lib/cloudflare/wrangler.json.js +23 -6
  135. package/lib/cloudflare/wrangler.json.js.map +1 -1
  136. package/lib/context.d.ts +11 -0
  137. package/lib/context.d.ts.map +1 -1
  138. package/lib/context.js +8 -0
  139. package/lib/context.js.map +1 -1
  140. package/lib/env.d.ts +2 -2
  141. package/lib/env.d.ts.map +1 -1
  142. package/lib/env.js +5 -6
  143. package/lib/env.js.map +1 -1
  144. package/lib/random/index.d.ts +2 -0
  145. package/lib/random/index.d.ts.map +1 -0
  146. package/lib/random/index.js +2 -0
  147. package/lib/random/index.js.map +1 -0
  148. package/lib/random/random-string.d.ts +87 -0
  149. package/lib/random/random-string.d.ts.map +1 -0
  150. package/lib/random/random-string.js +72 -0
  151. package/lib/random/random-string.js.map +1 -0
  152. package/lib/runtime/bind.d.ts +1 -1
  153. package/lib/runtime/bind.d.ts.map +1 -1
  154. package/lib/runtime/bind.js.map +1 -1
  155. package/lib/scope.d.ts +11 -0
  156. package/lib/scope.d.ts.map +1 -1
  157. package/lib/scope.js +24 -0
  158. package/lib/scope.js.map +1 -1
  159. package/lib/secret.d.ts +2 -2
  160. package/lib/secret.d.ts.map +1 -1
  161. package/lib/secret.js +2 -2
  162. package/lib/secret.js.map +1 -1
  163. package/lib/state/cloudflare-state-store.js +1 -1
  164. package/lib/state/cloudflare-state-store.js.map +1 -1
  165. package/lib/state/dofs-state-store/index.js +1 -1
  166. package/lib/state/dofs-state-store/index.js.map +1 -1
  167. package/lib/util/detect-package-manager.d.ts +1 -0
  168. package/lib/util/detect-package-manager.d.ts.map +1 -1
  169. package/lib/util/detect-package-manager.js +10 -0
  170. package/lib/util/detect-package-manager.js.map +1 -1
  171. package/lib/util/telemetry/client.d.ts +1 -1
  172. package/lib/util/telemetry/client.d.ts.map +1 -1
  173. package/lib/util/telemetry/client.js +22 -1
  174. package/lib/util/telemetry/client.js.map +1 -1
  175. package/lib/util/telemetry/constants.d.ts.map +1 -1
  176. package/lib/util/telemetry/constants.js +2 -3
  177. package/lib/util/telemetry/constants.js.map +1 -1
  178. package/lib/util/telemetry/context.d.ts +1 -1
  179. package/lib/util/telemetry/context.d.ts.map +1 -1
  180. package/lib/util/telemetry/types.d.ts +7 -3
  181. package/lib/util/telemetry/types.d.ts.map +1 -1
  182. package/lib/vercel/api.d.ts.map +1 -1
  183. package/lib/vercel/api.js +1 -1
  184. package/lib/vercel/api.js.map +1 -1
  185. package/package.json +43 -4
  186. package/src/alchemy.ts +7 -0
  187. package/src/apply.ts +3 -7
  188. package/src/cloudflare/{astro.ts → astro/astro.ts} +46 -29
  189. package/src/cloudflare/astro/plugin.ts +11 -0
  190. package/src/cloudflare/bundle/plugin-hot-reload.ts +4 -3
  191. package/src/cloudflare/cloudflare-env-proxy.ts +50 -0
  192. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  193. package/src/cloudflare/compatibility-presets.ts +1 -1
  194. package/src/cloudflare/d1-local-migrations.ts +1 -1
  195. package/src/cloudflare/index.ts +8 -8
  196. package/src/cloudflare/miniflare/build-worker-options.ts +454 -0
  197. package/src/cloudflare/miniflare/miniflare-controller.ts +129 -0
  198. package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +6 -15
  199. package/src/cloudflare/miniflare/paths.ts +52 -0
  200. package/src/cloudflare/miniflare/remote-binding-proxy.ts +18 -23
  201. package/src/cloudflare/{nuxt.ts → nuxt/nuxt.ts} +11 -16
  202. package/src/cloudflare/nuxt/plugin.ts +18 -0
  203. package/src/cloudflare/oauth.ts +2 -2
  204. package/src/cloudflare/orange.ts +13 -23
  205. package/src/cloudflare/react-router/plugin.ts +13 -0
  206. package/src/cloudflare/react-router/react-router.ts +41 -0
  207. package/src/cloudflare/redwood/plugin.ts +20 -0
  208. package/src/cloudflare/{redwood.ts → redwood/redwood.ts} +16 -19
  209. package/src/cloudflare/sveltekit/plugin.ts +12 -0
  210. package/src/cloudflare/{sveltekit.ts → sveltekit/sveltekit.ts} +9 -8
  211. package/src/cloudflare/tanstack-start/plugin.ts +30 -0
  212. package/src/cloudflare/tanstack-start/tanstack-start.ts +24 -0
  213. package/src/cloudflare/vite/plugin.ts +30 -0
  214. package/src/cloudflare/vite/vite.ts +34 -0
  215. package/src/cloudflare/website.ts +379 -204
  216. package/src/cloudflare/worker-bundle.ts +55 -16
  217. package/src/cloudflare/worker-stub.ts +11 -14
  218. package/src/cloudflare/worker.ts +23 -205
  219. package/src/cloudflare/wrangler.json.ts +32 -4
  220. package/src/context.ts +19 -0
  221. package/src/env.ts +8 -9
  222. package/src/random/index.ts +1 -0
  223. package/src/random/random-string.ts +126 -0
  224. package/src/runtime/bind.ts +2 -2
  225. package/src/scope.ts +25 -0
  226. package/src/secret.ts +4 -8
  227. package/src/state/cloudflare-state-store.ts +2 -2
  228. package/src/state/dofs-state-store/index.ts +1 -1
  229. package/src/util/detect-package-manager.ts +11 -0
  230. package/src/util/telemetry/client.ts +25 -2
  231. package/src/util/telemetry/constants.ts +2 -4
  232. package/src/util/telemetry/context.ts +1 -1
  233. package/src/util/telemetry/types.ts +8 -2
  234. package/src/vercel/api.ts +2 -4
  235. package/templates/astro/alchemy.run.ts +1 -3
  236. package/templates/astro/astro.config.mjs +2 -2
  237. package/templates/nuxt/alchemy.run.ts +1 -3
  238. package/templates/nuxt/nuxt.config.ts +4 -5
  239. package/templates/nuxt/package.json +0 -1
  240. package/templates/react-router/alchemy.run.ts +1 -4
  241. package/templates/react-router/vite.config.ts +2 -2
  242. package/templates/rwsdk/alchemy.run.ts +0 -1
  243. package/templates/rwsdk/package.json +0 -2
  244. package/templates/rwsdk/vite.config.mts +2 -2
  245. package/templates/sveltekit/alchemy.run.ts +1 -3
  246. package/templates/sveltekit/svelte.config.js +2 -2
  247. package/templates/tanstack-start/vite.config.ts +2 -2
  248. package/templates/vite/alchemy.run.ts +1 -1
  249. package/templates/vite/vite.config.ts +4 -5
  250. package/workers/cloudflare-state-store.js +12 -14
  251. package/lib/cloudflare/astro.d.ts.map +0 -1
  252. package/lib/cloudflare/astro.js +0 -69
  253. package/lib/cloudflare/astro.js.map +0 -1
  254. package/lib/cloudflare/local-dev-cloudflare-shim.d.ts +0 -13
  255. package/lib/cloudflare/local-dev-cloudflare-shim.d.ts.map +0 -1
  256. package/lib/cloudflare/local-dev-cloudflare-shim.js +0 -26
  257. package/lib/cloudflare/local-dev-cloudflare-shim.js.map +0 -1
  258. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts +0 -14
  259. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +0 -1
  260. package/lib/cloudflare/miniflare/miniflare-worker-options.js +0 -468
  261. package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +0 -1
  262. package/lib/cloudflare/miniflare/miniflare.d.ts +0 -40
  263. package/lib/cloudflare/miniflare/miniflare.d.ts.map +0 -1
  264. package/lib/cloudflare/miniflare/miniflare.js +0 -142
  265. package/lib/cloudflare/miniflare/miniflare.js.map +0 -1
  266. package/lib/cloudflare/nuxt.d.ts.map +0 -1
  267. package/lib/cloudflare/nuxt.js.map +0 -1
  268. package/lib/cloudflare/react-router.d.ts +0 -17
  269. package/lib/cloudflare/react-router.d.ts.map +0 -1
  270. package/lib/cloudflare/react-router.js +0 -35
  271. package/lib/cloudflare/react-router.js.map +0 -1
  272. package/lib/cloudflare/redwood.d.ts.map +0 -1
  273. package/lib/cloudflare/redwood.js.map +0 -1
  274. package/lib/cloudflare/sveltekit.d.ts.map +0 -1
  275. package/lib/cloudflare/sveltekit.js.map +0 -1
  276. package/lib/cloudflare/tanstack-start.d.ts.map +0 -1
  277. package/lib/cloudflare/tanstack-start.js +0 -21
  278. package/lib/cloudflare/tanstack-start.js.map +0 -1
  279. package/lib/cloudflare/vite.d.ts.map +0 -1
  280. package/lib/cloudflare/vite.js +0 -20
  281. package/lib/cloudflare/vite.js.map +0 -1
  282. package/src/cloudflare/local-dev-cloudflare-shim.ts +0 -25
  283. package/src/cloudflare/miniflare/miniflare-worker-options.ts +0 -599
  284. package/src/cloudflare/miniflare/miniflare.ts +0 -183
  285. package/src/cloudflare/react-router.ts +0 -56
  286. package/src/cloudflare/tanstack-start.ts +0 -35
  287. package/src/cloudflare/vite.ts +0 -35
  288. package/templates/react-router/wrangler.jsonc +0 -6
  289. package/templates/rwsdk/wrangler.jsonc +0 -31
  290. package/templates/sveltekit/wrangler.jsonc +0 -7
  291. package/templates/tanstack-start/wrangler.jsonc +0 -7
  292. package/templates/typescript/index.ts +0 -1
  293. package/templates/vite/wrangler.jsonc +0 -6
@@ -1,7 +1,8 @@
1
1
  import esbuild from "esbuild";
2
2
  import { err, ok, type Result } from "neverthrow";
3
3
  import fs from "node:fs/promises";
4
- import path from "node:path";
4
+ import path from "pathe";
5
+ import { logger } from "../util/logger.ts";
5
6
  import { external, external_als } from "./bundle/externals.ts";
6
7
  import { esbuildPluginAlias } from "./bundle/plugin-alias.ts";
7
8
  import { esbuildPluginCompatWarning } from "./bundle/plugin-compat-warning.ts";
@@ -17,6 +18,7 @@ export interface WorkerBundle {
17
18
  }
18
19
 
19
20
  export function normalizeWorkerBundle(props: {
21
+ id: string;
20
22
  script: string | undefined;
21
23
  entrypoint: string | undefined;
22
24
  noBundle: boolean | undefined;
@@ -66,12 +68,13 @@ export function normalizeWorkerBundle(props: {
66
68
  sourcemaps: props.sourceMap !== false,
67
69
  })
68
70
  : new WorkerBundleSource.ESBuild({
71
+ id: props.id,
69
72
  entrypoint: props.entrypoint,
70
73
  format: props.format ?? "esm",
71
74
  nodeCompat,
72
75
  cwd: props.cwd,
73
76
  outdir: props.outdir,
74
- sourcemap: props.sourceMap !== false ? "linked" : undefined,
77
+ sourcemap: props.sourceMap !== false ? true : undefined,
75
78
  ...props.bundle,
76
79
  }),
77
80
  );
@@ -125,7 +128,8 @@ export namespace WorkerBundle {
125
128
  (await fs.readFile(path.join(bundle.root!, module.path)));
126
129
  form.append(
127
130
  module.path,
128
- new Blob([content], {
131
+ // TODO(sam): tsc -b geting a weird error about SharedArrayBuffer
132
+ new Blob([content as any as BlobPart], {
129
133
  type: types[module.type],
130
134
  }),
131
135
  module.path,
@@ -238,6 +242,7 @@ export namespace WorkerBundleSource {
238
242
  esbuild.BuildOptions,
239
243
  "entryPoints" | "format" | "absWorkingDir" | "outdir"
240
244
  > {
245
+ id: string;
241
246
  entrypoint: string;
242
247
  cwd: string;
243
248
  outdir: string;
@@ -262,7 +267,7 @@ export namespace WorkerBundleSource {
262
267
  const wasmPlugin = createWasmPlugin();
263
268
  const options = this.buildOptions([wasmPlugin.plugin]);
264
269
  const result = await esbuild.build(options);
265
- const { entrypoint, root, modules } = this.resolveBuildOutput(
270
+ const { entrypoint, root, modules } = await this.formatBuildOutput(
266
271
  result.metafile,
267
272
  );
268
273
  return {
@@ -274,7 +279,20 @@ export namespace WorkerBundleSource {
274
279
 
275
280
  async *watch(signal: AbortSignal): AsyncIterable<WorkerBundle> {
276
281
  const wasm = createWasmPlugin();
277
- const hotReload = createHotReloadPlugin();
282
+ let count = 0;
283
+ const hotReload = createHotReloadPlugin({
284
+ onBuildStart: () => {
285
+ if (count > 0) {
286
+ logger.task(this.props.id, {
287
+ message: "Rebuilding",
288
+ status: "pending",
289
+ resource: this.props.id,
290
+ prefix: "dev",
291
+ prefixColor: "cyanBright",
292
+ });
293
+ }
294
+ },
295
+ });
278
296
  const options = this.buildOptions([wasm.plugin, hotReload.plugin]);
279
297
 
280
298
  const context = await esbuild.context(options);
@@ -282,7 +300,8 @@ export namespace WorkerBundleSource {
282
300
  await context.watch();
283
301
 
284
302
  for await (const result of hotReload.iterator) {
285
- const { entrypoint, root, modules } = this.resolveBuildOutput(
303
+ count++;
304
+ const { entrypoint, root, modules } = await this.formatBuildOutput(
286
305
  result.metafile!,
287
306
  );
288
307
  yield {
@@ -301,24 +320,38 @@ export namespace WorkerBundleSource {
301
320
  }
302
321
 
303
322
  private buildOptions(additionalPlugins: esbuild.Plugin[]) {
304
- const { entrypoint, nodeCompat, cwd, format, ...props } = this.props;
323
+ const {
324
+ id: _,
325
+ entrypoint,
326
+ nodeCompat,
327
+ cwd,
328
+ format,
329
+ ...props
330
+ } = this.props;
305
331
  return {
306
332
  entryPoints: [entrypoint],
307
333
  absWorkingDir: cwd,
334
+ target: "es2022",
335
+ loader: {
336
+ ".js": "jsx",
337
+ ".mjs": "jsx",
338
+ ".cjs": "jsx",
339
+ },
308
340
  format,
309
- target: "esnext",
341
+ sourceRoot: this.props.outdir,
342
+ jsxFactory: "React.createElement",
343
+ jsxFragment: "React.Fragment",
344
+ keepNames: true,
310
345
  ...props,
311
346
  metafile: true,
312
347
  write: true,
313
348
  bundle: true,
314
- conditions: props.conditions ?? ["workerd", "worker", "browser"],
315
- mainFields: props.mainFields,
316
- loader: {
317
- ".sql": "text",
318
- ".json": "json",
319
- ".wasm": "binary",
320
- ...props.loader,
349
+ define: {
350
+ "navigator.userAgent": '"Cloudflare-Workers"',
351
+ "process.env.NODE_ENV": '"undefined"',
352
+ ...props.define,
321
353
  },
354
+ conditions: props.conditions ?? ["workerd", "worker", "browser"],
322
355
  plugins: [
323
356
  esbuildPluginAlias(props.alias ?? {}, this.props.cwd),
324
357
  nodeCompat === "v2"
@@ -334,8 +367,14 @@ export namespace WorkerBundleSource {
334
367
  } satisfies esbuild.BuildOptions;
335
368
  }
336
369
 
337
- private resolveBuildOutput(metafile: esbuild.Metafile): WorkerBundle {
370
+ private async formatBuildOutput(
371
+ metafile: esbuild.Metafile,
372
+ ): Promise<WorkerBundle> {
338
373
  const outdir = path.resolve(this.props.cwd, this.props.outdir);
374
+ await fs.writeFile(
375
+ path.join(outdir, "metafile.json"),
376
+ JSON.stringify(metafile, null, 2),
377
+ );
339
378
  const paths: string[] = [];
340
379
  let entrypoint: string | undefined;
341
380
  for (const [key, value] of Object.entries(metafile.outputs)) {
@@ -2,6 +2,7 @@ import type { Context } from "../context.ts";
2
2
  import { Resource, ResourceKind } from "../resource.ts";
3
3
  import type { type } from "../type.ts";
4
4
  import { handleApiError } from "./api-error.ts";
5
+ import { extractCloudflareResult } from "./api-response.ts";
5
6
  import {
6
7
  createCloudflareApi,
7
8
  type CloudflareApi,
@@ -185,20 +186,16 @@ async function createEmptyWorker(
185
186
  );
186
187
 
187
188
  // Upload worker script
188
- const uploadResponse = await api.put(
189
- `/accounts/${api.accountId}/workers/scripts/${workerName}`,
190
- formData,
191
- {
192
- headers: {
193
- "Content-Type": "multipart/form-data",
189
+ await extractCloudflareResult(
190
+ `create empty worker "${workerName}"`,
191
+ api.put(
192
+ `/accounts/${api.accountId}/workers/scripts/${workerName}`,
193
+ formData,
194
+ {
195
+ headers: {
196
+ "Content-Type": "multipart/form-data",
197
+ },
194
198
  },
195
- },
199
+ ),
196
200
  );
197
-
198
- // Check if the upload was successful
199
- if (!uploadResponse.ok) {
200
- throw new Error(
201
- `Failed to create empty worker: ${uploadResponse.status} ${uploadResponse.statusText}`,
202
- );
203
- }
204
201
  }
@@ -1,12 +1,8 @@
1
- import kleur from "kleur";
2
- import { spawn } from "node:child_process";
3
- import fs from "node:fs/promises";
4
1
  import { isDeepStrictEqual } from "node:util";
5
2
  import path from "pathe";
6
3
  import type { Context } from "../context.ts";
7
4
  import type { BundleProps } from "../esbuild/bundle.ts";
8
5
  import { Resource, ResourceKind } from "../resource.ts";
9
- import { isSecret } from "../secret.ts";
10
6
  import type { type } from "../type.ts";
11
7
  import { DeferredPromise } from "../util/deferred-promise.ts";
12
8
  import { logger } from "../util/logger.ts";
@@ -38,8 +34,6 @@ import {
38
34
  isDurableObjectNamespace,
39
35
  } from "./durable-object-namespace.ts";
40
36
  import { type EventSource, isQueueEventSource } from "./event-source.ts";
41
- import type { MiniflareWorkerOptions } from "./miniflare/miniflare-worker-options.ts";
42
- import { miniflareServer } from "./miniflare/miniflare.ts";
43
37
  import {
44
38
  QueueConsumer,
45
39
  deleteQueueConsumer,
@@ -48,11 +42,7 @@ import {
48
42
  import { isQueue } from "./queue.ts";
49
43
  import { Route } from "./route.ts";
50
44
  import { uploadAssets } from "./worker-assets.ts";
51
- import {
52
- WorkerBundle,
53
- type WorkerBundleSource,
54
- normalizeWorkerBundle,
55
- } from "./worker-bundle.ts";
45
+ import { WorkerBundle, normalizeWorkerBundle } from "./worker-bundle.ts";
56
46
  import {
57
47
  type WorkerScriptMetadata,
58
48
  bumpMigrationTagVersion,
@@ -65,7 +55,6 @@ import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.ts";
65
55
  // Previous versions of `Worker` used the `Bundle` resource.
66
56
  // This import is here to avoid errors when destroying the `Bundle` resource.
67
57
  import "../esbuild/bundle.ts";
68
- import { exists } from "../util/exists.ts";
69
58
 
70
59
  /**
71
60
  * Configuration options for static assets
@@ -338,15 +327,10 @@ export interface BaseWorkerProps<
338
327
  * @default false
339
328
  */
340
329
  remote?: boolean;
341
- /** @internal */
342
- command?: undefined;
330
+ url?: undefined;
343
331
  }
344
332
  | {
345
- command: string;
346
- cwd?: string;
347
- /** @internal */
348
- port?: undefined;
349
- /** @internal */
333
+ url: string;
350
334
  remote?: undefined;
351
335
  };
352
336
 
@@ -736,6 +720,7 @@ const _Worker = Resource(
736
720
  : props.namespace?.namespaceName;
737
721
 
738
722
  const bundleSourceResult = normalizeWorkerBundle({
723
+ id,
739
724
  entrypoint: props.entrypoint,
740
725
  script: props.script,
741
726
  format: props.format,
@@ -746,8 +731,7 @@ const _Worker = Resource(
746
731
  compatibilityDate,
747
732
  compatibilityFlags,
748
733
  outdir:
749
- props.bundle?.outdir ??
750
- path.join(cwd, ".alchemy", ...this.scope.chain, id),
734
+ props.bundle?.outdir ?? path.join(cwd, ".alchemy", "out", workerName),
751
735
  sourceMap: "sourceMap" in props ? props.sourceMap : undefined,
752
736
  });
753
737
 
@@ -761,37 +745,25 @@ const _Worker = Resource(
761
745
  throw bundleSourceResult.error;
762
746
  }
763
747
 
764
- if (props.dev?.command) {
765
- const { url: commandUrl } = await createDevCommand({
766
- id,
767
- command: props.dev.command,
768
- cwd: props.dev.cwd || props.cwd || process.cwd(),
769
- env: {
770
- ...(process.env ?? {}),
771
- ...props.env,
772
- ...Object.fromEntries(
773
- Object.entries(props.bindings ?? {}).flatMap(([key, value]) =>
774
- typeof value === "string"
775
- ? [[key, value]]
776
- : isSecret(value)
777
- ? [[key, value.unencrypted]]
778
- : [],
779
- ),
780
- ),
781
- },
782
- });
783
- url = commandUrl;
748
+ if (props.dev && "url" in props.dev) {
749
+ url = props.dev.url;
784
750
  } else {
785
- url = await createMiniflare({
751
+ const { MiniflareController } = await import(
752
+ "./miniflare/miniflare-controller.js"
753
+ );
754
+ const controller = MiniflareController.singleton;
755
+ url = await controller.add({
786
756
  id,
787
- workerName,
757
+ name: workerName,
788
758
  compatibilityDate,
789
759
  compatibilityFlags,
790
760
  bindings: props.bindings,
791
- bundle: bundleSourceResult.value,
792
- port: props.dev?.port,
761
+ eventSources: props.eventSources,
793
762
  assets: props.assets,
763
+ bundle: bundleSourceResult.value,
764
+ port: props.dev?.port ?? undefined,
794
765
  });
766
+ this.onCleanup(() => controller.dispose());
795
767
  }
796
768
 
797
769
  return this({
@@ -848,7 +820,7 @@ const _Worker = Resource(
848
820
  const oldName = this.output.name ?? this.output.id;
849
821
  const newName = workerName;
850
822
 
851
- if (oldName !== newName) {
823
+ if (oldName && oldName !== newName) {
852
824
  if (dispatchNamespace) {
853
825
  this.replace(true);
854
826
  } else {
@@ -926,7 +898,6 @@ const _Worker = Resource(
926
898
  let putWorkerResult: PutWorkerResult;
927
899
  if (watch) {
928
900
  const controller = new AbortController();
929
- cleanups.push(() => controller.abort());
930
901
  const promise = new DeferredPromise<PutWorkerResult>();
931
902
  const runWatch = async () => {
932
903
  for await (const bundle of bundleSource.watch(controller.signal)) {
@@ -973,14 +944,12 @@ const _Worker = Resource(
973
944
  }
974
945
  };
975
946
  void runWatch(); // this is not awaited because it's an ongoing process
947
+ this.onCleanup(() => controller.abort());
976
948
  putWorkerResult = await promise.value;
977
- await createTail(api, id, workerName)
978
- .then((tail) => {
979
- cleanups.push(() => tail.close());
980
- })
981
- .catch((error) => {
982
- logger.error(`Failed to create tail for ${workerName}`, error);
983
- });
949
+ const tail = await createTail(api, id, workerName).catch((error) => {
950
+ logger.error(`Failed to create tail for ${workerName}`, error);
951
+ });
952
+ this.onCleanup(() => tail?.close());
984
953
  } else {
985
954
  const scriptBundle = await bundleSource.create();
986
955
  putWorkerResult = await putWorkerWithAssets(props, scriptBundle);
@@ -1102,22 +1071,6 @@ const _Worker = Resource(
1102
1071
  },
1103
1072
  );
1104
1073
 
1105
- const cleanups: (() => any)[] = [];
1106
- let exiting = false;
1107
-
1108
- process.on("SIGINT", async () => {
1109
- if (cleanups.length > 0) {
1110
- if (!exiting) {
1111
- exiting = true;
1112
- logger.log(`\n${kleur.gray("Exiting...")}`);
1113
- }
1114
- // TODO: for some reason this runs twice...
1115
- // and this whole thing feels hacky anyway
1116
- await Promise.allSettled(cleanups.map((cleanup) => cleanup()));
1117
- }
1118
- process.exit(0);
1119
- });
1120
-
1121
1074
  const assertUnique = <T, Key extends keyof T>(
1122
1075
  inputs: T[],
1123
1076
  key: Key,
@@ -1337,141 +1290,6 @@ async function provisionSubdomain(
1337
1290
  }
1338
1291
  }
1339
1292
 
1340
- async function createMiniflare(props: {
1341
- id: string;
1342
- workerName: string;
1343
- compatibilityDate: string;
1344
- compatibilityFlags: string[];
1345
- bindings: Bindings | undefined;
1346
- port: number | undefined;
1347
- bundle: WorkerBundleSource;
1348
- assets: AssetsConfig | undefined;
1349
- }) {
1350
- const sharedOptions: Omit<MiniflareWorkerOptions, "bundle"> = {
1351
- name: props.workerName,
1352
- compatibilityDate: props.compatibilityDate,
1353
- compatibilityFlags: props.compatibilityFlags,
1354
- bindings: props.bindings,
1355
- port: props.port,
1356
- assets: props.assets,
1357
- };
1358
-
1359
- const startPromise = new DeferredPromise<string>();
1360
- const controller = new AbortController();
1361
- cleanups.push(() => controller.abort());
1362
- const run = async () => {
1363
- for await (const bundle of props.bundle.watch(controller.signal)) {
1364
- const server = await miniflareServer.push({
1365
- ...sharedOptions,
1366
- bundle,
1367
- });
1368
- if (startPromise.status === "pending") {
1369
- startPromise.resolve(server.url);
1370
- }
1371
- logger.task("", {
1372
- message: `ready at ${server.url}`,
1373
- status: "success",
1374
- resource: props.id,
1375
- prefix: "miniflare",
1376
- prefixColor: "greenBright",
1377
- });
1378
- }
1379
- };
1380
- void run();
1381
- return await startPromise.value;
1382
- }
1383
-
1384
- async function createDevCommand(props: {
1385
- id: string;
1386
- command: string;
1387
- cwd: string;
1388
- env: Record<string, string | undefined>;
1389
- }): Promise<{ url: string }> {
1390
- const persistFile = path.join(process.cwd(), ".alchemy", `${props.id}.pid`);
1391
- if (await exists(persistFile)) {
1392
- const pid = Number.parseInt(await fs.readFile(persistFile, "utf8"));
1393
- try {
1394
- // Actually kill the process if it's alive
1395
- process.kill(pid, "SIGTERM");
1396
- } catch {
1397
- // ignore
1398
- }
1399
- try {
1400
- await fs.unlink(persistFile);
1401
- } catch {
1402
- // ignore
1403
- }
1404
- }
1405
- const command = props.command.split(" ");
1406
- const [cmd, ...args] = command;
1407
- const proc = spawn(cmd, args, {
1408
- cwd: props.cwd,
1409
- shell: true,
1410
- env: {
1411
- ...process.env,
1412
- ...props.env,
1413
- ALCHEMY_CLOUDFLARE_PERSIST_PATH: path.join(
1414
- process.cwd(),
1415
- ".alchemy",
1416
- "miniflare",
1417
- ),
1418
- // Force colors in the child process since we're piping output
1419
- // FORCE_COLOR: "1",
1420
- },
1421
- stdio: ["inherit", "pipe", "pipe"],
1422
- });
1423
- const { url } = await new Promise<{ url: string }>((resolve, reject) => {
1424
- let urlFound = false;
1425
- let stdout = "";
1426
- let stderr = "";
1427
- const urlRegex =
1428
- /http:\/\/(?:(?:localhost|0\.0\.0\.0|127\.0\.0\.1)|(?:\d{1,3}\.){3}\d{1,3}):\d+(?:\/)?/;
1429
-
1430
- const parseOutput = (data: string) => {
1431
- if (!urlFound) {
1432
- const match = data.match(urlRegex);
1433
- if (match) {
1434
- urlFound = true;
1435
- resolve({ url: match[0] });
1436
- }
1437
- }
1438
- };
1439
-
1440
- // Handle stdout - parse for URL and write through with colors preserved
1441
- proc.stdout?.on("data", (data) => {
1442
- parseOutput(
1443
- (stdout += data.toString().replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "")),
1444
- );
1445
- process.stdout.write(data);
1446
- });
1447
-
1448
- proc.stderr?.on("data", (data) => {
1449
- parseOutput(
1450
- (stderr += data.toString().replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "")),
1451
- );
1452
- process.stderr.write(data);
1453
- });
1454
-
1455
- proc.on("error", (error) => {
1456
- reject(error);
1457
- });
1458
-
1459
- cleanups.push(async () => {
1460
- try {
1461
- await fs.unlink(persistFile);
1462
- } catch {
1463
- // ignore
1464
- }
1465
- proc.kill();
1466
- });
1467
- });
1468
- if (proc.pid) {
1469
- await fs.mkdir(path.dirname(persistFile), { recursive: true });
1470
- await fs.writeFile(persistFile, proc.pid.toString());
1471
- }
1472
- return { url };
1473
- }
1474
-
1475
1293
  type PutWorkerOptions = Omit<WorkerProps, "entrypoint"> & {
1476
1294
  dispatchNamespace?: string;
1477
1295
  migrationTag?: string;
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import type { Context } from "../context.ts";
4
4
  import { formatJson } from "../fs/static-json-file.ts";
5
5
  import { Resource } from "../resource.ts";
6
+ import { isSecret } from "../secret.ts";
6
7
  import { assertNever } from "../util/assert-never.ts";
7
8
  import {
8
9
  Self,
@@ -56,6 +57,13 @@ export interface WranglerJsonProps {
56
57
  directory: string;
57
58
  };
58
59
 
60
+ /**
61
+ * Whether to include secrets in the wrangler.json file
62
+ *
63
+ * @default true
64
+ */
65
+ secrets?: boolean;
66
+
59
67
  /**
60
68
  * Transform hooks to modify generated configuration files
61
69
  */
@@ -169,6 +177,7 @@ export const WranglerJson = Resource(
169
177
  worker.eventSources,
170
178
  worker.name,
171
179
  cwd,
180
+ props.secrets ?? false,
172
181
  );
173
182
  }
174
183
 
@@ -191,7 +200,24 @@ export const WranglerJson = Resource(
191
200
  : spec;
192
201
 
193
202
  await fs.mkdir(dirname, { recursive: true });
194
- await fs.writeFile(filePath, await formatJson(finalSpec));
203
+ if (props.secrets) {
204
+ // If secrets are enabled, decrypt them in the wrangler.json file,
205
+ // but do not modify `finalSpec` so that way secrets aren't written to state unencrypted.
206
+ const withSecretsUnwrapped = {
207
+ ...finalSpec,
208
+ vars: {
209
+ ...finalSpec.vars,
210
+ ...Object.fromEntries(
211
+ Object.entries(finalSpec.vars ?? {}).map(([key, value]) =>
212
+ isSecret(value) ? [key, value.unencrypted] : [key, value],
213
+ ),
214
+ ),
215
+ },
216
+ };
217
+ await fs.writeFile(filePath, await formatJson(withSecretsUnwrapped));
218
+ } else {
219
+ await fs.writeFile(filePath, await formatJson(finalSpec));
220
+ }
195
221
 
196
222
  // Return the resource
197
223
  return this({
@@ -473,6 +499,7 @@ function processBindings(
473
499
  eventSources: EventSource[] | undefined,
474
500
  workerName: string,
475
501
  workerCwd: string,
502
+ writeSecrets: boolean,
476
503
  ): void {
477
504
  // Arrays to collect different binding types
478
505
  const kvNamespaces: {
@@ -578,10 +605,11 @@ function processBindings(
578
605
  }
579
606
  if (typeof binding === "string") {
580
607
  // Plain text binding - add to vars
581
- if (!spec.vars) {
582
- spec.vars = {};
583
- }
608
+ spec.vars ??= {};
584
609
  spec.vars[bindingName] = binding;
610
+ } else if (writeSecrets && isSecret(binding)) {
611
+ spec.vars ??= {};
612
+ spec.vars[bindingName] = binding as any;
585
613
  } else if (binding === Self) {
586
614
  // Self(service) binding
587
615
  services.push({
package/src/context.ts CHANGED
@@ -67,6 +67,17 @@ export interface BaseContext<Out extends Resource> {
67
67
  * "return undefined" so that `await MyResource()` always returns a value.
68
68
  */
69
69
  destroy(): never;
70
+ /**
71
+ * Register a cleanup function that will be called when the process exits.
72
+ *
73
+ * @example
74
+ * const proc = spawn('my-command', ['arg1', 'arg2']);
75
+ * this.onCleanup(async () => {
76
+ * proc.kill();
77
+ * await waitForExit(proc);
78
+ * });
79
+ */
80
+ onCleanup(fn: () => void | Promise<void>): void;
70
81
  /**
71
82
  * Create the Resource envelope (with Alchemy + User properties)
72
83
  */
@@ -153,6 +164,14 @@ export function context<
153
164
  destroy: () => {
154
165
  throw new DestroyedSignal();
155
166
  },
167
+ onCleanup: (fn: () => void | Promise<void>) => {
168
+ // make the function idempotent so repeated calls don't cause the process to hang
169
+ let promise: Promise<void> | undefined;
170
+ scope.root.onCleanup(async () => {
171
+ promise ??= Promise.resolve(fn());
172
+ await promise;
173
+ });
174
+ },
156
175
  create,
157
176
  }) as unknown as Context<Out>;
158
177
  }
package/src/env.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export interface Env {
2
- [key: string]: Promise<string>;
3
- <T = string>(name: string, value?: T | undefined, error?: string): Promise<T>;
2
+ [key: string]: string;
3
+ <T = string>(name: string, value?: T | undefined, error?: string): T;
4
4
  }
5
5
 
6
6
  export const env = new Proxy(_env, {
@@ -8,22 +8,21 @@ export const env = new Proxy(_env, {
8
8
  apply: (_, __, args: [string, any?, string?]) => _env(...args),
9
9
  }) as Env;
10
10
 
11
- async function _env<T = string>(
11
+ function _env<T = string>(
12
12
  name: string,
13
13
  value?: T | undefined,
14
14
  error?: string,
15
- ): Promise<T> {
15
+ ): T {
16
16
  if (value !== undefined) {
17
17
  return value;
18
18
  }
19
- const env = await resolveEnv();
20
- if (name in env) {
21
- return env[name] as T;
19
+ if (name in environment) {
20
+ return environment[name] as T;
22
21
  }
23
22
  throw new Error(error ?? `Environment variable ${name} is not set`);
24
23
  }
25
24
 
26
- async function resolveEnv(): Promise<Record<string, any>> {
25
+ const environment = await (async (): Promise<Record<string, any>> => {
27
26
  if (typeof process !== "undefined") {
28
27
  return process.env;
29
28
  }
@@ -35,4 +34,4 @@ async function resolveEnv(): Promise<Record<string, any>> {
35
34
  return import.meta.env;
36
35
  }
37
36
  throw new Error("No environment found");
38
- }
37
+ })();
@@ -0,0 +1 @@
1
+ export * from "./random-string.ts";