1import * as Effect from "effect/Effect";
2import type * as HttpClient from "effect/http/HttpClient";
3import { CloudflareEnvironment } from "../CloudflareEnvironment.ts";
4import type { Credentials } from "../Credentials.ts";
5import type { TunnelAuth } from "./TunnelBinding.ts";
6
7/**
8 * Shared scaffolding for the `*Local` tunnel services.
9 *
10 * Instead of minting a scoped {@link AccountApiToken} (the `*Binding` path), it
11 * captures the ambient current-credentials context available during stack-eval
12 * and builds a {@link TunnelAuth} that provides those credentials directly to
13 * the cfd_tunnel HTTP ops. It then delegates to the same client builders the
14 * `*Binding` variant uses.
15 *
16 * NOT exported from `index.ts` — this is internal scaffolding shared by the
17 * three access-level Local layers.
18 */
19export const makeLocalTunnelClient = <Client>(
20 makeClient: (auth: TunnelAuth) => Client,
21) =>
22 Effect.gen(function* () {
23 // Account + credentials are ambient during stack-eval (the stack's
24 // providers layer). Capture the full context so cfd_tunnel HTTP ops can run
25 // with the current credentials — no `host.bind`, no minted token.
26 const { accountId } = yield* yield* CloudflareEnvironment;
27 const context = yield* Effect.context<
28 Credentials | HttpClient.HttpClient
29 >();
30
31 return Effect.fn(function* () {
32 const auth: TunnelAuth = {
33 authorize: (eff) => eff.pipe(Effect.provideContext(context)),
34 accountId: Effect.succeed(accountId),
35 };
36 return makeClient(auth);
37 });
38 });