web-doc 0.7.0 → 0.9.0

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.
Files changed (65) hide show
  1. package/THIRD_PARTY_NOTICES.md +10 -3
  2. package/dist/contracts.d.ts +6 -0
  3. package/dist/edit/ai/outline.d.ts +47 -0
  4. package/dist/edit/ai/outline.js +338 -0
  5. package/dist/edit/ai/targets.d.ts +16 -0
  6. package/dist/edit/ai/targets.js +309 -0
  7. package/dist/edit/ai/tools.d.ts +28 -0
  8. package/dist/edit/ai/tools.js +607 -0
  9. package/dist/edit/ai/types.d.ts +175 -0
  10. package/dist/edit/ai/types.js +1 -0
  11. package/dist/edit/docx/elements.js +19 -1
  12. package/dist/edit/docx/engine.d.ts +10 -4
  13. package/dist/edit/docx/engine.js +80 -6
  14. package/dist/edit/docx/model.d.ts +2 -0
  15. package/dist/edit/docx/model.js +11 -0
  16. package/dist/edit/docx/operations.d.ts +10 -0
  17. package/dist/edit/docx/provider.d.ts +4 -1
  18. package/dist/edit/docx/provider.js +3 -0
  19. package/dist/edit/docx/session.d.ts +12 -1
  20. package/dist/edit/docx/session.js +41 -0
  21. package/dist/edit/docx/structure-ops.js +39 -4
  22. package/dist/edit/docx/table-ops.js +26 -4
  23. package/dist/edit/docx/text-ops.d.ts +22 -0
  24. package/dist/edit/docx/text-ops.js +49 -16
  25. package/dist/edit/docx/text.js +21 -0
  26. package/dist/edit/docx/tracked.d.ts +52 -0
  27. package/dist/edit/docx/tracked.js +347 -0
  28. package/dist/edit/docx/types.d.ts +24 -1
  29. package/dist/edit/docx/write.d.ts +19 -5
  30. package/dist/edit/docx/write.js +31 -8
  31. package/dist/edit/engine.d.ts +14 -3
  32. package/dist/edit/history.d.ts +27 -3
  33. package/dist/edit/history.js +29 -7
  34. package/dist/edit/pdf/engine/document.js +48 -3
  35. package/dist/edit/pdf/engine/elements.d.ts +6 -0
  36. package/dist/edit/pdf/engine/fonts.js +13 -10
  37. package/dist/edit/pdf/engine/pages.js +9 -1
  38. package/dist/edit/pdf/range-map.d.ts +4 -2
  39. package/dist/edit/pdf/schemas.js +4 -1
  40. package/dist/edit/pdf/session.d.ts +10 -0
  41. package/dist/edit/pdf/session.js +39 -0
  42. package/dist/edit/pdf/types.d.ts +15 -3
  43. package/dist/edit/pptx/handler.js +10 -2
  44. package/dist/edit/pptx/session.d.ts +10 -0
  45. package/dist/edit/pptx/session.js +31 -0
  46. package/dist/edit/session.d.ts +11 -0
  47. package/dist/edit/session.js +269 -27
  48. package/dist/edit/types.d.ts +17 -3
  49. package/dist/edit/worker-engine.d.ts +2 -2
  50. package/dist/edit/worker-engine.js +2 -2
  51. package/dist/fonts/THIRD_PARTY_NOTICES.md +6 -3
  52. package/dist/fonts/manifest.json +4 -4
  53. package/dist/fonts/noto-sans-latin-cyrillic.ttf +0 -0
  54. package/dist/fuzzy-alignment.d.ts +11 -4
  55. package/dist/fuzzy-alignment.js +3 -9
  56. package/dist/headless.d.ts +1 -1
  57. package/dist/headless.js +4 -1
  58. package/dist/index.d.ts +5 -2
  59. package/dist/index.js +11 -2
  60. package/dist/limits.js +3 -0
  61. package/dist/worker-protocol.d.ts +1 -1
  62. package/dist/workers/fuzzy-search-worker.js +1 -1
  63. package/dist/workers/ooxml-edit-worker.js +1415 -860
  64. package/dist/workers/pdf-edit-worker.js +64 -16
  65. package/package.json +1 -1
@@ -5850,13 +5850,16 @@ var pdfOperationSchemas = Object.freeze({
5850
5850
  },
5851
5851
  ["from", "to"]
5852
5852
  ),
5853
+ // Exactly one of `rotation` (absolute) and `by` (a turn from the current
5854
+ // angle); the handler reports a batch that gives both or neither.
5853
5855
  rotatePage: operation(
5854
5856
  "rotatePage",
5855
5857
  {
5856
5858
  pageIndex: { type: "integer", minimum: 0 },
5857
- rotation: { enum: [0, 90, 180, 270] }
5859
+ rotation: { enum: [0, 90, 180, 270] },
5860
+ by: { enum: [90, 180, 270] }
5858
5861
  },
5859
- ["pageIndex", "rotation"]
5862
+ ["pageIndex"]
5860
5863
  ),
5861
5864
  insertShape: operation(
5862
5865
  "insertShape",
@@ -6897,7 +6900,7 @@ var FontLibrary = class {
6897
6900
  if (this.#coveringRegistered(request)) return void 0;
6898
6901
  if (this.#fallback && this.#covers(this.#fallback, request.text))
6899
6902
  return void 0;
6900
- const bad = firstNonWinAnsi(request.text) ?? firstUncovered(request.text, this);
6903
+ const bad = this.#fallback ? this.#firstMissing(this.#fallback, request.text) : firstNonWinAnsi(request.text);
6901
6904
  return {
6902
6905
  path: "/text",
6903
6906
  code: "font-unavailable",
@@ -6955,6 +6958,10 @@ var FontLibrary = class {
6955
6958
  return candidates.sort((a, b) => score(b.font) - score(a.font))[0];
6956
6959
  }
6957
6960
  #covers(bytes, text) {
6961
+ return this.#firstMissing(bytes, text) === void 0;
6962
+ }
6963
+ /** The first character of `text` the font has no glyph for; layout handles line breaks and spaces. */
6964
+ #firstMissing(bytes, text) {
6958
6965
  let coverage = this.#coverage.get(bytes);
6959
6966
  if (!coverage) {
6960
6967
  coverage = parseCmap(bytes);
@@ -6963,9 +6970,9 @@ var FontLibrary = class {
6963
6970
  for (const character of text) {
6964
6971
  const code = character.codePointAt(0);
6965
6972
  if (code === 10 || code === 32) continue;
6966
- if (!coverage.has(code)) return false;
6973
+ if (!coverage.has(code)) return character;
6967
6974
  }
6968
- return true;
6975
+ return void 0;
6969
6976
  }
6970
6977
  #load(pdfium, document2, bytes) {
6971
6978
  let handles = this.#handles.get(document2);
@@ -7017,12 +7024,6 @@ function isBold(font) {
7017
7024
  function isItalic(font) {
7018
7025
  return font.style !== "normal";
7019
7026
  }
7020
- function firstUncovered(text, library) {
7021
- void library;
7022
- for (const character of text)
7023
- if (character !== "\n" && character !== " ") return character;
7024
- return void 0;
7025
- }
7026
7027
  function glyphOutlines(view, tables) {
7027
7028
  const head = tables.get("head");
7028
7029
  const maxp = tables.get("maxp");
@@ -8663,11 +8664,14 @@ var rotatePage = {
8663
8664
  validate(operation2, context, issue) {
8664
8665
  if (operation2.pageIndex >= context.pageCount)
8665
8666
  issue("/pageIndex", "unknown-target", `No page ${operation2.pageIndex}`);
8667
+ if (operation2.rotation === void 0 === (operation2.by === void 0))
8668
+ issue("", "one-of", "Give exactly one of `rotation` and `by`");
8666
8669
  },
8667
8670
  apply(operation2, context) {
8668
8671
  const { lib } = context.pdfium;
8669
8672
  context.withPage(operation2.pageIndex, (page) => {
8670
- lib.FPDFPage_SetRotation(page, operation2.rotation / 90);
8673
+ const quarters = operation2.by !== void 0 ? (lib.FPDFPage_GetRotation(page) + operation2.by / 90) % 4 : operation2.rotation / 90;
8674
+ lib.FPDFPage_SetRotation(page, quarters);
8671
8675
  });
8672
8676
  context.invalidatePage(operation2.pageIndex);
8673
8677
  return {
@@ -9513,7 +9517,10 @@ var defaultResourceLimits = Object.freeze({
9513
9517
  maxOperationMs: 3e4,
9514
9518
  maxEditOperations: 500,
9515
9519
  maxEditHistory: 200,
9516
- maxEditCheckpointBytes: 64 * 1024 * 1024
9520
+ maxEditCheckpointBytes: 64 * 1024 * 1024,
9521
+ maxOutlineNodes: 5e3,
9522
+ maxDescribeChars: 2e5,
9523
+ maxEditCheckpoints: 20
9517
9524
  });
9518
9525
 
9519
9526
  // src/edit/pdf/engine/document.ts
@@ -10040,8 +10047,11 @@ var PdfEditDocument = class {
10040
10047
  },
10041
10048
  // Ids name the state the batch leads to, the operation and the item,
10042
10049
  // so replaying the history reproduces them and an undone id is never
10043
- // handed out again.
10044
- newId: (pageIndex, suffix = "") => `${this.#pages[pageIndex].key}:n${stateId}.${operationIndex}.${created++}${suffix}`,
10050
+ // handed out again. A file saved by an earlier session carries the ids
10051
+ // that session numbered from 1 as well, so one already on the page
10052
+ // gets the first free `~n` instead (ACTION-886); the saved objects are
10053
+ // part of the base, so a replay meets them and picks the same id.
10054
+ newId: (pageIndex, suffix = "") => `${this.#unusedId(pageIndex, `${this.#pages[pageIndex].key}:n${stateId}.${operationIndex}.${created++}`)}${suffix}`,
10045
10055
  withPage: (pageIndex, use) => this.#writePage(pageIndex, use),
10046
10056
  appendObjects: (pageIndex, records) => {
10047
10057
  const page = this.#pages[pageIndex];
@@ -10197,10 +10207,48 @@ var PdfEditDocument = class {
10197
10207
  }
10198
10208
  }
10199
10209
  record.objects = objects.map(
10200
- (object, index) => object.mark && stale.has(object.id) ? { id: `${record.key}:o${index}`, type: object.type } : object
10210
+ (object, index) => object.mark && stale.has(object.id) ? {
10211
+ id: `${record.key}:o${index}`,
10212
+ type: object.type,
10213
+ staleMarkId: object.id
10214
+ } : object
10201
10215
  );
10202
10216
  return record.objects;
10203
10217
  }
10218
+ /**
10219
+ * `id`, or its first free `~n` when an object saved by an earlier session
10220
+ * has it already. Only ids a session numbered (`<key>:n…`) can collide, so
10221
+ * only those are gathered; the objects are read without the page's text.
10222
+ */
10223
+ #unusedId(pageIndex, id) {
10224
+ const record = this.#pages[pageIndex];
10225
+ const objects = record.objects ?? this.#loadObjects(pageIndex);
10226
+ const numbered = `${record.key}:n`;
10227
+ const taken = /* @__PURE__ */ new Set();
10228
+ for (const object of objects) {
10229
+ if (object.id.startsWith(numbered)) taken.add(object.id);
10230
+ if (object.staleMarkId?.startsWith(numbered))
10231
+ taken.add(object.staleMarkId);
10232
+ }
10233
+ if (!taken.has(id)) return id;
10234
+ let suffix = 1;
10235
+ while (taken.has(`${id}~${suffix}`)) suffix += 1;
10236
+ return `${id}~${suffix}`;
10237
+ }
10238
+ /** A page's objects, loading the page alone when they are not known yet. */
10239
+ #loadObjects(pageIndex) {
10240
+ const { lib } = this.#pdfium;
10241
+ const page = lib.FPDF_LoadPage(this.#document.handle, pageIndex);
10242
+ if (!page)
10243
+ throw new ViewerError("render-failed", "PDFium could not load the page", {
10244
+ details: { pageIndex }
10245
+ });
10246
+ try {
10247
+ return this.#objectsOf(pageIndex, page);
10248
+ } finally {
10249
+ lib.FPDF_ClosePage(page);
10250
+ }
10251
+ }
10204
10252
  /** Marks from other sessions keep their id only if it cannot collide with ours. */
10205
10253
  #ownMark(mark, pageKey) {
10206
10254
  return mark.id.startsWith(`${pageKey}:`) ? mark : { ...mark, id: `${pageKey}:${mark.id}` };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-doc",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "web-doc — embeddable browser-only document viewer with Rust/WASM adapters (a fork of Zrimo)",
5
5
  "keywords": [
6
6
  "document-viewer",