docx-editor

Verifying a commenter's file

Check on the server that a file returned by a comment editor differs from the original in comments alone.

A file returned by a comment editor should differ from the original in comments alone. The editor enforces that in the browser only, so check it again where the file arrives:

import { onlyCommentsChangedBy } from "@portone/docx-editor/core";

const verdict = onlyCommentsChangedBy(original, submitted, user.id);
if (!verdict.ok) console.warn(verdict.reason);

When the verdict is body-changed or part-changed, compareDocx lists the blocks and parts that differ. It compares comment text alone, so it shows nothing for a refusal over a comment's author, anchor, or markup.

What must hold

The comparison checks the whole package within the limits below:

  • Every part is byte-identical, except the comment parts: comments, extended comments, people, and the parts Word records a comment's time in (commentsIds.xml and commentsExtensible.xml).
  • The main document part is unchanged outside its body blocks.
  • Its relationships and [Content_Types].xml gain only what the comment parts need: a relationship to each and an override naming each part the file holds.
  • The story reads as it did with the comments taken out, and every changed comment is this author's.
  • Every entry of the comment parts is unchanged, or is one this editor writes and this author could have written; adding a person cannot claim an existing unattributed comment.
  • An entry of a comment that is still there is not removed, and a comment's recorded time can be added only to a comment that is new, within fourteen hours of the clock time on the comment.
  • XML comments, processing instructions, and the extension list that may close commentsExtensible.xml are unchanged outside those entries; layout whitespace may differ.

Both files are read through importDocx first, so a package that spelled the namespaces under other prefixes is compared respelled on both sides and the verdict is unaffected.

editableComments in the options says whose comments may have changed: "own" (the default) is this author's and the unattributed ones, "all" is every comment.

The verdict

type CommentOnlyVerdict =
  | { ok: true }
  | {
      ok: false;
      reason: "body-changed" | "comment-not-owned" | "comment-author-forged";
    }
  | {
      ok: false;
      reason:
        | "part-changed"
        | "relationship-changed"
        | "comment-markup-rejected";
      part: string;
    };
reasonWhat it means
body-changedThe document differs in something other than its comments, including a body edit that deleted commented text.
comment-not-ownedSomebody else's comment or reply was rewritten, re-anchored, or deleted.
comment-author-forgedA new comment claims another identity, or an existing comment's author was rewritten.
part-changedA part outside the comment parts differs, or the main part changed outside its body. part names it.
relationship-changedThe main part's relationships changed beyond what a comment part needs. part names the relationship part.
comment-markup-rejectedA comment part holds an entry this editor would not write for this author, or lacks the entry of a comment still in the file. part names it.

How files are compared

The story is compared as this editor would write it, so two spellings of the same markup (attribute order, 100% against 5000, split runs) are accepted. The comparison does not cover markup inside w:tblGrid beyond the column widths, the size a picture's own transform states, or table properties the model no longer needs. It also cannot detect changes inside cells that continue a vertical merge. Where integrity must hold to the byte, compare the parts yourself, after opening both files through the editor: a returned file whose original spelled the namespaces under other prefixes carries every markup part respelled, so a comparison against the original bytes differs throughout.

Run the verifier on a package at least as new as the editor that wrote the file. Unreadable bytes throw DocxImportError. Who may edit a comment describes the ownership rule the verdict holds to. Use an author name that is not already recorded for another identity; a conflict can produce comment-author-forged.

On this page