1import * as androiddeviceprovisioning from "@distilled.cloud/gcp/androiddeviceprovisioning_v1";
2import * as Effect from "effect/Effect";
3import { MinimumLogLevel } from "effect/References";
4import * as Schedule from "effect/Schedule";
5
6export const logLevel = Effect.provideService(
7 MinimumLogLevel,
8 process.env.DEBUG ? "Debug" : "Info",
9);
10
11const lastSegment = (value: string) => {
12 const trimmed = value.replace(/\/+$/, "");
13 const parts = trimmed.split("/");
14 return parts[parts.length - 1] || trimmed;
15};
16
17export const toCustomerName = (value: string) => {
18 const trimmed = value.replace(/\/+$/, "").trim();
19 if (trimmed.length === 0) return "";
20 const idx = trimmed.lastIndexOf("/customers/");
21 if (idx >= 0) {
22 const id = trimmed.slice(idx + "/customers/".length).split("/")[0] ?? "";
23 return id.length > 0 ? `customers/${id}` : "";
24 }
25 if (trimmed.startsWith("customers/")) {
26 const id = trimmed.slice("customers/".length).split("/")[0] ?? "";
27 return id.length > 0 ? `customers/${id}` : trimmed;
28 }
29 return `customers/${lastSegment(trimmed)}`;
30};
31
32export const customerName = (() => {
33 const raw =
34 process.env.GCP_ANDROIDDEVICEPROVISIONING_CUSTOMER?.trim() ||
35 process.env.GCP_ANDROIDDEVICEPROVISIONING_CUSTOMER_ID?.trim();
36 return raw ? toCustomerName(raw) : undefined;
37})();
38
39// Needs a zero-touch customer the credentials administer
40// (GCP_ANDROIDDEVICEPROVISIONING_CUSTOMER); zero-touch is a partner/reseller
41// portal with no self-serve customer for a service account.
42export const runLifecycle = !!customerName;
43
44export const probeParent = "customers/0";
45export const probeName = `${probeParent}/configurations/0`;
46
47const ANDROID_DEVICE_POLICY_PACKAGE = "com.google.android.apps.work.clouddpc";
48
49export const resolveDpc = (parent: string) =>
50 androiddeviceprovisioning.listCustomersDpcs({ parent }).pipe(
51 Effect.map((page) => {
52 const dpcs = page.dpcs ?? [];
53 const preferred = dpcs.find(
54 (dpc) => dpc.packageName === ANDROID_DEVICE_POLICY_PACKAGE && dpc.name,
55 );
56 return preferred?.name ?? dpcs.find((dpc) => dpc.name)?.name;
57 }),
58 Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
59 Effect.map((name) => name ?? `${parent}/dpcs/alchemy-missing`),
60 );
61
62export const waitUntilGone = (name: string) =>
63 androiddeviceprovisioning.getCustomersConfigurations({ name }).pipe(
64 Effect.as("found" as const),
65 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
66 Effect.repeat({
67 schedule: Schedule.spaced("1 second"),
68 until: (status) => status === "gone",
69 times: 10,
70 }),
71 );