@alchemy.run/planetscale 0.0.0-stage → 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.
Files changed (123) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +87 -2
  3. package/lib/AuthProvider.d.ts +64 -0
  4. package/lib/AuthProvider.d.ts.map +1 -0
  5. package/lib/AuthProvider.js +384 -0
  6. package/lib/AuthProvider.js.map +1 -0
  7. package/lib/Branch.d.ts +128 -0
  8. package/lib/Branch.d.ts.map +1 -0
  9. package/lib/Branch.js +420 -0
  10. package/lib/Branch.js.map +1 -0
  11. package/lib/Contributions.d.ts +7 -0
  12. package/lib/Contributions.d.ts.map +1 -0
  13. package/lib/Contributions.js +6 -0
  14. package/lib/Contributions.js.map +1 -0
  15. package/lib/Credentials.d.ts +33 -0
  16. package/lib/Credentials.d.ts.map +1 -0
  17. package/lib/Credentials.js +65 -0
  18. package/lib/Credentials.js.map +1 -0
  19. package/lib/Database.d.ts +138 -0
  20. package/lib/Database.d.ts.map +1 -0
  21. package/lib/Database.js +1 -0
  22. package/lib/Database.js.map +1 -0
  23. package/lib/MySQL/MySQLBranch.d.ts +87 -0
  24. package/lib/MySQL/MySQLBranch.d.ts.map +1 -0
  25. package/lib/MySQL/MySQLBranch.js +15 -0
  26. package/lib/MySQL/MySQLBranch.js.map +1 -0
  27. package/lib/MySQL/MySQLClusterSize.d.ts +32 -0
  28. package/lib/MySQL/MySQLClusterSize.d.ts.map +1 -0
  29. package/lib/MySQL/MySQLClusterSize.js +111 -0
  30. package/lib/MySQL/MySQLClusterSize.js.map +1 -0
  31. package/lib/MySQL/MySQLDatabase.d.ts +141 -0
  32. package/lib/MySQL/MySQLDatabase.d.ts.map +1 -0
  33. package/lib/MySQL/MySQLDatabase.js +294 -0
  34. package/lib/MySQL/MySQLDatabase.js.map +1 -0
  35. package/lib/MySQL/MySQLMigrations.d.ts +24 -0
  36. package/lib/MySQL/MySQLMigrations.d.ts.map +1 -0
  37. package/lib/MySQL/MySQLMigrations.js +106 -0
  38. package/lib/MySQL/MySQLMigrations.js.map +1 -0
  39. package/lib/MySQL/MySQLOrigin.d.ts +15 -0
  40. package/lib/MySQL/MySQLOrigin.d.ts.map +1 -0
  41. package/lib/MySQL/MySQLOrigin.js +2 -0
  42. package/lib/MySQL/MySQLOrigin.js.map +1 -0
  43. package/lib/MySQL/MySQLPassword.d.ts +116 -0
  44. package/lib/MySQL/MySQLPassword.d.ts.map +1 -0
  45. package/lib/MySQL/MySQLPassword.js +212 -0
  46. package/lib/MySQL/MySQLPassword.js.map +1 -0
  47. package/lib/MySQL/index.d.ts +6 -0
  48. package/lib/MySQL/index.d.ts.map +1 -0
  49. package/lib/MySQL/index.js +6 -0
  50. package/lib/MySQL/index.js.map +1 -0
  51. package/lib/OAuthClient.d.ts +32 -0
  52. package/lib/OAuthClient.d.ts.map +1 -0
  53. package/lib/OAuthClient.js +52 -0
  54. package/lib/OAuthClient.js.map +1 -0
  55. package/lib/Postgres/PostgresBranch.d.ts +75 -0
  56. package/lib/Postgres/PostgresBranch.d.ts.map +1 -0
  57. package/lib/Postgres/PostgresBranch.js +15 -0
  58. package/lib/Postgres/PostgresBranch.js.map +1 -0
  59. package/lib/Postgres/PostgresClusterSize.d.ts +77 -0
  60. package/lib/Postgres/PostgresClusterSize.d.ts.map +1 -0
  61. package/lib/Postgres/PostgresClusterSize.js +89 -0
  62. package/lib/Postgres/PostgresClusterSize.js.map +1 -0
  63. package/lib/Postgres/PostgresDatabase.d.ts +95 -0
  64. package/lib/Postgres/PostgresDatabase.d.ts.map +1 -0
  65. package/lib/Postgres/PostgresDatabase.js +294 -0
  66. package/lib/Postgres/PostgresDatabase.js.map +1 -0
  67. package/lib/Postgres/PostgresDefaultRole.d.ts +94 -0
  68. package/lib/Postgres/PostgresDefaultRole.d.ts.map +1 -0
  69. package/lib/Postgres/PostgresDefaultRole.js +187 -0
  70. package/lib/Postgres/PostgresDefaultRole.js.map +1 -0
  71. package/lib/Postgres/PostgresMigrations.d.ts +24 -0
  72. package/lib/Postgres/PostgresMigrations.d.ts.map +1 -0
  73. package/lib/Postgres/PostgresMigrations.js +116 -0
  74. package/lib/Postgres/PostgresMigrations.js.map +1 -0
  75. package/lib/Postgres/PostgresOrigin.d.ts +15 -0
  76. package/lib/Postgres/PostgresOrigin.d.ts.map +1 -0
  77. package/lib/Postgres/PostgresOrigin.js +2 -0
  78. package/lib/Postgres/PostgresOrigin.js.map +1 -0
  79. package/lib/Postgres/PostgresRole.d.ts +142 -0
  80. package/lib/Postgres/PostgresRole.d.ts.map +1 -0
  81. package/lib/Postgres/PostgresRole.js +268 -0
  82. package/lib/Postgres/PostgresRole.js.map +1 -0
  83. package/lib/Postgres/index.d.ts +7 -0
  84. package/lib/Postgres/index.d.ts.map +1 -0
  85. package/lib/Postgres/index.js +7 -0
  86. package/lib/Postgres/index.js.map +1 -0
  87. package/lib/Providers.d.ts +24 -0
  88. package/lib/Providers.d.ts.map +1 -0
  89. package/lib/Providers.js +40 -0
  90. package/lib/Providers.js.map +1 -0
  91. package/lib/Util.d.ts +93 -0
  92. package/lib/Util.d.ts.map +1 -0
  93. package/lib/Util.js +135 -0
  94. package/lib/Util.js.map +1 -0
  95. package/lib/index.d.ts +9 -0
  96. package/lib/index.d.ts.map +1 -0
  97. package/lib/index.js +9 -0
  98. package/lib/index.js.map +1 -0
  99. package/package.json +94 -3
  100. package/src/AuthProvider.ts +571 -0
  101. package/src/Branch.ts +657 -0
  102. package/src/Contributions.ts +9 -0
  103. package/src/Credentials.ts +116 -0
  104. package/src/Database.ts +152 -0
  105. package/src/MySQL/MySQLBranch.ts +109 -0
  106. package/src/MySQL/MySQLClusterSize.ts +185 -0
  107. package/src/MySQL/MySQLDatabase.ts +521 -0
  108. package/src/MySQL/MySQLMigrations.ts +182 -0
  109. package/src/MySQL/MySQLOrigin.ts +15 -0
  110. package/src/MySQL/MySQLPassword.ts +428 -0
  111. package/src/MySQL/index.ts +5 -0
  112. package/src/OAuthClient.ts +59 -0
  113. package/src/Postgres/PostgresBranch.ts +97 -0
  114. package/src/Postgres/PostgresClusterSize.ts +262 -0
  115. package/src/Postgres/PostgresDatabase.ts +469 -0
  116. package/src/Postgres/PostgresDefaultRole.ts +340 -0
  117. package/src/Postgres/PostgresMigrations.ts +193 -0
  118. package/src/Postgres/PostgresOrigin.ts +15 -0
  119. package/src/Postgres/PostgresRole.ts +547 -0
  120. package/src/Postgres/index.ts +6 -0
  121. package/src/Providers.ts +67 -0
  122. package/src/Util.ts +205 -0
  123. 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,6 @@
1
+ export * from "./MySQLClusterSize.ts";
2
+ export * from "./MySQLBranch.ts";
3
+ export * from "./MySQLDatabase.ts";
4
+ export * from "./MySQLOrigin.ts";
5
+ export * from "./MySQLPassword.ts";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -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,6 @@
1
+ export * from "./MySQLClusterSize.js";
2
+ export * from "./MySQLBranch.js";
3
+ export * from "./MySQLDatabase.js";
4
+ export * from "./MySQLOrigin.js";
5
+ export * from "./MySQLPassword.js";
6
+ //# sourceMappingURL=index.js.map
@@ -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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"}