Transformations
sensored supports five transformation actions. Each detector rule specifies which action to apply when a match is found.
Action precedence
When matches overlap, actions are resolved by precedence:
remove > redact > format-preserve > token-replace > mask
The highest-precedence action in an overlap group wins.
redact
Replaces the matched span with a type label like [EMAIL]. When restoration is enabled, labels are numbered: [EMAIL_1], [EMAIL_2], etc.
const redactor = createRedactor({
rules: { email: { action: "redact" } },
});
redactor.redact("Contact: john@example.com");
// "Contact: [EMAIL_1]"You can provide a custom replacement string and priority:
const redactor = createRedactor({
rules: {
email: { action: "redact", replacement: "[REDACTED]", priority: 10 },
},
});mask
Preserves the first and/or last N grapheme clusters, replacing the rest with *. Useful when you need to show partial values for verification.
const redactor = createRedactor({
rules: {
email: { action: "mask", preserve: { first: 2 } },
phone: { action: "mask", preserve: { first: 3, last: 4 } },
},
});
redactor.redact("Email: john@example.com, Phone: 555-123-4567");
// "Email: jo************, Phone: 555-****-4567"preserve.first— number of leading grapheme clusters to keeppreserve.last— number of trailing grapheme clusters to keep
If neither is specified, the entire match is replaced with * characters.
remove
Deletes the matched span entirely from the output.
const redactor = createRedactor({
rules: { phone: { action: "remove" } },
});
redactor.redact("Call 555-123-4567 now");
// "Call now"format-preserve
Transforms digits to X and letters to * while preserving separators, spaces, and structural characters. Useful when you need to maintain the format of the original text for downstream parsing.
const redactor = createRedactor({
rules: { payment_card: { action: "format-preserve" } },
});
redactor.redact("Card: 4532-1234-5678-9012");
// "Card: ****-****-****-****"token-replace
Generates deterministic fake data per entity type using FNV-1a 32-bit hashing. The same input always produces the same fake output, making it useful for consistent test data or anonymized datasets.
const redactor = createRedactor({
rules: { email: { action: "token-replace" } },
});
redactor.redact("Email: john@example.com");
// "Email: alicia.morgan@exmail.net"
// Same input always produces the same token
redactor.redact("Email: john@example.com");
// "Email: alicia.morgan@exmail.net"You can provide custom token mappings to override the default generators:
const redactor = createRedactor({
rules: {
email: {
action: "token-replace",
tokens: { email: "redacted@example.com" },
},
},
});Idempotency
All transformations are idempotent. Re-redacting already-redacted text is a no-op — the library detects placeholder patterns like [EMAIL] and [EMAIL_1] and skips detection within those spans.