alchemy 0.45.6 → 0.46.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 (346) hide show
  1. package/README.md +2 -2
  2. package/bin/alchemy.mjs +19285 -15137
  3. package/bin/alchemy.ts +14 -56
  4. package/bin/commands/create.ts +307 -137
  5. package/bin/commands/deploy.ts +23 -0
  6. package/bin/commands/destroy.ts +19 -0
  7. package/bin/commands/dev.ts +21 -0
  8. package/bin/commands/login.ts +66 -0
  9. package/bin/commands/run.ts +29 -0
  10. package/bin/services/dependencies.ts +0 -5
  11. package/bin/services/execute-alchemy.ts +160 -0
  12. package/bin/services/git.ts +27 -0
  13. package/bin/services/github-workflow.ts +229 -0
  14. package/bin/services/package-manager.ts +51 -68
  15. package/bin/services/template-manager.ts +10 -21
  16. package/bin/trpc.ts +3 -0
  17. package/bin/types.ts +4 -2
  18. package/lib/apply.d.ts +2 -0
  19. package/lib/apply.d.ts.map +1 -1
  20. package/lib/apply.js +26 -8
  21. package/lib/apply.js.map +1 -1
  22. package/lib/build-date.d.ts +1 -1
  23. package/lib/build-date.js +1 -1
  24. package/lib/cloudflare/ai.d.ts +8 -4
  25. package/lib/cloudflare/ai.d.ts.map +1 -1
  26. package/lib/cloudflare/ai.js +6 -8
  27. package/lib/cloudflare/ai.js.map +1 -1
  28. package/lib/cloudflare/analytics-engine.d.ts +11 -7
  29. package/lib/cloudflare/analytics-engine.d.ts.map +1 -1
  30. package/lib/cloudflare/analytics-engine.js +11 -9
  31. package/lib/cloudflare/analytics-engine.js.map +1 -1
  32. package/lib/cloudflare/{types.d.ts → api-response.d.ts} +6 -1
  33. package/lib/cloudflare/api-response.d.ts.map +1 -0
  34. package/lib/cloudflare/api-response.js +38 -0
  35. package/lib/cloudflare/api-response.js.map +1 -0
  36. package/lib/cloudflare/auth-wrangler.d.ts +25 -0
  37. package/lib/cloudflare/auth-wrangler.d.ts.map +1 -0
  38. package/lib/cloudflare/auth-wrangler.js +224 -0
  39. package/lib/cloudflare/auth-wrangler.js.map +1 -0
  40. package/lib/cloudflare/auth.d.ts.map +1 -1
  41. package/lib/cloudflare/auth.js +7 -116
  42. package/lib/cloudflare/auth.js.map +1 -1
  43. package/lib/cloudflare/browser-rendering.d.ts +12 -3
  44. package/lib/cloudflare/browser-rendering.d.ts.map +1 -1
  45. package/lib/cloudflare/browser-rendering.js +12 -2
  46. package/lib/cloudflare/browser-rendering.js.map +1 -1
  47. package/lib/cloudflare/bundle/fs.d.ts.map +1 -1
  48. package/lib/cloudflare/bundle/fs.js +3 -0
  49. package/lib/cloudflare/bundle/fs.js.map +1 -1
  50. package/lib/cloudflare/bundle/internal-worker-bundle.d.ts +6 -0
  51. package/lib/cloudflare/bundle/internal-worker-bundle.d.ts.map +1 -0
  52. package/lib/cloudflare/bundle/internal-worker-bundle.js +14 -0
  53. package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -0
  54. package/lib/cloudflare/compatibility-presets.d.ts +22 -0
  55. package/lib/cloudflare/compatibility-presets.d.ts.map +1 -0
  56. package/lib/cloudflare/compatibility-presets.js +27 -0
  57. package/lib/cloudflare/compatibility-presets.js.map +1 -0
  58. package/lib/cloudflare/container.d.ts +5 -1
  59. package/lib/cloudflare/container.d.ts.map +1 -1
  60. package/lib/cloudflare/container.js +42 -2
  61. package/lib/cloudflare/container.js.map +1 -1
  62. package/lib/cloudflare/dispatch-namespace.d.ts +5 -0
  63. package/lib/cloudflare/dispatch-namespace.d.ts.map +1 -1
  64. package/lib/cloudflare/dispatch-namespace.js +8 -0
  65. package/lib/cloudflare/dispatch-namespace.js.map +1 -1
  66. package/lib/cloudflare/durable-object-namespace.d.ts +23 -15
  67. package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -1
  68. package/lib/cloudflare/durable-object-namespace.js +22 -21
  69. package/lib/cloudflare/durable-object-namespace.js.map +1 -1
  70. package/lib/cloudflare/hyperdrive.d.ts +19 -5
  71. package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
  72. package/lib/cloudflare/hyperdrive.js +14 -0
  73. package/lib/cloudflare/hyperdrive.js.map +1 -1
  74. package/lib/cloudflare/images.d.ts +27 -17
  75. package/lib/cloudflare/images.d.ts.map +1 -1
  76. package/lib/cloudflare/images.js +13 -8
  77. package/lib/cloudflare/images.js.map +1 -1
  78. package/lib/cloudflare/index.d.ts +1 -3
  79. package/lib/cloudflare/index.d.ts.map +1 -1
  80. package/lib/cloudflare/index.js +1 -3
  81. package/lib/cloudflare/index.js.map +1 -1
  82. package/lib/cloudflare/miniflare/miniflare.d.ts +3 -3
  83. package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
  84. package/lib/cloudflare/miniflare/miniflare.js +7 -7
  85. package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
  86. package/lib/cloudflare/miniflare/{mixed-mode.d.ts → remote-binding-proxy.d.ts} +5 -5
  87. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -0
  88. package/lib/cloudflare/miniflare/{mixed-mode.js → remote-binding-proxy.js} +16 -52
  89. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -0
  90. package/lib/cloudflare/state.d.ts +26 -0
  91. package/lib/cloudflare/state.d.ts.map +1 -0
  92. package/lib/cloudflare/state.js +14 -0
  93. package/lib/cloudflare/state.js.map +1 -0
  94. package/lib/cloudflare/user.d.ts +2 -2
  95. package/lib/cloudflare/user.d.ts.map +1 -1
  96. package/lib/cloudflare/user.js +7 -21
  97. package/lib/cloudflare/user.js.map +1 -1
  98. package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
  99. package/lib/cloudflare/vectorize-index.js +5 -2
  100. package/lib/cloudflare/vectorize-index.js.map +1 -1
  101. package/lib/cloudflare/version-metadata.d.ts +15 -3
  102. package/lib/cloudflare/version-metadata.d.ts.map +1 -1
  103. package/lib/cloudflare/version-metadata.js +11 -2
  104. package/lib/cloudflare/version-metadata.js.map +1 -1
  105. package/lib/cloudflare/vite.d.ts.map +1 -1
  106. package/lib/cloudflare/vite.js +2 -1
  107. package/lib/cloudflare/vite.js.map +1 -1
  108. package/lib/cloudflare/worker-metadata.d.ts +13 -2
  109. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  110. package/lib/cloudflare/worker-metadata.js +10 -15
  111. package/lib/cloudflare/worker-metadata.js.map +1 -1
  112. package/lib/cloudflare/worker-subdomain.d.ts +7 -0
  113. package/lib/cloudflare/worker-subdomain.d.ts.map +1 -1
  114. package/lib/cloudflare/worker-subdomain.js +17 -22
  115. package/lib/cloudflare/worker-subdomain.js.map +1 -1
  116. package/lib/cloudflare/{worker/tail.d.ts → worker-tail.d.ts} +2 -2
  117. package/lib/cloudflare/worker-tail.d.ts.map +1 -0
  118. package/lib/cloudflare/{worker/tail.js → worker-tail.js} +11 -9
  119. package/lib/cloudflare/worker-tail.js.map +1 -0
  120. package/lib/cloudflare/worker.d.ts +18 -8
  121. package/lib/cloudflare/worker.d.ts.map +1 -1
  122. package/lib/cloudflare/worker.js +31 -7
  123. package/lib/cloudflare/worker.js.map +1 -1
  124. package/lib/cloudflare/workflow.d.ts +22 -11
  125. package/lib/cloudflare/workflow.d.ts.map +1 -1
  126. package/lib/cloudflare/workflow.js +23 -18
  127. package/lib/cloudflare/workflow.js.map +1 -1
  128. package/lib/context.d.ts +2 -2
  129. package/lib/context.d.ts.map +1 -1
  130. package/lib/docker/api.d.ts.map +1 -1
  131. package/lib/docker/api.js +30 -8
  132. package/lib/docker/api.js.map +1 -1
  133. package/lib/fs/file-system-state-store.d.ts +5 -20
  134. package/lib/fs/file-system-state-store.d.ts.map +1 -1
  135. package/lib/fs/file-system-state-store.js +5 -121
  136. package/lib/fs/file-system-state-store.js.map +1 -1
  137. package/lib/fs/index.d.ts +0 -1
  138. package/lib/fs/index.d.ts.map +1 -1
  139. package/lib/fs/index.js +0 -1
  140. package/lib/fs/index.js.map +1 -1
  141. package/lib/llms.cloudflare.txt +6 -5
  142. package/lib/planetscale/password.js +1 -1
  143. package/lib/planetscale/password.js.map +1 -1
  144. package/lib/scope.d.ts.map +1 -1
  145. package/lib/scope.js +3 -6
  146. package/lib/scope.js.map +1 -1
  147. package/lib/state/cloudflare-state-store.d.ts +34 -0
  148. package/lib/state/cloudflare-state-store.d.ts.map +1 -0
  149. package/lib/state/cloudflare-state-store.js +116 -0
  150. package/lib/state/cloudflare-state-store.js.map +1 -0
  151. package/lib/state/d1-state-store.d.ts +15 -0
  152. package/lib/state/d1-state-store.d.ts.map +1 -0
  153. package/lib/{cloudflare → state}/d1-state-store.js +31 -27
  154. package/lib/state/d1-state-store.js.map +1 -0
  155. package/lib/{cloudflare/do-state-store/types.d.ts → state/dofs-state-store/api.d.ts} +1 -1
  156. package/lib/state/dofs-state-store/api.d.ts.map +1 -0
  157. package/lib/state/dofs-state-store/api.js +1 -0
  158. package/lib/state/dofs-state-store/api.js.map +1 -0
  159. package/lib/{cloudflare/do-state-store/store.d.ts → state/dofs-state-store/index.d.ts} +10 -5
  160. package/lib/state/dofs-state-store/index.d.ts.map +1 -0
  161. package/lib/{cloudflare/do-state-store/store.js → state/dofs-state-store/index.js} +15 -11
  162. package/lib/state/dofs-state-store/index.js.map +1 -0
  163. package/lib/{cloudflare/do-state-store/internal.d.ts → state/dofs-state-store/store.d.ts} +4 -5
  164. package/lib/state/dofs-state-store/store.d.ts.map +1 -0
  165. package/lib/{cloudflare/do-state-store/internal.js → state/dofs-state-store/store.js} +7 -22
  166. package/lib/state/dofs-state-store/store.js.map +1 -0
  167. package/lib/state/file-system-state-store.d.ts +21 -0
  168. package/lib/state/file-system-state-store.d.ts.map +1 -0
  169. package/lib/state/file-system-state-store.js +122 -0
  170. package/lib/state/file-system-state-store.js.map +1 -0
  171. package/lib/state/index.d.ts +7 -0
  172. package/lib/state/index.d.ts.map +1 -0
  173. package/lib/state/index.js +7 -0
  174. package/lib/state/index.js.map +1 -0
  175. package/lib/state/migrations.d.ts +2 -0
  176. package/lib/state/migrations.d.ts.map +1 -0
  177. package/lib/state/migrations.js +3 -0
  178. package/lib/state/migrations.js.map +1 -0
  179. package/lib/state/operations.d.ts +36 -0
  180. package/lib/state/operations.d.ts.map +1 -0
  181. package/lib/state/operations.js +126 -0
  182. package/lib/state/operations.js.map +1 -0
  183. package/lib/state/proxy.d.ts +53 -0
  184. package/lib/state/proxy.d.ts.map +1 -0
  185. package/lib/state/proxy.js +65 -0
  186. package/lib/state/proxy.js.map +1 -0
  187. package/lib/{cloudflare → state}/r2-rest-state-store.d.ts +3 -1
  188. package/lib/state/r2-rest-state-store.d.ts.map +1 -0
  189. package/lib/{cloudflare → state}/r2-rest-state-store.js +6 -4
  190. package/lib/state/r2-rest-state-store.js.map +1 -0
  191. package/lib/state/schema.d.ts.map +1 -0
  192. package/lib/state/schema.js.map +1 -0
  193. package/lib/{sqlite → state}/sqlite-state-store.d.ts +5 -3
  194. package/lib/state/sqlite-state-store.d.ts.map +1 -0
  195. package/lib/{sqlite → state}/sqlite-state-store.js +15 -6
  196. package/lib/state/sqlite-state-store.js.map +1 -0
  197. package/lib/test/vitest.d.ts.map +1 -1
  198. package/lib/test/vitest.js +3 -6
  199. package/lib/test/vitest.js.map +1 -1
  200. package/lib/util/detect-node-runtime.d.ts +3 -0
  201. package/lib/util/detect-node-runtime.d.ts.map +1 -0
  202. package/lib/util/detect-node-runtime.js +10 -0
  203. package/lib/util/detect-node-runtime.js.map +1 -0
  204. package/lib/util/detect-package-manager.d.ts +2 -2
  205. package/lib/util/detect-package-manager.d.ts.map +1 -1
  206. package/lib/util/detect-package-manager.js +15 -5
  207. package/lib/util/detect-package-manager.js.map +1 -1
  208. package/lib/util/http-server.d.ts.map +1 -0
  209. package/lib/{cloudflare/miniflare → util}/http-server.js +1 -1
  210. package/lib/util/http-server.js.map +1 -0
  211. package/lib/util/memoize.d.ts +2 -0
  212. package/lib/util/memoize.d.ts.map +1 -1
  213. package/lib/util/memoize.js +14 -7
  214. package/lib/util/memoize.js.map +1 -1
  215. package/lib/util/neverthrow.d.ts +9 -0
  216. package/lib/util/neverthrow.d.ts.map +1 -0
  217. package/lib/util/neverthrow.js +29 -0
  218. package/lib/util/neverthrow.js.map +1 -0
  219. package/package.json +18 -16
  220. package/src/apply.ts +31 -10
  221. package/src/build-date.ts +1 -1
  222. package/src/cloudflare/ai.ts +10 -5
  223. package/src/cloudflare/analytics-engine.ts +20 -11
  224. package/src/cloudflare/{types.ts → api-response.ts} +31 -0
  225. package/src/cloudflare/auth-wrangler.ts +314 -0
  226. package/src/cloudflare/auth.ts +8 -156
  227. package/src/cloudflare/browser-rendering.ts +16 -2
  228. package/src/cloudflare/bundle/fs.ts +5 -0
  229. package/src/cloudflare/bundle/internal-worker-bundle.ts +21 -0
  230. package/src/cloudflare/compatibility-presets.ts +34 -0
  231. package/src/cloudflare/container.ts +70 -3
  232. package/src/cloudflare/dispatch-namespace.ts +28 -0
  233. package/src/cloudflare/durable-object-namespace.ts +38 -27
  234. package/src/cloudflare/hyperdrive.ts +19 -5
  235. package/src/cloudflare/images.ts +32 -17
  236. package/src/cloudflare/index.ts +1 -3
  237. package/src/cloudflare/miniflare/miniflare.ts +10 -7
  238. package/src/cloudflare/miniflare/{mixed-mode.ts → remote-binding-proxy.ts} +25 -75
  239. package/src/cloudflare/state.ts +35 -0
  240. package/src/cloudflare/user.ts +55 -70
  241. package/src/cloudflare/vectorize-index.ts +7 -2
  242. package/src/cloudflare/version-metadata.ts +19 -2
  243. package/src/cloudflare/vite.ts +2 -1
  244. package/src/cloudflare/worker-metadata.ts +18 -43
  245. package/src/cloudflare/worker-subdomain.ts +43 -37
  246. package/src/cloudflare/{worker/tail.ts → worker-tail.ts} +13 -10
  247. package/src/cloudflare/worker.ts +65 -19
  248. package/src/cloudflare/workflow.ts +38 -19
  249. package/src/context.ts +2 -2
  250. package/src/docker/api.ts +33 -8
  251. package/src/fs/file-system-state-store.ts +5 -148
  252. package/src/fs/index.ts +0 -1
  253. package/src/llms.cloudflare.txt +6 -5
  254. package/src/planetscale/password.ts +1 -1
  255. package/src/scope.ts +3 -6
  256. package/src/state/cloudflare-state-store.ts +170 -0
  257. package/src/state/d1-state-store.ts +102 -0
  258. package/src/{cloudflare/do-state-store/store.ts → state/dofs-state-store/index.ts} +20 -13
  259. package/src/{cloudflare/do-state-store/internal.ts → state/dofs-state-store/store.ts} +9 -27
  260. package/src/state/file-system-state-store.ts +149 -0
  261. package/src/state/index.ts +6 -0
  262. package/src/state/migrations.ts +9 -0
  263. package/src/state/operations.ts +152 -0
  264. package/src/state/proxy.ts +132 -0
  265. package/src/{cloudflare → state}/r2-rest-state-store.ts +11 -8
  266. package/src/{sqlite → state}/sqlite-state-store.ts +18 -10
  267. package/src/test/vitest.ts +8 -6
  268. package/src/util/detect-node-runtime.ts +12 -0
  269. package/src/util/detect-package-manager.ts +19 -6
  270. package/src/{cloudflare/miniflare → util}/http-server.ts +1 -1
  271. package/src/util/memoize.ts +18 -7
  272. package/src/util/neverthrow.ts +36 -0
  273. package/templates/astro/package.json +3 -3
  274. package/templates/nuxt/package.json +3 -3
  275. package/templates/react-router/package.json +3 -3
  276. package/templates/rwsdk/alchemy.run.ts +1 -1
  277. package/templates/rwsdk/package.json +3 -3
  278. package/templates/sveltekit/package.json +3 -3
  279. package/templates/tanstack-start/package.json +3 -3
  280. package/templates/typescript/package.json +3 -2
  281. package/templates/typescript/tsconfig.json +1 -0
  282. package/templates/vite/package.json +3 -3
  283. package/workers/cloudflare-state-store.js +5638 -0
  284. package/workers/cloudflare-state-store.ts +108 -0
  285. package/workers/{do-state-store.js → dofs-state-store.js} +4 -4
  286. package/workers/{do-state-store.ts → dofs-state-store.ts} +12 -8
  287. package/workers/{mixed-mode-proxy-worker.js → remote-binding-proxy.js} +3 -3
  288. package/workers/remote-binding-proxy.ts +45 -0
  289. package/lib/cloudflare/d1-state-store.d.ts +0 -10
  290. package/lib/cloudflare/d1-state-store.d.ts.map +0 -1
  291. package/lib/cloudflare/d1-state-store.js.map +0 -1
  292. package/lib/cloudflare/do-state-store/index.d.ts +0 -2
  293. package/lib/cloudflare/do-state-store/index.d.ts.map +0 -1
  294. package/lib/cloudflare/do-state-store/index.js +0 -2
  295. package/lib/cloudflare/do-state-store/index.js.map +0 -1
  296. package/lib/cloudflare/do-state-store/internal.d.ts.map +0 -1
  297. package/lib/cloudflare/do-state-store/internal.js.map +0 -1
  298. package/lib/cloudflare/do-state-store/store.d.ts.map +0 -1
  299. package/lib/cloudflare/do-state-store/store.js.map +0 -1
  300. package/lib/cloudflare/do-state-store/types.d.ts.map +0 -1
  301. package/lib/cloudflare/do-state-store/types.js +0 -1
  302. package/lib/cloudflare/do-state-store/types.js.map +0 -1
  303. package/lib/cloudflare/miniflare/http-server.d.ts.map +0 -1
  304. package/lib/cloudflare/miniflare/http-server.js.map +0 -1
  305. package/lib/cloudflare/miniflare/mixed-mode.d.ts.map +0 -1
  306. package/lib/cloudflare/miniflare/mixed-mode.js.map +0 -1
  307. package/lib/cloudflare/r2-rest-state-store.d.ts.map +0 -1
  308. package/lib/cloudflare/r2-rest-state-store.js.map +0 -1
  309. package/lib/cloudflare/types.d.ts.map +0 -1
  310. package/lib/cloudflare/types.js +0 -19
  311. package/lib/cloudflare/types.js.map +0 -1
  312. package/lib/cloudflare/worker/shared.d.ts +0 -4
  313. package/lib/cloudflare/worker/shared.d.ts.map +0 -1
  314. package/lib/cloudflare/worker/shared.js +0 -21
  315. package/lib/cloudflare/worker/shared.js.map +0 -1
  316. package/lib/cloudflare/worker/tail.d.ts.map +0 -1
  317. package/lib/cloudflare/worker/tail.js.map +0 -1
  318. package/lib/sqlite/base-sqlite-state-store.d.ts +0 -31
  319. package/lib/sqlite/base-sqlite-state-store.d.ts.map +0 -1
  320. package/lib/sqlite/base-sqlite-state-store.js +0 -124
  321. package/lib/sqlite/base-sqlite-state-store.js.map +0 -1
  322. package/lib/sqlite/index.d.ts +0 -2
  323. package/lib/sqlite/index.d.ts.map +0 -1
  324. package/lib/sqlite/index.js +0 -2
  325. package/lib/sqlite/index.js.map +0 -1
  326. package/lib/sqlite/schema.d.ts.map +0 -1
  327. package/lib/sqlite/schema.js.map +0 -1
  328. package/lib/sqlite/sqlite-state-store.d.ts.map +0 -1
  329. package/lib/sqlite/sqlite-state-store.js.map +0 -1
  330. package/src/cloudflare/d1-state-store.ts +0 -105
  331. package/src/cloudflare/do-state-store/index.ts +0 -1
  332. package/src/cloudflare/worker/shared.ts +0 -30
  333. package/src/sqlite/base-sqlite-state-store.ts +0 -199
  334. package/src/sqlite/index.ts +0 -1
  335. package/templates/typescript/src/worker.js +0 -5
  336. package/workers/mixed-mode-proxy-worker.ts +0 -46
  337. /package/drizzle/{0000_busy_mauler.sql → default/0000_busy_mauler.sql} +0 -0
  338. /package/drizzle/{0001_concerned_iceman.sql → default/0001_concerned_iceman.sql} +0 -0
  339. /package/drizzle/{meta → default/meta}/0000_snapshot.json +0 -0
  340. /package/drizzle/{meta → default/meta}/0001_snapshot.json +0 -0
  341. /package/drizzle/{meta → default/meta}/_journal.json +0 -0
  342. /package/lib/{sqlite → state}/schema.d.ts +0 -0
  343. /package/lib/{sqlite → state}/schema.js +0 -0
  344. /package/lib/{cloudflare/miniflare → util}/http-server.d.ts +0 -0
  345. /package/src/{cloudflare/do-state-store/types.ts → state/dofs-state-store/api.ts} +0 -0
  346. /package/src/{sqlite → state}/schema.ts +0 -0
@@ -0,0 +1,21 @@
1
+ import z from "zod";
2
+ import {
3
+ entrypoint,
4
+ execAlchemy,
5
+ execArgs,
6
+ } from "../services/execute-alchemy.ts";
7
+ import { t } from "../trpc.ts";
8
+
9
+ export const dev = t.procedure
10
+ .meta({
11
+ description:
12
+ "Run an Alchemy program in dev-mode (local simulation & hot reloading)",
13
+ })
14
+ .input(z.tuple([entrypoint, z.object(execArgs)]))
15
+ .mutation(async ({ input: [main, options] }) =>
16
+ execAlchemy(main, {
17
+ ...options,
18
+ dev: true,
19
+ watch: true,
20
+ }),
21
+ );
@@ -0,0 +1,66 @@
1
+ import { cancel, intro, log, outro } from "@clack/prompts";
2
+ import pc from "picocolors";
3
+ import z from "zod";
4
+ import {
5
+ DEFAULT_SCOPES,
6
+ wranglerLogin,
7
+ } from "../../src/cloudflare/auth-wrangler.ts";
8
+ import { throwWithContext } from "../errors.ts";
9
+ import { t } from "../trpc.ts";
10
+
11
+ export const login = t.procedure
12
+ .meta({
13
+ description: "Login to Cloudflare",
14
+ })
15
+ .input(
16
+ z.tuple([
17
+ z.object({
18
+ scopes: z
19
+ .array(z.string())
20
+ .optional()
21
+ .default([])
22
+ .describe("Cloudflare OAuth scopes to authorize"),
23
+ defaultScopes: z
24
+ .boolean()
25
+ .optional()
26
+ .default(true)
27
+ .describe(
28
+ "Whether to include the default Wrangler scopes when authenticating",
29
+ ),
30
+ }),
31
+ ]),
32
+ )
33
+ .mutation(async ({ input: [options] }) => {
34
+ try {
35
+ intro(pc.cyan("🔐 Cloudflare Login"));
36
+
37
+ const scopes = options.defaultScopes
38
+ ? Array.from(new Set([...DEFAULT_SCOPES, ...options.scopes]))
39
+ : options.scopes;
40
+ if (scopes.length === 0) {
41
+ cancel(
42
+ "No scopes provided. Please provide at least one scope or remove the --exclude-default-scopes flag.",
43
+ );
44
+ return;
45
+ }
46
+ const result = await wranglerLogin(scopes, (message) => {
47
+ log.step(message);
48
+ });
49
+
50
+ if (result.isErr()) {
51
+ throwWithContext(result.error, "Login failed");
52
+ }
53
+
54
+ outro(pc.green("✅ Login successful!"));
55
+ } catch (error) {
56
+ if (error instanceof Error) {
57
+ log.error(`${pc.red("Error:")} ${error.message}`);
58
+ if (error.stack && process.env.DEBUG) {
59
+ log.error(`${pc.gray("Stack trace:")}\n${error.stack}`);
60
+ }
61
+ } else {
62
+ log.error(pc.red(String(error)));
63
+ }
64
+ process.exit(1);
65
+ }
66
+ });
@@ -0,0 +1,29 @@
1
+ import z from "zod";
2
+ import {
3
+ entrypoint,
4
+ execAlchemy,
5
+ execArgs,
6
+ watch,
7
+ } from "../services/execute-alchemy.ts";
8
+ import { t } from "../trpc.ts";
9
+
10
+ export const run = t.procedure
11
+ .meta({
12
+ description:
13
+ "Run an Alchemy program with read-only access to your infrastructure (no changes will be applied)",
14
+ })
15
+ .input(
16
+ z.tuple([
17
+ entrypoint,
18
+ z.object({
19
+ ...execArgs,
20
+ watch,
21
+ }),
22
+ ]),
23
+ )
24
+ .mutation(async ({ input: [main, options] }) =>
25
+ execAlchemy(main, {
26
+ ...options,
27
+ read: true,
28
+ }),
29
+ );
@@ -1,4 +1,3 @@
1
- import { log } from "@clack/prompts";
2
1
  import fs from "fs-extra";
3
2
  import path from "node:path";
4
3
 
@@ -25,8 +24,6 @@ export const addPackageDependencies = async (opts: {
25
24
  const version = dependencyVersionMap[pkgName];
26
25
  if (version) {
27
26
  pkgJson.dependencies[pkgName] = version;
28
- } else {
29
- log.warn(`Warning: Dependency ${pkgName} not found in version map.`);
30
27
  }
31
28
  }
32
29
 
@@ -34,8 +31,6 @@ export const addPackageDependencies = async (opts: {
34
31
  const version = dependencyVersionMap[pkgName];
35
32
  if (version) {
36
33
  pkgJson.devDependencies[pkgName] = version;
37
- } else {
38
- log.warn(`Warning: Dev dependency ${pkgName} not found in version map.`);
39
34
  }
40
35
  }
41
36
 
@@ -0,0 +1,160 @@
1
+ import { log } from "@clack/prompts";
2
+ import { execa } from "execa";
3
+ import { resolve } from "node:path";
4
+ import pc from "picocolors";
5
+ import z from "zod";
6
+ import { detectRuntime } from "../../src/util/detect-node-runtime.ts";
7
+ import { detectPackageManager } from "../../src/util/detect-package-manager.ts";
8
+ import { exists } from "../../src/util/exists.ts";
9
+
10
+ export const entrypoint = z
11
+ .string()
12
+ .optional()
13
+ .describe(
14
+ "Path to the entrypoint file. Defaults to ./alchemy.run.ts > ./alchemy.run.js",
15
+ );
16
+
17
+ export const watch = z
18
+ .boolean()
19
+ .optional()
20
+ .default(false)
21
+ .describe("Watch for changes to infrastructure and redeploy automatically");
22
+
23
+ export const execArgs = {
24
+ cwd: z
25
+ .string()
26
+ .optional()
27
+ .describe("Path to the project directory (defaults to current directory)"),
28
+ quiet: z
29
+ .boolean()
30
+ .optional()
31
+ .default(false)
32
+ .describe("Suppress Create/Update/Delete messages"),
33
+ stage: z
34
+ .string()
35
+ .optional()
36
+ .describe(
37
+ "Specify which stage/environment to target. Defaults to your username ($USER, or $USERNAME on windows)",
38
+ ),
39
+ envFile: z.string().optional().describe("Path to environment file to load"),
40
+ } as const;
41
+
42
+ export async function execAlchemy(
43
+ main: string | undefined,
44
+ {
45
+ cwd = process.cwd(),
46
+ quiet,
47
+ stage,
48
+ destroy,
49
+ watch,
50
+ envFile,
51
+ read,
52
+ dev,
53
+ }: {
54
+ cwd?: string;
55
+ quiet?: boolean;
56
+ stage?: string;
57
+ destroy?: boolean;
58
+ watch?: boolean;
59
+ envFile?: string;
60
+ read?: boolean;
61
+ dev?: boolean;
62
+ },
63
+ ) {
64
+ const args: string[] = [];
65
+ const execArgs: string[] = [];
66
+ if (quiet) args.push("--quiet");
67
+ if (read) args.push("--read");
68
+ if (stage) args.push(`--stage ${stage}`);
69
+ if (destroy) args.push("--destroy");
70
+ if (watch) execArgs.push("--watch");
71
+ if (envFile) execArgs.push(`--env-file ${envFile}`);
72
+ if (dev) args.push("--dev");
73
+
74
+ // Check for alchemy.run.ts or alchemy.run.js (if not provided)
75
+ if (!main) {
76
+ const candidates = ["alchemy.run.ts", "alchemy.run.js"];
77
+ for (const file of candidates) {
78
+ const resolved = resolve(cwd, file);
79
+ if (await exists(resolved)) {
80
+ main = resolved;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+
86
+ if (!main) {
87
+ log.error(
88
+ pc.red(
89
+ "No alchemy.run.ts or alchemy.run.js file found in the current directory.",
90
+ ),
91
+ );
92
+ log.info("Create an alchemy.run.ts file to define your infrastructure.");
93
+ process.exit(1);
94
+ }
95
+
96
+ // Detect package manager
97
+ const packageManager = await detectPackageManager(cwd);
98
+ const runtime = detectRuntime();
99
+
100
+ const argsString = args.join(" ");
101
+ const execArgsString = execArgs.join(" ");
102
+ // Determine the command to run based on package manager and file extension
103
+ let command: string;
104
+ const isTypeScript = main.endsWith(".ts");
105
+
106
+ switch (packageManager) {
107
+ case "bun":
108
+ command = `bun ${execArgsString} ${main} ${argsString}`;
109
+ break;
110
+ case "deno":
111
+ command = `deno run -A ${execArgsString} ${main} ${argsString}`;
112
+ break;
113
+ case "pnpm":
114
+ command = isTypeScript
115
+ ? `pnpm tsx ${execArgsString} ${main} ${argsString}`
116
+ : `pnpm node ${execArgsString} ${main} ${argsString}`;
117
+ break;
118
+ case "yarn":
119
+ command = isTypeScript
120
+ ? `yarn tsx ${execArgsString} ${main} ${argsString}`
121
+ : `yarn node ${execArgsString} ${main} ${argsString}`;
122
+ break;
123
+ default:
124
+ switch (runtime) {
125
+ case "bun":
126
+ command = `bun ${execArgsString} ${main} ${argsString}`;
127
+ break;
128
+ case "deno":
129
+ command = `deno run -A ${execArgsString} ${main} ${argsString}`;
130
+ break;
131
+ case "node":
132
+ command = isTypeScript
133
+ ? `npx tsx ${execArgsString} ${main} ${argsString}`
134
+ : `node ${execArgsString} ${main} ${argsString}`;
135
+ break;
136
+ }
137
+ }
138
+
139
+ try {
140
+ console.log(command);
141
+ await execa(command, {
142
+ cwd,
143
+ shell: true,
144
+ stdio: "inherit",
145
+ env: {
146
+ ...process.env,
147
+ FORCE_COLOR: "1",
148
+ },
149
+ });
150
+ } catch (error: any) {
151
+ log.error(pc.red(`Deploy failed: ${error.message}`));
152
+ if (error.stdout) {
153
+ console.log(error.stdout);
154
+ }
155
+ if (error.stderr) {
156
+ console.error(error.stderr);
157
+ }
158
+ process.exit(1);
159
+ }
160
+ }
@@ -0,0 +1,27 @@
1
+ import { $ } from "execa";
2
+
3
+ import { throwWithContext } from "../errors.ts";
4
+ import type { ProjectContext } from "../types.ts";
5
+
6
+ export async function isGitInstalled(): Promise<boolean> {
7
+ try {
8
+ await $`git --version`;
9
+ return true;
10
+ } catch {
11
+ return false;
12
+ }
13
+ }
14
+
15
+ export async function initializeGitRepo(
16
+ context: ProjectContext,
17
+ ): Promise<void> {
18
+ const cwd = context.path;
19
+
20
+ try {
21
+ await $({ cwd })`git init`;
22
+ await $({ cwd })`git add -A`;
23
+ await $({ cwd })`git commit -m ${"initial commit"}`;
24
+ } catch (error) {
25
+ throwWithContext(error, "Git initialisation failed");
26
+ }
27
+ }
@@ -0,0 +1,229 @@
1
+ import { spinner } from "@clack/prompts";
2
+ import * as fs from "fs-extra";
3
+ import path from "node:path";
4
+ import { throwWithContext } from "../errors.ts";
5
+ import type { ProjectContext } from "../types.ts";
6
+
7
+ export async function addGitHubWorkflowToAlchemy(
8
+ context: ProjectContext,
9
+ ): Promise<void> {
10
+ const alchemyFilePath = path.join(context.path, "alchemy.run.ts");
11
+
12
+ const s = spinner();
13
+ s.start("Setting up GitHub Actions...");
14
+
15
+ try {
16
+ const workflowDir = path.join(context.path, ".github", "workflows");
17
+ await fs.ensureDir(workflowDir);
18
+
19
+ const prPreviewWorkflow = `name: Preview
20
+
21
+ on:
22
+ pull_request:
23
+ types: [opened, reopened, synchronize, closed]
24
+
25
+ # Ensure only one workflow runs at a time per PR
26
+ concurrency:
27
+ group: "pr-preview-\${{ github.event.pull_request.number }}"
28
+ cancel-in-progress: false
29
+
30
+ jobs:
31
+ deploy-preview:
32
+ if: \${{ github.event.action != 'closed' }}
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ contents: read
36
+ pull-requests: write
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - name: Setup Bun
41
+ uses: oven-sh/setup-bun@v1
42
+ with:
43
+ bun-version: latest
44
+
45
+ - name: Install dependencies
46
+ shell: bash
47
+ run: bun install
48
+
49
+ - name: Deploy Preview
50
+ run: bun run deploy
51
+ env:
52
+ BRANCH_PREFIX: pr-\${{ github.event.pull_request.number }}
53
+ GITHUB_SHA: \${{ github.event.pull_request.head.sha }}
54
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
55
+ GITHUB_REPOSITORY_OWNER: \${{ github.repository_owner }}
56
+ GITHUB_REPOSITORY_NAME: \${{ github.event.repository.name }}
57
+ PULL_REQUEST: \${{ github.event.pull_request.number }}
58
+ CLOUDFLARE_API_TOKEN: \${{ secrets.CLOUDFLARE_API_TOKEN }}
59
+ CLOUDFLARE_ACCOUNT_ID: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
60
+
61
+ cleanup-preview:
62
+ if: \${{ github.event.action == 'closed' }}
63
+ runs-on: ubuntu-latest
64
+ permissions:
65
+ contents: read
66
+ pull-requests: write
67
+ steps:
68
+ - uses: actions/checkout@v4
69
+
70
+ - name: Setup Bun
71
+ uses: oven-sh/setup-bun@v1
72
+ with:
73
+ bun-version: latest
74
+
75
+ - name: Install dependencies
76
+ shell: bash
77
+ run: bun install
78
+
79
+ - name: Cleanup Preview
80
+ run: bun run destroy
81
+ env:
82
+ BRANCH_PREFIX: pr-\${{ github.event.pull_request.number }}
83
+ GITHUB_SHA: \${{ github.event.pull_request.head.sha }}
84
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
85
+ GITHUB_REPOSITORY_OWNER: \${{ github.repository_owner }}
86
+ GITHUB_REPOSITORY_NAME: \${{ github.event.repository.name }}
87
+ PULL_REQUEST: \${{ github.event.pull_request.number }}
88
+ CLOUDFLARE_API_TOKEN: \${{ secrets.CLOUDFLARE_API_TOKEN }}
89
+ CLOUDFLARE_ACCOUNT_ID: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
90
+ `;
91
+
92
+ const publishWorkflow = `name: Publish
93
+
94
+ on:
95
+ push:
96
+ branches: [main]
97
+
98
+ # Ensure only one workflow runs at a time
99
+ concurrency:
100
+ group: "publish"
101
+ cancel-in-progress: false
102
+
103
+ jobs:
104
+ publish:
105
+ runs-on: ubuntu-latest
106
+ permissions:
107
+ contents: read
108
+ steps:
109
+ - uses: actions/checkout@v4
110
+
111
+ - name: Setup Bun
112
+ uses: oven-sh/setup-bun@v1
113
+ with:
114
+ bun-version: latest
115
+
116
+ - name: Install dependencies
117
+ shell: bash
118
+ run: bun install
119
+
120
+ - name: Deploy to Production
121
+ run: bun run deploy
122
+ env:
123
+ STAGE: prod
124
+ GITHUB_SHA: \${{ github.sha }}
125
+ CLOUDFLARE_API_TOKEN: \${{ secrets.CLOUDFLARE_API_TOKEN }}
126
+ CLOUDFLARE_ACCOUNT_ID: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
127
+ `;
128
+
129
+ await fs.writeFile(
130
+ path.join(workflowDir, "pr-preview.yml"),
131
+ prPreviewWorkflow,
132
+ );
133
+ await fs.writeFile(path.join(workflowDir, "publish.yml"), publishWorkflow);
134
+
135
+ let code = await fs.readFile(alchemyFilePath, "utf-8");
136
+
137
+ const alchemyImportRegex = /(import alchemy from "alchemy";)/;
138
+ const alchemyImportMatch = code.match(alchemyImportRegex);
139
+ if (alchemyImportMatch) {
140
+ const githubImport = '\nimport { GitHubComment } from "alchemy/github";';
141
+ code = code.replace(alchemyImportRegex, `$1${githubImport}`);
142
+ }
143
+
144
+ const lastImportRegex = /import[^;]+from[^;]+;(\s*\n)*/g;
145
+ let lastImportMatch;
146
+ let lastImportEnd = 0;
147
+
148
+ while ((lastImportMatch = lastImportRegex.exec(code)) !== null) {
149
+ lastImportEnd = lastImportMatch.index + lastImportMatch[0].length;
150
+ }
151
+
152
+ if (lastImportEnd > 0) {
153
+ const stageVariable = `
154
+ const stage = process.env.STAGE || process.env.BRANCH_PREFIX || "dev";
155
+ `;
156
+ code =
157
+ code.slice(0, lastImportEnd) +
158
+ stageVariable +
159
+ code.slice(lastImportEnd);
160
+ }
161
+
162
+ const appCallRegex = /const app = await alchemy\("([^"]+)"\);/;
163
+ const appMatch = code.match(appCallRegex);
164
+ if (appMatch) {
165
+ const appName = appMatch[1];
166
+ code = code.replace(
167
+ appCallRegex,
168
+ `const app = await alchemy("${appName}", {
169
+ stage,
170
+ });`,
171
+ );
172
+ }
173
+
174
+ const cloudflareResourceRegex =
175
+ /(await (?:Worker|TanStackStart|Nuxt|Astro|Website|SvelteKit|Redwood|ReactRouter|Vite)\([^,]+,\s*{[^}]*)(}\);)/g;
176
+ code = code.replace(
177
+ cloudflareResourceRegex,
178
+ (match, beforeClosing, closing) => {
179
+ if (beforeClosing.includes("version:")) {
180
+ return match;
181
+ }
182
+
183
+ const hasTrailingComma = beforeClosing.trim().endsWith(",");
184
+ const versionProp = hasTrailingComma
185
+ ? ` version: stage === "prod" ? undefined : stage,\n`
186
+ : `,\n version: stage === "prod" ? undefined : stage,\n`;
187
+
188
+ return beforeClosing + versionProp + closing;
189
+ },
190
+ );
191
+
192
+ const finalizeRegex = /(await app\.finalize\(\);)/;
193
+ const finalizeMatch = code.match(finalizeRegex);
194
+ if (finalizeMatch) {
195
+ const githubWorkflowCode = `
196
+ if (process.env.PULL_REQUEST) {
197
+ const previewUrl = worker.url;
198
+
199
+ await GitHubComment("pr-preview-comment", {
200
+ owner: process.env.GITHUB_REPOSITORY_OWNER || "your-username",
201
+ repository: process.env.GITHUB_REPOSITORY_NAME || "${context.name}",
202
+ issueNumber: Number(process.env.PULL_REQUEST),
203
+ body: \`
204
+ ## 🚀 Preview Deployed
205
+
206
+ Your preview is ready!
207
+
208
+ **Preview URL:** \${previewUrl}
209
+
210
+ This preview was built from commit \${process.env.GITHUB_SHA}
211
+
212
+ ---
213
+ <sub>🤖 This comment will be updated automatically when you push new commits to this PR.</sub>\`,
214
+ });
215
+ }
216
+
217
+ `;
218
+
219
+ code = code.replace(finalizeRegex, `${githubWorkflowCode}$1`);
220
+ }
221
+
222
+ await fs.writeFile(alchemyFilePath, code, "utf-8");
223
+
224
+ s.stop("GitHub Actions configured");
225
+ } catch (error) {
226
+ s.stop("GitHub Actions setup failed");
227
+ throwWithContext(error, "Failed to add GitHub workflow setup");
228
+ }
229
+ }
@@ -1,70 +1,54 @@
1
- import { log } from "@clack/prompts";
2
1
  import { execa } from "execa";
3
- import * as fs from "fs-extra";
4
- import type { PackageManager, ProjectContext } from "../types.ts";
2
+ import { throwWithContext } from "../errors.ts";
3
+ import type { ProjectContext } from "../types.ts";
5
4
 
6
- export function detectPackageManager(): PackageManager {
7
- if (fs.pathExistsSync("bun.lockb")) return "bun";
8
- if (fs.pathExistsSync("pnpm-lock.yaml")) return "pnpm";
9
- if (fs.pathExistsSync("yarn.lock")) return "yarn";
10
-
11
- if (process.env.npm_execpath?.includes("bun")) {
12
- return "bun";
13
- }
14
-
15
- const userAgent = process.env.npm_config_user_agent;
16
- if (userAgent) {
17
- if (userAgent.startsWith("bun")) return "bun";
18
- if (userAgent.startsWith("pnpm")) return "pnpm";
19
- if (userAgent.startsWith("yarn")) return "yarn";
20
- if (userAgent.startsWith("npm")) return "npm";
21
- }
22
-
23
- return "npm";
24
- }
25
-
26
- export function getPackageManagerCommands(pm: PackageManager) {
27
- const commands = {
28
- bun: {
29
- init: "bun init -y",
30
- install: "bun install",
31
- add: "bun add",
32
- addDev: "bun add -D",
33
- run: "bun run",
34
- create: "bun create",
35
- x: "bunx",
36
- },
37
- npm: {
38
- init: "npm init -y",
39
- install: "npm install",
40
- add: "npm install",
41
- addDev: "npm install --save-dev",
42
- run: "npm run",
43
- create: "npm create",
44
- x: "npx",
45
- },
46
- pnpm: {
47
- init: "pnpm init",
48
- install: "pnpm install",
49
- add: "pnpm add",
50
- addDev: "pnpm add -D",
51
- run: "pnpm run",
52
- create: "pnpm create",
53
- x: "pnpm dlx",
54
- },
55
- yarn: {
56
- init: "yarn init -y",
57
- install: "yarn install",
58
- add: "yarn add",
59
- addDev: "yarn add -D",
60
- run: "yarn",
61
- create: "yarn create",
62
- x: "yarn dlx",
63
- },
64
- } as const;
65
-
66
- return commands[pm];
67
- }
5
+ export const PackageManager = {
6
+ bun: {
7
+ init: "bun init -y",
8
+ install: "bun install",
9
+ add: "bun add",
10
+ addDev: "bun add -D",
11
+ run: "bun run",
12
+ create: "bun create",
13
+ x: "bunx",
14
+ },
15
+ npm: {
16
+ init: "npm init -y",
17
+ install: "npm install",
18
+ add: "npm install",
19
+ addDev: "npm install --save-dev",
20
+ run: "npm run",
21
+ create: "npm create",
22
+ x: "npx",
23
+ },
24
+ pnpm: {
25
+ init: "pnpm init",
26
+ install: "pnpm install",
27
+ add: "pnpm add",
28
+ addDev: "pnpm add -D",
29
+ run: "pnpm run",
30
+ create: "pnpm create",
31
+ x: "pnpm dlx",
32
+ },
33
+ yarn: {
34
+ init: "yarn init -y",
35
+ install: "yarn install",
36
+ add: "yarn add",
37
+ addDev: "yarn add -D",
38
+ run: "yarn",
39
+ create: "yarn create",
40
+ x: "yarn dlx",
41
+ },
42
+ deno: {
43
+ init: "deno init",
44
+ install: "deno install",
45
+ add: "deno add",
46
+ addDev: "deno add",
47
+ run: "deno task",
48
+ create: "deno run -A",
49
+ x: "deno run -A",
50
+ },
51
+ } as const;
68
52
 
69
53
  export async function installDependencies(
70
54
  context: ProjectContext,
@@ -80,7 +64,7 @@ export async function installDependencies(
80
64
  ): Promise<void> {
81
65
  const targetCwd = cwd || context.path;
82
66
  const pm = context.packageManager;
83
- const commands = getPackageManagerCommands(pm);
67
+ const commands = PackageManager[pm];
84
68
 
85
69
  try {
86
70
  if (!dependencies && !devDependencies) {
@@ -107,7 +91,6 @@ export async function installDependencies(
107
91
  });
108
92
  }
109
93
  } catch (error) {
110
- log.error("Failed to install dependencies");
111
- throw error;
94
+ throwWithContext(error, "Failed to install dependencies");
112
95
  }
113
96
  }