alchemy 0.63.1 → 0.65.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 (235) hide show
  1. package/bin/alchemy.js +7664 -5857
  2. package/bin/commands/init.ts +130 -9
  3. package/bin/constants.ts +4 -0
  4. package/bin/services/cdp-manager/cdp-proxy.ts +69 -0
  5. package/bin/services/cdp-manager/server.ts +173 -0
  6. package/bin/services/execute-alchemy.ts +83 -4
  7. package/bin/types.ts +1 -0
  8. package/lib/alchemy.d.ts +4 -0
  9. package/lib/alchemy.d.ts.map +1 -1
  10. package/lib/alchemy.js +10 -4
  11. package/lib/alchemy.js.map +1 -1
  12. package/lib/apply.d.ts +3 -0
  13. package/lib/apply.d.ts.map +1 -1
  14. package/lib/apply.js +11 -1
  15. package/lib/apply.js.map +1 -1
  16. package/lib/cloudflare/bindings.d.ts +3 -1
  17. package/lib/cloudflare/bindings.d.ts.map +1 -1
  18. package/lib/cloudflare/bucket.d.ts +2 -1
  19. package/lib/cloudflare/bucket.d.ts.map +1 -1
  20. package/lib/cloudflare/bucket.js.map +1 -1
  21. package/lib/cloudflare/bundle/cloudflare-internal.d.ts +6 -0
  22. package/lib/cloudflare/bundle/cloudflare-internal.d.ts.map +1 -0
  23. package/lib/cloudflare/bundle/cloudflare-internal.js +39 -0
  24. package/lib/cloudflare/bundle/cloudflare-internal.js.map +1 -0
  25. package/lib/cloudflare/bundle/nodejs-builtin-modules.d.ts +2 -0
  26. package/lib/cloudflare/bundle/nodejs-builtin-modules.d.ts.map +1 -0
  27. package/lib/cloudflare/bundle/nodejs-builtin-modules.js +9 -0
  28. package/lib/cloudflare/bundle/nodejs-builtin-modules.js.map +1 -0
  29. package/lib/cloudflare/bundle/plugin-als-external.d.ts +6 -0
  30. package/lib/cloudflare/bundle/plugin-als-external.d.ts.map +1 -0
  31. package/lib/cloudflare/bundle/plugin-als-external.js +12 -0
  32. package/lib/cloudflare/bundle/plugin-als-external.js.map +1 -0
  33. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.d.ts +4 -1
  34. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.d.ts.map +1 -1
  35. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js +23 -23
  36. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -1
  37. package/lib/cloudflare/bundle/plugin-node-compat.d.ts +11 -0
  38. package/lib/cloudflare/bundle/plugin-node-compat.d.ts.map +1 -0
  39. package/lib/cloudflare/bundle/plugin-node-compat.js +93 -0
  40. package/lib/cloudflare/bundle/plugin-node-compat.js.map +1 -0
  41. package/lib/cloudflare/bundle/plugin-wasm.d.ts.map +1 -1
  42. package/lib/cloudflare/bundle/plugin-wasm.js +20 -11
  43. package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -1
  44. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  45. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  46. package/lib/cloudflare/d1-local-migrations.js.map +1 -1
  47. package/lib/cloudflare/durable-object-namespace.d.ts +1 -0
  48. package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -1
  49. package/lib/cloudflare/durable-object-namespace.js.map +1 -1
  50. package/lib/cloudflare/hyperdrive.d.ts +7 -2
  51. package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
  52. package/lib/cloudflare/hyperdrive.js +39 -57
  53. package/lib/cloudflare/hyperdrive.js.map +1 -1
  54. package/lib/cloudflare/index.d.ts +1 -0
  55. package/lib/cloudflare/index.d.ts.map +1 -1
  56. package/lib/cloudflare/index.js +1 -0
  57. package/lib/cloudflare/index.js.map +1 -1
  58. package/lib/cloudflare/next.d.ts +13 -0
  59. package/lib/cloudflare/next.d.ts.map +1 -0
  60. package/lib/cloudflare/next.js +91 -0
  61. package/lib/cloudflare/next.js.map +1 -0
  62. package/lib/cloudflare/website.d.ts.map +1 -1
  63. package/lib/cloudflare/website.js +80 -82
  64. package/lib/cloudflare/website.js.map +1 -1
  65. package/lib/cloudflare/worker-assets.d.ts +3 -3
  66. package/lib/cloudflare/worker-assets.d.ts.map +1 -1
  67. package/lib/cloudflare/worker-assets.js +22 -47
  68. package/lib/cloudflare/worker-assets.js.map +1 -1
  69. package/lib/cloudflare/worker-bundle.d.ts +6 -0
  70. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  71. package/lib/cloudflare/worker-bundle.js +34 -10
  72. package/lib/cloudflare/worker-bundle.js.map +1 -1
  73. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  74. package/lib/cloudflare/worker-metadata.js +1 -0
  75. package/lib/cloudflare/worker-metadata.js.map +1 -1
  76. package/lib/cloudflare/worker.d.ts.map +1 -1
  77. package/lib/cloudflare/worker.js +24 -6
  78. package/lib/cloudflare/worker.js.map +1 -1
  79. package/lib/cloudflare/wrangler.json.d.ts +4 -6
  80. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  81. package/lib/cloudflare/wrangler.json.js +20 -15
  82. package/lib/cloudflare/wrangler.json.js.map +1 -1
  83. package/lib/context.d.ts +3 -1
  84. package/lib/context.d.ts.map +1 -1
  85. package/lib/context.js +2 -2
  86. package/lib/context.js.map +1 -1
  87. package/lib/destroy.d.ts +8 -0
  88. package/lib/destroy.d.ts.map +1 -1
  89. package/lib/destroy.js +20 -4
  90. package/lib/destroy.js.map +1 -1
  91. package/lib/planetscale/api/client.gen.d.ts +1750 -0
  92. package/lib/planetscale/api/client.gen.d.ts.map +1 -0
  93. package/lib/planetscale/api/client.gen.js +2401 -0
  94. package/lib/planetscale/api/client.gen.js.map +1 -0
  95. package/lib/planetscale/api/index.d.ts +3 -0
  96. package/lib/planetscale/api/index.d.ts.map +1 -0
  97. package/lib/planetscale/api/index.js +4 -0
  98. package/lib/planetscale/api/index.js.map +1 -0
  99. package/lib/planetscale/api/types.gen.d.ts +12156 -0
  100. package/lib/planetscale/api/types.gen.d.ts.map +1 -0
  101. package/lib/planetscale/api/types.gen.js +2 -0
  102. package/lib/planetscale/api/types.gen.js.map +1 -0
  103. package/lib/planetscale/branch.d.ts +5 -8
  104. package/lib/planetscale/branch.d.ts.map +1 -1
  105. package/lib/planetscale/branch.js +122 -97
  106. package/lib/planetscale/branch.js.map +1 -1
  107. package/lib/planetscale/database.d.ts +24 -11
  108. package/lib/planetscale/database.d.ts.map +1 -1
  109. package/lib/planetscale/database.js +163 -118
  110. package/lib/planetscale/database.js.map +1 -1
  111. package/lib/planetscale/index.d.ts +2 -1
  112. package/lib/planetscale/index.d.ts.map +1 -1
  113. package/lib/planetscale/index.js +2 -1
  114. package/lib/planetscale/index.js.map +1 -1
  115. package/lib/planetscale/password.d.ts +7 -8
  116. package/lib/planetscale/password.d.ts.map +1 -1
  117. package/lib/planetscale/password.js +74 -57
  118. package/lib/planetscale/password.js.map +1 -1
  119. package/lib/planetscale/role.d.ts +126 -0
  120. package/lib/planetscale/role.d.ts.map +1 -0
  121. package/lib/planetscale/role.js +144 -0
  122. package/lib/planetscale/role.js.map +1 -0
  123. package/lib/planetscale/utils.d.ts +23 -7
  124. package/lib/planetscale/utils.d.ts.map +1 -1
  125. package/lib/planetscale/utils.js +169 -75
  126. package/lib/planetscale/utils.js.map +1 -1
  127. package/lib/scope.d.ts +5 -1
  128. package/lib/scope.d.ts.map +1 -1
  129. package/lib/scope.js +11 -3
  130. package/lib/scope.js.map +1 -1
  131. package/lib/secret.d.ts +0 -3
  132. package/lib/secret.d.ts.map +1 -1
  133. package/lib/secret.js +0 -2
  134. package/lib/secret.js.map +1 -1
  135. package/lib/state/cloudflare-state-store.js +3 -3
  136. package/lib/state/cloudflare-state-store.js.map +1 -1
  137. package/lib/test/bun.d.ts +2 -2
  138. package/lib/test/bun.d.ts.map +1 -1
  139. package/lib/test/vitest.d.ts +2 -2
  140. package/lib/test/vitest.d.ts.map +1 -1
  141. package/lib/test/vitest.js +4 -4
  142. package/lib/test/vitest.js.map +1 -1
  143. package/lib/util/content-type.js +2 -2
  144. package/lib/util/content-type.js.map +1 -1
  145. package/lib/util/dedent.d.ts +3 -14
  146. package/lib/util/dedent.d.ts.map +1 -1
  147. package/lib/util/dedent.js +33 -45
  148. package/lib/util/dedent.js.map +1 -1
  149. package/lib/util/memoize.d.ts.map +1 -1
  150. package/lib/util/memoize.js +11 -1
  151. package/lib/util/memoize.js.map +1 -1
  152. package/package.json +8 -3
  153. package/src/alchemy.ts +14 -6
  154. package/src/apply.ts +13 -1
  155. package/src/cloudflare/bindings.ts +3 -1
  156. package/src/cloudflare/bucket.ts +3 -1
  157. package/src/cloudflare/bundle/cloudflare-internal.ts +42 -0
  158. package/src/cloudflare/bundle/nodejs-builtin-modules.ts +14 -0
  159. package/src/cloudflare/bundle/plugin-als-external.ts +13 -0
  160. package/src/cloudflare/bundle/plugin-hybrid-node-compat.ts +29 -28
  161. package/src/cloudflare/bundle/plugin-node-compat.ts +114 -0
  162. package/src/cloudflare/bundle/plugin-wasm.ts +34 -14
  163. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  164. package/src/cloudflare/d1-local-migrations.ts +2 -2
  165. package/src/cloudflare/durable-object-namespace.ts +1 -0
  166. package/src/cloudflare/hyperdrive.ts +136 -95
  167. package/src/cloudflare/index.ts +1 -0
  168. package/src/cloudflare/next.ts +123 -0
  169. package/src/cloudflare/website.ts +88 -89
  170. package/src/cloudflare/worker-assets.ts +43 -105
  171. package/src/cloudflare/worker-bundle.ts +46 -9
  172. package/src/cloudflare/worker-metadata.ts +2 -0
  173. package/src/cloudflare/worker.ts +35 -7
  174. package/src/cloudflare/wrangler.json.ts +114 -113
  175. package/src/context.ts +5 -3
  176. package/src/destroy.ts +26 -8
  177. package/src/planetscale/api/client.gen.ts +2882 -0
  178. package/src/planetscale/api/index.ts +4 -0
  179. package/src/planetscale/api/types.gen.ts +13041 -0
  180. package/src/planetscale/branch.ts +170 -162
  181. package/src/planetscale/database.ts +263 -243
  182. package/src/planetscale/index.ts +2 -1
  183. package/src/planetscale/password.ts +89 -86
  184. package/src/planetscale/role.ts +278 -0
  185. package/src/planetscale/utils.ts +289 -128
  186. package/src/scope.ts +12 -3
  187. package/src/secret.ts +0 -4
  188. package/src/state/cloudflare-state-store.ts +4 -4
  189. package/src/test/bun.ts +2 -2
  190. package/src/test/vitest.ts +6 -6
  191. package/src/util/content-type.ts +2 -2
  192. package/src/util/dedent.ts +34 -50
  193. package/src/util/memoize.ts +13 -1
  194. package/templates/astro/alchemy.run.ts +1 -3
  195. package/templates/hono/alchemy.run.ts +0 -1
  196. package/templates/nextjs/README.md +85 -0
  197. package/templates/nextjs/_env +1 -0
  198. package/templates/nextjs/_env.example +1 -0
  199. package/templates/nextjs/_gitignore +46 -0
  200. package/templates/nextjs/alchemy.run.ts +16 -0
  201. package/templates/nextjs/eslint.config.mjs +16 -0
  202. package/templates/nextjs/next-env.d.ts +5 -0
  203. package/templates/nextjs/next.config.ts +10 -0
  204. package/templates/nextjs/open-next.config.ts +5 -0
  205. package/templates/nextjs/package.json +31 -0
  206. package/templates/nextjs/src/app/api/hello/route.ts +19 -0
  207. package/templates/nextjs/src/app/favicon.ico +0 -0
  208. package/templates/nextjs/src/app/globals.css +72 -0
  209. package/templates/nextjs/src/app/layout.tsx +19 -0
  210. package/templates/nextjs/src/app/page.tsx +55 -0
  211. package/templates/nextjs/tsconfig.json +33 -0
  212. package/templates/nextjs/types/env.d.ts +14 -0
  213. package/templates/nuxt/alchemy.run.ts +1 -3
  214. package/templates/react-router/alchemy.run.ts +1 -3
  215. package/templates/rwsdk/alchemy.run.ts +0 -2
  216. package/templates/sveltekit/alchemy.run.ts +1 -3
  217. package/templates/tanstack-start/alchemy.run.ts +1 -3
  218. package/templates/typescript/alchemy.run.ts +0 -1
  219. package/templates/vite/alchemy.run.ts +0 -1
  220. package/workers/cloudflare-state-store.js +58 -58
  221. package/lib/cloudflare/bundle/externals.d.ts +0 -3
  222. package/lib/cloudflare/bundle/externals.d.ts.map +0 -1
  223. package/lib/cloudflare/bundle/externals.js +0 -35
  224. package/lib/cloudflare/bundle/externals.js.map +0 -1
  225. package/lib/cloudflare/bundle/plugin-compat-warning.d.ts +0 -10
  226. package/lib/cloudflare/bundle/plugin-compat-warning.d.ts.map +0 -1
  227. package/lib/cloudflare/bundle/plugin-compat-warning.js +0 -67
  228. package/lib/cloudflare/bundle/plugin-compat-warning.js.map +0 -1
  229. package/lib/planetscale/api.d.ts +0 -53
  230. package/lib/planetscale/api.d.ts.map +0 -1
  231. package/lib/planetscale/api.js +0 -84
  232. package/lib/planetscale/api.js.map +0 -1
  233. package/src/cloudflare/bundle/externals.ts +0 -36
  234. package/src/cloudflare/bundle/plugin-compat-warning.ts +0 -94
  235. package/src/planetscale/api.ts +0 -115
@@ -1,17 +1,15 @@
1
1
  import type { Context } from "../context.ts";
2
2
  import { Resource } from "../resource.ts";
3
- import type { Secret } from "../secret.ts";
4
- import { PlanetScaleApi } from "./api.ts";
3
+ import type { PlanetScaleProps } from "./api/client.gen.ts";
4
+ import { PlanetScaleClient } from "./api/client.gen.ts";
5
5
  import {
6
- fixClusterSize,
6
+ ensureProductionBranchClusterSize,
7
7
  type PlanetScaleClusterSize,
8
+ sanitizeClusterSize,
8
9
  waitForDatabaseReady,
9
10
  } from "./utils.ts";
10
11
 
11
- /**
12
- * Properties for creating or updating a PlanetScale Database
13
- */
14
- export interface DatabaseProps {
12
+ interface BaseDatabaseProps extends PlanetScaleProps {
15
13
  /**
16
14
  * The name of the database
17
15
  *
@@ -24,11 +22,6 @@ export interface DatabaseProps {
24
22
  */
25
23
  organizationId: string;
26
24
 
27
- /**
28
- * PlanetScale API token (overrides environment variable)
29
- */
30
- apiKey?: Secret;
31
-
32
25
  /**
33
26
  * Whether to adopt the database if it already exists in Planetscale
34
27
  */
@@ -93,54 +86,79 @@ export interface DatabaseProps {
93
86
  * The database cluster size (required)
94
87
  */
95
88
  clusterSize: PlanetScaleClusterSize;
96
- }
97
89
 
98
- /**
99
- * Represents a PlanetScale Database
100
- */
101
- export interface Database
102
- extends Resource<"planetscale::Database">,
103
- DatabaseProps {
104
90
  /**
105
- * The unique identifier of the database
91
+ * The engine kind for the database
92
+ * @default "mysql"
106
93
  */
107
- id: string;
94
+ kind?: "mysql" | "postgresql";
108
95
 
109
96
  /**
110
- * The name of the database
97
+ * The CPU architecture for the database. Only available for PostgreSQL databases.
111
98
  */
112
- name: string;
99
+ arch?: "x86" | "arm";
100
+ }
113
101
 
114
- /**
115
- * The current state of the database
116
- */
117
- state: string;
102
+ /**
103
+ * Properties for creating or updating a PlanetScale Database
104
+ */
105
+ export type DatabaseProps = BaseDatabaseProps &
106
+ (
107
+ | {
108
+ kind?: "mysql";
109
+ arch?: undefined;
110
+ }
111
+ | {
112
+ kind: "postgresql";
113
+ arch?: "x86" | "arm";
114
+ }
115
+ );
118
116
 
119
- /**
120
- * The default branch name
121
- */
122
- defaultBranch: string;
117
+ /**
118
+ * Represents a PlanetScale Database
119
+ */
120
+ export type Database = Resource<"planetscale::Database"> &
121
+ DatabaseProps & {
122
+ /**
123
+ * The unique identifier of the database
124
+ */
125
+ id: string;
123
126
 
124
- /**
125
- * The plan type
126
- */
127
- plan: string;
127
+ /**
128
+ * The name of the database
129
+ */
130
+ name: string;
128
131
 
129
- /**
130
- * Time at which the database was created
131
- */
132
- createdAt: string;
132
+ /**
133
+ * The current state of the database
134
+ */
135
+ state: string;
133
136
 
134
- /**
135
- * Time at which the database was last updated
136
- */
137
- updatedAt: string;
137
+ /**
138
+ * The default branch name
139
+ */
140
+ defaultBranch: string;
138
141
 
139
- /**
140
- * HTML URL to access the database
141
- */
142
- htmlUrl: string;
143
- }
142
+ /**
143
+ * The plan type
144
+ */
145
+ plan: string;
146
+
147
+ /**
148
+ * Time at which the database was created
149
+ */
150
+ createdAt: string;
151
+
152
+ /**
153
+ * Time at which the database was last updated
154
+ */
155
+ updatedAt: string;
156
+
157
+ /**
158
+ * HTML URL to access the database
159
+ */
160
+ htmlUrl: string;
161
+ };
144
162
 
145
163
  /**
146
164
  * Create, manage and delete PlanetScale databases
@@ -183,233 +201,235 @@ export const Database = Resource(
183
201
  id: string,
184
202
  props: DatabaseProps,
185
203
  ): Promise<Database> {
186
- const adopt = props.adopt ?? this.scope.adopt;
187
- const apiKey =
188
- props.apiKey?.unencrypted || process.env.PLANETSCALE_API_TOKEN;
189
- if (!apiKey) {
190
- throw new Error("PLANETSCALE_API_TOKEN environment variable is required");
191
- }
192
-
193
- const api = new PlanetScaleApi({ apiKey });
204
+ const api = new PlanetScaleClient(props);
194
205
 
195
206
  const databaseName =
196
207
  props.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
208
+ const clusterSize = sanitizeClusterSize({
209
+ size: props.clusterSize,
210
+ kind: props.kind,
211
+ arch: props.arch,
212
+ region: props.region?.slug,
213
+ });
197
214
 
198
215
  if (this.phase === "update" && this.output.name !== databaseName) {
199
- await api.patch(
200
- `/organizations/${props.organizationId}/databases/${this.output.name}`,
201
- { new_name: databaseName },
202
- );
216
+ await api.organizations.databases.patch({
217
+ path: {
218
+ organization: props.organizationId,
219
+ name: this.output.name,
220
+ },
221
+ body: { new_name: databaseName },
222
+ });
203
223
  }
204
224
 
205
225
  if (this.phase === "delete") {
206
- try {
207
- if (this.output?.name) {
208
- const response = await api.delete(
209
- `/organizations/${props.organizationId}/databases/${this.output.name}`,
210
- );
211
-
212
- if (!response.ok && response.status !== 404) {
213
- throw new Error(
214
- `Failed to delete database: ${response.statusText} ${await response.text()}`,
215
- );
216
- }
226
+ if (this.output?.name) {
227
+ const response = await api.organizations.databases.delete({
228
+ path: {
229
+ organization: props.organizationId,
230
+ name: this.output.name,
231
+ },
232
+ result: "full",
233
+ });
234
+
235
+ if (response.error && response.error.status !== 404) {
236
+ throw new Error(`Failed to delete database "${this.output.name}"`, {
237
+ cause: response.error,
238
+ });
217
239
  }
218
- } catch (error) {
219
- console.error("Error deleting database:", error);
220
- throw error;
221
240
  }
222
241
  return this.destroy();
223
242
  }
224
243
 
225
- try {
226
- // Check if database exists
227
- const getResponse = await api.get(
228
- `/organizations/${props.organizationId}/databases/${databaseName}`,
229
- );
230
- const getData = await getResponse.json<any>();
231
- if (this.phase === "update" || (adopt && getResponse.ok)) {
232
- if (!getResponse.ok) {
233
- throw new Error(`Database ${databaseName} not found`);
234
- }
235
- // Update database settings
236
- // If updating to a non-'main' default branch, create it first
237
- if (props.defaultBranch && props.defaultBranch !== "main") {
238
- const branchResponse = await api.get(
239
- `/organizations/${props.organizationId}/databases/${databaseName}/branches/${props.defaultBranch}`,
240
- );
241
- if (!getData.ready) {
242
- await waitForDatabaseReady(api, props.organizationId, databaseName);
243
- }
244
- if (!branchResponse.ok && branchResponse.status === 404) {
245
- // Create the branch
246
- const createBranchResponse = await api.post(
247
- `/organizations/${props.organizationId}/databases/${databaseName}/branches`,
248
- {
249
- name: props.defaultBranch,
250
- parent_branch: "main",
251
- },
252
- );
253
-
254
- if (!createBranchResponse.ok) {
255
- throw new Error(
256
- `Failed to create default branch: ${createBranchResponse.statusText} ${await createBranchResponse.text()}`,
257
- );
258
- }
259
- }
260
- }
261
-
262
- const updateResponse = await api.patch(
263
- `/organizations/${props.organizationId}/databases/${databaseName}`,
264
- {
265
- automatic_migrations: props.automaticMigrations,
266
- migration_framework: props.migrationFramework,
267
- migration_table_name: props.migrationTableName,
268
- require_approval_for_deploy: props.requireApprovalForDeploy,
269
- restrict_branch_region: props.restrictBranchRegion,
270
- allow_data_branching: props.allowDataBranching,
271
- insights_raw_queries: props.insightsRawQueries,
272
- production_branch_web_console: props.productionBranchWebConsole,
273
- default_branch: props.defaultBranch,
274
- },
275
- );
276
-
277
- if (!updateResponse.ok) {
278
- throw new Error(
279
- `Failed to update database: ${updateResponse.statusText} ${await updateResponse.text()}`,
280
- );
281
- }
282
-
283
- await fixClusterSize(
284
- api,
285
- props.organizationId,
286
- databaseName,
287
- props.defaultBranch || "main",
288
- props.clusterSize,
289
- getData.ready,
290
- );
291
-
292
- const data = await updateResponse.json<any>();
293
- return this({
294
- ...props,
295
- id: data.id,
296
- name: databaseName,
297
- state: data.state,
298
- defaultBranch: data.default_branch,
299
- plan: data.plan,
300
- createdAt: data.created_at,
301
- updatedAt: data.updated_at,
302
- htmlUrl: data.html_url,
244
+ // Check if database exists
245
+ const getResponse = await api.organizations.databases.get({
246
+ path: {
247
+ organization: props.organizationId,
248
+ name: databaseName,
249
+ },
250
+ result: "full",
251
+ });
252
+ if (this.phase === "update" || (props.adopt && getResponse.data)) {
253
+ if (!getResponse.data) {
254
+ throw new Error(`Database "${databaseName}" not found`, {
255
+ cause: getResponse.error,
303
256
  });
304
257
  }
305
-
306
- if (getResponse.ok) {
307
- throw new Error(`Database with name ${databaseName} already exists`);
258
+ // Update database settings
259
+ // If updating to a non-'main' default branch, create it first
260
+ if (props.defaultBranch && props.defaultBranch !== "main") {
261
+ const branchResponse = await api.organizations.databases.branches.get({
262
+ path: {
263
+ organization: props.organizationId,
264
+ database: databaseName,
265
+ name: props.defaultBranch,
266
+ },
267
+ result: "full",
268
+ });
269
+ if (!branchResponse.data) {
270
+ await waitForDatabaseReady(api, props.organizationId, databaseName);
271
+ }
272
+ if (branchResponse.error && branchResponse.error.status === 404) {
273
+ // Create the branch
274
+ await api.organizations.databases.branches.post({
275
+ path: {
276
+ organization: props.organizationId,
277
+ database: databaseName,
278
+ },
279
+ body: {
280
+ name: props.defaultBranch,
281
+ parent_branch: "main",
282
+ },
283
+ });
284
+ }
308
285
  }
309
286
 
310
- // Create new database
311
- const createResponse = await api.post(
312
- `/organizations/${props.organizationId}/databases`,
313
- {
287
+ const updateResponse = await api.organizations.databases.patch({
288
+ path: {
289
+ organization: props.organizationId,
314
290
  name: databaseName,
315
- region_slug: props.region?.slug,
316
- require_approval_for_deploy: props.requireApprovalForDeploy,
317
- allow_data_branching: props.allowDataBranching,
291
+ },
292
+ body: {
318
293
  automatic_migrations: props.automaticMigrations,
294
+ migration_framework: props.migrationFramework,
295
+ migration_table_name: props.migrationTableName,
296
+ require_approval_for_deploy: props.requireApprovalForDeploy,
319
297
  restrict_branch_region: props.restrictBranchRegion,
298
+ allow_data_branching: props.allowDataBranching,
320
299
  insights_raw_queries: props.insightsRawQueries,
321
300
  production_branch_web_console: props.productionBranchWebConsole,
322
- migration_framework: props.migrationFramework,
323
- migration_table_name: props.migrationTableName,
324
- cluster_size: props.clusterSize,
301
+ default_branch: props.defaultBranch,
325
302
  },
303
+ });
304
+
305
+ await ensureProductionBranchClusterSize(
306
+ api,
307
+ props.organizationId,
308
+ databaseName,
309
+ props.defaultBranch || "main",
310
+ updateResponse.kind,
311
+ clusterSize,
326
312
  );
327
313
 
328
- if (!createResponse.ok) {
329
- throw new Error(
330
- `Failed to create database: ${createResponse.statusText} ${await createResponse.text()}`,
331
- );
332
- }
314
+ return this({
315
+ ...props,
316
+ id: updateResponse.id,
317
+ name: databaseName,
318
+ state: updateResponse.state,
319
+ defaultBranch: updateResponse.default_branch,
320
+ plan: updateResponse.plan,
321
+ createdAt: updateResponse.created_at,
322
+ updatedAt: updateResponse.updated_at,
323
+ htmlUrl: updateResponse.html_url,
324
+ });
325
+ }
333
326
 
334
- const data = await createResponse.json<any>();
327
+ if (getResponse.data) {
328
+ throw new Error(`Database with name "${databaseName}" already exists`);
329
+ }
335
330
 
336
- // If a non-'main' default branch is specified, create it
337
- if (props.defaultBranch && props.defaultBranch !== "main") {
338
- await waitForDatabaseReady(api, props.organizationId, databaseName);
331
+ // Create new database
332
+ let data = await api.organizations.databases.post({
333
+ path: {
334
+ organization: props.organizationId,
335
+ },
336
+ body: {
337
+ name: databaseName,
338
+ region: props.region?.slug,
339
+ kind: props.kind,
340
+ cluster_size: clusterSize,
341
+ },
342
+ });
343
+
344
+ // These settings can't be set on creation, so we need to patch them after creation.
345
+ data = await api.organizations.databases.patch({
346
+ path: {
347
+ organization: props.organizationId,
348
+ name: databaseName,
349
+ },
350
+ body: {
351
+ require_approval_for_deploy: props.requireApprovalForDeploy,
352
+ allow_data_branching: props.allowDataBranching,
353
+ automatic_migrations: props.automaticMigrations,
354
+ restrict_branch_region: props.restrictBranchRegion,
355
+ insights_raw_queries: props.insightsRawQueries,
356
+ production_branch_web_console: props.productionBranchWebConsole,
357
+ migration_framework: props.migrationFramework,
358
+ migration_table_name: props.migrationTableName,
359
+ },
360
+ });
361
+
362
+ // If a non-'main' default branch is specified, create it
363
+ if (props.defaultBranch && props.defaultBranch !== "main") {
364
+ await waitForDatabaseReady(api, props.organizationId, databaseName);
365
+
366
+ // Check if branch exists
367
+ const branchResponse = await api.organizations.databases.branches.get({
368
+ path: {
369
+ organization: props.organizationId,
370
+ database: databaseName,
371
+ name: props.defaultBranch,
372
+ },
373
+ result: "full",
374
+ });
375
+
376
+ if (branchResponse.error && branchResponse.error.status === 404) {
377
+ // Create the branch
378
+ await api.organizations.databases.branches.post({
379
+ path: {
380
+ organization: props.organizationId,
381
+ database: databaseName,
382
+ },
383
+ body: {
384
+ name: props.defaultBranch,
385
+ parent_branch: "main",
386
+ },
387
+ });
339
388
 
340
- // Check if branch exists
341
- const branchResponse = await api.get(
342
- `/organizations/${props.organizationId}/databases/${databaseName}/branches/${props.defaultBranch}`,
389
+ await ensureProductionBranchClusterSize(
390
+ api,
391
+ props.organizationId,
392
+ databaseName,
393
+ props.defaultBranch || "main",
394
+ data.kind,
395
+ clusterSize,
343
396
  );
344
397
 
345
- if (!branchResponse.ok && branchResponse.status === 404) {
346
- // Create the branch
347
- const createBranchResponse = await api.post(
348
- `/organizations/${props.organizationId}/databases/${databaseName}/branches`,
349
- {
350
- name: props.defaultBranch,
351
- parent_branch: "main",
352
- },
353
- );
354
-
355
- if (!createBranchResponse.ok) {
356
- throw new Error(
357
- `Failed to create default branch: ${createBranchResponse.statusText} ${await createBranchResponse.text()}`,
358
- );
359
- }
360
-
361
- await fixClusterSize(
362
- api,
363
- props.organizationId,
364
- databaseName,
365
- props.defaultBranch || "main",
366
- props.clusterSize,
367
- false,
368
- );
369
-
370
- // Update database to use new branch as default
371
- const updateResponse = await api.patch(
372
- `/organizations/${props.organizationId}/databases/${databaseName}`,
373
- {
374
- default_branch: props.defaultBranch,
375
- },
376
- );
377
-
378
- if (!updateResponse.ok) {
379
- throw new Error(
380
- `Failed to set default branch: ${updateResponse.statusText} ${await updateResponse.text()}`,
381
- );
382
- }
383
-
384
- const updatedData = await updateResponse.json<any>();
385
- return this({
386
- ...props,
387
- id: data.id,
398
+ // Update database to use new branch as default
399
+ const updatedData = await api.organizations.databases.patch({
400
+ path: {
401
+ organization: props.organizationId,
388
402
  name: databaseName,
389
- state: updatedData.state,
390
- defaultBranch: updatedData.default_branch,
391
- plan: updatedData.plan,
392
- createdAt: updatedData.created_at,
393
- updatedAt: updatedData.updated_at,
394
- htmlUrl: updatedData.html_url,
395
- });
396
- }
397
- }
403
+ },
404
+ body: {
405
+ default_branch: props.defaultBranch,
406
+ },
407
+ });
398
408
 
399
- return this({
400
- ...props,
401
- id: data.id,
402
- name: databaseName,
403
- state: data.state,
404
- defaultBranch: data.default_branch || "main",
405
- plan: data.plan,
406
- createdAt: data.created_at,
407
- updatedAt: data.updated_at,
408
- htmlUrl: data.html_url,
409
- });
410
- } catch (error) {
411
- console.error("Error managing database:", error);
412
- throw error;
409
+ return this({
410
+ ...props,
411
+ id: data.id,
412
+ name: databaseName,
413
+ state: updatedData.state,
414
+ defaultBranch: updatedData.default_branch,
415
+ plan: updatedData.plan,
416
+ createdAt: updatedData.created_at,
417
+ updatedAt: updatedData.updated_at,
418
+ htmlUrl: updatedData.html_url,
419
+ });
420
+ }
413
421
  }
422
+
423
+ return this({
424
+ ...props,
425
+ id: data.id,
426
+ name: databaseName,
427
+ state: data.state,
428
+ defaultBranch: data.default_branch || "main",
429
+ plan: data.plan,
430
+ createdAt: data.created_at,
431
+ updatedAt: data.updated_at,
432
+ htmlUrl: data.html_url,
433
+ });
414
434
  },
415
435
  );
@@ -1,5 +1,6 @@
1
- export * from "./api.ts";
1
+ export * from "./api/client.gen.ts";
2
2
  export * from "./branch.ts";
3
3
  export * from "./database.ts";
4
4
  export * from "./password.ts";
5
+ export * from "./role.ts";
5
6
  export * from "./utils.ts";