alchemy 0.55.3 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/bin/alchemy.js +14245 -14406
  2. package/bin/commands/create.ts +7 -7
  3. package/bin/commands/deploy.ts +2 -2
  4. package/bin/commands/destroy.ts +2 -2
  5. package/bin/commands/dev.ts +2 -2
  6. package/bin/commands/init.ts +6 -6
  7. package/bin/commands/login.ts +3 -3
  8. package/bin/commands/run.ts +2 -2
  9. package/bin/services/execute-alchemy.ts +3 -3
  10. package/bin/trpc.ts +49 -0
  11. package/lib/alchemy.d.ts.map +1 -1
  12. package/lib/alchemy.js +7 -0
  13. package/lib/alchemy.js.map +1 -1
  14. package/lib/apply.d.ts.map +1 -1
  15. package/lib/apply.js +3 -4
  16. package/lib/apply.js.map +1 -1
  17. package/lib/cloudflare/{astro.d.ts → astro/astro.d.ts} +6 -5
  18. package/lib/cloudflare/astro/astro.d.ts.map +1 -0
  19. package/lib/cloudflare/astro/astro.js +91 -0
  20. package/lib/cloudflare/astro/astro.js.map +1 -0
  21. package/lib/cloudflare/astro/plugin.d.ts +4 -0
  22. package/lib/cloudflare/astro/plugin.d.ts.map +1 -0
  23. package/lib/cloudflare/astro/plugin.js +10 -0
  24. package/lib/cloudflare/astro/plugin.js.map +1 -0
  25. package/lib/cloudflare/bundle/plugin-hot-reload.d.ts +1 -3
  26. package/lib/cloudflare/bundle/plugin-hot-reload.d.ts.map +1 -1
  27. package/lib/cloudflare/bundle/plugin-hot-reload.js +4 -1
  28. package/lib/cloudflare/bundle/plugin-hot-reload.js.map +1 -1
  29. package/lib/cloudflare/cloudflare-env-proxy.d.ts +4 -0
  30. package/lib/cloudflare/cloudflare-env-proxy.d.ts.map +1 -0
  31. package/lib/cloudflare/cloudflare-env-proxy.js +34 -0
  32. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -0
  33. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  34. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  35. package/lib/cloudflare/compatibility-presets.d.ts +1 -1
  36. package/lib/cloudflare/compatibility-presets.js +1 -1
  37. package/lib/cloudflare/compatibility-presets.js.map +1 -1
  38. package/lib/cloudflare/d1-local-migrations.js +1 -1
  39. package/lib/cloudflare/d1-local-migrations.js.map +1 -1
  40. package/lib/cloudflare/index.d.ts +8 -8
  41. package/lib/cloudflare/index.d.ts.map +1 -1
  42. package/lib/cloudflare/index.js +8 -8
  43. package/lib/cloudflare/index.js.map +1 -1
  44. package/lib/cloudflare/miniflare/build-worker-options.d.ts +22 -0
  45. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -0
  46. package/lib/cloudflare/miniflare/build-worker-options.js +394 -0
  47. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -0
  48. package/lib/cloudflare/miniflare/miniflare-controller.d.ts +23 -0
  49. package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -0
  50. package/lib/cloudflare/miniflare/miniflare-controller.js +111 -0
  51. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -0
  52. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
  53. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +5 -15
  54. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
  55. package/lib/cloudflare/miniflare/paths.d.ts +5 -0
  56. package/lib/cloudflare/miniflare/paths.d.ts.map +1 -0
  57. package/lib/cloudflare/miniflare/paths.js +35 -0
  58. package/lib/cloudflare/miniflare/paths.js.map +1 -0
  59. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts +1 -5
  60. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  61. package/lib/cloudflare/miniflare/remote-binding-proxy.js +17 -22
  62. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  63. package/lib/cloudflare/{nuxt.d.ts → nuxt/nuxt.d.ts} +4 -4
  64. package/lib/cloudflare/nuxt/nuxt.d.ts.map +1 -0
  65. package/lib/cloudflare/{nuxt.js → nuxt/nuxt.js} +8 -13
  66. package/lib/cloudflare/nuxt/nuxt.js.map +1 -0
  67. package/lib/cloudflare/nuxt/plugin.d.ts +4 -0
  68. package/lib/cloudflare/nuxt/plugin.d.ts.map +1 -0
  69. package/lib/cloudflare/nuxt/plugin.js +14 -0
  70. package/lib/cloudflare/nuxt/plugin.js.map +1 -0
  71. package/lib/cloudflare/oauth.js +2 -2
  72. package/lib/cloudflare/oauth.js.map +1 -1
  73. package/lib/cloudflare/orange.d.ts +3 -3
  74. package/lib/cloudflare/orange.d.ts.map +1 -1
  75. package/lib/cloudflare/orange.js +11 -21
  76. package/lib/cloudflare/orange.js.map +1 -1
  77. package/lib/cloudflare/react-router/plugin.d.ts +4 -0
  78. package/lib/cloudflare/react-router/plugin.d.ts.map +1 -0
  79. package/lib/cloudflare/react-router/plugin.js +11 -0
  80. package/lib/cloudflare/react-router/plugin.js.map +1 -0
  81. package/lib/cloudflare/react-router/react-router.d.ts +17 -0
  82. package/lib/cloudflare/react-router/react-router.d.ts.map +1 -0
  83. package/lib/cloudflare/react-router/react-router.js +21 -0
  84. package/lib/cloudflare/react-router/react-router.js.map +1 -0
  85. package/lib/cloudflare/redwood/plugin.d.ts +4 -0
  86. package/lib/cloudflare/redwood/plugin.d.ts.map +1 -0
  87. package/lib/cloudflare/redwood/plugin.js +19 -0
  88. package/lib/cloudflare/redwood/plugin.js.map +1 -0
  89. package/lib/cloudflare/{redwood.d.ts → redwood/redwood.d.ts} +5 -5
  90. package/lib/cloudflare/redwood/redwood.d.ts.map +1 -0
  91. package/lib/cloudflare/{redwood.js → redwood/redwood.js} +12 -13
  92. package/lib/cloudflare/redwood/redwood.js.map +1 -0
  93. package/lib/cloudflare/sveltekit/plugin.d.ts +4 -0
  94. package/lib/cloudflare/sveltekit/plugin.d.ts.map +1 -0
  95. package/lib/cloudflare/sveltekit/plugin.js +11 -0
  96. package/lib/cloudflare/sveltekit/plugin.js.map +1 -0
  97. package/lib/cloudflare/{sveltekit.d.ts → sveltekit/sveltekit.d.ts} +5 -5
  98. package/lib/cloudflare/sveltekit/sveltekit.d.ts.map +1 -0
  99. package/lib/cloudflare/{sveltekit.js → sveltekit/sveltekit.js} +4 -4
  100. package/lib/cloudflare/sveltekit/sveltekit.js.map +1 -0
  101. package/lib/cloudflare/tanstack-start/plugin.d.ts +16 -0
  102. package/lib/cloudflare/tanstack-start/plugin.d.ts.map +1 -0
  103. package/lib/cloudflare/tanstack-start/plugin.js +28 -0
  104. package/lib/cloudflare/tanstack-start/plugin.js.map +1 -0
  105. package/lib/cloudflare/{tanstack-start.d.ts → tanstack-start/tanstack-start.d.ts} +5 -5
  106. package/lib/cloudflare/tanstack-start/tanstack-start.d.ts.map +1 -0
  107. package/lib/cloudflare/tanstack-start/tanstack-start.js +11 -0
  108. package/lib/cloudflare/tanstack-start/tanstack-start.js.map +1 -0
  109. package/lib/cloudflare/vite/plugin.d.ts +4 -0
  110. package/lib/cloudflare/vite/plugin.d.ts.map +1 -0
  111. package/lib/cloudflare/vite/plugin.js +23 -0
  112. package/lib/cloudflare/vite/plugin.js.map +1 -0
  113. package/lib/cloudflare/{vite.d.ts → vite/vite.d.ts} +4 -4
  114. package/lib/cloudflare/vite/vite.d.ts.map +1 -0
  115. package/lib/cloudflare/vite/vite.js +19 -0
  116. package/lib/cloudflare/vite/vite.js.map +1 -0
  117. package/lib/cloudflare/website.d.ts +92 -70
  118. package/lib/cloudflare/website.d.ts.map +1 -1
  119. package/lib/cloudflare/website.js +225 -94
  120. package/lib/cloudflare/website.js.map +1 -1
  121. package/lib/cloudflare/worker-bundle.d.ts +3 -1
  122. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  123. package/lib/cloudflare/worker-bundle.js +42 -16
  124. package/lib/cloudflare/worker-bundle.js.map +1 -1
  125. package/lib/cloudflare/worker-stub.d.ts.map +1 -1
  126. package/lib/cloudflare/worker-stub.js +3 -6
  127. package/lib/cloudflare/worker-stub.js.map +1 -1
  128. package/lib/cloudflare/worker.d.ts +2 -7
  129. package/lib/cloudflare/worker.d.ts.map +1 -1
  130. package/lib/cloudflare/worker.js +17 -157
  131. package/lib/cloudflare/worker.js.map +1 -1
  132. package/lib/cloudflare/wrangler.json.d.ts +6 -0
  133. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  134. package/lib/cloudflare/wrangler.json.js +23 -6
  135. package/lib/cloudflare/wrangler.json.js.map +1 -1
  136. package/lib/context.d.ts +11 -0
  137. package/lib/context.d.ts.map +1 -1
  138. package/lib/context.js +8 -0
  139. package/lib/context.js.map +1 -1
  140. package/lib/env.d.ts +2 -2
  141. package/lib/env.d.ts.map +1 -1
  142. package/lib/env.js +5 -6
  143. package/lib/env.js.map +1 -1
  144. package/lib/random/index.d.ts +2 -0
  145. package/lib/random/index.d.ts.map +1 -0
  146. package/lib/random/index.js +2 -0
  147. package/lib/random/index.js.map +1 -0
  148. package/lib/random/random-string.d.ts +87 -0
  149. package/lib/random/random-string.d.ts.map +1 -0
  150. package/lib/random/random-string.js +72 -0
  151. package/lib/random/random-string.js.map +1 -0
  152. package/lib/runtime/bind.d.ts +1 -1
  153. package/lib/runtime/bind.d.ts.map +1 -1
  154. package/lib/runtime/bind.js.map +1 -1
  155. package/lib/scope.d.ts +11 -0
  156. package/lib/scope.d.ts.map +1 -1
  157. package/lib/scope.js +24 -0
  158. package/lib/scope.js.map +1 -1
  159. package/lib/secret.d.ts +2 -2
  160. package/lib/secret.d.ts.map +1 -1
  161. package/lib/secret.js +2 -2
  162. package/lib/secret.js.map +1 -1
  163. package/lib/state/cloudflare-state-store.js +1 -1
  164. package/lib/state/cloudflare-state-store.js.map +1 -1
  165. package/lib/state/dofs-state-store/index.js +1 -1
  166. package/lib/state/dofs-state-store/index.js.map +1 -1
  167. package/lib/util/detect-package-manager.d.ts +1 -0
  168. package/lib/util/detect-package-manager.d.ts.map +1 -1
  169. package/lib/util/detect-package-manager.js +10 -0
  170. package/lib/util/detect-package-manager.js.map +1 -1
  171. package/lib/util/telemetry/client.d.ts +1 -1
  172. package/lib/util/telemetry/client.d.ts.map +1 -1
  173. package/lib/util/telemetry/client.js +22 -1
  174. package/lib/util/telemetry/client.js.map +1 -1
  175. package/lib/util/telemetry/constants.d.ts.map +1 -1
  176. package/lib/util/telemetry/constants.js +2 -3
  177. package/lib/util/telemetry/constants.js.map +1 -1
  178. package/lib/util/telemetry/context.d.ts +1 -1
  179. package/lib/util/telemetry/context.d.ts.map +1 -1
  180. package/lib/util/telemetry/types.d.ts +7 -3
  181. package/lib/util/telemetry/types.d.ts.map +1 -1
  182. package/lib/vercel/api.d.ts.map +1 -1
  183. package/lib/vercel/api.js +1 -1
  184. package/lib/vercel/api.js.map +1 -1
  185. package/package.json +43 -4
  186. package/src/alchemy.ts +7 -0
  187. package/src/apply.ts +3 -7
  188. package/src/cloudflare/{astro.ts → astro/astro.ts} +46 -29
  189. package/src/cloudflare/astro/plugin.ts +11 -0
  190. package/src/cloudflare/bundle/plugin-hot-reload.ts +4 -3
  191. package/src/cloudflare/cloudflare-env-proxy.ts +50 -0
  192. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  193. package/src/cloudflare/compatibility-presets.ts +1 -1
  194. package/src/cloudflare/d1-local-migrations.ts +1 -1
  195. package/src/cloudflare/index.ts +8 -8
  196. package/src/cloudflare/miniflare/build-worker-options.ts +454 -0
  197. package/src/cloudflare/miniflare/miniflare-controller.ts +129 -0
  198. package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +6 -15
  199. package/src/cloudflare/miniflare/paths.ts +52 -0
  200. package/src/cloudflare/miniflare/remote-binding-proxy.ts +18 -23
  201. package/src/cloudflare/{nuxt.ts → nuxt/nuxt.ts} +11 -16
  202. package/src/cloudflare/nuxt/plugin.ts +18 -0
  203. package/src/cloudflare/oauth.ts +2 -2
  204. package/src/cloudflare/orange.ts +13 -23
  205. package/src/cloudflare/react-router/plugin.ts +13 -0
  206. package/src/cloudflare/react-router/react-router.ts +41 -0
  207. package/src/cloudflare/redwood/plugin.ts +20 -0
  208. package/src/cloudflare/{redwood.ts → redwood/redwood.ts} +16 -19
  209. package/src/cloudflare/sveltekit/plugin.ts +12 -0
  210. package/src/cloudflare/{sveltekit.ts → sveltekit/sveltekit.ts} +9 -8
  211. package/src/cloudflare/tanstack-start/plugin.ts +30 -0
  212. package/src/cloudflare/tanstack-start/tanstack-start.ts +24 -0
  213. package/src/cloudflare/vite/plugin.ts +30 -0
  214. package/src/cloudflare/vite/vite.ts +34 -0
  215. package/src/cloudflare/website.ts +379 -204
  216. package/src/cloudflare/worker-bundle.ts +55 -16
  217. package/src/cloudflare/worker-stub.ts +11 -14
  218. package/src/cloudflare/worker.ts +23 -205
  219. package/src/cloudflare/wrangler.json.ts +32 -4
  220. package/src/context.ts +19 -0
  221. package/src/env.ts +8 -9
  222. package/src/random/index.ts +1 -0
  223. package/src/random/random-string.ts +126 -0
  224. package/src/runtime/bind.ts +2 -2
  225. package/src/scope.ts +25 -0
  226. package/src/secret.ts +4 -8
  227. package/src/state/cloudflare-state-store.ts +2 -2
  228. package/src/state/dofs-state-store/index.ts +1 -1
  229. package/src/util/detect-package-manager.ts +11 -0
  230. package/src/util/telemetry/client.ts +25 -2
  231. package/src/util/telemetry/constants.ts +2 -4
  232. package/src/util/telemetry/context.ts +1 -1
  233. package/src/util/telemetry/types.ts +8 -2
  234. package/src/vercel/api.ts +2 -4
  235. package/templates/astro/alchemy.run.ts +1 -3
  236. package/templates/astro/astro.config.mjs +2 -2
  237. package/templates/nuxt/alchemy.run.ts +1 -3
  238. package/templates/nuxt/nuxt.config.ts +4 -5
  239. package/templates/nuxt/package.json +0 -1
  240. package/templates/react-router/alchemy.run.ts +1 -4
  241. package/templates/react-router/vite.config.ts +2 -2
  242. package/templates/rwsdk/alchemy.run.ts +0 -1
  243. package/templates/rwsdk/package.json +0 -2
  244. package/templates/rwsdk/vite.config.mts +2 -2
  245. package/templates/sveltekit/alchemy.run.ts +1 -3
  246. package/templates/sveltekit/svelte.config.js +2 -2
  247. package/templates/tanstack-start/vite.config.ts +2 -2
  248. package/templates/vite/alchemy.run.ts +1 -1
  249. package/templates/vite/vite.config.ts +4 -5
  250. package/workers/cloudflare-state-store.js +12 -14
  251. package/lib/cloudflare/astro.d.ts.map +0 -1
  252. package/lib/cloudflare/astro.js +0 -69
  253. package/lib/cloudflare/astro.js.map +0 -1
  254. package/lib/cloudflare/local-dev-cloudflare-shim.d.ts +0 -13
  255. package/lib/cloudflare/local-dev-cloudflare-shim.d.ts.map +0 -1
  256. package/lib/cloudflare/local-dev-cloudflare-shim.js +0 -26
  257. package/lib/cloudflare/local-dev-cloudflare-shim.js.map +0 -1
  258. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts +0 -14
  259. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +0 -1
  260. package/lib/cloudflare/miniflare/miniflare-worker-options.js +0 -468
  261. package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +0 -1
  262. package/lib/cloudflare/miniflare/miniflare.d.ts +0 -40
  263. package/lib/cloudflare/miniflare/miniflare.d.ts.map +0 -1
  264. package/lib/cloudflare/miniflare/miniflare.js +0 -142
  265. package/lib/cloudflare/miniflare/miniflare.js.map +0 -1
  266. package/lib/cloudflare/nuxt.d.ts.map +0 -1
  267. package/lib/cloudflare/nuxt.js.map +0 -1
  268. package/lib/cloudflare/react-router.d.ts +0 -17
  269. package/lib/cloudflare/react-router.d.ts.map +0 -1
  270. package/lib/cloudflare/react-router.js +0 -35
  271. package/lib/cloudflare/react-router.js.map +0 -1
  272. package/lib/cloudflare/redwood.d.ts.map +0 -1
  273. package/lib/cloudflare/redwood.js.map +0 -1
  274. package/lib/cloudflare/sveltekit.d.ts.map +0 -1
  275. package/lib/cloudflare/sveltekit.js.map +0 -1
  276. package/lib/cloudflare/tanstack-start.d.ts.map +0 -1
  277. package/lib/cloudflare/tanstack-start.js +0 -21
  278. package/lib/cloudflare/tanstack-start.js.map +0 -1
  279. package/lib/cloudflare/vite.d.ts.map +0 -1
  280. package/lib/cloudflare/vite.js +0 -20
  281. package/lib/cloudflare/vite.js.map +0 -1
  282. package/src/cloudflare/local-dev-cloudflare-shim.ts +0 -25
  283. package/src/cloudflare/miniflare/miniflare-worker-options.ts +0 -599
  284. package/src/cloudflare/miniflare/miniflare.ts +0 -183
  285. package/src/cloudflare/react-router.ts +0 -56
  286. package/src/cloudflare/tanstack-start.ts +0 -35
  287. package/src/cloudflare/vite.ts +0 -35
  288. package/templates/react-router/wrangler.jsonc +0 -6
  289. package/templates/rwsdk/wrangler.jsonc +0 -31
  290. package/templates/sveltekit/wrangler.jsonc +0 -7
  291. package/templates/tanstack-start/wrangler.jsonc +0 -7
  292. package/templates/typescript/index.ts +0 -1
  293. package/templates/vite/wrangler.jsonc +0 -6
@@ -0,0 +1,126 @@
1
+ import { alchemy } from "../alchemy.ts";
2
+ import { Resource } from "../resource.ts";
3
+ import type { Secret } from "../secret.ts";
4
+
5
+ /**
6
+ * Properties for configuring a random string generation
7
+ */
8
+ export interface RandomStringProps {
9
+ /**
10
+ * The number of random bytes to generate.
11
+ * The actual string length will depend on the encoding:
12
+ * - hex: length * 2 characters
13
+ * - base64: approximately length * 1.33 characters
14
+ * @default 32
15
+ */
16
+ length?: number;
17
+
18
+ /**
19
+ * The encoding format for the random string.
20
+ * - "hex": Hexadecimal encoding (0-9, a-f)
21
+ * - "base64": Base64 encoding (A-Z, a-z, 0-9, +, /)
22
+ * @default "hex"
23
+ */
24
+ encoding?: "hex" | "base64";
25
+ }
26
+
27
+ /**
28
+ * A cryptographically secure random string resource
29
+ */
30
+ export interface RandomString extends Resource<"random::String"> {
31
+ /**
32
+ * The generated random string value, stored as a secret
33
+ */
34
+ value: Secret;
35
+
36
+ /**
37
+ * The length of the random string
38
+ */
39
+ length: number;
40
+
41
+ /**
42
+ * The encoding format of the random string
43
+ */
44
+ encoding: "hex" | "base64";
45
+ }
46
+
47
+ /**
48
+ * Generates a cryptographically secure random string that can be used
49
+ * for API keys, tokens, passwords, or other security-sensitive values.
50
+ * The generated value is automatically wrapped as a secret to prevent
51
+ * accidental exposure in logs or console output.
52
+ *
53
+ * @example
54
+ * // Generate a default random string (32 bytes, hex encoded)
55
+ * const apiKey = await RandomString("api-key");
56
+ * // Result: 64 character hex string (e.g., "a1b2c3d4...")
57
+ *
58
+ * @example
59
+ * // Generate a shorter random string for a verification code
60
+ * const verificationCode = await RandomString("email-verification", {
61
+ * length: 8,
62
+ * encoding: "hex"
63
+ * });
64
+ * // Result: 16 character hex string
65
+ *
66
+ * @example
67
+ * // Generate a base64-encoded random string for a session token
68
+ * const sessionToken = await RandomString("session-token", {
69
+ * length: 48,
70
+ * encoding: "base64"
71
+ * });
72
+ * // Result: ~64 character base64 string
73
+ *
74
+ * @example
75
+ * // Use with other resources that require secrets
76
+ * const database = await PostgresDatabase("mydb", {
77
+ * name: "production",
78
+ * password: (await RandomString("db-password")).value
79
+ * });
80
+ *
81
+ * @example
82
+ * // Generate multiple unique secrets
83
+ * const jwtSecret = await RandomString("jwt-secret", { length: 64 });
84
+ * const encryptionKey = await RandomString("encryption-key", {
85
+ * length: 32,
86
+ * encoding: "base64"
87
+ * });
88
+ *
89
+ * @param id - Unique identifier for this random string resource
90
+ * @param props - Configuration options for the random string generation
91
+ * @returns A RandomString resource containing the generated secret value
92
+ */
93
+ export const RandomString = Resource(
94
+ "random::String",
95
+ async function (
96
+ _id: string,
97
+ props: RandomStringProps = {},
98
+ ): Promise<RandomString> {
99
+ if (this.phase === "delete") {
100
+ return this.destroy();
101
+ }
102
+ const length = props.length ?? 32;
103
+ const encoding = props.encoding ?? "hex";
104
+
105
+ if (
106
+ this.phase === "update" &&
107
+ this.props.length === length &&
108
+ this.props.encoding === encoding
109
+ ) {
110
+ // this is an update (input props changed)
111
+ // but the length and encoding did not change
112
+ // so, we can just return the existing output (no-op)
113
+ return this(this.output);
114
+ }
115
+ const crypto = await import("node:crypto");
116
+ return this({
117
+ length,
118
+ encoding,
119
+ value: alchemy.secret(
120
+ crypto
121
+ .randomBytes(props.length ?? 32)
122
+ .toString(props.encoding ?? "hex"),
123
+ ),
124
+ });
125
+ },
126
+ );
@@ -10,8 +10,8 @@ import { isRuntime } from "./global.ts";
10
10
  /**
11
11
  * Get a Resource's Binding from the Environment.
12
12
  */
13
- export function getBinding<T extends Resource>(resource: T): Promise<Bound<T>> {
14
- return env[getBindKey(resource)] as Promise<Bound<T>>;
13
+ export function getBinding<T extends Resource>(resource: T): Bound<T> {
14
+ return env[getBindKey(resource)] as Bound<T>;
15
15
  }
16
16
 
17
17
  export function tryGetBinding<T extends Resource>(
package/src/scope.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import kleur from "kleur";
1
2
  import { AsyncLocalStorage } from "node:async_hooks";
2
3
  import util from "node:util";
3
4
  import type { Phase } from "./alchemy.ts";
@@ -144,6 +145,7 @@ export class Scope {
144
145
  private finalized = false;
145
146
  private startedAt = performance.now();
146
147
  private deferred: (() => Promise<any>)[] = [];
148
+ private cleanups: (() => Promise<void>)[] = [];
147
149
 
148
150
  public get appName(): string {
149
151
  if (this.parent) {
@@ -466,6 +468,7 @@ export class Scope {
466
468
  });
467
469
 
468
470
  if (!this.parent && process.env.ALCHEMY_TEST_KILL_ON_FINALIZE) {
471
+ await this.cleanup();
469
472
  process.exit(0);
470
473
  }
471
474
  }
@@ -537,6 +540,28 @@ export class Scope {
537
540
  return promise;
538
541
  }
539
542
 
543
+ /**
544
+ * Run all cleanup functions registered with `onCleanup`.
545
+ * This should only be called on the root scope.
546
+ */
547
+ public async cleanup() {
548
+ if (this.parent || this.cleanups.length === 0) return;
549
+ this.logger.log(kleur.gray("Exiting..."));
550
+ await Promise.allSettled(this.cleanups.map((cleanup) => cleanup()));
551
+ }
552
+
553
+ /**
554
+ * Register a cleanup function that will be called when the process exits.
555
+ * This should only be called on the root scope.
556
+ */
557
+ public onCleanup(fn: () => Promise<void>) {
558
+ if (this.parent) {
559
+ this.root.onCleanup(fn);
560
+ return;
561
+ }
562
+ this.cleanups.push(fn);
563
+ }
564
+
540
565
  /**
541
566
  * Returns a string representation of the scope.
542
567
  */
package/src/secret.ts CHANGED
@@ -123,8 +123,8 @@ export function secret<S = string>(
123
123
 
124
124
  export namespace secret {
125
125
  export interface Env {
126
- [key: string]: Promise<Secret>;
127
- (name: string, value?: string, error?: string): Promise<Secret>;
126
+ [key: string]: Secret;
127
+ (name: string, value?: string, error?: string): Secret;
128
128
  }
129
129
 
130
130
  export const env = new Proxy(_env, {
@@ -132,12 +132,8 @@ export namespace secret {
132
132
  apply: (_, __, args: [string, any?, string?]) => _env(...args),
133
133
  }) as Env;
134
134
 
135
- async function _env(
136
- name: string,
137
- value?: string,
138
- error?: string,
139
- ): Promise<Secret> {
140
- const result = await alchemy.env(name, value, error);
135
+ function _env(name: string, value?: string, error?: string): Secret {
136
+ const result = alchemy.env(name, value, error);
141
137
  if (typeof result === "string") {
142
138
  return secret(result, name);
143
139
  }
@@ -105,11 +105,11 @@ const provision = memoize(
105
105
  const scriptName = options.scriptName ?? "alchemy-state-service";
106
106
  const token =
107
107
  options.stateToken ??
108
- (await alchemy.secret.env(
108
+ alchemy.secret.env(
109
109
  "ALCHEMY_STATE_TOKEN",
110
110
  undefined,
111
111
  "Missing token for DOStateStore. Please set ALCHEMY_STATE_TOKEN in the environment or set the `stateToken` option in the DOStateStore constructor.",
112
- ));
112
+ );
113
113
 
114
114
  const api = await createCloudflareApi(options);
115
115
  const [bundle, settings, subdomain] = await Promise.all([
@@ -66,7 +66,7 @@ export class DOFSStateStore implements StateStore {
66
66
  private async createClient() {
67
67
  const token =
68
68
  this.options.worker?.token ??
69
- (await alchemy.secret.env.ALCHEMY_STATE_TOKEN).unencrypted;
69
+ alchemy.secret.env.ALCHEMY_STATE_TOKEN.unencrypted;
70
70
  if (this.options.worker && "url" in this.options.worker) {
71
71
  const client = new DOFSStateStoreClient({
72
72
  app: this.scope.appName ?? "alchemy",
@@ -34,3 +34,14 @@ export async function detectPackageManager(
34
34
 
35
35
  return "npm";
36
36
  }
37
+
38
+ export async function getPackageManagerRunner(): Promise<string> {
39
+ const packageManager = await detectPackageManager();
40
+ return {
41
+ bun: "bun run",
42
+ pnpm: "pnpm",
43
+ yarn: "yarn",
44
+ npm: "npx",
45
+ deno: "deno run",
46
+ }[packageManager];
47
+ }
@@ -10,7 +10,7 @@ import type { Telemetry } from "./types.ts";
10
10
 
11
11
  export interface TelemetryClientOptions {
12
12
  sessionId: string;
13
- phase: Phase;
13
+ phase?: Phase;
14
14
  enabled: boolean;
15
15
  quiet: boolean;
16
16
  }
@@ -85,7 +85,28 @@ export class TelemetryClient implements ITelemetryClient {
85
85
  if (events.length === 0) {
86
86
  return;
87
87
  }
88
- const { userId, ...context } = await this.context;
88
+ const { userId, projectId, ...context } = await this.context;
89
+ const safeProjectId = projectId ?? `temp_${userId}`;
90
+ const groupResponse = await fetch(`${POSTHOG_CLIENT_API_HOST}/i/v0/e/`, {
91
+ method: "POST",
92
+ headers: {
93
+ "Content-Type": "application/json",
94
+ },
95
+ body: JSON.stringify({
96
+ api_key: POSTHOG_PROJECT_ID,
97
+ event: "$groupidentify",
98
+ distinct_id: "project-identify",
99
+ properties: {
100
+ $group_type: "project",
101
+ $group_key: safeProjectId,
102
+ },
103
+ }),
104
+ });
105
+ if (!groupResponse.ok) {
106
+ throw new Error(
107
+ `Failed to send group identify: ${groupResponse.status} ${groupResponse.statusText} - ${await groupResponse.text()}`,
108
+ );
109
+ }
89
110
  const response = await fetch(`${POSTHOG_CLIENT_API_HOST}/batch`, {
90
111
  method: "POST",
91
112
  headers: {
@@ -100,6 +121,8 @@ export class TelemetryClient implements ITelemetryClient {
100
121
  distinct_id: userId,
101
122
  ...context,
102
123
  ...properties,
124
+ projectId: safeProjectId,
125
+ $groups: { project: safeProjectId },
103
126
  },
104
127
  timestamp: new Date(timestamp).toISOString(),
105
128
  })),
@@ -1,8 +1,6 @@
1
- import xdgAppPaths from "xdg-app-paths";
1
+ import envPaths from "env-paths";
2
2
 
3
- const xdg = xdgAppPaths("alchemy");
4
-
5
- export const CONFIG_DIR = xdg.config();
3
+ export const CONFIG_DIR = envPaths("alchemy", { suffix: "" }).config;
6
4
 
7
5
  export const TELEMETRY_DISABLED =
8
6
  !!process.env.ALCHEMY_TELEMETRY_DISABLED || !!process.env.DO_NOT_TRACK;
@@ -132,7 +132,7 @@ function environment(): Telemetry.Context["environment"] {
132
132
 
133
133
  export async function context(input: {
134
134
  sessionId: string;
135
- phase: Phase;
135
+ phase?: Phase;
136
136
  }): Promise<Telemetry.Context> {
137
137
  const env = environment();
138
138
  const [uid, pid] = await Promise.all([
@@ -29,7 +29,7 @@ export namespace Telemetry {
29
29
 
30
30
  alchemy: {
31
31
  version: string;
32
- phase: Phase;
32
+ phase?: Phase;
33
33
  };
34
34
  }
35
35
 
@@ -72,6 +72,11 @@ export namespace Telemetry {
72
72
  replaced?: boolean;
73
73
  }
74
74
 
75
+ export interface CliEvent extends BaseEvent {
76
+ event: "cli.start" | "cli.success" | "cli.error";
77
+ command: string;
78
+ }
79
+
75
80
  export interface StateStoreEvent extends BaseEvent {
76
81
  event:
77
82
  | "stateStore.init"
@@ -88,11 +93,12 @@ export namespace Telemetry {
88
93
  error?: SerializedError;
89
94
  }
90
95
 
91
- export type Event = AppEvent | ResourceEvent | StateStoreEvent;
96
+ export type Event = AppEvent | ResourceEvent | StateStoreEvent | CliEvent;
92
97
  export type EventInput = (
93
98
  | Omit<AppEvent, "timestamp" | "error">
94
99
  | Omit<ResourceEvent, "timestamp" | "error">
95
100
  | Omit<StateStoreEvent, "timestamp" | "error">
101
+ | Omit<CliEvent, "timestamp" | "error">
96
102
  ) & {
97
103
  error?: ErrorInput;
98
104
  };
package/src/vercel/api.ts CHANGED
@@ -26,10 +26,8 @@ export interface VercelApiOptions {
26
26
  export async function createVercelApi(
27
27
  options: VercelApiOptions,
28
28
  ): Promise<VercelApi> {
29
- const {
30
- accessToken = await alchemy.secret.env.VERCEL_ACCESS_TOKEN,
31
- baseUrl,
32
- } = options;
29
+ const { accessToken = alchemy.secret.env.VERCEL_ACCESS_TOKEN, baseUrl } =
30
+ options;
33
31
 
34
32
  return new VercelApi({
35
33
  baseUrl,
@@ -5,9 +5,7 @@ import { Astro } from "alchemy/cloudflare";
5
5
 
6
6
  const app = await alchemy("my-alchemy-app");
7
7
 
8
- export const worker = await Astro("website", {
9
- command: "bun run build",
10
- });
8
+ export const worker = await Astro("website");
11
9
 
12
10
  console.log({
13
11
  url: worker.url,
@@ -1,8 +1,8 @@
1
+ import alchemy from 'alchemy/cloudflare/astro';
1
2
  import { defineConfig } from 'astro/config';
2
- import cloudflare from '@astrojs/cloudflare';
3
3
 
4
4
  // https://astro.build/config
5
5
  export default defineConfig({
6
6
  output: 'server',
7
- adapter: cloudflare(),
7
+ adapter: alchemy(),
8
8
  });
@@ -5,9 +5,7 @@ import { Nuxt } from "alchemy/cloudflare";
5
5
 
6
6
  const app = await alchemy("my-alchemy-app");
7
7
 
8
- export const worker = await Nuxt("website", {
9
- command: "bun run build",
10
- });
8
+ export const worker = await Nuxt("website");
11
9
 
12
10
  console.log({
13
11
  url: worker.url,
@@ -1,13 +1,12 @@
1
+ import alchemy from "alchemy/cloudflare/nuxt";
2
+ import { defineNuxtConfig } from "nuxt/config";
3
+
1
4
  // https://nuxt.com/docs/api/configuration/nuxt-config
2
5
  export default defineNuxtConfig({
3
- compatibilityDate: '2025-05-15',
4
6
  devtools: { enabled: true },
5
7
  nitro: {
6
8
  preset: "cloudflare_module",
7
- cloudflare: {
8
- deployConfig: true,
9
- nodeCompat: true
10
- }
9
+ cloudflare: alchemy(),
11
10
  },
12
11
  modules: ["nitro-cloudflare-dev"],
13
12
  });
@@ -8,7 +8,6 @@
8
8
  "destroy": "alchemy destroy",
9
9
  "dev": "alchemy dev",
10
10
  "generate": "nuxt generate",
11
- "postinstall": "nuxt prepare",
12
11
  "preview": "nuxt preview"
13
12
  },
14
13
  "dependencies": {
@@ -5,10 +5,7 @@ import { ReactRouter } from "alchemy/cloudflare";
5
5
 
6
6
  const app = await alchemy("my-alchemy-app");
7
7
 
8
- export const worker = await ReactRouter("website", {
9
- main: "workers/app.ts",
10
- command: "bun run build",
11
- });
8
+ export const worker = await ReactRouter("website");
12
9
 
13
10
  console.log({
14
11
  url: worker.url,
@@ -1,12 +1,12 @@
1
1
  import { reactRouter } from "@react-router/dev/vite";
2
- import { cloudflare } from "@cloudflare/vite-plugin";
3
2
  import tailwindcss from "@tailwindcss/vite";
3
+ import alchemy from "alchemy/cloudflare/react-router";
4
4
  import { defineConfig } from "vite";
5
5
  import tsconfigPaths from "vite-tsconfig-paths";
6
6
 
7
7
  export default defineConfig({
8
8
  plugins: [
9
- cloudflare({ viteEnvironment: { name: "ssr" } }),
9
+ alchemy(),
10
10
  tailwindcss(),
11
11
  reactRouter(),
12
12
  tsconfigPaths(),
@@ -11,7 +11,6 @@ const database = await D1Database("database", {
11
11
 
12
12
  export const worker = await Redwood("website", {
13
13
  name: "my-alchemy-app-website",
14
- command: "bun run build",
15
14
  bindings: {
16
15
  AUTH_SECRET_KEY: alchemy.secret(process.env.AUTH_SECRET_KEY),
17
16
  DB: database,
@@ -16,7 +16,6 @@
16
16
  "deploy": "alchemy deploy",
17
17
  "destroy": "alchemy destroy",
18
18
  "dev": "alchemy dev",
19
- "dev:init": "rw-scripts dev-init",
20
19
  "generate": "rw-scripts ensure-env && prisma generate && wrangler types",
21
20
  "migrate:dev": "prisma generate && wrangler d1 migrations apply DB --local",
22
21
  "migrate:new": "rw-scripts migrate-new",
@@ -24,7 +23,6 @@
24
23
  "prepare": "vibe-rules install cursor",
25
24
  "preview": "vite preview",
26
25
  "release": "rw-scripts ensure-deploy-env && npm run clean && prisma generate && RWSDK_DEPLOY=1 npm run build && wrangler deploy",
27
- "seed": "npm run worker:run ./src/scripts/seed.ts",
28
26
  "types": "tsc",
29
27
  "worker:run": "rw-scripts worker-run"
30
28
  },
@@ -1,6 +1,6 @@
1
+ import alchemyRedwood from "alchemy/cloudflare/redwood";
1
2
  import { defineConfig } from "vite";
2
- import { redwood } from "rwsdk/vite";
3
3
 
4
4
  export default defineConfig({
5
- plugins: [redwood()],
5
+ plugins: [alchemyRedwood()],
6
6
  });
@@ -5,9 +5,7 @@ import { SvelteKit } from "alchemy/cloudflare";
5
5
 
6
6
  const app = await alchemy("my-alchemy-app");
7
7
 
8
- export const worker = await SvelteKit("website", {
9
- command: "bun run build",
10
- });
8
+ export const worker = await SvelteKit("website");
11
9
 
12
10
  console.log({
13
11
  url: worker.url,
@@ -1,11 +1,11 @@
1
- import adapter from '@sveltejs/adapter-cloudflare';
2
1
  import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
2
+ import alchemy from 'alchemy/cloudflare/sveltekit';
3
3
 
4
4
  /** @type {import('@sveltejs/kit').Config} */
5
5
  const config = {
6
6
  preprocess: vitePreprocess(),
7
7
  kit: {
8
- adapter: adapter()
8
+ adapter: alchemy()
9
9
  }
10
10
  };
11
11
 
@@ -1,7 +1,7 @@
1
1
  import tailwindcss from "@tailwindcss/vite";
2
2
  import { tanstackStart } from "@tanstack/react-start/plugin/vite";
3
3
  import viteReact from "@vitejs/plugin-react";
4
- import { cloudflareWorkersDevEnvironmentShim } from "alchemy/cloudflare";
4
+ import alchemy from "alchemy/cloudflare/tanstack-start";
5
5
  import { defineConfig, PluginOption } from "vite";
6
6
  import tsConfigPaths from "vite-tsconfig-paths";
7
7
 
@@ -17,7 +17,7 @@ export default defineConfig({
17
17
  },
18
18
  plugins: [
19
19
  tailwindcss() as PluginOption,
20
- cloudflareWorkersDevEnvironmentShim(),
20
+ alchemy(),
21
21
  tsConfigPaths({
22
22
  projects: ["./tsconfig.json"],
23
23
  }),
@@ -6,7 +6,7 @@ import { Vite } from "alchemy/cloudflare";
6
6
  const app = await alchemy("my-alchemy-app");
7
7
 
8
8
  export const worker = await Vite("website", {
9
- main: "worker/index.ts",
9
+ entrypoint: "worker/index.ts",
10
10
  });
11
11
 
12
12
  console.log({
@@ -1,9 +1,8 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- import { cloudflare } from "@cloudflare/vite-plugin";
1
+ import react from '@vitejs/plugin-react';
2
+ import alchemy from "alchemy/cloudflare/vite";
3
+ import { defineConfig } from 'vite';
5
4
 
6
5
  // https://vite.dev/config/
7
6
  export default defineConfig({
8
- plugins: [react(), cloudflare()],
7
+ plugins: [react(), alchemy()],
9
8
  });
@@ -736,7 +736,7 @@ var WithSubquery = class extends Subquery {
736
736
  };
737
737
 
738
738
  // ../node_modules/drizzle-orm/version.js
739
- var version = "0.44.3";
739
+ var version = "0.44.4";
740
740
 
741
741
  // ../node_modules/drizzle-orm/tracing.js
742
742
  var otel;
@@ -2739,6 +2739,17 @@ var DrizzleError = class extends Error {
2739
2739
  this.cause = cause;
2740
2740
  }
2741
2741
  };
2742
+ var DrizzleQueryError = class _DrizzleQueryError extends Error {
2743
+ constructor(query, params, cause) {
2744
+ super(`Failed query: ${query}
2745
+ params: ${params}`);
2746
+ this.query = query;
2747
+ this.params = params;
2748
+ this.cause = cause;
2749
+ Error.captureStackTrace(this, _DrizzleQueryError);
2750
+ if (cause) this.cause = cause;
2751
+ }
2752
+ };
2742
2753
  var TransactionRollbackError = class extends DrizzleError {
2743
2754
  static [entityKind] = "TransactionRollbackError";
2744
2755
  constructor() {
@@ -4985,19 +4996,6 @@ async function hashQuery(sql2, params) {
4985
4996
  return hashHex;
4986
4997
  }
4987
4998
 
4988
- // ../node_modules/drizzle-orm/errors/index.js
4989
- var DrizzleQueryError = class _DrizzleQueryError extends Error {
4990
- constructor(query, params, cause) {
4991
- super(`Failed query: ${query}
4992
- params: ${params}`);
4993
- this.query = query;
4994
- this.params = params;
4995
- this.cause = cause;
4996
- Error.captureStackTrace(this, _DrizzleQueryError);
4997
- if (cause) this.cause = cause;
4998
- }
4999
- };
5000
-
5001
4999
  // ../node_modules/drizzle-orm/sqlite-core/session.js
5002
5000
  var ExecuteResultSync = class extends QueryPromise {
5003
5001
  constructor(resultCb) {
@@ -1 +0,0 @@
1
- {"version":3,"file":"astro.d.ts","sourceRoot":"","sources":["../../src/cloudflare/astro.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,QAAQ,CAAE,SAAQ,YAAY,CAAC,CAAC,CAAC;CAAG;AAE1E;;;;GAIG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,SAAS;IAAE,MAAM,EAAE,GAAG,CAAA;CAAE,GAC7D,KAAK,GACL,MAAM,CAAC,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,KAAK,CAAC,CAAC,SAAS,QAAQ,EAC5C,EAAE,EAAE,MAAM,EACV,KAAK,GAAE,UAAU,CAAC,CAAC,CAAM,GACxB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CA0BnB"}