@baruchiro/paperless-mcp
Version:
Model Context Protocol (MCP) server for interacting with Paperless-NGX document management system. Enables AI assistants to manage documents, tags, correspondents, and document types through the Paperless-NGX API.
165 lines (164 loc) • 9.12 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_test_1 = require("node:test");
const strict_1 = __importDefault(require("node:assert/strict"));
const selectFields_1 = require("./selectFields");
const LEGACY_SELECT_FIELD = {
id: 2,
name: "Retention period",
data_type: "select",
extra_data: { select_options: ["1 year", "7 years", "2 years"], default_currency: null },
document_count: 10,
};
const OBJECT_SELECT_FIELD = {
id: 3,
name: "Priority",
data_type: "select",
extra_data: {
select_options: [
{ id: "abc123", label: "Low" },
{ id: "def456", label: "High" },
],
},
document_count: 5,
};
const STRING_FIELD = {
id: 4,
name: "Reference",
data_type: "string",
document_count: 1,
};
(0, node_test_1.describe)("resolveSelectCustomFieldValue", () => {
(0, node_test_1.test)("translates a label to its zero-based index (pre-2.17 string options)", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, "1 year"), 0);
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, "7 years"), 1);
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, "2 years"), 2);
});
(0, node_test_1.test)("translates a label to its zero-based index (2.17+ object options)", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "Low"), 0);
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "High"), 1);
});
(0, node_test_1.test)("passes through an already-encoded index (pre-2.17)", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, 1), 1);
});
(0, node_test_1.test)("maps an option id back to its zero-based index (2.17+ round-trip)", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "def456"), 1);
});
(0, node_test_1.test)("resolves both the label and the option id to the same index", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "Low"), 0);
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "abc123"), 0);
});
(0, node_test_1.test)("returns null unchanged so the field can be cleared", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, null), null);
});
(0, node_test_1.test)("leaves non-select field values untouched", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(STRING_FIELD, "1 year"), "1 year");
});
(0, node_test_1.test)("throws an actionable error listing valid options for an unknown value", () => {
strict_1.default.throws(() => (0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, "forever"), (err) => {
strict_1.default.match(err.message, /forever/);
strict_1.default.match(err.message, /Retention period/);
strict_1.default.match(err.message, /1 year/);
strict_1.default.match(err.message, /7 years/);
return true;
});
});
(0, node_test_1.test)("rejects an out-of-range index rather than forwarding it", () => {
strict_1.default.throws(() => (0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, 9));
});
(0, node_test_1.test)("throws on a value that matches one option's label and another's id", () => {
const collidingField = {
id: 5,
name: "Collision",
data_type: "select",
extra_data: {
select_options: [
{ id: "High", label: "Low" },
{ id: "xyz789", label: "High" },
],
},
document_count: 0,
};
strict_1.default.throws(() => (0, selectFields_1.resolveSelectCustomFieldValue)(collidingField, "High"), /Ambiguous/);
});
});
(0, node_test_1.describe)("resolveSelectCustomFieldValue with stored encoding (bulk_edit path)", () => {
(0, node_test_1.test)("translates a label to the option id on 2.17+ object options", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "Low", "stored"), "abc123");
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "High", "stored"), "def456");
});
(0, node_test_1.test)("translates a label to the index on pre-2.17 string options (no id to store)", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(LEGACY_SELECT_FIELD, "7 years", "stored"), 1);
});
(0, node_test_1.test)("passes an already-stored option id through unchanged", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, "def456", "stored"), "def456");
});
(0, node_test_1.test)("maps an option index to its stored id (2.17+)", () => {
strict_1.default.equal((0, selectFields_1.resolveSelectCustomFieldValue)(OBJECT_SELECT_FIELD, 1, "stored"), "def456");
});
});
function apiReturning(fields) {
const requestedIds = [];
const fieldMap = new Map(fields.map((field) => [field.id, field]));
const api = {
getCustomField: (id) => __awaiter(this, void 0, void 0, function* () {
requestedIds.push(id);
const field = fieldMap.get(id);
if (!field)
throw new Error(`custom field ${id} not found`);
return field;
}),
};
return { api, requestedIds };
}
(0, node_test_1.describe)("resolveSelectCustomFieldValues", () => {
(0, node_test_1.test)("returns undefined/empty input unchanged without fetching definitions", () => __awaiter(void 0, void 0, void 0, function* () {
const { api, requestedIds } = apiReturning([]);
strict_1.default.equal(yield (0, selectFields_1.resolveSelectCustomFieldValues)(api, undefined), undefined);
strict_1.default.deepEqual(yield (0, selectFields_1.resolveSelectCustomFieldValues)(api, []), []);
strict_1.default.deepEqual(requestedIds, []);
}));
(0, node_test_1.test)("resolves select labels and leaves other fields untouched", () => __awaiter(void 0, void 0, void 0, function* () {
const { api } = apiReturning([LEGACY_SELECT_FIELD, STRING_FIELD]);
const resolved = yield (0, selectFields_1.resolveSelectCustomFieldValues)(api, [
{ field: 2, value: "2 years" },
{ field: 4, value: "INV-001" },
]);
strict_1.default.deepEqual(resolved, [
{ field: 2, value: 2 },
{ field: 4, value: "INV-001" },
]);
}));
(0, node_test_1.test)("applies the stored encoding (option id) when requested", () => __awaiter(void 0, void 0, void 0, function* () {
const { api } = apiReturning([OBJECT_SELECT_FIELD]);
const resolved = yield (0, selectFields_1.resolveSelectCustomFieldValues)(api, [{ field: 3, value: "High" }], "stored");
strict_1.default.deepEqual(resolved, [{ field: 3, value: "def456" }]);
}));
(0, node_test_1.test)("fetches each referenced field definition only once", () => __awaiter(void 0, void 0, void 0, function* () {
const { api, requestedIds } = apiReturning([LEGACY_SELECT_FIELD]);
yield (0, selectFields_1.resolveSelectCustomFieldValues)(api, [
{ field: 2, value: "1 year" },
{ field: 2, value: "7 years" },
]);
strict_1.default.deepEqual(requestedIds, [2]);
}));
(0, node_test_1.test)("passes the value through when the field definition cannot be fetched", () => __awaiter(void 0, void 0, void 0, function* () {
const { api } = apiReturning([]);
const resolved = yield (0, selectFields_1.resolveSelectCustomFieldValues)(api, [
{ field: 99, value: "whatever" },
]);
strict_1.default.deepEqual(resolved, [{ field: 99, value: "whatever" }]);
}));
});