@microagi/alchemy-gcp 0.3.0 → 0.5.1

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 (91) hide show
  1. package/CHANGELOG.md +124 -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 +256 -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/Auth/Credentials.d.ts +2 -1
  23. package/lib/Auth/Credentials.d.ts.map +1 -1
  24. package/lib/Auth/Credentials.js +3 -2
  25. package/lib/Auth/Credentials.js.map +1 -1
  26. package/lib/CloudResourceManager/Project.d.ts +1 -1
  27. package/lib/Compute/GlobalAddress.d.ts +1 -1
  28. package/lib/Compute/Network.d.ts +1 -1
  29. package/lib/Compute/SharedVpcHost.d.ts +1 -1
  30. package/lib/Compute/SharedVpcServiceProject.d.ts +1 -1
  31. package/lib/Compute/Subnetwork.d.ts +1 -1
  32. package/lib/Container/Cluster.d.ts +1 -1
  33. package/lib/Container/NodePool.d.ts +1 -1
  34. package/lib/ManagedLustre/Instance.d.ts +1 -1
  35. package/lib/Providers.d.ts +1 -1
  36. package/lib/Providers.d.ts.map +1 -1
  37. package/lib/Providers.js +9 -1
  38. package/lib/Providers.js.map +1 -1
  39. package/lib/Run/Job.d.ts +1 -1
  40. package/lib/Run/Service.d.ts +1 -1
  41. package/lib/ServiceNetworking/PsaConnection.d.ts +1 -1
  42. package/lib/ServiceUsage/ApiEnable.d.ts +1 -1
  43. package/lib/Sqladmin/Database.d.ts +82 -0
  44. package/lib/Sqladmin/Database.d.ts.map +1 -0
  45. package/lib/Sqladmin/Database.js +87 -0
  46. package/lib/Sqladmin/Database.js.map +1 -0
  47. package/lib/Sqladmin/Instance.d.ts +234 -0
  48. package/lib/Sqladmin/Instance.d.ts.map +1 -0
  49. package/lib/Sqladmin/Instance.js +251 -0
  50. package/lib/Sqladmin/Instance.js.map +1 -0
  51. package/lib/Sqladmin/Operations.d.ts +41 -0
  52. package/lib/Sqladmin/Operations.d.ts.map +1 -0
  53. package/lib/Sqladmin/Operations.js +42 -0
  54. package/lib/Sqladmin/Operations.js.map +1 -0
  55. package/lib/Sqladmin/Types.d.ts +82 -0
  56. package/lib/Sqladmin/Types.d.ts.map +1 -0
  57. package/lib/Sqladmin/Types.js +28 -0
  58. package/lib/Sqladmin/Types.js.map +1 -0
  59. package/lib/Sqladmin/User.d.ts +110 -0
  60. package/lib/Sqladmin/User.d.ts.map +1 -0
  61. package/lib/Sqladmin/User.js +156 -0
  62. package/lib/Sqladmin/User.js.map +1 -0
  63. package/lib/Sqladmin/Validation.d.ts +60 -0
  64. package/lib/Sqladmin/Validation.d.ts.map +1 -0
  65. package/lib/Sqladmin/Validation.js +125 -0
  66. package/lib/Sqladmin/Validation.js.map +1 -0
  67. package/lib/Sqladmin/index.d.ts +9 -0
  68. package/lib/Sqladmin/index.d.ts.map +1 -0
  69. package/lib/Sqladmin/index.js +5 -0
  70. package/lib/Sqladmin/index.js.map +1 -0
  71. package/lib/Tags.d.ts +4 -4
  72. package/lib/index.d.ts +2 -0
  73. package/lib/index.d.ts.map +1 -1
  74. package/lib/index.js +2 -0
  75. package/lib/index.js.map +1 -1
  76. package/package.json +2 -2
  77. package/src/ArtifactRegistry/Operations.ts +79 -0
  78. package/src/ArtifactRegistry/Repository.ts +628 -0
  79. package/src/ArtifactRegistry/Types.ts +49 -0
  80. package/src/ArtifactRegistry/Validation.ts +112 -0
  81. package/src/ArtifactRegistry/index.ts +10 -0
  82. package/src/Auth/Credentials.ts +3 -2
  83. package/src/Providers.ts +15 -0
  84. package/src/Sqladmin/Database.ts +209 -0
  85. package/src/Sqladmin/Instance.ts +620 -0
  86. package/src/Sqladmin/Operations.ts +73 -0
  87. package/src/Sqladmin/Types.ts +101 -0
  88. package/src/Sqladmin/User.ts +333 -0
  89. package/src/Sqladmin/Validation.ts +148 -0
  90. package/src/Sqladmin/index.ts +19 -0
  91. package/src/index.ts +2 -0
@@ -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":"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"}
@@ -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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"}
@@ -0,0 +1,9 @@
1
+ export { SqlDatabase, SqlDatabaseProvider } from "./Database.ts";
2
+ export type { SqlDatabaseAttributes, SqlDatabaseProps } from "./Database.ts";
3
+ export { SqlInstance, SqlInstanceProvider } from "./Instance.ts";
4
+ export type { SqlInstanceAttributes, SqlInstanceIpAddress, SqlInstanceProps, } from "./Instance.ts";
5
+ export { isIamUserType } from "./Types.ts";
6
+ export type { PostgresVersion, SqlActivationPolicy, SqlAvailabilityType, SqlDataDiskType, SqlEdition, SqlUserType, } from "./Types.ts";
7
+ export { SqlUser, SqlUserProvider } from "./User.ts";
8
+ export type { SqlUserAttributes, SqlUserProps } from "./User.ts";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Sqladmin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACrD,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { SqlDatabase, SqlDatabaseProvider } from "./Database.js";
2
+ export { SqlInstance, SqlInstanceProvider } from "./Instance.js";
3
+ export { isIamUserType } from "./Types.js";
4
+ export { SqlUser, SqlUserProvider } from "./User.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Sqladmin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAMjE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAS3C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
package/lib/Tags.d.ts CHANGED
@@ -28,25 +28,25 @@ export declare const gcpInternalLabels: (id: string) => Effect.Effect<{
28
28
  alchemy_app: string;
29
29
  alchemy_stage: string;
30
30
  alchemy_id: string;
31
- }, never, Stage | Stack>;
31
+ }, never, Stack | Stage>;
32
32
  /**
33
33
  * True when `labels` contains all three alchemy-internal keys with
34
34
  * values matching this stack/stage/id. Used in `read` to decide
35
35
  * adoption ownership.
36
36
  */
37
- export declare const hasAlchemyLabels: (id: string, labels: Record<string, string> | undefined) => Effect.Effect<boolean, never, Stage | Stack>;
37
+ export declare const hasAlchemyLabels: (id: string, labels: Record<string, string> | undefined) => Effect.Effect<boolean, never, Stack | Stage>;
38
38
  export { LABEL_KEY_APP as ALCHEMY_LABEL_APP, LABEL_KEY_STAGE as ALCHEMY_LABEL_STAGE, LABEL_KEY_ID as ALCHEMY_LABEL_ID, };
39
39
  /**
40
40
  * Compose `[alchemy:...] <userDescription?>`. Pass through to the
41
41
  * resource's `description` body field at create time.
42
42
  */
43
- export declare const gcpAlchemyDescription: (id: string, userDescription?: string | undefined) => Effect.Effect<string, never, Stage | Stack>;
43
+ export declare const gcpAlchemyDescription: (id: string, userDescription?: string | undefined) => Effect.Effect<string, never, Stack | Stage>;
44
44
  /**
45
45
  * True when `description` begins with an alchemy marker matching this
46
46
  * stack/stage/id. Used in `read` for resources that lack a labels
47
47
  * field.
48
48
  */
49
- export declare const descriptionHasAlchemyMarker: (id: string, description: string | undefined) => Effect.Effect<boolean, never, Stage | Stack>;
49
+ export declare const descriptionHasAlchemyMarker: (id: string, description: string | undefined) => Effect.Effect<boolean, never, Stack | Stage>;
50
50
  /**
51
51
  * Strip the leading alchemy marker (if any) and return what remains —
52
52
  * used when surfacing the user-visible description back through
package/lib/index.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  export { Credentials, fromADC, fromAuthProvider } from "./Auth/Credentials.ts";
2
2
  export { GCP_AUTH_PROVIDER_NAME, GCPAuth, } from "./Auth/AuthProvider.ts";
3
3
  export type { GCPAuthConfig, GCPResolvedCredentials, } from "./Auth/AuthProvider.ts";
4
+ export * from "./ArtifactRegistry/index.ts";
4
5
  export * from "./CloudResourceManager/index.ts";
5
6
  export * from "./Compute/index.ts";
6
7
  export * from "./Container/index.ts";
7
8
  export * from "./ManagedLustre/index.ts";
8
9
  export * from "./Run/index.ts";
9
10
  export * from "./ServiceNetworking/index.ts";
11
+ export * from "./Sqladmin/index.ts";
10
12
  export * from "./ServiceUsage/index.ts";
11
13
  export * from "./Providers.ts";
12
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EACL,sBAAsB,EACtB,OAAO,GACR,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,aAAa,EACb,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,cAAc,iCAAiC,CAAC;AAChD,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EACL,sBAAsB,EACtB,OAAO,GACR,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,aAAa,EACb,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
package/lib/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  export { Credentials, fromADC, fromAuthProvider } from "./Auth/Credentials.js";
2
2
  export { GCP_AUTH_PROVIDER_NAME, GCPAuth, } from "./Auth/AuthProvider.js";
3
+ export * from "./ArtifactRegistry/index.js";
3
4
  export * from "./CloudResourceManager/index.js";
4
5
  export * from "./Compute/index.js";
5
6
  export * from "./Container/index.js";
6
7
  export * from "./ManagedLustre/index.js";
7
8
  export * from "./Run/index.js";
8
9
  export * from "./ServiceNetworking/index.js";
10
+ export * from "./Sqladmin/index.js";
9
11
  export * from "./ServiceUsage/index.js";
10
12
  export * from "./Providers.js";
11
13
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EACL,sBAAsB,EACtB,OAAO,GACR,MAAM,wBAAwB,CAAC;AAKhC,cAAc,iCAAiC,CAAC;AAChD,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EACL,sBAAsB,EACtB,OAAO,GACR,MAAM,wBAAwB,CAAC;AAKhC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@microagi/alchemy-gcp",
3
- "version": "0.3.0",
4
- "description": "GCP provider for Alchemy v2 (Effect-based IaC). Resources for Project, Cluster, NodePool, Compute, ManagedLustre, ServiceUsage, ServiceNetworking, Cloud Run (Service + Job + IAM), with ADC-backed credentials and target-side IAM bindings.",
3
+ "version": "0.5.1",
4
+ "description": "GCP provider for Alchemy v2 (Effect-based IaC). Resources for Project, Cluster, NodePool, Compute, ManagedLustre, ServiceUsage, ServiceNetworking, Cloud Run (Service + Job + IAM), Cloud SQL (Instance + Database + User with IAM database authn), Artifact Registry (Docker repositories, standard + remote pull-through caches), with ADC-backed credentials and target-side IAM bindings.",
5
5
  "keywords": [
6
6
  "alchemy",
7
7
  "alchemy-effect",
@@ -0,0 +1,79 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as ar from "@distilled.cloud/gcp/artifactregistry-v1";
3
+ import type { ScopedPlanStatusSession } from "alchemy/Cli/Cli";
4
+ import * as Duration from "effect/Duration";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Schedule from "effect/Schedule";
7
+
8
+ /**
9
+ * Resolved callable signature of `ar.getProjectsLocationsOperations`.
10
+ *
11
+ * `ar.getProjectsLocationsOperations` is itself an
12
+ * `Effect<callable, never, Credentials | HttpClient>`, so
13
+ * `Effect.Success` extracts the callable type. Using a derived alias
14
+ * keeps the helper aligned with the SDK without us hand-writing the
15
+ * input/output/error union, which would drift if the patch set changes.
16
+ */
17
+ type GetOperations = Effect.Success<typeof ar.getProjectsLocationsOperations>;
18
+
19
+ /**
20
+ * Build the Artifact Registry long-running-operation polling helper.
21
+ *
22
+ * Artifact Registry `Operation`s use the standard
23
+ * `GoogleLongrunningOperation` shape — doneness is `.done === true`
24
+ * (NOT `.status === "DONE"` like the GKE Container API and NOT
25
+ * Sqladmin's tri-state `.status`). Verified at
26
+ * `vendor/distilled/packages/gcp/src/services/artifactregistry-v1.ts:308–328`.
27
+ *
28
+ * Operation names returned by `artifactregistry-v1`
29
+ * (`createProjectsLocationsRepositories`,
30
+ * `patchProjectsLocationsRepositories`,
31
+ * `deleteProjectsLocationsRepositories`) are already fully qualified
32
+ * (`projects/{p}/locations/{l}/operations/{id}`), so callers pass them
33
+ * straight through to `getProjectsLocationsOperations` — no qualify
34
+ * dance needed (unlike Container, which returns bare ids).
35
+ *
36
+ * Schedule: exponential 1s → 1.5× growth, capped per-poll at 10s via
37
+ * `Schedule.either`, then a hard count cap of 60 retries → ~10 min wall
38
+ * ceiling. Repository CRUD is fast (seconds); the only long-running
39
+ * case is a delete on a repository with many cached images, where AR
40
+ * has to GC the underlying blobs.
41
+ *
42
+ * The helper is a factory — the caller resolves
43
+ * `ar.getProjectsLocationsOperations` once at provider construction
44
+ * and passes the resulting callable here, so we never re-resolve
45
+ * services on each await.
46
+ */
47
+ export const makeAwaitOperation = (getOperations: GetOperations) =>
48
+ Effect.fn(function* (
49
+ operationName: string,
50
+ session: ScopedPlanStatusSession,
51
+ ) {
52
+ const op = yield* getOperations({ name: operationName }).pipe(
53
+ Effect.flatMap((current) =>
54
+ current.done === true
55
+ ? Effect.succeed(current)
56
+ : Effect.fail({ _tag: "OperationPending" as const }),
57
+ ),
58
+ Effect.retry({
59
+ while: (e: { _tag?: string }) => e?._tag === "OperationPending",
60
+ schedule: Schedule.exponential(Duration.seconds(1), 1.5).pipe(
61
+ Schedule.either(Schedule.spaced(Duration.seconds(10))),
62
+ Schedule.both(Schedule.recurs(60)),
63
+ Schedule.tapOutput(() =>
64
+ session.note(
65
+ `Waiting for Artifact Registry operation ${operationName}…`,
66
+ ),
67
+ ),
68
+ ),
69
+ }),
70
+ );
71
+ if (op.error) {
72
+ return yield* new ConfigError({
73
+ message: `Artifact Registry operation ${operationName} failed: ${
74
+ op.error.message ?? JSON.stringify(op.error)
75
+ }`,
76
+ });
77
+ }
78
+ return op;
79
+ });