@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,187 @@
1
+ import * as planetscale from "@distilled.cloud/planetscale";
2
+ import { Credentials } from "@distilled.cloud/planetscale/Credentials";
3
+ import { isResolved } from "alchemy/Diff";
4
+ import * as Provider from "alchemy/Provider";
5
+ import { Resource } from "alchemy/Resource";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Redacted from "effect/Redacted";
8
+ import * as Stream from "effect/Stream";
9
+ import { PlanetscaleConflict, waitForBranchReady } from "../Util.js";
10
+ /** @resource */
11
+ export const PostgresDefaultRole = Resource("Planetscale.PostgresDefaultRole");
12
+ export const PostgresDefaultRoleProvider = () => Provider.succeed(PostgresDefaultRole, {
13
+ stables: ["id"],
14
+ diff: Effect.fn(function* ({ news, olds = {} }) {
15
+ if (!isResolved(news))
16
+ return undefined;
17
+ const newDb = resolveDatabaseName(news.database);
18
+ const oldDb = olds.database ? resolveDatabaseName(olds.database) : undefined;
19
+ if (oldDb && newDb !== oldDb) {
20
+ return { action: "replace" };
21
+ }
22
+ const newBranch = resolveBranchName(news.branch);
23
+ const oldBranch = resolveBranchName(olds.branch);
24
+ if (newBranch !== oldBranch) {
25
+ return { action: "replace" };
26
+ }
27
+ return undefined;
28
+ }),
29
+ read: Effect.fn(function* ({ output }) {
30
+ // Adoption (no cached output) is impossible without destroying
31
+ // existing credentials. The engine routes adoption through
32
+ // `read`, but here we always defer to reconcile so the
33
+ // `forceReset` props flag remains the user-facing switch for
34
+ // takeover. Returning undefined makes the engine treat the
35
+ // resource as greenfield; reconcile then observes live state
36
+ // and either fails (no forceReset) or resets (forceReset).
37
+ if (!output)
38
+ return undefined;
39
+ // Refresh — verify the default role still exists and re-emit
40
+ // the persisted output (with plaintext intact). If gone,
41
+ // return undefined so the engine routes through reconcile,
42
+ // which will recreate via reset.
43
+ return yield* planetscale
44
+ .getDefaultRole({
45
+ organization: output.organization,
46
+ database: output.database,
47
+ branch: output.branch,
48
+ })
49
+ .pipe(Effect.map((role) => ({
50
+ ...output,
51
+ privateHost: role.private_access_host_url,
52
+ privateConnectionServiceName: role.private_connection_service_name,
53
+ })), Effect.catchTag("NotFound", () => Effect.succeed(undefined)));
54
+ }),
55
+ reconcile: Effect.fn(function* ({ news, output }) {
56
+ const { organization: envOrg } = yield* yield* Credentials;
57
+ const organization = resolveDatabaseOrg(news.database) ?? envOrg;
58
+ const databaseName = resolveDatabaseName(news.database);
59
+ const branchName = resolveBranchName(news.branch);
60
+ // 1. Observe — the default role is the singleton for this
61
+ // (database, branch); we key on those rather than an id.
62
+ // Observation runs unconditionally so the adoption guard
63
+ // below fires on greenfield deploys against branches that
64
+ // already have a default role (otherwise we would silently
65
+ // `resetDefault` and destroy their credentials).
66
+ const observed = yield* planetscale
67
+ .getDefaultRole({
68
+ organization,
69
+ database: databaseName,
70
+ branch: branchName,
71
+ })
72
+ .pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)));
73
+ // 2. Sync (no-op) — we own the role and it still exists in the
74
+ // cloud. Default roles have nothing mutable in place: their
75
+ // plaintext password isn't retrievable, so we retain the cached
76
+ // credentials while refreshing the private connection details.
77
+ // diff() forces a replace when database/branch change.
78
+ if (output && observed) {
79
+ return {
80
+ ...output,
81
+ privateHost: observed.private_access_host_url,
82
+ privateConnectionServiceName: observed.private_connection_service_name,
83
+ };
84
+ }
85
+ // 3. Adoption guard — observed exists but we have no prior
86
+ // output (greenfield against a pre-existing default role).
87
+ // Taking over requires a reset (which destroys the existing
88
+ // password), so gate on an explicit forceReset opt-in.
89
+ if (observed && !news.forceReset) {
90
+ return yield* new PlanetscaleConflict({
91
+ message: `Default role already exists for database "${databaseName}" branch "${branchName}". Use forceReset: true to reset.`,
92
+ });
93
+ }
94
+ // 4. Ensure — (re)create the default role. This branch runs
95
+ // for greenfield (no output, no observed), drift recovery
96
+ // (output cached but cloud state gone), and authorised
97
+ // adoption (observed present + forceReset).
98
+ yield* waitForBranchReady(organization, databaseName, branchName);
99
+ const data = yield* planetscale.resetDefaultRole({
100
+ organization,
101
+ database: databaseName,
102
+ branch: branchName,
103
+ });
104
+ if (!data.password) {
105
+ return yield* Effect.die(`Planetscale did not return a password for Default Role.`);
106
+ }
107
+ const password = Redacted.isRedacted(data.password)
108
+ ? Redacted.value(data.password)
109
+ : data.password;
110
+ const connectionUrl = `postgresql://${data.username}:${password}@${data.access_host_url}:5432/${data.database_name}?sslmode=verify-full`;
111
+ const connectionUrlPooled = `postgresql://${data.username}:${password}@${data.access_host_url}:6432/${data.database_name}?sslmode=verify-full`;
112
+ return {
113
+ id: data.id,
114
+ name: data.name,
115
+ expiresAt: data.expires_at,
116
+ host: data.access_host_url,
117
+ username: data.username,
118
+ password: Redacted.make(password),
119
+ ttl: data.ttl,
120
+ databaseName: data.database_name,
121
+ connectionUrl: Redacted.make(connectionUrl),
122
+ connectionUrlPooled: Redacted.make(connectionUrlPooled),
123
+ privateHost: data.private_access_host_url,
124
+ privateConnectionServiceName: data.private_connection_service_name,
125
+ inheritedRoles: data.inherited_roles,
126
+ organization,
127
+ database: databaseName,
128
+ branch: branchName,
129
+ };
130
+ }),
131
+ delete: Effect.fn(function* ({ output }) {
132
+ // No delete endpoint — reset to invalidate existing credentials.
133
+ yield* planetscale
134
+ .resetDefaultRole({
135
+ organization: output.organization,
136
+ database: output.database,
137
+ branch: output.branch,
138
+ })
139
+ .pipe(Effect.catchTag("NotFound", () => Effect.void));
140
+ }),
141
+ list: Effect.fn(function* () {
142
+ const { organization } = yield* yield* Credentials;
143
+ const roles = yield* planetscale.listDatabases.pages({ organization }).pipe(Stream.map((page) => page.data.filter((db) => db.kind === "postgresql")), Stream.flattenIterable, Stream.flatMap((db) => planetscale.listBranches.pages({ organization, database: db.name }).pipe(Stream.map((page) => page.data.filter((branch) => branch.kind === "postgresql")), Stream.flattenIterable, Stream.catchTag("NotFound", () => Stream.succeed({ name: db.default_branch ?? "main" })), Stream.flatMap((branch) => planetscale.listRoles
144
+ .pages({
145
+ organization,
146
+ database: db.name,
147
+ branch: branch.name,
148
+ })
149
+ .pipe(Stream.map((page) => page.data
150
+ .filter((role) => role.default)
151
+ .map((role) => ({
152
+ id: role.id,
153
+ name: role.name,
154
+ expiresAt: role.expires_at,
155
+ host: role.access_host_url,
156
+ username: role.username,
157
+ password: Redacted.make(""),
158
+ ttl: role.ttl,
159
+ databaseName: role.database_name,
160
+ connectionUrl: Redacted.make(""),
161
+ connectionUrlPooled: Redacted.make(""),
162
+ privateHost: role.private_access_host_url,
163
+ privateConnectionServiceName: role.private_connection_service_name,
164
+ inheritedRoles: role.inherited_roles,
165
+ organization,
166
+ database: db.name,
167
+ branch: branch.name,
168
+ }))), Stream.flattenIterable, Stream.catchTags({
169
+ NotFound: () => Stream.empty,
170
+ Forbidden: () => Stream.empty,
171
+ })), { concurrency: 10 })), { concurrency: 10 }), Stream.runCollect);
172
+ return Array.from(roles);
173
+ }),
174
+ });
175
+ const resolveDatabaseName = (database) => {
176
+ const ref = database;
177
+ return typeof ref === "string" ? ref : ref.name;
178
+ };
179
+ const resolveDatabaseOrg = (database) => {
180
+ const ref = database;
181
+ return typeof ref === "string" ? undefined : ref.organization;
182
+ };
183
+ const resolveBranchName = (branch) => {
184
+ const ref = branch;
185
+ return !ref ? "main" : typeof ref === "string" ? ref : ref.name;
186
+ };
187
+ //# sourceMappingURL=PostgresDefaultRole.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresDefaultRole.js","sourceRoot":"","sources":["../../src/Postgres/PostgresDefaultRole.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type NormalizedMigrationsInput, type StampedMigrationsState } from "@alchemy.run/sql/Migrations";
2
+ import * as ps from "@distilled.cloud/planetscale";
3
+ import * as Effect from "effect/Effect";
4
+ declare const PostgresMigrationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
5
+ readonly _tag: "Planetscale::PostgresMigrationError";
6
+ } & Readonly<A>;
7
+ export declare class PostgresMigrationError extends PostgresMigrationError_base<{
8
+ message: string;
9
+ cause?: unknown;
10
+ }> {
11
+ }
12
+ export interface PostgresMigrationTarget {
13
+ organization: string;
14
+ database: string;
15
+ branch: string;
16
+ }
17
+ /**
18
+ * PlanetScale Postgres's migration adaptation is exactly this: the shared
19
+ * pipeline with a temp-role-scoped pg client as its executor.
20
+ */
21
+ export declare const runPostgresMigrations: (target: PostgresMigrationTarget, input: NormalizedMigrationsInput, stamped: StampedMigrationsState) => Effect.Effect<import("@alchemy.run/sql/Migrations").MigrationRun, import("@alchemy.run/sql/Migrations").DrizzleV0LayoutError | PostgresMigrationError | ps.CreateRoleError | import("@alchemy.run/sql/Migrations").MigrationApplyError, import("effect/FileSystem").FileSystem | import("effect/Path").Path | ps.PlanetScaleOpContext>;
22
+ export declare const runPostgresImports: (target: PostgresMigrationTarget, importFiles: ReadonlyArray<string>, rootDir: string, previous: Record<string, string>) => Effect.Effect<Record<string, string>, import("effect/PlatformError").PlatformError | PostgresMigrationError | ps.CreateRoleError, import("effect/FileSystem").FileSystem | import("effect/Path").Path | ps.PlanetScaleOpContext>;
23
+ export {};
24
+ //# sourceMappingURL=PostgresMigrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresMigrations.d.ts","sourceRoot":"","sources":["../../src/Postgres/PostgresMigrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC5B,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAEnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;;;;AAiBxC,qBAAa,sBAAuB,SAAQ,4BAE1C;IACA,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;CAAG;AAEL,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,WACxB,uBAAuB,SACxB,yBAAyB,WACvB,sBAAsB,2UAO7B,CAAC;AAEL,eAAO,MAAM,kBAAkB,WACrB,uBAAuB,eAClB,aAAa,CAAC,MAAM,CAAC,WACzB,MAAM,YACL,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,qOAkB9B,CAAC"}
@@ -0,0 +1,116 @@
1
+ import { makePgMigrationExecutor, runMigrations, } from "@alchemy.run/sql/Migrations";
2
+ import { readSqlFile } from "@alchemy.run/sql/SqlFile";
3
+ import * as ps from "@distilled.cloud/planetscale";
4
+ import * as Data from "effect/Data";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Redacted from "effect/Redacted";
7
+ import * as Schedule from "effect/Schedule";
8
+ // `pg` is an optional peer dependency — loaded lazily so importing the
9
+ // Planetscale provider never requires the driver unless migrations run.
10
+ const importPg = () => import("pg").catch((cause) => {
11
+ throw new Error("Failed to load the 'pg' driver. Install the optional peer dependency 'pg' to run Planetscale Postgres migrations.", { cause });
12
+ });
13
+ const MIGRATION_ROLE_TTL_SECONDS = 600;
14
+ export class PostgresMigrationError extends Data.TaggedError("Planetscale::PostgresMigrationError") {
15
+ }
16
+ /**
17
+ * PlanetScale Postgres's migration adaptation is exactly this: the shared
18
+ * pipeline with a temp-role-scoped pg client as its executor.
19
+ */
20
+ export const runPostgresMigrations = (target, input, stamped) => runMigrations({
21
+ input,
22
+ stamped,
23
+ withExecutor: (apply) => withPostgresClient(target, (client) => apply(makePgMigrationExecutor(client))),
24
+ });
25
+ export const runPostgresImports = (target, importFiles, rootDir, previous) => Effect.gen(function* () {
26
+ const hashes = { ...previous };
27
+ for (const filePath of importFiles) {
28
+ const file = yield* readSqlFile(rootDir, filePath);
29
+ if (previous[filePath] === file.hash) {
30
+ hashes[filePath] = file.hash;
31
+ continue;
32
+ }
33
+ yield* runPostgresSql(target, file.sql);
34
+ hashes[filePath] = file.hash;
35
+ }
36
+ const tracked = new Set(importFiles);
37
+ for (const key of Object.keys(hashes)) {
38
+ if (!tracked.has(key))
39
+ delete hashes[key];
40
+ }
41
+ return hashes;
42
+ });
43
+ const runPostgresSql = (target, sql) => withPostgresClient(target, (client) => pgExec(client, sql));
44
+ const withPostgresClient = (target, use) => withTemporaryPostgresRole(target, (role) => Effect.acquireUseRelease(Effect.gen(function* () {
45
+ const { Client } = yield* Effect.tryPromise({
46
+ try: importPg,
47
+ catch: toMigrationError,
48
+ });
49
+ const client = yield* Effect.sync(() => new Client({
50
+ connectionString: role.connectionUrl.pipe(Redacted.value, stripPgSslQueryParams),
51
+ ssl: { rejectUnauthorized: true },
52
+ }));
53
+ yield* Effect.tryPromise({
54
+ try: () => client.connect(),
55
+ catch: toMigrationError,
56
+ });
57
+ return client;
58
+ }), use, (client) => Effect.tryPromise({
59
+ try: () => client.end(),
60
+ catch: toMigrationError,
61
+ }).pipe(Effect.ignore)));
62
+ const withTemporaryPostgresRole = (target, use) => Effect.acquireUseRelease(Effect.gen(function* () {
63
+ const created = yield* ps.createRole({
64
+ organization: target.organization,
65
+ database: target.database,
66
+ branch: target.branch,
67
+ ttl: MIGRATION_ROLE_TTL_SECONDS,
68
+ inherited_roles: ["postgres"],
69
+ });
70
+ const password = created.password;
71
+ const value = Redacted.value(password);
72
+ const connectionUrl = yield* Effect.sync(() => `postgresql://${encodeURIComponent(created.username)}:${encodeURIComponent(value)}@${created.access_host_url}:5432/${created.database_name}?sslmode=verify-full`);
73
+ return {
74
+ id: created.id,
75
+ connectionUrl: Redacted.make(connectionUrl),
76
+ };
77
+ }), use, (role) => ps
78
+ .deleteRole({
79
+ organization: target.organization,
80
+ database: target.database,
81
+ branch: target.branch,
82
+ id: role.id,
83
+ successor: "postgres",
84
+ })
85
+ .pipe(
86
+ // Already-deleted roles are a success: nothing to clean up.
87
+ Effect.catchTag("NotFound", () => Effect.void), Effect.retry({
88
+ schedule: Schedule.max([Schedule.exponential("500 millis"), Schedule.recurs(5)]),
89
+ }),
90
+ // Migrations succeeded; don't fail the parent over a release-step
91
+ // hiccup. The role's TTL bounds the orphan window; log loudly so
92
+ // an operator can clean it up manually if needed.
93
+ Effect.catch((cause) => Effect.logWarning(`Failed to delete temporary Planetscale migration role after retries. ` +
94
+ `It will expire via TTL (~${MIGRATION_ROLE_TTL_SECONDS}s). ` +
95
+ `organization=${target.organization} database=${target.database} ` +
96
+ `branch=${target.branch} id=${role.id}`, cause))));
97
+ const pgExec = (client, sql, values) => Effect.tryPromise({
98
+ try: () => client.query(sql, values).then(() => undefined),
99
+ catch: toMigrationError,
100
+ });
101
+ const toMigrationError = (cause) => new PostgresMigrationError({
102
+ message: cause instanceof Error ? cause.message : String(cause),
103
+ cause,
104
+ });
105
+ const stripPgSslQueryParams = (uri) => {
106
+ try {
107
+ const url = new URL(uri);
108
+ url.searchParams.delete("sslmode");
109
+ url.searchParams.delete("channel_binding");
110
+ return url.toString();
111
+ }
112
+ catch {
113
+ return uri;
114
+ }
115
+ };
116
+ //# sourceMappingURL=PostgresMigrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresMigrations.js","sourceRoot":"","sources":["../../src/Postgres/PostgresMigrations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import * as Redacted from "effect/Redacted";
2
+ /**
3
+ * The shape `Cloudflare.Hyperdrive` and other Postgres consumers accept as an
4
+ * origin. Materialized on `Planetscale.PostgresRole` so callers can wire role
5
+ * credentials into Hyperdrive directly.
6
+ */
7
+ export type PostgresOrigin = {
8
+ scheme: "postgres" | "postgresql";
9
+ host: string;
10
+ port: number;
11
+ database: string;
12
+ user: string;
13
+ password: Redacted.Redacted<string>;
14
+ };
15
+ //# sourceMappingURL=PostgresOrigin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresOrigin.d.ts","sourceRoot":"","sources":["../../src/Postgres/PostgresOrigin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAE5C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,UAAU,GAAG,YAAY,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACrC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import * as Redacted from "effect/Redacted";
2
+ //# sourceMappingURL=PostgresOrigin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresOrigin.js","sourceRoot":"","sources":["../../src/Postgres/PostgresOrigin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,142 @@
1
+ import * as planetscale from "@distilled.cloud/planetscale";
2
+ import * as Provider from "alchemy/Provider";
3
+ import { Resource } from "alchemy/Resource";
4
+ import * as Redacted from "effect/Redacted";
5
+ import type { Providers } from "../Providers.ts";
6
+ import type { PostgresBranch } from "./PostgresBranch.ts";
7
+ import type { PostgresDatabase } from "./PostgresDatabase.ts";
8
+ import type { PostgresOrigin } from "./PostgresOrigin.ts";
9
+ /**
10
+ * Built-in PostgreSQL roles that can be inherited from. Custom role names
11
+ * (referencing other Role resources) are also accepted.
12
+ */
13
+ export type InheritedRole = "pscale_managed" | "pg_checkpoint" | "pg_create_subscription" | "pg_maintain" | "pg_monitor" | "pg_read_all_data" | "pg_read_all_settings" | "pg_read_all_stats" | "pg_signal_backend" | "pg_stat_scan_tables" | "pg_use_reserved_connections" | "pg_write_all_data" | "postgres" | (string & {});
14
+ /**
15
+ * Properties for creating or updating a PlanetScale PostgreSQL role.
16
+ *
17
+ * Roles are only meant for PostgreSQL databases. For MySQL,
18
+ * use {@link MySQLPassword} instead.
19
+ */
20
+ export interface PostgresRoleProps {
21
+ /**
22
+ * Role name. If not provided, a physical name will be generated.
23
+ */
24
+ name?: string;
25
+ /**
26
+ * PostgreSQL database — string name or {@link PostgresDatabase} resource.
27
+ */
28
+ database: string | PostgresDatabase;
29
+ /**
30
+ * Branch — string name or {@link PostgresBranch} resource.
31
+ * @default "main"
32
+ */
33
+ branch?: string | PostgresBranch;
34
+ /**
35
+ * Time to live in seconds.
36
+ */
37
+ ttl?: number;
38
+ /**
39
+ * Roles to inherit from. Either a list of built-in role names, or
40
+ * another {@link PostgresRole} resource (whose `inheritedRoles` are reused).
41
+ */
42
+ inheritedRoles: InheritedRole[] | PostgresRole;
43
+ /**
44
+ * Give the role the REPLICATION attribute, for a logical-replication
45
+ * consumer (Electric, Debezium, a CDC pipeline). PlanetScale only grants
46
+ * it alongside `inheritedRoles: ["postgres"]`. Create-only: changing it
47
+ * replaces the role.
48
+ * @default false
49
+ */
50
+ withReplication?: boolean;
51
+ /**
52
+ * Successor role to reassign ownership to before dropping. Used during
53
+ * delete.
54
+ * @default "postgres"
55
+ */
56
+ successor?: string | PostgresRole;
57
+ }
58
+ /**
59
+ * Output attributes of a deployed PlanetScale role.
60
+ */
61
+ export interface PostgresRoleAttributes {
62
+ /** Unique identifier for the role (stable). */
63
+ id: string;
64
+ /** The Postgres role name (assigned by PlanetScale). */
65
+ name: string;
66
+ /** ISO 8601 timestamp at which the role expires. */
67
+ expiresAt: string | null;
68
+ /** Hostname for the database connection. */
69
+ host: string;
70
+ /** Username for database authentication. */
71
+ username: string;
72
+ /** Password for database authentication (Redacted). */
73
+ password: Redacted.Redacted<string>;
74
+ /** The database name. */
75
+ database: string;
76
+ /** The Postgres database name inside the branch. */
77
+ databaseName: string;
78
+ /** Parsed direct (port 5432) connection components ready to feed into Cloudflare Hyperdrive. */
79
+ origin: PostgresOrigin;
80
+ /** Parsed pooled (PSBouncer, port 6432) connection components, e.g. for a Hyperdrive `dev` origin. */
81
+ pooledOrigin: PostgresOrigin;
82
+ /**
83
+ * Private connection host or DNS zone for this branch, supplied by
84
+ * PlanetScale. GCP Private Service Connect requires an endpoint name before
85
+ * this DNS zone.
86
+ */
87
+ privateHost: string;
88
+ /** Service name for this branch supplied by PlanetScale to establish a private connection. */
89
+ privateConnectionServiceName: string;
90
+ /** Direct connection URL for the database (Redacted). */
91
+ connectionUrl: Redacted.Redacted<string>;
92
+ /** Pooled connection URL via PSBouncer (port 6432, Redacted). */
93
+ connectionUrlPooled: Redacted.Redacted<string>;
94
+ /** Inherited roles. */
95
+ inheritedRoles: InheritedRole[];
96
+ /** Whether the role carries the REPLICATION attribute. */
97
+ withReplication: boolean;
98
+ /** The successor role used during delete. */
99
+ successor: string;
100
+ /** Resolved organization slug. */
101
+ organization: string;
102
+ /** Resolved branch name. */
103
+ branch: string;
104
+ /** Time-to-live for the role in seconds. */
105
+ ttl: number | null;
106
+ }
107
+ /**
108
+ * A PlanetScale role for accessing a PostgreSQL database branch.
109
+ *
110
+ * For MySQL databases, use {@link MySQLPassword} instead.
111
+ *
112
+ * ### Creating a Role
113
+ * **Example:** Postgres admin role
114
+ * ```typescript
115
+ * const admin = yield* Planetscale.PostgresRole("Admin", {
116
+ * database: "my-db",
117
+ * inheritedRoles: ["postgres"],
118
+ * });
119
+ * ```
120
+ *
121
+ * **Example:** Read-only role
122
+ * ```typescript
123
+ * const reader = yield* Planetscale.PostgresRole("Reader", {
124
+ * database: "my-db",
125
+ * inheritedRoles: ["pg_read_all_data", "pg_read_all_settings"],
126
+ * });
127
+ * ```
128
+ *
129
+ * **Example:** Role with TTL
130
+ * ```typescript
131
+ * const tempReader = yield* Planetscale.PostgresRole("TempReader", {
132
+ * database: "my-db",
133
+ * inheritedRoles: ["pg_read_all_data"],
134
+ * ttl: 3600,
135
+ * });
136
+ * ```
137
+ */
138
+ export type PostgresRole = Resource<"Planetscale.PostgresRole", PostgresRoleProps, PostgresRoleAttributes, never, Providers>;
139
+ /** @resource */
140
+ export declare const PostgresRole: import("alchemy/Resource").ResourceClass<PostgresRole>;
141
+ export declare const PostgresRoleProvider: () => import("effect/Layer").Layer<Provider.Provider<PostgresRole>, never, import("alchemy/Stack").Stack | import("alchemy/Stage").Stage | planetscale.PlanetScaleOpContext>;
142
+ //# sourceMappingURL=PostgresRole.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresRole.d.ts","sourceRoot":"","sources":["../../src/Postgres/PostgresRole.ts"],"names":[],"mappings":"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"}