@microagi/alchemy-gcp 0.3.0 → 0.5.0

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 (71) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/lib/ArtifactRegistry/Operations.d.ts +47 -0
  3. package/lib/ArtifactRegistry/Operations.d.ts.map +1 -0
  4. package/lib/ArtifactRegistry/Operations.js +47 -0
  5. package/lib/ArtifactRegistry/Operations.js.map +1 -0
  6. package/lib/ArtifactRegistry/Repository.d.ts +263 -0
  7. package/lib/ArtifactRegistry/Repository.d.ts.map +1 -0
  8. package/lib/ArtifactRegistry/Repository.js +257 -0
  9. package/lib/ArtifactRegistry/Repository.js.map +1 -0
  10. package/lib/ArtifactRegistry/Types.d.ts +32 -0
  11. package/lib/ArtifactRegistry/Types.d.ts.map +1 -0
  12. package/lib/ArtifactRegistry/Types.js +12 -0
  13. package/lib/ArtifactRegistry/Types.js.map +1 -0
  14. package/lib/ArtifactRegistry/Validation.d.ts +43 -0
  15. package/lib/ArtifactRegistry/Validation.d.ts.map +1 -0
  16. package/lib/ArtifactRegistry/Validation.js +95 -0
  17. package/lib/ArtifactRegistry/Validation.js.map +1 -0
  18. package/lib/ArtifactRegistry/index.d.ts +4 -0
  19. package/lib/ArtifactRegistry/index.d.ts.map +1 -0
  20. package/lib/ArtifactRegistry/index.js +2 -0
  21. package/lib/ArtifactRegistry/index.js.map +1 -0
  22. package/lib/Providers.d.ts.map +1 -1
  23. package/lib/Providers.js +9 -1
  24. package/lib/Providers.js.map +1 -1
  25. package/lib/Sqladmin/Database.d.ts +82 -0
  26. package/lib/Sqladmin/Database.d.ts.map +1 -0
  27. package/lib/Sqladmin/Database.js +87 -0
  28. package/lib/Sqladmin/Database.js.map +1 -0
  29. package/lib/Sqladmin/Instance.d.ts +234 -0
  30. package/lib/Sqladmin/Instance.d.ts.map +1 -0
  31. package/lib/Sqladmin/Instance.js +251 -0
  32. package/lib/Sqladmin/Instance.js.map +1 -0
  33. package/lib/Sqladmin/Operations.d.ts +41 -0
  34. package/lib/Sqladmin/Operations.d.ts.map +1 -0
  35. package/lib/Sqladmin/Operations.js +42 -0
  36. package/lib/Sqladmin/Operations.js.map +1 -0
  37. package/lib/Sqladmin/Types.d.ts +82 -0
  38. package/lib/Sqladmin/Types.d.ts.map +1 -0
  39. package/lib/Sqladmin/Types.js +28 -0
  40. package/lib/Sqladmin/Types.js.map +1 -0
  41. package/lib/Sqladmin/User.d.ts +110 -0
  42. package/lib/Sqladmin/User.d.ts.map +1 -0
  43. package/lib/Sqladmin/User.js +156 -0
  44. package/lib/Sqladmin/User.js.map +1 -0
  45. package/lib/Sqladmin/Validation.d.ts +60 -0
  46. package/lib/Sqladmin/Validation.d.ts.map +1 -0
  47. package/lib/Sqladmin/Validation.js +125 -0
  48. package/lib/Sqladmin/Validation.js.map +1 -0
  49. package/lib/Sqladmin/index.d.ts +9 -0
  50. package/lib/Sqladmin/index.d.ts.map +1 -0
  51. package/lib/Sqladmin/index.js +5 -0
  52. package/lib/Sqladmin/index.js.map +1 -0
  53. package/lib/index.d.ts +2 -0
  54. package/lib/index.d.ts.map +1 -1
  55. package/lib/index.js +2 -0
  56. package/lib/index.js.map +1 -1
  57. package/package.json +2 -2
  58. package/src/ArtifactRegistry/Operations.ts +79 -0
  59. package/src/ArtifactRegistry/Repository.ts +624 -0
  60. package/src/ArtifactRegistry/Types.ts +49 -0
  61. package/src/ArtifactRegistry/Validation.ts +112 -0
  62. package/src/ArtifactRegistry/index.ts +10 -0
  63. package/src/Providers.ts +15 -0
  64. package/src/Sqladmin/Database.ts +209 -0
  65. package/src/Sqladmin/Instance.ts +620 -0
  66. package/src/Sqladmin/Operations.ts +73 -0
  67. package/src/Sqladmin/Types.ts +101 -0
  68. package/src/Sqladmin/User.ts +333 -0
  69. package/src/Sqladmin/Validation.ts +148 -0
  70. package/src/Sqladmin/index.ts +19 -0
  71. package/src/index.ts +2 -0
@@ -0,0 +1,42 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as Duration from "effect/Duration";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Schedule from "effect/Schedule";
5
+ /**
6
+ * Build the Cloud SQL Admin long-running-operation polling helper.
7
+ *
8
+ * Sqladmin `Operation`s carry `.status: "PENDING" | "RUNNING" | "DONE"`
9
+ * (NOT `.done: boolean` like Cloud Resource Manager / Cloud Run, and
10
+ * NOT `.status === "DONE"` against a different enum). Verified at
11
+ * `vendor/distilled/packages/gcp/src/services/sqladmin-v1.ts:606–612`.
12
+ *
13
+ * Unlike Cloud Run, Sqladmin operations are NOT fully-qualified path
14
+ * names — the API returns a bare operation id (e.g. `e9e88dca-...`),
15
+ * and `getOperations` takes `{ project, operation }`. Callers therefore
16
+ * pass the bare id alongside the parent project context.
17
+ *
18
+ * Schedule: exponential 1s → 1.5× growth, capped via the count cap of
19
+ * 60 retries → roughly a few minutes wall ceiling. Most Cloud SQL
20
+ * operations (CREATE_USER, CREATE_DATABASE, UPDATE settings) finish
21
+ * in 1–30 s; instance CREATE / patch involving a restart are the long
22
+ * pole at 4–10 min, so callers running those should be aware that
23
+ * recurs(60) may bottom out and surface as a retry budget exhaustion.
24
+ *
25
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/operations
26
+ */
27
+ export const makeAwaitOperation = (getOperations) => Effect.fn(function* (project, operationName, session) {
28
+ const op = yield* getOperations({ project, operation: operationName }).pipe(Effect.flatMap((current) => current.status === "DONE"
29
+ ? Effect.succeed(current)
30
+ : Effect.fail({ _tag: "OperationPending" })), Effect.retry({
31
+ while: (e) => e?._tag === "OperationPending",
32
+ schedule: Schedule.exponential(Duration.seconds(1), 1.5).pipe(Schedule.either(Schedule.spaced(Duration.seconds(10))), Schedule.both(Schedule.recurs(60)), Schedule.tapOutput(() => session.note(`Waiting for Cloud SQL operation ${operationName}…`))),
33
+ }));
34
+ if (op.error) {
35
+ const firstErr = op.error.errors?.[0];
36
+ return yield* new ConfigError({
37
+ message: `Cloud SQL operation ${operationName} failed: ${firstErr?.message ?? JSON.stringify(op.error)}`,
38
+ });
39
+ }
40
+ return op;
41
+ });
42
+ //# sourceMappingURL=Operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Operations.js","sourceRoot":"","sources":["../../src/Sqladmin/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAa5C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,aAA4B,EAAE,EAAE,CACjE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EACjB,OAAe,EACf,aAAqB,EACrB,OAAgC;IAEhC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,IAAI,CACzE,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CACzB,OAAO,CAAC,MAAM,KAAK,MAAM;QACvB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;QACzB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAA2B,EAAE,CAAC,CACvD,EACD,MAAM,CAAC,KAAK,CAAC;QACX,KAAK,EAAE,CAAC,CAAoB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,kBAAkB;QAC/D,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAC3D,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EACtD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAClC,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,CACtB,OAAO,CAAC,IAAI,CAAC,mCAAmC,aAAa,GAAG,CAAC,CAClE,CACF;KACF,CAAC,CACH,CAAC;IACF,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QACtC,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,CAAC;YAC5B,OAAO,EAAE,uBAAuB,aAAa,YAC3C,QAAQ,EAAE,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAC9C,EAAE;SACH,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Branded literal-union types for Cloud SQL props.
3
+ *
4
+ * Distilled's generated `databaseVersion` field is an open-tailed union
5
+ * (`"POSTGRES_15" | … | (string & {})`) so the GCP server can ship new
6
+ * versions without breaking SDK consumers. For our props we narrow to
7
+ * the subset we actually support — at the moment, the supported
8
+ * Postgres versions for greenfield instances. This gives consumers
9
+ * compile-time autocomplete and rejects typos like `"POSTGES_15"`.
10
+ *
11
+ * MySQL / SQL Server enum members are intentionally omitted — we only
12
+ * provision Postgres. Add a sibling `MySqlVersion` / `SqlServerVersion`
13
+ * type if/when those land as targets.
14
+ */
15
+ /**
16
+ * Supported Postgres major versions for new Cloud SQL instances.
17
+ *
18
+ * Cloud SQL only allows creating instances on currently-supported
19
+ * majors. As of 2026-06, that's 13–17 for greenfield; we expose 15+
20
+ * since that's what new MicroAGI stacks target. Older versions can be
21
+ * read/managed but should be migrated.
22
+ *
23
+ * @see https://cloud.google.com/sql/docs/postgres/db-versions
24
+ */
25
+ export type PostgresVersion = "POSTGRES_15" | "POSTGRES_16" | "POSTGRES_17";
26
+ /**
27
+ * Cloud SQL edition. `ENTERPRISE_PLUS` unlocks Data Cache, near-zero
28
+ * downtime planned maintenance, and longer log retention; `ENTERPRISE`
29
+ * is the standard tier.
30
+ *
31
+ * @see https://cloud.google.com/sql/docs/postgres/editions-intro
32
+ */
33
+ export type SqlEdition = "ENTERPRISE" | "ENTERPRISE_PLUS";
34
+ /**
35
+ * Data-disk type. PD_SSD is the default and what any new workload
36
+ * should pick. PD_HDD is legacy and slower; only useful for archival
37
+ * read replicas.
38
+ *
39
+ * @see https://cloud.google.com/sql/docs/postgres/instance-settings#storage-type-2ndgen
40
+ */
41
+ export type SqlDataDiskType = "PD_SSD" | "PD_HDD";
42
+ /**
43
+ * Availability type. `ZONAL` runs in one zone; `REGIONAL` runs a
44
+ * standby in a second zone for HA at ~2× the cost.
45
+ *
46
+ * @see https://cloud.google.com/sql/docs/postgres/high-availability
47
+ */
48
+ export type SqlAvailabilityType = "ZONAL" | "REGIONAL";
49
+ /**
50
+ * Activation policy. `ALWAYS` keeps the instance on; `NEVER` parks
51
+ * it (useful for occasional dev databases).
52
+ *
53
+ * @see https://cloud.google.com/sql/docs/postgres/start-stop-restart-instance
54
+ */
55
+ export type SqlActivationPolicy = "ALWAYS" | "NEVER";
56
+ /**
57
+ * Cloud SQL user auth type.
58
+ *
59
+ * - `BUILT_IN` — classic username + password Postgres role. The
60
+ * provider requires a `password` Redacted for this type.
61
+ * - `CLOUD_IAM_USER` — a human IAM principal authenticated via the
62
+ * Cloud SQL Auth Proxy / IAM database authn token exchange.
63
+ * - `CLOUD_IAM_SERVICE_ACCOUNT` — a GCP service-account principal,
64
+ * same auth mechanism as `CLOUD_IAM_USER`. The Postgres role name
65
+ * is the SA email **with the trailing `.gserviceaccount.com`
66
+ * stripped** (Cloud SQL caps role names at 63 chars; SA emails are
67
+ * longer than that).
68
+ * - Open tail `(string & {})` keeps forward compatibility for
69
+ * `CLOUD_IAM_GROUP`, `CLOUD_IAM_GROUP_SERVICE_ACCOUNT`, etc.
70
+ *
71
+ * @see https://cloud.google.com/sql/docs/postgres/iam-authentication
72
+ */
73
+ export type SqlUserType = "BUILT_IN" | "CLOUD_IAM_USER" | "CLOUD_IAM_SERVICE_ACCOUNT" | "CLOUD_IAM_GROUP" | (string & {});
74
+ /**
75
+ * Convenience predicate: `true` for any IAM-backed user type, where
76
+ * passwords are forbidden and the principal is a GCP identity.
77
+ *
78
+ * Used by `Validation.ts` and `User.ts` to fan out between the
79
+ * built-in password path and the IAM token-exchange path.
80
+ */
81
+ export declare const isIamUserType: (type: SqlUserType | undefined) => boolean;
82
+ //# sourceMappingURL=Types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Types.d.ts","sourceRoot":"","sources":["../../src/Sqladmin/Types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,CAAC;AAE5E;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAElD;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,UAAU,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,WAAW,GACnB,UAAU,GACV,gBAAgB,GAChB,2BAA2B,GAC3B,iBAAiB,GACjB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,WAAW,GAAG,SAAS,KAC5B,OAMsB,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Branded literal-union types for Cloud SQL props.
3
+ *
4
+ * Distilled's generated `databaseVersion` field is an open-tailed union
5
+ * (`"POSTGRES_15" | … | (string & {})`) so the GCP server can ship new
6
+ * versions without breaking SDK consumers. For our props we narrow to
7
+ * the subset we actually support — at the moment, the supported
8
+ * Postgres versions for greenfield instances. This gives consumers
9
+ * compile-time autocomplete and rejects typos like `"POSTGES_15"`.
10
+ *
11
+ * MySQL / SQL Server enum members are intentionally omitted — we only
12
+ * provision Postgres. Add a sibling `MySqlVersion` / `SqlServerVersion`
13
+ * type if/when those land as targets.
14
+ */
15
+ /**
16
+ * Convenience predicate: `true` for any IAM-backed user type, where
17
+ * passwords are forbidden and the principal is a GCP identity.
18
+ *
19
+ * Used by `Validation.ts` and `User.ts` to fan out between the
20
+ * built-in password path and the IAM token-exchange path.
21
+ */
22
+ export const isIamUserType = (type) => type === "CLOUD_IAM_USER" ||
23
+ type === "CLOUD_IAM_SERVICE_ACCOUNT" ||
24
+ type === "CLOUD_IAM_GROUP" ||
25
+ type === "CLOUD_IAM_GROUP_USER" ||
26
+ type === "CLOUD_IAM_GROUP_SERVICE_ACCOUNT" ||
27
+ type === "ENTRAID_USER";
28
+ //# sourceMappingURL=Types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Types.js","sourceRoot":"","sources":["../../src/Sqladmin/Types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAwEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,IAA6B,EACpB,EAAE,CACX,IAAI,KAAK,gBAAgB;IACzB,IAAI,KAAK,2BAA2B;IACpC,IAAI,KAAK,iBAAiB;IAC1B,IAAI,KAAK,sBAAsB;IAC/B,IAAI,KAAK,iCAAiC;IAC1C,IAAI,KAAK,cAAc,CAAC"}
@@ -0,0 +1,110 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Provider from "alchemy/Provider";
3
+ import * as Redacted from "effect/Redacted";
4
+ import type * as GCP from "../Providers.ts";
5
+ import { type SqlUserType } from "./Types.ts";
6
+ /**
7
+ * A Cloud SQL user (database role + auth binding).
8
+ *
9
+ * **Three auth modes:**
10
+ *
11
+ * - `BUILT_IN` — classic Postgres username/password. Requires
12
+ * `password`. The role exists only inside Postgres.
13
+ * - `CLOUD_IAM_USER` — a human IAM principal. `name` is the user's
14
+ * email. Authenticates via the Cloud SQL Auth Proxy / IAM token
15
+ * exchange; no password.
16
+ * - `CLOUD_IAM_SERVICE_ACCOUNT` — a GCP service account principal.
17
+ * `name` is the SA email with the trailing `.gserviceaccount.com`
18
+ * stripped (Postgres role names cap at 63 chars; full SA emails
19
+ * often exceed that). No password.
20
+ *
21
+ * The Postgres role itself is granted no privileges by default — wire
22
+ * up grants via SQL (psql / migrations) once the user exists. Cloud
23
+ * SQL IAM authn is independent of grant management.
24
+ *
25
+ * **Adoption.** Users carry no labels and no useful comparable shape
26
+ * beyond `(name, host, type)`. `read` returns the observed user if it
27
+ * exists at this address, `undefined` otherwise. No `Unowned` wrapper
28
+ * — adoption is implicit; the worst case is alchemy issuing a no-op
29
+ * patch / a delete on what it thinks is its own.
30
+ *
31
+ * **Replace triggers.** `project`, `instance`, `name`, `host`, `type`.
32
+ * Type changes need a drop/recreate because Cloud SQL stores the auth
33
+ * shape immutably; we surface that via replace.
34
+ *
35
+ * @example IAM service-account user (workload identity → DB role)
36
+ * ```typescript
37
+ * yield* GCP.SqlUser("AppSaUser", {
38
+ * project: instance.project,
39
+ * instance: instance.name,
40
+ * // App SA email is `app@my-project.iam.gserviceaccount.com` — strip
41
+ * // `.gserviceaccount.com` so the Postgres role name fits in 63 chars.
42
+ * name: "app@my-project.iam",
43
+ * type: "CLOUD_IAM_SERVICE_ACCOUNT",
44
+ * });
45
+ * ```
46
+ *
47
+ * @example Built-in user with a Redacted password
48
+ * ```typescript
49
+ * yield* GCP.SqlUser("MigratorUser", {
50
+ * project: instance.project,
51
+ * instance: instance.name,
52
+ * name: "migrator",
53
+ * password: Redacted.make(process.env.MIGRATOR_PASSWORD!),
54
+ * });
55
+ * ```
56
+ *
57
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/users
58
+ * @see https://cloud.google.com/sql/docs/postgres/iam-authentication
59
+ */
60
+ export type SqlUserProps = {
61
+ /**
62
+ * GCP project ID hosting the parent instance. Immutable — replace.
63
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/users#User
64
+ */
65
+ project: string;
66
+ /**
67
+ * Parent Cloud SQL instance name. Immutable — replace.
68
+ */
69
+ instance: string;
70
+ /**
71
+ * User/role name. For `BUILT_IN`, any valid Postgres identifier.
72
+ * For `CLOUD_IAM_USER`, the principal's email. For
73
+ * `CLOUD_IAM_SERVICE_ACCOUNT`, the SA email **with the trailing
74
+ * `.gserviceaccount.com` stripped** — Postgres role names cap at
75
+ * 63 chars; full SA emails are typically 70+. Immutable — replace.
76
+ */
77
+ name: string;
78
+ /**
79
+ * Host the user can connect from. PostgreSQL ignores this and
80
+ * defaults to `%` (any host). For MySQL it's load-bearing.
81
+ * Immutable — replace.
82
+ */
83
+ host?: string;
84
+ /**
85
+ * Auth backend. Defaults to `BUILT_IN` if unset.
86
+ * @see https://cloud.google.com/sql/docs/postgres/iam-authentication
87
+ */
88
+ type?: SqlUserType;
89
+ /**
90
+ * Password for `BUILT_IN` users. Required for that type; forbidden
91
+ * for any IAM type (validated at plan time).
92
+ */
93
+ password?: Redacted.Redacted<string>;
94
+ };
95
+ export type SqlUserAttributes = {
96
+ /** User name. */
97
+ name: string;
98
+ /** Parent instance name. */
99
+ instance: string;
100
+ /** Project ID. */
101
+ project: string;
102
+ /** Connecting host (defaults to `%` for Postgres). */
103
+ host: string;
104
+ /** Auth backend in effect. */
105
+ type: string;
106
+ };
107
+ export type SqlUser = Resource<"GCP.SqlUser", SqlUserProps, SqlUserAttributes, never, GCP.Providers>;
108
+ export declare const SqlUser: import("alchemy").ResourceClass<SqlUser>;
109
+ export declare const SqlUserProvider: () => import("effect/Layer").Layer<Provider.Provider<SqlUser>, never, import("effect/unstable/http/HttpClient").HttpClient | import("@distilled.cloud/gcp").Credentials>;
110
+ //# sourceMappingURL=User.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.d.ts","sourceRoot":"","sources":["../../src/Sqladmin/User.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAG7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,QAAQ,CAC5B,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AACF,eAAO,MAAM,OAAO,0CAAmC,CAAC;AAaxD,eAAO,MAAM,eAAe,0KAsMzB,CAAC"}
@@ -0,0 +1,156 @@
1
+ import * as sql from "@distilled.cloud/gcp/sqladmin-v1";
2
+ import { Resource } from "alchemy";
3
+ import { isResolved, somePropsAreDifferent } from "alchemy/Diff";
4
+ import * as Provider from "alchemy/Provider";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Redacted from "effect/Redacted";
7
+ import { makeAwaitOperation } from "./Operations.js";
8
+ import { isIamUserType } from "./Types.js";
9
+ import { reshapeBadRequest, validateUser } from "./Validation.js";
10
+ export const SqlUser = Resource("GCP.SqlUser");
11
+ const toAttributes = (u, parent) => ({
12
+ name: parent.name,
13
+ instance: parent.instance,
14
+ project: parent.project,
15
+ host: u.host ?? parent.host,
16
+ type: u.type ?? "BUILT_IN",
17
+ });
18
+ export const SqlUserProvider = () => Provider.effect(SqlUser, Effect.gen(function* () {
19
+ const getUsers = yield* sql.getUsers;
20
+ const listUsers = yield* sql.listUsers;
21
+ const insertUsers = yield* sql.insertUsers;
22
+ const updateUsers = yield* sql.updateUsers;
23
+ const deleteUsers = yield* sql.deleteUsers;
24
+ const getOperations = yield* sql.getOperations;
25
+ const awaitOperation = makeAwaitOperation(getOperations);
26
+ /**
27
+ * Observe a user. Cloud SQL's `getUsers` endpoint returns 404
28
+ * for IAM-typed users in some Postgres minor versions — those
29
+ * are listable but not directly addressable by `name`. Fall
30
+ * back to a list filter on 404 to be safe.
31
+ */
32
+ const observe = (project, instance, name, host) => getUsers({
33
+ project,
34
+ instance,
35
+ name,
36
+ ...(host ? { host } : {}),
37
+ }).pipe(Effect.catchTag("NotFound", () => listUsers({ project, instance }).pipe(Effect.map((res) => (res.items ?? []).find((u) => u.name === name && (host ? u.host === host : true))), Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)))), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
38
+ return {
39
+ stables: ["name", "instance", "project", "host", "type"],
40
+ diff: Effect.fn(function* ({ news, olds = {} }) {
41
+ if (!isResolved(news))
42
+ return undefined;
43
+ if (somePropsAreDifferent(olds, news, [
44
+ "project",
45
+ "instance",
46
+ "name",
47
+ "host",
48
+ "type",
49
+ ])) {
50
+ return { action: "replace" };
51
+ }
52
+ return undefined;
53
+ }),
54
+ reconcile: Effect.fn(function* ({ news, session }) {
55
+ const desiredType = news.type ?? "BUILT_IN";
56
+ const desiredHost = news.host ?? "%";
57
+ yield* validateUser({
58
+ name: news.name,
59
+ type: desiredType,
60
+ hasPassword: news.password !== undefined,
61
+ });
62
+ let observed = yield* observe(news.project, news.instance, news.name, news.host);
63
+ if (!observed) {
64
+ const body = {
65
+ name: news.name,
66
+ ...(news.host !== undefined ? { host: news.host } : {}),
67
+ type: desiredType,
68
+ ...(news.password
69
+ ? { password: Redacted.value(news.password) }
70
+ : {}),
71
+ };
72
+ const op = yield* insertUsers({
73
+ project: news.project,
74
+ instance: news.instance,
75
+ body,
76
+ }).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)), Effect.catchTag("BadRequest", reshapeBadRequest("User", "insert")));
77
+ if (op?.name)
78
+ yield* awaitOperation(news.project, op.name, session);
79
+ observed = yield* observe(news.project, news.instance, news.name, news.host);
80
+ }
81
+ else if (
82
+ // Only BUILT_IN users have a rotatable password. For IAM
83
+ // users the type is fixed at insert and there's nothing
84
+ // mutable to sync. We don't store/compare BUILT_IN
85
+ // passwords (they're write-only on the API side) — if the
86
+ // user explicitly supplies one we re-issue the update so
87
+ // a rotated `Redacted` propagates, but we can't detect
88
+ // drift here so this is a deliberate "user is source of
89
+ // truth" path.
90
+ !isIamUserType(desiredType) &&
91
+ news.password) {
92
+ const op = yield* updateUsers({
93
+ project: news.project,
94
+ instance: news.instance,
95
+ name: news.name,
96
+ ...(news.host !== undefined ? { host: news.host } : {}),
97
+ body: {
98
+ name: news.name,
99
+ ...(news.host !== undefined ? { host: news.host } : {}),
100
+ type: desiredType,
101
+ password: Redacted.value(news.password),
102
+ },
103
+ }).pipe(Effect.catchTag("BadRequest", reshapeBadRequest("User", "update")));
104
+ if (op.name)
105
+ yield* awaitOperation(news.project, op.name, session);
106
+ }
107
+ // observed is non-undefined here: either we just created it
108
+ // and re-observed, or we found it pre-existing. If somehow
109
+ // listUsers still returns nothing (eventual consistency
110
+ // window), synthesise a minimal attribute set from inputs.
111
+ if (!observed) {
112
+ return {
113
+ name: news.name,
114
+ instance: news.instance,
115
+ project: news.project,
116
+ host: desiredHost,
117
+ type: desiredType,
118
+ };
119
+ }
120
+ return toAttributes(observed, {
121
+ project: news.project,
122
+ instance: news.instance,
123
+ name: news.name,
124
+ host: desiredHost,
125
+ });
126
+ }),
127
+ delete: Effect.fn(function* ({ output, session }) {
128
+ yield* deleteUsers({
129
+ project: output.project,
130
+ instance: output.instance,
131
+ name: output.name,
132
+ ...(output.host && output.host !== "%" ? { host: output.host } : {}),
133
+ }).pipe(Effect.flatMap((op) => op.name
134
+ ? awaitOperation(output.project, op.name, session)
135
+ : Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void), Effect.catchTag("BadRequest", reshapeBadRequest("User", "delete")));
136
+ }),
137
+ read: Effect.fn(function* ({ output, olds }) {
138
+ const project = output?.project ?? olds?.project;
139
+ const instance = output?.instance ?? olds?.instance;
140
+ const name = output?.name ?? olds?.name;
141
+ if (!project || !instance || !name)
142
+ return undefined;
143
+ const host = output?.host ?? olds?.host;
144
+ const observed = yield* observe(project, instance, name, host);
145
+ if (!observed)
146
+ return undefined;
147
+ return toAttributes(observed, {
148
+ project,
149
+ instance,
150
+ name,
151
+ host: host ?? "%",
152
+ });
153
+ }),
154
+ };
155
+ }));
156
+ //# sourceMappingURL=User.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.js","sourceRoot":"","sources":["../../src/Sqladmin/User.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,kCAAkC,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAgHlE,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAU,aAAa,CAAC,CAAC;AAExD,MAAM,YAAY,GAAG,CACnB,CAAW,EACX,MAAyE,EACtD,EAAE,CAAC,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,IAAI;IACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;IACzB,OAAO,EAAE,MAAM,CAAC,OAAO;IACvB,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI;IAC3B,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,UAAU;CAC3B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE,CAClC,QAAQ,CAAC,MAAM,CACb,OAAO,EACP,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;IACrC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;IACvC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;IAC3C,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;IAC3C,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;IAC3C,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC;IAC/C,MAAM,cAAc,GAAG,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAEzD;;;;;OAKG;IACH,MAAM,OAAO,GAAG,CACd,OAAe,EACf,QAAgB,EAChB,IAAY,EACZ,IAAwB,EACxB,EAAE,CACF,QAAQ,CAAC;QACP,OAAO;QACP,QAAQ;QACR,IAAI;QACJ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1B,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAC/B,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,CACnC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACjB,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CACpB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAC1D,CACF,EACD,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAC/B,MAAM,CAAC,OAAO,CAAC,SAAiC,CAAC,CAClD,EACD,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,CAChC,MAAM,CAAC,OAAO,CAAC,SAAiC,CAAC,CAClD,CACF,CACF,EACD,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,CAChC,MAAM,CAAC,OAAO,CAAC,SAAiC,CAAC,CAClD,CACF,CAAC;IAEJ,OAAO;QACL,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;QACxD,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE;YAC5C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,OAAO,SAAS,CAAC;YACxC,IACE,qBAAqB,CAAC,IAAoB,EAAE,IAAI,EAAE;gBAChD,SAAS;gBACT,UAAU;gBACV,MAAM;gBACN,MAAM;gBACN,MAAM;aACP,CAAC,EACF,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAW,CAAC;YACxC,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC;QACF,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;YAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC;YAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC;YAErC,KAAK,CAAC,CAAC,YAAY,CAAC;gBAClB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,IAAI,CAAC,QAAQ,KAAK,SAAS;aACzC,CAAC,CAAC;YAEH,IAAI,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CAC3B,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,CACV,CAAC;YAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,GAAa;oBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvD,IAAI,EAAE,WAAW;oBACjB,GAAG,CAAC,IAAI,CAAC,QAAQ;wBACf,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;wBAC7C,CAAC,CAAC,EAAE,CAAC;iBACR,CAAC;gBACF,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;oBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,IAAI;iBACL,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAC/B,MAAM,CAAC,OAAO,CAAC,SAAsC,CAAC,CACvD,EACD,MAAM,CAAC,QAAQ,CACb,YAAY,EACZ,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CACpC,CACF,CAAC;gBACF,IAAI,EAAE,EAAE,IAAI;oBAAE,KAAK,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACpE,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CACvB,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,CACV,CAAC;YACJ,CAAC;iBAAM;YACL,yDAAyD;YACzD,wDAAwD;YACxD,mDAAmD;YACnD,0DAA0D;YAC1D,yDAAyD;YACzD,uDAAuD;YACvD,wDAAwD;YACxD,eAAe;YACf,CAAC,aAAa,CAAC,WAAW,CAAC;gBAC3B,IAAI,CAAC,QAAQ,EACb,CAAC;gBACD,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;oBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvD,IAAI,EAAE;wBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACvD,IAAI,EAAE,WAAW;wBACjB,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;qBACxC;iBACF,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CACb,YAAY,EACZ,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CACpC,CACF,CAAC;gBACF,IAAI,EAAE,CAAC,IAAI;oBAAE,KAAK,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACrE,CAAC;YAED,4DAA4D;YAC5D,2DAA2D;YAC3D,wDAAwD;YACxD,2DAA2D;YAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;oBACL,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,WAAW;iBACU,CAAC;YAChC,CAAC;YACD,OAAO,YAAY,CAAC,QAAQ,EAAE;gBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,WAAW;aAClB,CAAC,CAAC;QACL,CAAC,CAAC;QACF,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;YAC9C,KAAK,CAAC,CAAC,WAAW,CAAC;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrE,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CACpB,EAAE,CAAC,IAAI;gBACL,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;gBAClD,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CACvB,EACD,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAC9C,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CACnE,CAAC;QACJ,CAAC,CAAC;QACF,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;YACzC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,OAAO,CAAC;YACjD,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,IAAI,EAAE,QAAQ,CAAC;YACpD,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,CAAC;YACxC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACrD,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,CAAC;YACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC/D,IAAI,CAAC,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAChC,OAAO,YAAY,CAAC,QAAQ,EAAE;gBAC5B,OAAO;gBACP,QAAQ;gBACR,IAAI;gBACJ,IAAI,EAAE,IAAI,IAAI,GAAG;aAClB,CAAC,CAAC;QACL,CAAC,CAAC;KACH,CAAC;AACJ,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as Effect from "effect/Effect";
3
+ import { type SqlUserType } from "./Types.ts";
4
+ /**
5
+ * Validate a Cloud SQL instance name. Returns a `ConfigError` on the
6
+ * failure channel if the name is invalid, otherwise succeeds.
7
+ *
8
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/instances#SqlInstance
9
+ */
10
+ export declare const validateInstanceName: (name: string) => Effect.Effect<void, ConfigError>;
11
+ /**
12
+ * Validate a Cloud SQL database name (1–64 chars, non-empty).
13
+ *
14
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/databases#Database
15
+ */
16
+ export declare const validateDatabaseName: (name: string) => Effect.Effect<void, ConfigError>;
17
+ /**
18
+ * Validate a Cloud SQL user shape — primarily that the password/type
19
+ * combination is consistent:
20
+ *
21
+ * - `BUILT_IN` users MUST carry a password.
22
+ * - Any IAM user type (`CLOUD_IAM_USER`, `CLOUD_IAM_SERVICE_ACCOUNT`,
23
+ * `CLOUD_IAM_GROUP*`, `ENTRAID_USER`) MUST NOT carry a password —
24
+ * the IAM principal is authenticated by token exchange.
25
+ *
26
+ * Other types from the open tail of the enum (forward-compat) skip
27
+ * the password check.
28
+ *
29
+ * @see https://cloud.google.com/sql/docs/postgres/users
30
+ * @see https://cloud.google.com/sql/docs/postgres/iam-authentication
31
+ */
32
+ export declare const validateUser: (args: {
33
+ name: string;
34
+ type: SqlUserType | undefined;
35
+ hasPassword: boolean;
36
+ }) => Effect.Effect<void, ConfigError>;
37
+ /**
38
+ * Reshape a `BadRequest` from a Cloud SQL Admin create/patch/delete
39
+ * into a `ConfigError` with a remediation hint for the top failure
40
+ * modes:
41
+ *
42
+ * 1. **Billing not enabled** — Cloud SQL refuses to provision against
43
+ * a project without billing. Common right after `ApiEnable` lands
44
+ * but before billing reconciles in a fresh project.
45
+ * 2. **Private network not set up** — `privateNetwork` references a
46
+ * VPC that has no PSA peering for `servicenetworking.googleapis.com`.
47
+ * Surface the precondition.
48
+ * 3. **Invalid tier** — typo'd `db-custom-…` or one outside the
49
+ * project's allow-list. Pass the underlying message through with
50
+ * a pointer to the tier catalogue.
51
+ *
52
+ * Anything else propagates verbatim — the underlying GCP message is
53
+ * usually clear enough.
54
+ *
55
+ * @see https://cloud.google.com/sql/docs/postgres/instance-settings
56
+ */
57
+ export declare const reshapeBadRequest: (kind: "Instance" | "Database" | "User", op: "insert" | "patch" | "update" | "delete") => (e: {
58
+ message?: string;
59
+ }) => Effect.Effect<never, ConfigError>;
60
+ //# sourceMappingURL=Validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Validation.d.ts","sourceRoot":"","sources":["../../src/Sqladmin/Validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAgC7D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CASjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAOjC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;CACtB,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAiBlC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,iBAAiB,GAC3B,MAAM,UAAU,GAAG,UAAU,GAAG,MAAM,EAAE,IAAI,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,MACpF,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAkB1D,CAAC"}
@@ -0,0 +1,125 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as Effect from "effect/Effect";
3
+ import { isIamUserType } from "./Types.js";
4
+ /**
5
+ * Plan-time validation for Cloud SQL resource props. Failing fast with
6
+ * a typed `ConfigError` is friendlier than letting the user wait for
7
+ * Cloud SQL to reject the request, and unlike server-side errors these
8
+ * surface before any state mutation happens.
9
+ *
10
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/instances
11
+ */
12
+ /**
13
+ * Instance name regex per
14
+ * <https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/instances#SqlInstance>:
15
+ * 1–98 lowercase letters/digits/hyphens, must begin with a letter and
16
+ * not end with a hyphen.
17
+ *
18
+ * @internal
19
+ */
20
+ const INSTANCE_NAME_RE = /^[a-z]([-a-z0-9]*[a-z0-9])?$/;
21
+ /**
22
+ * Database name length cap per
23
+ * <https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/databases#Database>:
24
+ * 1–64 chars. Postgres has additional character constraints (no NUL,
25
+ * no embedded quotes) but the API rejects those, and they'd require
26
+ * dialect-specific parsing here.
27
+ *
28
+ * @internal
29
+ */
30
+ const DATABASE_NAME_MAX = 64;
31
+ /**
32
+ * Validate a Cloud SQL instance name. Returns a `ConfigError` on the
33
+ * failure channel if the name is invalid, otherwise succeeds.
34
+ *
35
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/instances#SqlInstance
36
+ */
37
+ export const validateInstanceName = (name) => {
38
+ if (INSTANCE_NAME_RE.test(name) && name.length >= 1 && name.length <= 98) {
39
+ return Effect.void;
40
+ }
41
+ return Effect.fail(new ConfigError({
42
+ message: `Cloud SQL instance name ${JSON.stringify(name)} is invalid: must match /^[a-z]([-a-z0-9]*[a-z0-9])?$/ (1–98 lowercase letters/digits/hyphens, start with letter, no trailing hyphen).`,
43
+ }));
44
+ };
45
+ /**
46
+ * Validate a Cloud SQL database name (1–64 chars, non-empty).
47
+ *
48
+ * @see https://cloud.google.com/sql/docs/postgres/admin-api/rest/v1/databases#Database
49
+ */
50
+ export const validateDatabaseName = (name) => {
51
+ if (name.length >= 1 && name.length <= DATABASE_NAME_MAX)
52
+ return Effect.void;
53
+ return Effect.fail(new ConfigError({
54
+ message: `Cloud SQL database name ${JSON.stringify(name)} is invalid: must be 1–${DATABASE_NAME_MAX} characters.`,
55
+ }));
56
+ };
57
+ /**
58
+ * Validate a Cloud SQL user shape — primarily that the password/type
59
+ * combination is consistent:
60
+ *
61
+ * - `BUILT_IN` users MUST carry a password.
62
+ * - Any IAM user type (`CLOUD_IAM_USER`, `CLOUD_IAM_SERVICE_ACCOUNT`,
63
+ * `CLOUD_IAM_GROUP*`, `ENTRAID_USER`) MUST NOT carry a password —
64
+ * the IAM principal is authenticated by token exchange.
65
+ *
66
+ * Other types from the open tail of the enum (forward-compat) skip
67
+ * the password check.
68
+ *
69
+ * @see https://cloud.google.com/sql/docs/postgres/users
70
+ * @see https://cloud.google.com/sql/docs/postgres/iam-authentication
71
+ */
72
+ export const validateUser = (args) => {
73
+ const type = args.type ?? "BUILT_IN";
74
+ if (isIamUserType(type) && args.hasPassword) {
75
+ return Effect.fail(new ConfigError({
76
+ message: `Cloud SQL user ${JSON.stringify(args.name)} has type ${JSON.stringify(type)} (IAM-backed) but a password was supplied. IAM users authenticate via the Cloud SQL Auth Proxy / IAM token exchange — drop the \`password\` field.`,
77
+ }));
78
+ }
79
+ if (type === "BUILT_IN" && !args.hasPassword) {
80
+ return Effect.fail(new ConfigError({
81
+ message: `Cloud SQL user ${JSON.stringify(args.name)} has type "BUILT_IN" but no password was supplied. BUILT_IN users require a password — pass \`password: Redacted.make("...")\` or switch to an IAM type.`,
82
+ }));
83
+ }
84
+ return Effect.void;
85
+ };
86
+ /**
87
+ * Reshape a `BadRequest` from a Cloud SQL Admin create/patch/delete
88
+ * into a `ConfigError` with a remediation hint for the top failure
89
+ * modes:
90
+ *
91
+ * 1. **Billing not enabled** — Cloud SQL refuses to provision against
92
+ * a project without billing. Common right after `ApiEnable` lands
93
+ * but before billing reconciles in a fresh project.
94
+ * 2. **Private network not set up** — `privateNetwork` references a
95
+ * VPC that has no PSA peering for `servicenetworking.googleapis.com`.
96
+ * Surface the precondition.
97
+ * 3. **Invalid tier** — typo'd `db-custom-…` or one outside the
98
+ * project's allow-list. Pass the underlying message through with
99
+ * a pointer to the tier catalogue.
100
+ *
101
+ * Anything else propagates verbatim — the underlying GCP message is
102
+ * usually clear enough.
103
+ *
104
+ * @see https://cloud.google.com/sql/docs/postgres/instance-settings
105
+ */
106
+ export const reshapeBadRequest = (kind, op) => (e) => {
107
+ const underlying = e.message ?? `unknown 400 from ${kind} ${op}`;
108
+ let hint = "";
109
+ if (/billing/i.test(underlying)) {
110
+ hint =
111
+ " Cloud SQL requires billing to be enabled on the project. Attach a billing account (see `GCP.Project({ billingAccount })`) and retry.";
112
+ }
113
+ else if (/private.*service.*access|servicenetworking|peering/i.test(underlying)) {
114
+ hint =
115
+ " The host VPC needs a Private Services Access (PSA) peering with `servicenetworking.googleapis.com` before a private-IP Cloud SQL instance can attach. Provision a `GCP.GlobalAddress` (purpose=VPC_PEERING) and a `GCP.PsaConnection` on the VPC first.";
116
+ }
117
+ else if (/tier|machine.*type/i.test(underlying)) {
118
+ hint =
119
+ " Check the tier identifier against https://cloud.google.com/sql/docs/postgres/instance-settings — and remember that Enterprise Plus tiers (`db-perf-optimized-*`) require `edition: \"ENTERPRISE_PLUS\"`.";
120
+ }
121
+ return Effect.fail(new ConfigError({
122
+ message: `Cloud SQL ${kind} ${op} rejected: ${underlying}.${hint}`,
123
+ }));
124
+ };
125
+ //# sourceMappingURL=Validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Validation.js","sourceRoot":"","sources":["../../src/Sqladmin/Validation.ts"],"names":[],"mappings":"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"}