alchemy 0.74.2 → 0.75.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/README.md +1 -1
  2. package/bin/alchemy.js +1781 -1746
  3. package/bin/alchemy.ts +1 -1
  4. package/bin/commands/create.ts +5 -4
  5. package/bin/commands/init.ts +109 -65
  6. package/bin/commands/util.ts +3 -1
  7. package/bin/constants.ts +2 -2
  8. package/bin/services/dependencies.ts +4 -4
  9. package/bin/services/execute-alchemy.ts +5 -3
  10. package/bin/services/get-package-version.ts +4 -4
  11. package/bin/services/github-workflow.ts +9 -10
  12. package/bin/services/package-manager.ts +1 -5
  13. package/bin/services/template-manager.ts +20 -13
  14. package/bin/services/vibe-rules.ts +6 -5
  15. package/bin/trpc.ts +7 -0
  16. package/bin/types.ts +1 -0
  17. package/lib/alchemy.d.ts +1 -1
  18. package/lib/alchemy.d.ts.map +1 -1
  19. package/lib/alchemy.js +30 -2
  20. package/lib/alchemy.js.map +1 -1
  21. package/lib/apply.js +10 -0
  22. package/lib/apply.js.map +1 -1
  23. package/lib/auth.js +1 -1
  24. package/lib/auth.js.map +1 -1
  25. package/lib/aws/control/types.d.ts.map +1 -1
  26. package/lib/aws/control/types.js.map +1 -1
  27. package/lib/clickhouse/api/sdk.gen.d.ts.map +1 -1
  28. package/lib/clickhouse/api/sdk.gen.js.map +1 -1
  29. package/lib/cloudflare/account-api-token.d.ts.map +1 -1
  30. package/lib/cloudflare/account-api-token.js.map +1 -1
  31. package/lib/cloudflare/astro/astro.js +1 -1
  32. package/lib/cloudflare/astro/astro.js.map +1 -1
  33. package/lib/cloudflare/bound.d.ts.map +1 -1
  34. package/lib/cloudflare/bucket.d.ts +1 -1
  35. package/lib/cloudflare/bucket.d.ts.map +1 -1
  36. package/lib/cloudflare/bucket.js +1 -1
  37. package/lib/cloudflare/bucket.js.map +1 -1
  38. package/lib/cloudflare/bun-spa/bun-spa.d.ts +1 -1
  39. package/lib/cloudflare/bun-spa/bun-spa.d.ts.map +1 -1
  40. package/lib/cloudflare/bun-spa/bun-spa.js +10 -11
  41. package/lib/cloudflare/bun-spa/bun-spa.js.map +1 -1
  42. package/lib/cloudflare/bun-spa/get-bun-spa-backend.d.ts +11 -0
  43. package/lib/cloudflare/bun-spa/get-bun-spa-backend.d.ts.map +1 -0
  44. package/lib/cloudflare/bun-spa/get-bun-spa-backend.js +26 -0
  45. package/lib/cloudflare/bun-spa/get-bun-spa-backend.js.map +1 -0
  46. package/lib/cloudflare/bun-spa/index.d.ts +2 -0
  47. package/lib/cloudflare/bun-spa/index.d.ts.map +1 -0
  48. package/lib/cloudflare/bun-spa/index.js +2 -0
  49. package/lib/cloudflare/bun-spa/index.js.map +1 -0
  50. package/lib/cloudflare/bundle/internal-worker-bundle.js +1 -1
  51. package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -1
  52. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js +1 -1
  53. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -1
  54. package/lib/cloudflare/bundle/plugin-node-compat.js +1 -1
  55. package/lib/cloudflare/bundle/plugin-node-compat.js.map +1 -1
  56. package/lib/cloudflare/bundle/plugin-wasm.js +1 -1
  57. package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -1
  58. package/lib/cloudflare/cloudflare-env-proxy.d.ts.map +1 -1
  59. package/lib/cloudflare/cloudflare-env-proxy.js +3 -3
  60. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -1
  61. package/lib/cloudflare/d1-migrations.js +1 -1
  62. package/lib/cloudflare/d1-migrations.js.map +1 -1
  63. package/lib/cloudflare/dns-records.js.map +1 -1
  64. package/lib/cloudflare/kv-namespace.d.ts +5 -0
  65. package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
  66. package/lib/cloudflare/kv-namespace.js +44 -19
  67. package/lib/cloudflare/kv-namespace.js.map +1 -1
  68. package/lib/cloudflare/miniflare/delete.d.ts.map +1 -1
  69. package/lib/cloudflare/miniflare/delete.js +3 -0
  70. package/lib/cloudflare/miniflare/delete.js.map +1 -1
  71. package/lib/cloudflare/miniflare/miniflare-controller.js +1 -1
  72. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -1
  73. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
  74. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +34 -4
  75. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
  76. package/lib/cloudflare/miniflare/paths.d.ts +0 -1
  77. package/lib/cloudflare/miniflare/paths.d.ts.map +1 -1
  78. package/lib/cloudflare/miniflare/paths.js +6 -18
  79. package/lib/cloudflare/miniflare/paths.js.map +1 -1
  80. package/lib/cloudflare/next.js +1 -1
  81. package/lib/cloudflare/next.js.map +1 -1
  82. package/lib/cloudflare/nuxt/nuxt.js +1 -1
  83. package/lib/cloudflare/nuxt/nuxt.js.map +1 -1
  84. package/lib/cloudflare/nuxt/plugin.d.ts.map +1 -1
  85. package/lib/cloudflare/nuxt/plugin.js +2 -2
  86. package/lib/cloudflare/nuxt/plugin.js.map +1 -1
  87. package/lib/cloudflare/react-router/plugin.js +1 -1
  88. package/lib/cloudflare/react-router/plugin.js.map +1 -1
  89. package/lib/cloudflare/react-router/react-router.js +1 -1
  90. package/lib/cloudflare/react-router/react-router.js.map +1 -1
  91. package/lib/cloudflare/redwood/redwood.js +1 -1
  92. package/lib/cloudflare/redwood/redwood.js.map +1 -1
  93. package/lib/cloudflare/sveltekit/sveltekit.js +1 -1
  94. package/lib/cloudflare/sveltekit/sveltekit.js.map +1 -1
  95. package/lib/cloudflare/tanstack-start/tanstack-start.js +1 -1
  96. package/lib/cloudflare/tanstack-start/tanstack-start.js.map +1 -1
  97. package/lib/cloudflare/tunnel.d.ts.map +1 -1
  98. package/lib/cloudflare/tunnel.js +25 -1
  99. package/lib/cloudflare/tunnel.js.map +1 -1
  100. package/lib/cloudflare/vite/plugin.d.ts.map +1 -1
  101. package/lib/cloudflare/vite/plugin.js +4 -4
  102. package/lib/cloudflare/vite/plugin.js.map +1 -1
  103. package/lib/cloudflare/website.d.ts.map +1 -1
  104. package/lib/cloudflare/website.js +1 -5
  105. package/lib/cloudflare/website.js.map +1 -1
  106. package/lib/cloudflare/worker-assets.d.ts +1 -1
  107. package/lib/cloudflare/worker-assets.d.ts.map +1 -1
  108. package/lib/cloudflare/worker-assets.js +1 -1
  109. package/lib/cloudflare/worker-assets.js.map +1 -1
  110. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  111. package/lib/cloudflare/worker-metadata.js.map +1 -1
  112. package/lib/cloudflare/worker-tail.d.ts.map +1 -1
  113. package/lib/cloudflare/worker-tail.js.map +1 -1
  114. package/lib/cloudflare/worker.d.ts.map +1 -1
  115. package/lib/cloudflare/worker.js +1 -1
  116. package/lib/cloudflare/worker.js.map +1 -1
  117. package/lib/cloudflare/wrangler.json.js +1 -2
  118. package/lib/cloudflare/wrangler.json.js.map +1 -1
  119. package/lib/coinbase/evm-account.d.ts.map +1 -1
  120. package/lib/coinbase/evm-account.js.map +1 -1
  121. package/lib/coinbase/evm-smart-account.d.ts.map +1 -1
  122. package/lib/coinbase/evm-smart-account.js.map +1 -1
  123. package/lib/coinbase/faucet.js +2 -2
  124. package/lib/coinbase/faucet.js.map +1 -1
  125. package/lib/docker/api.d.ts.map +1 -1
  126. package/lib/docker/api.js +1 -1
  127. package/lib/docker/api.js.map +1 -1
  128. package/lib/docker/image.js +1 -1
  129. package/lib/docker/image.js.map +1 -1
  130. package/lib/esbuild/bundle.js +1 -1
  131. package/lib/esbuild/bundle.js.map +1 -1
  132. package/lib/fs/file.js +1 -1
  133. package/lib/fs/file.js.map +1 -1
  134. package/lib/github/secret.d.ts.map +1 -1
  135. package/lib/github/secret.js.map +1 -1
  136. package/lib/llms.js +1 -1
  137. package/lib/llms.js.map +1 -1
  138. package/lib/neon/api/sdk.gen.d.ts.map +1 -1
  139. package/lib/neon/api/sdk.gen.js.map +1 -1
  140. package/lib/os/exec.d.ts.map +1 -1
  141. package/lib/os/exec.js +1 -1
  142. package/lib/os/exec.js.map +1 -1
  143. package/lib/planetscale/api/sdk.gen.d.ts.map +1 -1
  144. package/lib/planetscale/api/sdk.gen.js.map +1 -1
  145. package/lib/prisma-postgres/api/sdk.gen.d.ts.map +1 -1
  146. package/lib/prisma-postgres/api/sdk.gen.js.map +1 -1
  147. package/lib/scope.d.ts.map +1 -1
  148. package/lib/scope.js +3 -3
  149. package/lib/scope.js.map +1 -1
  150. package/lib/sentry/client-key.js +1 -1
  151. package/lib/sentry/client-key.js.map +1 -1
  152. package/lib/state/file-system-state-store.js +1 -1
  153. package/lib/state/file-system-state-store.js.map +1 -1
  154. package/lib/state/migrations.js +1 -1
  155. package/lib/state/migrations.js.map +1 -1
  156. package/lib/state/sqlite-state-store.js +1 -1
  157. package/lib/state/sqlite-state-store.js.map +1 -1
  158. package/lib/stripe/file.d.ts +3 -3
  159. package/lib/stripe/file.js +3 -3
  160. package/lib/test/bun.d.ts.map +1 -1
  161. package/lib/test/bun.js +1 -1
  162. package/lib/test/bun.js.map +1 -1
  163. package/lib/test/prune.js +1 -1
  164. package/lib/test/prune.js.map +1 -1
  165. package/lib/test/vitest.d.ts.map +1 -1
  166. package/lib/test/vitest.js +1 -1
  167. package/lib/test/vitest.js.map +1 -1
  168. package/lib/util/api/client/client.gen.d.ts +1 -1
  169. package/lib/util/api/client/client.gen.js +45 -45
  170. package/lib/util/api/client/types.gen.d.ts +22 -22
  171. package/lib/util/api/client/utils.gen.d.ts +3 -3
  172. package/lib/util/api/client/utils.gen.d.ts.map +1 -1
  173. package/lib/util/api/client/utils.gen.js +34 -34
  174. package/lib/util/api/client/utils.gen.js.map +1 -1
  175. package/lib/util/api/core/auth.gen.d.ts +3 -3
  176. package/lib/util/api/core/auth.gen.js +3 -3
  177. package/lib/util/api/core/bodySerializer.gen.d.ts +1 -1
  178. package/lib/util/api/core/bodySerializer.gen.js +3 -3
  179. package/lib/util/api/core/params.gen.d.ts +3 -3
  180. package/lib/util/api/core/params.gen.js +7 -7
  181. package/lib/util/api/core/pathSerializer.gen.d.ts +3 -3
  182. package/lib/util/api/core/pathSerializer.gen.js +36 -36
  183. package/lib/util/api/core/serverSentEvents.gen.d.ts +3 -3
  184. package/lib/util/api/core/serverSentEvents.gen.js +18 -18
  185. package/lib/util/api/core/types.gen.d.ts +4 -4
  186. package/lib/util/api/core/utils.gen.d.ts +1 -1
  187. package/lib/util/api/core/utils.gen.js +17 -17
  188. package/lib/util/camel-to-snake.d.ts.map +1 -1
  189. package/lib/util/content-type.js +1 -1
  190. package/lib/util/content-type.js.map +1 -1
  191. package/lib/util/find-workspace-root.d.ts +3 -0
  192. package/lib/util/find-workspace-root.d.ts.map +1 -0
  193. package/lib/util/find-workspace-root.js +64 -0
  194. package/lib/util/find-workspace-root.js.map +1 -0
  195. package/lib/util/idempotent-spawn.d.ts.map +1 -1
  196. package/lib/util/idempotent-spawn.js +2 -2
  197. package/lib/util/idempotent-spawn.js.map +1 -1
  198. package/lib/util/lock.js +1 -1
  199. package/lib/util/lock.js.map +1 -1
  200. package/lib/util/peer.d.ts.map +1 -1
  201. package/lib/util/peer.js.map +1 -1
  202. package/package.json +6 -1
  203. package/src/alchemy.ts +60 -4
  204. package/src/apply.ts +16 -1
  205. package/src/auth.ts +1 -1
  206. package/src/aws/control/types.ts +87107 -85281
  207. package/src/clickhouse/api/sdk.gen.ts +1 -3
  208. package/src/cloudflare/account-api-token.ts +3 -1
  209. package/src/cloudflare/astro/astro.ts +1 -1
  210. package/src/cloudflare/bound.ts +64 -65
  211. package/src/cloudflare/bucket.ts +4 -7
  212. package/src/cloudflare/bun-spa/bun-spa.ts +13 -13
  213. package/src/cloudflare/bun-spa/get-bun-spa-backend.ts +29 -0
  214. package/src/cloudflare/bun-spa/index.ts +1 -0
  215. package/src/cloudflare/bundle/internal-worker-bundle.ts +1 -1
  216. package/src/cloudflare/bundle/plugin-hybrid-node-compat.ts +1 -1
  217. package/src/cloudflare/bundle/plugin-node-compat.ts +1 -1
  218. package/src/cloudflare/bundle/plugin-wasm.ts +1 -1
  219. package/src/cloudflare/cloudflare-env-proxy.ts +2 -4
  220. package/src/cloudflare/d1-migrations.ts +1 -1
  221. package/src/cloudflare/dns-records.ts +3 -1
  222. package/src/cloudflare/kv-namespace.ts +52 -20
  223. package/src/cloudflare/miniflare/delete.ts +3 -0
  224. package/src/cloudflare/miniflare/miniflare-controller.ts +1 -1
  225. package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +39 -4
  226. package/src/cloudflare/miniflare/paths.ts +6 -26
  227. package/src/cloudflare/next.ts +1 -1
  228. package/src/cloudflare/nuxt/nuxt.ts +1 -1
  229. package/src/cloudflare/nuxt/plugin.ts +1 -4
  230. package/src/cloudflare/react-router/plugin.ts +1 -1
  231. package/src/cloudflare/react-router/react-router.ts +1 -1
  232. package/src/cloudflare/redwood/redwood.ts +1 -1
  233. package/src/cloudflare/sveltekit/sveltekit.ts +1 -1
  234. package/src/cloudflare/tanstack-start/tanstack-start.ts +1 -1
  235. package/src/cloudflare/tunnel.ts +36 -1
  236. package/src/cloudflare/vite/plugin.ts +2 -4
  237. package/src/cloudflare/website.ts +1 -6
  238. package/src/cloudflare/worker-assets.ts +1 -6
  239. package/src/cloudflare/worker-metadata.ts +5 -3
  240. package/src/cloudflare/worker-tail.ts +3 -1
  241. package/src/cloudflare/worker.ts +1 -3
  242. package/src/cloudflare/wrangler.json.ts +1 -2
  243. package/src/coinbase/evm-account.ts +3 -1
  244. package/src/coinbase/evm-smart-account.ts +3 -1
  245. package/src/coinbase/faucet.ts +2 -2
  246. package/src/docker/api.ts +4 -2
  247. package/src/docker/image.ts +1 -1
  248. package/src/esbuild/bundle.ts +1 -1
  249. package/src/fs/file.ts +1 -1
  250. package/src/github/secret.ts +5 -1
  251. package/src/llms.ts +1 -1
  252. package/src/neon/api/sdk.gen.ts +1 -3
  253. package/src/os/exec.ts +4 -2
  254. package/src/planetscale/api/sdk.gen.ts +1 -3
  255. package/src/prisma-postgres/api/sdk.gen.ts +1 -3
  256. package/src/scope.ts +3 -3
  257. package/src/sentry/client-key.ts +1 -5
  258. package/src/state/file-system-state-store.ts +1 -1
  259. package/src/state/migrations.ts +1 -1
  260. package/src/state/sqlite-state-store.ts +1 -1
  261. package/src/stripe/file.ts +3 -3
  262. package/src/test/bun.ts +4 -2
  263. package/src/test/prune.ts +1 -1
  264. package/src/test/vitest.ts +4 -2
  265. package/src/util/api/client/client.gen.ts +49 -49
  266. package/src/util/api/client/types.gen.ts +43 -43
  267. package/src/util/api/client/utils.gen.ts +47 -42
  268. package/src/util/api/core/auth.gen.ts +6 -6
  269. package/src/util/api/core/bodySerializer.gen.ts +4 -4
  270. package/src/util/api/core/params.gen.ts +10 -10
  271. package/src/util/api/core/pathSerializer.gen.ts +39 -39
  272. package/src/util/api/core/serverSentEvents.gen.ts +22 -22
  273. package/src/util/api/core/types.gen.ts +12 -12
  274. package/src/util/api/core/utils.gen.ts +18 -18
  275. package/src/util/camel-to-snake.ts +12 -10
  276. package/src/util/content-type.ts +1 -1
  277. package/{bin/services → src/util}/find-workspace-root.ts +27 -5
  278. package/src/util/idempotent-spawn.ts +2 -6
  279. package/src/util/lock.ts +1 -1
  280. package/src/util/peer.ts +3 -1
  281. package/templates/astro/alchemy.run.ts +0 -2
  282. package/templates/astro/astro.config.mjs +3 -3
  283. package/templates/astro/src/pages/api/hello.ts +16 -13
  284. package/templates/bun-spa/README.md +94 -0
  285. package/templates/bun-spa/_env +1 -0
  286. package/templates/bun-spa/_env.example +1 -0
  287. package/templates/bun-spa/_gitignore +29 -0
  288. package/templates/bun-spa/alchemy.run.ts +21 -0
  289. package/templates/bun-spa/bun-env.d.ts +25 -0
  290. package/templates/bun-spa/eslint.config.js +26 -0
  291. package/templates/bun-spa/package.json +30 -0
  292. package/templates/bun-spa/src/App.css +46 -0
  293. package/templates/bun-spa/src/App.tsx +53 -0
  294. package/templates/bun-spa/src/assets/logo.svg +1 -0
  295. package/templates/bun-spa/src/assets/react.svg +1 -0
  296. package/templates/bun-spa/src/frontend.tsx +14 -0
  297. package/templates/bun-spa/src/index.css +69 -0
  298. package/templates/bun-spa/src/index.html +14 -0
  299. package/templates/bun-spa/src/worker.ts +51 -0
  300. package/templates/bun-spa/tsconfig.json +24 -0
  301. package/templates/hono/alchemy.run.ts +0 -2
  302. package/templates/hono/src/index.ts +13 -13
  303. package/templates/nextjs/alchemy.run.ts +1 -3
  304. package/templates/nextjs/eslint.config.mjs +1 -1
  305. package/templates/nextjs/next-env.d.ts +1 -1
  306. package/templates/nextjs/next.config.ts +1 -1
  307. package/templates/nextjs/open-next.config.ts +1 -1
  308. package/templates/nextjs/src/app/api/hello/route.ts +2 -2
  309. package/templates/nextjs/src/app/layout.tsx +1 -1
  310. package/templates/nextjs/src/app/page.tsx +14 -15
  311. package/templates/nextjs/types/env.d.ts +4 -4
  312. package/templates/nuxt/alchemy.run.ts +0 -2
  313. package/templates/nuxt/server/middleware/auth.ts +1 -1
  314. package/templates/nuxt/server/middleware/hello.ts +2 -2
  315. package/templates/react-router/alchemy.run.ts +0 -2
  316. package/templates/react-router/app/entry.server.tsx +2 -2
  317. package/templates/react-router/package.json +1 -1
  318. package/templates/react-router/vite.config.ts +1 -1
  319. package/templates/react-router/workers/app.ts +2 -2
  320. package/templates/rwsdk/alchemy.run.ts +6 -4
  321. package/templates/rwsdk/package.json +1 -1
  322. package/templates/sveltekit/alchemy.run.ts +0 -2
  323. package/templates/sveltekit/package.json +1 -1
  324. package/templates/sveltekit/src/app.d.ts +7 -7
  325. package/templates/sveltekit/svelte.config.js +4 -4
  326. package/templates/sveltekit/vite.config.ts +3 -3
  327. package/templates/tanstack-start/alchemy.run.ts +0 -2
  328. package/templates/tanstack-start/package.json +1 -1
  329. package/templates/tanstack-start/src/components/Header.tsx +2 -2
  330. package/templates/tanstack-start/src/router.tsx +4 -4
  331. package/templates/tanstack-start/src/routes/__root.tsx +10 -10
  332. package/templates/tanstack-start/src/routes/api.demo-names.ts +6 -6
  333. package/templates/tanstack-start/src/routes/demo.start.api-request.tsx +11 -11
  334. package/templates/tanstack-start/src/routes/demo.start.server-funcs.tsx +30 -30
  335. package/templates/tanstack-start/src/routes/index.tsx +5 -5
  336. package/templates/tanstack-start/vite.config.ts +9 -9
  337. package/templates/typescript/alchemy.run.ts +0 -2
  338. package/templates/typescript/src/worker.ts +5 -1
  339. package/templates/vite/alchemy.run.ts +0 -2
  340. package/templates/vite/eslint.config.js +12 -12
  341. package/templates/vite/package.json +1 -1
  342. package/templates/vite/src/App.tsx +7 -7
  343. package/templates/vite/src/main.tsx +6 -6
  344. package/templates/vite/src/worker.ts +11 -12
  345. package/templates/vite/vite.config.ts +2 -2
  346. package/workers/tunnel-proxy.js +1 -1
  347. package/lib/cloudflare/miniflare/symlink-miniflare-state.d.ts +0 -2
  348. package/lib/cloudflare/miniflare/symlink-miniflare-state.d.ts.map +0 -1
  349. package/lib/cloudflare/miniflare/symlink-miniflare-state.js +0 -18
  350. package/lib/cloudflare/miniflare/symlink-miniflare-state.js.map +0 -1
  351. package/src/cloudflare/miniflare/symlink-miniflare-state.ts +0 -18
@@ -200,9 +200,7 @@ export type Options<
200
200
  class _HeyApiClient {
201
201
  protected _client: Client = client;
202
202
 
203
- constructor(args?: {
204
- client?: Client;
205
- }) {
203
+ constructor(args?: { client?: Client }) {
206
204
  if (args?.client) {
207
205
  this._client = args.client;
208
206
  }
@@ -360,7 +360,9 @@ export const AccountApiToken = Resource(
360
360
  }));
361
361
 
362
362
  throw new Error(
363
- `Error ${this.phase === "update" ? "updating" : "creating"} token '${tokenName}': ${
363
+ `Error ${
364
+ this.phase === "update" ? "updating" : "creating"
365
+ } token '${tokenName}': ${
364
366
  errorData.errors?.[0]?.message || response.statusText
365
367
  }`,
366
368
  );
@@ -1,4 +1,4 @@
1
- import { join, resolve } from "node:path";
1
+ import { join, resolve } from "pathe";
2
2
  import { getPackageManagerRunner } from "../../util/detect-package-manager.ts";
3
3
  import type { Assets } from "../assets.ts";
4
4
  import type { Bindings } from "../bindings.ts";
@@ -37,69 +37,68 @@ type BoundWorker<
37
37
  >]: Rpc.Provider<RPC, "fetch" | "connect">[property];
38
38
  };
39
39
 
40
- export type Bound<T extends Binding> = T extends _DurableObjectNamespace<
41
- infer O
42
- >
43
- ? DurableObjectNamespace<O & Rpc.DurableObjectBranded>
44
- : T extends { type: "kv_namespace" }
45
- ? KVNamespace
46
- : T extends WorkerStub<infer RPC>
47
- ? BoundWorker<RPC>
48
- : T extends _Worker<any, infer RPC> | WorkerRef<infer RPC>
40
+ export type Bound<T extends Binding> =
41
+ T extends _DurableObjectNamespace<infer O>
42
+ ? DurableObjectNamespace<O & Rpc.DurableObjectBranded>
43
+ : T extends { type: "kv_namespace" }
44
+ ? KVNamespace
45
+ : T extends WorkerStub<infer RPC>
49
46
  ? BoundWorker<RPC>
50
- : T extends { type: "service" }
51
- ? Service
52
- : T extends _R2Bucket
53
- ? R2Bucket
54
- : T extends _Hyperdrive | HyperdriveRef
55
- ? Hyperdrive
56
- : T extends Secret
57
- ? string
58
- : T extends CloudflareSecret | CloudflareSecretRef
59
- ? SecretsStoreSecret
60
- : T extends SecretKey
61
- ? CryptoKey
62
- : T extends Assets
63
- ? Service
64
- : T extends _Workflow<infer P>
65
- ? Workflow<P>
66
- : T extends _D1Database
67
- ? D1Database
68
- : T extends DispatchNamespace
69
- ? DispatchNamespace
70
- : T extends _WorkerLoader
71
- ? WorkerLoader
72
- : T extends _VectorizeIndex
73
- ? VectorizeIndex
74
- : T extends _Queue<infer Body>
75
- ? Queue<Body>
76
- : T extends _AnalyticsEngineDataset
77
- ? AnalyticsEngineDataset
78
- : T extends _Pipeline<infer R>
79
- ? Pipeline<R>
80
- : T extends _RateLimit
81
- ? RateLimit
82
- : T extends string
83
- ? T
84
- : T extends BrowserRendering
85
- ? Fetcher
86
- : T extends _Ai<infer M>
87
- ? Ai<M>
88
- : T extends _Images
89
- ? ImagesBinding
90
- : T extends _VersionMetadata
91
- ? WorkerVersionMetadata
92
- : T extends Self
93
- ? Service
94
- : T extends Json<infer T>
95
- ? T
96
- : T extends _Container<
97
- infer Obj
98
- >
99
- ? DurableObjectNamespace<
100
- Obj &
101
- Rpc.DurableObjectBranded
102
- >
103
- : T extends undefined
104
- ? undefined
105
- : Service;
47
+ : T extends _Worker<any, infer RPC> | WorkerRef<infer RPC>
48
+ ? BoundWorker<RPC>
49
+ : T extends { type: "service" }
50
+ ? Service
51
+ : T extends _R2Bucket
52
+ ? R2Bucket
53
+ : T extends _Hyperdrive | HyperdriveRef
54
+ ? Hyperdrive
55
+ : T extends Secret
56
+ ? string
57
+ : T extends CloudflareSecret | CloudflareSecretRef
58
+ ? SecretsStoreSecret
59
+ : T extends SecretKey
60
+ ? CryptoKey
61
+ : T extends Assets
62
+ ? Service
63
+ : T extends _Workflow<infer P>
64
+ ? Workflow<P>
65
+ : T extends _D1Database
66
+ ? D1Database
67
+ : T extends DispatchNamespace
68
+ ? DispatchNamespace
69
+ : T extends _WorkerLoader
70
+ ? WorkerLoader
71
+ : T extends _VectorizeIndex
72
+ ? VectorizeIndex
73
+ : T extends _Queue<infer Body>
74
+ ? Queue<Body>
75
+ : T extends _AnalyticsEngineDataset
76
+ ? AnalyticsEngineDataset
77
+ : T extends _Pipeline<infer R>
78
+ ? Pipeline<R>
79
+ : T extends _RateLimit
80
+ ? RateLimit
81
+ : T extends string
82
+ ? T
83
+ : T extends BrowserRendering
84
+ ? Fetcher
85
+ : T extends _Ai<infer M>
86
+ ? Ai<M>
87
+ : T extends _Images
88
+ ? ImagesBinding
89
+ : T extends _VersionMetadata
90
+ ? WorkerVersionMetadata
91
+ : T extends Self
92
+ ? Service
93
+ : T extends Json<infer T>
94
+ ? T
95
+ : T extends _Container<
96
+ infer Obj
97
+ >
98
+ ? DurableObjectNamespace<
99
+ Obj &
100
+ Rpc.DurableObjectBranded
101
+ >
102
+ : T extends undefined
103
+ ? undefined
104
+ : Service;
@@ -1007,7 +1007,9 @@ export async function listBuckets(
1007
1007
  }
1008
1008
 
1009
1009
  // Build URL with query parameters
1010
- const path = `/accounts/${api.accountId}/r2/buckets${params.toString() ? `?${params.toString()}` : ""}`;
1010
+ const path = `/accounts/${api.accountId}/r2/buckets${
1011
+ params.toString() ? `?${params.toString()}` : ""
1012
+ }`;
1011
1013
 
1012
1014
  // Make the API request
1013
1015
  const result = await extractCloudflareResult<{
@@ -1262,12 +1264,7 @@ function mapHeadersToHttpMetadata(headers: Headers): R2HTTPMetadata {
1262
1264
 
1263
1265
  export async function putObject(
1264
1266
  api: CloudflareApi,
1265
- {
1266
- bucketName,
1267
- key,
1268
- object,
1269
- options,
1270
- }: {
1267
+ { bucketName, key, object, options }: {
1271
1268
  bucketName: string;
1272
1269
  key: string;
1273
1270
  object: PutObjectObject;
@@ -1,5 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
- import path from "node:path";
2
+ import path from "pathe";
3
3
  import { Scope } from "../../scope.ts";
4
4
  import { exists } from "../../util/exists.ts";
5
5
  import type { Bindings } from "../bindings.ts";
@@ -18,7 +18,7 @@ export interface BunSPAProps<B extends Bindings> extends WebsiteProps<B> {
18
18
  /**
19
19
  * The path to the frontend entrypoints that bun should bundle for deployment & serve in dev mode.
20
20
  * These are usually html files. Glob patterns are supported.
21
- * Typically set to index.html
21
+ * Typically set to src/index.html
22
22
  */
23
23
  frontend: string | string[];
24
24
  outDir?: string;
@@ -70,6 +70,8 @@ export async function BunSPA<B extends Bindings>(
70
70
  }
71
71
 
72
72
  const scope = Scope.current;
73
+ const nodeEnv =
74
+ (props.bindings?.NODE_ENV ?? scope.local) ? "development" : "production";
73
75
  console.log("creating website", outDir);
74
76
  const website = await Website(id, {
75
77
  spa: true,
@@ -77,17 +79,14 @@ export async function BunSPA<B extends Bindings>(
77
79
  bindings: {
78
80
  ...props.bindings,
79
81
  // set NODE_ENV in worker appropriately if not already set
80
- NODE_ENV:
81
- (props.bindings?.NODE_ENV ?? scope.local)
82
- ? "development"
83
- : "production",
82
+ NODE_ENV: nodeEnv,
84
83
  } as unknown as B,
85
84
  assets: {
86
85
  directory: path.resolve(outDir),
87
86
  },
88
87
  build: spreadBuildProps(
89
88
  props,
90
- `bun build '${frontendPaths.join("' '")}' --outdir ${outDir}`,
89
+ `bun build '${frontendPaths.join("' '")}' --target=browser --minify --define:process.env.NODE_ENV='"${nodeEnv}"' --env='BUN_PUBLIC_*' --outdir ${outDir}`,
91
90
  ),
92
91
  });
93
92
 
@@ -129,7 +128,7 @@ export async function BunSPA<B extends Bindings>(
129
128
  ...process.env,
130
129
  NODE_ENV: "development",
131
130
  ALCHEMY_ROOT: Scope.current.rootDir,
132
- PUBLIC_BACKEND_URL: apiUrl,
131
+ BUN_PUBLIC_BACKEND_URL: apiUrl,
133
132
  },
134
133
  });
135
134
  }
@@ -144,8 +143,8 @@ async function validateBunfigToml(cwd: string): Promise<void> {
144
143
  "bunfig.toml is required for BunSPA to work correctly.\n\n" +
145
144
  `Create ${bunfigPath} with the following content:\n\n` +
146
145
  "[serve.static]\n" +
147
- `env='PUBLIC_*'\n\n` +
148
- "This allows Bun to expose PUBLIC_* environment variables to the frontend during development.",
146
+ `env='BUN_PUBLIC_*'\n\n` +
147
+ "This allows Bun to expose BUN_PUBLIC_* environment variables to the frontend during development.",
149
148
  );
150
149
  }
151
150
 
@@ -153,15 +152,16 @@ async function validateBunfigToml(cwd: string): Promise<void> {
153
152
  const config = Bun.TOML.parse(content) as Record<string, any>;
154
153
 
155
154
  const hasServeStatic = config.serve?.static;
156
- const hasEnvConfig = hasServeStatic && config.serve.static.env === "PUBLIC_*";
155
+ const hasEnvConfig =
156
+ hasServeStatic && config.serve.static.env === "BUN_PUBLIC_*";
157
157
 
158
158
  if (!hasServeStatic || !hasEnvConfig) {
159
159
  throw new Error(
160
160
  "bunfig.toml is missing required configuration for BunSPA.\n\n" +
161
161
  `Add the following section to ${bunfigPath}:\n\n` +
162
162
  "[serve.static]\n" +
163
- `env='PUBLIC_*'\n\n` +
164
- "This allows Bun to expose PUBLIC_* environment variables to the frontend during development.",
163
+ `env='BUN_PUBLIC_*'\n\n` +
164
+ "This allows Bun to expose BUN_PUBLIC_* environment variables to the frontend during development.",
165
165
  );
166
166
  }
167
167
  }
@@ -0,0 +1,29 @@
1
+ type GetBackendUrlProps = {
2
+ // If you're using routes with paths in your worker configuration, you'll need to pass the path you want to use here, e.g. "/api"
3
+ routePath?: string;
4
+ };
5
+
6
+ /**
7
+ * Use this function in your frontend code to automatically get the correct URL for your backend API in both local and deployed environments
8
+ * @param param0 { path: string }
9
+ * @returns
10
+ */
11
+ export function getBackendUrl({ routePath }: GetBackendUrlProps = {}): URL {
12
+ let pathToUse = !routePath
13
+ ? "/"
14
+ : routePath.startsWith("/")
15
+ ? routePath
16
+ : `/${routePath}`;
17
+ // This is ugly but it's necessary to support both local and prod environments
18
+ // Start with the current host
19
+ let backendUrl = `${window.location.protocol}//${window.location.host}${pathToUse}`;
20
+ try {
21
+ // Bun will only inline this if we use exactly `process.env.BUN_PUBLIC_BACKEND_URL` it we use other forms including process?.env for example bun will not inline it
22
+ // we can't check typeof process either because process may not be available but Bun may already have inlined process.env.BUN_PUBLIC_BACKEND_URL with the correct value
23
+ backendUrl = process.env.BUN_PUBLIC_BACKEND_URL ?? backendUrl;
24
+ } catch {
25
+ // Bun may not have had anything to inline and process.env may not exist to above can throw an error
26
+ // do nothing
27
+ }
28
+ return new URL(backendUrl);
29
+ }
@@ -0,0 +1 @@
1
+ export * from "./get-bun-spa-backend.ts";
@@ -1,6 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import fs from "node:fs/promises";
3
- import path from "node:path";
3
+ import path from "pathe";
4
4
  import { memoize } from "../../util/memoize.ts";
5
5
  import type { WorkerBundle } from "../worker-bundle.ts";
6
6
 
@@ -5,7 +5,7 @@
5
5
  import type { Plugin, PluginBuild } from "esbuild";
6
6
  import assert from "node:assert";
7
7
  import { createRequire } from "node:module";
8
- import nodePath from "node:path";
8
+ import nodePath from "pathe";
9
9
  import { dedent } from "../../util/dedent.ts";
10
10
  import { NODEJS_MODULES_RE } from "./nodejs-builtin-modules.ts";
11
11
 
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from "esbuild";
2
2
  import type { NodeJSCompatMode } from "miniflare";
3
- import { relative } from "node:path";
3
+ import { relative } from "pathe";
4
4
  import pc from "picocolors";
5
5
  import { dedent } from "../../util/dedent.ts";
6
6
  import { logger } from "../../util/logger.ts";
@@ -1,7 +1,7 @@
1
1
  import type esbuild from "esbuild";
2
2
  import assert from "node:assert";
3
3
  import fs from "node:fs/promises";
4
- import path from "node:path";
4
+ import path from "pathe";
5
5
  import type { WorkerBundle } from "../worker-bundle.ts";
6
6
 
7
7
  export function createWasmPlugin() {
@@ -3,7 +3,6 @@ import {
3
3
  getDefaultConfigPath,
4
4
  getDefaultPersistPath,
5
5
  validateConfigPath,
6
- validatePersistPath,
7
6
  } from "./miniflare/paths.ts";
8
7
 
9
8
  export const getCloudflareEnvProxy = async <E>(
@@ -22,12 +21,11 @@ export const getPlatformProxyOptions = (
22
21
  input.persist === false
23
22
  ? false
24
23
  : {
25
- path: validatePersistPath(
24
+ path:
26
25
  typeof input.persist === "object" &&
27
- typeof input.persist.path === "string"
26
+ typeof input.persist.path === "string"
28
27
  ? input.persist.path
29
28
  : getDefaultPersistPath(),
30
- ),
31
29
  };
32
30
  if (!persist) {
33
31
  const message =
@@ -1,6 +1,6 @@
1
1
  import { glob } from "glob";
2
2
  import * as fs from "node:fs/promises";
3
- import * as path from "node:path";
3
+ import path from "pathe";
4
4
  import { logger } from "../util/logger.ts";
5
5
  import { handleApiError } from "./api-error.ts";
6
6
  import type { CloudflareApi } from "./api.ts";
@@ -314,7 +314,9 @@ async function createOrUpdateRecord(
314
314
  }
315
315
 
316
316
  throw new Error(
317
- `Failed to ${existingId ? "update" : "create"} DNS record ${record.name}: ${response.statusText}\nResponse: ${errorBody}`,
317
+ `Failed to ${
318
+ existingId ? "update" : "create"
319
+ } DNS record ${record.name}: ${response.statusText}\nResponse: ${errorBody}`,
318
320
  );
319
321
  }
320
322
 
@@ -13,6 +13,8 @@ import {
13
13
  type CloudflareApiOptions,
14
14
  } from "./api.ts";
15
15
  import { deleteMiniflareBinding } from "./miniflare/delete.ts";
16
+ import * as mf from "miniflare";
17
+ import { getDefaultPersistPath } from "./miniflare/paths.ts";
16
18
 
17
19
  /**
18
20
  * Properties for creating or updating a KV Namespace
@@ -220,6 +222,13 @@ const _KVNamespace = Resource(
220
222
  };
221
223
 
222
224
  if (local) {
225
+ if (props.values) {
226
+ await insertLocalKVRecords({
227
+ namespaceId: dev.id,
228
+ values: props.values,
229
+ rootDir: this.scope.rootDir,
230
+ });
231
+ }
223
232
  return {
224
233
  type: "kv_namespace",
225
234
  namespaceId: this.output?.namespaceId ?? "",
@@ -340,31 +349,18 @@ export async function insertKVRecords(
340
349
  const BATCH_SIZE = 10000;
341
350
 
342
351
  for (let i = 0; i < props.values.length; i += BATCH_SIZE) {
343
- const batch = props.values.slice(i, i + BATCH_SIZE);
344
-
345
- const bulkPayload = batch.map((entry) => {
346
- const item: any = {
352
+ const bulkPayload = props.values
353
+ .slice(i, i + BATCH_SIZE)
354
+ .map((entry) => ({
347
355
  key: entry.key,
348
356
  value:
349
357
  typeof entry.value === "string"
350
358
  ? entry.value
351
359
  : JSON.stringify(entry.value),
352
- };
353
-
354
- if (entry.expiration) {
355
- item.expiration = entry.expiration;
356
- }
357
-
358
- if (entry.expirationTtl) {
359
- item.expiration_ttl = entry.expirationTtl;
360
- }
361
-
362
- if (entry.metadata) {
363
- item.metadata = entry.metadata;
364
- }
365
-
366
- return item;
367
- });
360
+ expiration: entry.expiration,
361
+ expiration_ttl: entry.expirationTtl,
362
+ metadata: entry.metadata,
363
+ }));
368
364
 
369
365
  await withExponentialBackoff(
370
366
  async () => {
@@ -397,6 +393,42 @@ export async function insertKVRecords(
397
393
  }
398
394
  }
399
395
 
396
+ export async function insertLocalKVRecords(input: {
397
+ namespaceId: string;
398
+ values: KVPair[];
399
+ rootDir: string;
400
+ }) {
401
+ const miniflare = new mf.Miniflare({
402
+ script: "",
403
+ modules: true,
404
+ defaultPersistRoot: getDefaultPersistPath(input.rootDir),
405
+ kvNamespaces: { KV: input.namespaceId },
406
+ kvPersist: true,
407
+ log: process.env.DEBUG ? new mf.Log(mf.LogLevel.DEBUG) : undefined,
408
+ });
409
+ try {
410
+ await miniflare.ready;
411
+ const kv = await miniflare.getKVNamespace("KV");
412
+ await Promise.all(
413
+ input.values.map((record) =>
414
+ kv.put(
415
+ record.key,
416
+ typeof record.value === "string"
417
+ ? record.value
418
+ : JSON.stringify(record.value),
419
+ {
420
+ expiration: record.expiration,
421
+ expirationTtl: record.expirationTtl,
422
+ metadata: record.metadata,
423
+ },
424
+ ),
425
+ ),
426
+ );
427
+ } finally {
428
+ await miniflare.dispose();
429
+ }
430
+ }
431
+
400
432
  /**
401
433
  * Interface representing a KV namespace as returned by Cloudflare API
402
434
  */
@@ -38,6 +38,9 @@ export async function deleteMiniflareBinding(
38
38
  .catch(() => []);
39
39
  await Promise.all(files.map((file) => fs.rm(path.join(bindingPath, file))));
40
40
 
41
+ // if running E2E tests, do not delete the data directory to prevent race conditions in smoke tests
42
+ if (process.env.ALCHEMY_E2E) return;
43
+
41
44
  // delete data directory, if present
42
45
  await removeDirectory(path.join(persistRoot, type, id), {
43
46
  recursive: true,
@@ -1,6 +1,6 @@
1
1
  import * as miniflare from "miniflare";
2
2
  import assert from "node:assert";
3
- import path from "node:path";
3
+ import path from "pathe";
4
4
  import { Scope } from "../../scope.ts";
5
5
  import { findOpenPort } from "../../util/find-open-port.ts";
6
6
  import type { HTTPServer } from "../../util/http.ts";
@@ -1,9 +1,11 @@
1
1
  import * as miniflare from "miniflare";
2
+ import assert from "node:assert";
2
3
  import { once } from "node:events";
3
4
  import http from "node:http";
4
5
  import { Readable } from "node:stream";
5
6
  import { WebSocket, WebSocketServer } from "ws";
6
7
  import { createUpgradeHandler } from "../../util/http.ts";
8
+ import { logger } from "../../util/logger.ts";
7
9
 
8
10
  export interface MiniflareWorkerProxy {
9
11
  url: URL;
@@ -90,12 +92,10 @@ export async function createMiniflareWorkerProxy(options: {
90
92
  });
91
93
  };
92
94
 
93
- server.listen(options.port);
94
- await once(server, "listening");
95
- const url = new URL(`http://localhost:${options.port}`);
95
+ await listen(server, options.port);
96
96
 
97
97
  return {
98
- url,
98
+ url: getAddress(server),
99
99
  close: async () => {
100
100
  // If we await this while the `wss` server is open, the server will hang.
101
101
  server.close();
@@ -103,6 +103,41 @@ export async function createMiniflareWorkerProxy(options: {
103
103
  };
104
104
  }
105
105
 
106
+ /**
107
+ * Listens on the given port, retrying on the next port if the port is already in use.
108
+ */
109
+ async function listen(server: http.Server, port: number) {
110
+ try {
111
+ server.listen(port);
112
+ await once(server, "listening");
113
+ } catch (error) {
114
+ if (
115
+ typeof error === "object" &&
116
+ error !== null &&
117
+ "code" in error &&
118
+ error.code === "EADDRINUSE"
119
+ ) {
120
+ logger.warn(`Port ${port} is already in use, trying ${port + 1}...`);
121
+ await listen(server, port + 1);
122
+ } else {
123
+ throw error;
124
+ }
125
+ }
126
+ }
127
+
128
+ function getAddress(server: http.Server) {
129
+ const address = server.address();
130
+ assert(
131
+ address &&
132
+ typeof address === "object" &&
133
+ "address" in address &&
134
+ "port" in address,
135
+ "Server is not listening",
136
+ );
137
+ const hostname = address.address === "::" ? "localhost" : address.address;
138
+ return new URL(`http://${hostname}:${address.port}`);
139
+ }
140
+
106
141
  interface RequestInfo {
107
142
  method: string;
108
143
  url: URL;
@@ -1,6 +1,8 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
- import { existsSync, readlinkSync, statSync } from "node:fs";
3
- import path from "node:path";
2
+ // biome-ignore lint/style/noRestrictedImports: I/O is acceptable here
3
+ import { existsSync } from "node:fs";
4
+ import path from "pathe";
5
+ import { findWorkspaceRootSync } from "../../util/find-workspace-root.ts";
4
6
  import { ALCHEMY_ROOT } from "../../util/root-dir.ts";
5
7
 
6
8
  const dynamicImportContext = new AsyncLocalStorage<boolean>();
@@ -17,7 +19,8 @@ export const getDefaultConfigPath = (rootDir: string = process.cwd()) => {
17
19
  };
18
20
 
19
21
  export const getDefaultPersistPath = (rootDir: string = ALCHEMY_ROOT) => {
20
- return path.join(rootDir, ".alchemy", "miniflare", "v3");
22
+ const workspaceRoot = findWorkspaceRootSync(rootDir);
23
+ return path.join(workspaceRoot, ".alchemy", "miniflare", "v3");
21
24
  };
22
25
 
23
26
  export const validateConfigPath = (path: string, throws = true) => {
@@ -30,29 +33,6 @@ export const validateConfigPath = (path: string, throws = true) => {
30
33
  return path;
31
34
  };
32
35
 
33
- const DEFAULT_VALIDATE_PERSIST =
34
- process.env.NODE_ENV === "development" ||
35
- !process.argv.some((arg) => ["build", "prepare", "typegen"].includes(arg));
36
-
37
- export const validatePersistPath = (
38
- path: string,
39
- throws = DEFAULT_VALIDATE_PERSIST,
40
- ) => {
41
- try {
42
- const stat = statSync(path);
43
- if (stat.isSymbolicLink()) {
44
- return readlinkSync(path);
45
- }
46
- return path;
47
- } catch {
48
- warnOrThrow(
49
- `The Alchemy data path, "${path}", could not be resolved. This is required for Cloudflare bindings during development. Please run \`alchemy dev\` to create it.`,
50
- throws,
51
- );
52
- return path;
53
- }
54
- };
55
-
56
36
  const warned = new Set<string>();
57
37
 
58
38
  const warnOrThrow = (message: string, throws: boolean) => {
@@ -1,5 +1,5 @@
1
1
  import * as fs from "node:fs/promises";
2
- import path from "node:path";
2
+ import path from "pathe";
3
3
  import pc from "picocolors";
4
4
  import { getPackageManagerRunner } from "../util/detect-package-manager.ts";
5
5
  import { exists } from "../util/exists.ts";
@@ -1,4 +1,4 @@
1
- import path from "node:path";
1
+ import path from "pathe";
2
2
  import { getPackageManagerRunner } from "../../util/detect-package-manager.ts";
3
3
  import type { Assets } from "../assets.ts";
4
4
  import type { Bindings } from "../bindings.ts";