# Redacted

Secrets — API keys, passwords, tokens — have a way of escaping into log lines,
error messages, and serialized output. `Redacted<A>` wraps a sensitive value so
that its string, JSON, and inspection representations all render as
`<redacted>`, never the underlying secret. The real value is held off to the
side and is only recoverable by explicitly calling `Redacted.value`, which makes
every point of exposure visible and greppable in your code.

```ts
import { Redacted } from "effect"

// Wrap a secret — the value is now protected from accidental logging
const apiKey = Redacted.make("sk-1234567890abcdef")

console.log(apiKey)            // <redacted>
console.log(`Bearer ${apiKey}`) // "Bearer <redacted>"
console.log(JSON.stringify({ apiKey }))   // {"apiKey":"<redacted>"}

// You must opt in, explicitly, to read the real value
console.log(Redacted.value(apiKey)) // "sk-1234567890abcdef"
```

Every accidental path — `console.log`, string interpolation, `JSON.stringify` —
shows `<redacted>`. Only the deliberate `Redacted.value(apiKey)` call exposes the
secret, so a code reviewer can audit exactly where secrets are read.

## Creating and reading

```ts
import { Redacted } from "effect"

const secret = Redacted.make("my-password")

// Recover the wrapped value (use sparingly, at the point of use)
const plain = Redacted.value(secret)
```

You can attach a label, which appears in the rendered output. The label itself
is *not* secret, so it helps you tell redacted values apart in logs without
revealing anything:

```ts
import { Redacted } from "effect"

const token = Redacted.make("secret-token", { label: "api-token" })

console.log(token) // <redacted:api-token>
```

## Value equality

`Redacted` compares by the wrapped value, so two redacted wrappers holding the
same secret are `Equal.equals` — without either of them exposing the secret:

```ts
import { Redacted, Equal } from "effect"

console.log(Equal.equals(Redacted.make("abc"), Redacted.make("abc"))) // true
console.log(Equal.equals(Redacted.make("abc"), Redacted.make("xyz"))) // false
```

## Reading secrets from configuration

The most common source of a secret is configuration. `Config.redacted` reads an
environment value and wraps it in a `Redacted` automatically, so a misconfigured
log statement can never print it. See [Configuration](https://effect.plants.sh/configuration/) for the
full configuration story.

```ts
import { Config, ConfigProvider, Effect } from "effect"

const program = Effect.gen(function* () {
  // apiKey is a Redacted<string>, not a raw string
  const apiKey = yield* Config.redacted("API_KEY")
  console.log(apiKey) // <redacted>
})

const provider = ConfigProvider.fromEnv({
  env: { API_KEY: "sk-1234567890abcdef" }
})

Effect.runSync(
  program.pipe(
    Effect.provideService(ConfigProvider.ConfigProvider, provider)
  )
)
// Output: <redacted>
```

When you actually need to send the key — as an `Authorization` header, say — call
`Redacted.value` at that single, intentional point. Everywhere else the value
stays protected.

## Wiping a secret

For extra safety, `Redacted.wipeUnsafe` deletes the stored value, after which any
further `Redacted.value` call on that wrapper fails. Use it once a short-lived
secret is no longer needed so it cannot be recovered later.

## Redacted in schemas

When a secret crosses a boundary that decodes input — an [HTTP API](https://effect.plants.sh/http-api/)
request body, a config file — use `Schema.Redacted` from the [Schema](https://effect.plants.sh/schema/)
module so the value is wrapped as part of decoding. That is exactly what
`Config.redacted` does under the hood (`Schema.Redacted(Schema.String)`).