1import { Random } from "../../Random.ts";
2import * as Effect from "effect/Effect";
3import * as Secret from "../SecretsStore/Secret.ts";
4import { Store as SecretsStore } from "../SecretsStore/SecretsStore.ts";
5
6/**
7 * The account-wide Secrets Store that backs every secret used by the
8 * state store worker. `SecretsStore` adopts the single store that
9 * already exists on the account, or creates one if none exists.
10 */
11export const Store = SecretsStore("StateStoreSecrets");
12
13/**
14 * The randomly generated bearer token value. Generated once on create
15 * and persisted in alchemy state, so subsequent deploys keep the same
16 * value unless the resource is replaced.
17 */
18export const TokenValue = Random("StateStoreAuthTokenValue");
19
20/**
21 * The name of the secret in the Cloudflare Secrets Store that contains the bearer token.
22 */
23export const AuthTokenSecretName = "AlchemyStateStoreToken" as const;
24
25/**
26 * The bearer token used to authenticate every request to the state
27 * store worker. The value comes from {@link TokenValue} and lives in
28 * the account-wide Cloudflare Secrets Store so it can be bound into
29 * the worker without bundling the raw string.
30 */
31export const AuthToken = Effect.gen(function* () {
32 const store = yield* Store;
33 const random = yield* TokenValue;
34 return yield* Secret.Secret(AuthTokenSecretName, {
35 name: AuthTokenSecretName,
36 store,
37 value: random.text,
38 });
39});
40
41/**
42 * A 32-byte (256-bit) random value, hex-encoded, that seeds the
43 * AES-CTR key used to encrypt resource state at rest. Generated once
44 * and persisted, so the ciphertext stored by the Durable Object can
45 * always be decrypted by subsequent worker boots.
46 */
47export const EncryptionKeyValue = Random("StateStoreEncryptionKeyValue", {
48 bytes: 32,
49});
50
51export const EncryptionKeySecretName =
52 "AlchemyStateStoreEncryptionKey" as const;
53
54/**
55 * The encryption key secret. The raw hex-encoded bytes live inside
56 * Cloudflare's Secrets Store; the Durable Object binds to it at
57 * runtime to derive an AES-CTR `CryptoKey` via Web Crypto's
58 * `subtle.importKey`.
59 */
60export const EncryptionKey = Effect.gen(function* () {
61 const store = yield* Store;
62 const random = yield* EncryptionKeyValue;
63 return yield* Secret.Secret("StateStoreEncryptionKey", {
64 name: EncryptionKeySecretName,
65 store,
66 value: random.text,
67 });
68});