@microagi/alchemy-gcp 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +88 -0
- package/lib/Auth/AuthProvider.d.ts +48 -0
- package/lib/Auth/AuthProvider.d.ts.map +1 -0
- package/lib/Auth/AuthProvider.js +84 -0
- package/lib/Auth/AuthProvider.js.map +1 -0
- package/lib/Auth/Credentials.d.ts +28 -0
- package/lib/Auth/Credentials.d.ts.map +1 -0
- package/lib/Auth/Credentials.js +41 -0
- package/lib/Auth/Credentials.js.map +1 -0
- package/lib/CloudResourceManager/Project.d.ts +143 -0
- package/lib/CloudResourceManager/Project.d.ts.map +1 -0
- package/lib/CloudResourceManager/Project.js +272 -0
- package/lib/CloudResourceManager/Project.js.map +1 -0
- package/lib/CloudResourceManager/index.d.ts +3 -0
- package/lib/CloudResourceManager/index.d.ts.map +1 -0
- package/lib/CloudResourceManager/index.js +2 -0
- package/lib/CloudResourceManager/index.js.map +1 -0
- package/lib/Compute/GlobalAddress.d.ts +101 -0
- package/lib/Compute/GlobalAddress.d.ts.map +1 -0
- package/lib/Compute/GlobalAddress.js +134 -0
- package/lib/Compute/GlobalAddress.js.map +1 -0
- package/lib/Compute/Network.d.ts +114 -0
- package/lib/Compute/Network.d.ts.map +1 -0
- package/lib/Compute/Network.js +145 -0
- package/lib/Compute/Network.js.map +1 -0
- package/lib/Compute/Operations.d.ts +34 -0
- package/lib/Compute/Operations.d.ts.map +1 -0
- package/lib/Compute/Operations.js +62 -0
- package/lib/Compute/Operations.js.map +1 -0
- package/lib/Compute/SharedVpcHost.d.ts +44 -0
- package/lib/Compute/SharedVpcHost.d.ts.map +1 -0
- package/lib/Compute/SharedVpcHost.js +71 -0
- package/lib/Compute/SharedVpcHost.js.map +1 -0
- package/lib/Compute/SharedVpcServiceProject.d.ts +46 -0
- package/lib/Compute/SharedVpcServiceProject.d.ts.map +1 -0
- package/lib/Compute/SharedVpcServiceProject.js +96 -0
- package/lib/Compute/SharedVpcServiceProject.js.map +1 -0
- package/lib/Compute/Subnetwork.d.ts +108 -0
- package/lib/Compute/Subnetwork.d.ts.map +1 -0
- package/lib/Compute/Subnetwork.js +201 -0
- package/lib/Compute/Subnetwork.js.map +1 -0
- package/lib/Compute/index.d.ts +6 -0
- package/lib/Compute/index.d.ts.map +1 -0
- package/lib/Compute/index.js +6 -0
- package/lib/Compute/index.js.map +1 -0
- package/lib/Container/Cluster.d.ts +216 -0
- package/lib/Container/Cluster.d.ts.map +1 -0
- package/lib/Container/Cluster.js +326 -0
- package/lib/Container/Cluster.js.map +1 -0
- package/lib/Container/NodePool.d.ts +214 -0
- package/lib/Container/NodePool.d.ts.map +1 -0
- package/lib/Container/NodePool.js +344 -0
- package/lib/Container/NodePool.js.map +1 -0
- package/lib/Container/Operations.d.ts +50 -0
- package/lib/Container/Operations.d.ts.map +1 -0
- package/lib/Container/Operations.js +51 -0
- package/lib/Container/Operations.js.map +1 -0
- package/lib/Container/index.d.ts +5 -0
- package/lib/Container/index.d.ts.map +1 -0
- package/lib/Container/index.js +3 -0
- package/lib/Container/index.js.map +1 -0
- package/lib/Parallelstore/Instance.d.ts +119 -0
- package/lib/Parallelstore/Instance.d.ts.map +1 -0
- package/lib/Parallelstore/Instance.js +180 -0
- package/lib/Parallelstore/Instance.js.map +1 -0
- package/lib/Parallelstore/index.d.ts +2 -0
- package/lib/Parallelstore/index.d.ts.map +1 -0
- package/lib/Parallelstore/index.js +2 -0
- package/lib/Parallelstore/index.js.map +1 -0
- package/lib/Providers.d.ts +24 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +51 -0
- package/lib/Providers.js.map +1 -0
- package/lib/ServiceNetworking/PsaConnection.d.ts +84 -0
- package/lib/ServiceNetworking/PsaConnection.d.ts.map +1 -0
- package/lib/ServiceNetworking/PsaConnection.js +130 -0
- package/lib/ServiceNetworking/PsaConnection.js.map +1 -0
- package/lib/ServiceNetworking/index.d.ts +2 -0
- package/lib/ServiceNetworking/index.d.ts.map +1 -0
- package/lib/ServiceNetworking/index.js +2 -0
- package/lib/ServiceNetworking/index.js.map +1 -0
- package/lib/ServiceUsage/ApiEnable.d.ts +78 -0
- package/lib/ServiceUsage/ApiEnable.d.ts.map +1 -0
- package/lib/ServiceUsage/ApiEnable.js +132 -0
- package/lib/ServiceUsage/ApiEnable.js.map +1 -0
- package/lib/ServiceUsage/index.d.ts +3 -0
- package/lib/ServiceUsage/index.d.ts.map +1 -0
- package/lib/ServiceUsage/index.js +2 -0
- package/lib/ServiceUsage/index.js.map +1 -0
- package/lib/Tags.d.ts +57 -0
- package/lib/Tags.d.ts.map +1 -0
- package/lib/Tags.js +106 -0
- package/lib/Tags.js.map +1 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/package.json +70 -0
- package/src/Auth/AuthProvider.ts +180 -0
- package/src/Auth/Credentials.ts +69 -0
- package/src/CloudResourceManager/Project.ts +517 -0
- package/src/CloudResourceManager/index.ts +2 -0
- package/src/Compute/GlobalAddress.ts +283 -0
- package/src/Compute/Network.ts +306 -0
- package/src/Compute/Operations.ts +108 -0
- package/src/Compute/SharedVpcHost.ts +141 -0
- package/src/Compute/SharedVpcServiceProject.ts +185 -0
- package/src/Compute/Subnetwork.ts +375 -0
- package/src/Compute/index.ts +5 -0
- package/src/Container/Cluster.ts +599 -0
- package/src/Container/NodePool.ts +620 -0
- package/src/Container/Operations.ts +88 -0
- package/src/Container/index.ts +8 -0
- package/src/Parallelstore/Instance.ts +371 -0
- package/src/Parallelstore/index.ts +1 -0
- package/src/Providers.ts +84 -0
- package/src/ServiceNetworking/PsaConnection.ts +269 -0
- package/src/ServiceNetworking/index.ts +1 -0
- package/src/ServiceUsage/ApiEnable.ts +267 -0
- package/src/ServiceUsage/index.ts +2 -0
- package/src/Tags.ts +130 -0
- package/src/index.ts +16 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/gcp";
|
|
2
|
+
import * as sn from "@distilled.cloud/gcp/servicenetworking-v1";
|
|
3
|
+
import { Resource } from "alchemy";
|
|
4
|
+
import { deepEqual, isResolved } from "alchemy/Diff";
|
|
5
|
+
import * as Provider from "alchemy/Provider";
|
|
6
|
+
import * as Duration from "effect/Duration";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Schedule from "effect/Schedule";
|
|
9
|
+
export const PsaConnection = Resource("GCP.PsaConnection");
|
|
10
|
+
const DEFAULT_SERVICE = "servicenetworking.googleapis.com";
|
|
11
|
+
const serviceParent = (service) => service.startsWith("services/") ? service : `services/${service}`;
|
|
12
|
+
export const PsaConnectionProvider = () => Provider.effect(PsaConnection, Effect.gen(function* () {
|
|
13
|
+
const listConnections = yield* sn.listServicesConnections;
|
|
14
|
+
const createConnection = yield* sn.createServicesConnections;
|
|
15
|
+
const patchConnection = yield* sn.patchServicesConnections;
|
|
16
|
+
const deleteConnection = yield* sn.deleteConnectionServicesConnections;
|
|
17
|
+
const getOperations = yield* sn.getOperations;
|
|
18
|
+
const awaitOperation = Effect.fn(function* (operationName, session) {
|
|
19
|
+
const op = yield* getOperations({ name: operationName }).pipe(Effect.flatMap((current) => current.done === true
|
|
20
|
+
? Effect.succeed(current)
|
|
21
|
+
: Effect.fail({ _tag: "OperationPending" })), Effect.retry({
|
|
22
|
+
while: (e) => e?._tag === "OperationPending",
|
|
23
|
+
schedule: Schedule.exponential(Duration.seconds(2), 1.5).pipe(Schedule.either(Schedule.spaced(Duration.seconds(15))),
|
|
24
|
+
// PSA peering creates can take 5–10 min while the
|
|
25
|
+
// service producer provisions its side. 80 × 15s ≈ 20 min.
|
|
26
|
+
Schedule.both(Schedule.recurs(80)), Schedule.tapOutput(() => session.note(`Waiting for ServiceNetworking operation ${operationName}…`))),
|
|
27
|
+
}));
|
|
28
|
+
if (op.error) {
|
|
29
|
+
return yield* new ConfigError({
|
|
30
|
+
message: `ServiceNetworking operation ${operationName} failed: ${op.error.message ?? JSON.stringify(op.error)}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return op;
|
|
34
|
+
});
|
|
35
|
+
// List connections in the consumer VPC and return the matching
|
|
36
|
+
// one (there can be at most one connection per `(network, service)`
|
|
37
|
+
// pair). 404/403 collapse to "not present".
|
|
38
|
+
const observe = (parent, network) => listConnections({ parent, network }).pipe(Effect.map((res) => (res.connections ?? []).find((c) => c.network === network)), Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
|
|
39
|
+
return {
|
|
40
|
+
stables: ["network", "serviceName", "peering"],
|
|
41
|
+
diff: Effect.fn(function* ({ news, olds = {} }) {
|
|
42
|
+
if (!isResolved(news))
|
|
43
|
+
return undefined;
|
|
44
|
+
const oldsService = olds.service ?? DEFAULT_SERVICE;
|
|
45
|
+
const newsService = news.service ?? DEFAULT_SERVICE;
|
|
46
|
+
if ((olds.network !== undefined && olds.network !== news.network) ||
|
|
47
|
+
(olds.service !== undefined && oldsService !== newsService)) {
|
|
48
|
+
return { action: "replace" };
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}),
|
|
52
|
+
reconcile: Effect.fn(function* ({ news, session }) {
|
|
53
|
+
const service = news.service ?? DEFAULT_SERVICE;
|
|
54
|
+
const parent = serviceParent(service);
|
|
55
|
+
const desired = [...news.reservedPeeringRanges].sort();
|
|
56
|
+
let observed = yield* observe(parent, news.network);
|
|
57
|
+
if (!observed) {
|
|
58
|
+
const op = yield* createConnection({
|
|
59
|
+
parent,
|
|
60
|
+
body: {
|
|
61
|
+
network: news.network,
|
|
62
|
+
reservedPeeringRanges: desired,
|
|
63
|
+
},
|
|
64
|
+
}).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
|
|
65
|
+
if (op?.name)
|
|
66
|
+
yield* awaitOperation(op.name, session);
|
|
67
|
+
observed = yield* observe(parent, news.network);
|
|
68
|
+
}
|
|
69
|
+
if (!observed) {
|
|
70
|
+
return yield* new ConfigError({
|
|
71
|
+
message: `PSA connection on ${news.network} did not appear after create.`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Sync reserved ranges. `force=true` is required when removing
|
|
75
|
+
// a previously-assigned range; we pass it unconditionally to
|
|
76
|
+
// keep the patch idempotent regardless of which direction the
|
|
77
|
+
// diff went.
|
|
78
|
+
const observedRanges = [...(observed.reservedPeeringRanges ?? [])].sort();
|
|
79
|
+
if (!deepEqual(observedRanges, desired) && observed.peering) {
|
|
80
|
+
const op = yield* patchConnection({
|
|
81
|
+
name: `${parent}/connections/${observed.peering}`,
|
|
82
|
+
force: true,
|
|
83
|
+
updateMask: "reservedPeeringRanges",
|
|
84
|
+
body: {
|
|
85
|
+
network: news.network,
|
|
86
|
+
reservedPeeringRanges: desired,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
if (op.name)
|
|
90
|
+
yield* awaitOperation(op.name, session);
|
|
91
|
+
observed = yield* observe(parent, news.network);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
network: news.network,
|
|
95
|
+
serviceName: parent,
|
|
96
|
+
peering: observed?.peering ?? "",
|
|
97
|
+
reservedPeeringRanges: observed?.reservedPeeringRanges ?? desired,
|
|
98
|
+
};
|
|
99
|
+
}),
|
|
100
|
+
delete: Effect.fn(function* ({ output, session }) {
|
|
101
|
+
if (!output.peering)
|
|
102
|
+
return; // Never fully created.
|
|
103
|
+
yield* deleteConnection({
|
|
104
|
+
name: `${output.serviceName}/connections/${output.peering}`,
|
|
105
|
+
body: { consumerNetwork: output.network },
|
|
106
|
+
}).pipe(Effect.flatMap((op) => op.name ? awaitOperation(op.name, session) : Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void));
|
|
107
|
+
}),
|
|
108
|
+
read: Effect.fn(function* ({ output, olds }) {
|
|
109
|
+
const network = output?.network ?? olds?.network;
|
|
110
|
+
const service = olds?.service ?? DEFAULT_SERVICE;
|
|
111
|
+
const parent = output?.serviceName ?? serviceParent(service);
|
|
112
|
+
if (!network)
|
|
113
|
+
return undefined;
|
|
114
|
+
const observed = yield* observe(parent, network);
|
|
115
|
+
if (!observed)
|
|
116
|
+
return undefined;
|
|
117
|
+
// No ownership concept: PSA connections are unique per
|
|
118
|
+
// `(network, service)`, and the operation can only be
|
|
119
|
+
// performed by the consumer-VPC project owner. Adoption is
|
|
120
|
+
// permissive — same stance as `ApiEnable`.
|
|
121
|
+
return {
|
|
122
|
+
network,
|
|
123
|
+
serviceName: parent,
|
|
124
|
+
peering: observed.peering ?? "",
|
|
125
|
+
reservedPeeringRanges: observed.reservedPeeringRanges ?? [],
|
|
126
|
+
};
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
}));
|
|
130
|
+
//# sourceMappingURL=PsaConnection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PsaConnection.js","sourceRoot":"","sources":["../../src/ServiceNetworking/PsaConnection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ServiceNetworking/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ServiceNetworking/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Resource } from "alchemy";
|
|
2
|
+
import * as Provider from "alchemy/Provider";
|
|
3
|
+
import type * as GCP from "../Providers.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Enable a Google Cloud API on a project (`serviceusage.googleapis.com`
|
|
6
|
+
* `services.enable`). Required before any operation against the
|
|
7
|
+
* underlying API will succeed — e.g. a fresh `GCP.Project` cannot host
|
|
8
|
+
* a `GCP.Cluster` until `container.googleapis.com` is enabled.
|
|
9
|
+
*
|
|
10
|
+
* The resource is keyed by `(project, service)`; both are immutable —
|
|
11
|
+
* changing either replaces.
|
|
12
|
+
*
|
|
13
|
+
* `delete` calls `services.disable`, which GCP rejects with HTTP 400
|
|
14
|
+
* (`FAILED_PRECONDITION`) if the service is already disabled or has
|
|
15
|
+
* dependent services in use. We treat "already disabled" as success
|
|
16
|
+
* (idempotent teardown). Other 400s propagate so the user sees the
|
|
17
|
+
* real reason (typically: another service depends on this one).
|
|
18
|
+
*/
|
|
19
|
+
export type ApiEnableProps = {
|
|
20
|
+
/** GCP project ID hosting the API enablement. Immutable — replace. */
|
|
21
|
+
project: string;
|
|
22
|
+
/**
|
|
23
|
+
* Fully-qualified service name, e.g. `container.googleapis.com`,
|
|
24
|
+
* `compute.googleapis.com`, `iam.googleapis.com`. Immutable — replace.
|
|
25
|
+
*/
|
|
26
|
+
service: string;
|
|
27
|
+
};
|
|
28
|
+
export type ApiEnableAttributes = {
|
|
29
|
+
/** GCP project ID, threaded through from props. */
|
|
30
|
+
project: string;
|
|
31
|
+
/** Service name, threaded through from props. */
|
|
32
|
+
service: string;
|
|
33
|
+
/** Resource name in the form `projects/{project}/services/{service}`. */
|
|
34
|
+
name: string;
|
|
35
|
+
/** Lifecycle state — `"ENABLED"` once the LRO completes. */
|
|
36
|
+
state: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* @section Enabling APIs
|
|
40
|
+
*
|
|
41
|
+
* **Dependency edges are explicit.** Alchemy sequences resources by the
|
|
42
|
+
* Output references they consume. To make a downstream resource (e.g.
|
|
43
|
+
* `GCP.Cluster`) wait for the API enable, route its `project` prop
|
|
44
|
+
* through `apiEnable.project` rather than `project.projectId`:
|
|
45
|
+
*
|
|
46
|
+
* @example Container API for GKE
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const project = yield* GCP.Project("Research", { ... });
|
|
49
|
+
* const containerApi = yield* GCP.ApiEnable("ContainerApi", {
|
|
50
|
+
* project: project.projectId,
|
|
51
|
+
* service: "container.googleapis.com",
|
|
52
|
+
* });
|
|
53
|
+
* const cluster = yield* GCP.Cluster("Main", {
|
|
54
|
+
* project: containerApi.project, // ← edge through ApiEnable, not Project
|
|
55
|
+
* location: "us-central1-a",
|
|
56
|
+
* // ...
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* If the cluster instead read `project.projectId`, alchemy would
|
|
61
|
+
* schedule the cluster create in parallel with the API enable and the
|
|
62
|
+
* GKE call would fail with `Forbidden: <X> API has not been used in
|
|
63
|
+
* project ... before or it is disabled.`
|
|
64
|
+
*
|
|
65
|
+
* @example Multiple APIs on a project
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const containerApi = yield* GCP.ApiEnable("ContainerApi",
|
|
68
|
+
* { project: project.projectId, service: "container.googleapis.com" });
|
|
69
|
+
* const computeApi = yield* GCP.ApiEnable("ComputeApi",
|
|
70
|
+
* { project: project.projectId, service: "compute.googleapis.com" });
|
|
71
|
+
* // Then route downstream resources through the API enables that gate them:
|
|
72
|
+
* const cluster = yield* GCP.Cluster("Main", { project: containerApi.project, ... });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export type ApiEnable = Resource<"GCP.ApiEnable", ApiEnableProps, ApiEnableAttributes, never, GCP.Providers>;
|
|
76
|
+
export declare const ApiEnable: import("alchemy").ResourceClass<ApiEnable>;
|
|
77
|
+
export declare const ApiEnableProvider: () => import("effect/Layer").Layer<Provider.Provider<ApiEnable>, never, import("effect/unstable/http/HttpClient").HttpClient | import("@distilled.cloud/gcp").Credentials>;
|
|
78
|
+
//# sourceMappingURL=ApiEnable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiEnable.d.ts","sourceRoot":"","sources":["../../src/ServiceUsage/ApiEnable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,CAC9B,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AAEF,eAAO,MAAM,SAAS,4CAAuC,CAAC;AAK9D,eAAO,MAAM,iBAAiB,4KAyK3B,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/gcp";
|
|
2
|
+
import * as su from "@distilled.cloud/gcp/serviceusage-v1";
|
|
3
|
+
import { Resource } from "alchemy";
|
|
4
|
+
import { isResolved } from "alchemy/Diff";
|
|
5
|
+
import * as Provider from "alchemy/Provider";
|
|
6
|
+
import * as Duration from "effect/Duration";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Schedule from "effect/Schedule";
|
|
9
|
+
export const ApiEnable = Resource("GCP.ApiEnable");
|
|
10
|
+
const fqServiceName = (project, service) => `projects/${project}/services/${service}`;
|
|
11
|
+
export const ApiEnableProvider = () => Provider.effect(ApiEnable, Effect.gen(function* () {
|
|
12
|
+
const getServices = yield* su.getServices;
|
|
13
|
+
const enableServices = yield* su.enableServices;
|
|
14
|
+
const disableServices = yield* su.disableServices;
|
|
15
|
+
const getOperations = yield* su.getOperations;
|
|
16
|
+
// Service Usage `Operation` carries `.done: boolean` (matching CRM,
|
|
17
|
+
// NOT Container's `.status: "DONE"`), so we can't reuse the
|
|
18
|
+
// Container `makeAwaitOperation`. Mirror Project.ts's polling
|
|
19
|
+
// schedule (cheap polls for fast LROs; service enable usually
|
|
20
|
+
// resolves in <30s).
|
|
21
|
+
const awaitOperation = Effect.fn(function* (operationName, session) {
|
|
22
|
+
const op = yield* getOperations({ name: operationName }).pipe(Effect.flatMap((current) => current.done === true
|
|
23
|
+
? Effect.succeed(current)
|
|
24
|
+
: Effect.fail({ _tag: "OperationPending" })), Effect.retry({
|
|
25
|
+
while: (e) => e?._tag === "OperationPending",
|
|
26
|
+
schedule: Schedule.exponential(Duration.seconds(1), 1.5).pipe(Schedule.either(Schedule.spaced(Duration.seconds(15))), Schedule.both(Schedule.recurs(60)), Schedule.tapOutput(() => session.note(`Waiting for ServiceUsage operation ${operationName}…`))),
|
|
27
|
+
}));
|
|
28
|
+
if (op.error) {
|
|
29
|
+
return yield* new ConfigError({
|
|
30
|
+
message: `ServiceUsage operation ${operationName} failed: ${op.error.message ?? JSON.stringify(op.error)}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return op;
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
// No physical-name generation: identity is `(project, service)`.
|
|
37
|
+
// Both are static strings on `news`/`olds`/`output`.
|
|
38
|
+
stables: ["project", "service", "name"],
|
|
39
|
+
diff: Effect.fn(function* ({ news, olds = {} }) {
|
|
40
|
+
if (!isResolved(news))
|
|
41
|
+
return undefined;
|
|
42
|
+
if ((olds.project !== undefined && olds.project !== news.project) ||
|
|
43
|
+
(olds.service !== undefined && olds.service !== news.service)) {
|
|
44
|
+
return { action: "replace" };
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}),
|
|
48
|
+
reconcile: Effect.fn(function* ({ news, session }) {
|
|
49
|
+
const name = fqServiceName(news.project, news.service);
|
|
50
|
+
// `getServices` returns the service entity even when disabled
|
|
51
|
+
// (state="DISABLED"), so 404 here means an invalid service
|
|
52
|
+
// name, not "not enabled". Treat NotFound and Forbidden as
|
|
53
|
+
// "needs enable attempt" — the enable call will surface the
|
|
54
|
+
// real error.
|
|
55
|
+
let observed = yield* getServices({ name }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
|
|
56
|
+
if (!observed || observed.state !== "ENABLED") {
|
|
57
|
+
// `Conflict` here covers concurrent enable / state-persistence
|
|
58
|
+
// race; fall through and re-observe.
|
|
59
|
+
const op = yield* enableServices({ name, body: {} }).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
|
|
60
|
+
if (op?.name)
|
|
61
|
+
yield* awaitOperation(op.name, session);
|
|
62
|
+
observed = yield* getServices({ name });
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
project: news.project,
|
|
66
|
+
service: news.service,
|
|
67
|
+
name: observed.name ?? name,
|
|
68
|
+
state: observed.state ?? "ENABLED",
|
|
69
|
+
};
|
|
70
|
+
}),
|
|
71
|
+
delete: Effect.fn(function* ({ output, session }) {
|
|
72
|
+
const name = fqServiceName(output.project, output.service);
|
|
73
|
+
yield* disableServices({
|
|
74
|
+
name,
|
|
75
|
+
body: { disableDependentServices: false },
|
|
76
|
+
}).pipe(Effect.flatMap((op) => op.name ? awaitOperation(op.name, session) : Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void),
|
|
77
|
+
// GCP returns HTTP 400 in two important cases on disable
|
|
78
|
+
// that we treat as idempotent success:
|
|
79
|
+
//
|
|
80
|
+
// 1. Service already disabled. The resource is gone from
|
|
81
|
+
// the user's perspective; alchemy is removing it from
|
|
82
|
+
// state.
|
|
83
|
+
//
|
|
84
|
+
// 2. "Resources are found when disabling service(s) X.
|
|
85
|
+
// Before you can disable, please delete the following
|
|
86
|
+
// resources first: …" — this is GCP's eventual-
|
|
87
|
+
// consistency lag: a sibling resource (cluster, node
|
|
88
|
+
// pool) was deleted via its own API but ServiceUsage's
|
|
89
|
+
// "what's still using this service" view hasn't
|
|
90
|
+
// propagated yet. The cluster is gone; alchemy state is
|
|
91
|
+
// being torn down; if the project itself is also being
|
|
92
|
+
// destroyed (the typical case in `stack.destroy`), all
|
|
93
|
+
// API state goes with it. Failing here would leave a
|
|
94
|
+
// half-torn-down stack the user has to clean up by
|
|
95
|
+
// hand.
|
|
96
|
+
//
|
|
97
|
+
// Other 400s (e.g. dependent *services* still enabled, or
|
|
98
|
+
// a true API-level rejection) propagate so the user sees
|
|
99
|
+
// the real failure.
|
|
100
|
+
Effect.catchTag("BadRequest", (e) => /already.*disabled|not.*currently enabled|FAILED_PRECONDITION|Resources are found/i.test(e.message ?? "")
|
|
101
|
+
? Effect.void
|
|
102
|
+
: Effect.fail(e)));
|
|
103
|
+
}),
|
|
104
|
+
read: Effect.fn(function* ({ output, olds }) {
|
|
105
|
+
const project = output?.project ?? olds?.project;
|
|
106
|
+
const service = output?.service ?? olds?.service;
|
|
107
|
+
if (!project || !service)
|
|
108
|
+
return undefined;
|
|
109
|
+
const name = fqServiceName(project, service);
|
|
110
|
+
const observed = yield* getServices({ name }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
|
|
111
|
+
if (!observed)
|
|
112
|
+
return undefined;
|
|
113
|
+
// A DISABLED service is functionally absent from this
|
|
114
|
+
// resource's perspective — the engine treats `undefined` as
|
|
115
|
+
// "needs reconcile" and the next plan will re-enable.
|
|
116
|
+
if (observed.state !== "ENABLED")
|
|
117
|
+
return undefined;
|
|
118
|
+
// No `alchemy_*` ownership labels available on services
|
|
119
|
+
// (no labels field), so we can't gate via `Unowned`.
|
|
120
|
+
// API enablement is project-scoped state, not a labeled
|
|
121
|
+
// resource — adoption is fine: any project we can read from
|
|
122
|
+
// has the API enabled regardless of who turned it on.
|
|
123
|
+
return {
|
|
124
|
+
project,
|
|
125
|
+
service,
|
|
126
|
+
name: observed.name ?? name,
|
|
127
|
+
state: observed.state,
|
|
128
|
+
};
|
|
129
|
+
}),
|
|
130
|
+
};
|
|
131
|
+
}));
|
|
132
|
+
//# sourceMappingURL=ApiEnable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiEnable.js","sourceRoot":"","sources":["../../src/ServiceUsage/ApiEnable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ServiceUsage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ServiceUsage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/lib/Tags.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { Stack } from "alchemy/Stack";
|
|
3
|
+
import { Stage } from "alchemy/Stage";
|
|
4
|
+
/**
|
|
5
|
+
* GCP labels are stricter than AWS tags:
|
|
6
|
+
*
|
|
7
|
+
* - **Keys** must match `[a-z][a-z0-9_-]{0,62}`. Alchemy's default
|
|
8
|
+
* `createInternalTags` returns keys like `alchemy::stack` — `:` is
|
|
9
|
+
* illegal in a GCP label key, so we use `_` separators here.
|
|
10
|
+
* - **Values** must match `[a-z0-9_-]{0,63}`. We lowercase and replace
|
|
11
|
+
* any out-of-range character with `-`.
|
|
12
|
+
*
|
|
13
|
+
* The label values together with the keys are what `read` uses to
|
|
14
|
+
* decide whether a project is owned by this stack/stage/id (returning
|
|
15
|
+
* plain attrs) or foreign (returning `Unowned(attrs)`).
|
|
16
|
+
*
|
|
17
|
+
* @see {@link https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements}
|
|
18
|
+
*/
|
|
19
|
+
declare const LABEL_KEY_APP = "alchemy_app";
|
|
20
|
+
declare const LABEL_KEY_STAGE = "alchemy_stage";
|
|
21
|
+
declare const LABEL_KEY_ID = "alchemy_id";
|
|
22
|
+
/**
|
|
23
|
+
* Compute the alchemy-internal label set for a Resource. Merge the
|
|
24
|
+
* result with user-provided labels (user wins on key collision is
|
|
25
|
+
* deliberately disallowed — alchemy keys are reserved).
|
|
26
|
+
*/
|
|
27
|
+
export declare const gcpInternalLabels: (id: string) => Effect.Effect<{
|
|
28
|
+
alchemy_app: string;
|
|
29
|
+
alchemy_stage: string;
|
|
30
|
+
alchemy_id: string;
|
|
31
|
+
}, never, Stage | Stack>;
|
|
32
|
+
/**
|
|
33
|
+
* True when `labels` contains all three alchemy-internal keys with
|
|
34
|
+
* values matching this stack/stage/id. Used in `read` to decide
|
|
35
|
+
* adoption ownership.
|
|
36
|
+
*/
|
|
37
|
+
export declare const hasAlchemyLabels: (id: string, labels: Record<string, string> | undefined) => Effect.Effect<boolean, never, Stage | Stack>;
|
|
38
|
+
export { LABEL_KEY_APP as ALCHEMY_LABEL_APP, LABEL_KEY_STAGE as ALCHEMY_LABEL_STAGE, LABEL_KEY_ID as ALCHEMY_LABEL_ID, };
|
|
39
|
+
/**
|
|
40
|
+
* Compose `[alchemy:...] <userDescription?>`. Pass through to the
|
|
41
|
+
* resource's `description` body field at create time.
|
|
42
|
+
*/
|
|
43
|
+
export declare const gcpAlchemyDescription: (id: string, userDescription?: string | undefined) => Effect.Effect<string, never, Stage | Stack>;
|
|
44
|
+
/**
|
|
45
|
+
* True when `description` begins with an alchemy marker matching this
|
|
46
|
+
* stack/stage/id. Used in `read` for resources that lack a labels
|
|
47
|
+
* field.
|
|
48
|
+
*/
|
|
49
|
+
export declare const descriptionHasAlchemyMarker: (id: string, description: string | undefined) => Effect.Effect<boolean, never, Stage | Stack>;
|
|
50
|
+
/**
|
|
51
|
+
* Strip the leading alchemy marker (if any) and return what remains —
|
|
52
|
+
* used when surfacing the user-visible description back through
|
|
53
|
+
* Attributes. Matches whether the marker was generated by us or not;
|
|
54
|
+
* if there's no marker, returns the description unchanged.
|
|
55
|
+
*/
|
|
56
|
+
export declare const stripAlchemyMarker: (description: string | undefined) => string | undefined;
|
|
57
|
+
//# sourceMappingURL=Tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tags.d.ts","sourceRoot":"","sources":["../src/Tags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC;;;;;;;;;;;;;;GAcG;AAEH,QAAA,MAAM,aAAa,gBAAgB,CAAC;AACpC,QAAA,MAAM,eAAe,kBAAkB,CAAC;AACxC,QAAA,MAAM,YAAY,eAAe,CAAC;AAQlC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;wBAQ5B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,0GAW3B,CAAC;AAEH,OAAO,EACL,aAAa,IAAI,iBAAiB,EAClC,eAAe,IAAI,mBAAmB,EACtC,YAAY,IAAI,gBAAgB,GACjC,CAAC;AAsBF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,mGAQhC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,+FAStC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,aAAa,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAI7E,CAAC"}
|
package/lib/Tags.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { Stack } from "alchemy/Stack";
|
|
3
|
+
import { Stage } from "alchemy/Stage";
|
|
4
|
+
/**
|
|
5
|
+
* GCP labels are stricter than AWS tags:
|
|
6
|
+
*
|
|
7
|
+
* - **Keys** must match `[a-z][a-z0-9_-]{0,62}`. Alchemy's default
|
|
8
|
+
* `createInternalTags` returns keys like `alchemy::stack` — `:` is
|
|
9
|
+
* illegal in a GCP label key, so we use `_` separators here.
|
|
10
|
+
* - **Values** must match `[a-z0-9_-]{0,63}`. We lowercase and replace
|
|
11
|
+
* any out-of-range character with `-`.
|
|
12
|
+
*
|
|
13
|
+
* The label values together with the keys are what `read` uses to
|
|
14
|
+
* decide whether a project is owned by this stack/stage/id (returning
|
|
15
|
+
* plain attrs) or foreign (returning `Unowned(attrs)`).
|
|
16
|
+
*
|
|
17
|
+
* @see {@link https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements}
|
|
18
|
+
*/
|
|
19
|
+
const LABEL_KEY_APP = "alchemy_app";
|
|
20
|
+
const LABEL_KEY_STAGE = "alchemy_stage";
|
|
21
|
+
const LABEL_KEY_ID = "alchemy_id";
|
|
22
|
+
const sanitizeLabelValue = (raw) => {
|
|
23
|
+
const lowered = raw.toLowerCase();
|
|
24
|
+
const replaced = lowered.replace(/[^a-z0-9_-]/g, "-");
|
|
25
|
+
return replaced.slice(0, 63);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Compute the alchemy-internal label set for a Resource. Merge the
|
|
29
|
+
* result with user-provided labels (user wins on key collision is
|
|
30
|
+
* deliberately disallowed — alchemy keys are reserved).
|
|
31
|
+
*/
|
|
32
|
+
export const gcpInternalLabels = Effect.fnUntraced(function* (id) {
|
|
33
|
+
const stack = yield* Stack;
|
|
34
|
+
const stage = yield* Stage;
|
|
35
|
+
return {
|
|
36
|
+
[LABEL_KEY_APP]: sanitizeLabelValue(stack.name),
|
|
37
|
+
[LABEL_KEY_STAGE]: sanitizeLabelValue(stage),
|
|
38
|
+
[LABEL_KEY_ID]: sanitizeLabelValue(id),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* True when `labels` contains all three alchemy-internal keys with
|
|
43
|
+
* values matching this stack/stage/id. Used in `read` to decide
|
|
44
|
+
* adoption ownership.
|
|
45
|
+
*/
|
|
46
|
+
export const hasAlchemyLabels = Effect.fnUntraced(function* (id, labels) {
|
|
47
|
+
if (!labels)
|
|
48
|
+
return false;
|
|
49
|
+
const expected = yield* gcpInternalLabels(id);
|
|
50
|
+
return (labels[LABEL_KEY_APP] === expected[LABEL_KEY_APP] &&
|
|
51
|
+
labels[LABEL_KEY_STAGE] === expected[LABEL_KEY_STAGE] &&
|
|
52
|
+
labels[LABEL_KEY_ID] === expected[LABEL_KEY_ID]);
|
|
53
|
+
});
|
|
54
|
+
export { LABEL_KEY_APP as ALCHEMY_LABEL_APP, LABEL_KEY_STAGE as ALCHEMY_LABEL_STAGE, LABEL_KEY_ID as ALCHEMY_LABEL_ID, };
|
|
55
|
+
/**
|
|
56
|
+
* Some GCP resources (compute Networks, Subnetworks) carry no labels
|
|
57
|
+
* field, so the label-based adoption gate cannot apply. For these we
|
|
58
|
+
* encode the same `(app, stage, id)` triple as a sentinel inside the
|
|
59
|
+
* resource's `description` field — created on insert and read back on
|
|
60
|
+
* adoption.
|
|
61
|
+
*
|
|
62
|
+
* Format: `[alchemy:app=<app>,stage=<stage>,id=<id>] <user description>`.
|
|
63
|
+
* The leading bracketed segment is what `descriptionHasAlchemyMarker`
|
|
64
|
+
* matches; everything after the closing `]` is the user-supplied
|
|
65
|
+
* description and is preserved as-is. We never *update* this marker
|
|
66
|
+
* because both Network and Subnetwork treat `description` as immutable
|
|
67
|
+
* after create — the marker is only ever written on insert.
|
|
68
|
+
*/
|
|
69
|
+
const sanitizeMarkerValue = (raw) => raw.toLowerCase().replace(/[^a-z0-9_-]/g, "-").slice(0, 63);
|
|
70
|
+
const buildMarkerPrefix = (app, stage, id) => `[alchemy:app=${sanitizeMarkerValue(app)},stage=${sanitizeMarkerValue(stage)},id=${sanitizeMarkerValue(id)}]`;
|
|
71
|
+
/**
|
|
72
|
+
* Compose `[alchemy:...] <userDescription?>`. Pass through to the
|
|
73
|
+
* resource's `description` body field at create time.
|
|
74
|
+
*/
|
|
75
|
+
export const gcpAlchemyDescription = Effect.fnUntraced(function* (id, userDescription) {
|
|
76
|
+
const stack = yield* Stack;
|
|
77
|
+
const stage = yield* Stage;
|
|
78
|
+
const prefix = buildMarkerPrefix(stack.name, stage, id);
|
|
79
|
+
return userDescription ? `${prefix} ${userDescription}` : prefix;
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* True when `description` begins with an alchemy marker matching this
|
|
83
|
+
* stack/stage/id. Used in `read` for resources that lack a labels
|
|
84
|
+
* field.
|
|
85
|
+
*/
|
|
86
|
+
export const descriptionHasAlchemyMarker = Effect.fnUntraced(function* (id, description) {
|
|
87
|
+
if (!description)
|
|
88
|
+
return false;
|
|
89
|
+
const stack = yield* Stack;
|
|
90
|
+
const stage = yield* Stage;
|
|
91
|
+
const expected = buildMarkerPrefix(stack.name, stage, id);
|
|
92
|
+
return description.startsWith(expected);
|
|
93
|
+
});
|
|
94
|
+
/**
|
|
95
|
+
* Strip the leading alchemy marker (if any) and return what remains —
|
|
96
|
+
* used when surfacing the user-visible description back through
|
|
97
|
+
* Attributes. Matches whether the marker was generated by us or not;
|
|
98
|
+
* if there's no marker, returns the description unchanged.
|
|
99
|
+
*/
|
|
100
|
+
export const stripAlchemyMarker = (description) => {
|
|
101
|
+
if (!description)
|
|
102
|
+
return description;
|
|
103
|
+
const m = description.match(/^\[alchemy:[^\]]+\]\s?/);
|
|
104
|
+
return m ? description.slice(m[0].length) || undefined : description;
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=Tags.js.map
|
package/lib/Tags.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tags.js","sourceRoot":"","sources":["../src/Tags.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { Credentials, fromADC, fromAuthProvider } from "./Auth/Credentials.ts";
|
|
2
|
+
export { GCP_AUTH_PROVIDER_NAME, GCPAuth, } from "./Auth/AuthProvider.ts";
|
|
3
|
+
export type { GCPAuthConfig, GCPResolvedCredentials, } from "./Auth/AuthProvider.ts";
|
|
4
|
+
export * from "./CloudResourceManager/index.ts";
|
|
5
|
+
export * from "./Compute/index.ts";
|
|
6
|
+
export * from "./Container/index.ts";
|
|
7
|
+
export * from "./Parallelstore/index.ts";
|
|
8
|
+
export * from "./ServiceNetworking/index.ts";
|
|
9
|
+
export * from "./ServiceUsage/index.ts";
|
|
10
|
+
export * from "./Providers.ts";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Credentials, fromADC, fromAuthProvider } from "./Auth/Credentials.js";
|
|
2
|
+
export { GCP_AUTH_PROVIDER_NAME, GCPAuth, } from "./Auth/AuthProvider.js";
|
|
3
|
+
export * from "./CloudResourceManager/index.js";
|
|
4
|
+
export * from "./Compute/index.js";
|
|
5
|
+
export * from "./Container/index.js";
|
|
6
|
+
export * from "./Parallelstore/index.js";
|
|
7
|
+
export * from "./ServiceNetworking/index.js";
|
|
8
|
+
export * from "./ServiceUsage/index.js";
|
|
9
|
+
export * from "./Providers.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +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,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
|