alchemy 0.45.6 → 0.46.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 (352) hide show
  1. package/README.md +2 -2
  2. package/bin/alchemy.mjs +19280 -15136
  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 +63 -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/api.d.ts +9 -5
  37. package/lib/cloudflare/api.d.ts.map +1 -1
  38. package/lib/cloudflare/api.js +6 -46
  39. package/lib/cloudflare/api.js.map +1 -1
  40. package/lib/cloudflare/auth.d.ts +16 -35
  41. package/lib/cloudflare/auth.d.ts.map +1 -1
  42. package/lib/cloudflare/auth.js +50 -129
  43. package/lib/cloudflare/auth.js.map +1 -1
  44. package/lib/cloudflare/browser-rendering.d.ts +12 -3
  45. package/lib/cloudflare/browser-rendering.d.ts.map +1 -1
  46. package/lib/cloudflare/browser-rendering.js +12 -2
  47. package/lib/cloudflare/browser-rendering.js.map +1 -1
  48. package/lib/cloudflare/bundle/fs.d.ts.map +1 -1
  49. package/lib/cloudflare/bundle/fs.js +3 -0
  50. package/lib/cloudflare/bundle/fs.js.map +1 -1
  51. package/lib/cloudflare/bundle/internal-worker-bundle.d.ts +6 -0
  52. package/lib/cloudflare/bundle/internal-worker-bundle.d.ts.map +1 -0
  53. package/lib/cloudflare/bundle/internal-worker-bundle.js +14 -0
  54. package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -0
  55. package/lib/cloudflare/compatibility-presets.d.ts +22 -0
  56. package/lib/cloudflare/compatibility-presets.d.ts.map +1 -0
  57. package/lib/cloudflare/compatibility-presets.js +27 -0
  58. package/lib/cloudflare/compatibility-presets.js.map +1 -0
  59. package/lib/cloudflare/container.d.ts +5 -1
  60. package/lib/cloudflare/container.d.ts.map +1 -1
  61. package/lib/cloudflare/container.js +42 -2
  62. package/lib/cloudflare/container.js.map +1 -1
  63. package/lib/cloudflare/dispatch-namespace.d.ts +5 -0
  64. package/lib/cloudflare/dispatch-namespace.d.ts.map +1 -1
  65. package/lib/cloudflare/dispatch-namespace.js +8 -0
  66. package/lib/cloudflare/dispatch-namespace.js.map +1 -1
  67. package/lib/cloudflare/durable-object-namespace.d.ts +23 -15
  68. package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -1
  69. package/lib/cloudflare/durable-object-namespace.js +22 -21
  70. package/lib/cloudflare/durable-object-namespace.js.map +1 -1
  71. package/lib/cloudflare/hyperdrive.d.ts +19 -5
  72. package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
  73. package/lib/cloudflare/hyperdrive.js +14 -0
  74. package/lib/cloudflare/hyperdrive.js.map +1 -1
  75. package/lib/cloudflare/images.d.ts +27 -17
  76. package/lib/cloudflare/images.d.ts.map +1 -1
  77. package/lib/cloudflare/images.js +13 -8
  78. package/lib/cloudflare/images.js.map +1 -1
  79. package/lib/cloudflare/index.d.ts +1 -3
  80. package/lib/cloudflare/index.d.ts.map +1 -1
  81. package/lib/cloudflare/index.js +1 -3
  82. package/lib/cloudflare/index.js.map +1 -1
  83. package/lib/cloudflare/miniflare/miniflare.d.ts +3 -3
  84. package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
  85. package/lib/cloudflare/miniflare/miniflare.js +7 -7
  86. package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
  87. package/lib/cloudflare/miniflare/{mixed-mode.d.ts → remote-binding-proxy.d.ts} +5 -5
  88. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -0
  89. package/lib/cloudflare/miniflare/{mixed-mode.js → remote-binding-proxy.js} +16 -52
  90. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -0
  91. package/lib/cloudflare/oauth.d.ts +22 -0
  92. package/lib/cloudflare/oauth.d.ts.map +1 -0
  93. package/lib/cloudflare/oauth.js +213 -0
  94. package/lib/cloudflare/oauth.js.map +1 -0
  95. package/lib/cloudflare/state.d.ts +26 -0
  96. package/lib/cloudflare/state.d.ts.map +1 -0
  97. package/lib/cloudflare/state.js +14 -0
  98. package/lib/cloudflare/state.js.map +1 -0
  99. package/lib/cloudflare/user.d.ts +2 -2
  100. package/lib/cloudflare/user.d.ts.map +1 -1
  101. package/lib/cloudflare/user.js +24 -47
  102. package/lib/cloudflare/user.js.map +1 -1
  103. package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
  104. package/lib/cloudflare/vectorize-index.js +5 -2
  105. package/lib/cloudflare/vectorize-index.js.map +1 -1
  106. package/lib/cloudflare/version-metadata.d.ts +15 -3
  107. package/lib/cloudflare/version-metadata.d.ts.map +1 -1
  108. package/lib/cloudflare/version-metadata.js +11 -2
  109. package/lib/cloudflare/version-metadata.js.map +1 -1
  110. package/lib/cloudflare/vite.d.ts.map +1 -1
  111. package/lib/cloudflare/vite.js +2 -1
  112. package/lib/cloudflare/vite.js.map +1 -1
  113. package/lib/cloudflare/worker-metadata.d.ts +13 -2
  114. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  115. package/lib/cloudflare/worker-metadata.js +10 -15
  116. package/lib/cloudflare/worker-metadata.js.map +1 -1
  117. package/lib/cloudflare/worker-subdomain.d.ts +7 -0
  118. package/lib/cloudflare/worker-subdomain.d.ts.map +1 -1
  119. package/lib/cloudflare/worker-subdomain.js +17 -22
  120. package/lib/cloudflare/worker-subdomain.js.map +1 -1
  121. package/lib/cloudflare/{worker/tail.d.ts → worker-tail.d.ts} +2 -2
  122. package/lib/cloudflare/worker-tail.d.ts.map +1 -0
  123. package/lib/cloudflare/{worker/tail.js → worker-tail.js} +11 -9
  124. package/lib/cloudflare/worker-tail.js.map +1 -0
  125. package/lib/cloudflare/worker.d.ts +19 -8
  126. package/lib/cloudflare/worker.d.ts.map +1 -1
  127. package/lib/cloudflare/worker.js +35 -10
  128. package/lib/cloudflare/worker.js.map +1 -1
  129. package/lib/cloudflare/workflow.d.ts +22 -11
  130. package/lib/cloudflare/workflow.d.ts.map +1 -1
  131. package/lib/cloudflare/workflow.js +23 -18
  132. package/lib/cloudflare/workflow.js.map +1 -1
  133. package/lib/context.d.ts +2 -2
  134. package/lib/context.d.ts.map +1 -1
  135. package/lib/docker/api.d.ts.map +1 -1
  136. package/lib/docker/api.js +30 -8
  137. package/lib/docker/api.js.map +1 -1
  138. package/lib/fs/file-system-state-store.d.ts +5 -20
  139. package/lib/fs/file-system-state-store.d.ts.map +1 -1
  140. package/lib/fs/file-system-state-store.js +5 -121
  141. package/lib/fs/file-system-state-store.js.map +1 -1
  142. package/lib/fs/index.d.ts +0 -1
  143. package/lib/fs/index.d.ts.map +1 -1
  144. package/lib/fs/index.js +0 -1
  145. package/lib/fs/index.js.map +1 -1
  146. package/lib/llms.cloudflare.txt +6 -5
  147. package/lib/planetscale/password.js +1 -1
  148. package/lib/planetscale/password.js.map +1 -1
  149. package/lib/scope.d.ts.map +1 -1
  150. package/lib/scope.js +3 -6
  151. package/lib/scope.js.map +1 -1
  152. package/lib/state/cloudflare-state-store.d.ts +34 -0
  153. package/lib/state/cloudflare-state-store.d.ts.map +1 -0
  154. package/lib/state/cloudflare-state-store.js +116 -0
  155. package/lib/state/cloudflare-state-store.js.map +1 -0
  156. package/lib/state/d1-state-store.d.ts +15 -0
  157. package/lib/state/d1-state-store.d.ts.map +1 -0
  158. package/lib/{cloudflare → state}/d1-state-store.js +31 -27
  159. package/lib/state/d1-state-store.js.map +1 -0
  160. package/lib/{cloudflare/do-state-store/types.d.ts → state/dofs-state-store/api.d.ts} +1 -1
  161. package/lib/state/dofs-state-store/api.d.ts.map +1 -0
  162. package/lib/state/dofs-state-store/api.js +1 -0
  163. package/lib/state/dofs-state-store/api.js.map +1 -0
  164. package/lib/{cloudflare/do-state-store/store.d.ts → state/dofs-state-store/index.d.ts} +10 -5
  165. package/lib/state/dofs-state-store/index.d.ts.map +1 -0
  166. package/lib/{cloudflare/do-state-store/store.js → state/dofs-state-store/index.js} +15 -11
  167. package/lib/state/dofs-state-store/index.js.map +1 -0
  168. package/lib/{cloudflare/do-state-store/internal.d.ts → state/dofs-state-store/store.d.ts} +4 -5
  169. package/lib/state/dofs-state-store/store.d.ts.map +1 -0
  170. package/lib/{cloudflare/do-state-store/internal.js → state/dofs-state-store/store.js} +7 -22
  171. package/lib/state/dofs-state-store/store.js.map +1 -0
  172. package/lib/state/file-system-state-store.d.ts +21 -0
  173. package/lib/state/file-system-state-store.d.ts.map +1 -0
  174. package/lib/state/file-system-state-store.js +122 -0
  175. package/lib/state/file-system-state-store.js.map +1 -0
  176. package/lib/state/index.d.ts +7 -0
  177. package/lib/state/index.d.ts.map +1 -0
  178. package/lib/state/index.js +7 -0
  179. package/lib/state/index.js.map +1 -0
  180. package/lib/state/migrations.d.ts +2 -0
  181. package/lib/state/migrations.d.ts.map +1 -0
  182. package/lib/state/migrations.js +3 -0
  183. package/lib/state/migrations.js.map +1 -0
  184. package/lib/state/operations.d.ts +36 -0
  185. package/lib/state/operations.d.ts.map +1 -0
  186. package/lib/state/operations.js +126 -0
  187. package/lib/state/operations.js.map +1 -0
  188. package/lib/state/proxy.d.ts +53 -0
  189. package/lib/state/proxy.d.ts.map +1 -0
  190. package/lib/state/proxy.js +65 -0
  191. package/lib/state/proxy.js.map +1 -0
  192. package/lib/{cloudflare → state}/r2-rest-state-store.d.ts +3 -1
  193. package/lib/state/r2-rest-state-store.d.ts.map +1 -0
  194. package/lib/{cloudflare → state}/r2-rest-state-store.js +6 -4
  195. package/lib/state/r2-rest-state-store.js.map +1 -0
  196. package/lib/state/schema.d.ts.map +1 -0
  197. package/lib/state/schema.js.map +1 -0
  198. package/lib/{sqlite → state}/sqlite-state-store.d.ts +5 -3
  199. package/lib/state/sqlite-state-store.d.ts.map +1 -0
  200. package/lib/{sqlite → state}/sqlite-state-store.js +15 -6
  201. package/lib/state/sqlite-state-store.js.map +1 -0
  202. package/lib/test/vitest.d.ts.map +1 -1
  203. package/lib/test/vitest.js +3 -6
  204. package/lib/test/vitest.js.map +1 -1
  205. package/lib/util/detect-node-runtime.d.ts +3 -0
  206. package/lib/util/detect-node-runtime.d.ts.map +1 -0
  207. package/lib/util/detect-node-runtime.js +10 -0
  208. package/lib/util/detect-node-runtime.js.map +1 -0
  209. package/lib/util/detect-package-manager.d.ts +2 -2
  210. package/lib/util/detect-package-manager.d.ts.map +1 -1
  211. package/lib/util/detect-package-manager.js +15 -5
  212. package/lib/util/detect-package-manager.js.map +1 -1
  213. package/lib/util/http-server.d.ts.map +1 -0
  214. package/lib/{cloudflare/miniflare → util}/http-server.js +1 -1
  215. package/lib/util/http-server.js.map +1 -0
  216. package/lib/util/memoize.d.ts +1 -0
  217. package/lib/util/memoize.d.ts.map +1 -1
  218. package/lib/util/memoize.js +2 -8
  219. package/lib/util/memoize.js.map +1 -1
  220. package/lib/util/neverthrow.d.ts +16 -0
  221. package/lib/util/neverthrow.d.ts.map +1 -0
  222. package/lib/util/neverthrow.js +46 -0
  223. package/lib/util/neverthrow.js.map +1 -0
  224. package/package.json +18 -16
  225. package/src/apply.ts +31 -10
  226. package/src/build-date.ts +1 -1
  227. package/src/cloudflare/ai.ts +10 -5
  228. package/src/cloudflare/analytics-engine.ts +20 -11
  229. package/src/cloudflare/{types.ts → api-response.ts} +31 -0
  230. package/src/cloudflare/api.ts +18 -57
  231. package/src/cloudflare/auth.ts +79 -211
  232. package/src/cloudflare/browser-rendering.ts +16 -2
  233. package/src/cloudflare/bundle/fs.ts +5 -0
  234. package/src/cloudflare/bundle/internal-worker-bundle.ts +21 -0
  235. package/src/cloudflare/compatibility-presets.ts +34 -0
  236. package/src/cloudflare/container.ts +70 -3
  237. package/src/cloudflare/dispatch-namespace.ts +28 -0
  238. package/src/cloudflare/durable-object-namespace.ts +38 -27
  239. package/src/cloudflare/hyperdrive.ts +19 -5
  240. package/src/cloudflare/images.ts +32 -17
  241. package/src/cloudflare/index.ts +1 -3
  242. package/src/cloudflare/miniflare/miniflare.ts +10 -7
  243. package/src/cloudflare/miniflare/{mixed-mode.ts → remote-binding-proxy.ts} +25 -75
  244. package/src/cloudflare/oauth.ts +300 -0
  245. package/src/cloudflare/state.ts +35 -0
  246. package/src/cloudflare/user.ts +40 -73
  247. package/src/cloudflare/vectorize-index.ts +7 -2
  248. package/src/cloudflare/version-metadata.ts +19 -2
  249. package/src/cloudflare/vite.ts +2 -1
  250. package/src/cloudflare/worker-metadata.ts +18 -43
  251. package/src/cloudflare/worker-subdomain.ts +43 -37
  252. package/src/cloudflare/{worker/tail.ts → worker-tail.ts} +13 -10
  253. package/src/cloudflare/worker.ts +74 -23
  254. package/src/cloudflare/workflow.ts +38 -19
  255. package/src/context.ts +2 -2
  256. package/src/docker/api.ts +33 -8
  257. package/src/fs/file-system-state-store.ts +5 -148
  258. package/src/fs/index.ts +0 -1
  259. package/src/llms.cloudflare.txt +6 -5
  260. package/src/planetscale/password.ts +1 -1
  261. package/src/scope.ts +3 -6
  262. package/src/state/cloudflare-state-store.ts +170 -0
  263. package/src/state/d1-state-store.ts +102 -0
  264. package/src/{cloudflare/do-state-store/store.ts → state/dofs-state-store/index.ts} +20 -13
  265. package/src/{cloudflare/do-state-store/internal.ts → state/dofs-state-store/store.ts} +9 -27
  266. package/src/state/file-system-state-store.ts +149 -0
  267. package/src/state/index.ts +6 -0
  268. package/src/state/migrations.ts +9 -0
  269. package/src/state/operations.ts +152 -0
  270. package/src/state/proxy.ts +132 -0
  271. package/src/{cloudflare → state}/r2-rest-state-store.ts +11 -8
  272. package/src/{sqlite → state}/sqlite-state-store.ts +18 -10
  273. package/src/test/vitest.ts +8 -6
  274. package/src/util/detect-node-runtime.ts +12 -0
  275. package/src/util/detect-package-manager.ts +19 -6
  276. package/src/{cloudflare/miniflare → util}/http-server.ts +1 -1
  277. package/src/util/memoize.ts +2 -8
  278. package/src/util/neverthrow.ts +64 -0
  279. package/templates/astro/package.json +3 -3
  280. package/templates/nuxt/package.json +3 -3
  281. package/templates/react-router/package.json +3 -3
  282. package/templates/rwsdk/alchemy.run.ts +1 -1
  283. package/templates/rwsdk/package.json +3 -3
  284. package/templates/sveltekit/package.json +3 -3
  285. package/templates/tanstack-start/package.json +3 -3
  286. package/templates/typescript/package.json +3 -2
  287. package/templates/typescript/tsconfig.json +1 -0
  288. package/templates/vite/package.json +3 -3
  289. package/workers/cloudflare-state-store.js +5638 -0
  290. package/workers/cloudflare-state-store.ts +108 -0
  291. package/workers/{do-state-store.js → dofs-state-store.js} +4 -4
  292. package/workers/{do-state-store.ts → dofs-state-store.ts} +12 -8
  293. package/workers/{mixed-mode-proxy-worker.js → remote-binding-proxy.js} +3 -3
  294. package/workers/remote-binding-proxy.ts +45 -0
  295. package/lib/cloudflare/d1-state-store.d.ts +0 -10
  296. package/lib/cloudflare/d1-state-store.d.ts.map +0 -1
  297. package/lib/cloudflare/d1-state-store.js.map +0 -1
  298. package/lib/cloudflare/do-state-store/index.d.ts +0 -2
  299. package/lib/cloudflare/do-state-store/index.d.ts.map +0 -1
  300. package/lib/cloudflare/do-state-store/index.js +0 -2
  301. package/lib/cloudflare/do-state-store/index.js.map +0 -1
  302. package/lib/cloudflare/do-state-store/internal.d.ts.map +0 -1
  303. package/lib/cloudflare/do-state-store/internal.js.map +0 -1
  304. package/lib/cloudflare/do-state-store/store.d.ts.map +0 -1
  305. package/lib/cloudflare/do-state-store/store.js.map +0 -1
  306. package/lib/cloudflare/do-state-store/types.d.ts.map +0 -1
  307. package/lib/cloudflare/do-state-store/types.js +0 -1
  308. package/lib/cloudflare/do-state-store/types.js.map +0 -1
  309. package/lib/cloudflare/miniflare/http-server.d.ts.map +0 -1
  310. package/lib/cloudflare/miniflare/http-server.js.map +0 -1
  311. package/lib/cloudflare/miniflare/mixed-mode.d.ts.map +0 -1
  312. package/lib/cloudflare/miniflare/mixed-mode.js.map +0 -1
  313. package/lib/cloudflare/r2-rest-state-store.d.ts.map +0 -1
  314. package/lib/cloudflare/r2-rest-state-store.js.map +0 -1
  315. package/lib/cloudflare/types.d.ts.map +0 -1
  316. package/lib/cloudflare/types.js +0 -19
  317. package/lib/cloudflare/types.js.map +0 -1
  318. package/lib/cloudflare/worker/shared.d.ts +0 -4
  319. package/lib/cloudflare/worker/shared.d.ts.map +0 -1
  320. package/lib/cloudflare/worker/shared.js +0 -21
  321. package/lib/cloudflare/worker/shared.js.map +0 -1
  322. package/lib/cloudflare/worker/tail.d.ts.map +0 -1
  323. package/lib/cloudflare/worker/tail.js.map +0 -1
  324. package/lib/sqlite/base-sqlite-state-store.d.ts +0 -31
  325. package/lib/sqlite/base-sqlite-state-store.d.ts.map +0 -1
  326. package/lib/sqlite/base-sqlite-state-store.js +0 -124
  327. package/lib/sqlite/base-sqlite-state-store.js.map +0 -1
  328. package/lib/sqlite/index.d.ts +0 -2
  329. package/lib/sqlite/index.d.ts.map +0 -1
  330. package/lib/sqlite/index.js +0 -2
  331. package/lib/sqlite/index.js.map +0 -1
  332. package/lib/sqlite/schema.d.ts.map +0 -1
  333. package/lib/sqlite/schema.js.map +0 -1
  334. package/lib/sqlite/sqlite-state-store.d.ts.map +0 -1
  335. package/lib/sqlite/sqlite-state-store.js.map +0 -1
  336. package/src/cloudflare/d1-state-store.ts +0 -105
  337. package/src/cloudflare/do-state-store/index.ts +0 -1
  338. package/src/cloudflare/worker/shared.ts +0 -30
  339. package/src/sqlite/base-sqlite-state-store.ts +0 -199
  340. package/src/sqlite/index.ts +0 -1
  341. package/templates/typescript/src/worker.js +0 -5
  342. package/workers/mixed-mode-proxy-worker.ts +0 -46
  343. /package/drizzle/{0000_busy_mauler.sql → default/0000_busy_mauler.sql} +0 -0
  344. /package/drizzle/{0001_concerned_iceman.sql → default/0001_concerned_iceman.sql} +0 -0
  345. /package/drizzle/{meta → default/meta}/0000_snapshot.json +0 -0
  346. /package/drizzle/{meta → default/meta}/0001_snapshot.json +0 -0
  347. /package/drizzle/{meta → default/meta}/_journal.json +0 -0
  348. /package/lib/{sqlite → state}/schema.d.ts +0 -0
  349. /package/lib/{sqlite → state}/schema.js +0 -0
  350. /package/lib/{cloudflare/miniflare → util}/http-server.d.ts +0 -0
  351. /package/src/{cloudflare/do-state-store/types.ts → state/dofs-state-store/api.ts} +0 -0
  352. /package/src/{sqlite → state}/schema.ts +0 -0
@@ -1,233 +1,101 @@
1
- import fs from "node:fs/promises";
2
- import os from "node:os";
3
- import path from "node:path";
1
+ import { alchemy } from "../alchemy.ts";
4
2
  import type { Secret } from "../secret.ts";
5
- import { createXdgAppPaths } from "../util/xdg-paths.ts";
6
- /**
7
- * Authentication options for Cloudflare API
8
- */
9
- export type CloudflareAuthOptions =
10
- | CloudflareApiKeyAuthOptions
11
- | CloudflareApiTokenAuthOptions;
12
-
13
- export type CloudflareApiKeyAuthOptions = {
14
- /**
15
- * API Key to use with API Key
16
- */
17
- apiKey: Secret;
18
- /**
19
- * Email to use with API Key
20
- * If not provided, will attempt to discover from Cloudflare API
21
- */
22
- email: string;
3
+ import type { CloudflareApiOptions } from "./api.ts";
4
+ import { getRefreshedWranglerConfig } from "./oauth.ts";
5
+ import { getUserEmailFromApiKey } from "./user.ts";
23
6
 
24
- /**
25
- * API Token to use with API Key
26
- */
27
- apiToken?: undefined;
28
- };
29
-
30
- export function isCloudflareApiKeyAuthOptions(
31
- options: CloudflareAuthOptions | undefined,
32
- ): options is CloudflareApiKeyAuthOptions {
33
- return options !== undefined && options.apiKey !== undefined;
7
+ export interface CloudflareApiTokenAuthOptions {
8
+ type: "api-token";
9
+ apiToken: Secret<string>;
34
10
  }
35
11
 
36
- export type CloudflareApiTokenAuthOptions = {
37
- /**
38
- * API Token to use with API Key
39
- */
40
- apiToken?: Secret;
12
+ export interface CloudflareApiKeyAuthOptions {
13
+ type: "api-key";
14
+ apiKey: Secret;
15
+ apiEmail: string;
16
+ }
41
17
 
42
- /**
43
- * API Key to use with API Token
44
- */
45
- apiKey?: undefined;
18
+ export interface CloudflareWranglerAuthOptions {
19
+ type: "wrangler";
20
+ }
46
21
 
47
- /**
48
- * Email to use with API Token
49
- */
50
- email?: undefined;
22
+ export type CloudflareAuthOptions =
23
+ | CloudflareApiTokenAuthOptions
24
+ | CloudflareApiKeyAuthOptions
25
+ | CloudflareWranglerAuthOptions;
26
+
27
+ export const isCloudflareAuthOptions = (
28
+ input?: CloudflareApiOptions | CloudflareAuthOptions,
29
+ ): input is CloudflareAuthOptions => {
30
+ return (
31
+ input !== undefined &&
32
+ "type" in input &&
33
+ (input.type === "api-token" ||
34
+ input.type === "api-key" ||
35
+ input.type === "wrangler")
36
+ );
51
37
  };
52
38
 
53
- export function isCloudflareApiTokenAuthOptions(
54
- options: CloudflareAuthOptions | undefined,
55
- ): options is CloudflareApiTokenAuthOptions {
56
- return options !== undefined && options.apiToken !== undefined;
57
- }
58
-
59
- export async function getCloudflareAuthHeaders(
60
- options: CloudflareAuthOptions | undefined,
61
- ): Promise<Record<string, string>> {
62
- if (isCloudflareApiKeyAuthOptions(options)) {
63
- // Global API Key
64
- return {
65
- "X-Auth-Key": options.apiKey.unencrypted,
66
- "X-Auth-Email": options.email,
67
- };
68
- } else if (isCloudflareApiTokenAuthOptions(options)) {
69
- // API Token
70
- return {
71
- Authorization: `Bearer ${options.apiToken?.unencrypted}`,
72
- };
39
+ export async function normalizeAuthOptions(
40
+ input?: CloudflareApiOptions | CloudflareAuthOptions,
41
+ ): Promise<CloudflareAuthOptions> {
42
+ if (isCloudflareAuthOptions(input)) {
43
+ return input;
73
44
  }
74
- // Wrangler OAuth Token
75
- const authConfig = await getRefreshedAuthConfig();
76
- if (authConfig.oauth_token) {
45
+
46
+ const email = async (apiKey: Secret<string>) =>
47
+ input?.email ??
48
+ process.env.CLOUDFLARE_EMAIL ??
49
+ (await getUserEmailFromApiKey(apiKey.unencrypted));
50
+
51
+ if (input?.apiKey) {
77
52
  return {
78
- Authorization: `Bearer ${authConfig.oauth_token}`,
53
+ type: "api-key",
54
+ apiKey: input.apiKey,
55
+ apiEmail: await email(input.apiKey),
79
56
  };
80
57
  }
81
- throw new Error(
82
- "Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY?",
83
- );
84
- }
85
-
86
- async function refreshAuthToken(
87
- options: WranglerConfig,
88
- ): Promise<WranglerConfig> {
89
- const response = await fetch("https://dash.cloudflare.com/oauth2/token", {
90
- method: "POST",
91
- headers: {
92
- "Content-Type": "application/x-www-form-urlencoded",
93
- },
94
- body: new URLSearchParams({
95
- grant_type: "refresh_token",
96
- refresh_token: options.refresh_token!,
97
- client_id: "54d11594-84e4-41aa-b438-e81b8fa78ee7",
98
- }).toString(),
99
- });
100
-
101
- if (!response.ok) {
102
- throw new Error(
103
- `Failed to refresh auth token: ${response.status} ${response.statusText} ${await response.text()}`,
104
- );
58
+ if (input?.apiToken) {
59
+ return { type: "api-token", apiToken: input.apiToken };
105
60
  }
106
-
107
- const data: any = await response.json();
108
- if (!data.access_token) {
109
- throw new Error("Failed to refresh auth token - no access token returned");
61
+ if (process.env.CLOUDFLARE_API_KEY) {
62
+ const key = alchemy.secret(process.env.CLOUDFLARE_API_KEY);
63
+ return { type: "api-key", apiKey: key, apiEmail: await email(key) };
110
64
  }
111
-
112
- options.oauth_token = data.access_token;
113
- options.refresh_token = data.refresh_token;
114
- options.expiration_time = new Date(
115
- Date.now() + data.expires_in * 1000,
116
- ).toISOString();
117
- options.scopes = data.scope?.split(" ") || [];
118
-
119
- return options;
120
- }
121
-
122
- interface WranglerConfig {
123
- path: string;
124
- oauth_token?: string;
125
- refresh_token?: string;
126
- expiration_time?: string;
127
- scopes?: string[];
128
- /** exists is `false` if the config file doesn't exist, like in CI */
129
- exists?: boolean;
130
- /** @deprecated - this field was only provided by the deprecated v1 `wrangler config` command. */
131
- api_token?: string;
132
- }
133
-
134
- async function getRefreshedAuthConfig(): Promise<WranglerConfig> {
135
- let authConfig = await readWranglerConfig();
136
- if (authConfig.expiration_time) {
137
- const expiry = new Date(authConfig.expiration_time);
138
- // if expiring in 10s
139
- if (expiry.getTime() < Date.now() + 10 * 1000) {
140
- authConfig = await refreshAuthToken(authConfig);
141
- authConfigCache[authConfig.path] = authConfig;
142
- await writeWranglerConfig(authConfig);
143
- }
65
+ if (process.env.CLOUDFLARE_API_TOKEN) {
66
+ return {
67
+ type: "api-token",
68
+ apiToken: alchemy.secret(process.env.CLOUDFLARE_API_TOKEN),
69
+ };
144
70
  }
145
- return authConfig;
146
- }
147
-
148
- async function writeWranglerConfig(config: WranglerConfig) {
149
- if (config.exists === false) return;
150
-
151
- const TOML = await import("@iarna/toml");
152
- const configPath = await findWranglerConfig();
153
- config = {
154
- ...config,
155
- };
156
- // @ts-ignore - i put this here
157
- delete config.path;
158
- const toml = TOML.stringify(config as any);
159
- await fs.writeFile(configPath, toml);
71
+ return { type: "wrangler" };
160
72
  }
161
73
 
162
- // cache the file once per process
163
- const authConfigCache: Record<string, WranglerConfig> = {};
164
-
165
- async function readWranglerConfig(): Promise<WranglerConfig> {
166
- const configPath = await findWranglerConfig();
167
- try {
168
- const config = (authConfigCache[configPath] ??= await parseTOML(
169
- await fs.readFile(configPath, "utf-8"),
170
- ));
171
- config.path = configPath;
172
-
173
- return config;
174
- } catch (e: any) {
175
- if (e.code === "ENOENT") {
176
- // The config doesn't exist
74
+ export async function getCloudflareAuthHeaders(
75
+ authOptions: CloudflareAuthOptions,
76
+ ): Promise<Record<string, string>> {
77
+ switch (authOptions.type) {
78
+ case "api-token":
79
+ return { Authorization: `Bearer ${authOptions.apiToken.unencrypted}` };
80
+ case "api-key":
177
81
  return {
178
- path: configPath,
179
- exists: false,
82
+ "X-Auth-Key": authOptions.apiKey.unencrypted,
83
+ "X-Auth-Email": authOptions.apiEmail,
84
+ };
85
+ case "wrangler": {
86
+ const wranglerConfig = await getRefreshedWranglerConfig();
87
+ if (wranglerConfig.isErr()) {
88
+ throw new Error(
89
+ [
90
+ wranglerConfig.error.message,
91
+ "Please run `alchemy login`, or set either CLOUDFLARE_API_TOKEN or CLOUDFLARE_API_KEY in your environment.",
92
+ "Learn more: https://alchemy.run/guides/cloudflare/",
93
+ ].join("\n"),
94
+ );
95
+ }
96
+ return {
97
+ Authorization: `Bearer ${wranglerConfig.value.oauth_token}`,
180
98
  };
181
99
  }
182
-
183
- throw e;
184
- }
185
- }
186
-
187
- let wranglerConfigPath: string | undefined;
188
-
189
- async function findWranglerConfig(): Promise<string> {
190
- if (wranglerConfigPath) {
191
- return wranglerConfigPath;
192
- }
193
- const environment = process.env.WRANGLER_API_ENVIRONMENT ?? "production";
194
- const filePath = path.join(
195
- "config",
196
- `${environment === "production" ? "default.toml" : `${environment}.toml`}`,
197
- );
198
-
199
- const xdgAppPaths = createXdgAppPaths(".wrangler");
200
- //TODO: We should implement a custom path --global-config and/or the WRANGLER_HOME type environment variable
201
- const configDir = xdgAppPaths.config(); // New XDG compliant config path
202
- const legacyConfigDir = path.join(os.homedir(), ".wrangler"); // Legacy config in user's home directory
203
-
204
- // Check for the .wrangler directory in root if it is not there then use the XDG compliant path.
205
- wranglerConfigPath = path.join(
206
- (await isDirectory(legacyConfigDir)) ? legacyConfigDir : configDir,
207
- filePath,
208
- );
209
- return wranglerConfigPath;
210
- }
211
-
212
- async function parseTOML(input: string): Promise<any> {
213
- const TOML = await import("@iarna/toml");
214
- try {
215
- // Normalize CRLF to LF to avoid hitting https://github.com/iarna/iarna-toml/issues/33.
216
- const normalizedInput = input.replace(/\r\n/g, "\n");
217
- return TOML.parse(normalizedInput);
218
- } catch (err: any) {
219
- const { name } = err;
220
- if (name !== "TomlError") {
221
- throw err;
222
- }
223
- throw new Error("TOML parse error");
224
- }
225
- }
226
-
227
- async function isDirectory(dir: string) {
228
- try {
229
- return (await fs.stat(dir)).isDirectory();
230
- } catch (_err) {
231
- return false;
232
100
  }
233
101
  }
@@ -1,3 +1,17 @@
1
- export class BrowserRendering {
2
- public readonly type = "browser";
1
+ export type BrowserRendering = {
2
+ type: "browser";
3
+ };
4
+
5
+ /**
6
+ * Creates a browser rendering binding for running browser tasks in Workers.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const browser = BrowserRendering();
11
+ * ```
12
+ */
13
+ export function BrowserRendering(): BrowserRendering {
14
+ return {
15
+ type: "browser",
16
+ };
3
17
  }
@@ -45,6 +45,11 @@ export class FSBundleProvider implements WorkerBundleProvider {
45
45
  }
46
46
  }),
47
47
  );
48
+ if (fileNames.size === 0) {
49
+ throw new Error(
50
+ `No files found matching ${this.globs.join(", ")} in ${this.root}`,
51
+ );
52
+ }
48
53
  const { files, hash } = await parseFiles(
49
54
  this.root,
50
55
  Array.from(fileNames),
@@ -0,0 +1,21 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { memoize } from "../../util/memoize.ts";
5
+
6
+ export type InternalWorker =
7
+ | "cloudflare-state-store"
8
+ | "dofs-state-store"
9
+ | "remote-binding-proxy";
10
+
11
+ export const getInternalWorkerBundle = memoize(async (name: InternalWorker) => {
12
+ const content = await fs.readFile(
13
+ path.join(import.meta.dirname, "..", "..", "..", "workers", `${name}.js`),
14
+ );
15
+ return {
16
+ file: new File([content], `${name}.js`, {
17
+ type: "application/javascript+module",
18
+ }),
19
+ tag: `${name}:${crypto.createHash("sha256").update(content).digest("hex")}`,
20
+ };
21
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Compatibility presets for Cloudflare Workers
3
+ *
4
+ * These presets provide common sets of compatibility flags to avoid
5
+ * users having to remember which flags they need for common use cases.
6
+ */
7
+
8
+ /**
9
+ * Mapping of compatibility presets to their respective compatibility flags
10
+ */
11
+ export const COMPATIBILITY_PRESETS = {
12
+ /**
13
+ * Node.js compatibility preset
14
+ * Enables Node.js APIs and runtime compatibility
15
+ */
16
+ node: ["nodejs_compat"],
17
+ } as const;
18
+
19
+ export type CompatibilityPreset = keyof typeof COMPATIBILITY_PRESETS;
20
+
21
+ /**
22
+ * Union preset compatibility flags with user-provided flags
23
+ */
24
+ export function unionCompatibilityFlags(
25
+ preset: CompatibilityPreset | undefined,
26
+ userFlags: string[] = [],
27
+ ): string[] {
28
+ if (!preset) {
29
+ return userFlags;
30
+ }
31
+
32
+ const presetFlags = COMPATIBILITY_PRESETS[preset];
33
+ return Array.from(new Set([...presetFlags, ...userFlags]));
34
+ }
@@ -545,7 +545,7 @@ export const ContainerApplication = Resource(
545
545
  let application: ContainerApplicationData;
546
546
 
547
547
  try {
548
- application = await createContainerApplication(api, {
548
+ application = await createContainerApplication(api, props.adopt, {
549
549
  name: props.name,
550
550
  scheduling_policy: props.schedulingPolicy ?? "default",
551
551
  instances: props.instances ?? 1,
@@ -734,6 +734,23 @@ export interface ContainerApplicationData {
734
734
  [key: string]: any;
735
735
  }
736
736
 
737
+ export async function getContainerApplication(
738
+ api: CloudflareApi,
739
+ applicationId: string,
740
+ ) {
741
+ const response = await api.get(
742
+ `/accounts/${api.accountId}/containers/applications/${applicationId}`,
743
+ );
744
+
745
+ const result = (await response.json()) as {
746
+ result: ContainerApplicationData;
747
+ errors: { message: string }[];
748
+ };
749
+ if (response.ok) {
750
+ return result.result;
751
+ }
752
+ }
753
+
737
754
  export async function listContainerApplications(
738
755
  api: CloudflareApi,
739
756
  ): Promise<ContainerApplicationData[]> {
@@ -770,11 +787,15 @@ export interface CreateContainerApplicationBody {
770
787
  instances?: number;
771
788
  scheduling_policy?: string;
772
789
  constraints?: { tier: number };
790
+ affinities?: {
791
+ colocation?: "datacenter";
792
+ };
773
793
  [key: string]: any;
774
794
  }
775
795
 
776
796
  export async function createContainerApplication(
777
797
  api: CloudflareApi,
798
+ adopt: boolean | undefined,
778
799
  body: CreateContainerApplicationBody,
779
800
  ) {
780
801
  const response = await api.post(
@@ -783,17 +804,63 @@ export async function createContainerApplication(
783
804
  );
784
805
  const result = (await response.json()) as {
785
806
  result: ContainerApplicationData;
786
- errors: { message: string }[];
807
+ errors: { message: string; code: number }[];
787
808
  };
788
809
  if (response.ok) {
789
810
  return result.result;
790
811
  }
791
812
 
813
+ const error = result.errors.find((e) => e.code === 1000);
814
+ if (error) {
815
+ // WEIRD: json-encoded error message - might change when they release an official API
816
+ const errorMessage = JSON.parse(error.message) as {
817
+ error: "DURABLE_OBJECT_ALREADY_HAS_APPLICATION" | (string & {});
818
+ details: {
819
+ name: string;
820
+ id: string;
821
+ };
822
+ };
823
+
824
+ if (errorMessage.error === "DURABLE_OBJECT_ALREADY_HAS_APPLICATION") {
825
+ if (!adopt) {
826
+ throw new Error(
827
+ `Durable Object namespace ${body.durable_objects?.namespace_id} already has an application with id ${errorMessage.details.id}. Use adopt: true to adopt it.`,
828
+ );
829
+ }
830
+ const application = await getContainerApplication(
831
+ api,
832
+ errorMessage.details.id,
833
+ );
834
+ if (application) {
835
+ const currentId = application.durable_objects.namespace_id;
836
+ const desiredId = body.durable_objects?.namespace_id;
837
+ if (currentId === desiredId) {
838
+ await updateContainerApplication(api, application.id, {
839
+ configuration: body.configuration,
840
+ instances: body.instances,
841
+ constraints: body.constraints,
842
+ scheduling_policy: body.scheduling_policy,
843
+ max_instances: body.max_instances,
844
+ affinities: body.affinities,
845
+ // TODO(sam): API does not accepet this as input, we may need to repace
846
+ // durable_objects: body.durable_objects,
847
+ });
848
+ // it's the same application, so we can just adpt it
849
+ return application;
850
+ } else {
851
+ // TODO(sam): not sure what to do in this case
852
+ throw new Error(
853
+ "Cannot adopt an existing Container Application that is bound to a different Durable Object",
854
+ );
855
+ }
856
+ }
857
+ }
858
+ }
859
+
792
860
  throw Error(
793
861
  `Failed to create container application: ${result.errors?.map((e: { message: string }) => e.message).join(", ") ?? "Unknown error"}`,
794
862
  );
795
863
  }
796
-
797
864
  type Region =
798
865
  | "AFR"
799
866
  | "APAC"
@@ -279,3 +279,31 @@ export async function deleteDispatchNamespace(
279
279
  );
280
280
  }
281
281
  }
282
+
283
+ export async function listWorkersInNamespace(
284
+ api: CloudflareApi,
285
+ namespace: string,
286
+ ): Promise<Array<{ id: string; created_on: string; modified_on: string }>> {
287
+ const response = await api.get(
288
+ `/accounts/${api.accountId}/workers/dispatch/namespaces/${namespace}/scripts`,
289
+ );
290
+
291
+ if (!response.ok) {
292
+ await handleApiError(
293
+ response,
294
+ "list workers in",
295
+ "dispatch_namespace",
296
+ namespace,
297
+ );
298
+ }
299
+
300
+ const data = (await response.json()) as {
301
+ result: Array<{
302
+ id: string;
303
+ created_on: string;
304
+ modified_on: string;
305
+ }>;
306
+ };
307
+
308
+ return data.result || [];
309
+ }
@@ -3,7 +3,7 @@ import type { Binding } from "./bindings.ts";
3
3
  /**
4
4
  * Properties for creating a Durable Object Namespace
5
5
  */
6
- export interface DurableObjectNamespaceInput {
6
+ export interface DurableObjectNamespaceProps {
7
7
  className: string;
8
8
  scriptName?: string | undefined;
9
9
  environment?: string | undefined;
@@ -11,6 +11,18 @@ export interface DurableObjectNamespaceInput {
11
11
  namespaceId?: string | undefined;
12
12
  }
13
13
 
14
+ export type DurableObjectNamespace<T = any> = {
15
+ type: "durable_object_namespace";
16
+ id: string;
17
+ className: string;
18
+ scriptName?: string;
19
+ environment?: string;
20
+ sqlite?: boolean;
21
+ namespaceId?: string;
22
+ // @ts-ignore - phantom type
23
+ __service__: T;
24
+ };
25
+
14
26
  export function isDurableObjectNamespace(
15
27
  binding: Binding,
16
28
  ): binding is DurableObjectNamespace {
@@ -20,48 +32,47 @@ export function isDurableObjectNamespace(
20
32
  }
21
33
 
22
34
  /**
35
+ * Creates a Durable Object namespace binding.
36
+ *
23
37
  * @example
38
+ * ```ts
24
39
  * // Create a basic Durable Object namespace for stateful chat rooms
25
- * const rooms = new DurableObjectNamespace("chat-rooms", {
40
+ * const rooms = DurableObjectNamespace("chat-rooms", {
26
41
  * className: "ChatRoom"
27
42
  * });
43
+ * ```
28
44
  *
29
45
  * @example
46
+ * ```ts
30
47
  * // Create a Durable Object with SQLite storage for user data
31
- * const users = new DurableObjectNamespace("user-store", {
48
+ * const users = DurableObjectNamespace("user-store", {
32
49
  * className: "User",
33
50
  * sqlite: true
34
51
  * });
52
+ * ```
35
53
  *
36
54
  * @example
55
+ * ```ts
37
56
  * // Create a Durable Object in production for game state management
38
- * const game = new DurableObjectNamespace("game-state", {
57
+ * const game = DurableObjectNamespace("game-state", {
39
58
  * className: "GameState",
40
59
  * scriptName: "game-worker",
41
60
  * environment: "production"
42
61
  * });
62
+ * ```
43
63
  */
44
- export class DurableObjectNamespace<T = any>
45
- implements DurableObjectNamespaceInput
46
- {
47
- public readonly type = "durable_object_namespace" as const;
48
- // alias for bindingName to be consistent with other bindings
49
- public readonly className: string;
50
- public readonly scriptName?: string | undefined;
51
- public readonly environment?: string | undefined;
52
- public readonly sqlite?: boolean | undefined;
53
- public readonly namespaceId?: string | undefined;
54
-
55
- // @ts-ignore - phantom type
56
- protected readonly __service__: T;
57
-
58
- constructor(
59
- public readonly id: string,
60
- input: DurableObjectNamespaceInput,
61
- ) {
62
- this.className = input.className;
63
- this.scriptName = input.scriptName;
64
- this.environment = input.environment;
65
- this.sqlite = input.sqlite;
66
- }
64
+ export function DurableObjectNamespace<T = any>(
65
+ id: string,
66
+ props: DurableObjectNamespaceProps,
67
+ ): DurableObjectNamespace<T> {
68
+ return {
69
+ type: "durable_object_namespace",
70
+ id,
71
+ className: props.className,
72
+ scriptName: props.scriptName,
73
+ environment: props.environment,
74
+ sqlite: props.sqlite,
75
+ namespaceId: props.namespaceId,
76
+ __service__: undefined!,
77
+ };
67
78
  }