alchemy 0.69.0 → 0.70.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 (314) hide show
  1. package/bin/alchemy.js +3810 -3889
  2. package/bin/commands/init.ts +41 -55
  3. package/bin/trpc.ts +4 -9
  4. package/lib/alchemy.d.ts +3 -3
  5. package/lib/alchemy.d.ts.map +1 -1
  6. package/lib/alchemy.js +2 -15
  7. package/lib/alchemy.js.map +1 -1
  8. package/lib/apply.js +24 -9
  9. package/lib/apply.js.map +1 -1
  10. package/lib/aws/utils.d.ts +2 -1
  11. package/lib/aws/utils.d.ts.map +1 -1
  12. package/lib/aws/utils.js.map +1 -1
  13. package/lib/clickhouse/api/client.gen.d.ts +13 -0
  14. package/lib/clickhouse/api/client.gen.d.ts.map +1 -0
  15. package/lib/clickhouse/api/client.gen.js +7 -0
  16. package/lib/clickhouse/api/client.gen.js.map +1 -0
  17. package/lib/clickhouse/api/sdk.gen.d.ts +322 -0
  18. package/lib/clickhouse/api/sdk.gen.d.ts.map +1 -0
  19. package/lib/clickhouse/api/sdk.gen.js +683 -0
  20. package/lib/clickhouse/api/sdk.gen.js.map +1 -0
  21. package/lib/clickhouse/api/types.gen.d.ts +5030 -0
  22. package/lib/clickhouse/api/types.gen.d.ts.map +1 -0
  23. package/lib/clickhouse/api/types.gen.js +2 -0
  24. package/lib/clickhouse/api/types.gen.js.map +1 -0
  25. package/lib/clickhouse/api-key.d.ts +29 -0
  26. package/lib/clickhouse/api-key.d.ts.map +1 -0
  27. package/lib/clickhouse/api-key.js +83 -0
  28. package/lib/clickhouse/api-key.js.map +1 -0
  29. package/lib/clickhouse/api.d.ts +36 -0
  30. package/lib/clickhouse/api.d.ts.map +1 -0
  31. package/lib/clickhouse/api.js +48 -0
  32. package/lib/clickhouse/api.js.map +1 -0
  33. package/lib/clickhouse/index.d.ts +4 -0
  34. package/lib/clickhouse/index.d.ts.map +1 -0
  35. package/lib/clickhouse/index.js +4 -0
  36. package/lib/clickhouse/index.js.map +1 -0
  37. package/lib/clickhouse/organization.d.ts +16 -0
  38. package/lib/clickhouse/organization.d.ts.map +1 -0
  39. package/lib/clickhouse/organization.js +21 -0
  40. package/lib/clickhouse/organization.js.map +1 -0
  41. package/lib/clickhouse/service.d.ts +275 -0
  42. package/lib/clickhouse/service.d.ts.map +1 -0
  43. package/lib/clickhouse/service.js +274 -0
  44. package/lib/clickhouse/service.js.map +1 -0
  45. package/lib/cloudflare/account-api-token.d.ts.map +1 -1
  46. package/lib/cloudflare/account-api-token.js +1 -1
  47. package/lib/cloudflare/account-api-token.js.map +1 -1
  48. package/lib/cloudflare/bucket-object.d.ts +5 -0
  49. package/lib/cloudflare/bucket-object.d.ts.map +1 -1
  50. package/lib/cloudflare/bucket-object.js +1 -1
  51. package/lib/cloudflare/bucket-object.js.map +1 -1
  52. package/lib/cloudflare/bucket.d.ts +6 -3
  53. package/lib/cloudflare/bucket.d.ts.map +1 -1
  54. package/lib/cloudflare/bucket.js +60 -8
  55. package/lib/cloudflare/bucket.js.map +1 -1
  56. package/lib/cloudflare/bun-spa/bun-spa.d.ts +15 -0
  57. package/lib/cloudflare/bun-spa/bun-spa.d.ts.map +1 -0
  58. package/lib/cloudflare/bun-spa/bun-spa.js +95 -0
  59. package/lib/cloudflare/bun-spa/bun-spa.js.map +1 -0
  60. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  61. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  62. package/lib/cloudflare/container.d.ts +11 -1
  63. package/lib/cloudflare/container.d.ts.map +1 -1
  64. package/lib/cloudflare/container.js +1 -1
  65. package/lib/cloudflare/container.js.map +1 -1
  66. package/lib/cloudflare/index.d.ts +1 -0
  67. package/lib/cloudflare/index.d.ts.map +1 -1
  68. package/lib/cloudflare/index.js +1 -0
  69. package/lib/cloudflare/index.js.map +1 -1
  70. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
  71. package/lib/cloudflare/miniflare/build-worker-options.js +3 -3
  72. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
  73. package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -1
  74. package/lib/cloudflare/miniflare/miniflare-controller.js +2 -0
  75. package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -1
  76. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts +1 -1
  77. package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
  78. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +33 -14
  79. package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
  80. package/lib/cloudflare/permission-groups.d.ts +2 -3
  81. package/lib/cloudflare/permission-groups.d.ts.map +1 -1
  82. package/lib/cloudflare/permission-groups.js +10 -15
  83. package/lib/cloudflare/permission-groups.js.map +1 -1
  84. package/lib/cloudflare/redwood/redwood.d.ts +1 -1
  85. package/lib/cloudflare/redwood/redwood.js +1 -1
  86. package/lib/cloudflare/tanstack-start/plugin.d.ts +2 -15
  87. package/lib/cloudflare/tanstack-start/plugin.d.ts.map +1 -1
  88. package/lib/cloudflare/tanstack-start/plugin.js +5 -25
  89. package/lib/cloudflare/tanstack-start/plugin.js.map +1 -1
  90. package/lib/cloudflare/tanstack-start/tanstack-start.d.ts.map +1 -1
  91. package/lib/cloudflare/tanstack-start/tanstack-start.js +15 -4
  92. package/lib/cloudflare/tanstack-start/tanstack-start.js.map +1 -1
  93. package/lib/cloudflare/util/filter-env-bindings.d.ts +62 -0
  94. package/lib/cloudflare/util/filter-env-bindings.d.ts.map +1 -0
  95. package/lib/cloudflare/util/filter-env-bindings.js +81 -0
  96. package/lib/cloudflare/util/filter-env-bindings.js.map +1 -0
  97. package/lib/cloudflare/website.d.ts +2 -2
  98. package/lib/cloudflare/website.d.ts.map +1 -1
  99. package/lib/cloudflare/website.js +7 -18
  100. package/lib/cloudflare/website.js.map +1 -1
  101. package/lib/cloudflare/worker-metadata.d.ts +5 -1
  102. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  103. package/lib/cloudflare/worker-metadata.js +3 -0
  104. package/lib/cloudflare/worker-metadata.js.map +1 -1
  105. package/lib/cloudflare/worker.d.ts +17 -1
  106. package/lib/cloudflare/worker.d.ts.map +1 -1
  107. package/lib/cloudflare/worker.js +1 -0
  108. package/lib/cloudflare/worker.js.map +1 -1
  109. package/lib/cloudflare/wrangler.json.d.ts +15 -1
  110. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  111. package/lib/cloudflare/wrangler.json.js +12 -4
  112. package/lib/cloudflare/wrangler.json.js.map +1 -1
  113. package/lib/coinbase/client.d.ts +54 -0
  114. package/lib/coinbase/client.d.ts.map +1 -0
  115. package/lib/coinbase/client.js +89 -0
  116. package/lib/coinbase/client.js.map +1 -0
  117. package/lib/coinbase/evm-account.d.ts +118 -0
  118. package/lib/coinbase/evm-account.d.ts.map +1 -0
  119. package/lib/coinbase/evm-account.js +198 -0
  120. package/lib/coinbase/evm-account.js.map +1 -0
  121. package/lib/coinbase/evm-smart-account.d.ts +122 -0
  122. package/lib/coinbase/evm-smart-account.d.ts.map +1 -0
  123. package/lib/coinbase/evm-smart-account.js +213 -0
  124. package/lib/coinbase/evm-smart-account.js.map +1 -0
  125. package/lib/coinbase/faucet.d.ts +11 -0
  126. package/lib/coinbase/faucet.d.ts.map +1 -0
  127. package/lib/coinbase/faucet.js +146 -0
  128. package/lib/coinbase/faucet.js.map +1 -0
  129. package/lib/coinbase/index.d.ts +4 -0
  130. package/lib/coinbase/index.d.ts.map +1 -0
  131. package/lib/coinbase/index.js +4 -0
  132. package/lib/coinbase/index.js.map +1 -0
  133. package/lib/coinbase/types.d.ts +28 -0
  134. package/lib/coinbase/types.d.ts.map +1 -0
  135. package/lib/coinbase/types.js +4 -0
  136. package/lib/{util/telemetry → coinbase}/types.js.map +1 -1
  137. package/lib/coinbase/utils.d.ts +13 -0
  138. package/lib/coinbase/utils.d.ts.map +1 -0
  139. package/lib/coinbase/utils.js +17 -0
  140. package/lib/coinbase/utils.js.map +1 -0
  141. package/lib/docker/api.d.ts +22 -1
  142. package/lib/docker/api.d.ts.map +1 -1
  143. package/lib/docker/api.js +64 -2
  144. package/lib/docker/api.js.map +1 -1
  145. package/lib/docker/container.d.ts +88 -0
  146. package/lib/docker/container.d.ts.map +1 -1
  147. package/lib/docker/container.js +36 -0
  148. package/lib/docker/container.js.map +1 -1
  149. package/lib/neon/api/types.gen.d.ts +7 -2
  150. package/lib/neon/api/types.gen.d.ts.map +1 -1
  151. package/lib/planetscale/api/types.gen.d.ts +20 -4
  152. package/lib/planetscale/api/types.gen.d.ts.map +1 -1
  153. package/lib/planetscale/api.d.ts.map +1 -1
  154. package/lib/planetscale/api.js +1 -0
  155. package/lib/planetscale/api.js.map +1 -1
  156. package/lib/planetscale/password.d.ts.map +1 -1
  157. package/lib/planetscale/password.js +1 -13
  158. package/lib/planetscale/password.js.map +1 -1
  159. package/lib/resource.d.ts.map +1 -1
  160. package/lib/resource.js +7 -3
  161. package/lib/resource.js.map +1 -1
  162. package/lib/scope.d.ts +4 -9
  163. package/lib/scope.d.ts.map +1 -1
  164. package/lib/scope.js +16 -37
  165. package/lib/scope.js.map +1 -1
  166. package/lib/state/instrumented-state-store.d.ts +1 -3
  167. package/lib/state/instrumented-state-store.d.ts.map +1 -1
  168. package/lib/state/instrumented-state-store.js +19 -21
  169. package/lib/state/instrumented-state-store.js.map +1 -1
  170. package/lib/test/bun.d.ts.map +1 -1
  171. package/lib/test/bun.js +1 -2
  172. package/lib/test/bun.js.map +1 -1
  173. package/lib/test/vitest.d.ts.map +1 -1
  174. package/lib/test/vitest.js +1 -2
  175. package/lib/test/vitest.js.map +1 -1
  176. package/lib/util/diff.d.ts +5 -0
  177. package/lib/util/diff.d.ts.map +1 -0
  178. package/lib/util/diff.js +14 -0
  179. package/lib/util/diff.js.map +1 -0
  180. package/lib/util/telemetry.d.ts +52 -0
  181. package/lib/util/telemetry.d.ts.map +1 -0
  182. package/lib/util/telemetry.js +191 -0
  183. package/lib/util/telemetry.js.map +1 -0
  184. package/package.json +19 -1
  185. package/src/alchemy.ts +5 -20
  186. package/src/apply.ts +29 -12
  187. package/src/aws/utils.ts +2 -1
  188. package/src/clickhouse/api/client.gen.ts +28 -0
  189. package/src/clickhouse/api/sdk.gen.ts +1286 -0
  190. package/src/clickhouse/api/types.gen.ts +5898 -0
  191. package/src/clickhouse/api-key.ts +136 -0
  192. package/src/clickhouse/api.ts +84 -0
  193. package/src/clickhouse/index.ts +3 -0
  194. package/src/clickhouse/organization.ts +31 -0
  195. package/src/clickhouse/service.ts +668 -0
  196. package/src/cloudflare/account-api-token.ts +1 -4
  197. package/src/cloudflare/bucket-object.ts +11 -1
  198. package/src/cloudflare/bucket.ts +72 -6
  199. package/src/cloudflare/bun-spa/bun-spa.ts +139 -0
  200. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  201. package/src/cloudflare/container.ts +22 -3
  202. package/src/cloudflare/index.ts +1 -0
  203. package/src/cloudflare/miniflare/build-worker-options.ts +6 -4
  204. package/src/cloudflare/miniflare/miniflare-controller.ts +2 -0
  205. package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +42 -15
  206. package/src/cloudflare/permission-groups.ts +21 -49
  207. package/src/cloudflare/redwood/redwood.ts +1 -1
  208. package/src/cloudflare/tanstack-start/plugin.ts +7 -28
  209. package/src/cloudflare/tanstack-start/tanstack-start.ts +15 -4
  210. package/src/cloudflare/util/filter-env-bindings.ts +96 -0
  211. package/src/cloudflare/website.ts +12 -24
  212. package/src/cloudflare/worker-metadata.ts +8 -1
  213. package/src/cloudflare/worker.ts +19 -1
  214. package/src/cloudflare/wrangler.json.ts +27 -9
  215. package/src/coinbase/client.ts +146 -0
  216. package/src/coinbase/evm-account.ts +317 -0
  217. package/src/coinbase/evm-smart-account.ts +339 -0
  218. package/src/coinbase/faucet.ts +173 -0
  219. package/src/coinbase/index.ts +3 -0
  220. package/src/coinbase/types.ts +33 -0
  221. package/src/coinbase/utils.ts +19 -0
  222. package/src/docker/api.ts +86 -2
  223. package/src/docker/container.ts +97 -0
  224. package/src/neon/api/types.gen.ts +13 -1
  225. package/src/planetscale/api/types.gen.ts +22 -2
  226. package/src/planetscale/api.ts +1 -0
  227. package/src/planetscale/password.ts +1 -14
  228. package/src/resource.ts +11 -4
  229. package/src/scope.ts +22 -45
  230. package/src/state/instrumented-state-store.ts +27 -26
  231. package/src/test/bun.ts +1 -2
  232. package/src/test/vitest.ts +1 -2
  233. package/src/util/diff.ts +14 -0
  234. package/src/util/telemetry.ts +297 -0
  235. package/templates/tanstack-start/.cta.json +13 -0
  236. package/templates/tanstack-start/README.md +267 -49
  237. package/templates/tanstack-start/_gitignore +9 -18
  238. package/templates/tanstack-start/alchemy.run.ts +2 -2
  239. package/templates/tanstack-start/package.json +24 -19
  240. package/templates/tanstack-start/public/favicon.ico +0 -0
  241. package/templates/tanstack-start/public/logo192.png +0 -0
  242. package/templates/tanstack-start/public/logo512.png +0 -0
  243. package/templates/tanstack-start/public/manifest.json +25 -0
  244. package/templates/tanstack-start/public/robots.txt +3 -0
  245. package/templates/tanstack-start/src/components/Header.tsx +21 -0
  246. package/templates/tanstack-start/src/logo.svg +12 -0
  247. package/templates/tanstack-start/src/router.tsx +7 -16
  248. package/templates/tanstack-start/src/routes/__root.tsx +13 -114
  249. package/templates/tanstack-start/src/routes/api.demo-names.ts +15 -0
  250. package/templates/tanstack-start/src/routes/demo.start.api-request.tsx +44 -0
  251. package/templates/tanstack-start/src/routes/demo.start.server-funcs.tsx +97 -0
  252. package/templates/tanstack-start/src/routes/index.tsx +31 -4
  253. package/templates/tanstack-start/src/styles.css +15 -0
  254. package/templates/tanstack-start/tsconfig.json +19 -22
  255. package/templates/tanstack-start/types/env.d.ts +2 -2
  256. package/templates/tanstack-start/vite.config.ts +16 -25
  257. package/workers/tunnel-proxy.js +1 -1
  258. package/lib/util/telemetry/client.d.ts +0 -31
  259. package/lib/util/telemetry/client.d.ts.map +0 -1
  260. package/lib/util/telemetry/client.js +0 -121
  261. package/lib/util/telemetry/client.js.map +0 -1
  262. package/lib/util/telemetry/constants.d.ts +0 -5
  263. package/lib/util/telemetry/constants.d.ts.map +0 -1
  264. package/lib/util/telemetry/constants.js +0 -8
  265. package/lib/util/telemetry/constants.js.map +0 -1
  266. package/lib/util/telemetry/context.d.ts +0 -15
  267. package/lib/util/telemetry/context.d.ts.map +0 -1
  268. package/lib/util/telemetry/context.js +0 -128
  269. package/lib/util/telemetry/context.js.map +0 -1
  270. package/lib/util/telemetry/index.d.ts +0 -3
  271. package/lib/util/telemetry/index.d.ts.map +0 -1
  272. package/lib/util/telemetry/index.js +0 -3
  273. package/lib/util/telemetry/index.js.map +0 -1
  274. package/lib/util/telemetry/types.d.ts +0 -68
  275. package/lib/util/telemetry/types.d.ts.map +0 -1
  276. package/lib/util/telemetry/types.js +0 -1
  277. package/src/util/telemetry/client.ts +0 -156
  278. package/src/util/telemetry/constants.ts +0 -13
  279. package/src/util/telemetry/context.ts +0 -154
  280. package/src/util/telemetry/index.ts +0 -2
  281. package/src/util/telemetry/types.ts +0 -105
  282. package/templates/tanstack-start/_prettierignore +0 -4
  283. package/templates/tanstack-start/public/android-chrome-192x192.png +0 -0
  284. package/templates/tanstack-start/public/android-chrome-512x512.png +0 -0
  285. package/templates/tanstack-start/public/apple-touch-icon.png +0 -0
  286. package/templates/tanstack-start/public/favicon-16x16.png +0 -0
  287. package/templates/tanstack-start/public/favicon-32x32.png +0 -0
  288. package/templates/tanstack-start/public/favicon.png +0 -0
  289. package/templates/tanstack-start/public/site.webmanifest +0 -19
  290. package/templates/tanstack-start/src/components/DefaultCatchBoundary.tsx +0 -53
  291. package/templates/tanstack-start/src/components/NotFound.tsx +0 -25
  292. package/templates/tanstack-start/src/components/PostError.tsx +0 -5
  293. package/templates/tanstack-start/src/components/UserError.tsx +0 -5
  294. package/templates/tanstack-start/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +0 -10
  295. package/templates/tanstack-start/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +0 -10
  296. package/templates/tanstack-start/src/routes/_pathlessLayout/_nested-layout.tsx +0 -34
  297. package/templates/tanstack-start/src/routes/_pathlessLayout.tsx +0 -16
  298. package/templates/tanstack-start/src/routes/api/users.$userId.ts +0 -28
  299. package/templates/tanstack-start/src/routes/api/users.ts +0 -59
  300. package/templates/tanstack-start/src/routes/customScript[.]js.ts +0 -10
  301. package/templates/tanstack-start/src/routes/deferred.tsx +0 -62
  302. package/templates/tanstack-start/src/routes/posts.$postId.tsx +0 -34
  303. package/templates/tanstack-start/src/routes/posts.index.tsx +0 -8
  304. package/templates/tanstack-start/src/routes/posts.tsx +0 -38
  305. package/templates/tanstack-start/src/routes/posts_.$postId.deep.tsx +0 -29
  306. package/templates/tanstack-start/src/routes/redirect.tsx +0 -9
  307. package/templates/tanstack-start/src/routes/users.$userId.tsx +0 -44
  308. package/templates/tanstack-start/src/routes/users.index.tsx +0 -18
  309. package/templates/tanstack-start/src/routes/users.tsx +0 -49
  310. package/templates/tanstack-start/src/styles/app.css +0 -12
  311. package/templates/tanstack-start/src/utils/loggingMiddleware.tsx +0 -41
  312. package/templates/tanstack-start/src/utils/posts.tsx +0 -40
  313. package/templates/tanstack-start/src/utils/seo.ts +0 -33
  314. package/templates/tanstack-start/src/utils/users.tsx +0 -5
@@ -0,0 +1,668 @@
1
+ import type { Context } from "../context.ts";
2
+ import { Resource } from "../resource.ts";
3
+ import { secret, type Secret } from "../secret.ts";
4
+ import { diff } from "../util/diff.ts";
5
+ import { createClickhouseApi } from "./api.ts";
6
+ import type { ClickhouseClient } from "./api/sdk.gen.ts";
7
+ import type { Service as ApiService, Organization } from "./api/types.gen.ts";
8
+
9
+ export interface ServiceProps {
10
+ /**
11
+ * The key ID for the Clickhouse API
12
+ */
13
+ keyId?: string | Secret<string>;
14
+
15
+ /**
16
+ * The secret for the Clickhouse API
17
+ */
18
+ secret?: string | Secret<string>;
19
+
20
+ /**
21
+ * The id of Clickhouse cloud organization to create the service in.
22
+ */
23
+ organization: string | Organization;
24
+
25
+ /**
26
+ * The name of the Clickhouse service to create.
27
+ *
28
+ * @default ${app}-${stage}-${id}
29
+ */
30
+ name?: string;
31
+
32
+ /**
33
+ * The underlying cloud provider to create the service on.
34
+ */
35
+ provider: ApiService["provider"];
36
+
37
+ /**
38
+ * The region to create the service in.
39
+ */
40
+ region: ApiService["region"];
41
+
42
+ /**
43
+ * The IP access list to create the service with.
44
+ *
45
+ * @default [{ description: "Anywhere", source: "0.0.0.0/0" }]
46
+ */
47
+ ipAccessList?: ApiService["ipAccessList"];
48
+
49
+ /**
50
+ * The minimum replica memory to create the service with.
51
+ *
52
+ * @default 8
53
+ */
54
+ minReplicaMemoryGb?: ApiService["minReplicaMemoryGb"];
55
+
56
+ /**
57
+ * The maximum replica memory to create the service with.
58
+ *
59
+ * @default 356
60
+ */
61
+ maxReplicaMemoryGb?: ApiService["maxReplicaMemoryGb"];
62
+
63
+ /**
64
+ * The number of replicas to create the service with.
65
+ *
66
+ * @default 3
67
+ */
68
+ numReplicas?: ApiService["numReplicas"];
69
+
70
+ /**
71
+ * Whether to enable idle scaling.
72
+ *
73
+ * @default true
74
+ */
75
+ idleScaling?: ApiService["idleScaling"];
76
+
77
+ /**
78
+ * The timeout minutes for idle scaling.
79
+ *
80
+ * @default 15
81
+ */
82
+ idleTimeoutMinutes?: ApiService["idleTimeoutMinutes"];
83
+
84
+ /**
85
+ * Whether to make the service readonly.
86
+ *
87
+ * @default false
88
+ */
89
+ isReadonly?: ApiService["isReadonly"];
90
+
91
+ /**
92
+ * The release channel to create the service with.
93
+ *
94
+ * @default "default"
95
+ */
96
+ releaseChannel?: ApiService["releaseChannel"];
97
+
98
+ /**
99
+ * The desired state of the service.
100
+ *
101
+ * @default "start"
102
+ */
103
+ stateTarget?: "start" | "stop";
104
+
105
+ /**
106
+ * Whether to enable the mysql endpoint.
107
+ *
108
+ * @default true
109
+ */
110
+ enableMysqlEndpoint?: boolean;
111
+
112
+ /**
113
+ * Whether to enable the https endpoint. Cannot be disabled
114
+ *
115
+ * @default true
116
+ */
117
+ enableHttpsEndpoint?: true;
118
+
119
+ /**
120
+ * Whether to enable the nativesecure endpoint. Cannot be disabled
121
+ *
122
+ * @default true
123
+ */
124
+ enableNativesecureEndpoint?: true;
125
+
126
+ /**
127
+ * The compliance type to create the service with.
128
+ */
129
+ complianceType?: ApiService["complianceType"];
130
+
131
+ //todo(michael): I need to understand more about what these properties do before documenting
132
+ //todo(michael): support linking to BYOC infrastructure directly
133
+ byocId?: ApiService["byocId"];
134
+ hasTransparentDataEncryption?: ApiService["hasTransparentDataEncryption"];
135
+ profile?: ApiService["profile"];
136
+ dataWarehouseId?: ApiService["dataWarehouseId"];
137
+ backupId?: string;
138
+ encryptionKey?: ApiService["encryptionKey"];
139
+ encryptionAssumedRoleIdentifier?: ApiService["encryptionAssumedRoleIdentifier"];
140
+ }
141
+
142
+ export interface Service {
143
+ /**
144
+ * The id of Clickhouse cloud organization the service is in.
145
+ */
146
+ organizationId: string;
147
+
148
+ /**
149
+ * The name of the Clickhouse service.
150
+ *
151
+ */
152
+ name: string;
153
+
154
+ /**
155
+ * The clickhouse id of the Clickhouse service.
156
+ */
157
+ clickhouseId: string;
158
+
159
+ /**
160
+ * The password for the Clickhouse service.
161
+ */
162
+ password: Secret<string>;
163
+
164
+ /**
165
+ * The provider of the Clickhouse service.
166
+ */
167
+ provider: NonNullable<ApiService["provider"]>;
168
+
169
+ /**
170
+ * The region of the Clickhouse service.
171
+ */
172
+ region: NonNullable<ApiService["region"]>;
173
+
174
+ /**
175
+ * The IP access list of the Clickhouse service.
176
+ */
177
+ ipAccessList: NonNullable<ApiService["ipAccessList"]>;
178
+
179
+ /**
180
+ * The minimum replica memory of the Clickhouse service.
181
+ */
182
+ minReplicaMemoryGb: NonNullable<ApiService["minReplicaMemoryGb"]>;
183
+
184
+ /**
185
+ * The maximum replica memory of the Clickhouse service.
186
+ */
187
+ maxReplicaMemoryGb: NonNullable<ApiService["maxReplicaMemoryGb"]>;
188
+
189
+ /**
190
+ * The number of replicas of the Clickhouse service.
191
+ */
192
+ numReplicas: NonNullable<ApiService["numReplicas"]>;
193
+
194
+ /**
195
+ * Whether to enable idle scaling of the Clickhouse service.
196
+ */
197
+ idleScaling: NonNullable<ApiService["idleScaling"]>;
198
+
199
+ /**
200
+ * The timeout minutes for idle scaling of the Clickhouse service.
201
+ */
202
+ idleTimeoutMinutes: NonNullable<ApiService["idleTimeoutMinutes"]>;
203
+
204
+ /**
205
+ * Whether to make the Clickhouse service readonly.
206
+ */
207
+ isReadonly: NonNullable<ApiService["isReadonly"]>;
208
+
209
+ /**
210
+ * The data warehouse id of the Clickhouse service.
211
+ */
212
+ dataWarehouseId: NonNullable<ApiService["dataWarehouseId"]>;
213
+
214
+ /**
215
+ * The encryption key of the Clickhouse service.
216
+ */
217
+ encryptionKey?: ApiService["encryptionKey"];
218
+
219
+ /**
220
+ * The encryption assumed role identifier of the Clickhouse service.
221
+ */
222
+ encryptionAssumedRoleIdentifier?: ApiService["encryptionAssumedRoleIdentifier"];
223
+
224
+ /**
225
+ * The release channel of the Clickhouse service.
226
+ */
227
+ releaseChannel: NonNullable<ApiService["releaseChannel"]>;
228
+
229
+ /**
230
+ * The byoc id of the Clickhouse service if it is using BYOC infrastructure.
231
+ */
232
+ byocId?: ApiService["byocId"];
233
+
234
+ /**
235
+ * Whether to enable transparent data encryption of the Clickhouse service.
236
+ */
237
+ hasTransparentDataEncryption?: ApiService["hasTransparentDataEncryption"];
238
+
239
+ /**
240
+ * The profile the Clickhouse service was created using.
241
+ */
242
+ profile?: ApiService["profile"];
243
+
244
+ /**
245
+ * The compliance type of the Clickhouse service.
246
+ */
247
+ complianceType?: ApiService["complianceType"];
248
+
249
+ /**
250
+ * The backup id of the Clickhouse service.
251
+ */
252
+ backupId?: string;
253
+
254
+ /**
255
+ * If the mysql endpoint is enabled.
256
+ */
257
+ enableMysqlEndpoint?: boolean;
258
+
259
+ /**
260
+ * If the https endpoint is enabled.
261
+ */
262
+ enableHttpsEndpoint?: true;
263
+
264
+ /**
265
+ * If the nativesecure endpoint is enabled.
266
+ */
267
+ enableNativesecureEndpoint?: true;
268
+
269
+ /**
270
+ * The mysql endpoint details of the Clickhouse service.
271
+ */
272
+ mysqlEndpoint?: {
273
+ protocol: "mysql";
274
+ host: string;
275
+ port: number;
276
+ username: string;
277
+ };
278
+
279
+ /**
280
+ * The https endpoint details of the Clickhouse service.
281
+ */
282
+ httpsEndpoint?: {
283
+ protocol: "https";
284
+ host: string;
285
+ port: number;
286
+ };
287
+
288
+ /**
289
+ * The nativesecure endpoint details of the Clickhouse service.
290
+ */
291
+ nativesecureEndpoint?: {
292
+ protocol: "nativesecure";
293
+ host: string;
294
+ port: number;
295
+ };
296
+
297
+ /**
298
+ * The desired state of the Clickhouse service.
299
+ */
300
+ stateTarget: "start" | "stop";
301
+
302
+ /**
303
+ * The state of the Clickhouse service.
304
+ */
305
+ state: ApiService["state"];
306
+ }
307
+
308
+ /**
309
+ * Create, manage and delete Clickhouse services
310
+ *
311
+ * @example
312
+ * // Create a basic Clickhouse service on aws
313
+ * const organization = await getOrganizationByName("Alchemy's Organization");
314
+ * const service = await Service("clickhouse", {
315
+ * organization,
316
+ * provider: "aws",
317
+ * region: "us-east-1",
318
+ * });
319
+ *
320
+ * @example
321
+ * // Create a basic Clickhouse service on aws with custom scaling rules
322
+ * const service = await Service("clickhouse", {
323
+ * organization,
324
+ * provider: "aws",
325
+ * region: "us-east-1",
326
+ * minReplicaMemoryGb: 8,
327
+ * maxReplicaMemoryGb: 356,
328
+ * numReplicas: 3,
329
+ * });
330
+ */
331
+ export const Service = Resource(
332
+ "clickhouse::Service",
333
+ async function (
334
+ this: Context<Service>,
335
+ id: string,
336
+ props: ServiceProps,
337
+ ): Promise<Service> {
338
+ const api = createClickhouseApi({
339
+ keyId: props.keyId,
340
+ secret: props.secret,
341
+ });
342
+
343
+ const idleScaling = props.idleScaling ?? true;
344
+ const isReadonly = props.isReadonly ?? false;
345
+ const releaseChannel = props.releaseChannel ?? "default";
346
+ const endpoints: Array<{ protocol: "mysql"; enabled: boolean }> = [];
347
+ const enableMysqlEndpoint = props.enableMysqlEndpoint ?? true;
348
+ if (enableMysqlEndpoint) {
349
+ endpoints.push({ protocol: "mysql", enabled: true });
350
+ }
351
+ //todo(michael): comment these in when disabling is supported
352
+ // const enableHttpsEndpoint = props.enableHttpsEndpoint ?? true;
353
+ // if (enableHttpsEndpoint) {
354
+ // endpoints.push({ protocol: "https", enabled: true });
355
+ // }
356
+ // const enableNativesecureEndpoint = props.enableNativesecureEndpoint ?? true;
357
+ // if (enableNativesecureEndpoint) {
358
+ // endpoints.push({ protocol: "nativesecure", enabled: true });
359
+ // }
360
+ const stateTarget = props.stateTarget ?? "start";
361
+ const ipAccessList = props.ipAccessList ?? [
362
+ {
363
+ description: "Anywhere",
364
+ source: "0.0.0.0/0",
365
+ },
366
+ ];
367
+ const minReplicaMemoryGb = props.minReplicaMemoryGb ?? 8;
368
+ const maxReplicaMemoryGb = props.maxReplicaMemoryGb ?? 356;
369
+ const numReplicas = props.numReplicas ?? 3;
370
+ const idleTimeoutMinutes = props.idleTimeoutMinutes ?? 15;
371
+
372
+ const name =
373
+ props.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
374
+
375
+ const organizationId =
376
+ typeof props.organization === "string"
377
+ ? props.organization
378
+ : props.organization.id!;
379
+
380
+ if (this.phase === "delete") {
381
+ await api.updateServiceState({
382
+ path: {
383
+ organizationId: organizationId,
384
+ serviceId: this.output.clickhouseId,
385
+ },
386
+ body: {
387
+ command: "stop",
388
+ },
389
+ });
390
+
391
+ await waitForServiceState(
392
+ api,
393
+ organizationId,
394
+ this.output.clickhouseId,
395
+ (state) => state === "stopped",
396
+ 10 * 60,
397
+ );
398
+
399
+ await api.deleteService({
400
+ path: {
401
+ organizationId: organizationId,
402
+ serviceId: this.output.clickhouseId,
403
+ },
404
+ });
405
+
406
+ return this.destroy();
407
+ }
408
+ if (this.phase === "update") {
409
+ const resourceDiff = diff(
410
+ {
411
+ ...props,
412
+ idleScaling,
413
+ isReadonly,
414
+ releaseChannel,
415
+ name,
416
+ },
417
+ {
418
+ ...this.output,
419
+ organization: props.organization,
420
+ },
421
+ );
422
+
423
+ const updates: Partial<Service> = {};
424
+
425
+ if (
426
+ resourceDiff.some(
427
+ (prop) =>
428
+ prop !== "name" &&
429
+ prop !== "ipAccessList" &&
430
+ prop !== "releaseChannel" &&
431
+ prop !== "enableMysqlEndpoint" &&
432
+ prop !== "enableHttpsEndpoint" &&
433
+ prop !== "enableNativesecureEndpoint" &&
434
+ prop !== "minReplicaMemoryGb" &&
435
+ prop !== "maxReplicaMemoryGb" &&
436
+ prop !== "numReplicas" &&
437
+ prop !== "idleScaling" &&
438
+ prop !== "idleTimeoutMinutes" &&
439
+ prop !== "stateTarget",
440
+ )
441
+ ) {
442
+ return this.replace();
443
+ }
444
+
445
+ if (
446
+ //todo(michael): check encryption key swap?
447
+ resourceDiff.some(
448
+ (prop) =>
449
+ prop === "name" ||
450
+ prop === "ipAccessList" ||
451
+ prop === "releaseChannel",
452
+ ) ||
453
+ enableMysqlEndpoint !== this.output.enableMysqlEndpoint
454
+ ) {
455
+ const ipAccessListToRemove = this.output.ipAccessList.filter(
456
+ (ipAccessList) => !props.ipAccessList?.includes(ipAccessList),
457
+ );
458
+ const ipAccessListToAdd = props.ipAccessList?.filter(
459
+ (ipAccessList) => !this.output.ipAccessList.includes(ipAccessList),
460
+ );
461
+ const response = (
462
+ await api.updateServiceBasicDetails({
463
+ path: {
464
+ organizationId: organizationId,
465
+ serviceId: this.output.clickhouseId,
466
+ },
467
+ body: {
468
+ name,
469
+ ipAccessList: {
470
+ remove: ipAccessListToRemove,
471
+ add: ipAccessListToAdd,
472
+ },
473
+ releaseChannel,
474
+ endpoints,
475
+ },
476
+ })
477
+ ).data.result!;
478
+
479
+ updates.name = response.name!;
480
+ updates.ipAccessList = response.ipAccessList!;
481
+ updates.releaseChannel = response.releaseChannel!;
482
+ updates.mysqlEndpoint = response!.endpoints!.find(
483
+ (endpoint) => endpoint.protocol === "mysql",
484
+ ) as any;
485
+ updates.httpsEndpoint = response!.endpoints!.find(
486
+ (endpoint) => endpoint.protocol === "https",
487
+ ) as any;
488
+ updates.nativesecureEndpoint = response!.endpoints!.find(
489
+ (endpoint) => endpoint.protocol === "nativesecure",
490
+ ) as any;
491
+ }
492
+
493
+ if (stateTarget !== this.output.stateTarget) {
494
+ const response = await api.updateServiceState({
495
+ path: {
496
+ organizationId: organizationId,
497
+ serviceId: this.output.clickhouseId,
498
+ },
499
+ body: {
500
+ command: stateTarget,
501
+ },
502
+ });
503
+
504
+ updates.state = response.data.result!.state!;
505
+ updates.stateTarget = stateTarget;
506
+ }
507
+
508
+ if (
509
+ resourceDiff.some(
510
+ (prop) =>
511
+ prop === "minReplicaMemoryGb" ||
512
+ prop === "maxReplicaMemoryGb" ||
513
+ prop === "numReplicas" ||
514
+ prop === "idleScaling" ||
515
+ prop === "idleTimeoutMinutes",
516
+ )
517
+ ) {
518
+ const response = (
519
+ await api.updateServiceAutoScalingSettings2({
520
+ path: {
521
+ organizationId: organizationId,
522
+ serviceId: this.output.clickhouseId,
523
+ },
524
+ body: {
525
+ minReplicaMemoryGb: props.minReplicaMemoryGb,
526
+ maxReplicaMemoryGb: props.maxReplicaMemoryGb,
527
+ numReplicas: props.numReplicas,
528
+ idleScaling: props.idleScaling,
529
+ idleTimeoutMinutes: idleTimeoutMinutes,
530
+ },
531
+ })
532
+ ).data.result!;
533
+
534
+ updates.minReplicaMemoryGb = response.minReplicaMemoryGb!;
535
+ updates.maxReplicaMemoryGb = response.maxReplicaMemoryGb!;
536
+ updates.numReplicas = response.numReplicas!;
537
+ updates.idleScaling = response.idleScaling!;
538
+ updates.idleTimeoutMinutes = response.idleTimeoutMinutes!;
539
+ }
540
+
541
+ return {
542
+ ...this.output,
543
+ ...updates,
544
+ };
545
+ }
546
+
547
+ const response = (
548
+ await api.createNewService({
549
+ path: {
550
+ organizationId: organizationId,
551
+ },
552
+ body: {
553
+ name,
554
+ provider: props.provider,
555
+ region: props.region,
556
+ ipAccessList: ipAccessList,
557
+ minReplicaMemoryGb: minReplicaMemoryGb,
558
+ maxReplicaMemoryGb: maxReplicaMemoryGb,
559
+ numReplicas: numReplicas,
560
+ idleScaling: idleScaling,
561
+ idleTimeoutMinutes: idleTimeoutMinutes,
562
+ isReadonly: isReadonly,
563
+ dataWarehouseId: props.dataWarehouseId,
564
+ backupId: props.backupId,
565
+ encryptionKey: props.encryptionKey,
566
+ encryptionAssumedRoleIdentifier:
567
+ props.encryptionAssumedRoleIdentifier,
568
+ privatePreviewTermsChecked: true,
569
+ releaseChannel: releaseChannel,
570
+ byocId: props.byocId,
571
+ hasTransparentDataEncryption:
572
+ props.hasTransparentDataEncryption ?? false,
573
+ endpoints: endpoints,
574
+ profile: props.profile,
575
+ complianceType: props.complianceType,
576
+ },
577
+ })
578
+ ).data.result!;
579
+ const password = response.password!;
580
+ const service = response.service!;
581
+
582
+ await waitForServiceState(
583
+ api,
584
+ organizationId,
585
+ response.service!.id!,
586
+ (state) => state === "running" || state === "idle",
587
+ 10 * 60,
588
+ );
589
+
590
+ return {
591
+ organizationId: organizationId,
592
+ name: service.name!,
593
+ clickhouseId: service.id!,
594
+ password: secret(password!),
595
+ provider: service.provider!,
596
+ region: service.region!,
597
+ ipAccessList: service.ipAccessList!,
598
+ minReplicaMemoryGb: service.minReplicaMemoryGb!,
599
+ maxReplicaMemoryGb: service.maxReplicaMemoryGb!,
600
+ numReplicas: service.numReplicas!,
601
+ idleScaling: service.idleScaling!,
602
+ idleTimeoutMinutes: service.idleTimeoutMinutes!,
603
+ isReadonly: service.isReadonly!,
604
+ dataWarehouseId: service.dataWarehouseId!,
605
+ backupId: props.backupId,
606
+ encryptionKey: service.encryptionKey,
607
+ encryptionAssumedRoleIdentifier: service.encryptionAssumedRoleIdentifier,
608
+ releaseChannel: service.releaseChannel!,
609
+ byocId: service.byocId,
610
+ hasTransparentDataEncryption: service.hasTransparentDataEncryption,
611
+ profile: service.profile,
612
+ complianceType: service.complianceType,
613
+ stateTarget,
614
+ state: service.state,
615
+ mysqlEndpoint: service.endpoints!.find(
616
+ (endpoint) => endpoint.protocol === "mysql",
617
+ ) as any,
618
+ httpsEndpoint: service.endpoints!.find(
619
+ (endpoint) => endpoint.protocol === "https",
620
+ ) as any,
621
+ nativesecureEndpoint: service.endpoints!.find(
622
+ (endpoint) => endpoint.protocol === "nativesecure",
623
+ ) as any,
624
+ };
625
+ },
626
+ );
627
+
628
+ async function waitForServiceState(
629
+ api: ClickhouseClient,
630
+ organizationId: string,
631
+ serviceId: string,
632
+ stateChecker: (state: string) => boolean,
633
+ maxWaitSeconds: number,
634
+ ) {
635
+ const checkState = async (): Promise<void> => {
636
+ const service = await api.getServiceDetails({
637
+ path: {
638
+ organizationId: organizationId,
639
+ serviceId: serviceId,
640
+ },
641
+ });
642
+ const serviceState = service.data.result!.state!;
643
+
644
+ if (stateChecker(serviceState)) {
645
+ return;
646
+ }
647
+
648
+ throw new Error(`Service ${serviceId} is in state ${serviceState}`);
649
+ };
650
+
651
+ if (maxWaitSeconds < 5) {
652
+ maxWaitSeconds = 5;
653
+ }
654
+
655
+ const maxRetries = Math.floor(maxWaitSeconds / 5);
656
+
657
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
658
+ try {
659
+ await checkState();
660
+ return;
661
+ } catch (error) {
662
+ if (attempt === maxRetries - 1) {
663
+ throw error;
664
+ }
665
+ await new Promise((resolve) => setTimeout(resolve, 5000));
666
+ }
667
+ }
668
+ }
@@ -282,10 +282,7 @@ export const AccountApiToken = Resource(
282
282
  return this.destroy();
283
283
  }
284
284
 
285
- const permissionGroups = await PermissionGroups(
286
- "cloudflare-permission-groups",
287
- props,
288
- );
285
+ const permissionGroups = await PermissionGroups(props);
289
286
 
290
287
  // Transform our properties to API format
291
288
  const apiPayload = {
@@ -1,3 +1,4 @@
1
+ import type { R2PutOptions } from "@cloudflare/workers-types/experimental/index.ts";
1
2
  import type { Context } from "../context.ts";
2
3
  import { Resource } from "../resource.ts";
3
4
  import { createCloudflareApi, type CloudflareApiOptions } from "./api.ts";
@@ -23,6 +24,11 @@ export interface R2ObjectProps extends CloudflareApiOptions {
23
24
  * Supports various data types including streams, buffers, strings, and blobs
24
25
  */
25
26
  content: PutObjectObject;
27
+
28
+ /**
29
+ * The options to use for the object
30
+ */
31
+ options?: Pick<R2PutOptions, "httpMetadata">;
26
32
  }
27
33
 
28
34
  /**
@@ -105,7 +111,11 @@ export const R2Object = Resource(
105
111
  this.replace();
106
112
  }
107
113
  // Create or update the object in the bucket
108
- const response = await props.bucket.put(props.key, props.content);
114
+ const response = await props.bucket.put(
115
+ props.key,
116
+ props.content,
117
+ props.options,
118
+ );
109
119
 
110
120
  return {
111
121
  id,