1import * as Effect from "effect/Effect";
2import * as Layer from "effect/Layer";
3import * as Output from "../Output.ts";
4import type { Account } from "./Account.ts";
5import {
6 accountLayer,
7 issueCertificate,
8 revokeCertificate,
9 type AccountCredentials,
10} from "./Client.ts";
11import {
12 IssueCertificate,
13 type IssueCertificateClient,
14} from "./IssueCertificate.ts";
15
16/**
17 * Implementation of {@link IssueCertificate}: the account's directory
18 * URL, account URL and private key are bound into the host at deploy time
19 * and read back at runtime; every call signs with them over HTTPS.
20 *
21 * Provide it on the Worker / Service / Action Effect.
22 *
23 * ### Provide the layer
24 * **Example:** On a Fly Service
25 * ```typescript
26 * Effect.gen(function* () {
27 * const acme = yield* ACME.IssueCertificate(LetsEncrypt);
28 * // ...
29 * }).pipe(Effect.provide(ACME.IssueCertificateHttp))
30 * ```
31 *
32 * @layer
33 * @product Certificate
34 * @provides ACME.IssueCertificate
35 */
36export const IssueCertificateHttp = Layer.succeed(
37 IssueCertificate,
38 Effect.fn(function* (account: Account) {
39 const directoryUrl = yield* account.directoryUrl;
40 const accountUrl = yield* account.accountUrl;
41 const trustedRoot = yield* account.trustedRoot.pipe(
42 Output.map((root) => root ?? ""),
43 );
44 const privateKey = yield* account.privateKey;
45 const credentials = Effect.all({
46 directoryUrl,
47 trustedRoot,
48 accountUrl,
49 privateKey,
50 }).pipe(
51 Effect.map((bound): AccountCredentials => ({
52 ca: {
53 directoryUrl: bound.directoryUrl,
54 trustedRoot: bound.trustedRoot || undefined,
55 },
56 accountKey: bound.privateKey,
57 accountUrl: bound.accountUrl,
58 })),
59 );
60 const client: IssueCertificateClient = {
61 issue: Effect.fn("ACME.IssueCertificate.issue")(function* (request) {
62 const creds = yield* credentials;
63 return yield* issueCertificate(request).pipe(
64 Effect.provide(accountLayer(creds)),
65 );
66 }),
67 revoke: Effect.fn("ACME.IssueCertificate.revoke")(function* (request) {
68 const creds = yield* credentials;
69 return yield* revokeCertificate(request).pipe(
70 Effect.provide(accountLayer(creds)),
71 );
72 }),
73 };
74 return client;
75 }),
76);