1import type {
2 AppSecretsUpdateResp,
3 DeleteAppSecretResponse,
4 CreateSecretError,
5 DeleteSecretError,
6 UpdateSecretsError,
7 SetAppSecretResponse,
8} from "@distilled.cloud/fly-io/machines";
9import * as Effect from "effect/Effect";
10import type * as Redacted from "effect/Redacted";
11import * as Binding from "../Binding.ts";
12import type { RuntimeContext } from "../RuntimeContext.ts";
13import type { Secret } from "./Secret.ts";
14
15/**
16 * Create, update, and delete Fly.io App secrets at runtime.
17 *
18 * The App is fixed by `WriteSecret(secret)`. Calls take no
19 * `app_name`. Inside a {@link Machine} or {@link Service}, Alchemy
20 * mints an App deploy token. Inside an Action, the ambient
21 * `FLY_API_TOKEN` is used.
22 *
23 *
24 * ### Create
25 * Bind the client in init. Provide {@link WriteSecretHttp}. Wrap
26 * values with `Redacted.make`.
27 *
28 * **Example:** Create a secret
29 * ```typescript
30 * const Seed = Alchemy.Action(
31 * "Seed",
32 * Effect.gen(function* () {
33 * const secrets = yield* Fly.WriteSecret(ApiToken);
34 *
35 * return Effect.fn(function* () {
36 * yield* secrets.create("API_KEY", Redacted.make("sk_live"));
37 * });
38 * }).pipe(Effect.provide(Fly.WriteSecretHttp)),
39 * );
40 * ```
41 *
42 * ### Update
43 * `update` rotates by name (batch of one).
44 *
45 * **Example:** Rotate
46 * ```typescript
47 * yield* secrets.update("API_KEY", Redacted.make("sk_live_rotated"));
48 * ```
49 *
50 * ### Delete
51 * `delete` removes a secret by name.
52 *
53 * **Example:** Delete
54 * ```typescript
55 * yield* secrets.delete("API_KEY");
56 * ```
57 *
58 * @binding
59 * @product Secret
60 */
61export interface WriteSecret extends Binding.Service<
62 WriteSecret,
63 "Fly.WriteSecret",
64 (secret: Secret) => Effect.Effect<WriteSecretClient>
65> {}
66
67export const WriteSecret = Binding.Service<WriteSecret>("Fly.WriteSecret");
68
69/**
70 * Mutating App secret operations. The App is fixed when the client is
71 * bound, so no `app_name` is passed per call.
72 */
73export interface WriteSecretClient {
74 /** Create or upsert a secret by name. */
75 create(
76 name: string,
77 value: Redacted.Redacted<string> | string,
78 ): Effect.Effect<SetAppSecretResponse, CreateSecretError, RuntimeContext>;
79 /** Update secrets by name (batch of one). */
80 update(
81 name: string,
82 value: Redacted.Redacted<string> | string,
83 ): Effect.Effect<AppSecretsUpdateResp, UpdateSecretsError, RuntimeContext>;
84 /** Delete a secret by name. */
85 delete(
86 name: string,
87 ): Effect.Effect<DeleteAppSecretResponse, DeleteSecretError, RuntimeContext>;
88}