@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.
Files changed (123) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +88 -0
  3. package/lib/Auth/AuthProvider.d.ts +48 -0
  4. package/lib/Auth/AuthProvider.d.ts.map +1 -0
  5. package/lib/Auth/AuthProvider.js +84 -0
  6. package/lib/Auth/AuthProvider.js.map +1 -0
  7. package/lib/Auth/Credentials.d.ts +28 -0
  8. package/lib/Auth/Credentials.d.ts.map +1 -0
  9. package/lib/Auth/Credentials.js +41 -0
  10. package/lib/Auth/Credentials.js.map +1 -0
  11. package/lib/CloudResourceManager/Project.d.ts +143 -0
  12. package/lib/CloudResourceManager/Project.d.ts.map +1 -0
  13. package/lib/CloudResourceManager/Project.js +272 -0
  14. package/lib/CloudResourceManager/Project.js.map +1 -0
  15. package/lib/CloudResourceManager/index.d.ts +3 -0
  16. package/lib/CloudResourceManager/index.d.ts.map +1 -0
  17. package/lib/CloudResourceManager/index.js +2 -0
  18. package/lib/CloudResourceManager/index.js.map +1 -0
  19. package/lib/Compute/GlobalAddress.d.ts +101 -0
  20. package/lib/Compute/GlobalAddress.d.ts.map +1 -0
  21. package/lib/Compute/GlobalAddress.js +134 -0
  22. package/lib/Compute/GlobalAddress.js.map +1 -0
  23. package/lib/Compute/Network.d.ts +114 -0
  24. package/lib/Compute/Network.d.ts.map +1 -0
  25. package/lib/Compute/Network.js +145 -0
  26. package/lib/Compute/Network.js.map +1 -0
  27. package/lib/Compute/Operations.d.ts +34 -0
  28. package/lib/Compute/Operations.d.ts.map +1 -0
  29. package/lib/Compute/Operations.js +62 -0
  30. package/lib/Compute/Operations.js.map +1 -0
  31. package/lib/Compute/SharedVpcHost.d.ts +44 -0
  32. package/lib/Compute/SharedVpcHost.d.ts.map +1 -0
  33. package/lib/Compute/SharedVpcHost.js +71 -0
  34. package/lib/Compute/SharedVpcHost.js.map +1 -0
  35. package/lib/Compute/SharedVpcServiceProject.d.ts +46 -0
  36. package/lib/Compute/SharedVpcServiceProject.d.ts.map +1 -0
  37. package/lib/Compute/SharedVpcServiceProject.js +96 -0
  38. package/lib/Compute/SharedVpcServiceProject.js.map +1 -0
  39. package/lib/Compute/Subnetwork.d.ts +108 -0
  40. package/lib/Compute/Subnetwork.d.ts.map +1 -0
  41. package/lib/Compute/Subnetwork.js +201 -0
  42. package/lib/Compute/Subnetwork.js.map +1 -0
  43. package/lib/Compute/index.d.ts +6 -0
  44. package/lib/Compute/index.d.ts.map +1 -0
  45. package/lib/Compute/index.js +6 -0
  46. package/lib/Compute/index.js.map +1 -0
  47. package/lib/Container/Cluster.d.ts +216 -0
  48. package/lib/Container/Cluster.d.ts.map +1 -0
  49. package/lib/Container/Cluster.js +326 -0
  50. package/lib/Container/Cluster.js.map +1 -0
  51. package/lib/Container/NodePool.d.ts +214 -0
  52. package/lib/Container/NodePool.d.ts.map +1 -0
  53. package/lib/Container/NodePool.js +344 -0
  54. package/lib/Container/NodePool.js.map +1 -0
  55. package/lib/Container/Operations.d.ts +50 -0
  56. package/lib/Container/Operations.d.ts.map +1 -0
  57. package/lib/Container/Operations.js +51 -0
  58. package/lib/Container/Operations.js.map +1 -0
  59. package/lib/Container/index.d.ts +5 -0
  60. package/lib/Container/index.d.ts.map +1 -0
  61. package/lib/Container/index.js +3 -0
  62. package/lib/Container/index.js.map +1 -0
  63. package/lib/Parallelstore/Instance.d.ts +119 -0
  64. package/lib/Parallelstore/Instance.d.ts.map +1 -0
  65. package/lib/Parallelstore/Instance.js +180 -0
  66. package/lib/Parallelstore/Instance.js.map +1 -0
  67. package/lib/Parallelstore/index.d.ts +2 -0
  68. package/lib/Parallelstore/index.d.ts.map +1 -0
  69. package/lib/Parallelstore/index.js +2 -0
  70. package/lib/Parallelstore/index.js.map +1 -0
  71. package/lib/Providers.d.ts +24 -0
  72. package/lib/Providers.d.ts.map +1 -0
  73. package/lib/Providers.js +51 -0
  74. package/lib/Providers.js.map +1 -0
  75. package/lib/ServiceNetworking/PsaConnection.d.ts +84 -0
  76. package/lib/ServiceNetworking/PsaConnection.d.ts.map +1 -0
  77. package/lib/ServiceNetworking/PsaConnection.js +130 -0
  78. package/lib/ServiceNetworking/PsaConnection.js.map +1 -0
  79. package/lib/ServiceNetworking/index.d.ts +2 -0
  80. package/lib/ServiceNetworking/index.d.ts.map +1 -0
  81. package/lib/ServiceNetworking/index.js +2 -0
  82. package/lib/ServiceNetworking/index.js.map +1 -0
  83. package/lib/ServiceUsage/ApiEnable.d.ts +78 -0
  84. package/lib/ServiceUsage/ApiEnable.d.ts.map +1 -0
  85. package/lib/ServiceUsage/ApiEnable.js +132 -0
  86. package/lib/ServiceUsage/ApiEnable.js.map +1 -0
  87. package/lib/ServiceUsage/index.d.ts +3 -0
  88. package/lib/ServiceUsage/index.d.ts.map +1 -0
  89. package/lib/ServiceUsage/index.js +2 -0
  90. package/lib/ServiceUsage/index.js.map +1 -0
  91. package/lib/Tags.d.ts +57 -0
  92. package/lib/Tags.d.ts.map +1 -0
  93. package/lib/Tags.js +106 -0
  94. package/lib/Tags.js.map +1 -0
  95. package/lib/index.d.ts +11 -0
  96. package/lib/index.d.ts.map +1 -0
  97. package/lib/index.js +10 -0
  98. package/lib/index.js.map +1 -0
  99. package/package.json +70 -0
  100. package/src/Auth/AuthProvider.ts +180 -0
  101. package/src/Auth/Credentials.ts +69 -0
  102. package/src/CloudResourceManager/Project.ts +517 -0
  103. package/src/CloudResourceManager/index.ts +2 -0
  104. package/src/Compute/GlobalAddress.ts +283 -0
  105. package/src/Compute/Network.ts +306 -0
  106. package/src/Compute/Operations.ts +108 -0
  107. package/src/Compute/SharedVpcHost.ts +141 -0
  108. package/src/Compute/SharedVpcServiceProject.ts +185 -0
  109. package/src/Compute/Subnetwork.ts +375 -0
  110. package/src/Compute/index.ts +5 -0
  111. package/src/Container/Cluster.ts +599 -0
  112. package/src/Container/NodePool.ts +620 -0
  113. package/src/Container/Operations.ts +88 -0
  114. package/src/Container/index.ts +8 -0
  115. package/src/Parallelstore/Instance.ts +371 -0
  116. package/src/Parallelstore/index.ts +1 -0
  117. package/src/Providers.ts +84 -0
  118. package/src/ServiceNetworking/PsaConnection.ts +269 -0
  119. package/src/ServiceNetworking/index.ts +1 -0
  120. package/src/ServiceUsage/ApiEnable.ts +267 -0
  121. package/src/ServiceUsage/index.ts +2 -0
  122. package/src/Tags.ts +130 -0
  123. package/src/index.ts +16 -0
@@ -0,0 +1,114 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Output from "alchemy/Output";
3
+ import * as Provider from "alchemy/Provider";
4
+ import type * as GCP from "../Providers.ts";
5
+ /**
6
+ * Fully-qualified VPC reference in **project-number** form:
7
+ * `projects/{projectNumber}/global/networks/{name}`.
8
+ *
9
+ * Several GCP service-producer APIs (servicenetworking PSA,
10
+ * Parallelstore) require this exact shape — the *project number*, not
11
+ * project ID — because they resolve peerings against numeric ids that
12
+ * are stable across project renames. Compose with `networkRef`:
13
+ *
14
+ * ```typescript
15
+ * const ref = networkRef(project.projectNumber, vpc.name);
16
+ * // typed as Output<NetworkRef>, accepted by GCP.PsaConnection /
17
+ * // GCP.ParallelstoreInstance via the Resource constructor's
18
+ * // InputProps widening.
19
+ * ```
20
+ *
21
+ * `Project.projectNumber` is typed as `` `${number}` `` precisely so
22
+ * this template literal type composes without a runtime coercion at
23
+ * the call site.
24
+ */
25
+ export type NetworkRef = `projects/${number}/global/networks/${string}`;
26
+ /**
27
+ * Build a project-number-form `NetworkRef`. Lifted through `Output`
28
+ * so it composes with `Project.projectNumber` (an `Output<\`${number}\`>`)
29
+ * and `Network.name` (an `Output<string>`) coming from other resource
30
+ * constructors. The `` `${number}` `` argument type prevents
31
+ * accidentally passing `Project.projectId` here — TS rejects strings
32
+ * that don't match the numeric shape.
33
+ *
34
+ * Plain literal arguments still work: `networkRef("415104041262", "main")`
35
+ * is wrapped via `Output.asOutput` and resolves immediately at apply
36
+ * time.
37
+ */
38
+ export declare const networkRef: (projectNumber: `${number}` | Output.Output<`${number}`>, networkName: string | Output.Output<string>) => Output.Output<NetworkRef>;
39
+ /**
40
+ * A VPC Network in custom-mode (`autoCreateSubnetworks=false`). Auto-mode
41
+ * networks are intentionally not exposed — every cluster/parallelstore
42
+ * deployment in this provider expects explicit subnets in known regions.
43
+ *
44
+ * Compute Networks have no `labels` field, so adoption gating uses an
45
+ * alchemy marker embedded in the `description` field instead (see
46
+ * `gcpAlchemyDescription`). Network `description` is set at create time
47
+ * and is treated as immutable — the marker survives for the resource's
48
+ * lifetime.
49
+ *
50
+ * @section Creating a VPC
51
+ * @example Custom-mode VPC for a Shared VPC host
52
+ * ```typescript
53
+ * const vpc = yield* GCP.Network("ResearchVpc", {
54
+ * project: hostProject.projectId,
55
+ * routingMode: "GLOBAL",
56
+ * });
57
+ * ```
58
+ */
59
+ export type NetworkProps = {
60
+ /** GCP project ID hosting the network. Immutable — replace if changed. */
61
+ project: string;
62
+ /**
63
+ * Network name. Defaults to `createPhysicalName({ id, lowercase: true,
64
+ * maxLength: 63 })`. Must match `[a-z]([-a-z0-9]*[a-z0-9])?`.
65
+ * Immutable — replace if changed.
66
+ */
67
+ name?: string;
68
+ /**
69
+ * User-visible description. Stored in the resource's `description`
70
+ * field after the alchemy ownership marker prefix. Treated as
71
+ * immutable by GCP after create — changes here do NOT replace.
72
+ */
73
+ description?: string;
74
+ /**
75
+ * `auto` mode: GCP allocates one subnet per region with predetermined
76
+ * CIDRs. `custom` mode (default): you create subnetworks explicitly
77
+ * via `GCP.Subnetwork`. Immutable — switching modes requires replace.
78
+ */
79
+ autoCreateSubnetworks?: boolean;
80
+ /**
81
+ * Network-wide routing config. Cloud Routers in REGIONAL mode advertise
82
+ * only same-region subnets; GLOBAL mode advertises across regions.
83
+ * Mutable via `patchNetworks` (the only field GCP allows mutating
84
+ * post-create on a VPC).
85
+ */
86
+ routingMode?: "REGIONAL" | "GLOBAL";
87
+ /**
88
+ * MTU in bytes. Range 1300-8896. Defaults to 1460. Common values:
89
+ * 1500 (internet default), 8896 (jumbo frames). Immutable — replace.
90
+ */
91
+ mtu?: number;
92
+ };
93
+ export type NetworkAttributes = {
94
+ /** Network name. */
95
+ name: string;
96
+ /** GCP project ID, threaded through from props for delete/read. */
97
+ project: string;
98
+ /** Server-defined URL for the resource. */
99
+ selfLink: string;
100
+ /** Server-assigned numeric id. */
101
+ id: string;
102
+ /** User-visible description (with the alchemy marker stripped off). */
103
+ description: string | undefined;
104
+ /** Custom (false) vs auto (true) subnet mode. */
105
+ autoCreateSubnetworks: boolean;
106
+ /** Active routing mode. */
107
+ routingMode: string | undefined;
108
+ /** Active MTU in bytes. */
109
+ mtu: number | undefined;
110
+ };
111
+ export type Network = Resource<"GCP.Network", NetworkProps, NetworkAttributes, never, GCP.Providers>;
112
+ export declare const Network: import("alchemy").ResourceClass<Network>;
113
+ export declare const NetworkProvider: () => import("effect/Layer").Layer<Provider.Provider<Network>, never, import("effect/unstable/http/HttpClient").HttpClient | import("alchemy").Stage | import("alchemy").Stack | import("@distilled.cloud/gcp").Credentials>;
114
+ //# sourceMappingURL=Network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Network.d.ts","sourceRoot":"","sources":["../../src/Compute/Network.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKnC,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAO7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,MAAM,oBAAoB,MAAM,EAAE,CAAC;AAExE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,GACrB,eAAe,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,EACvD,aAAa,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAC1C,MAAM,CAAC,MAAM,CAAC,UAAU,CASxB,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACpC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iDAAiD;IACjD,qBAAqB,EAAE,OAAO,CAAC;IAC/B,2BAA2B;IAC3B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,2BAA2B;IAC3B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB,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;AAgBxD,eAAO,MAAM,eAAe,8NA+IzB,CAAC"}
@@ -0,0 +1,145 @@
1
+ import * as compute from "@distilled.cloud/gcp/compute-v1";
2
+ import { Resource } from "alchemy";
3
+ import { Unowned } from "alchemy/AdoptPolicy";
4
+ import { isResolved, somePropsAreDifferent } from "alchemy/Diff";
5
+ import { createPhysicalName } from "alchemy/PhysicalName";
6
+ import * as Output from "alchemy/Output";
7
+ import * as Provider from "alchemy/Provider";
8
+ import * as Effect from "effect/Effect";
9
+ import { descriptionHasAlchemyMarker, gcpAlchemyDescription, stripAlchemyMarker, } from "../Tags.js";
10
+ import { makeAwaitGlobalOperation } from "./Operations.js";
11
+ /**
12
+ * Build a project-number-form `NetworkRef`. Lifted through `Output`
13
+ * so it composes with `Project.projectNumber` (an `Output<\`${number}\`>`)
14
+ * and `Network.name` (an `Output<string>`) coming from other resource
15
+ * constructors. The `` `${number}` `` argument type prevents
16
+ * accidentally passing `Project.projectId` here — TS rejects strings
17
+ * that don't match the numeric shape.
18
+ *
19
+ * Plain literal arguments still work: `networkRef("415104041262", "main")`
20
+ * is wrapped via `Output.asOutput` and resolves immediately at apply
21
+ * time.
22
+ */
23
+ export const networkRef = (projectNumber, networkName) => Output.all(Output.asOutput(projectNumber), Output.asOutput(networkName)).pipe(Output.map(([num, name]) => `projects/${num}/global/networks/${name}`));
24
+ export const Network = Resource("GCP.Network");
25
+ const toNetworkAttributes = (n, parent) => ({
26
+ name: n.name ?? "",
27
+ project: parent.project,
28
+ selfLink: n.selfLink ?? "",
29
+ id: n.id ?? "",
30
+ description: stripAlchemyMarker(n.description),
31
+ autoCreateSubnetworks: n.autoCreateSubnetworks ?? false,
32
+ routingMode: n.routingConfig?.routingMode,
33
+ mtu: n.mtu,
34
+ });
35
+ export const NetworkProvider = () => Provider.effect(Network, Effect.gen(function* () {
36
+ const getNetworks = yield* compute.getNetworks;
37
+ const insertNetworks = yield* compute.insertNetworks;
38
+ const patchNetworks = yield* compute.patchNetworks;
39
+ const deleteNetworks = yield* compute.deleteNetworks;
40
+ const getGlobalOperations = yield* compute.getGlobalOperations;
41
+ const awaitOp = makeAwaitGlobalOperation(getGlobalOperations);
42
+ const observe = (project, name) => getNetworks({ project, network: name }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
43
+ const syncRoutingMode = Effect.fn(function* (args) {
44
+ if (!args.desired)
45
+ return;
46
+ if (args.observed.routingConfig?.routingMode === args.desired)
47
+ return;
48
+ const op = yield* patchNetworks({
49
+ project: args.project,
50
+ network: args.name,
51
+ body: { routingConfig: { routingMode: args.desired } },
52
+ });
53
+ if (op.name)
54
+ yield* awaitOp(args.project, op.name, args.session);
55
+ });
56
+ return {
57
+ stables: ["name", "project", "selfLink", "id"],
58
+ diff: Effect.fn(function* ({ news, olds = {} }) {
59
+ if (!isResolved(news))
60
+ return undefined;
61
+ if (somePropsAreDifferent(olds, news, [
62
+ "project",
63
+ "name",
64
+ "autoCreateSubnetworks",
65
+ "mtu",
66
+ ])) {
67
+ return { action: "replace" };
68
+ }
69
+ return undefined;
70
+ }),
71
+ reconcile: Effect.fn(function* ({ id, news, session }) {
72
+ const desiredName = news.name ??
73
+ (yield* createPhysicalName({ id, maxLength: 63 })).toLowerCase();
74
+ const desiredDescription = yield* gcpAlchemyDescription(id, news.description);
75
+ // 1. Observe — collapse 403 to "missing" alongside 404.
76
+ let observed = yield* observe(news.project, desiredName);
77
+ // 2. Ensure — create if missing. `autoCreateSubnetworks`
78
+ // defaults to *true* on the GCP side (auto-mode VPC), but
79
+ // we default to false because every consumer in this
80
+ // provider creates explicit subnets. `Conflict` covers
81
+ // concurrent creates and state-persistence races.
82
+ if (!observed) {
83
+ const body = {
84
+ name: desiredName,
85
+ description: desiredDescription,
86
+ autoCreateSubnetworks: news.autoCreateSubnetworks ?? false,
87
+ ...(news.mtu !== undefined ? { mtu: news.mtu } : {}),
88
+ ...(news.routingMode
89
+ ? { routingConfig: { routingMode: news.routingMode } }
90
+ : {}),
91
+ };
92
+ const op = yield* insertNetworks({
93
+ project: news.project,
94
+ body,
95
+ }).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
96
+ if (op?.name)
97
+ yield* awaitOp(news.project, op.name, session);
98
+ observed = yield* getNetworks({
99
+ project: news.project,
100
+ network: desiredName,
101
+ });
102
+ }
103
+ // 3. Sync — only routing config can be mutated post-create.
104
+ // Description, MTU, autoCreateSubnetworks are all locked.
105
+ yield* syncRoutingMode({
106
+ project: news.project,
107
+ name: desiredName,
108
+ observed,
109
+ desired: news.routingMode,
110
+ session,
111
+ });
112
+ const final = yield* getNetworks({
113
+ project: news.project,
114
+ network: desiredName,
115
+ });
116
+ return toNetworkAttributes(final, { project: news.project });
117
+ }),
118
+ delete: Effect.fn(function* ({ output, session }) {
119
+ yield* deleteNetworks({
120
+ project: output.project,
121
+ network: output.name,
122
+ }).pipe(Effect.flatMap((op) => op.name
123
+ ? awaitOp(output.project, op.name, session)
124
+ : Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void));
125
+ }),
126
+ read: Effect.fn(function* ({ id, output, olds }) {
127
+ const project = output?.project ?? olds?.project;
128
+ if (!project)
129
+ return undefined;
130
+ const name = output?.name ??
131
+ olds?.name ??
132
+ (yield* createPhysicalName({ id, maxLength: 63 })).toLowerCase();
133
+ const observed = yield* observe(project, name);
134
+ if (!observed)
135
+ return undefined;
136
+ const attrs = toNetworkAttributes(observed, { project });
137
+ // Adoption gate via the description marker — networks have no
138
+ // labels field (verified against compute-v1 SDK Network type).
139
+ return (yield* descriptionHasAlchemyMarker(id, observed.description))
140
+ ? attrs
141
+ : Unowned(attrs);
142
+ }),
143
+ };
144
+ }));
145
+ //# sourceMappingURL=Network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Network.js","sourceRoot":"","sources":["../../src/Compute/Network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as compute from "@distilled.cloud/gcp/compute-v1";
3
+ import type { ScopedPlanStatusSession } from "alchemy/Cli/Cli";
4
+ import * as Effect from "effect/Effect";
5
+ /**
6
+ * Resolved callable signatures for the compute LRO getters. We hold both
7
+ * — global resources (networks, addresses with `addressType=INTERNAL`
8
+ * `purpose=VPC_PEERING`) emit Operations under
9
+ * `projects/{p}/global/operations/{op}`, while regional resources
10
+ * (subnetworks) emit Operations under
11
+ * `projects/{p}/regions/{r}/operations/{op}`. The `Operation.name`
12
+ * returned by the create/update/delete calls is a *bare* id (e.g.
13
+ * `operation-1700000000000-...`); callers thread back project (and
14
+ * region) at the await site.
15
+ */
16
+ type GetGlobalOperations = Effect.Success<typeof compute.getGlobalOperations>;
17
+ type GetRegionOperations = Effect.Success<typeof compute.getRegionOperations>;
18
+ /**
19
+ * Build a poller for compute global operations
20
+ * (`projects/{p}/global/operations/{op}`). Same exponential-then-spaced
21
+ * schedule as the GKE poller.
22
+ */
23
+ export declare const makeAwaitGlobalOperation: (getGlobalOperations: GetGlobalOperations) => (project: string, operationName: string, session: ScopedPlanStatusSession) => Effect.Effect<compute.Operation, ConfigError | compute.GetGlobalOperationsError | {
24
+ _tag: "OperationPending";
25
+ }, never>;
26
+ /**
27
+ * Build a poller for compute regional operations
28
+ * (`projects/{p}/regions/{r}/operations/{op}`).
29
+ */
30
+ export declare const makeAwaitRegionOperation: (getRegionOperations: GetRegionOperations) => (project: string, region: string, operationName: string, session: ScopedPlanStatusSession) => Effect.Effect<compute.Operation, ConfigError | compute.GetRegionOperationsError | {
31
+ _tag: "OperationPending";
32
+ }, never>;
33
+ export {};
34
+ //# sourceMappingURL=Operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Operations.d.ts","sourceRoot":"","sources":["../../src/Compute/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,OAAO,MAAM,iCAAiC,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC;;;;;;;;;;GAUG;AACH,KAAK,mBAAmB,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAC9E,KAAK,mBAAmB,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAwB9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,qBAAqB,mBAAmB;;SAwB7E,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,qBAAqB,mBAAmB;;SA6B7E,CAAC"}
@@ -0,0 +1,62 @@
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
+ const formatOperationError = (op) => {
6
+ const errors = op.error?.errors ?? [];
7
+ if (errors.length === 0)
8
+ return JSON.stringify(op.error ?? {});
9
+ return errors
10
+ .map((e) => `${e.code ?? "?"}${e.location ? ` @ ${e.location}` : ""}: ${e.message ?? "?"}`)
11
+ .join("; ");
12
+ };
13
+ const isDone = (op) => op.status === "DONE";
14
+ const pollSchedule = (label, session) => Schedule.exponential(Duration.seconds(2), 1.5).pipe(Schedule.either(Schedule.spaced(Duration.seconds(15))),
15
+ // 80 × ≤15s ≈ 20 min — long enough for a network create (~1 min),
16
+ // a parallelstore-adjacent global op, or a 10-minute parallelstore
17
+ // delete (longest LRO observed in this provider's surface).
18
+ Schedule.both(Schedule.recurs(80)), Schedule.tapOutput(() => session.note(`Waiting for Compute operation ${label}…`)));
19
+ /**
20
+ * Build a poller for compute global operations
21
+ * (`projects/{p}/global/operations/{op}`). Same exponential-then-spaced
22
+ * schedule as the GKE poller.
23
+ */
24
+ export const makeAwaitGlobalOperation = (getGlobalOperations) => Effect.fn(function* (project, operationName, session) {
25
+ const label = `${project}/global/${operationName}`;
26
+ const op = yield* getGlobalOperations({ project, operation: operationName }).pipe(Effect.flatMap((current) => isDone(current)
27
+ ? Effect.succeed(current)
28
+ : Effect.fail({ _tag: "OperationPending" })), Effect.retry({
29
+ while: (e) => e?._tag === "OperationPending",
30
+ schedule: pollSchedule(label, session),
31
+ }));
32
+ if (op.error) {
33
+ return yield* new ConfigError({
34
+ message: `Compute global operation ${operationName} failed: ${formatOperationError(op)}`,
35
+ });
36
+ }
37
+ return op;
38
+ });
39
+ /**
40
+ * Build a poller for compute regional operations
41
+ * (`projects/{p}/regions/{r}/operations/{op}`).
42
+ */
43
+ export const makeAwaitRegionOperation = (getRegionOperations) => Effect.fn(function* (project, region, operationName, session) {
44
+ const label = `${project}/${region}/${operationName}`;
45
+ const op = yield* getRegionOperations({
46
+ project,
47
+ region,
48
+ operation: operationName,
49
+ }).pipe(Effect.flatMap((current) => isDone(current)
50
+ ? Effect.succeed(current)
51
+ : Effect.fail({ _tag: "OperationPending" })), Effect.retry({
52
+ while: (e) => e?._tag === "OperationPending",
53
+ schedule: pollSchedule(label, session),
54
+ }));
55
+ if (op.error) {
56
+ return yield* new ConfigError({
57
+ message: `Compute region operation ${operationName} failed: ${formatOperationError(op)}`,
58
+ });
59
+ }
60
+ return op;
61
+ });
62
+ //# sourceMappingURL=Operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Operations.js","sourceRoot":"","sources":["../../src/Compute/Operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Provider from "alchemy/Provider";
3
+ import type * as GCP from "../Providers.ts";
4
+ /**
5
+ * Mark a GCP project as a Shared VPC **host**. Service projects can
6
+ * then attach to this host via `GCP.SharedVpcServiceProject` and use
7
+ * its VPC for clusters, VMs, etc.
8
+ *
9
+ * Identity: `(project)` — there's at most one host-status flag per
10
+ * project, so the resource is keyed by project ID alone. State is
11
+ * binary (host or not host), so there's no ownership concept; `read`
12
+ * returns plain attrs whenever the project's
13
+ * `xpnProjectStatus === "HOST"`.
14
+ *
15
+ * The `compute.googleapis.com` API must be enabled on the project
16
+ * before this resource succeeds — wire `project` through an
17
+ * `ApiEnable("compute.googleapis.com")` output to make alchemy
18
+ * sequence this resource after the API enable.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const computeApi = yield* GCP.ApiEnable("HostComputeApi", {
23
+ * project: hostProject.projectId,
24
+ * service: "compute.googleapis.com",
25
+ * });
26
+ * const host = yield* GCP.SharedVpcHost("ResearchHost", {
27
+ * project: computeApi.project,
28
+ * });
29
+ * ```
30
+ */
31
+ export type SharedVpcHostProps = {
32
+ /** GCP project ID to mark as a Shared VPC host. Immutable — replace. */
33
+ project: string;
34
+ };
35
+ export type SharedVpcHostAttributes = {
36
+ /** Project ID. */
37
+ project: string;
38
+ /** `"HOST"` once the enable completes. */
39
+ xpnProjectStatus: string;
40
+ };
41
+ export type SharedVpcHost = Resource<"GCP.SharedVpcHost", SharedVpcHostProps, SharedVpcHostAttributes, never, GCP.Providers>;
42
+ export declare const SharedVpcHost: import("alchemy").ResourceClass<SharedVpcHost>;
43
+ export declare const SharedVpcHostProvider: () => import("effect/Layer").Layer<Provider.Provider<SharedVpcHost>, never, import("effect/unstable/http/HttpClient").HttpClient | import("@distilled.cloud/gcp").Credentials>;
44
+ //# sourceMappingURL=SharedVpcHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedVpcHost.d.ts","sourceRoot":"","sources":["../../src/Compute/SharedVpcHost.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAClC,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AACF,eAAO,MAAM,aAAa,gDAA+C,CAAC;AAE1E,eAAO,MAAM,qBAAqB,gLAoF/B,CAAC"}
@@ -0,0 +1,71 @@
1
+ import * as compute from "@distilled.cloud/gcp/compute-v1";
2
+ import { Resource } from "alchemy";
3
+ import { isResolved } from "alchemy/Diff";
4
+ import * as Provider from "alchemy/Provider";
5
+ import * as Effect from "effect/Effect";
6
+ import { makeAwaitGlobalOperation } from "./Operations.js";
7
+ export const SharedVpcHost = Resource("GCP.SharedVpcHost");
8
+ export const SharedVpcHostProvider = () => Provider.effect(SharedVpcHost, Effect.gen(function* () {
9
+ const getProjects = yield* compute.getProjects;
10
+ const enableXpnHostProjects = yield* compute.enableXpnHostProjects;
11
+ const disableXpnHostProjects = yield* compute.disableXpnHostProjects;
12
+ const getGlobalOperations = yield* compute.getGlobalOperations;
13
+ const awaitOp = makeAwaitGlobalOperation(getGlobalOperations);
14
+ const observe = (project) => getProjects({ project }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
15
+ return {
16
+ stables: ["project"],
17
+ diff: Effect.fn(function* ({ news, olds = {} }) {
18
+ if (!isResolved(news))
19
+ return undefined;
20
+ if (olds.project !== undefined && olds.project !== news.project) {
21
+ return { action: "replace" };
22
+ }
23
+ return undefined;
24
+ }),
25
+ reconcile: Effect.fn(function* ({ news, session }) {
26
+ const observed = yield* observe(news.project);
27
+ if (observed?.xpnProjectStatus === "HOST") {
28
+ return { project: news.project, xpnProjectStatus: "HOST" };
29
+ }
30
+ // `enableXpnHost` is idempotent on the GCP side when the
31
+ // project is already a host (returns a no-op operation), but
32
+ // we still tolerate `Conflict` defensively to cover the
33
+ // narrow window where state-persistence races with another
34
+ // reconciler.
35
+ const op = yield* enableXpnHostProjects({
36
+ project: news.project,
37
+ }).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
38
+ if (op?.name)
39
+ yield* awaitOp(news.project, op.name, session);
40
+ return { project: news.project, xpnProjectStatus: "HOST" };
41
+ }),
42
+ delete: Effect.fn(function* ({ output, session }) {
43
+ yield* disableXpnHostProjects({ project: output.project }).pipe(Effect.flatMap((op) => op.name
44
+ ? awaitOp(output.project, op.name, session)
45
+ : Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void),
46
+ // `BadRequest` is returned when:
47
+ // 1. The project isn't a host (idempotent disable — fine).
48
+ // 2. Service projects are still attached. The user has
49
+ // to detach them first; surface that error so they
50
+ // can act. Only swallow case 1.
51
+ Effect.catchTag("BadRequest", (e) => /not.*host|not.*xpn|UNSPECIFIED_XPN_PROJECT_STATUS/i.test(e.message ?? "")
52
+ ? Effect.void
53
+ : Effect.fail(e)));
54
+ }),
55
+ read: Effect.fn(function* ({ output, olds }) {
56
+ const project = output?.project ?? olds?.project;
57
+ if (!project)
58
+ return undefined;
59
+ const observed = yield* observe(project);
60
+ if (!observed)
61
+ return undefined;
62
+ if (observed.xpnProjectStatus !== "HOST")
63
+ return undefined;
64
+ // No labels-based ownership: host status is project-scoped
65
+ // state. Any host project we can see we treat as adopted —
66
+ // mirrors `ApiEnable`'s stance.
67
+ return { project, xpnProjectStatus: "HOST" };
68
+ }),
69
+ };
70
+ }));
71
+ //# sourceMappingURL=SharedVpcHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedVpcHost.js","sourceRoot":"","sources":["../../src/Compute/SharedVpcHost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,iCAAiC,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAgD3D,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAgB,mBAAmB,CAAC,CAAC;AAE1E,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,EAAE,CACxC,QAAQ,CAAC,MAAM,CACb,aAAa,EACb,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;IAC/C,MAAM,qBAAqB,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC;IACnE,MAAM,sBAAsB,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC;IACrE,MAAM,mBAAmB,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC;IAC/D,MAAM,OAAO,GAAG,wBAAwB,CAAC,mBAAmB,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,EAAE,CAClC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAC3B,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAC/B,MAAM,CAAC,OAAO,CAAC,SAAwC,CAAC,CACzD,EACD,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,CAChC,MAAM,CAAC,OAAO,CAAC,SAAwC,CAAC,CACzD,CACF,CAAC;IAEJ,OAAO;QACL,OAAO,EAAE,CAAC,SAAS,CAAC;QACpB,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,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChE,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,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,QAAQ,EAAE,gBAAgB,KAAK,MAAM,EAAE,CAAC;gBAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;YAC7D,CAAC;YACD,yDAAyD;YACzD,6DAA6D;YAC7D,wDAAwD;YACxD,2DAA2D;YAC3D,cAAc;YACd,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,qBAAqB,CAAC;gBACtC,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAC/B,MAAM,CAAC,OAAO,CAAC,SAA0C,CAAC,CAC3D,CACF,CAAC;YACF,IAAI,EAAE,EAAE,IAAI;gBAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC7D,CAAC,CAAC;QACF,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;YAC9C,KAAK,CAAC,CAAC,sBAAsB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAC7D,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CACpB,EAAE,CAAC,IAAI;gBACL,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;gBAC3C,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CACvB,EACD,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;YAC9C,iCAAiC;YACjC,6DAA6D;YAC7D,yDAAyD;YACzD,wDAAwD;YACxD,qCAAqC;YACrC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAClC,oDAAoD,CAAC,IAAI,CACvD,CAAC,CAAC,OAAO,IAAI,EAAE,CAChB;gBACC,CAAC,CAAC,MAAM,CAAC,IAAI;gBACb,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CACnB,CACF,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,IAAI,CAAC,OAAO;gBAAE,OAAO,SAAS,CAAC;YAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACzC,IAAI,CAAC,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAChC,IAAI,QAAQ,CAAC,gBAAgB,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC3D,2DAA2D;YAC3D,2DAA2D;YAC3D,gCAAgC;YAChC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC/C,CAAC,CAAC;KACH,CAAC;AACJ,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Provider from "alchemy/Provider";
3
+ import type * as GCP from "../Providers.ts";
4
+ /**
5
+ * Attach a service project to a Shared VPC **host**. Once attached,
6
+ * resources in the service project (clusters, VMs) can use VPCs and
7
+ * subnets owned by the host project.
8
+ *
9
+ * Identity: `(hostProject, serviceProject)`. Both are immutable —
10
+ * changing either replaces. Read uses
11
+ * `compute.projects.getXpnHost({ project: serviceProject })`, which
12
+ * returns the host the service project is attached to (or 4xx if
13
+ * unattached). When the returned host name matches `hostProject`, the
14
+ * attachment is present.
15
+ *
16
+ * The host project must already be enabled (`GCP.SharedVpcHost`), and
17
+ * the IAM principal running the deploy needs `compute.xpnAdmin` at the
18
+ * organisation or folder level — that role is what authorises both
19
+ * sides of the attach (the host, owned by infra; the service project,
20
+ * owned by the team consuming the VPC).
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const host = yield* GCP.SharedVpcHost("ResearchHost", { project: hostProject.projectId });
25
+ * yield* GCP.SharedVpcServiceProject("AttachGkeProj", {
26
+ * hostProject: host.project,
27
+ * serviceProject: gkeProject.projectId,
28
+ * });
29
+ * ```
30
+ */
31
+ export type SharedVpcServiceProjectProps = {
32
+ /** Shared VPC host project ID. Immutable — replace. */
33
+ hostProject: string;
34
+ /** Service project ID to attach. Immutable — replace. */
35
+ serviceProject: string;
36
+ };
37
+ export type SharedVpcServiceProjectAttributes = {
38
+ /** Host project ID. */
39
+ hostProject: string;
40
+ /** Service project ID. */
41
+ serviceProject: string;
42
+ };
43
+ export type SharedVpcServiceProject = Resource<"GCP.SharedVpcServiceProject", SharedVpcServiceProjectProps, SharedVpcServiceProjectAttributes, never, GCP.Providers>;
44
+ export declare const SharedVpcServiceProject: import("alchemy").ResourceClass<SharedVpcServiceProject>;
45
+ export declare const SharedVpcServiceProjectProvider: () => import("effect/Layer").Layer<Provider.Provider<SharedVpcServiceProject>, never, import("effect/unstable/http/HttpClient").HttpClient | import("@distilled.cloud/gcp").Credentials>;
46
+ //# sourceMappingURL=SharedVpcServiceProject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedVpcServiceProject.d.ts","sourceRoot":"","sources":["../../src/Compute/SharedVpcServiceProject.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAC5C,6BAA6B,EAC7B,4BAA4B,EAC5B,iCAAiC,EACjC,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AACF,eAAO,MAAM,uBAAuB,0DAEnC,CAAC;AAEF,eAAO,MAAM,+BAA+B,0LA2HzC,CAAC"}