@alchemy.run/planetscale 0.0.0 → 2.0.0-beta.84
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/LICENSE +201 -0
- package/README.md +83 -4
- package/lib/AuthProvider.d.ts +64 -0
- package/lib/AuthProvider.d.ts.map +1 -0
- package/lib/AuthProvider.js +384 -0
- package/lib/AuthProvider.js.map +1 -0
- package/lib/Branch.d.ts +128 -0
- package/lib/Branch.d.ts.map +1 -0
- package/lib/Branch.js +420 -0
- package/lib/Branch.js.map +1 -0
- package/lib/Contributions.d.ts +7 -0
- package/lib/Contributions.d.ts.map +1 -0
- package/lib/Contributions.js +6 -0
- package/lib/Contributions.js.map +1 -0
- package/lib/Credentials.d.ts +33 -0
- package/lib/Credentials.d.ts.map +1 -0
- package/lib/Credentials.js +65 -0
- package/lib/Credentials.js.map +1 -0
- package/lib/Database.d.ts +138 -0
- package/lib/Database.d.ts.map +1 -0
- package/lib/Database.js +1 -0
- package/lib/Database.js.map +1 -0
- package/lib/MySQL/MySQLBranch.d.ts +87 -0
- package/lib/MySQL/MySQLBranch.d.ts.map +1 -0
- package/lib/MySQL/MySQLBranch.js +15 -0
- package/lib/MySQL/MySQLBranch.js.map +1 -0
- package/lib/MySQL/MySQLClusterSize.d.ts +32 -0
- package/lib/MySQL/MySQLClusterSize.d.ts.map +1 -0
- package/lib/MySQL/MySQLClusterSize.js +111 -0
- package/lib/MySQL/MySQLClusterSize.js.map +1 -0
- package/lib/MySQL/MySQLDatabase.d.ts +141 -0
- package/lib/MySQL/MySQLDatabase.d.ts.map +1 -0
- package/lib/MySQL/MySQLDatabase.js +294 -0
- package/lib/MySQL/MySQLDatabase.js.map +1 -0
- package/lib/MySQL/MySQLMigrations.d.ts +24 -0
- package/lib/MySQL/MySQLMigrations.d.ts.map +1 -0
- package/lib/MySQL/MySQLMigrations.js +106 -0
- package/lib/MySQL/MySQLMigrations.js.map +1 -0
- package/lib/MySQL/MySQLOrigin.d.ts +15 -0
- package/lib/MySQL/MySQLOrigin.d.ts.map +1 -0
- package/lib/MySQL/MySQLOrigin.js +2 -0
- package/lib/MySQL/MySQLOrigin.js.map +1 -0
- package/lib/MySQL/MySQLPassword.d.ts +116 -0
- package/lib/MySQL/MySQLPassword.d.ts.map +1 -0
- package/lib/MySQL/MySQLPassword.js +212 -0
- package/lib/MySQL/MySQLPassword.js.map +1 -0
- package/lib/MySQL/index.d.ts +6 -0
- package/lib/MySQL/index.d.ts.map +1 -0
- package/lib/MySQL/index.js +6 -0
- package/lib/MySQL/index.js.map +1 -0
- package/lib/OAuthClient.d.ts +32 -0
- package/lib/OAuthClient.d.ts.map +1 -0
- package/lib/OAuthClient.js +52 -0
- package/lib/OAuthClient.js.map +1 -0
- package/lib/Postgres/PostgresBranch.d.ts +75 -0
- package/lib/Postgres/PostgresBranch.d.ts.map +1 -0
- package/lib/Postgres/PostgresBranch.js +15 -0
- package/lib/Postgres/PostgresBranch.js.map +1 -0
- package/lib/Postgres/PostgresClusterSize.d.ts +77 -0
- package/lib/Postgres/PostgresClusterSize.d.ts.map +1 -0
- package/lib/Postgres/PostgresClusterSize.js +89 -0
- package/lib/Postgres/PostgresClusterSize.js.map +1 -0
- package/lib/Postgres/PostgresDatabase.d.ts +95 -0
- package/lib/Postgres/PostgresDatabase.d.ts.map +1 -0
- package/lib/Postgres/PostgresDatabase.js +294 -0
- package/lib/Postgres/PostgresDatabase.js.map +1 -0
- package/lib/Postgres/PostgresDefaultRole.d.ts +94 -0
- package/lib/Postgres/PostgresDefaultRole.d.ts.map +1 -0
- package/lib/Postgres/PostgresDefaultRole.js +187 -0
- package/lib/Postgres/PostgresDefaultRole.js.map +1 -0
- package/lib/Postgres/PostgresMigrations.d.ts +24 -0
- package/lib/Postgres/PostgresMigrations.d.ts.map +1 -0
- package/lib/Postgres/PostgresMigrations.js +116 -0
- package/lib/Postgres/PostgresMigrations.js.map +1 -0
- package/lib/Postgres/PostgresOrigin.d.ts +15 -0
- package/lib/Postgres/PostgresOrigin.d.ts.map +1 -0
- package/lib/Postgres/PostgresOrigin.js +2 -0
- package/lib/Postgres/PostgresOrigin.js.map +1 -0
- package/lib/Postgres/PostgresRole.d.ts +142 -0
- package/lib/Postgres/PostgresRole.d.ts.map +1 -0
- package/lib/Postgres/PostgresRole.js +268 -0
- package/lib/Postgres/PostgresRole.js.map +1 -0
- package/lib/Postgres/index.d.ts +7 -0
- package/lib/Postgres/index.d.ts.map +1 -0
- package/lib/Postgres/index.js +7 -0
- package/lib/Postgres/index.js.map +1 -0
- package/lib/Providers.d.ts +24 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +40 -0
- package/lib/Providers.js.map +1 -0
- package/lib/Util.d.ts +93 -0
- package/lib/Util.d.ts.map +1 -0
- package/lib/Util.js +135 -0
- package/lib/Util.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/package.json +79 -3
- package/src/AuthProvider.ts +571 -0
- package/src/Branch.ts +657 -0
- package/src/Contributions.ts +9 -0
- package/src/Credentials.ts +116 -0
- package/src/Database.ts +152 -0
- package/src/MySQL/MySQLBranch.ts +109 -0
- package/src/MySQL/MySQLClusterSize.ts +185 -0
- package/src/MySQL/MySQLDatabase.ts +521 -0
- package/src/MySQL/MySQLMigrations.ts +182 -0
- package/src/MySQL/MySQLOrigin.ts +15 -0
- package/src/MySQL/MySQLPassword.ts +428 -0
- package/src/MySQL/index.ts +5 -0
- package/src/OAuthClient.ts +59 -0
- package/src/Postgres/PostgresBranch.ts +97 -0
- package/src/Postgres/PostgresClusterSize.ts +262 -0
- package/src/Postgres/PostgresDatabase.ts +469 -0
- package/src/Postgres/PostgresDefaultRole.ts +340 -0
- package/src/Postgres/PostgresMigrations.ts +193 -0
- package/src/Postgres/PostgresOrigin.ts +15 -0
- package/src/Postgres/PostgresRole.ts +547 -0
- package/src/Postgres/index.ts +6 -0
- package/src/Providers.ts +67 -0
- package/src/Util.ts +205 -0
- package/src/index.ts +14 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import * as planetscale from "@distilled.cloud/planetscale";
|
|
2
|
+
import { Credentials } from "@distilled.cloud/planetscale/Credentials";
|
|
3
|
+
import { deepEqual, isResolved } from "alchemy/Diff";
|
|
4
|
+
import { createPhysicalName } from "alchemy/PhysicalName";
|
|
5
|
+
import * as Provider from "alchemy/Provider";
|
|
6
|
+
import { Resource } from "alchemy/Resource";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Redacted from "effect/Redacted";
|
|
9
|
+
import * as Stream from "effect/Stream";
|
|
10
|
+
/** @resource */
|
|
11
|
+
export const MySQLPassword = Resource("Planetscale.MySQLPassword");
|
|
12
|
+
export const MySQLPasswordProvider = () => Provider.succeed(MySQLPassword, {
|
|
13
|
+
stables: ["id"],
|
|
14
|
+
diff: Effect.fn(function* ({ olds = {}, news }) {
|
|
15
|
+
if (!isResolved(news))
|
|
16
|
+
return undefined;
|
|
17
|
+
// Replace on any immutable-in-place change; engine falls through
|
|
18
|
+
// to reconcile for everything else (which authoritatively diffs
|
|
19
|
+
// against observed cloud state).
|
|
20
|
+
if (news.role !== olds.role)
|
|
21
|
+
return { action: "replace" };
|
|
22
|
+
if (news.replica !== olds.replica) {
|
|
23
|
+
return { action: "replace" };
|
|
24
|
+
}
|
|
25
|
+
if (news.ttl !== olds.ttl)
|
|
26
|
+
return { action: "replace" };
|
|
27
|
+
const newDb = resolveDatabaseName(news.database);
|
|
28
|
+
const oldDb = olds.database ? resolveDatabaseName(olds.database) : undefined;
|
|
29
|
+
if (oldDb && newDb !== oldDb) {
|
|
30
|
+
return { action: "replace" };
|
|
31
|
+
}
|
|
32
|
+
const newBranch = resolveBranchName(news.branch);
|
|
33
|
+
const oldBranch = resolveBranchName(olds.branch);
|
|
34
|
+
if (newBranch !== oldBranch) {
|
|
35
|
+
return { action: "replace" };
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}),
|
|
39
|
+
read: Effect.fn(function* ({ output }) {
|
|
40
|
+
// Adoption (no cached output) is impossible: the PlanetScale API
|
|
41
|
+
// never re-issues plaintext, so even if we found a matching live
|
|
42
|
+
// password by listing+name we couldn't deliver the `password`
|
|
43
|
+
// attribute. Fall through to greenfield create in `reconcile`.
|
|
44
|
+
if (!output)
|
|
45
|
+
return undefined;
|
|
46
|
+
// Refresh — verify the cached password still exists and
|
|
47
|
+
// re-emit the persisted output (with plaintext intact).
|
|
48
|
+
// If it's gone, return undefined so the engine routes to
|
|
49
|
+
// reconcile, which will surface the unrecoverable-rotation
|
|
50
|
+
// condition explicitly.
|
|
51
|
+
return yield* planetscale
|
|
52
|
+
.getPassword({
|
|
53
|
+
organization: output.organization,
|
|
54
|
+
database: output.database,
|
|
55
|
+
branch: output.branch,
|
|
56
|
+
id: output.id,
|
|
57
|
+
})
|
|
58
|
+
.pipe(Effect.map((password) => buildAttributes(password, output.password, {
|
|
59
|
+
organization: output.organization,
|
|
60
|
+
database: output.database,
|
|
61
|
+
branch: output.branch,
|
|
62
|
+
})), Effect.catchTag("NotFound", () => Effect.succeed(undefined)));
|
|
63
|
+
}),
|
|
64
|
+
reconcile: Effect.fn(function* ({ id, news, output }) {
|
|
65
|
+
const newName = yield* createPasswordName(id, news.name);
|
|
66
|
+
// Identifiers — stable across update (diff replaces on
|
|
67
|
+
// database/branch changes), so we can pull from `output` first
|
|
68
|
+
// and fall back to `news` for greenfield.
|
|
69
|
+
const { organization: envOrg } = yield* yield* Credentials;
|
|
70
|
+
const organization = output?.organization ?? resolveDatabaseOrg(news.database) ?? envOrg;
|
|
71
|
+
const databaseName = output?.database ?? resolveDatabaseName(news.database);
|
|
72
|
+
const branchName = output?.branch ?? resolveBranchName(news.branch);
|
|
73
|
+
// 1. Observe — read live state. The PlanetScale API has no
|
|
74
|
+
// "lookup by name" path (names aren't unique within a branch)
|
|
75
|
+
// so the only way to find the live password is by id. Without
|
|
76
|
+
// a cached output we cannot observe and fall straight through
|
|
77
|
+
// to ensure (greenfield create).
|
|
78
|
+
const observed = output
|
|
79
|
+
? yield* planetscale
|
|
80
|
+
.getPassword({
|
|
81
|
+
organization,
|
|
82
|
+
database: databaseName,
|
|
83
|
+
branch: branchName,
|
|
84
|
+
id: output.id,
|
|
85
|
+
})
|
|
86
|
+
.pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)))
|
|
87
|
+
: undefined;
|
|
88
|
+
// 2. Ensure — create the password if it doesn't exist live.
|
|
89
|
+
// This single branch covers greenfield (no output) AND the
|
|
90
|
+
// out-of-band-deletion case (output cached but cloud lost it).
|
|
91
|
+
// The latter is structurally a rotation: the new password
|
|
92
|
+
// has a fresh id/host/username/plaintext that propagate
|
|
93
|
+
// downstream through the dependency graph. There is no path
|
|
94
|
+
// to recover the original plaintext, so recreating is the
|
|
95
|
+
// only way to converge.
|
|
96
|
+
let live;
|
|
97
|
+
let plaintext;
|
|
98
|
+
if (observed) {
|
|
99
|
+
live = observed;
|
|
100
|
+
// We re-use the cached plaintext: the API never re-issues it.
|
|
101
|
+
plaintext = output.password;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const created = yield* planetscale.createPassword({
|
|
105
|
+
organization,
|
|
106
|
+
database: databaseName,
|
|
107
|
+
branch: branchName,
|
|
108
|
+
name: newName,
|
|
109
|
+
role: news.role,
|
|
110
|
+
replica: news.replica,
|
|
111
|
+
ttl: news.ttl,
|
|
112
|
+
cidrs: news.cidrs,
|
|
113
|
+
});
|
|
114
|
+
plaintext = created.plain_text;
|
|
115
|
+
live = created;
|
|
116
|
+
}
|
|
117
|
+
// 3. Sync — diff observed cloud state against desired and patch
|
|
118
|
+
// only what changed. Only `name` and `cidrs` are mutable in
|
|
119
|
+
// place; everything else triggers a replace via diff().
|
|
120
|
+
// Skip the API entirely when there's no delta.
|
|
121
|
+
const wantsRename = newName !== live.name;
|
|
122
|
+
const observedCidrs = normalizeCidrs(live.cidrs);
|
|
123
|
+
const desiredCidrs = normalizeCidrs(news.cidrs);
|
|
124
|
+
const wantsCidrs = !deepEqual(desiredCidrs, observedCidrs);
|
|
125
|
+
if (wantsRename || wantsCidrs) {
|
|
126
|
+
live = yield* planetscale.updatePassword({
|
|
127
|
+
organization,
|
|
128
|
+
database: databaseName,
|
|
129
|
+
branch: branchName,
|
|
130
|
+
id: live.id,
|
|
131
|
+
name: wantsRename ? newName : undefined,
|
|
132
|
+
cidrs: wantsCidrs ? news.cidrs : undefined,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// 4. Return — fresh attrs sourced from observed cloud state,
|
|
136
|
+
// re-using cached plaintext when we didn't just create.
|
|
137
|
+
return buildAttributes(live, plaintext, {
|
|
138
|
+
organization,
|
|
139
|
+
database: databaseName,
|
|
140
|
+
branch: branchName,
|
|
141
|
+
});
|
|
142
|
+
}),
|
|
143
|
+
delete: Effect.fn(function* ({ output }) {
|
|
144
|
+
yield* planetscale
|
|
145
|
+
.deletePassword({
|
|
146
|
+
organization: output.organization,
|
|
147
|
+
database: output.database,
|
|
148
|
+
branch: output.branch,
|
|
149
|
+
id: output.id,
|
|
150
|
+
})
|
|
151
|
+
.pipe(Effect.catchTag("NotFound", () => Effect.void));
|
|
152
|
+
}),
|
|
153
|
+
list: Effect.fn(function* () {
|
|
154
|
+
const { organization } = yield* yield* Credentials;
|
|
155
|
+
const databases = yield* planetscale.listDatabases.pages({ organization }).pipe(Stream.runCollect, Effect.map((chunk) => Array.from(chunk).flatMap((page) => page.data.filter((db) => db.kind === "mysql"))));
|
|
156
|
+
const rows = yield* Effect.forEach(databases, (db) => planetscale.listBranches.pages({ organization, database: db.name }).pipe(Stream.runCollect, Effect.map((branchPages) => Array.from(branchPages).flatMap((page) => page.data.filter((branch) => branch.kind === "mysql"))), Effect.catchTag("NotFound", () => Effect.succeed([{ name: db.default_branch ?? "main" }])), Effect.flatMap((branches) => Effect.forEach(branches, (branch) => planetscale.listPasswords
|
|
157
|
+
.pages({
|
|
158
|
+
organization,
|
|
159
|
+
database: db.name,
|
|
160
|
+
branch: branch.name,
|
|
161
|
+
})
|
|
162
|
+
.pipe(Stream.runCollect, Effect.map((passwordPages) => Array.from(passwordPages).flatMap((page) => page.data.map((password) => buildAttributes(password, Redacted.make(""), {
|
|
163
|
+
organization,
|
|
164
|
+
database: db.name,
|
|
165
|
+
branch: branch.name,
|
|
166
|
+
})))), Effect.catchTag("NotFound", () => Effect.succeed([]))), { concurrency: 10 }).pipe(Effect.map((perBranch) => perBranch.flat())))), { concurrency: 10 });
|
|
167
|
+
return rows.flat();
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
170
|
+
const resolveDatabaseName = (database) => {
|
|
171
|
+
const ref = database;
|
|
172
|
+
return typeof ref === "string" ? ref : ref.name;
|
|
173
|
+
};
|
|
174
|
+
const resolveDatabaseOrg = (database) => {
|
|
175
|
+
const ref = database;
|
|
176
|
+
return typeof ref === "string" ? undefined : ref.organization;
|
|
177
|
+
};
|
|
178
|
+
const resolveBranchName = (branch) => {
|
|
179
|
+
const ref = branch;
|
|
180
|
+
return !ref ? "main" : typeof ref === "string" ? ref : ref.name;
|
|
181
|
+
};
|
|
182
|
+
const createPasswordName = (id, name) => Effect.gen(function* () {
|
|
183
|
+
return name ?? (yield* createPhysicalName({ id, lowercase: true, maxLength: 63 }));
|
|
184
|
+
});
|
|
185
|
+
// Normalize the API's nullable `cidrs` field into the `string[] | undefined`
|
|
186
|
+
// shape we persist so downstream comparisons line up regardless of the
|
|
187
|
+
// API returning `null` vs `[]` vs an actual list.
|
|
188
|
+
const normalizeCidrs = (cidrs) => (cidrs == null || cidrs.length === 0 ? undefined : cidrs);
|
|
189
|
+
const buildAttributes = (password, plaintext, context) => ({
|
|
190
|
+
id: password.id,
|
|
191
|
+
name: password.name,
|
|
192
|
+
expiresAt: password.expires_at,
|
|
193
|
+
host: password.access_host_url,
|
|
194
|
+
username: password.username,
|
|
195
|
+
password: plaintext,
|
|
196
|
+
origin: {
|
|
197
|
+
scheme: "mysql",
|
|
198
|
+
host: password.access_host_url,
|
|
199
|
+
port: 3306,
|
|
200
|
+
database: context.database,
|
|
201
|
+
user: password.username,
|
|
202
|
+
password: plaintext,
|
|
203
|
+
},
|
|
204
|
+
organization: context.organization,
|
|
205
|
+
database: context.database,
|
|
206
|
+
branch: context.branch,
|
|
207
|
+
role: password.role,
|
|
208
|
+
replica: password.replica,
|
|
209
|
+
ttl: password.ttl_seconds ?? undefined,
|
|
210
|
+
cidrs: normalizeCidrs(password.cidrs),
|
|
211
|
+
});
|
|
212
|
+
//# sourceMappingURL=MySQLPassword.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MySQLPassword.js","sourceRoot":"","sources":["../../src/MySQL/MySQLPassword.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MySQL/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/MySQL/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as Redacted from "effect/Redacted";
|
|
2
|
+
export { OAuthCredentials, OAuthError, type Authorization } from "alchemy/Auth/OAuthFlow";
|
|
3
|
+
/**
|
|
4
|
+
* Registered PlanetScale OAuth application credentials.
|
|
5
|
+
*
|
|
6
|
+
* Unlike Cloudflare, PlanetScale OAuth has **no public-client flow** — the
|
|
7
|
+
* token endpoint requires client authentication for every grant (PKCE is
|
|
8
|
+
* advertised in their discovery doc but does not lift that requirement), so
|
|
9
|
+
* exchanging the authorization code (and refreshing the token) requires the
|
|
10
|
+
* application's `client_secret`. There is no way to keep that secret out of
|
|
11
|
+
* a distributed CLI, so it ships here: the exposure is the same posture as a
|
|
12
|
+
* public `client_id` (a stolen refresh token is usable, exactly like
|
|
13
|
+
* Cloudflare's secret-less refresh), and it can be rotated by cutting a new
|
|
14
|
+
* release. PlanetScale's own CLI ships its OAuth `client_secret` in source
|
|
15
|
+
* the same way:
|
|
16
|
+
* https://github.com/planetscale/cli/blob/main/internal/auth/authenticator.go
|
|
17
|
+
*
|
|
18
|
+
* Registered at https://app.planetscale.com with redirect URI
|
|
19
|
+
* {@link OAUTH_REDIRECT_URI}. Scopes are configured on the application
|
|
20
|
+
* itself, not requested per-authorization (so `authorize()` is called with
|
|
21
|
+
* no scopes). Rotate by registering a new secret and cutting a release.
|
|
22
|
+
*/
|
|
23
|
+
export declare const OAUTH_CLIENT_ID = "pscale_app_aa12e3938baebb788aac443f66e422da";
|
|
24
|
+
export declare const OAUTH_CLIENT_SECRET: Redacted.Redacted<string>;
|
|
25
|
+
export declare const OAUTH_REDIRECT_URI = "https://alchemy.run/auth/callback";
|
|
26
|
+
export declare const OAUTH_LOCAL_CALLBACK_URI = "http://localhost:9976/auth/callback";
|
|
27
|
+
export declare const OAUTH_ENDPOINTS: {
|
|
28
|
+
authorize: string;
|
|
29
|
+
token: string;
|
|
30
|
+
};
|
|
31
|
+
export declare const { authorize, callback, exchange, exchangeCallbackInput, refresh, usesCurrentClient }: import("alchemy/Auth/OAuthFlow").OAuthClient;
|
|
32
|
+
//# sourceMappingURL=OAuthClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OAuthClient.d.ts","sourceRoot":"","sources":["../src/OAuthClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE1F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,gDAAgD,CAAC;AAC7E,eAAO,MAAM,mBAAmB,2BAE/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,sCAAsC,CAAC;AACtE,eAAO,MAAM,wBAAwB,wCAAwC,CAAC;AAC9E,eAAO,MAAM,eAAe;IAO1B,SAAS;IACT,KAAK;CACN,CAAC;AAgBF,eAAO,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,OAAO,EAAE,iBAAiB,EAAE,8CACzF,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { makeOAuthClient } from "alchemy/Auth/OAuthFlow";
|
|
2
|
+
import * as Redacted from "effect/Redacted";
|
|
3
|
+
export { OAuthCredentials, OAuthError } from "alchemy/Auth/OAuthFlow";
|
|
4
|
+
/**
|
|
5
|
+
* Registered PlanetScale OAuth application credentials.
|
|
6
|
+
*
|
|
7
|
+
* Unlike Cloudflare, PlanetScale OAuth has **no public-client flow** — the
|
|
8
|
+
* token endpoint requires client authentication for every grant (PKCE is
|
|
9
|
+
* advertised in their discovery doc but does not lift that requirement), so
|
|
10
|
+
* exchanging the authorization code (and refreshing the token) requires the
|
|
11
|
+
* application's `client_secret`. There is no way to keep that secret out of
|
|
12
|
+
* a distributed CLI, so it ships here: the exposure is the same posture as a
|
|
13
|
+
* public `client_id` (a stolen refresh token is usable, exactly like
|
|
14
|
+
* Cloudflare's secret-less refresh), and it can be rotated by cutting a new
|
|
15
|
+
* release. PlanetScale's own CLI ships its OAuth `client_secret` in source
|
|
16
|
+
* the same way:
|
|
17
|
+
* https://github.com/planetscale/cli/blob/main/internal/auth/authenticator.go
|
|
18
|
+
*
|
|
19
|
+
* Registered at https://app.planetscale.com with redirect URI
|
|
20
|
+
* {@link OAUTH_REDIRECT_URI}. Scopes are configured on the application
|
|
21
|
+
* itself, not requested per-authorization (so `authorize()` is called with
|
|
22
|
+
* no scopes). Rotate by registering a new secret and cutting a release.
|
|
23
|
+
*/
|
|
24
|
+
export const OAUTH_CLIENT_ID = "pscale_app_aa12e3938baebb788aac443f66e422da";
|
|
25
|
+
export const OAUTH_CLIENT_SECRET = Redacted.make("pscale_app_secret_yyZ3Q8oe99GP9_yA5wrA5er6RuN6Lz9dC66Bj1OJzpg");
|
|
26
|
+
export const OAUTH_REDIRECT_URI = "https://alchemy.run/auth/callback";
|
|
27
|
+
export const OAUTH_LOCAL_CALLBACK_URI = "http://localhost:9976/auth/callback";
|
|
28
|
+
export const OAUTH_ENDPOINTS = {
|
|
29
|
+
// PlanetScale's own .well-known OAuth discovery doc declares this as
|
|
30
|
+
// the authorization_endpoint — NOT auth.planetscale.com/oauth/authorize
|
|
31
|
+
// (which their public docs cite). The auth.planetscale.com alias does
|
|
32
|
+
// render a consent screen but emits codes whose resulting tokens lack
|
|
33
|
+
// a `sub` claim, so the resource API at api.planetscale.com rejects
|
|
34
|
+
// them as invalid. Use the canonical endpoint.
|
|
35
|
+
authorize: "https://app.planetscale.com/oauth/authorize",
|
|
36
|
+
token: "https://auth.planetscale.com/oauth/token",
|
|
37
|
+
};
|
|
38
|
+
const client = makeOAuthClient({
|
|
39
|
+
clientId: OAUTH_CLIENT_ID,
|
|
40
|
+
endpoints: OAUTH_ENDPOINTS,
|
|
41
|
+
redirectUri: OAUTH_REDIRECT_URI,
|
|
42
|
+
localCallbackUri: OAUTH_LOCAL_CALLBACK_URI,
|
|
43
|
+
auth: { kind: "clientSecret", clientSecret: OAUTH_CLIENT_SECRET },
|
|
44
|
+
// PlanetScale's docs show the token endpoint with all parameters in the
|
|
45
|
+
// query string (https://planetscale.com/docs/api/reference/oauth). Their
|
|
46
|
+
// .well-known discovery doc advertises client_secret_basic /
|
|
47
|
+
// client_secret_post instead, but both behave identically to the
|
|
48
|
+
// query-string form in practice, so we follow the public docs literally.
|
|
49
|
+
tokenTransport: "query",
|
|
50
|
+
});
|
|
51
|
+
export const { authorize, callback, exchange, exchangeCallbackInput, refresh, usesCurrentClient } = client;
|
|
52
|
+
//# sourceMappingURL=OAuthClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OAuthClient.js","sourceRoot":"","sources":["../src/OAuthClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAsB,MAAM,wBAAwB,CAAC;AAE1F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,6CAA6C,CAAC;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,IAAI,CAC9C,+DAA+D,CAChE,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,mCAAmC,CAAC;AACtE,MAAM,CAAC,MAAM,wBAAwB,GAAG,qCAAqC,CAAC;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,qEAAqE;IACrE,wEAAwE;IACxE,sEAAsE;IACtE,sEAAsE;IACtE,oEAAoE;IACpE,+CAA+C;IAC/C,SAAS,EAAE,6CAA6C;IACxD,KAAK,EAAE,0CAA0C;CAClD,CAAC;AAEF,MAAM,MAAM,GAAG,eAAe,CAAC;IAC7B,QAAQ,EAAE,eAAe;IACzB,SAAS,EAAE,eAAe;IAC1B,WAAW,EAAE,kBAAkB;IAC/B,gBAAgB,EAAE,wBAAwB;IAC1C,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE;IACjE,wEAAwE;IACxE,yEAAyE;IACzE,6DAA6D;IAC7D,iEAAiE;IACjE,yEAAyE;IACzE,cAAc,EAAE,OAAO;CACxB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,OAAO,EAAE,iBAAiB,EAAE,GAC/F,MAAM,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Resource } from "alchemy/Resource";
|
|
2
|
+
import { type BaseBranchAttributes, type BaseBranchProps } from "../Branch.ts";
|
|
3
|
+
import type { Providers } from "../Providers.ts";
|
|
4
|
+
import type { PostgresClusterSize } from "./PostgresClusterSize.ts";
|
|
5
|
+
import type { PostgresDatabase } from "./PostgresDatabase.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Properties for creating or updating a {@link PostgresBranch}.
|
|
8
|
+
*/
|
|
9
|
+
export interface PostgresBranchProps extends BaseBranchProps {
|
|
10
|
+
/**
|
|
11
|
+
* The Postgres database. Either a string database name or a
|
|
12
|
+
* {@link PostgresDatabase} resource.
|
|
13
|
+
*/
|
|
14
|
+
database: string | PostgresDatabase;
|
|
15
|
+
/**
|
|
16
|
+
* PostgreSQL cluster size for the branch. Required if `backupId` is provided.
|
|
17
|
+
* Short NAS sizes are expanded using the parent branch's region and CPU
|
|
18
|
+
* architecture (e.g. `"PS_DEV"` off an ARM parent becomes `"PS_DEV_AWS_ARM"`). Metal
|
|
19
|
+
* requires the full SKU (e.g. `"M1_10_AWS_ARM_D_METAL_10"`).
|
|
20
|
+
*/
|
|
21
|
+
clusterSize?: PostgresClusterSize;
|
|
22
|
+
/**
|
|
23
|
+
* Total number of replicas for the branch. `0` creates or converges the
|
|
24
|
+
* branch to non-HA/single-node; `2+` enables HA.
|
|
25
|
+
*/
|
|
26
|
+
replicas?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Parent branch — either a string name or another {@link PostgresBranch}.
|
|
29
|
+
* @default "main"
|
|
30
|
+
*/
|
|
31
|
+
parentBranch?: string | PostgresBranch;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Output attributes of a deployed {@link PostgresBranch}.
|
|
35
|
+
*/
|
|
36
|
+
export interface PostgresBranchAttributes extends BaseBranchAttributes {
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A PlanetScale branch of a {@link PostgresDatabase}. For MySQL branches
|
|
40
|
+
* use {@link MySQLBranch} instead.
|
|
41
|
+
*
|
|
42
|
+
* ### Creating a Branch
|
|
43
|
+
* **Example:** Branch from main
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const branch = yield* Planetscale.PostgresBranch("Feature123", {
|
|
46
|
+
* database: "my-db",
|
|
47
|
+
* parentBranch: "main",
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* **Example:** Branch from a PostgresDatabase resource
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const db = yield* Planetscale.PostgresDatabase("MyDb", { clusterSize: "PS_10" });
|
|
54
|
+
* const branch = yield* Planetscale.PostgresBranch("Feature456", {
|
|
55
|
+
* database: db,
|
|
56
|
+
* parentBranch: "main",
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* ### Migrations and seed data
|
|
61
|
+
* **Example:** Apply migrations on a branch
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const branch = yield* Planetscale.PostgresBranch("Feature123", {
|
|
64
|
+
* database: db,
|
|
65
|
+
* parentBranch: "main",
|
|
66
|
+
* migrationsDir: "./migrations",
|
|
67
|
+
* importFiles: ["./seed.sql"],
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export type PostgresBranch = Resource<"Planetscale.PostgresBranch", PostgresBranchProps, PostgresBranchAttributes, never, Providers>;
|
|
72
|
+
/** @resource */
|
|
73
|
+
export declare const PostgresBranch: import("alchemy/Resource").ResourceClass<PostgresBranch>;
|
|
74
|
+
export declare const PostgresBranchProvider: () => import("effect/Layer").Layer<import("alchemy/Provider").Provider<PostgresBranch>, never, never>;
|
|
75
|
+
//# sourceMappingURL=PostgresBranch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresBranch.d.ts","sourceRoot":"","sources":["../../src/Postgres/PostgresBranch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAsB,MAAM,cAAc,CAAC;AACnG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IAC1D;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAEpC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,oBAAoB;CAAG;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CACnC,4BAA4B,EAC5B,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,EACL,SAAS,CACV,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc,0DAAyD,CAAC;AAErF,eAAO,MAAM,sBAAsB,uGAS/B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Resource } from "alchemy/Resource";
|
|
2
|
+
import { makeBranchProvider } from "../Branch.js";
|
|
3
|
+
import { runPostgresImports, runPostgresMigrations } from "./PostgresMigrations.js";
|
|
4
|
+
/** @resource */
|
|
5
|
+
export const PostgresBranch = Resource("Planetscale.PostgresBranch");
|
|
6
|
+
export const PostgresBranchProvider = () => makeBranchProvider({
|
|
7
|
+
resource: PostgresBranch,
|
|
8
|
+
expectedKind: "postgresql",
|
|
9
|
+
engineLabel: "PostgresBranch",
|
|
10
|
+
runners: {
|
|
11
|
+
runMigrations: runPostgresMigrations,
|
|
12
|
+
runImports: runPostgresImports,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=PostgresBranch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresBranch.js","sourceRoot":"","sources":["../../src/Postgres/PostgresBranch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAmD,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAInG,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AA+EpF,gBAAgB;AAChB,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAiB,4BAA4B,CAAC,CAAC;AAErF,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,EAAE,CACzC,kBAAkB,CAAC;IACjB,QAAQ,EAAE,cAAc;IACxB,YAAY,EAAE,YAAY;IAC1B,WAAW,EAAE,gBAAgB;IAC7B,OAAO,EAAE;QACP,aAAa,EAAE,qBAAqB;QACpC,UAAU,EAAE,kBAAkB;KAC/B;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as planetscale from "@distilled.cloud/planetscale";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
/**
|
|
4
|
+
* Published PlanetScale Metal SKUs for Postgres (AWS).
|
|
5
|
+
*
|
|
6
|
+
* Short display names (`"M-10"`, `"M_10"`) are **not** valid SKUs. Each
|
|
7
|
+
* Metal SKU encodes CPU series, compute size, provider, architecture, and
|
|
8
|
+
* NVMe storage size.
|
|
9
|
+
*
|
|
10
|
+
* Hyphenated SKUs copied from PlanetScale's pricing docs
|
|
11
|
+
* (`"M1-10-AWS-ARM-D-METAL-10"`) are accepted and normalized to
|
|
12
|
+
* underscores by {@link toPostgresClusterSku}. GCP and custom SKUs are
|
|
13
|
+
* still valid via {@link PostgresClusterSize}'s open-string fallback.
|
|
14
|
+
*
|
|
15
|
+
* @see https://planetscale.com/docs/postgres/pricing
|
|
16
|
+
* @see https://planetscale.com/docs/metal
|
|
17
|
+
*/
|
|
18
|
+
export type PostgresMetalClusterSize = "M1_10_AWS_ARM_D_METAL_10" | "M1_10_AWS_AMD_D_METAL_10" | "M1_10_AWS_ARM_D_METAL_25" | "M1_10_AWS_AMD_D_METAL_25" | "M1_10_AWS_ARM_D_METAL_50" | "M1_10_AWS_AMD_D_METAL_50" | "M1_10_AWS_ARM_D_METAL_100" | "M1_10_AWS_AMD_D_METAL_100" | "M1_10_AWS_ARM_D_METAL_200" | "M1_10_AWS_AMD_D_METAL_200" | "M1_20_AWS_ARM_D_METAL_10" | "M1_20_AWS_AMD_D_METAL_10" | "M1_20_AWS_ARM_D_METAL_25" | "M1_20_AWS_AMD_D_METAL_25" | "M1_20_AWS_ARM_D_METAL_50" | "M1_20_AWS_AMD_D_METAL_50" | "M1_20_AWS_ARM_D_METAL_100" | "M1_20_AWS_AMD_D_METAL_100" | "M1_20_AWS_ARM_D_METAL_200" | "M1_20_AWS_AMD_D_METAL_200" | "M1_40_AWS_ARM_D_METAL_10" | "M1_40_AWS_AMD_D_METAL_10" | "M1_40_AWS_ARM_D_METAL_25" | "M1_40_AWS_AMD_D_METAL_25" | "M1_40_AWS_ARM_D_METAL_50" | "M1_40_AWS_AMD_D_METAL_50" | "M1_40_AWS_ARM_D_METAL_100" | "M1_40_AWS_AMD_D_METAL_100" | "M1_40_AWS_ARM_D_METAL_200" | "M1_40_AWS_AMD_D_METAL_200" | "M1_40_AWS_ARM_D_METAL_400" | "M1_40_AWS_AMD_D_METAL_400" | "M1_40_AWS_ARM_D_METAL_800" | "M1_40_AWS_AMD_D_METAL_800" | "M1_40_AWS_ARM_D_METAL_1200" | "M1_40_AWS_AMD_D_METAL_1200" | "M1_80_AWS_ARM_D_METAL_100" | "M1_80_AWS_AMD_D_METAL_100" | "M1_80_AWS_ARM_D_METAL_200" | "M1_80_AWS_AMD_D_METAL_200" | "M1_80_AWS_ARM_D_METAL_400" | "M1_80_AWS_AMD_D_METAL_400" | "M1_80_AWS_ARM_D_METAL_800" | "M1_80_AWS_AMD_D_METAL_800" | "M1_80_AWS_ARM_D_METAL_1200" | "M1_80_AWS_AMD_D_METAL_1200" | "M1_160_AWS_ARM_D_METAL_100" | "M1_160_AWS_AMD_D_METAL_100" | "M1_160_AWS_ARM_D_METAL_200" | "M1_160_AWS_AMD_D_METAL_200" | "M1_160_AWS_ARM_D_METAL_400" | "M1_160_AWS_AMD_D_METAL_400" | "M1_160_AWS_ARM_D_METAL_800" | "M1_160_AWS_AMD_D_METAL_800" | "M1_160_AWS_ARM_D_METAL_1200" | "M1_160_AWS_AMD_D_METAL_1200" | "M8_160_AWS_ARM_D_METAL_118" | "M6_160_AWS_INTEL_D_METAL_118" | "M7_160_AWS_INTEL_D_METAL_468" | "M7_160_AWS_INTEL_D_METAL_1250" | "M8_320_AWS_ARM_D_METAL_237" | "M6_320_AWS_INTEL_D_METAL_237" | "M7_320_AWS_INTEL_D_METAL_937" | "M7_320_AWS_INTEL_D_METAL_2500" | "M8_640_AWS_ARM_D_METAL_474" | "M6_640_AWS_INTEL_D_METAL_474" | "M7_640_AWS_INTEL_D_METAL_1875" | "M7_640_AWS_INTEL_D_METAL_5000" | "M7_960_AWS_INTEL_D_METAL_7500" | "M8_1280_AWS_ARM_D_METAL_950" | "M6_1280_AWS_INTEL_D_METAL_950" | "M7_1280_AWS_INTEL_D_METAL_3750" | "M7_1920_AWS_INTEL_D_METAL_15000" | "M8_2560_AWS_ARM_D_METAL_1900" | "M6_2560_AWS_INTEL_D_METAL_1900" | "M7_2560_AWS_INTEL_D_METAL_7500" | "M8_3840_AWS_ARM_D_METAL_2850" | "M6_3840_AWS_INTEL_D_METAL_2850" | "M7_3840_AWS_INTEL_D_METAL_11250" | "M7_3840_AWS_INTEL_D_METAL_30000" | "M8_5120_AWS_ARM_D_METAL_3800" | "M6_5120_AWS_INTEL_D_METAL_3800" | "M7_5120_AWS_INTEL_D_METAL_15000" | "M7_5760_AWS_INTEL_D_METAL_45000" | "M8_7680_AWS_ARM_D_METAL_5700" | "M6_7680_AWS_INTEL_D_METAL_5700" | "M7_7680_AWS_INTEL_D_METAL_22500" | "M7_7680_AWS_INTEL_D_METAL_60000" | "M6_10240_AWS_INTEL_D_METAL_7600" | "M8_15360_AWS_ARM_D_METAL_11400" | "M7_15360_AWS_INTEL_D_METAL_45000" | "M7_15360_AWS_INTEL_D_METAL_120000";
|
|
19
|
+
/**
|
|
20
|
+
* Available PlanetScale PostgreSQL cluster sizes.
|
|
21
|
+
*
|
|
22
|
+
* ## Network-attached storage (NAS)
|
|
23
|
+
*
|
|
24
|
+
* `PS_*` sizes are backed by network-attached storage and can be specified
|
|
25
|
+
* either as the short size (`"PS_10"`) or the API SKU (`"PS_10_AWS_X86"`).
|
|
26
|
+
* Short NAS sizes are expanded to a SKU by {@link toPostgresClusterSku}
|
|
27
|
+
* using the target region and arch.
|
|
28
|
+
*
|
|
29
|
+
* ## Metal
|
|
30
|
+
*
|
|
31
|
+
* [PlanetScale Metal](https://planetscale.com/docs/metal) sizes are backed
|
|
32
|
+
* by locally-attached NVMe. Pass a **full Metal SKU** from
|
|
33
|
+
* {@link PostgresMetalClusterSize} — short `M-*` names are not valid on
|
|
34
|
+
* their own because Metal SKUs also encode CPU series, architecture, and
|
|
35
|
+
* drive size. See [Postgres pricing](https://planetscale.com/docs/postgres/pricing).
|
|
36
|
+
*
|
|
37
|
+
* @see https://planetscale.com/docs/postgres/pricing
|
|
38
|
+
* @see https://planetscale.com/docs/metal
|
|
39
|
+
*/
|
|
40
|
+
export type PostgresClusterSize = "PS_DEV" | "PS_5" | "PS_10" | "PS_20" | "PS_40" | "PS_80" | "PS_160" | "PS_320" | "PS_640" | "PS_1280" | "PS_2560" | PostgresMetalClusterSize | (string & {});
|
|
41
|
+
/**
|
|
42
|
+
* Converts a {@link PostgresClusterSize} into the SKU string expected by
|
|
43
|
+
* the PlanetScale API.
|
|
44
|
+
*
|
|
45
|
+
* Hyphens are normalized to underscores so SKUs copied from PlanetScale
|
|
46
|
+
* docs (`"PS-10"`, `"M1-10-AWS-ARM-D-METAL-10"`) match the API form.
|
|
47
|
+
*
|
|
48
|
+
* For NAS-backed clusters, the API expects a suffixed name like
|
|
49
|
+
* `PS_<size>_<provider>_<arch>`. Short `PS_*` sizes are expanded using the
|
|
50
|
+
* supplied region and arch.
|
|
51
|
+
*
|
|
52
|
+
* Metal-backed sizes (anything starting with `M`) are passed through after
|
|
53
|
+
* hyphen normalization. The short `M_*` / `M-*` form is not a valid SKU on
|
|
54
|
+
* its own — the API requires the full Metal SKU (e.g.
|
|
55
|
+
* `M1_10_AWS_ARM_D_METAL_10`), which encodes the CPU series, provider,
|
|
56
|
+
* arch, and storage size.
|
|
57
|
+
*
|
|
58
|
+
* Already-suffixed NAS sizes are also passed through unchanged.
|
|
59
|
+
*/
|
|
60
|
+
export declare function toPostgresClusterSku(input: {
|
|
61
|
+
size: PostgresClusterSize;
|
|
62
|
+
arch?: "x86" | "arm";
|
|
63
|
+
region?: string;
|
|
64
|
+
}): string;
|
|
65
|
+
export declare function toPostgresClusterArch(architecture: planetscale.DatabaseBranch["cluster_architecture"]): "arm" | "x86";
|
|
66
|
+
/**
|
|
67
|
+
* Polls branch change requests until all visible changes are in a terminal
|
|
68
|
+
* state (`completed` or `canceled`), or — if `changeId` is provided — until
|
|
69
|
+
* that specific change reaches a terminal state.
|
|
70
|
+
*/
|
|
71
|
+
export declare const waitForPendingPostgresChanges: (organization: string, database: string, branch: string, changeId?: string | undefined) => Effect.Effect<void, planetscale.ListBranchChangeRequestsError, planetscale.PlanetScaleOpContext>;
|
|
72
|
+
/**
|
|
73
|
+
* Ensures a PostgreSQL production branch has the expected cluster size,
|
|
74
|
+
* queuing the change via the change-request API if it doesn't.
|
|
75
|
+
*/
|
|
76
|
+
export declare const ensurePostgresProductionBranchClusterSize: (organization: string, database: string, branch: string, expectedClusterSize: PostgresClusterSize) => Effect.Effect<void, import("../Util.ts").NotReady | planetscale.ListBranchChangeRequestsError, planetscale.PlanetScaleOpContext>;
|
|
77
|
+
//# sourceMappingURL=PostgresClusterSize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresClusterSize.d.ts","sourceRoot":"","sources":["../../src/Postgres/PostgresClusterSize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,wBAAwB,GAChC,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,4BAA4B,GAC5B,4BAA4B,GAC5B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,4BAA4B,GAC5B,6BAA6B,GAC7B,6BAA6B,GAC7B,4BAA4B,GAC5B,8BAA8B,GAC9B,8BAA8B,GAC9B,+BAA+B,GAC/B,4BAA4B,GAC5B,8BAA8B,GAC9B,8BAA8B,GAC9B,+BAA+B,GAC/B,4BAA4B,GAC5B,8BAA8B,GAC9B,+BAA+B,GAC/B,+BAA+B,GAC/B,+BAA+B,GAC/B,6BAA6B,GAC7B,+BAA+B,GAC/B,gCAAgC,GAChC,iCAAiC,GACjC,8BAA8B,GAC9B,gCAAgC,GAChC,gCAAgC,GAChC,8BAA8B,GAC9B,gCAAgC,GAChC,iCAAiC,GACjC,iCAAiC,GACjC,8BAA8B,GAC9B,gCAAgC,GAChC,iCAAiC,GACjC,iCAAiC,GACjC,8BAA8B,GAC9B,gCAAgC,GAChC,iCAAiC,GACjC,iCAAiC,GACjC,iCAAiC,GACjC,gCAAgC,GAChC,kCAAkC,GAClC,mCAAmC,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,mBAAmB,GAC3B,QAAQ,GACR,MAAM,GACN,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,SAAS,GACT,wBAAwB,GACxB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAOT;AAED,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,sBAAsB,CAAC,GAC/D,KAAK,GAAG,KAAK,CAEf;AASD;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,6LA2BxC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,yCAAyC,wOA4BpD,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as planetscale from "@distilled.cloud/planetscale";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Schedule from "effect/Schedule";
|
|
4
|
+
import { pollUntil, waitForBranchReady } from "../Util.js";
|
|
5
|
+
/**
|
|
6
|
+
* Converts a {@link PostgresClusterSize} into the SKU string expected by
|
|
7
|
+
* the PlanetScale API.
|
|
8
|
+
*
|
|
9
|
+
* Hyphens are normalized to underscores so SKUs copied from PlanetScale
|
|
10
|
+
* docs (`"PS-10"`, `"M1-10-AWS-ARM-D-METAL-10"`) match the API form.
|
|
11
|
+
*
|
|
12
|
+
* For NAS-backed clusters, the API expects a suffixed name like
|
|
13
|
+
* `PS_<size>_<provider>_<arch>`. Short `PS_*` sizes are expanded using the
|
|
14
|
+
* supplied region and arch.
|
|
15
|
+
*
|
|
16
|
+
* Metal-backed sizes (anything starting with `M`) are passed through after
|
|
17
|
+
* hyphen normalization. The short `M_*` / `M-*` form is not a valid SKU on
|
|
18
|
+
* its own — the API requires the full Metal SKU (e.g.
|
|
19
|
+
* `M1_10_AWS_ARM_D_METAL_10`), which encodes the CPU series, provider,
|
|
20
|
+
* arch, and storage size.
|
|
21
|
+
*
|
|
22
|
+
* Already-suffixed NAS sizes are also passed through unchanged.
|
|
23
|
+
*/
|
|
24
|
+
export function toPostgresClusterSku(input) {
|
|
25
|
+
const size = input.size.replaceAll("-", "_");
|
|
26
|
+
if (!size.startsWith("PS_") || size.match(/(AWS|GCP)/))
|
|
27
|
+
return size;
|
|
28
|
+
// Not all AWS regions start with "aws-", but all GCP regions start with "gcp-".
|
|
29
|
+
const provider = input.region?.startsWith("gcp") ? "GCP" : "AWS";
|
|
30
|
+
const arch = (input.arch ?? "x86").toUpperCase();
|
|
31
|
+
return `${size}_${provider}_${arch}`;
|
|
32
|
+
}
|
|
33
|
+
export function toPostgresClusterArch(architecture) {
|
|
34
|
+
return architecture === "aarch64" ? "arm" : "x86";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Schedule for polling branch change requests. Postgres cluster resizes
|
|
38
|
+
* routinely take longer than the default 10-minute polling budget, so
|
|
39
|
+
* give change requests a 60-minute budget (720 × 5s).
|
|
40
|
+
*/
|
|
41
|
+
const changeRequestSchedule = Schedule.max([Schedule.spaced("5 seconds"), Schedule.recurs(720)]);
|
|
42
|
+
/**
|
|
43
|
+
* Polls branch change requests until all visible changes are in a terminal
|
|
44
|
+
* state (`completed` or `canceled`), or — if `changeId` is provided — until
|
|
45
|
+
* that specific change reaches a terminal state.
|
|
46
|
+
*/
|
|
47
|
+
export const waitForPendingPostgresChanges = Effect.fn(function* (organization, database, branch, changeId) {
|
|
48
|
+
yield* pollUntil(`changes for branch "${branch}"`, planetscale.listBranchChangeRequests({
|
|
49
|
+
organization,
|
|
50
|
+
database,
|
|
51
|
+
branch,
|
|
52
|
+
page: 1,
|
|
53
|
+
per_page: 25,
|
|
54
|
+
}), (page) => {
|
|
55
|
+
const isTerminal = (state) => state === "completed" || state === "canceled";
|
|
56
|
+
if (changeId) {
|
|
57
|
+
const change = page.data.find((change) => change.id === changeId);
|
|
58
|
+
return change ? isTerminal(change.state) : false;
|
|
59
|
+
}
|
|
60
|
+
return page.data.every((change) => isTerminal(change.state));
|
|
61
|
+
}, changeRequestSchedule);
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Ensures a PostgreSQL production branch has the expected cluster size,
|
|
65
|
+
* queuing the change via the change-request API if it doesn't.
|
|
66
|
+
*/
|
|
67
|
+
export const ensurePostgresProductionBranchClusterSize = Effect.fn(function* (organization, database, branch, expectedClusterSize) {
|
|
68
|
+
// A freshly-forked branch can't accept (or complete) change requests
|
|
69
|
+
// until it has finished provisioning — queueing a resize against it
|
|
70
|
+
// just leaves the change pending until the poll budget runs out.
|
|
71
|
+
const data = yield* waitForBranchReady(organization, database, branch);
|
|
72
|
+
const sku = toPostgresClusterSku({
|
|
73
|
+
size: expectedClusterSize,
|
|
74
|
+
arch: toPostgresClusterArch(data.cluster_architecture),
|
|
75
|
+
region: data.region.slug,
|
|
76
|
+
});
|
|
77
|
+
if (data.cluster_name === sku) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
yield* waitForPendingPostgresChanges(organization, database, branch);
|
|
81
|
+
const change = yield* planetscale.updateBranchChangeRequest({
|
|
82
|
+
organization,
|
|
83
|
+
database,
|
|
84
|
+
branch,
|
|
85
|
+
cluster_size: sku,
|
|
86
|
+
});
|
|
87
|
+
yield* waitForPendingPostgresChanges(organization, database, branch, change.id);
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=PostgresClusterSize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresClusterSize.js","sourceRoot":"","sources":["../../src/Postgres/PostgresClusterSize.ts"],"names":[],"mappings":"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"}
|