1import * as ces from "@distilled.cloud/gcp/ces_v1";
2import * as Effect from "effect/Effect";
3import {
4 waitForOperation as waitForLongRunning,
5 type LongRunningOperation,
6} from "../Operation.ts";
7
8// A display-name clash ("App with display name … already exists") also reports
9// ALREADY_EXISTS but means our resource was never created, so it must fail.
10
11/** CES app and agent operations finish within a few minutes. */
12const OPERATION_BUDGET = "10 minutes";
13
14/**
15 * Wait for a long-running operation. ALREADY_EXISTS (code 6) means a
16 * concurrent create won the race; reconcile observes the resource next.
17 */
18export const waitForOperation = (operation: LongRunningOperation) =>
19 waitForLongRunning(
20 operation,
21 (name) => ces.getProjectsLocationsOperations({ name }),
22 {
23 budget: OPERATION_BUDGET,
24 },
25 ).pipe(
26 Effect.catchIf(
27 (error) => error._tag === "GCP.OperationFailed" && error.code === 6,
28 () => Effect.succeed(operation),
29 ),
30 );
31
32/**
33 * Wait for a delete operation. A vanished operation or NOT_FOUND (code 5)
34 * means the resource is already gone.
35 */
36export const waitForDeleteOperation = (operation: LongRunningOperation) =>
37 waitForOperation(operation).pipe(
38 Effect.catchIf(
39 (error) =>
40 error._tag === "NotFound" ||
41 (error._tag === "GCP.OperationFailed" && error.code === 5),
42 () => Effect.succeed(operation),
43 ),
44 );