API reference › @evolu/common › Type › redacted

function redacted<Inner extends AnyType>(
  inner: ValidateRedactedInner<Inner>,
): RedactedType<Inner>;

Defined in: packages/common/src/Type.ts:10084

Validates a secret string with an inner Type and wraps the inner Output in Redacted.

Use it where an app receives a secret it holds, such as a form field or environment configuration, so the decoded value does not leak through logging or serialization.

The inner Type's errors are returned unchanged, so it must refine String, and its errors must not contain the value, as with SimplePassword, Mnemonic, and brands over them. The compiler rejects an inner Type that does not refine String or whose errors have a value property, such as minLength or regex, so a custom inner error must not keep the input under another name. A non-string fails with a value-free RedactedError instead of the String error, which keeps the input.

Encoding reveals the secret: to and json encode the revealed value with the inner Type. A json parse error keeps the whole malformed text, which can contain the secret. Each decode creates a new wrapper, so compare round trips by their revealed values.

The Output is not Data, so it cannot be an Evolu column or an item of unique.

A union lets its other members see the raw input, and their errors keep it. By default, a union reports the error of its first member, so a member listed before the redacted Type leaks the secret. When all errors are collected, as with { errors: "all" } and always with Standard Schema validation, every member does, including the Null or Undefined member of nullOr or undefinedOr, which list the redacted Type first. Prefer optional for an absent secret, or list the redacted Type first.

Example

import {
  assertEqual,
  assertErr,
  assertOk,
  object,
  redacted,
  revealRedacted,
  SimplePassword,
  String,
} from "@evolu/common";

const SignIn = object({
  email: String,
  password: redacted(SimplePassword),
});

const signIn = SignIn.fromUnknown({
  email: "ada@example.com",
  password: "correct horse",
});
assertOk(signIn);
assertEqual(revealRedacted(signIn.value.password), "correct horse");
assertEqual(
  JSON.stringify(signIn.value),
  '{"email":"ada@example.com","password":"<redacted>"}',
);
// Encoding reveals the secret.
assertEqual(SignIn.to(signIn.value).password, "correct horse");

assertErr(SignIn.fromUnknown({ email: "ada@example.com", password: "short" }), {
  type: "Object",
  reason: {
    kind: "Properties",
    errors: {
      password: { type: "SimplePassword", reason: "TooShort" },
    },
  },
});
assertErr(SignIn.fromUnknown({ email: "ada@example.com", password: 42 }), {
  type: "Object",
  reason: {
    kind: "Properties",
    errors: { password: { type: "Redacted" } },
  },
});