@alchemy.run/planetscale 2.0.0-beta.85 → 2.0.0-beta.87
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.
- package/lib/AuthProvider.d.ts.map +1 -1
- package/lib/AuthProvider.js.map +1 -1
- package/lib/Branch.d.ts +6 -1
- package/lib/Branch.d.ts.map +1 -1
- package/lib/Branch.js +21 -0
- package/lib/Branch.js.map +1 -1
- package/lib/Contributions.d.ts.map +1 -1
- package/lib/Contributions.js.map +1 -1
- package/lib/Credentials.d.ts.map +1 -1
- package/lib/Credentials.js.map +1 -1
- package/lib/Database.d.ts +7 -0
- package/lib/Database.d.ts.map +1 -1
- package/lib/Database.js.map +1 -1
- package/lib/MySQL/MySQLBranch.d.ts +26 -2
- package/lib/MySQL/MySQLBranch.d.ts.map +1 -1
- package/lib/MySQL/MySQLBranch.js +15 -1
- package/lib/MySQL/MySQLBranch.js.map +1 -1
- package/lib/MySQL/MySQLClusterSize.d.ts +1 -1
- package/lib/MySQL/MySQLClusterSize.d.ts.map +1 -1
- package/lib/MySQL/MySQLClusterSize.js.map +1 -1
- package/lib/MySQL/MySQLDatabase.d.ts +28 -2
- package/lib/MySQL/MySQLDatabase.d.ts.map +1 -1
- package/lib/MySQL/MySQLDatabase.js +71 -50
- package/lib/MySQL/MySQLDatabase.js.map +1 -1
- package/lib/MySQL/MySQLMigrations.d.ts.map +1 -1
- package/lib/MySQL/MySQLMigrations.js.map +1 -1
- package/lib/MySQL/MySQLOrigin.d.ts.map +1 -1
- package/lib/MySQL/MySQLOrigin.js.map +1 -1
- package/lib/MySQL/MySQLPassword.d.ts.map +1 -1
- package/lib/MySQL/MySQLPassword.js.map +1 -1
- package/lib/MySQL/index.d.ts.map +1 -1
- package/lib/MySQL/index.js.map +1 -1
- package/lib/OAuthClient.d.ts.map +1 -1
- package/lib/OAuthClient.js.map +1 -1
- package/lib/Postgres/PostgresBranch.d.ts +26 -2
- package/lib/Postgres/PostgresBranch.d.ts.map +1 -1
- package/lib/Postgres/PostgresBranch.js +15 -1
- package/lib/Postgres/PostgresBranch.js.map +1 -1
- package/lib/Postgres/PostgresClusterSize.d.ts.map +1 -1
- package/lib/Postgres/PostgresClusterSize.js.map +1 -1
- package/lib/Postgres/PostgresDatabase.d.ts +28 -2
- package/lib/Postgres/PostgresDatabase.d.ts.map +1 -1
- package/lib/Postgres/PostgresDatabase.js +75 -54
- package/lib/Postgres/PostgresDatabase.js.map +1 -1
- package/lib/Postgres/PostgresDefaultRole.d.ts.map +1 -1
- package/lib/Postgres/PostgresDefaultRole.js.map +1 -1
- package/lib/Postgres/PostgresMigrations.d.ts.map +1 -1
- package/lib/Postgres/PostgresMigrations.js.map +1 -1
- package/lib/Postgres/PostgresOrigin.d.ts.map +1 -1
- package/lib/Postgres/PostgresOrigin.js.map +1 -1
- package/lib/Postgres/PostgresRole.d.ts.map +1 -1
- package/lib/Postgres/PostgresRole.js.map +1 -1
- package/lib/Postgres/index.d.ts.map +1 -1
- package/lib/Postgres/index.js.map +1 -1
- package/lib/Providers.d.ts.map +1 -1
- package/lib/Providers.js +3 -1
- package/lib/Providers.js.map +1 -1
- package/lib/ServiceToken.d.ts +142 -0
- package/lib/ServiceToken.d.ts.map +1 -0
- package/lib/ServiceToken.js +268 -0
- package/lib/ServiceToken.js.map +1 -0
- package/lib/Util.d.ts +3 -3
- package/lib/Util.d.ts.map +1 -1
- package/lib/Util.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +9 -9
- package/src/Branch.ts +34 -1
- package/src/Database.ts +7 -0
- package/src/MySQL/MySQLBranch.ts +28 -2
- package/src/MySQL/MySQLDatabase.ts +102 -62
- package/src/Postgres/PostgresBranch.ts +28 -2
- package/src/Postgres/PostgresDatabase.ts +102 -61
- package/src/Providers.ts +3 -0
- package/src/ServiceToken.ts +431 -0
- package/src/index.ts +1 -0
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","
|
|
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.
|
|
3
|
+
"version": "2.0.0-beta.87",
|
|
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.
|
|
62
|
-
"@distilled.cloud/core": "1.0.0-rc.
|
|
63
|
-
"@distilled.cloud/planetscale": "1.0.0-rc.
|
|
61
|
+
"@alchemy.run/sql": "2.0.0-beta.87",
|
|
62
|
+
"@distilled.cloud/core": "1.0.0-rc.20",
|
|
63
|
+
"@distilled.cloud/planetscale": "1.0.0-rc.20"
|
|
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.
|
|
69
|
-
"effect": "^4.1.
|
|
68
|
+
"alchemy": "2.0.0-beta.87",
|
|
69
|
+
"effect": "^4.1.4",
|
|
70
70
|
"mysql2": "^3.24.2",
|
|
71
71
|
"pg": "^8.22.0",
|
|
72
|
-
"typescript": "^7.0.
|
|
72
|
+
"typescript": "^7.1.0-dev.20261105.1"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
|
-
"alchemy": "2.0.0-beta.
|
|
76
|
-
"effect": "^4.1.
|
|
75
|
+
"alchemy": "2.0.0-beta.87",
|
|
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
|
|
package/src/MySQL/MySQLBranch.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
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()),
|