alchemy 0.56.0 → 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 (247) hide show
  1. package/bin/alchemy.js +14201 -14162
  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/apply.d.ts.map +1 -1
  12. package/lib/apply.js +3 -4
  13. package/lib/apply.js.map +1 -1
  14. package/lib/cloudflare/{astro.d.ts → astro/astro.d.ts} +6 -5
  15. package/lib/cloudflare/astro/astro.d.ts.map +1 -0
  16. package/lib/cloudflare/astro/astro.js +91 -0
  17. package/lib/cloudflare/astro/astro.js.map +1 -0
  18. package/lib/cloudflare/astro/plugin.d.ts +4 -0
  19. package/lib/cloudflare/astro/plugin.d.ts.map +1 -0
  20. package/lib/cloudflare/astro/plugin.js +10 -0
  21. package/lib/cloudflare/astro/plugin.js.map +1 -0
  22. package/lib/cloudflare/cloudflare-env-proxy.d.ts +4 -0
  23. package/lib/cloudflare/cloudflare-env-proxy.d.ts.map +1 -0
  24. package/lib/cloudflare/cloudflare-env-proxy.js +34 -0
  25. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -0
  26. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  27. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  28. package/lib/cloudflare/d1-local-migrations.js +1 -1
  29. package/lib/cloudflare/d1-local-migrations.js.map +1 -1
  30. package/lib/cloudflare/index.d.ts +8 -8
  31. package/lib/cloudflare/index.d.ts.map +1 -1
  32. package/lib/cloudflare/index.js +8 -8
  33. package/lib/cloudflare/index.js.map +1 -1
  34. package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -1
  35. package/lib/cloudflare/miniflare/miniflare-controller.js +2 -1
  36. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -1
  37. package/lib/cloudflare/miniflare/paths.d.ts +5 -0
  38. package/lib/cloudflare/miniflare/paths.d.ts.map +1 -0
  39. package/lib/cloudflare/miniflare/paths.js +35 -0
  40. package/lib/cloudflare/miniflare/paths.js.map +1 -0
  41. package/lib/cloudflare/{nuxt.d.ts → nuxt/nuxt.d.ts} +4 -4
  42. package/lib/cloudflare/nuxt/nuxt.d.ts.map +1 -0
  43. package/lib/cloudflare/{nuxt.js → nuxt/nuxt.js} +8 -13
  44. package/lib/cloudflare/nuxt/nuxt.js.map +1 -0
  45. package/lib/cloudflare/nuxt/plugin.d.ts +4 -0
  46. package/lib/cloudflare/nuxt/plugin.d.ts.map +1 -0
  47. package/lib/cloudflare/nuxt/plugin.js +14 -0
  48. package/lib/cloudflare/nuxt/plugin.js.map +1 -0
  49. package/lib/cloudflare/oauth.js +2 -2
  50. package/lib/cloudflare/oauth.js.map +1 -1
  51. package/lib/cloudflare/orange.d.ts +3 -3
  52. package/lib/cloudflare/orange.d.ts.map +1 -1
  53. package/lib/cloudflare/orange.js +11 -21
  54. package/lib/cloudflare/orange.js.map +1 -1
  55. package/lib/cloudflare/react-router/plugin.d.ts +4 -0
  56. package/lib/cloudflare/react-router/plugin.d.ts.map +1 -0
  57. package/lib/cloudflare/react-router/plugin.js +11 -0
  58. package/lib/cloudflare/react-router/plugin.js.map +1 -0
  59. package/lib/cloudflare/react-router/react-router.d.ts +17 -0
  60. package/lib/cloudflare/react-router/react-router.d.ts.map +1 -0
  61. package/lib/cloudflare/react-router/react-router.js +21 -0
  62. package/lib/cloudflare/react-router/react-router.js.map +1 -0
  63. package/lib/cloudflare/redwood/plugin.d.ts +4 -0
  64. package/lib/cloudflare/redwood/plugin.d.ts.map +1 -0
  65. package/lib/cloudflare/redwood/plugin.js +19 -0
  66. package/lib/cloudflare/redwood/plugin.js.map +1 -0
  67. package/lib/cloudflare/{redwood.d.ts → redwood/redwood.d.ts} +5 -5
  68. package/lib/cloudflare/redwood/redwood.d.ts.map +1 -0
  69. package/lib/cloudflare/{redwood.js → redwood/redwood.js} +12 -13
  70. package/lib/cloudflare/redwood/redwood.js.map +1 -0
  71. package/lib/cloudflare/sveltekit/plugin.d.ts +4 -0
  72. package/lib/cloudflare/sveltekit/plugin.d.ts.map +1 -0
  73. package/lib/cloudflare/sveltekit/plugin.js +11 -0
  74. package/lib/cloudflare/sveltekit/plugin.js.map +1 -0
  75. package/lib/cloudflare/{sveltekit.d.ts → sveltekit/sveltekit.d.ts} +5 -5
  76. package/lib/cloudflare/sveltekit/sveltekit.d.ts.map +1 -0
  77. package/lib/cloudflare/{sveltekit.js → sveltekit/sveltekit.js} +4 -4
  78. package/lib/cloudflare/sveltekit/sveltekit.js.map +1 -0
  79. package/lib/cloudflare/{local-dev-cloudflare-shim.d.ts → tanstack-start/plugin.d.ts} +3 -2
  80. package/lib/cloudflare/tanstack-start/plugin.d.ts.map +1 -0
  81. package/lib/cloudflare/{local-dev-cloudflare-shim.js → tanstack-start/plugin.js} +6 -9
  82. package/lib/cloudflare/tanstack-start/plugin.js.map +1 -0
  83. package/lib/cloudflare/{tanstack-start.d.ts → tanstack-start/tanstack-start.d.ts} +5 -5
  84. package/lib/cloudflare/tanstack-start/tanstack-start.d.ts.map +1 -0
  85. package/lib/cloudflare/tanstack-start/tanstack-start.js +11 -0
  86. package/lib/cloudflare/tanstack-start/tanstack-start.js.map +1 -0
  87. package/lib/cloudflare/vite/plugin.d.ts +4 -0
  88. package/lib/cloudflare/vite/plugin.d.ts.map +1 -0
  89. package/lib/cloudflare/vite/plugin.js +23 -0
  90. package/lib/cloudflare/vite/plugin.js.map +1 -0
  91. package/lib/cloudflare/{vite.d.ts → vite/vite.d.ts} +4 -4
  92. package/lib/cloudflare/vite/vite.d.ts.map +1 -0
  93. package/lib/cloudflare/vite/vite.js +19 -0
  94. package/lib/cloudflare/vite/vite.js.map +1 -0
  95. package/lib/cloudflare/website.d.ts +92 -70
  96. package/lib/cloudflare/website.d.ts.map +1 -1
  97. package/lib/cloudflare/website.js +225 -94
  98. package/lib/cloudflare/website.js.map +1 -1
  99. package/lib/cloudflare/worker-bundle.d.ts +1 -1
  100. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  101. package/lib/cloudflare/worker-bundle.js +23 -13
  102. package/lib/cloudflare/worker-bundle.js.map +1 -1
  103. package/lib/cloudflare/worker-stub.d.ts.map +1 -1
  104. package/lib/cloudflare/worker-stub.js +3 -6
  105. package/lib/cloudflare/worker-stub.js.map +1 -1
  106. package/lib/cloudflare/worker.d.ts +2 -7
  107. package/lib/cloudflare/worker.d.ts.map +1 -1
  108. package/lib/cloudflare/worker.js +5 -124
  109. package/lib/cloudflare/worker.js.map +1 -1
  110. package/lib/cloudflare/wrangler.json.d.ts +6 -0
  111. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  112. package/lib/cloudflare/wrangler.json.js +23 -6
  113. package/lib/cloudflare/wrangler.json.js.map +1 -1
  114. package/lib/env.d.ts +2 -2
  115. package/lib/env.d.ts.map +1 -1
  116. package/lib/env.js +5 -6
  117. package/lib/env.js.map +1 -1
  118. package/lib/random/index.d.ts +2 -0
  119. package/lib/random/index.d.ts.map +1 -0
  120. package/lib/random/index.js +2 -0
  121. package/lib/random/index.js.map +1 -0
  122. package/lib/random/random-string.d.ts +87 -0
  123. package/lib/random/random-string.d.ts.map +1 -0
  124. package/lib/random/random-string.js +72 -0
  125. package/lib/random/random-string.js.map +1 -0
  126. package/lib/runtime/bind.d.ts +1 -1
  127. package/lib/runtime/bind.d.ts.map +1 -1
  128. package/lib/runtime/bind.js.map +1 -1
  129. package/lib/scope.d.ts +0 -1
  130. package/lib/scope.d.ts.map +1 -1
  131. package/lib/scope.js +1 -2
  132. package/lib/scope.js.map +1 -1
  133. package/lib/secret.d.ts +2 -2
  134. package/lib/secret.d.ts.map +1 -1
  135. package/lib/secret.js +2 -2
  136. package/lib/secret.js.map +1 -1
  137. package/lib/state/cloudflare-state-store.js +1 -1
  138. package/lib/state/cloudflare-state-store.js.map +1 -1
  139. package/lib/state/dofs-state-store/index.js +1 -1
  140. package/lib/state/dofs-state-store/index.js.map +1 -1
  141. package/lib/util/detect-package-manager.d.ts +1 -0
  142. package/lib/util/detect-package-manager.d.ts.map +1 -1
  143. package/lib/util/detect-package-manager.js +10 -0
  144. package/lib/util/detect-package-manager.js.map +1 -1
  145. package/lib/util/telemetry/client.d.ts +1 -1
  146. package/lib/util/telemetry/client.d.ts.map +1 -1
  147. package/lib/util/telemetry/client.js +22 -1
  148. package/lib/util/telemetry/client.js.map +1 -1
  149. package/lib/util/telemetry/constants.d.ts.map +1 -1
  150. package/lib/util/telemetry/constants.js +2 -3
  151. package/lib/util/telemetry/constants.js.map +1 -1
  152. package/lib/util/telemetry/context.d.ts +1 -1
  153. package/lib/util/telemetry/context.d.ts.map +1 -1
  154. package/lib/util/telemetry/types.d.ts +7 -3
  155. package/lib/util/telemetry/types.d.ts.map +1 -1
  156. package/lib/vercel/api.d.ts.map +1 -1
  157. package/lib/vercel/api.js +1 -1
  158. package/lib/vercel/api.js.map +1 -1
  159. package/package.json +41 -3
  160. package/src/apply.ts +3 -7
  161. package/src/cloudflare/{astro.ts → astro/astro.ts} +46 -29
  162. package/src/cloudflare/astro/plugin.ts +11 -0
  163. package/src/cloudflare/cloudflare-env-proxy.ts +50 -0
  164. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  165. package/src/cloudflare/d1-local-migrations.ts +1 -1
  166. package/src/cloudflare/index.ts +8 -8
  167. package/src/cloudflare/miniflare/miniflare-controller.ts +2 -1
  168. package/src/cloudflare/miniflare/paths.ts +52 -0
  169. package/src/cloudflare/{nuxt.ts → nuxt/nuxt.ts} +11 -16
  170. package/src/cloudflare/nuxt/plugin.ts +18 -0
  171. package/src/cloudflare/oauth.ts +2 -2
  172. package/src/cloudflare/orange.ts +13 -23
  173. package/src/cloudflare/react-router/plugin.ts +13 -0
  174. package/src/cloudflare/react-router/react-router.ts +41 -0
  175. package/src/cloudflare/redwood/plugin.ts +20 -0
  176. package/src/cloudflare/{redwood.ts → redwood/redwood.ts} +16 -19
  177. package/src/cloudflare/sveltekit/plugin.ts +12 -0
  178. package/src/cloudflare/{sveltekit.ts → sveltekit/sveltekit.ts} +9 -8
  179. package/src/cloudflare/{local-dev-cloudflare-shim.ts → tanstack-start/plugin.ts} +8 -9
  180. package/src/cloudflare/tanstack-start/tanstack-start.ts +24 -0
  181. package/src/cloudflare/vite/plugin.ts +30 -0
  182. package/src/cloudflare/vite/vite.ts +34 -0
  183. package/src/cloudflare/website.ts +379 -204
  184. package/src/cloudflare/worker-bundle.ts +27 -13
  185. package/src/cloudflare/worker-stub.ts +11 -14
  186. package/src/cloudflare/worker.ts +8 -155
  187. package/src/cloudflare/wrangler.json.ts +32 -4
  188. package/src/env.ts +8 -9
  189. package/src/random/index.ts +1 -0
  190. package/src/random/random-string.ts +126 -0
  191. package/src/runtime/bind.ts +2 -2
  192. package/src/scope.ts +1 -3
  193. package/src/secret.ts +4 -8
  194. package/src/state/cloudflare-state-store.ts +2 -2
  195. package/src/state/dofs-state-store/index.ts +1 -1
  196. package/src/util/detect-package-manager.ts +11 -0
  197. package/src/util/telemetry/client.ts +25 -2
  198. package/src/util/telemetry/constants.ts +2 -4
  199. package/src/util/telemetry/context.ts +1 -1
  200. package/src/util/telemetry/types.ts +8 -2
  201. package/src/vercel/api.ts +2 -4
  202. package/templates/astro/alchemy.run.ts +1 -3
  203. package/templates/astro/astro.config.mjs +2 -2
  204. package/templates/nuxt/alchemy.run.ts +1 -3
  205. package/templates/nuxt/nuxt.config.ts +4 -5
  206. package/templates/nuxt/package.json +0 -1
  207. package/templates/react-router/alchemy.run.ts +1 -4
  208. package/templates/react-router/vite.config.ts +2 -2
  209. package/templates/rwsdk/alchemy.run.ts +0 -1
  210. package/templates/rwsdk/package.json +0 -2
  211. package/templates/rwsdk/vite.config.mts +2 -2
  212. package/templates/sveltekit/alchemy.run.ts +1 -3
  213. package/templates/sveltekit/svelte.config.js +2 -2
  214. package/templates/tanstack-start/vite.config.ts +2 -2
  215. package/templates/vite/alchemy.run.ts +1 -1
  216. package/templates/vite/vite.config.ts +4 -5
  217. package/workers/cloudflare-state-store.js +12 -14
  218. package/lib/cloudflare/astro.d.ts.map +0 -1
  219. package/lib/cloudflare/astro.js +0 -69
  220. package/lib/cloudflare/astro.js.map +0 -1
  221. package/lib/cloudflare/local-dev-cloudflare-shim.d.ts.map +0 -1
  222. package/lib/cloudflare/local-dev-cloudflare-shim.js.map +0 -1
  223. package/lib/cloudflare/nuxt.d.ts.map +0 -1
  224. package/lib/cloudflare/nuxt.js.map +0 -1
  225. package/lib/cloudflare/react-router.d.ts +0 -17
  226. package/lib/cloudflare/react-router.d.ts.map +0 -1
  227. package/lib/cloudflare/react-router.js +0 -35
  228. package/lib/cloudflare/react-router.js.map +0 -1
  229. package/lib/cloudflare/redwood.d.ts.map +0 -1
  230. package/lib/cloudflare/redwood.js.map +0 -1
  231. package/lib/cloudflare/sveltekit.d.ts.map +0 -1
  232. package/lib/cloudflare/sveltekit.js.map +0 -1
  233. package/lib/cloudflare/tanstack-start.d.ts.map +0 -1
  234. package/lib/cloudflare/tanstack-start.js +0 -21
  235. package/lib/cloudflare/tanstack-start.js.map +0 -1
  236. package/lib/cloudflare/vite.d.ts.map +0 -1
  237. package/lib/cloudflare/vite.js +0 -20
  238. package/lib/cloudflare/vite.js.map +0 -1
  239. package/src/cloudflare/react-router.ts +0 -56
  240. package/src/cloudflare/tanstack-start.ts +0 -35
  241. package/src/cloudflare/vite.ts +0 -35
  242. package/templates/react-router/wrangler.jsonc +0 -6
  243. package/templates/rwsdk/wrangler.jsonc +0 -31
  244. package/templates/sveltekit/wrangler.jsonc +0 -7
  245. package/templates/tanstack-start/wrangler.jsonc +0 -7
  246. package/templates/typescript/index.ts +0 -1
  247. package/templates/vite/wrangler.jsonc +0 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemy",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Sam Goodwin <sam@alchemy.run>",
6
6
  "homepage": "https://alchemy.run",
@@ -61,6 +61,34 @@
61
61
  "bun": "./src/cloudflare/index.ts",
62
62
  "import": "./lib/cloudflare/index.js"
63
63
  },
64
+ "./cloudflare/astro": {
65
+ "bun": "./src/cloudflare/astro/plugin.ts",
66
+ "import": "./lib/cloudflare/astro/plugin.js"
67
+ },
68
+ "./cloudflare/nuxt": {
69
+ "bun": "./src/cloudflare/nuxt/plugin.ts",
70
+ "import": "./lib/cloudflare/nuxt/plugin.js"
71
+ },
72
+ "./cloudflare/redwood": {
73
+ "bun": "./src/cloudflare/redwood/plugin.ts",
74
+ "import": "./lib/cloudflare/redwood/plugin.js"
75
+ },
76
+ "./cloudflare/react-router": {
77
+ "bun": "./src/cloudflare/react-router/plugin.ts",
78
+ "import": "./lib/cloudflare/react-router/plugin.js"
79
+ },
80
+ "./cloudflare/sveltekit": {
81
+ "bun": "./src/cloudflare/sveltekit/plugin.ts",
82
+ "import": "./lib/cloudflare/sveltekit/plugin.js"
83
+ },
84
+ "./cloudflare/tanstack-start": {
85
+ "bun": "./src/cloudflare/tanstack-start/plugin.ts",
86
+ "import": "./lib/cloudflare/tanstack-start/plugin.js"
87
+ },
88
+ "./cloudflare/vite": {
89
+ "bun": "./src/cloudflare/vite/plugin.ts",
90
+ "import": "./lib/cloudflare/vite/plugin.js"
91
+ },
64
92
  "./dns": {
65
93
  "bun": "./src/dns/index.ts",
66
94
  "import": "./lib/dns/index.js"
@@ -93,6 +121,10 @@
93
121
  "bun": "./src/planetscale/index.ts",
94
122
  "import": "./lib/planetscale/index.js"
95
123
  },
124
+ "./random": {
125
+ "bun": "./src/random/index.ts",
126
+ "import": "./lib/random/index.js"
127
+ },
96
128
  "./sentry": {
97
129
  "bun": "./src/sentry/index.ts",
98
130
  "import": "./lib/sentry/index.js"
@@ -143,6 +175,7 @@
143
175
  "@swc/core": "^1.11.24",
144
176
  "aws4fetch": "^1.0.20",
145
177
  "diff": "^8.0.2",
178
+ "env-paths": "^3.0.0",
146
179
  "esbuild": "^0.25.1",
147
180
  "execa": "^9.6.0",
148
181
  "fast-json-patch": "^3.1.1",
@@ -160,7 +193,6 @@
160
193
  "turndown": "^7.0.0",
161
194
  "unenv": "2.0.0-rc.15",
162
195
  "ws": "^8.18.3",
163
- "xdg-app-paths": "^8.3.0",
164
196
  "yaml": "^2.0.0"
165
197
  },
166
198
  "peerDependencies": {
@@ -177,6 +209,7 @@
177
209
  "@aws-sdk/client-sqs": "^3.0.0",
178
210
  "@aws-sdk/client-ssm": "^3.0.0",
179
211
  "@aws-sdk/client-sts": "^3.0.0",
212
+ "@cloudflare/vite-plugin": "^1.10.1",
180
213
  "@libsql/client": "^0.15.9",
181
214
  "@octokit/rest": "^21.1.1",
182
215
  "ai": "^4.0.0",
@@ -199,6 +232,9 @@
199
232
  "@cloudflare/workers-types": "^4.20250620.0",
200
233
  "@iarna/toml": "^2.2.5",
201
234
  "@octokit/rest": "^21.1.1",
235
+ "@react-router/dev": "^7.7.1",
236
+ "@sveltejs/adapter-cloudflare": "^7.1.2",
237
+ "@sentry/cloudflare": "^9.43.0",
202
238
  "@types/bun": "latest",
203
239
  "@types/diff": "^5.0.0",
204
240
  "@types/fs-extra": "^11.0.4",
@@ -221,9 +257,11 @@
221
257
  "libsodium-wrappers": "^0.7.15",
222
258
  "listr2": "^8.0.0",
223
259
  "nitro-cloudflare-dev": "^0.2.2",
260
+ "nitropack": "^2.12.4",
224
261
  "openpgp": "^6.1.0",
225
262
  "picocolors": "^1.1.1",
226
263
  "prettier": "^3.5.3",
264
+ "rwsdk": "^0.1.28",
227
265
  "trpc-cli": "^0.10.0",
228
266
  "ts-morph": "^26.0.0",
229
267
  "tsdown": "^0.13.0",
@@ -233,7 +271,7 @@
233
271
  "typescript": "^5.8.3",
234
272
  "vite": "^6.0.7",
235
273
  "vitepress": "^1.6.3",
236
- "wrangler": "^3.114.0",
274
+ "wrangler": "^4.27.0",
237
275
  "yaml": "^2.7.1",
238
276
  "zod": "^4.0.10"
239
277
  }
package/src/apply.ts CHANGED
@@ -15,7 +15,6 @@ import {
15
15
  } from "./resource.ts";
16
16
  import { Scope, type PendingDeletions } from "./scope.ts";
17
17
  import { serialize } from "./serde.ts";
18
- import type { State } from "./state.ts";
19
18
  import { formatFQN } from "./util/cli.ts";
20
19
  import { logger } from "./util/logger.ts";
21
20
  import type { Telemetry } from "./util/telemetry/index.ts";
@@ -53,9 +52,7 @@ async function _apply<Out extends Resource>(
53
52
  try {
54
53
  const quiet = props?.quiet ?? scope.quiet;
55
54
  await scope.init();
56
- let state: State | undefined = (await scope.state.get(
57
- resource[ResourceID],
58
- ))!;
55
+ let state = await scope.state.get(resource[ResourceID]);
59
56
  const provider: Provider = PROVIDERS.get(resource[ResourceKind]);
60
57
  if (provider === undefined) {
61
58
  throw new Error(`Provider "${resource[ResourceKind]}" not found`);
@@ -280,17 +277,16 @@ async function _apply<Out extends Resource>(
280
277
  replaced: isReplaced,
281
278
  });
282
279
 
283
- state = (await scope.state.get(resource[ResourceID]))!;
280
+ state = await scope.state.get(resource[ResourceID]);
284
281
  await scope.state.set(resource[ResourceID], {
285
282
  kind: resource[ResourceKind],
286
283
  id: resource[ResourceID],
287
284
  fqn: resource[ResourceFQN],
288
285
  seq: resource[ResourceSeq],
289
- data: state.data,
286
+ data: state?.data ?? {}, // TODO: this used to be force-unwrapped but that was crashing for me - is this change ok?
290
287
  status,
291
288
  output,
292
289
  props,
293
- // deps: [...deps],
294
290
  });
295
291
  return output as any;
296
292
  } catch (error) {
@@ -1,15 +1,18 @@
1
- import path from "node:path";
2
- import type { Assets } from "./assets.ts";
3
- import type { Bindings } from "./bindings.ts";
4
- import type { WebsiteProps } from "./website.ts";
5
- import { Website } from "./website.ts";
6
- import type { Worker } from "./worker.ts";
1
+ import { join, resolve } from "node:path";
2
+ import { getPackageManagerRunner } from "../../util/detect-package-manager.ts";
3
+ import type { Assets } from "../assets.ts";
4
+ import type { Bindings } from "../bindings.ts";
5
+ import { Website, type WebsiteProps } from "../website.ts";
6
+ import type { Worker } from "../worker.ts";
7
7
 
8
8
  /**
9
9
  * Properties for creating an Astro resource.
10
10
  * Extends WebsiteProps, allowing customization of the underlying Website.
11
11
  */
12
- export interface AstroProps<B extends Bindings> extends WebsiteProps<B> {}
12
+ export interface AstroProps<B extends Bindings>
13
+ extends Omit<WebsiteProps<B>, "spa"> {
14
+ output?: "server" | "static";
15
+ }
13
16
 
14
17
  /**
15
18
  * Represents the output of an Astro resource deployment.
@@ -65,29 +68,43 @@ export async function Astro<B extends Bindings>(
65
68
  id: string,
66
69
  props: AstroProps<B> = {},
67
70
  ): Promise<Astro<B>> {
68
- if (props?.bindings?.ASSETS) {
69
- throw new Error("ASSETS binding is reserved for internal use");
70
- }
71
- const wrangler = props?.wrangler ?? true;
72
- const main = props?.main ?? path.join("dist", "_worker.js/index.js");
73
- const assetsDir =
74
- typeof props?.assets === "string"
75
- ? props?.assets
76
- : (props?.assets?.dist ?? "dist");
77
-
78
- return Website(id, {
71
+ const cwd = resolve(props.cwd ?? process.cwd());
72
+ const output = props.output ?? (await resolveOutputType(cwd));
73
+ const runner = await getPackageManagerRunner();
74
+ return await Website(id, {
79
75
  ...props,
80
- command: props.command ?? "astro build",
81
- dev: props.dev ?? {
82
- command: "astro dev",
83
- },
84
76
  noBundle: props.noBundle ?? true,
85
- main,
86
- assets: {
87
- dist: assetsDir,
88
- not_found_handling: "none",
89
- run_worker_first: false,
90
- },
91
- wrangler,
77
+ build: props.build ?? `${runner} astro build`,
78
+ dev: props.dev ?? `${runner} astro dev`,
79
+ entrypoint:
80
+ props.entrypoint ??
81
+ (output === "server" ? "dist/_worker.js/index.js" : undefined),
82
+ assets: props.assets ?? "dist",
92
83
  });
93
84
  }
85
+
86
+ async function resolveOutputType(cwd: string): Promise<"server" | "static"> {
87
+ const candidates = [
88
+ "astro.config.mjs",
89
+ "astro.config.js",
90
+ "astro.config.ts",
91
+ "astro.config.mts",
92
+ ];
93
+ for (const candidate of candidates) {
94
+ try {
95
+ const config = await import(join(cwd, candidate));
96
+ if (
97
+ typeof config.default === "object" &&
98
+ config.default &&
99
+ "output" in config.default &&
100
+ typeof config.default.output === "string"
101
+ ) {
102
+ return config.default.output;
103
+ }
104
+ return "static";
105
+ } catch {
106
+ // ignore
107
+ }
108
+ }
109
+ return "static";
110
+ }
@@ -0,0 +1,11 @@
1
+ import cloudflare, { type Options } from "@astrojs/cloudflare";
2
+ import { getPlatformProxyOptions } from "../cloudflare-env-proxy.ts";
3
+
4
+ const alchemy = (options?: Options) => {
5
+ return cloudflare({
6
+ platformProxy: getPlatformProxyOptions(options?.platformProxy),
7
+ ...options,
8
+ });
9
+ };
10
+
11
+ export default alchemy;
@@ -0,0 +1,50 @@
1
+ import type { GetPlatformProxyOptions } from "wrangler";
2
+ import {
3
+ DEFAULT_CONFIG_PATH,
4
+ DEFAULT_PERSIST_PATH,
5
+ validateConfigPath,
6
+ validatePersistPath,
7
+ } from "./miniflare/paths.ts";
8
+
9
+ export const getCloudflareEnvProxy = async <E>(
10
+ options: GetPlatformProxyOptions = {},
11
+ ) => {
12
+ const { getPlatformProxy } = await import("wrangler");
13
+ const config = getPlatformProxyOptions(options);
14
+ const proxy = await getPlatformProxy(config);
15
+ return proxy.env as E;
16
+ };
17
+
18
+ export const getPlatformProxyOptions = (
19
+ input: GetPlatformProxyOptions = {},
20
+ ): GetPlatformProxyOptions => {
21
+ const persist =
22
+ input.persist === false
23
+ ? false
24
+ : {
25
+ path: validatePersistPath(
26
+ typeof input.persist === "object" &&
27
+ typeof input.persist.path === "string"
28
+ ? input.persist.path
29
+ : DEFAULT_PERSIST_PATH,
30
+ ),
31
+ };
32
+ if (!persist) {
33
+ const message =
34
+ "[Alchemy] Persistence for local bindings is disabled. Some bindings may not work as expected. To enable, remove the \`persist\` option from getPlatformProxyOptions.";
35
+ if (!warned.has(message)) {
36
+ console.warn(message);
37
+ warned.add(message);
38
+ }
39
+ }
40
+ return {
41
+ ...input,
42
+ configPath: validateConfigPath(input.configPath ?? DEFAULT_CONFIG_PATH),
43
+ persist,
44
+ experimental: input.experimental ?? {
45
+ remoteBindings: true,
46
+ },
47
+ };
48
+ };
49
+
50
+ const warned = new Set<string>();
@@ -4,4 +4,4 @@
4
4
  /**
5
5
  * The default Cloudflare Workers compatibility date, set based on the latest workerd release at the time of build.
6
6
  */
7
- export const DEFAULT_COMPATIBILITY_DATE = "2025-08-02";
7
+ export const DEFAULT_COMPATIBILITY_DATE = "2025-08-03";
@@ -13,7 +13,7 @@ export const applyLocalD1Migrations = async (
13
13
  const miniflare = new mf.Miniflare({
14
14
  script: "",
15
15
  modules: true,
16
- defaultPersistRoot: path.join(process.cwd(), ".alchemy/miniflare"),
16
+ defaultPersistRoot: path.join(process.cwd(), ".alchemy/miniflare/v3"), // vite plugin forces /v3 suffix
17
17
  d1Persist: true,
18
18
  d1Databases: { DB: options.databaseId },
19
19
  log: process.env.DEBUG ? new mf.Log(mf.LogLevel.DEBUG) : undefined,
@@ -9,12 +9,13 @@ export * from "./api-schema.ts";
9
9
  export * from "./api-shield.ts";
10
10
  export * from "./api.ts";
11
11
  export * from "./assets.ts";
12
- export * from "./astro.ts";
12
+ export * from "./astro/astro.ts";
13
13
  export * from "./bindings.ts";
14
14
  export * from "./bound.ts";
15
15
  export * from "./browser-rendering.ts";
16
16
  export * from "./bucket.ts";
17
17
  export * from "./certificate-pack.ts";
18
+ export * from "./cloudflare-env-proxy.ts";
18
19
  export * from "./compatibility-date.gen.ts";
19
20
  export * from "./container.ts";
20
21
  export * from "./custom-domain.ts";
@@ -32,28 +33,27 @@ export * from "./email-rule.ts";
32
33
  export * from "./hyperdrive.ts";
33
34
  export * from "./images.ts";
34
35
  export * from "./kv-namespace.ts";
35
- export * from "./local-dev-cloudflare-shim.ts";
36
- export * from "./nuxt.ts";
36
+ export * from "./nuxt/nuxt.ts";
37
37
  export * from "./orange.ts";
38
38
  export * from "./permission-groups.ts";
39
39
  export * from "./pipeline.ts";
40
40
  export * from "./queue-consumer.ts";
41
41
  export * from "./queue.ts";
42
42
  export * from "./rate-limit.ts";
43
- export * from "./react-router.ts";
43
+ export * from "./react-router/react-router.ts";
44
44
  export * from "./redirect-rule.ts";
45
- export * from "./redwood.ts";
45
+ export * from "./redwood/redwood.ts";
46
46
  export * from "./route.ts";
47
47
  export * from "./secret-key.ts";
48
48
  export * from "./secret.ts";
49
49
  export * from "./secrets-store.ts";
50
50
  export * from "./state.ts";
51
- export * from "./sveltekit.ts";
52
- export * from "./tanstack-start.ts";
51
+ export * from "./sveltekit/sveltekit.ts";
52
+ export * from "./tanstack-start/tanstack-start.ts";
53
53
  export * from "./vectorize-index.ts";
54
54
  export * from "./vectorize-metadata-index.ts";
55
55
  export * from "./version-metadata.ts";
56
- export * from "./vite.ts";
56
+ export * from "./vite/vite.ts";
57
57
  export * from "./website.ts";
58
58
  export * from "./worker-ref.ts";
59
59
  export * from "./worker-stub.ts";
@@ -10,6 +10,7 @@ import {
10
10
  type MiniflareWorkerInput,
11
11
  } from "./build-worker-options.ts";
12
12
  import { MiniflareWorkerProxy } from "./miniflare-worker-proxy.ts";
13
+ import { DEFAULT_PERSIST_PATH } from "./paths.ts";
13
14
 
14
15
  declare global {
15
16
  var ALCHEMY_MINIFLARE_CONTROLLER: MiniflareController | undefined;
@@ -76,7 +77,7 @@ export class MiniflareController {
76
77
  return await this.mutex.lock(async () => {
77
78
  const options: miniflare.MiniflareOptions = {
78
79
  workers: Array.from(this.options.values()),
79
- defaultPersistRoot: path.join(process.cwd(), ".alchemy/miniflare"),
80
+ defaultPersistRoot: path.resolve(DEFAULT_PERSIST_PATH),
80
81
  unsafeDevRegistryPath: miniflare.getDefaultDevRegistryPath(),
81
82
  analyticsEngineDatasetsPersist: true,
82
83
  cachePersist: true,
@@ -0,0 +1,52 @@
1
+ import { existsSync, readlinkSync, statSync } from "node:fs";
2
+
3
+ export const DEFAULT_CONFIG_PATH = ".alchemy/local/wrangler.jsonc";
4
+ export const DEFAULT_PERSIST_PATH = ".alchemy/miniflare/v3";
5
+
6
+ export const validateConfigPath = (
7
+ path = DEFAULT_CONFIG_PATH,
8
+ throws = true,
9
+ ) => {
10
+ if (!existsSync(path)) {
11
+ warnOrThrow(
12
+ `The Wrangler config path, "${path}", could not be found. Please run \`alchemy dev\` or \`alchemy deploy\` to create it.`,
13
+ throws,
14
+ );
15
+ }
16
+ return path;
17
+ };
18
+
19
+ const DEFAULT_VALIDATE_PERSIST =
20
+ process.env.NODE_ENV === "development" ||
21
+ !process.argv.some((arg) => ["build", "prepare", "typegen"].includes(arg));
22
+
23
+ export const validatePersistPath = (
24
+ path = DEFAULT_PERSIST_PATH,
25
+ throws = DEFAULT_VALIDATE_PERSIST,
26
+ ) => {
27
+ try {
28
+ const stat = statSync(path);
29
+ if (stat.isSymbolicLink()) {
30
+ return readlinkSync(path);
31
+ }
32
+ return path;
33
+ } catch {
34
+ warnOrThrow(
35
+ `The Alchemy data path, "${path}", could not be resolved. This is required for Cloudflare bindings during development. Please run \`alchemy dev\` to create it.`,
36
+ throws,
37
+ );
38
+ return path;
39
+ }
40
+ };
41
+
42
+ const warned = new Set<string>();
43
+
44
+ const warnOrThrow = (message: string, throws: boolean) => {
45
+ if (throws) {
46
+ throw new Error(message);
47
+ }
48
+ if (!warned.has(message)) {
49
+ console.warn(message);
50
+ warned.add(message);
51
+ }
52
+ };
@@ -1,8 +1,9 @@
1
1
  import path from "node:path";
2
- import type { Assets } from "./assets.ts";
3
- import type { Bindings } from "./bindings.ts";
4
- import { Website, type WebsiteProps } from "./website.ts";
5
- import type { Worker } from "./worker.ts";
2
+ import { getPackageManagerRunner } from "../../util/detect-package-manager.ts";
3
+ import type { Assets } from "../assets.ts";
4
+ import type { Bindings } from "../bindings.ts";
5
+ import { Website, type WebsiteProps } from "../website.ts";
6
+ import type { Worker } from "../worker.ts";
6
7
 
7
8
  /**
8
9
  * Properties for creating a Nuxt resource.
@@ -50,22 +51,16 @@ export async function Nuxt<B extends Bindings>(
50
51
  id: string,
51
52
  props?: Partial<NuxtProps<B>>,
52
53
  ): Promise<Nuxt<B>> {
53
- // Call the underlying Website resource with Nuxt defaults
54
- return Website(id, {
54
+ const runner = await getPackageManagerRunner();
55
+ return await Website(id, {
55
56
  ...props,
56
57
  noBundle: props?.noBundle ?? true,
57
- // Default build command, can be overridden by props.command
58
- command: props?.command ?? "nuxt build",
58
+ build: props?.build ?? `${runner} nuxt build`,
59
+ dev: props?.dev ?? `${runner} nuxt dev`,
60
+ compatibility: "node",
59
61
  // Default entry point for cloudflare-module preset
60
- main: props?.main ?? "./.output/server/index.mjs",
62
+ entrypoint: props?.entrypoint ?? "./.output/server/index.mjs",
61
63
  // Default static assets directory for cloudflare-module preset
62
64
  assets: props?.assets ?? path.join(".output", "public"),
63
- // Ensure nodejs_compat flag is included for Nuxt compatibility
64
- compatibilityFlags: ["nodejs_compat", ...(props?.compatibilityFlags ?? [])],
65
- // Enable wrangler by default, common for Nuxt/Cloudflare deployments
66
- wrangler: props?.wrangler ?? true,
67
- dev: props?.dev ?? {
68
- command: "nuxt dev",
69
- },
70
65
  });
71
66
  }
@@ -0,0 +1,18 @@
1
+ import type { CloudflareOptions } from "nitropack/presets/cloudflare/types";
2
+ import { validateConfigPath, validatePersistPath } from "../miniflare/paths.ts";
3
+
4
+ const alchemy = (
5
+ options: Partial<CloudflareOptions> = {},
6
+ ): CloudflareOptions => {
7
+ return {
8
+ nodeCompat: true,
9
+ dev: {
10
+ configPath: validateConfigPath(options.dev?.configPath),
11
+ persistDir: validatePersistPath(options.dev?.persistDir),
12
+ ...options.dev,
13
+ },
14
+ ...options,
15
+ };
16
+ };
17
+
18
+ export default alchemy;
@@ -6,7 +6,7 @@ import fs from "node:fs/promises";
6
6
  import os from "node:os";
7
7
  import path from "node:path";
8
8
  import open from "open";
9
- import xdgAppPaths from "xdg-app-paths";
9
+ import envPaths from "env-paths";
10
10
  import { HTTPServer } from "../util/http.ts";
11
11
  import { memoize } from "../util/memoize.ts";
12
12
  import {
@@ -70,7 +70,7 @@ export const getRefreshedWranglerConfig = singleFlight(() =>
70
70
  );
71
71
 
72
72
  const getWranglerConfigPath = memoize(async () => {
73
- const xdgConfigDir = xdgAppPaths(".wrangler").config();
73
+ const xdgConfigDir = envPaths(".wrangler", { suffix: "" }).config;
74
74
  const legacyConfigDir = path.join(os.homedir(), ".wrangler");
75
75
  const configDir = (await fs
76
76
  .stat(legacyConfigDir)
@@ -1,9 +1,9 @@
1
1
  import type { Assets } from "./assets.js";
2
2
  import type { Bindings } from "./bindings.js";
3
- import { Website, type WebsiteProps } from "./website.js";
4
- import type { Worker } from "./worker.js";
3
+ import { Vite, type ViteProps } from "./vite/vite.ts";
4
+ import type { Worker } from "./worker.ts";
5
5
 
6
- export interface OrangeProps<B extends Bindings> extends WebsiteProps<B> {}
6
+ export interface OrangeProps<B extends Bindings> extends ViteProps<B> {}
7
7
 
8
8
  // don't allow the ASSETS to be overriden
9
9
  export type Orange<B extends Bindings> = B extends { ASSETS: any }
@@ -36,29 +36,19 @@ export type Orange<B extends Bindings> = B extends { ASSETS: any }
36
36
  */
37
37
  export async function Orange<B extends Bindings>(
38
38
  id: string,
39
- props?: Partial<OrangeProps<B>>,
39
+ props: Partial<OrangeProps<B>> = {},
40
40
  ): Promise<Orange<B>> {
41
- return Website(id, {
41
+ return await Vite(id, {
42
42
  ...props,
43
- command: props?.command ?? "vite build",
44
- dev: props?.dev ?? {
45
- command: "vite dev",
46
- },
47
- // The entrypoint and the Wrangler main must differ for the Cloudflare vite plugin
48
- // to bundle the application correctly, and alchemy must run our bundler on the Vite
49
- // output since we don't resolve vite imports.
50
- wrangler: props?.wrangler ?? {
43
+ noBundle: props.noBundle ?? true,
44
+ entrypoint: props.entrypoint ?? "dist/ssr/entry.server.js",
45
+ assets: props.assets ?? "dist/client",
46
+ compatibilityFlags: ["nodejs_compat", ...(props?.compatibilityFlags ?? [])],
47
+ wrangler: {
48
+ path: "wrangler.jsonc",
51
49
  main: "app/entry.server.ts",
50
+ secrets: false,
51
+ ...props.wrangler,
52
52
  },
53
- // Since we've already bundled the application with the build command, we can just
54
- // upload the modules in the `dist/srr` directory. With `noBundle: true`, any files
55
- // that match `**/*.js`, `**/*.mjs`, and `**/*.wasm` under the entrypoint's directory
56
- // (which is `dist/ssr`) will be uploaded to the worker so we don't need any explicit
57
- // module rules.
58
- noBundle: true,
59
- // `main` is used as the entrypoint in the Worker resource.
60
- main: props?.main ?? "dist/ssr/entry.server.js",
61
- assets: props?.assets ?? "dist/client",
62
- compatibilityFlags: ["nodejs_compat", ...(props?.compatibilityFlags ?? [])],
63
53
  });
64
54
  }
@@ -0,0 +1,13 @@
1
+ import type { PluginConfig } from "@cloudflare/vite-plugin";
2
+ import alchemyVite from "../vite/plugin.ts";
3
+
4
+ const alchemy = (config?: PluginConfig) => {
5
+ return alchemyVite({
6
+ ...config,
7
+ viteEnvironment: {
8
+ name: "ssr",
9
+ },
10
+ });
11
+ };
12
+
13
+ export default alchemy;
@@ -0,0 +1,41 @@
1
+ import { getPackageManagerRunner } from "../../util/detect-package-manager.ts";
2
+ import type { Assets } from "../assets.ts";
3
+ import type { Bindings } from "../bindings.ts";
4
+ import { Vite, type ViteProps } from "../vite/vite.ts";
5
+ import type { Worker } from "../worker.ts";
6
+
7
+ export interface ReactRouterProps<B extends Bindings> extends ViteProps<B> {
8
+ /**
9
+ * @default workers/app.ts
10
+ */
11
+ main?: string;
12
+ }
13
+
14
+ // don't allow the ASSETS to be overriden
15
+ export type ReactRouter<B extends Bindings> = B extends { ASSETS: any }
16
+ ? never
17
+ : Worker<B & { ASSETS: Assets }>;
18
+
19
+ export async function ReactRouter<B extends Bindings>(
20
+ id: string,
21
+ props: ReactRouterProps<B> = {},
22
+ ): Promise<ReactRouter<B>> {
23
+ const runner = await getPackageManagerRunner();
24
+ return await Vite(id, {
25
+ ...props,
26
+ build:
27
+ props.build ??
28
+ `${runner} react-router typegen && ${runner} react-router build`,
29
+ dev:
30
+ props.dev ??
31
+ `${runner} react-router typegen && ${runner} react-router dev`,
32
+ compatibility: "node",
33
+ entrypoint: props.entrypoint ?? "build/server/index.js",
34
+ noBundle: props.noBundle ?? true,
35
+ assets: props.assets ?? "build/client",
36
+ wrangler: {
37
+ main: props.wrangler?.main ?? props.main ?? "workers/app.ts",
38
+ transform: props.wrangler?.transform,
39
+ },
40
+ });
41
+ }
@@ -0,0 +1,20 @@
1
+ import { redwood, type RedwoodPluginOptions } from "rwsdk/vite";
2
+ import { DEFAULT_CONFIG_PATH } from "../miniflare/paths.ts";
3
+ import alchemyVite from "../vite/plugin.ts";
4
+
5
+ const alchemyRedwood = (options?: RedwoodPluginOptions) => {
6
+ const configPath = options?.configPath ?? DEFAULT_CONFIG_PATH;
7
+ return [
8
+ redwood({
9
+ ...options,
10
+ configPath,
11
+ includeCloudflarePlugin: false,
12
+ }),
13
+ alchemyVite({
14
+ configPath,
15
+ viteEnvironment: { name: "worker" },
16
+ }),
17
+ ];
18
+ };
19
+
20
+ export default alchemyRedwood;