@sellable/install
Version:
One-command installer for Sellable MCP in Claude Code, Codex, and Hermes
118 lines (108 loc) • 4.01 kB
JavaScript
import { createHash } from "node:crypto";
export const SOUL_ARTIFACT_MAX_BYTES = 64 * 1024;
export const SOUL_EFFECTIVE_MAX_CHARACTERS = 20_000;
const SECRET_PATTERNS = Object.freeze([
/(?:^|[^A-Za-z0-9])(?:xapp|xoxb|xoxa|sat)[_-][A-Za-z0-9_-]+/i,
/sk_lf_[A-Za-z0-9_-]{8,}/i,
/asec\.v1\./i,
/wkey\.v1\./i,
/authorization[_-]?code/i,
/access[_-]?token/i,
/refresh[_-]?token/i,
/\bctok_[0-9a-f]{32}\b/i,
/"(?:connectHandle|handle|callbackNonce|nonce|connectLinkUrl|connectToken)"\s*:/i,
]);
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
export class SoulArtifactValidationError extends Error {
constructor(code) {
super(code);
this.name = "SoulArtifactValidationError";
this.code = code;
}
}
function invalid(code) {
return Object.freeze({ ok: false, code });
}
function decodeUtf8(input) {
if (typeof input === "string") {
const bytes = Buffer.from(input, "utf8");
// Node replaces unpaired UTF-16 surrogates during UTF-8 encoding. Reject
// them so the raw hash always describes the exact caller-visible text.
if (bytes.toString("utf8") !== input) return invalid("soul_utf8_invalid");
return { ok: true, content: input, bytes };
}
if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) {
return invalid("soul_content_invalid");
}
const bytes = Buffer.from(input);
try {
const content = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
return { ok: true, content, bytes };
} catch {
return invalid("soul_utf8_invalid");
}
}
/**
* The one portable SOUL content contract used by server compilation and by
* the installed Machine bridge. Results are intentionally redacted: invalid
* content never appears in messages, details, logs, or receipts.
*/
export function validateSoulArtifact(
input,
{ enforceEffectiveLimit = true } = {}
) {
const decoded = decodeUtf8(input);
if (!decoded.ok) return decoded;
const { bytes, content } = decoded;
if (bytes.byteLength < 1) return invalid("soul_empty");
if (bytes.byteLength > SOUL_ARTIFACT_MAX_BYTES) {
return invalid("soul_bytes_exceeded");
}
if (content.charCodeAt(0) === 0xfeff) return invalid("soul_bom_rejected");
if (content.includes("\0")) return invalid("soul_nul_rejected");
if (!content.trim()) return invalid("soul_empty");
// Existing published SOUL artifacts conventionally end in one LF. Hermes
// strips that LF, so accept exactly that established representation while
// rejecting every other trim delta (leading space, trailing spaces/CR, or
// multiple terminal whitespace). Raw and effective hashes remain distinct.
const effectiveContent = content.endsWith("\n")
? content.slice(0, -1)
: content;
if (
!effectiveContent ||
effectiveContent.trim() !== effectiveContent ||
(content !== effectiveContent && content !== `${effectiveContent}\n`)
) {
return invalid("soul_trim_changes_effective_content");
}
const effectiveBytes = Buffer.from(effectiveContent, "utf8");
const characterCount = Array.from(effectiveContent).length;
if (enforceEffectiveLimit && characterCount > SOUL_EFFECTIVE_MAX_CHARACTERS) {
return invalid("soul_effective_limit_exceeded");
}
if (SECRET_PATTERNS.some((pattern) => pattern.test(content))) {
return invalid("soul_secret_material_rejected");
}
return Object.freeze({
ok: true,
content,
bytes,
byteLength: bytes.byteLength,
characterCount,
rawFileSha256: sha256(bytes),
effectiveSha256: sha256(effectiveBytes),
effectiveByteLength: effectiveBytes.byteLength,
});
}
export function assertSoulArtifact(input, options) {
const result = validateSoulArtifact(input, options);
if (!result.ok) throw new SoulArtifactValidationError(result.code);
return result;
}
export function containsSoulSecretMaterial(input) {
const decoded = decodeUtf8(input);
return (
decoded.ok &&
SECRET_PATTERNS.some((pattern) => pattern.test(decoded.content))
);
}