document-operations 1.1.49 → 1.1.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +37 -37
- package/dist/index.d.cts +37 -37
- package/dist/index.d.ts +37 -37
- package/dist/index.js +37 -37
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -10,13 +10,13 @@ import { buildOutline, isOutlineNode, outlineLeafText } from "document-outline.j
|
|
|
10
10
|
/**
|
|
11
11
|
* Builds a DocumentOperation whose input and output types are both inferred from real Zod schemas, so a call site never has to repeat `z.infer<typeof Schema>` itself. Use `defineOperationWithoutOutputSchema` instead for the rare operation whose original MCP tool registration declared no outputSchema at all.
|
|
12
12
|
*
|
|
13
|
-
* Deliberately returns the parameter object's own inferred literal type rather than an explicit `DocumentOperation<...>` return annotation. Zod 4's ZodType carries its own output type as one of three generic parameters (ZodType<Output, Input, Internals>), and TypeScript cannot prove, from inside this function body, that a generic `InputSchema extends z.ZodType` also extends `z.ZodType<z.infer<InputSchema>>`
|
|
13
|
+
* Deliberately returns the parameter object's own inferred literal type rather than an explicit `DocumentOperation<...>` return annotation. Zod 4's ZodType carries its own output type as one of three generic parameters (ZodType<Output, Input, Internals>), and TypeScript cannot prove, from inside this function body, that a generic `InputSchema extends z.ZodType` also extends `z.ZodType<z.infer<InputSchema>>` — the two-step indirection through an abstract type parameter defeats it even though it is true for every concrete schema. Letting the literal's own type flow out instead sidesteps that: a caller's own concrete schema (e.g. `ConvertDocumentInputSchema`) is trivially assignable to `DocumentOperation<In, Out>`'s `z.ZodType<In>` field wherever that supertype is actually needed (the registry array below, or a future MCP/REST/CLI adapter parameter), because widening a CONCRETE schema's output type to line up is a normal covariant check, not the same self-referential generic one.
|
|
14
14
|
*/
|
|
15
15
|
function defineOperation(operation) {
|
|
16
16
|
return operation;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* The `defineOperation` counterpart for an operation with no output schema to infer from (the original MCP tool registration declared none)
|
|
19
|
+
* The `defineOperation` counterpart for an operation with no output schema to infer from (the original MCP tool registration declared none) — `Out` is inferred from `run`'s own return type instead. See `defineOperation`'s own comment for why this returns the parameter object's inferred literal type rather than an explicit `DocumentOperation<...>` annotation.
|
|
20
20
|
*/
|
|
21
21
|
function defineOperationWithoutOutputSchema(operation) {
|
|
22
22
|
return operation;
|
|
@@ -67,7 +67,7 @@ function inferFormatFromExtension(path) {
|
|
|
67
67
|
*/
|
|
68
68
|
const DocumentInputSchema = z.union([z.object({ path: z.string().describe("Filesystem path to the document to read. The document format is inferred from the file extension.") }), z.object({
|
|
69
69
|
bytesBase64: z.string().describe("Base64-encoded document bytes."),
|
|
70
|
-
format: DocumentFormatSchema.describe("The document format of bytesBase64
|
|
70
|
+
format: DocumentFormatSchema.describe("The document format of bytesBase64 — required, since inline bytes carry no filename to infer it from.")
|
|
71
71
|
})]);
|
|
72
72
|
/**
|
|
73
73
|
* Resolves the hybrid DocumentInput union to concrete bytes and a format: for the path shape, reads the file from disk and infers its format from the extension (throwing if the extension is unrecognised); for the bytesBase64 shape, decodes the inline payload and uses the caller-supplied format directly.
|
|
@@ -94,7 +94,7 @@ async function resolveDocumentInput(input, options) {
|
|
|
94
94
|
*/
|
|
95
95
|
const DocumentOutputSchema = z.object({ outputPath: z.string().optional().describe("Filesystem path to write the resulting document to. Omit to receive the document bytes inline, base64-encoded, in the tool result instead.") });
|
|
96
96
|
/**
|
|
97
|
-
* Above this many bytes, an inline base64 result is flagged `large: true` so a caller/LLM can see the response is sizeable before deciding whether to consume it directly. Purely advisory: `resolveDocumentOutput` never truncates or refuses to return large bytes, it only flags them
|
|
97
|
+
* Above this many bytes, an inline base64 result is flagged `large: true` so a caller/LLM can see the response is sizeable before deciding whether to consume it directly. Purely advisory: `resolveDocumentOutput` never truncates or refuses to return large bytes, it only flags them — silently truncating a document would produce a corrupt file with no indication anything was lost. 5 MB is a reasonable default order of magnitude for "an LLM context probably wants to know before this lands inline", well under typical MCP stdio transport limits.
|
|
98
98
|
*/
|
|
99
99
|
const LARGE_RESULT_THRESHOLD_BYTES = 5242880;
|
|
100
100
|
/**
|
|
@@ -150,11 +150,11 @@ const FontInputSchema = z.object({
|
|
|
150
150
|
});
|
|
151
151
|
const ConvertDocumentInputSchema = z.object({
|
|
152
152
|
source: DocumentInputSchema.describe("The document to convert."),
|
|
153
|
-
targetFormat: DocumentFormatSchema.describe("The format to convert the document to. Not every (source, targetFormat) pair is supported directly
|
|
153
|
+
targetFormat: DocumentFormatSchema.describe("The format to convert the document to. Not every (source, targetFormat) pair is supported directly — call list_document_conversions first to confirm this one is."),
|
|
154
154
|
output: DocumentOutputSchema.optional().describe("Where to write the converted document. Omit entirely to receive the bytes inline, base64-encoded, instead."),
|
|
155
155
|
fonts: z.array(FontInputSchema).optional().describe("Extra font faces to make available to the conversion, for a family the source document does not already embed. Only consulted by a conversion that runs a layout engine (a <format>-to-pdf conversion); every other conversion ignores this option entirely."),
|
|
156
|
-
onSubstitutionDiagnostics: z.boolean().optional().describe("When true, additionally report each individual font-substitution event as structured fontSubstitutions (which family/weight/style was requested, what it resolved to instead, and why). Every substitution is always reported as a plain diagnostic in `diagnostics` regardless of this flag
|
|
157
|
-
images: z.record(z.string(), z.string()).optional().describe("A map from a markdown image destination (the part in the parentheses of ) to its base64-encoded PNG/JPEG bytes, for resolving a markdown source's own non-data: images. Only consulted by a markdown-sourced conversion; every other conversion ignores it. A destination absent from the map degrades to alt text, matching documents.js's own MarkdownImageResolver port
|
|
156
|
+
onSubstitutionDiagnostics: z.boolean().optional().describe("When true, additionally report each individual font-substitution event as structured fontSubstitutions (which family/weight/style was requested, what it resolved to instead, and why). Every substitution is always reported as a plain diagnostic in `diagnostics` regardless of this flag — this only controls whether the fuller, structured event is also collected."),
|
|
157
|
+
images: z.record(z.string(), z.string()).optional().describe("A map from a markdown image destination (the part in the parentheses of ) to its base64-encoded PNG/JPEG bytes, for resolving a markdown source's own non-data: images. Only consulted by a markdown-sourced conversion; every other conversion ignores it. A destination absent from the map degrades to alt text, matching documents.js's own MarkdownImageResolver port — a caller with no filesystem context has no other way to supply a relative path's bytes.")
|
|
158
158
|
});
|
|
159
159
|
const ConvertDocumentOutputSchema = z.object({
|
|
160
160
|
targetFormat: DocumentFormatSchema,
|
|
@@ -171,7 +171,7 @@ const converter = createLocalDocumentConverter();
|
|
|
171
171
|
const convertDocumentOperation = defineOperation({
|
|
172
172
|
name: "convert_document",
|
|
173
173
|
title: "Convert document",
|
|
174
|
-
description: "Converts a document from one supported format to another via documents.js's DocumentConverter port
|
|
174
|
+
description: "Converts a document from one supported format to another via documents.js's DocumentConverter port — docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, rtf, wpd, doc, xls, ppt, epub, csv, svg, and pdf. Not every (source, targetFormat) pair is supported directly (odf, for instance, only ever converts to pdf); call list_document_conversions first to see which pairs actually are.",
|
|
175
175
|
inputSchema: ConvertDocumentInputSchema,
|
|
176
176
|
outputSchema: ConvertDocumentOutputSchema,
|
|
177
177
|
async run({ source, targetFormat, output, fonts, onSubstitutionDiagnostics, images }, context) {
|
|
@@ -212,7 +212,7 @@ const convertDocumentOperation = defineOperation({
|
|
|
212
212
|
const listDocumentConversionsOperation = defineOperation({
|
|
213
213
|
name: "list_document_conversions",
|
|
214
214
|
title: "List document conversions",
|
|
215
|
-
description: "Lists every (source, target) format pair convert_document actually supports, straight from documents.js's own DocumentConverter port
|
|
215
|
+
description: "Lists every (source, target) format pair convert_document actually supports, straight from documents.js's own DocumentConverter port — the definitive source of truth for what convert_document will and will not accept as a (source, targetFormat) combination.",
|
|
216
216
|
inputSchema: ListDocumentConversionsInputSchema,
|
|
217
217
|
outputSchema: ListDocumentConversionsOutputSchema,
|
|
218
218
|
run() {
|
|
@@ -267,7 +267,7 @@ const ComputeFormulaOutputSchema = z.object({
|
|
|
267
267
|
const computeFormulaOperation = defineOperation({
|
|
268
268
|
name: "compute_formula",
|
|
269
269
|
title: "Compute document formulas",
|
|
270
|
-
description: "Reads every formula a document embeds (docx/odt/markdown paragraphs and pptx/odp slide shapes; a table cell's own blocks too
|
|
270
|
+
description: "Reads every formula a document embeds (docx/odt/markdown paragraphs and pptx/odp slide shapes; a table cell's own blocks too — docx's own reader recovers a real equation nested inside a table cell; structurally, the walk also covers a drawing page's own shape flow, though no writer in the family populates a formula there today; a spreadsheet's own cell-anchored formula objects; a standalone .odf formula document; and a formula nested inside another embedded object at any depth, e.g. a formula embedded in a drawing embedded in a spreadsheet) and evaluates each through document-compute.js's units-typed evaluate() — a caller's way to check whether a document's stated arithmetic actually checks out. A formula referencing a symbol (e.g. F = m * a) needs that symbol's value supplied via bindings, keyed by the document's own symbol-table id (see the document's symbolTable.symbols[].id, or a returned formula's own latex to identify which symbol is which); a formula with no free symbols (units and numeric literals only) evaluates with no bindings at all. Each formula reports its own outcome independently — 'evaluated' with the result, 'no-content' when the formula was never lowered to a computable MathExpression (the common case for a spreadsheet's own embedded formula object, or any format other than markdown, none of which yet stores the semantic layer on disk), or 'error' naming which document-compute.js error it hit (e.g. UnboundSymbolError) — so one formula needing more bindings never blocks the others. Each entry's own `locate` field is the reliable way to tell two formulas in the same document apart — a structural path guaranteed unique per formula — unlike `sourcePath`, which several formats leave undefined or stamp with the identical constant across sibling formulas (markdown's own display-math lowering among them).",
|
|
271
271
|
inputSchema: z.object({
|
|
272
272
|
source: DocumentInputSchema.describe("The document to read formulas from."),
|
|
273
273
|
bindings: FormulaBindingsSchema.optional().describe("Known values for symbols the document's formulas reference, keyed by symbol-table id (a Quantity { kind: 'quantity', magnitude, dimension } or an Interval { kind: 'interval', min, max, dimension } per symbol). Omit for a document whose formulas are fully closed (units and numeric literals only, no 'sym' nodes).")
|
|
@@ -298,7 +298,7 @@ const computeFormulaOperation = defineOperation({
|
|
|
298
298
|
const docxExtrasOperation = defineOperationWithoutOutputSchema({
|
|
299
299
|
name: "docx_extras",
|
|
300
300
|
title: "Docx extras",
|
|
301
|
-
description: "Reads a docx's own comments, footnotes, header/footer parts, and numbering definitions
|
|
301
|
+
description: "Reads a docx's own comments, footnotes, header/footer parts, and numbering definitions — data documents.js's ContentDocument pivot cannot carry, so ordinary document-reading operations never see it. Returns the real DocxExtras object (comments/footnotes/headerFooterParts/sectionHeaderFooters/numbering) as structured data.",
|
|
302
302
|
inputSchema: z.object({ source: DocumentInputSchema.describe("The docx document to read.") }),
|
|
303
303
|
async run({ source }) {
|
|
304
304
|
const { bytes } = await resolveDocumentInput(source);
|
|
@@ -328,7 +328,7 @@ const RunSchema = z.object({
|
|
|
328
328
|
sizePt: z.number().positive().optional().describe("docx/odt only."),
|
|
329
329
|
colorHex: z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("6-digit hex colour (e.g. 'ff0000' or '#ff0000'). docx/odt only."),
|
|
330
330
|
hyperlink: z.string().optional().describe("markdown only."),
|
|
331
|
-
code: z.boolean().optional().describe("markdown only
|
|
331
|
+
code: z.boolean().optional().describe("markdown only — renders the run as an inline code span.")
|
|
332
332
|
});
|
|
333
333
|
const ParagraphSchema = z.object({
|
|
334
334
|
text: z.string().optional().describe("Plain paragraph text, as a single run. Omit and use `runs` instead for mixed formatting within one paragraph."),
|
|
@@ -347,7 +347,7 @@ function unsupportedFieldNames(input, unsupported) {
|
|
|
347
347
|
}
|
|
348
348
|
function rejectUnsupportedFields(input, unsupported, formatLabel, context) {
|
|
349
349
|
const present = unsupportedFieldNames(input, unsupported);
|
|
350
|
-
if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel}
|
|
350
|
+
if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel} — remove ${present.length === 1 ? "it" : "them"} or target docx/odt instead.`);
|
|
351
351
|
}
|
|
352
352
|
const DOCX_ODT_UNSUPPORTED_RUN_FIELDS = ["hyperlink", "code"];
|
|
353
353
|
const MARKDOWN_UNSUPPORTED_RUN_FIELDS = [
|
|
@@ -424,7 +424,7 @@ const ResolvedDocumentOutputSchema$2 = z.union([z.object({
|
|
|
424
424
|
const documentCreateOperation = defineOperation({
|
|
425
425
|
name: "document_create",
|
|
426
426
|
title: "Create a blank document",
|
|
427
|
-
description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content
|
|
427
|
+
description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content — follow with document_append_paragraphs (docx/odt/markdown) to add text.",
|
|
428
428
|
inputSchema: z.object({
|
|
429
429
|
format: WritableFormatSchema.describe("The format of document to create."),
|
|
430
430
|
output: DocumentOutputSchema.optional().describe("Where to write the created document. Omit entirely to receive the bytes inline, base64-encoded.")
|
|
@@ -437,7 +437,7 @@ const documentCreateOperation = defineOperation({
|
|
|
437
437
|
const documentAppendParagraphsOperation = defineOperation({
|
|
438
438
|
name: "document_append_paragraphs",
|
|
439
439
|
title: "Append paragraphs to a wordprocessing document",
|
|
440
|
-
description: "Appends one or more paragraphs
|
|
440
|
+
description: "Appends one or more paragraphs — each optionally built from several independently-formatted runs — to the end of a docx, odt, or markdown document, through documents.js's own live-view editors (the same DocxBody.appendParagraph/OdtBody.appendParagraph/MarkdownBody.appendParagraph document-cli's own TUI uses). Does not convert format — the source document's own format and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colorHex, headingLevel, alignment all supported); markdown supports a different, smaller set (hyperlink, code) and rejects the docx/odt-only fields outright rather than silently dropping them. This covers wordprocessing paragraph/run editing only — slides, sheets, drawings, tables, lists, and images are a separate, larger editing surface not exposed here yet.",
|
|
441
441
|
inputSchema: z.object({
|
|
442
442
|
source: DocumentInputSchema.describe("The document to append paragraphs to."),
|
|
443
443
|
targetFormat: z.enum([
|
|
@@ -451,7 +451,7 @@ const documentAppendParagraphsOperation = defineOperation({
|
|
|
451
451
|
outputSchema: ResolvedDocumentOutputSchema$2,
|
|
452
452
|
async run({ source, targetFormat, paragraphs, output }) {
|
|
453
453
|
const { bytes, format } = await resolveDocumentInput(source);
|
|
454
|
-
if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}"
|
|
454
|
+
if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}" — document_append_paragraphs never converts format, so the two must match.`);
|
|
455
455
|
let resultBytes;
|
|
456
456
|
if (targetFormat === "markdown") {
|
|
457
457
|
const editor = openMarkdown(decodeMarkdownText(bytes));
|
|
@@ -507,7 +507,7 @@ const describeFontFileOperation = defineOperation({
|
|
|
507
507
|
name: "describe_font_file",
|
|
508
508
|
title: "Describe font file",
|
|
509
509
|
description: "Reads a standalone TrueType/OpenType font file (.ttf/.otf) and reports the family/bold/italic triple it declares about itself.",
|
|
510
|
-
inputSchema: z.object({ source: FontFileInputSchema.describe("The standalone .ttf/.otf font file to inspect
|
|
510
|
+
inputSchema: z.object({ source: FontFileInputSchema.describe("The standalone .ttf/.otf font file to inspect — not a document.") }),
|
|
511
511
|
outputSchema: z.object({
|
|
512
512
|
family: z.string(),
|
|
513
513
|
bold: z.boolean(),
|
|
@@ -535,9 +535,9 @@ async function readSourceBytes(source) {
|
|
|
535
535
|
const fromPackageOperation = defineOperation({
|
|
536
536
|
name: "from_package",
|
|
537
537
|
title: "Build document from package",
|
|
538
|
-
description: "Rebuilds real document bytes in a target format from a DocumentTree previously serialised to JSON (e.g. by a caller's own --dump-package-equivalent step)
|
|
538
|
+
description: "Rebuilds real document bytes in a target format from a DocumentTree previously serialised to JSON (e.g. by a caller's own --dump-package-equivalent step) — the read side of the DocumentTree round trip a conversion's onDocument callback produces.",
|
|
539
539
|
inputSchema: z.object({
|
|
540
|
-
source: DocumentInputSchema.describe("The DocumentTree JSON to read. 'path' points at a JSON file on disk
|
|
540
|
+
source: DocumentInputSchema.describe("The DocumentTree JSON to read. 'path' points at a JSON file on disk — its extension is never used to infer a document format, since the file holds a DocumentTree, not a document. 'bytesBase64' carries the JSON inline; its 'format' field is required by the shared hybrid input shape but unused by this operation."),
|
|
541
541
|
targetFormat: DocumentFormatSchema.describe("The document format to build from the DocumentTree."),
|
|
542
542
|
output: DocumentOutputSchema.optional().describe("Where to write the resulting document. Omit entirely (or omit outputPath within it) to receive the bytes inline instead.")
|
|
543
543
|
}),
|
|
@@ -562,11 +562,11 @@ const fromPackageOperation = defineOperation({
|
|
|
562
562
|
try {
|
|
563
563
|
result = documentFromJson(parsed);
|
|
564
564
|
} catch (error) {
|
|
565
|
-
if (error instanceof UnrecognizedDocumentSchemaError) throw new Error("'source' has no recognised $schema
|
|
565
|
+
if (error instanceof UnrecognizedDocumentSchemaError) throw new Error("'source' has no recognised $schema — only a file carrying a real DocumentTree (e.g. written by a caller's own --dump-package-equivalent step) can be read back by this operation", { cause: error });
|
|
566
566
|
if (error instanceof z.ZodError) throw new Error(`'source' failed ${documentSchemaKindOf(parsed)} validation: ${error.message}`, { cause: error });
|
|
567
567
|
throw error;
|
|
568
568
|
}
|
|
569
|
-
if (result.kind !== "DocumentTree") throw new Error(`'source' is a ${result.kind}, not a DocumentTree
|
|
569
|
+
if (result.kind !== "DocumentTree") throw new Error(`'source' is a ${result.kind}, not a DocumentTree — only a file carrying a real DocumentTree (e.g. written by a caller's own --dump-package-equivalent step) can be read back by this operation`);
|
|
570
570
|
return resolveDocumentOutput(buildDocumentBytes(result.value, targetFormat), output ?? {});
|
|
571
571
|
}
|
|
572
572
|
});
|
|
@@ -591,10 +591,10 @@ const ResolvedDocumentOutputSchema = z.union([z.object({
|
|
|
591
591
|
const metadataWriteOperation = defineOperation({
|
|
592
592
|
name: "metadata_write",
|
|
593
593
|
title: "Write document metadata",
|
|
594
|
-
description: "Patches a document's own title/author/subject/keywords, leaving every other field and every other flag as-is. Does not convert format
|
|
594
|
+
description: "Patches a document's own title/author/subject/keywords, leaving every other field and every other flag as-is. Does not convert format — the source document's own format and targetFormat must match (or both be 'pdf'); odf (a standalone formula document) is rejected outright as either a source or a target, since it has no write path back out at all. Convert the document to a different format first (e.g. with a documents.js conversion operation) if metadata needs to be set on the result of a format change.",
|
|
595
595
|
inputSchema: z.object({
|
|
596
596
|
source: DocumentInputSchema.describe("The document to patch metadata on."),
|
|
597
|
-
targetFormat: DocumentFormatSchema.describe("The format to write the patched document back out as
|
|
597
|
+
targetFormat: DocumentFormatSchema.describe("The format to write the patched document back out as — must match the source document's own format (or both be 'pdf'). metadata_write never converts format."),
|
|
598
598
|
output: DocumentOutputSchema.optional().describe("Where to write the patched document. Omit entirely to receive the bytes inline, base64-encoded."),
|
|
599
599
|
setTitle: z.string().optional().describe("Set the title field. Omit to leave it exactly as the source document already has it."),
|
|
600
600
|
setAuthor: z.string().optional().describe("Set the author field. Omit to leave it exactly as the source document already has it."),
|
|
@@ -614,7 +614,7 @@ const metadataWriteOperation = defineOperation({
|
|
|
614
614
|
});
|
|
615
615
|
//#endregion
|
|
616
616
|
//#region src/operations/odb.ts
|
|
617
|
-
const ODB_SOURCE_DESCRIPTION = ".odb database to read. 'path' points at the .odb file on disk
|
|
617
|
+
const ODB_SOURCE_DESCRIPTION = ".odb database to read. 'path' points at the .odb file on disk — its extension is never used to infer a document format, since documents.js deliberately excludes 'odb' from DocumentFormat (an embedded database front end has no single natural target format — tables, saved queries, and reports are three unrelated output shapes — see that package's own README). 'bytesBase64' carries the .odb bytes inline; its 'format' field is required by the shared hybrid input shape but unused by every odb operation.";
|
|
618
618
|
async function resolveOdbBytes(source) {
|
|
619
619
|
if ("path" in source) {
|
|
620
620
|
const buffer = await readFile(source.path);
|
|
@@ -622,11 +622,11 @@ async function resolveOdbBytes(source) {
|
|
|
622
622
|
}
|
|
623
623
|
return base64ToBytes(source.bytesBase64);
|
|
624
624
|
}
|
|
625
|
-
/** Resolves an .odb DocumentInput straight through to a decoded Package (via documents.js's own decodeOdbPackage)
|
|
625
|
+
/** Resolves an .odb DocumentInput straight through to a decoded Package (via documents.js's own decodeOdbPackage) — the shape every read (as opposed to export) odb operation needs. */
|
|
626
626
|
async function resolveOdbPackage(source) {
|
|
627
627
|
return decodeOdbPackage(await resolveOdbBytes(source));
|
|
628
628
|
}
|
|
629
|
-
/** Resolves a saved query's own SQL text by name against the .odb's own db:queries (read via readOdbInventory)
|
|
629
|
+
/** Resolves a saved query's own SQL text by name against the .odb's own db:queries (read via readOdbInventory) — odb_query's own equivalent of document-cli's resolveQuerySql, for the case where the caller named a saved query rather than supplying SQL directly. Throws, naming every available query, when the name doesn't resolve. */
|
|
630
630
|
function resolveSavedQuerySql(pkg, name) {
|
|
631
631
|
const inventory = readOdbInventory(pkg);
|
|
632
632
|
const saved = inventory.queries.find((candidate) => candidate.name === name);
|
|
@@ -653,7 +653,7 @@ const OdbSourceInputSchema = z.object({ source: DocumentInputSchema.describe(ODB
|
|
|
653
653
|
const odbTablesOperation = defineOperationWithoutOutputSchema({
|
|
654
654
|
name: "odb_tables",
|
|
655
655
|
title: "List .odb tables",
|
|
656
|
-
description: "Lists every table an embedded .odb database declares
|
|
656
|
+
description: "Lists every table an embedded .odb database declares — column names, types, and row data — across every storage tier documents.js supports (HSQLDB TEXT/CACHED/BINARY script formats, Firebird gbak backups).",
|
|
657
657
|
inputSchema: OdbSourceInputSchema,
|
|
658
658
|
async run({ source }) {
|
|
659
659
|
return readOdbTables(await resolveOdbPackage(source));
|
|
@@ -680,7 +680,7 @@ const odbReportsOperation = defineOperationWithoutOutputSchema({
|
|
|
680
680
|
const odbQueryOperation = defineOperationWithoutOutputSchema({
|
|
681
681
|
name: "odb_query",
|
|
682
682
|
title: "Query an .odb database",
|
|
683
|
-
description: "Runs a bounded SELECT (with optional JOINs of any kind, table aliases, a derived table in FROM, and IN/EXISTS subqueries) over an embedded .odb database's own extracted tables, given directly as SQL or by naming one of the database's saved queries. No database engine is involved
|
|
683
|
+
description: "Runs a bounded SELECT (with optional JOINs of any kind, table aliases, a derived table in FROM, and IN/EXISTS subqueries) over an embedded .odb database's own extracted tables, given directly as SQL or by naming one of the database's saved queries. No database engine is involved — the query runs in memory over the same tables odb_tables would return, against a closed grammar (SELECT/FROM/JOIN [INNER|LEFT [OUTER]|RIGHT [OUTER]|FULL [OUTER]|CROSS|NATURAL] ... [ON|USING]/WHERE/GROUP BY/ORDER BY, with an optional [AS] alias on any table, WHERE and ON also accepting [NOT] IN (SELECT ...) and [NOT] EXISTS (SELECT ...) — no column aliases); an unsupported construct is reported as an error naming it, never silently ignored.",
|
|
684
684
|
inputSchema: z.object({
|
|
685
685
|
source: DocumentInputSchema.describe(ODB_SOURCE_DESCRIPTION),
|
|
686
686
|
sql: z.string().describe("A literal SELECT statement to run. Mutually exclusive with \"query\".").optional(),
|
|
@@ -699,7 +699,7 @@ const odbToCsvOperation = defineOperationWithoutOutputSchema({
|
|
|
699
699
|
description: "Extracts exactly one named table from an embedded .odb database as CSV bytes. The table name is required whenever the database declares more than one table.",
|
|
700
700
|
inputSchema: z.object({
|
|
701
701
|
source: DocumentInputSchema.describe(ODB_SOURCE_DESCRIPTION),
|
|
702
|
-
table: z.string().describe("The table to export
|
|
702
|
+
table: z.string().describe("The table to export — required when the .odb declares more than one table.").optional(),
|
|
703
703
|
output: DocumentOutputSchema.optional().describe("Where to write the resulting CSV. Omit entirely (or omit outputPath within it) to receive the bytes inline instead.")
|
|
704
704
|
}),
|
|
705
705
|
async run({ source, table, output }, context) {
|
|
@@ -731,11 +731,11 @@ const OdbRenderReportTargetFormatSchema = z.enum([
|
|
|
731
731
|
"pdf"
|
|
732
732
|
]);
|
|
733
733
|
const OdbRenderReportInputSchema = z.object({
|
|
734
|
-
source: DocumentInputSchema.describe(".odb database to render a report from. 'path' points at the .odb file on disk
|
|
735
|
-
report: z.string().optional().describe("The name of the report to render. Required only when the .odb declares more than one report
|
|
734
|
+
source: DocumentInputSchema.describe(".odb database to render a report from. 'path' points at the .odb file on disk — its extension is never used to infer a document format, since documents.js deliberately excludes 'odb' from DocumentFormat (an embedded database front end has no single natural target format — tables, saved queries, and reports are three unrelated output shapes — see that package's own README). 'bytesBase64' carries the .odb bytes inline; its 'format' field is required by the shared hybrid input shape but unused by this operation."),
|
|
735
|
+
report: z.string().optional().describe("The name of the report to render. Required only when the .odb declares more than one report — omitting it when exactly one is declared renders that one automatically."),
|
|
736
736
|
targetFormat: OdbRenderReportTargetFormatSchema.describe("The format to render the report into."),
|
|
737
737
|
output: DocumentOutputSchema.optional().describe("Where to write the rendered report. Omit entirely (or omit outputPath within it) to receive the bytes inline instead."),
|
|
738
|
-
fonts: z.array(FontInputSchema).optional().describe("Extra font faces to make available, for a family the rendered report's own text otherwise falls back on. Only consulted when targetFormat is 'pdf'
|
|
738
|
+
fonts: z.array(FontInputSchema).optional().describe("Extra font faces to make available, for a family the rendered report's own text otherwise falls back on. Only consulted when targetFormat is 'pdf' — docx and odt output is genuine editable text with no font-embedding step of its own, so fonts is ignored for those two targets.")
|
|
739
739
|
});
|
|
740
740
|
const MathDiagnosticSchema = z.object({
|
|
741
741
|
kind: z.enum(["unsupported-element", "approximated-element"]),
|
|
@@ -772,7 +772,7 @@ const OdbRenderReportOutputSchema = z.union([z.object({
|
|
|
772
772
|
const odbRenderReportOperation = defineOperation({
|
|
773
773
|
name: "odb_render_report",
|
|
774
774
|
title: "Render .odb report",
|
|
775
|
-
description: "Resolves one of an .odb database's own reports
|
|
775
|
+
description: "Resolves one of an .odb database's own reports — its data-bound command run through the bounded SQL engine, its rpt: formulas evaluated, its bands laid out — and renders the result to docx, odt, or pdf.",
|
|
776
776
|
inputSchema: OdbRenderReportInputSchema,
|
|
777
777
|
outputSchema: OdbRenderReportOutputSchema,
|
|
778
778
|
async run({ source, report, targetFormat, output, fonts }, context) {
|
|
@@ -819,7 +819,7 @@ async function resolveOdmMasterBytes(source) {
|
|
|
819
819
|
}
|
|
820
820
|
const OdmChapterInputSchema = z.object({
|
|
821
821
|
href: z.string().describe("The chapter's own text:section-source href as declared inside the .odm master document (e.g. '../chapter1.odt')."),
|
|
822
|
-
source: DocumentInputSchema.describe("The chapter document's own bytes
|
|
822
|
+
source: DocumentInputSchema.describe("The chapter document's own bytes — always read as odt, regardless of the format this hybrid input declares.")
|
|
823
823
|
});
|
|
824
824
|
const OdmToPdfInputSchema = z.object({
|
|
825
825
|
source: OdmMasterSourceSchema.describe("The .odm master document to convert."),
|
|
@@ -838,7 +838,7 @@ const OdmToPdfOutputSchema = z.union([z.object({
|
|
|
838
838
|
const odmToPdfOperation = defineOperation({
|
|
839
839
|
name: "odm_to_pdf",
|
|
840
840
|
title: "Convert ODM master document to PDF",
|
|
841
|
-
description: "Converts a .odm (ODF master document) to PDF. A .odm never carries its own chapters' content inline
|
|
841
|
+
description: "Converts a .odm (ODF master document) to PDF. A .odm never carries its own chapters' content inline — every text:section is a bare external reference to a standalone .odt file — so each chapter the master document declares must resolve through `chapters` (an explicit href -> document override) and/or `chaptersDir` (a directory searched by the href's own basename), checked in that order. A chapter left unresolved by both fails the whole conversion, naming every unresolved href.",
|
|
842
842
|
inputSchema: OdmToPdfInputSchema,
|
|
843
843
|
outputSchema: OdmToPdfOutputSchema,
|
|
844
844
|
async run({ source, chapters, chaptersDir, output }) {
|
|
@@ -879,7 +879,7 @@ function toOutlineJson(children) {
|
|
|
879
879
|
const outlineDocumentOperation = defineOperationWithoutOutputSchema({
|
|
880
880
|
name: "outline_document",
|
|
881
881
|
title: "Outline document",
|
|
882
|
-
description: "Projects a document's table of contents as a structured outline: reads the source's own native DocumentTree directly (documents.js's readNativeDocumentTree
|
|
882
|
+
description: "Projects a document's table of contents as a structured outline: reads the source's own native DocumentTree directly (documents.js's readNativeDocumentTree — no bridging conversion, no discarded output bytes) and runs document-outline.js's buildOutline over it. Groups carry { text, level, children } (a heading's, list item's, slide's, sheet's, or page's own label plus nested children); leaves carry { kind, text }.",
|
|
883
883
|
inputSchema: z.object({ source: DocumentInputSchema.describe("The document to outline.") }),
|
|
884
884
|
async run({ source }, context) {
|
|
885
885
|
const signal = context?.signal;
|
|
@@ -933,7 +933,7 @@ const pdfInspectOperation = defineOperationWithoutOutputSchema({
|
|
|
933
933
|
//#endregion
|
|
934
934
|
//#region src/registry.ts
|
|
935
935
|
/**
|
|
936
|
-
* Every document operation this package defines, one entry per MCP tool/CLI command/REST route
|
|
936
|
+
* Every document operation this package defines, one entry per MCP tool/CLI command/REST route — "the same registry as the MCP" a consumer that needs to enumerate every operation (rather than importing one by name) reaches for: an MCP server registers each entry as a tool, a REST server adds one route per entry, and a CLI can validate its own parsed flags against an entry's inputSchema before dispatching to its run().
|
|
937
937
|
*/
|
|
938
938
|
const DOCUMENT_OPERATIONS = [
|
|
939
939
|
convertDocumentOperation,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-operations",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "The canonical set of document-conversion, editing, inspection, and .odb operations documents.js exposes
|
|
3
|
+
"version": "1.1.51",
|
|
4
|
+
"description": "The canonical set of document-conversion, editing, inspection, and .odb operations documents.js exposes — one Zod input/output schema and one transport-agnostic run() function per operation, shared by document-mcp, document-cli, and a REST API server rather than each defining its own copy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -82,10 +82,10 @@
|
|
|
82
82
|
"license": "MIT",
|
|
83
83
|
"packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"document-compute.js": "1.5.
|
|
86
|
-
"document-outline.js": "3.9.
|
|
87
|
-
"document-schema.js": "7.14.
|
|
88
|
-
"documents.js": "14.
|
|
85
|
+
"document-compute.js": "1.5.53",
|
|
86
|
+
"document-outline.js": "3.9.23",
|
|
87
|
+
"document-schema.js": "7.14.1",
|
|
88
|
+
"documents.js": "14.1.1",
|
|
89
89
|
"zod": "4.4.3"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"@vitest/coverage-v8": "4.1.11",
|
|
99
99
|
"eslint": "10.8.1",
|
|
100
100
|
"husky": "9.1.7",
|
|
101
|
-
"odf.js": "11.0.
|
|
101
|
+
"odf.js": "11.0.1",
|
|
102
102
|
"publint": "0.3.22",
|
|
103
103
|
"semantic-release": "25.0.9",
|
|
104
104
|
"tsdown": "0.22.14",
|