@alchemy.run/planetscale 2.0.0-beta.85 → 2.0.0-beta.86

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 (78) hide show
  1. package/lib/AuthProvider.d.ts.map +1 -1
  2. package/lib/AuthProvider.js.map +1 -1
  3. package/lib/Branch.d.ts +6 -1
  4. package/lib/Branch.d.ts.map +1 -1
  5. package/lib/Branch.js +21 -0
  6. package/lib/Branch.js.map +1 -1
  7. package/lib/Contributions.d.ts.map +1 -1
  8. package/lib/Contributions.js.map +1 -1
  9. package/lib/Credentials.d.ts.map +1 -1
  10. package/lib/Credentials.js.map +1 -1
  11. package/lib/Database.d.ts +7 -0
  12. package/lib/Database.d.ts.map +1 -1
  13. package/lib/Database.js.map +1 -1
  14. package/lib/MySQL/MySQLBranch.d.ts +26 -2
  15. package/lib/MySQL/MySQLBranch.d.ts.map +1 -1
  16. package/lib/MySQL/MySQLBranch.js +15 -1
  17. package/lib/MySQL/MySQLBranch.js.map +1 -1
  18. package/lib/MySQL/MySQLClusterSize.d.ts +1 -1
  19. package/lib/MySQL/MySQLClusterSize.d.ts.map +1 -1
  20. package/lib/MySQL/MySQLClusterSize.js.map +1 -1
  21. package/lib/MySQL/MySQLDatabase.d.ts +28 -2
  22. package/lib/MySQL/MySQLDatabase.d.ts.map +1 -1
  23. package/lib/MySQL/MySQLDatabase.js +71 -50
  24. package/lib/MySQL/MySQLDatabase.js.map +1 -1
  25. package/lib/MySQL/MySQLMigrations.d.ts.map +1 -1
  26. package/lib/MySQL/MySQLMigrations.js.map +1 -1
  27. package/lib/MySQL/MySQLOrigin.d.ts.map +1 -1
  28. package/lib/MySQL/MySQLOrigin.js.map +1 -1
  29. package/lib/MySQL/MySQLPassword.d.ts.map +1 -1
  30. package/lib/MySQL/MySQLPassword.js.map +1 -1
  31. package/lib/MySQL/index.d.ts.map +1 -1
  32. package/lib/MySQL/index.js.map +1 -1
  33. package/lib/OAuthClient.d.ts.map +1 -1
  34. package/lib/OAuthClient.js.map +1 -1
  35. package/lib/Postgres/PostgresBranch.d.ts +26 -2
  36. package/lib/Postgres/PostgresBranch.d.ts.map +1 -1
  37. package/lib/Postgres/PostgresBranch.js +15 -1
  38. package/lib/Postgres/PostgresBranch.js.map +1 -1
  39. package/lib/Postgres/PostgresClusterSize.d.ts.map +1 -1
  40. package/lib/Postgres/PostgresClusterSize.js.map +1 -1
  41. package/lib/Postgres/PostgresDatabase.d.ts +28 -2
  42. package/lib/Postgres/PostgresDatabase.d.ts.map +1 -1
  43. package/lib/Postgres/PostgresDatabase.js +75 -54
  44. package/lib/Postgres/PostgresDatabase.js.map +1 -1
  45. package/lib/Postgres/PostgresDefaultRole.d.ts.map +1 -1
  46. package/lib/Postgres/PostgresDefaultRole.js.map +1 -1
  47. package/lib/Postgres/PostgresMigrations.d.ts.map +1 -1
  48. package/lib/Postgres/PostgresMigrations.js.map +1 -1
  49. package/lib/Postgres/PostgresOrigin.d.ts.map +1 -1
  50. package/lib/Postgres/PostgresOrigin.js.map +1 -1
  51. package/lib/Postgres/PostgresRole.d.ts.map +1 -1
  52. package/lib/Postgres/PostgresRole.js.map +1 -1
  53. package/lib/Postgres/index.d.ts.map +1 -1
  54. package/lib/Postgres/index.js.map +1 -1
  55. package/lib/Providers.d.ts.map +1 -1
  56. package/lib/Providers.js +3 -1
  57. package/lib/Providers.js.map +1 -1
  58. package/lib/ServiceToken.d.ts +142 -0
  59. package/lib/ServiceToken.d.ts.map +1 -0
  60. package/lib/ServiceToken.js +268 -0
  61. package/lib/ServiceToken.js.map +1 -0
  62. package/lib/Util.d.ts +3 -3
  63. package/lib/Util.d.ts.map +1 -1
  64. package/lib/Util.js.map +1 -1
  65. package/lib/index.d.ts +1 -0
  66. package/lib/index.d.ts.map +1 -1
  67. package/lib/index.js +1 -0
  68. package/lib/index.js.map +1 -1
  69. package/package.json +9 -9
  70. package/src/Branch.ts +34 -1
  71. package/src/Database.ts +7 -0
  72. package/src/MySQL/MySQLBranch.ts +28 -2
  73. package/src/MySQL/MySQLDatabase.ts +102 -62
  74. package/src/Postgres/PostgresBranch.ts +28 -2
  75. package/src/Postgres/PostgresDatabase.ts +102 -61
  76. package/src/Providers.ts +3 -0
  77. package/src/ServiceToken.ts +431 -0
  78. package/src/index.ts +1 -0
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAmD,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClG,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAmD,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClG,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy.run/planetscale",
3
- "version": "2.0.0-beta.85",
3
+ "version": "2.0.0-beta.86",
4
4
  "description": "PlanetScale MySQL and Postgres databases for Alchemy.",
5
5
  "keywords": [
6
6
  "alchemy",
@@ -58,22 +58,22 @@
58
58
  "access": "public"
59
59
  },
60
60
  "dependencies": {
61
- "@alchemy.run/sql": "2.0.0-beta.85",
62
- "@distilled.cloud/core": "1.0.0-rc.18",
63
- "@distilled.cloud/planetscale": "1.0.0-rc.18"
61
+ "@alchemy.run/sql": "2.0.0-beta.86",
62
+ "@distilled.cloud/core": "1.0.0-rc.19",
63
+ "@distilled.cloud/planetscale": "1.0.0-rc.19"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@types/bun": "1.4.3",
67
67
  "@types/pg": "^8.20.0",
68
- "alchemy": "2.0.0-beta.85",
69
- "effect": "^4.1.0",
68
+ "alchemy": "2.0.0-beta.86",
69
+ "effect": "^4.1.4",
70
70
  "mysql2": "^3.24.2",
71
71
  "pg": "^8.22.0",
72
- "typescript": "^7.0.2"
72
+ "typescript": "^7.1.0-dev.20261105.1"
73
73
  },
74
74
  "peerDependencies": {
75
- "alchemy": "2.0.0-beta.85",
76
- "effect": "^4.1.0",
75
+ "alchemy": "2.0.0-beta.86",
76
+ "effect": "^4.1.4",
77
77
  "mysql2": "^3.24.2",
78
78
  "pg": "^8.22.0"
79
79
  },
package/src/Branch.ts CHANGED
@@ -73,7 +73,12 @@ export interface BaseBranchProps {
73
73
  * Adding a file is an in-place update. Editing or removing an
74
74
  * already-applied file replaces a non-production branch (re-forked from
75
75
  * its parent) and fails on a current or desired production branch — add
76
- * a forward migration instead.
76
+ * a forward migration instead. Renaming an applied file without changing
77
+ * its contents keeps it applied and replaces nothing.
78
+ *
79
+ * History is linear: a new file must sort after every applied one, or
80
+ * the deploy fails with `NonLinearMigrationHistoryError`. See
81
+ * [Migrations](https://alchemy.run/sql/effect-sql/migrations#change-migration-history-safely).
77
82
  */
78
83
  migrations?: MigrationsInput;
79
84
 
@@ -361,6 +366,34 @@ export const makeBranchProvider = <R extends ResourceLike>(opts: {
361
366
  return stables ? ({ action: "noop", stables } as const) : undefined;
362
367
  }),
363
368
 
369
+ lookup: Effect.fn(function* ({ database, name }: any) {
370
+ const { organization } = yield* yield* Credentials;
371
+ return yield* planetscale.getBranch({ organization, database, branch: name }).pipe(
372
+ Effect.map(
373
+ (data) =>
374
+ ({
375
+ name: data.name,
376
+ organization,
377
+ database,
378
+ parentBranch: data.parent_branch ?? "main",
379
+ production: data.production,
380
+ createdAt: data.created_at,
381
+ updatedAt: data.updated_at,
382
+ htmlUrl: data.html_url,
383
+ region: { slug: data.region.slug },
384
+ migrationsDir: undefined,
385
+ migrationsTable: undefined,
386
+ migrationsHashes: {},
387
+ importHashes: {},
388
+ desiredReplicas: undefined,
389
+ hasReplicas: data.has_replicas,
390
+ hasReadOnlyReplicas: data.has_read_only_replicas,
391
+ }) satisfies BaseBranchAttributes,
392
+ ),
393
+ Effect.catchTag("NotFound", () => Effect.undefined),
394
+ );
395
+ }),
396
+
364
397
  read: Effect.fn(function* ({ id, olds, output }: any) {
365
398
  // If we have neither a cached output nor a usable `olds.database`
366
399
  // there's no way to identify which branch to refresh — most often
package/src/Database.ts CHANGED
@@ -84,6 +84,13 @@ export interface BaseDatabaseProps {
84
84
  * one-way conversion on first deploy: the old tool's applied history is
85
85
  * copied into Alchemy's table and the old table is left frozen. No
86
86
  * baselining required.
87
+ *
88
+ * History is forward-only and linear. A new file must sort after every
89
+ * applied one, or the deploy fails with `NonLinearMigrationHistoryError`;
90
+ * an edited or deleted applied file fails with
91
+ * `RewrittenMigrationHistoryError`. Renaming an applied file without
92
+ * changing its contents keeps it applied. See
93
+ * [Migrations](https://alchemy.run/sql/effect-sql/migrations#change-migration-history-safely).
87
94
  */
88
95
  migrations?: MigrationsInput;
89
96
 
@@ -91,10 +91,36 @@ export type MySQLBranch = Resource<
91
91
  MySQLBranchProps,
92
92
  MySQLBranchAttributes,
93
93
  never,
94
- Providers
94
+ Providers,
95
+ MySQLBranchLookup
95
96
  >;
96
97
 
97
- /** @resource */
98
+ /**
99
+ * Props for {@link MySQLBranch.lookup}: find a MySQL branch this
100
+ * stack doesn't manage by its database and name.
101
+ */
102
+ export interface MySQLBranchLookup {
103
+ /** Database name. */
104
+ database: string;
105
+ /** Branch name. */
106
+ name: string;
107
+ }
108
+
109
+ /**
110
+ * A branch of a PlanetScale MySQL database.
111
+ *
112
+ * ### Looking up an existing MySQL branch
113
+ * `MySQLBranch.lookup` references a MySQL branch Alchemy doesn't manage (created in
114
+ * the PlanetScale dashboard or by another stack). It is read during
115
+ * plan/deploy, never created, updated or deleted.
116
+ *
117
+ * **Example:** Reference an existing branch
118
+ * ```typescript
119
+ * const main = Planetscale.MySQLBranch.lookup({ database: "app", name: "main" });
120
+ * ```
121
+ *
122
+ * @resource
123
+ */
98
124
  export const MySQLBranch = Resource<MySQLBranch>("Planetscale.MySQLBranch");
99
125
 
100
126
  export const MySQLBranchProvider = () =>
@@ -180,12 +180,109 @@ export type MySQLDatabase = Resource<
180
180
  MySQLDatabaseProps,
181
181
  MySQLDatabaseAttributes,
182
182
  never,
183
- Providers
183
+ Providers,
184
+ MySQLDatabaseLookup
184
185
  >;
185
186
 
186
- /** @resource */
187
+ /**
188
+ * Props for {@link MySQLDatabase.lookup}: find a MySQL database this
189
+ * stack doesn't manage by its name, in the credentialed organization.
190
+ */
191
+ export interface MySQLDatabaseLookup {
192
+ /** Database name. */
193
+ name: string;
194
+ }
195
+
196
+ /**
197
+ * A PlanetScale MySQL (Vitess) database.
198
+ *
199
+ * ### Looking up an existing MySQL database
200
+ * `MySQLDatabase.lookup` references a MySQL database Alchemy doesn't manage (created in
201
+ * the PlanetScale dashboard or by another stack). It is read during
202
+ * plan/deploy, never created, updated or deleted.
203
+ *
204
+ * **Example:** Branch an existing database
205
+ * ```typescript
206
+ * const db = Planetscale.MySQLDatabase.lookup({ name: "app" });
207
+ * const preview = yield* Planetscale.MySQLBranch("Preview", {
208
+ * database: db,
209
+ * isProduction: false,
210
+ * });
211
+ * ```
212
+ *
213
+ * @resource
214
+ */
187
215
  export const MySQLDatabase = Resource<MySQLDatabase>("Planetscale.MySQLDatabase");
188
216
 
217
+ /** Observe a database by name; `read` and `lookup` share it. */
218
+ const readMySQLDatabase = Effect.fn(function* ({
219
+ id,
220
+ output,
221
+ olds,
222
+ }: {
223
+ id: string;
224
+ output?: MySQLDatabase["Attributes"];
225
+ olds?: Partial<MySQLDatabaseProps>;
226
+ }) {
227
+ const { organization } = yield* yield* Credentials;
228
+ const databaseName = output?.name ?? (yield* createDatabaseName(id, olds?.name));
229
+ return yield* planetscale
230
+ .getDatabase({
231
+ organization,
232
+ database: databaseName,
233
+ })
234
+ .pipe(
235
+ Effect.flatMap(
236
+ Effect.fn(function* (data) {
237
+ if (data.kind !== "mysql") {
238
+ return yield* new PlanetscaleConflict({
239
+ message:
240
+ `Planetscale database "${data.name}" has kind "${data.kind}" but this resource ` +
241
+ `is a MySQLDatabase. Use Planetscale.${data.kind === "postgresql" ? "PostgresDatabase" : data.kind}() instead, ` +
242
+ `or delete the existing database and retry.`,
243
+ });
244
+ }
245
+ // Observe the default keyspace's live replica configuration
246
+ // so adopted databases diff against reality.
247
+ const replicas = yield* observeDefaultKeyspaceReplicas(
248
+ organization,
249
+ data.name,
250
+ data.default_branch ?? "main",
251
+ );
252
+ return {
253
+ id: data.id,
254
+ name: data.name,
255
+ organization,
256
+ state: data.state,
257
+ defaultBranch: data.default_branch ?? "main",
258
+ replicas,
259
+ plan: data.plan ?? "hobby",
260
+ createdAt: data.created_at,
261
+ updatedAt: data.updated_at,
262
+ htmlUrl: data.html_url,
263
+ region: { slug: data.region.slug },
264
+ migrationsDir: output?.migrationsDir ?? (olds && migrationsInputOf(olds))?.dir,
265
+ migrationsTable: output?.migrationsTable ?? (olds && migrationsInputOf(olds))?.table,
266
+ migrationsHashes: output?.migrationsHashes ?? {},
267
+ importHashes: output?.importHashes ?? {},
268
+ clusterSize: output?.clusterSize ?? "",
269
+ requireApprovalForDeploy: data.require_approval_for_deploy ?? false,
270
+ restrictBranchRegion: data.restrict_branch_region ?? false,
271
+ insightsRawQueries: data.insights_raw_queries ?? false,
272
+ productionBranchWebConsole: data.production_branch_web_console ?? false,
273
+ deletionProtection: data.deletion_protected ?? false,
274
+ automaticMigrations: data.automatic_migrations ?? false,
275
+ migrationFramework: data.migration_framework ?? undefined,
276
+ migrationTableName: data.migration_table_name ?? undefined,
277
+ allowDataBranching: data.allow_data_branching ?? false,
278
+ allowForeignKeyConstraints: data.foreign_keys_enabled ?? false,
279
+ };
280
+ }),
281
+ ),
282
+ Effect.catchTag("NotFound", () => Effect.undefined),
283
+ );
284
+ });
285
+
189
286
  export const MySQLDatabaseProvider = () =>
190
287
  Provider.succeed(MySQLDatabase, {
191
288
  stables: ["id", "organization", "region"],
@@ -246,66 +343,9 @@ export const MySQLDatabaseProvider = () =>
246
343
  return stables ? ({ action: "noop", stables } as const) : undefined;
247
344
  }),
248
345
 
249
- read: Effect.fn(function* ({ id, output, olds }) {
250
- const { organization } = yield* yield* Credentials;
251
- const databaseName = output?.name ?? (yield* createDatabaseName(id, olds?.name));
252
- return yield* planetscale
253
- .getDatabase({
254
- organization,
255
- database: databaseName,
256
- })
257
- .pipe(
258
- Effect.flatMap(
259
- Effect.fn(function* (data) {
260
- if (data.kind !== "mysql") {
261
- return yield* new PlanetscaleConflict({
262
- message:
263
- `Planetscale database "${data.name}" has kind "${data.kind}" but this resource ` +
264
- `is a MySQLDatabase. Use Planetscale.${data.kind === "postgresql" ? "PostgresDatabase" : data.kind}() instead, ` +
265
- `or delete the existing database and retry.`,
266
- });
267
- }
268
- // Observe the default keyspace's live replica configuration
269
- // so adopted databases diff against reality.
270
- const replicas = yield* observeDefaultKeyspaceReplicas(
271
- organization,
272
- data.name,
273
- data.default_branch ?? "main",
274
- );
275
- return {
276
- id: data.id,
277
- name: data.name,
278
- organization,
279
- state: data.state,
280
- defaultBranch: data.default_branch ?? "main",
281
- replicas,
282
- plan: data.plan ?? "hobby",
283
- createdAt: data.created_at,
284
- updatedAt: data.updated_at,
285
- htmlUrl: data.html_url,
286
- region: { slug: data.region.slug },
287
- migrationsDir: output?.migrationsDir ?? (olds && migrationsInputOf(olds))?.dir,
288
- migrationsTable:
289
- output?.migrationsTable ?? (olds && migrationsInputOf(olds))?.table,
290
- migrationsHashes: output?.migrationsHashes ?? {},
291
- importHashes: output?.importHashes ?? {},
292
- clusterSize: output?.clusterSize ?? "",
293
- requireApprovalForDeploy: data.require_approval_for_deploy ?? false,
294
- restrictBranchRegion: data.restrict_branch_region ?? false,
295
- insightsRawQueries: data.insights_raw_queries ?? false,
296
- productionBranchWebConsole: data.production_branch_web_console ?? false,
297
- deletionProtection: data.deletion_protected ?? false,
298
- automaticMigrations: data.automatic_migrations ?? false,
299
- migrationFramework: data.migration_framework ?? undefined,
300
- migrationTableName: data.migration_table_name ?? undefined,
301
- allowDataBranching: data.allow_data_branching ?? false,
302
- allowForeignKeyConstraints: data.foreign_keys_enabled ?? false,
303
- };
304
- }),
305
- ),
306
- Effect.catchTag("NotFound", () => Effect.undefined),
307
- );
308
- }),
346
+ lookup: ({ name }) => readMySQLDatabase({ id: name, olds: { name } }),
347
+
348
+ read: readMySQLDatabase,
309
349
 
310
350
  reconcile: Effect.fn(function* ({ id, news, output, session }) {
311
351
  const { organization } = yield* yield* Credentials;
@@ -79,10 +79,36 @@ export type PostgresBranch = Resource<
79
79
  PostgresBranchProps,
80
80
  PostgresBranchAttributes,
81
81
  never,
82
- Providers
82
+ Providers,
83
+ PostgresBranchLookup
83
84
  >;
84
85
 
85
- /** @resource */
86
+ /**
87
+ * Props for {@link PostgresBranch.lookup}: find a Postgres branch this
88
+ * stack doesn't manage by its database and name.
89
+ */
90
+ export interface PostgresBranchLookup {
91
+ /** Database name. */
92
+ database: string;
93
+ /** Branch name. */
94
+ name: string;
95
+ }
96
+
97
+ /**
98
+ * A branch of a PlanetScale Postgres database.
99
+ *
100
+ * ### Looking up an existing Postgres branch
101
+ * `PostgresBranch.lookup` references a Postgres branch Alchemy doesn't manage (created in
102
+ * the PlanetScale dashboard or by another stack). It is read during
103
+ * plan/deploy, never created, updated or deleted.
104
+ *
105
+ * **Example:** Reference an existing branch
106
+ * ```typescript
107
+ * const main = Planetscale.PostgresBranch.lookup({ database: "app", name: "main" });
108
+ * ```
109
+ *
110
+ * @resource
111
+ */
86
112
  export const PostgresBranch = Resource<PostgresBranch>("Planetscale.PostgresBranch");
87
113
 
88
114
  export const PostgresBranchProvider = () =>
@@ -124,12 +124,110 @@ export type PostgresDatabase = Resource<
124
124
  PostgresDatabaseProps,
125
125
  PostgresDatabaseAttributes,
126
126
  never,
127
- Providers
127
+ Providers,
128
+ PostgresDatabaseLookup
128
129
  >;
129
130
 
130
- /** @resource */
131
+ /**
132
+ * Props for {@link PostgresDatabase.lookup}: find a Postgres database this
133
+ * stack doesn't manage by its name, in the credentialed organization.
134
+ */
135
+ export interface PostgresDatabaseLookup {
136
+ /** Database name. */
137
+ name: string;
138
+ }
139
+
140
+ /**
141
+ * A PlanetScale Postgres database.
142
+ *
143
+ * ### Looking up an existing Postgres database
144
+ * `PostgresDatabase.lookup` references a Postgres database Alchemy doesn't manage (created in
145
+ * the PlanetScale dashboard or by another stack). It is read during
146
+ * plan/deploy, never created, updated or deleted.
147
+ *
148
+ * **Example:** Branch an existing database
149
+ * ```typescript
150
+ * const db = Planetscale.PostgresDatabase.lookup({ name: "app" });
151
+ * const preview = yield* Planetscale.PostgresBranch("Preview", {
152
+ * database: db,
153
+ * isProduction: false,
154
+ * });
155
+ * ```
156
+ *
157
+ * @resource
158
+ */
131
159
  export const PostgresDatabase = Resource<PostgresDatabase>("Planetscale.PostgresDatabase");
132
160
 
161
+ /** Observe a database by name; `read` and `lookup` share it. */
162
+ const readPostgresDatabase = Effect.fn(function* ({
163
+ id,
164
+ output,
165
+ olds,
166
+ }: {
167
+ id: string;
168
+ output?: PostgresDatabase["Attributes"];
169
+ olds?: Partial<PostgresDatabaseProps>;
170
+ }) {
171
+ const { organization } = yield* yield* Credentials;
172
+ const databaseName = output?.name ?? (yield* createDatabaseName(id, olds?.name));
173
+
174
+ const data = yield* planetscale
175
+ .getDatabase({
176
+ organization,
177
+ database: databaseName,
178
+ })
179
+ .pipe(Effect.catchTag("NotFound", () => Effect.undefined));
180
+
181
+ if (!data) return undefined;
182
+
183
+ if (data.kind !== "postgresql") {
184
+ return yield* new PlanetscaleConflict({
185
+ message:
186
+ `Planetscale database "${data.name}" has kind "${data.kind}" but this resource ` +
187
+ `is a PostgresDatabase. Use Planetscale.${data.kind === "mysql" ? "MySQLDatabase" : data.kind}() instead, ` +
188
+ `or delete the existing database and retry.`,
189
+ });
190
+ }
191
+
192
+ const defaultBranch = data.default_branch ?? "main";
193
+
194
+ // Observe `arch` and `clusterSize` from the default branch rather
195
+ // than echoing input.
196
+ const branch = yield* planetscale
197
+ .getBranch({
198
+ organization,
199
+ database: data.name,
200
+ branch: defaultBranch,
201
+ })
202
+ .pipe(Effect.catchTag("NotFound", () => Effect.undefined));
203
+
204
+ const arch = toPostgresClusterArch(branch!.cluster_architecture);
205
+ const clusterSize = branch!.cluster_name;
206
+
207
+ return {
208
+ id: data.id,
209
+ name: data.name,
210
+ organization,
211
+ state: data.state,
212
+ defaultBranch,
213
+ plan: data.plan ?? "hobby",
214
+ createdAt: data.created_at,
215
+ updatedAt: data.updated_at,
216
+ htmlUrl: data.html_url,
217
+ region: { slug: data.region.slug },
218
+ migrationsDir: output?.migrationsDir ?? (olds && migrationsInputOf(olds))?.dir,
219
+ migrationsTable: output?.migrationsTable ?? (olds && migrationsInputOf(olds))?.table,
220
+ migrationsHashes: output?.migrationsHashes ?? {},
221
+ importHashes: output?.importHashes ?? {},
222
+ clusterSize,
223
+ arch,
224
+ requireApprovalForDeploy: data.require_approval_for_deploy ?? false,
225
+ restrictBranchRegion: data.restrict_branch_region ?? false,
226
+ productionBranchWebConsole: data.production_branch_web_console ?? false,
227
+ deletionProtection: data.deletion_protected ?? false,
228
+ };
229
+ });
230
+
133
231
  export const PostgresDatabaseProvider = () =>
134
232
  Provider.succeed(PostgresDatabase, {
135
233
  stables: ["id", "organization", "region"],
@@ -191,66 +289,9 @@ export const PostgresDatabaseProvider = () =>
191
289
  return stables ? ({ action: "noop", stables } as const) : undefined;
192
290
  }),
193
291
 
194
- read: Effect.fn(function* ({ id, output, olds }) {
195
- const { organization } = yield* yield* Credentials;
196
- const databaseName = output?.name ?? (yield* createDatabaseName(id, olds?.name));
197
-
198
- const data = yield* planetscale
199
- .getDatabase({
200
- organization,
201
- database: databaseName,
202
- })
203
- .pipe(Effect.catchTag("NotFound", () => Effect.undefined));
204
-
205
- if (!data) return undefined;
206
-
207
- if (data.kind !== "postgresql") {
208
- return yield* new PlanetscaleConflict({
209
- message:
210
- `Planetscale database "${data.name}" has kind "${data.kind}" but this resource ` +
211
- `is a PostgresDatabase. Use Planetscale.${data.kind === "mysql" ? "MySQLDatabase" : data.kind}() instead, ` +
212
- `or delete the existing database and retry.`,
213
- });
214
- }
215
-
216
- const defaultBranch = data.default_branch ?? "main";
292
+ lookup: ({ name }) => readPostgresDatabase({ id: name, olds: { name } }),
217
293
 
218
- // Observe `arch` and `clusterSize` from the default branch rather
219
- // than echoing input.
220
- const branch = yield* planetscale
221
- .getBranch({
222
- organization,
223
- database: data.name,
224
- branch: defaultBranch,
225
- })
226
- .pipe(Effect.catchTag("NotFound", () => Effect.undefined));
227
-
228
- const arch = toPostgresClusterArch(branch!.cluster_architecture);
229
- const clusterSize = branch!.cluster_name;
230
-
231
- return {
232
- id: data.id,
233
- name: data.name,
234
- organization,
235
- state: data.state,
236
- defaultBranch,
237
- plan: data.plan ?? "hobby",
238
- createdAt: data.created_at,
239
- updatedAt: data.updated_at,
240
- htmlUrl: data.html_url,
241
- region: { slug: data.region.slug },
242
- migrationsDir: output?.migrationsDir ?? (olds && migrationsInputOf(olds))?.dir,
243
- migrationsTable: output?.migrationsTable ?? (olds && migrationsInputOf(olds))?.table,
244
- migrationsHashes: output?.migrationsHashes ?? {},
245
- importHashes: output?.importHashes ?? {},
246
- clusterSize,
247
- arch,
248
- requireApprovalForDeploy: data.require_approval_for_deploy ?? false,
249
- restrictBranchRegion: data.restrict_branch_region ?? false,
250
- productionBranchWebConsole: data.production_branch_web_console ?? false,
251
- deletionProtection: data.deletion_protected ?? false,
252
- };
253
- }),
294
+ read: readPostgresDatabase,
254
295
 
255
296
  reconcile: Effect.fn(function* ({ id, news, output, session }) {
256
297
  const { organization } = yield* yield* Credentials;
package/src/Providers.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  PostgresDefaultRoleProvider,
16
16
  } from "./Postgres/PostgresDefaultRole.ts";
17
17
  import { PostgresRole, PostgresRoleProvider } from "./Postgres/PostgresRole.ts";
18
+ import { ServiceToken, ServiceTokenProvider } from "./ServiceToken.ts";
18
19
 
19
20
  /**
20
21
  * Service tag bundling all PlanetScale providers + auth + credentials. Use
@@ -45,6 +46,7 @@ export const providers = () =>
45
46
  MySQLPassword,
46
47
  PostgresRole,
47
48
  PostgresDefaultRole,
49
+ ServiceToken,
48
50
  ]),
49
51
  ).pipe(
50
52
  Layer.provide(
@@ -56,6 +58,7 @@ export const providers = () =>
56
58
  MySQLPasswordProvider(),
57
59
  PostgresRoleProvider(),
58
60
  PostgresDefaultRoleProvider(),
61
+ ServiceTokenProvider(),
59
62
  ),
60
63
  ),
61
64
  Layer.provideMerge(Credentials.fromAuthProvider()),