@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
93 lines (92 loc) • 4.5 kB
JavaScript
import { BINARY_KEYS, BINARY_PAYLOAD_MIN_CHARS, REDACTED_VALUE, } from "../constants/telemetry.js";
const TOKEN_KEY_PATTERN = /tokens?$/;
const BASE64_PATTERN = /^[A-Za-z0-9+/_\-=\s]+$/;
const MIME_TYPE_KEYS = ["mimeType", "mediaType", "media_type", "mime_type"];
const DATA_URL_PATTERN = new RegExp(`data:([\\w.+-]+/[\\w.+-]+)?(?:;[\\w=.+-]+)*;base64,[A-Za-z0-9+/_\\-=]{${BINARY_PAYLOAD_MIN_CHARS},}`, "g");
const ENV_SECRET_PATTERN = /\b([\w.-]*(?:api[_-]?key|secret|password|passwd|token|credential|private[_-]?key|signature)[\w.-]*)(\s*[=:]\s*)(?!\d+\b)[^\s&"',;]+/gi;
const BARE_SECRET_PATTERN = /\b(?:sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|AKIA[0-9A-Z]{16}|xox[baprs]-[A-Za-z0-9-]{10,})/g;
function normalizeKey(key) {
return key.replace(/[_-]/g, "").toLowerCase();
}
function maskStrings(value) {
if (typeof value === "string") {
return REDACTED_VALUE;
}
if (Array.isArray(value)) {
return value.map(maskStrings);
}
if (value === null || typeof value !== "object") {
return value;
}
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, maskStrings(entry)]));
}
/**
* @description Masks the value stored under a credential-looking key. Structures under a plural token key (`tokens`) keep their shape with every string masked; anything else collapses to the placeholder.
* @param key {string} - Property name that matched the sensitive-key pattern.
* @param entry {JsonValue} - Value stored under that key.
* @returns {JsonValue} The masked value.
*/
export function redactSensitiveEntry(key, entry) {
const isStructure = typeof entry === "object" && entry !== null;
return isStructure && TOKEN_KEY_PATTERN.test(normalizeKey(key))
? maskStrings(entry)
: REDACTED_VALUE;
}
/**
* @description Masks credentials written as `name=value`, `name: value` or as a recognizable bare key (OpenAI, GitHub, AWS, Slack). Purely numeric values after a credential-looking name are left alone.
* @param text {string} - Text to scan.
* @returns {string} The text with credential values replaced.
*/
export function redactSecretAssignments(text) {
return text
.replace(ENV_SECRET_PATTERN, (_match, key, separator) => `${key}${separator}${REDACTED_VALUE}`)
.replace(BARE_SECRET_PATTERN, REDACTED_VALUE);
}
/**
* @description Replaces inline base64 data URLs with a size and MIME-type placeholder.
* @param text {string} - Text to scan.
* @returns {string} The text with each data URL payload replaced by `[N bytes mime/type]`.
*/
export function describeDataUrls(text) {
return text.replace(DATA_URL_PATTERN, (match, mimeType) => `[${Math.floor(((match.length - match.indexOf(",") - 1) * 3) / 4)} bytes${mimeType ? ` ${mimeType}` : ""}]`);
}
/**
* @description Tells whether an object key conventionally holds a binary payload.
* @param key {string} - Property name.
* @returns {boolean} `true` for keys such as `data`, `image`, `bytes` and `base64`.
*/
export function isBinaryKey(key) {
return BINARY_KEYS.has(normalizeKey(key));
}
/**
* @description Reads the MIME type an object declares for its payload.
* @param node {object} - Object that may carry `mimeType`, `mediaType`, `media_type` or `mime_type`.
* @returns {string | undefined} The declared MIME type, or `undefined` when none is a string.
*/
export function declaredMimeType(node) {
for (const key of MIME_TYPE_KEYS) {
const declared = Reflect.get(node, key);
if (typeof declared === "string") {
return declared;
}
}
return undefined;
}
/**
* @description Describes a binary payload by size instead of content.
* @param value {ArrayBuffer | ArrayBufferView | string} - Raw bytes, or a base64 string long enough to be treated as bytes.
* @param mimeType {string | undefined} - MIME type to include in the placeholder.
* @returns {string | undefined} `[N bytes mime/type]`, or `undefined` when the value is not binary.
*/
export function binaryPlaceholder(value, mimeType) {
const suffix = mimeType ? ` ${mimeType}` : "";
if (typeof value !== "string") {
return value instanceof ArrayBuffer || ArrayBuffer.isView(value)
? `[${value.byteLength} bytes${suffix}]`
: undefined;
}
if (value.length > BINARY_PAYLOAD_MIN_CHARS && BASE64_PATTERN.test(value)) {
return `[${Math.floor((value.length * 3) / 4)} bytes${suffix}]`;
}
return undefined;
}