1import { Credentials } from "@distilled.cloud/gcp/Credentials";
2import * as Effect from "effect/Effect";
3import * as HttpClient from "effect/http/HttpClient";
4import type { Job } from "./Job.ts";
5import { bindGcpHost } from "../Host.ts";
6import { grantFor, type BindingIam } from "../HttpBinding.ts";
7
8/**
9 * Shared HTTP scaffolding for Cloud Scheduler job bindings.
10 * NOT exported from index.ts.
11 *
12 * Distilled ops are `OperationMethod`s: yield them once at Layer construction
13 * (after providing Credentials + HttpClient) so the inner runtime Effect is
14 * `Effect<A, E>` and does not leak `GcpOpContext`.
15 */
16export const makeJobHttpBinding = <I extends { name?: string }, A, E>(options: {
17 tag: string;
18 iam: BindingIam;
19 operation: Effect.Effect<
20 (input: I) => Effect.Effect<A, E>,
21 never,
22 Credentials | HttpClient.HttpClient
23 > &
24 ((input: I) => Effect.Effect<A, E, Credentials | HttpClient.HttpClient>);
25}) =>
26 Effect.gen(function* () {
27 const run = yield* options.operation;
28 return Effect.fn(function* (job: Job) {
29 yield* bindGcpHost({
30 tag: options.tag,
31 resource: job,
32 iam: [grantFor(options.iam, job.name)],
33 });
34 const name = yield* job.name;
35 return Effect.fn(`${options.tag}(${job.LogicalId})`)(function* (
36 request?: Omit<I, "name">,
37 ) {
38 const jobName = yield* name;
39 return yield* run({
40 ...(request ?? {}),
41 name: jobName,
42 } as I);
43 });
44 });
45 });