lib/knowledge-db-import-validation.js
Rama main · réplica de lectura del repositorio original.
var crypto = require("crypto");
var validation = require("./knowledge-db-validation");
var MAX_BATCH_ROWS = 100;
var MAX_BATCH_BYTES = 256 * 1024;
function fail(message, code) { throw Object.assign(new Error(message), { code: code || "INVALID" }); }
function json(value, depth) {
if (depth > 32) fail("Import JSON exceeds 32 nesting levels.");
if (value === null || typeof value === "string" || typeof value === "boolean") return;
if (typeof value === "number" && Number.isFinite(value)) return;
if (typeof value !== "object" || !value) fail("Import payload must contain finite JSON values.");
if (!Array.isArray(value)) validation.plainObject(value, "Import payload");
Object.keys(value).forEach(function (key) { json(value[key], depth + 1); });
}
function canonical(value) {
if (Array.isArray(value)) return value.map(canonical);
if (!value || typeof value !== "object") return value;
var out = {}; Object.keys(value).sort().forEach(function (key) { out[key] = canonical(value[key]); }); return out;
}
function identity(namespace, key) { return JSON.stringify([namespace, key]); }
function sourceText(value, label, max) {
var clean = validation.text(value, label, max, false);
if (clean !== value) fail(label + " must not have surrounding whitespace.");
return clean;
}
function batch(args) {
validation.plainObject(args, "Import request");
var namespace = sourceText(args.sourceNamespace, "Source namespace", 120);
if (!Array.isArray(args.rows) || !args.rows.length || args.rows.length > MAX_BATCH_ROWS) fail("Import batch must contain between 1 and " + MAX_BATCH_ROWS + " rows.", "IMPORT_BATCH_LIMIT");
json(args.rows, 0);
if (Buffer.byteLength(JSON.stringify(args.rows), "utf8") > MAX_BATCH_BYTES) fail("Import rows exceed the " + MAX_BATCH_BYTES + " byte input limit.", "IMPORT_BYTES_LIMIT");
var seen = new Set();
var rows = args.rows.map(function (row) {
validation.plainObject(row, "Import row");
var key = sourceText(row.sourceKey, "Source row key", 200);
if (seen.has(key)) fail("Import batch contains duplicate source row keys.");
seen.add(key);
if (!Object.prototype.hasOwnProperty.call(row, "sourcePayload")) fail("Each import row needs an immutable sourcePayload.");
validation.plainObject(row.values, "Import values");
var fingerprint = crypto.createHash("sha256").update(JSON.stringify(canonical({ sourcePayload: row.sourcePayload, values: row.values }))).digest("hex");
return { sourceKey: key, fingerprint: fingerprint, values: row.values };
});
return { sourceNamespace: namespace, rows: rows };
}
module.exports = { batch: batch, identity: identity, sourceText: sourceText, MAX_BATCH_ROWS: MAX_BATCH_ROWS, MAX_BATCH_BYTES: MAX_BATCH_BYTES };