ooxml-core 1.22.0 → 1.24.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 (126) hide show
  1. package/README.md +7 -2
  2. package/dist/automation/index.cjs +559 -339
  3. package/dist/automation/index.d.ts +1 -0
  4. package/dist/automation/index.d.ts.map +1 -1
  5. package/dist/automation/index.mjs +558 -340
  6. package/dist/automation/live.d.ts +89 -0
  7. package/dist/automation/live.d.ts.map +1 -0
  8. package/dist/collab/embedding.d.ts +7 -0
  9. package/dist/collab/embedding.d.ts.map +1 -1
  10. package/dist/collab/index.cjs +189 -0
  11. package/dist/collab/index.d.ts +2 -0
  12. package/dist/collab/index.d.ts.map +1 -1
  13. package/dist/collab/index.mjs +186 -1
  14. package/dist/collab/write-back-lifecycle.d.ts +33 -0
  15. package/dist/collab/write-back-lifecycle.d.ts.map +1 -0
  16. package/dist/collab/write-back.d.ts +75 -0
  17. package/dist/collab/write-back.d.ts.map +1 -0
  18. package/dist/docx/ui/customization.d.ts +30 -0
  19. package/dist/docx/ui/customization.d.ts.map +1 -0
  20. package/dist/docx/ui/index.cjs +51 -0
  21. package/dist/docx/ui/index.d.ts +1 -0
  22. package/dist/docx/ui/index.d.ts.map +1 -1
  23. package/dist/docx/ui/index.mjs +46 -1
  24. package/dist/embedding/backstage.d.ts +48 -0
  25. package/dist/embedding/backstage.d.ts.map +1 -0
  26. package/dist/embedding/capabilities.d.ts +60 -0
  27. package/dist/embedding/capabilities.d.ts.map +1 -0
  28. package/dist/embedding/customization.d.ts +32 -0
  29. package/dist/embedding/customization.d.ts.map +1 -0
  30. package/dist/embedding/index.cjs +229 -0
  31. package/dist/embedding/index.d.ts +7 -0
  32. package/dist/embedding/index.d.ts.map +1 -0
  33. package/dist/embedding/index.mjs +204 -0
  34. package/dist/embedding/menu-commands.d.ts +66 -0
  35. package/dist/embedding/menu-commands.d.ts.map +1 -0
  36. package/dist/embedding/regions.d.ts +58 -0
  37. package/dist/embedding/regions.d.ts.map +1 -0
  38. package/dist/embedding/storage.d.ts +111 -0
  39. package/dist/embedding/storage.d.ts.map +1 -0
  40. package/dist/index.cjs +233 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.mjs +233 -1
  44. package/dist/visio/collab/baseline.d.ts +36 -0
  45. package/dist/visio/collab/baseline.d.ts.map +1 -0
  46. package/dist/visio/collab/bind.d.ts +20 -2
  47. package/dist/visio/collab/bind.d.ts.map +1 -1
  48. package/dist/visio/collab/compose-lists.d.ts +27 -0
  49. package/dist/visio/collab/compose-lists.d.ts.map +1 -0
  50. package/dist/visio/collab/compose.d.ts +6 -2
  51. package/dist/visio/collab/compose.d.ts.map +1 -1
  52. package/dist/visio/collab/fixups.d.ts +5 -0
  53. package/dist/visio/collab/fixups.d.ts.map +1 -0
  54. package/dist/visio/collab/index.cjs +1603 -361
  55. package/dist/visio/collab/index.d.ts +3 -2
  56. package/dist/visio/collab/index.d.ts.map +1 -1
  57. package/dist/visio/collab/index.mjs +1596 -362
  58. package/dist/visio/collab/keys.d.ts +32 -1
  59. package/dist/visio/collab/keys.d.ts.map +1 -1
  60. package/dist/visio/collab/package.d.ts +22 -1
  61. package/dist/visio/collab/package.d.ts.map +1 -1
  62. package/dist/visio/collab/pieces.d.ts +41 -0
  63. package/dist/visio/collab/pieces.d.ts.map +1 -0
  64. package/dist/visio/collab/read-ids.d.ts +35 -0
  65. package/dist/visio/collab/read-ids.d.ts.map +1 -0
  66. package/dist/visio/collab/read-parts.d.ts +34 -0
  67. package/dist/visio/collab/read-parts.d.ts.map +1 -0
  68. package/dist/visio/collab/read-shapes.d.ts +34 -0
  69. package/dist/visio/collab/read-shapes.d.ts.map +1 -0
  70. package/dist/visio/collab/read-util.d.ts +20 -0
  71. package/dist/visio/collab/read-util.d.ts.map +1 -0
  72. package/dist/visio/collab/read.d.ts +40 -19
  73. package/dist/visio/collab/read.d.ts.map +1 -1
  74. package/dist/visio/collab/schema.d.ts +55 -1
  75. package/dist/visio/collab/schema.d.ts.map +1 -1
  76. package/dist/visio/collab/snapshot-contents.d.ts +9 -0
  77. package/dist/visio/collab/snapshot-contents.d.ts.map +1 -0
  78. package/dist/visio/collab/snapshot-io.d.ts +26 -0
  79. package/dist/visio/collab/snapshot-io.d.ts.map +1 -0
  80. package/dist/visio/collab/snapshot-parts.d.ts +14 -0
  81. package/dist/visio/collab/snapshot-parts.d.ts.map +1 -0
  82. package/dist/visio/collab/snapshot.d.ts +31 -24
  83. package/dist/visio/collab/snapshot.d.ts.map +1 -1
  84. package/dist/visio/collab/write-parts.d.ts +8 -0
  85. package/dist/visio/collab/write-parts.d.ts.map +1 -0
  86. package/dist/visio/collab/write-shapes.d.ts +30 -0
  87. package/dist/visio/collab/write-shapes.d.ts.map +1 -0
  88. package/dist/visio/collab/write.d.ts +4 -16
  89. package/dist/visio/collab/write.d.ts.map +1 -1
  90. package/dist/visio/collab/zip-store.d.ts +4 -0
  91. package/dist/visio/collab/zip-store.d.ts.map +1 -0
  92. package/dist/visio/document-level.d.ts +57 -0
  93. package/dist/visio/document-level.d.ts.map +1 -0
  94. package/dist/visio/index.cjs +485 -333
  95. package/dist/visio/index.d.ts +2 -0
  96. package/dist/visio/index.d.ts.map +1 -1
  97. package/dist/visio/index.mjs +484 -334
  98. package/dist/visio/layers.d.ts +3 -0
  99. package/dist/visio/layers.d.ts.map +1 -1
  100. package/dist/visio/package.d.ts +9 -0
  101. package/dist/visio/package.d.ts.map +1 -1
  102. package/dist/visio/parse-incremental.d.ts +16 -0
  103. package/dist/visio/parse-incremental.d.ts.map +1 -0
  104. package/dist/visio/parser.d.ts +14 -0
  105. package/dist/visio/parser.d.ts.map +1 -1
  106. package/dist/visio/shape-metadata.d.ts +3 -0
  107. package/dist/visio/shape-metadata.d.ts.map +1 -1
  108. package/dist/visio/ui/collab-options.d.ts +10 -5
  109. package/dist/visio/ui/collab-options.d.ts.map +1 -1
  110. package/dist/visio/ui/contract.d.ts +27 -2
  111. package/dist/visio/ui/contract.d.ts.map +1 -1
  112. package/dist/visio/ui/customization.d.ts +46 -0
  113. package/dist/visio/ui/customization.d.ts.map +1 -0
  114. package/dist/visio/ui/index.cjs +460 -320
  115. package/dist/visio/ui/index.d.ts +1 -0
  116. package/dist/visio/ui/index.d.ts.map +1 -1
  117. package/dist/visio/ui/index.mjs +458 -321
  118. package/dist/xlsx/ui/commands.d.ts +2 -0
  119. package/dist/xlsx/ui/commands.d.ts.map +1 -1
  120. package/dist/xlsx/ui/customization.d.ts +49 -0
  121. package/dist/xlsx/ui/customization.d.ts.map +1 -0
  122. package/dist/xlsx/ui/index.cjs +39 -1
  123. package/dist/xlsx/ui/index.d.ts +1 -0
  124. package/dist/xlsx/ui/index.d.ts.map +1 -1
  125. package/dist/xlsx/ui/index.mjs +37 -2
  126. package/package.json +6 -1
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var Y = require('yjs');
4
- var JSZip = require('jszip');
5
4
  var xmldom = require('@xmldom/xmldom');
5
+ var JSZip = require('jszip');
6
6
 
7
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
8
 
@@ -28,6 +28,143 @@ var Y__namespace = /*#__PURE__*/_interopNamespace(Y);
28
28
  var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
29
29
 
30
30
  // visio/collab/bind.ts
31
+
32
+ // digest/sha256.ts
33
+ var K = new Uint32Array([
34
+ 1116352408,
35
+ 1899447441,
36
+ 3049323471,
37
+ 3921009573,
38
+ 961987163,
39
+ 1508970993,
40
+ 2453635748,
41
+ 2870763221,
42
+ 3624381080,
43
+ 310598401,
44
+ 607225278,
45
+ 1426881987,
46
+ 1925078388,
47
+ 2162078206,
48
+ 2614888103,
49
+ 3248222580,
50
+ 3835390401,
51
+ 4022224774,
52
+ 264347078,
53
+ 604807628,
54
+ 770255983,
55
+ 1249150122,
56
+ 1555081692,
57
+ 1996064986,
58
+ 2554220882,
59
+ 2821834349,
60
+ 2952996808,
61
+ 3210313671,
62
+ 3336571891,
63
+ 3584528711,
64
+ 113926993,
65
+ 338241895,
66
+ 666307205,
67
+ 773529912,
68
+ 1294757372,
69
+ 1396182291,
70
+ 1695183700,
71
+ 1986661051,
72
+ 2177026350,
73
+ 2456956037,
74
+ 2730485921,
75
+ 2820302411,
76
+ 3259730800,
77
+ 3345764771,
78
+ 3516065817,
79
+ 3600352804,
80
+ 4094571909,
81
+ 275423344,
82
+ 430227734,
83
+ 506948616,
84
+ 659060556,
85
+ 883997877,
86
+ 958139571,
87
+ 1322822218,
88
+ 1537002063,
89
+ 1747873779,
90
+ 1955562222,
91
+ 2024104815,
92
+ 2227730452,
93
+ 2361852424,
94
+ 2428436474,
95
+ 2756734187,
96
+ 3204031479,
97
+ 3329325298
98
+ ]);
99
+ var IV = [
100
+ 1779033703,
101
+ 3144134277,
102
+ 1013904242,
103
+ 2773480762,
104
+ 1359893119,
105
+ 2600822924,
106
+ 528734635,
107
+ 1541459225
108
+ ];
109
+ var W = new Uint32Array(64);
110
+ var rotr = (x, n) => x >>> n | x << 32 - n;
111
+ function compress(h, view, offset) {
112
+ for (let i = 0; i < 16; i++) W[i] = view.getUint32(offset + i * 4);
113
+ for (let i = 16; i < 64; i++) {
114
+ const a2 = W[i - 15];
115
+ const b2 = W[i - 2];
116
+ const s0 = rotr(a2, 7) ^ rotr(a2, 18) ^ a2 >>> 3;
117
+ const s1 = rotr(b2, 17) ^ rotr(b2, 19) ^ b2 >>> 10;
118
+ W[i] = W[i - 16] + s0 + W[i - 7] + s1 >>> 0;
119
+ }
120
+ let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], k = h[7];
121
+ for (let i = 0; i < 64; i++) {
122
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
123
+ const ch = e & f ^ ~e & g;
124
+ const t1 = k + S1 + ch + K[i] + W[i] >>> 0;
125
+ const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
126
+ const maj = a & b ^ a & c ^ b & c;
127
+ const t2 = S0 + maj >>> 0;
128
+ k = g;
129
+ g = f;
130
+ f = e;
131
+ e = d + t1 >>> 0;
132
+ d = c;
133
+ c = b;
134
+ b = a;
135
+ a = t1 + t2 >>> 0;
136
+ }
137
+ h[0] = h[0] + a >>> 0;
138
+ h[1] = h[1] + b >>> 0;
139
+ h[2] = h[2] + c >>> 0;
140
+ h[3] = h[3] + d >>> 0;
141
+ h[4] = h[4] + e >>> 0;
142
+ h[5] = h[5] + f >>> 0;
143
+ h[6] = h[6] + g >>> 0;
144
+ h[7] = h[7] + k >>> 0;
145
+ }
146
+ function pad64(data) {
147
+ const padded = new Uint8Array(Math.ceil((data.length + 9) / 64) * 64);
148
+ padded.set(data);
149
+ padded[data.length] = 128;
150
+ const bits = data.length * 8;
151
+ const view = new DataView(padded.buffer);
152
+ view.setUint32(padded.length - 8, Math.floor(bits / 4294967296));
153
+ view.setUint32(padded.length - 4, bits >>> 0);
154
+ return view;
155
+ }
156
+ function wordsOut(h) {
157
+ const out = new Uint8Array(h.length * 4);
158
+ const view = new DataView(out.buffer);
159
+ for (let i = 0; i < h.length; i++) view.setUint32(i * 4, h[i]);
160
+ return out;
161
+ }
162
+ function sha256(data) {
163
+ const h = new Uint32Array(IV);
164
+ const view = pad64(data);
165
+ for (let offset = 0; offset < view.byteLength; offset += 64) compress(h, view, offset);
166
+ return wordsOut(h);
167
+ }
31
168
  var DEFAULT_XML_LIMITS = {
32
169
  maxDepth: 512,
33
170
  maxNodes: 5e6
@@ -278,11 +415,51 @@ function stripPageOverrides(xml) {
278
415
  (tag) => attrOf(tag, "ContentType") === PAGE_CONTENT_TYPE ? "" : tag
279
416
  );
280
417
  }
281
- function withPageOverrides(xml, pagePaths) {
282
- const clean = stripPageOverrides(xml);
283
- const add = pagePaths.map((path) => `<Override PartName="/${path}" ContentType="${PAGE_CONTENT_TYPE}"/>`).join("");
284
- const close = clean.lastIndexOf("</");
285
- return close < 0 ? clean : clean.slice(0, close) + add + clean.slice(close);
418
+ var withPageOverrides = (xml, pagePaths) => withOverrides(stripPageOverrides(xml), PAGE_CONTENT_TYPE, pagePaths);
419
+ var MASTER_TYPE = "http://schemas.microsoft.com/visio/2010/relationships/master";
420
+ var MASTER_CONTENT_TYPE = "application/vnd.ms-visio.master+xml";
421
+ function withOverrides(xml, contentType, paths) {
422
+ const add = paths.map((path) => `<Override PartName="/${path}" ContentType="${contentType}"/>`).join("");
423
+ const close = xml.lastIndexOf("</");
424
+ return close < 0 ? xml : xml.slice(0, close) + add + xml.slice(close);
425
+ }
426
+ function stripOverrides(xml, types, parts = /* @__PURE__ */ new Set()) {
427
+ return xml.replace(/<(?:\w+:)?Override\b[^>]*>/g, (tag) => {
428
+ const type = attrOf(tag, "ContentType");
429
+ const name = attrOf(tag, "PartName");
430
+ return type !== void 0 && types.includes(type) || name !== void 0 && parts.has(name.replace(/^\//, "")) ? "" : tag;
431
+ });
432
+ }
433
+ function declaredType(xml, path) {
434
+ for (const tag of xml.matchAll(/<(?:\w+:)?Override\b[^>]*>/g)) {
435
+ const name = attrOf(tag[0], "PartName");
436
+ const type = attrOf(tag[0], "ContentType");
437
+ if (name === `/${path}` && type !== void 0) return { type, byDefault: false };
438
+ }
439
+ const ext = /\.([^./]+)$/.exec(path)?.[1]?.toLowerCase();
440
+ if (ext === void 0) return void 0;
441
+ for (const tag of xml.matchAll(/<(?:\w+:)?Default\b[^>]*>/g)) {
442
+ const e = attrOf(tag[0], "Extension");
443
+ const type = attrOf(tag[0], "ContentType");
444
+ if (e?.toLowerCase() === ext && type !== void 0) return { type, byDefault: true };
445
+ }
446
+ return void 0;
447
+ }
448
+ function ensureType(xml, path, declared) {
449
+ if (declaredType(xml, path)) return xml;
450
+ const close = xml.lastIndexOf("</");
451
+ if (close < 0) return xml;
452
+ const ext = /\.([^./]+)$/.exec(path)?.[1];
453
+ const tag = declared.byDefault && ext ? `<Default Extension="${ext}" ContentType="${declared.type}"/>` : `<Override PartName="/${path}" ContentType="${declared.type}"/>`;
454
+ return xml.slice(0, close) + tag + xml.slice(close);
455
+ }
456
+ var isMediaPart = (path) => /(^|\/)media\/[^/]+$/i.test(path);
457
+ function relativeTarget(dir, path) {
458
+ const from = dir ? dir.split("/") : [];
459
+ const to = path.split("/");
460
+ let i = 0;
461
+ while (i < from.length && i < to.length - 1 && from[i] === to[i]) i++;
462
+ return [...from.slice(i).map(() => ".."), ...to.slice(i)].join("/");
286
463
  }
287
464
  function toBase64(bytes) {
288
465
  let out = "";
@@ -316,15 +493,154 @@ function canon(xml) {
316
493
  canonCache.set(xml, result);
317
494
  return result;
318
495
  }
496
+ function contentHash(bytes) {
497
+ let out = "";
498
+ for (const byte of sha256(bytes)) out += byte.toString(16).padStart(2, "0");
499
+ return out;
500
+ }
501
+
502
+ // visio/collab/pieces.ts
503
+ var seg = (value) => value.replace(/[%/]/g, (c) => c === "%" ? "%25" : "%2F");
504
+ var tagName = (open) => /^<([^\s/>]+)/.exec(open)?.[1] ?? "Shape";
505
+ var openTagOf = (text, span) => {
506
+ const tag = text.slice(span.start, span.openEnd);
507
+ return span.selfClosing ? tag.replace(/\s*\/>$/, ">") : tag;
508
+ };
509
+ var closeTagOf = (open) => `</${tagName(open)}>`;
510
+ function splitShape(xml) {
511
+ const box = scanContainer(xml, "Shape");
512
+ if (!box) return void 0;
513
+ const used = /* @__PURE__ */ new Set();
514
+ const unique = (path) => {
515
+ let out = path;
516
+ for (let n = 2; used.has(out); n++) out = `${path}~${n}`;
517
+ used.add(out);
518
+ return out;
519
+ };
520
+ const pieces = [];
521
+ const nested = [];
522
+ const others = /* @__PURE__ */ new Map();
523
+ const other = (parent, name, text) => {
524
+ const k = others.get(parent + name) ?? 0;
525
+ others.set(parent + name, k + 1);
526
+ pieces.push({
527
+ path: unique(`${parent ? `${parent}/` : ""}x/${name}#${k}`),
528
+ parent,
529
+ kind: "leaf",
530
+ text
531
+ });
532
+ };
533
+ const cell = (parent, text) => {
534
+ const n = attrOf(text.slice(0, text.search(/>/) + 1), "N");
535
+ if (n === void 0) return other(parent, "Cell", text);
536
+ pieces.push({
537
+ path: unique(`${parent ? `${parent}/` : ""}c/${seg(n)}`),
538
+ parent,
539
+ kind: "leaf",
540
+ text
541
+ });
542
+ };
543
+ for (const child of box.children) {
544
+ const text = xml.slice(child.start, child.end);
545
+ if (child.name === "Cell") cell("", text);
546
+ else if (child.name === "Shapes") {
547
+ const list = scanContainer(text, "Shapes");
548
+ for (const s of list?.children ?? [])
549
+ if (s.name === "Shape") nested.push(text.slice(s.start, s.end));
550
+ } else if (child.name === "Section") {
551
+ const head = openTagOf(xml, child);
552
+ const n = attrOf(head, "N");
553
+ const ix = attrOf(head, "IX");
554
+ if (n === void 0 && ix === void 0) {
555
+ other("", "Section", text);
556
+ continue;
557
+ }
558
+ const sec = unique(`s/${seg(n ?? "")}${ix !== void 0 ? `:${seg(ix)}` : ""}`);
559
+ pieces.push({ path: sec, parent: "", kind: "open", text: head });
560
+ const inner = scanContainer(text, "Section");
561
+ let rowIndex = 0;
562
+ for (const part of inner?.children ?? []) {
563
+ const sub = text.slice(part.start, part.end);
564
+ if (part.name === "Cell") cell(sec, sub);
565
+ else if (part.name === "Row") {
566
+ const rowHead = openTagOf(text, part);
567
+ const id = attrOf(rowHead, "IX") ?? attrOf(rowHead, "N") ?? `#${rowIndex}`;
568
+ rowIndex++;
569
+ const row = unique(`${sec}/r/${seg(id)}`);
570
+ pieces.push({ path: row, parent: sec, kind: "open", text: rowHead });
571
+ for (const rc of scanContainer(sub, "Row")?.children ?? [])
572
+ if (rc.name === "Cell") cell(row, sub.slice(rc.start, rc.end));
573
+ else other(row, rc.name, sub.slice(rc.start, rc.end));
574
+ } else other(sec, part.name, sub);
575
+ }
576
+ } else other("", child.name, text);
577
+ }
578
+ return { open: openTagOf(xml, box), pieces, nested };
579
+ }
580
+ function buildShape(open, entries, tail) {
581
+ const byParent = /* @__PURE__ */ new Map();
582
+ for (const [path, entry] of entries) {
583
+ const parent = parentOf(path);
584
+ const list = byParent.get(parent) ?? [];
585
+ list.push({ path, entry });
586
+ byParent.set(parent, list);
587
+ }
588
+ const render = (parent) => (byParent.get(parent) ?? []).sort((a, b) => a.entry.pos - b.entry.pos || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)).map(
589
+ ({ path, entry }) => entry.open !== void 0 ? entry.open + render(path) + closeTagOf(entry.open) : entry.xml ?? ""
590
+ ).join("");
591
+ return open + render("") + tail + closeTagOf(open);
592
+ }
593
+ function parentOf(path) {
594
+ const parts = path.split("/");
595
+ return parts.length <= 2 ? "" : parts.slice(0, -2).join("/");
596
+ }
597
+ var SIMPLE = /^<([^\s/>]+)((?:\s+[^\s=/>]+\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(?:\/>|>([^<]*)<\/\1>)$/;
598
+ var ATTR = /\s([^\s=/>]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
599
+ function pieceContent(kind, text) {
600
+ const simple = SIMPLE.exec(kind === "open" ? `${text}</${tagName(text)}>` : text);
601
+ if (!simple) return kind === "open" ? canon(`${text}</${tagName(text)}>`) : canon(text);
602
+ const attrs = [...(simple[2] ?? "").matchAll(ATTR)].map((m) => [m[1], m[2] ?? m[3] ?? ""]).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
603
+ return JSON.stringify([simple[1], attrs, simple[3] ?? ""]);
604
+ }
605
+
606
+ // visio/collab/baseline.ts
607
+ var masterScope = (key) => `m~${key}`;
608
+ var pageId = (key) => `p:${key}`;
609
+ var bodyId = (key) => `b:${key}`;
610
+ var shapeId = (page, key) => `s:${page}/${key}`;
611
+ var cellId = (page, shape, path) => `f:${page}/${shape}/${path}`;
612
+ var connectId = (key) => `c:${key}`;
613
+ var masterId = (key) => `m:${key}`;
614
+ var mediaId = (key) => `i:${key}`;
615
+ var pageContent = (e) => JSON.stringify([e.id, e.back ?? null, canon(e.xml)]);
616
+ var bodyContent = (e) => JSON.stringify([canon(e.shell), e.rels ?? null]);
617
+ var shellContent = (e) => JSON.stringify([e.parent ?? null, pieceContent("open", e.open)]);
618
+ var entryContent = (e) => e.xml !== void 0 ? pieceContent("leaf", e.xml) : pieceContent("open", e.open ?? "");
619
+ var masterContent = (e) => JSON.stringify([e.id, canon(e.xml), e.rels ?? null, e.print]);
319
620
 
320
621
  // visio/collab/schema.ts
321
- var SCHEMA_VERSION = 1;
622
+ var SCHEMA_VERSION = 4;
623
+ var SchemaVersionError = class extends Error {
624
+ constructor(found) {
625
+ super(
626
+ `The shared drawing uses schema version ${String(found)}; this build reads version ${SCHEMA_VERSION}.`
627
+ );
628
+ this.found = found;
629
+ this.name = "SchemaVersionError";
630
+ }
631
+ found;
632
+ };
322
633
  var META = "visio:meta";
323
634
  var PAGES = "visio:pages";
324
635
  var BODIES = "visio:bodies";
325
636
  var SHAPES = "visio:shapes";
637
+ var CELLS = "visio:cells";
326
638
  var CONNECTS = "visio:connects";
327
639
  var DEAD = "visio:dead";
640
+ var MASTERS = "visio:masters";
641
+ var RENUM = "visio:renum";
642
+ var MEDIA = "visio:media";
643
+ var BLOBS = "visio:blobs";
328
644
  var PARTS = "visio:parts";
329
645
  var REL_MARK = "<!--@rel-->";
330
646
  var SHAPES_MARK = "<!--@shapes-->";
@@ -335,8 +651,13 @@ function sharedDrawing(doc) {
335
651
  pages: doc.getMap(PAGES),
336
652
  bodies: doc.getMap(BODIES),
337
653
  shapes: doc.getMap(SHAPES),
654
+ cells: doc.getMap(CELLS),
338
655
  connects: doc.getMap(CONNECTS),
339
656
  dead: doc.getMap(DEAD),
657
+ masters: doc.getMap(MASTERS),
658
+ renum: doc.getMap(RENUM),
659
+ media: doc.getMap(MEDIA),
660
+ blobs: doc.getMap(BLOBS),
340
661
  parts: doc.getMap(PARTS)
341
662
  };
342
663
  }
@@ -345,17 +666,27 @@ var sharedTypes = (shared) => [
345
666
  shared.pages,
346
667
  shared.bodies,
347
668
  shared.shapes,
669
+ shared.cells,
348
670
  shared.connects,
349
671
  shared.dead,
672
+ shared.masters,
673
+ shared.renum,
674
+ shared.media,
675
+ shared.blobs,
350
676
  shared.parts
351
677
  ];
352
678
  var isSharedDrawingEmpty = (shared) => shared.pages.size === 0 && shared.meta.get("v") === void 0;
679
+ function assertSchemaVersion(shared) {
680
+ const v = shared.meta.get("v");
681
+ if (v !== void 0 && v !== SCHEMA_VERSION) throw new SchemaVersionError(v);
682
+ }
353
683
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
354
684
  function sameRecord(a, b) {
355
685
  if (!isRecord(a) || !isRecord(b)) return a === b;
356
686
  const ka = Object.keys(a).filter((k) => a[k] !== void 0);
357
687
  const kb = Object.keys(b).filter((k) => b[k] !== void 0);
358
- return ka.length === kb.length && ka.every((k) => a[k] === b[k]);
688
+ const same = (x, y) => x === y || Array.isArray(x) && Array.isArray(y) && JSON.stringify(x) === JSON.stringify(y);
689
+ return ka.length === kb.length && ka.every((k) => same(a[k], b[k]));
359
690
  }
360
691
  function setIfChanged(map, key, value) {
361
692
  if (sameRecord(map.get(key), value)) return false;
@@ -364,27 +695,59 @@ function setIfChanged(map, key, value) {
364
695
  }
365
696
  var str = (value) => typeof value === "string" ? value : void 0;
366
697
  var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
698
+ var opt = (key, value) => value === void 0 ? {} : { [key]: value };
367
699
  function pageEntry(value) {
368
700
  if (!isRecord(value)) return void 0;
369
701
  const pos = num(value.pos);
370
702
  const id = str(value.id);
371
703
  const xml = str(value.xml);
372
704
  if (pos === void 0 || id === void 0 || xml === void 0) return void 0;
373
- const back = str(value.back);
374
- return { pos, id, xml, ...back !== void 0 ? { back } : {} };
705
+ return { pos, id, xml, ...opt("back", str(value.back)) };
375
706
  }
376
707
  function bodyEntry(value) {
377
708
  if (!isRecord(value)) return void 0;
378
709
  const shell = str(value.shell);
379
710
  if (shell === void 0) return void 0;
380
- const rels = str(value.rels);
381
- return { shell, ...rels !== void 0 ? { rels } : {} };
711
+ return { shell, ...opt("rels", str(value.rels)), ...opt("b", str(value.b)) };
382
712
  }
383
713
  function shapeEntry(value) {
714
+ if (!isRecord(value)) return void 0;
715
+ const pos = num(value.pos);
716
+ const open = str(value.open);
717
+ if (pos === void 0 || open === void 0) return void 0;
718
+ return { pos, open, ...opt("parent", str(value.parent)), ...opt("b", str(value.b)) };
719
+ }
720
+ function cellEntry(value) {
384
721
  if (!isRecord(value)) return void 0;
385
722
  const pos = num(value.pos);
386
723
  const xml = str(value.xml);
387
- return pos === void 0 || xml === void 0 ? void 0 : { pos, xml };
724
+ const open = str(value.open);
725
+ if (pos === void 0 || xml === void 0 && open === void 0) return void 0;
726
+ const r = Array.isArray(value.r) && value.r.length % 2 === 0 && value.r.every((v) => typeof v === "string") ? value.r : void 0;
727
+ return {
728
+ pos,
729
+ ...opt("xml", xml),
730
+ ...opt("open", xml === void 0 ? open : void 0),
731
+ ...r && r.length ? { r } : {}
732
+ };
733
+ }
734
+ function masterEntry(value) {
735
+ if (!isRecord(value)) return void 0;
736
+ const pos = num(value.pos);
737
+ const id = str(value.id);
738
+ const xml = str(value.xml);
739
+ const part = str(value.part);
740
+ if (pos === void 0 || id === void 0 || xml === void 0 || part === void 0)
741
+ return void 0;
742
+ return { pos, id, xml, part, ...opt("rels", str(value.rels)), ...opt("b", str(value.b)) };
743
+ }
744
+ function mediaEntry(value) {
745
+ if (!isRecord(value)) return void 0;
746
+ const path = str(value.path);
747
+ const hash = str(value.hash);
748
+ const ct = str(value.ct);
749
+ if (path === void 0 || hash === void 0 || ct === void 0) return void 0;
750
+ return { path, hash, ct, d: value.d === true, ...opt("b", str(value.b)) };
388
751
  }
389
752
  function connectEntry(value) {
390
753
  if (!isRecord(value)) return void 0;
@@ -396,11 +759,15 @@ function connectEntry(value) {
396
759
  }
397
760
  return out;
398
761
  }
399
- var DEFAULT_MAX_PART_BYTES = 48 * 1024 * 1024;
400
- var SHAPE_ID = /<(?:\w+:)?Shape\s[^>]*?\bID\s*=\s*(["'])(\d+)\1/g;
401
- function shapeIds(xml) {
402
- return [...xml.matchAll(SHAPE_ID)].map((m) => m[2]);
762
+ function renumEntry(value) {
763
+ if (!isRecord(value)) return void 0;
764
+ const pair = (v) => Array.isArray(v) && v.length === 2 && typeof v[0] === "string" && typeof v[1] === "string" ? [v[0], v[1]] : void 0;
765
+ const i = pair(value.i);
766
+ const m = pair(value.m);
767
+ return i || m ? { ...i ? { i } : {}, ...m ? { m } : {} } : void 0;
403
768
  }
769
+
770
+ // visio/collab/snapshot-contents.ts
404
771
  function splitList(text, name, mark, child) {
405
772
  const box = scanContainer(text, name);
406
773
  if (!box) return { text, items: [] };
@@ -416,6 +783,66 @@ function splitList(text, name, mark, child) {
416
783
  }
417
784
  return { text: text.slice(0, box.openEnd) + mark + text.slice(box.closeStart), items };
418
785
  }
786
+ function formulaRefs(text, owner) {
787
+ const out = [];
788
+ const seen = /* @__PURE__ */ new Set();
789
+ for (const f of text.matchAll(/\sF\s*=\s*("[^"]*"|'[^']*')/g))
790
+ for (const m of f[1].matchAll(/Sheet\.(\d+)(?!\d)/g)) {
791
+ const id = m[1];
792
+ const key = owner.get(id);
793
+ if (key !== void 0 && !seen.has(id)) {
794
+ seen.add(id);
795
+ out.push(id, key);
796
+ }
797
+ }
798
+ return out;
799
+ }
800
+ function flatten(xml, parent, page, keys, out) {
801
+ const split2 = splitShape(xml);
802
+ const id = split2 ? attrOf(split2.open, "ID") : void 0;
803
+ if (!split2 || id === void 0) return;
804
+ const key = keys.shapeKey(page, id);
805
+ out.push({
806
+ key,
807
+ id,
808
+ ...parent !== void 0 ? { parent } : {},
809
+ open: split2.open,
810
+ pieces: split2.pieces
811
+ });
812
+ for (const nested of split2.nested) flatten(nested, key, page, keys, out);
813
+ }
814
+ function splitContents(content, scope, keys) {
815
+ const shapesSplit = splitList(content, "Shapes", SHAPES_MARK, "Shape");
816
+ const connectsSplit = splitList(shapesSplit.text, "Connects", CONNECTS_MARK, "Connect");
817
+ const shapes = [];
818
+ for (const text of shapesSplit.items) flatten(text, void 0, scope, keys, shapes);
819
+ const owner = new Map(shapes.map((s) => [s.id, s.key]));
820
+ for (const shape of shapes)
821
+ for (const piece of shape.pieces)
822
+ if (piece.kind === "leaf") {
823
+ const refs = formulaRefs(piece.text, owner);
824
+ if (refs.length) piece.refs = refs;
825
+ }
826
+ const connects = [];
827
+ for (const text of connectsSplit.items) {
828
+ const a = (name) => attrOf(text, name) ?? "";
829
+ const entry = {
830
+ fk: owner.get(a("FromSheet")) ?? "",
831
+ fi: a("FromSheet"),
832
+ tk: owner.get(a("ToSheet")) ?? "",
833
+ ti: a("ToSheet"),
834
+ fc: a("FromCell"),
835
+ tc: a("ToCell"),
836
+ fp: a("FromPart"),
837
+ tp: a("ToPart")
838
+ };
839
+ connects.push({
840
+ key: `${scope}/${entry.fk}.${entry.fi}.${entry.fc}.${entry.fp}>${entry.tk}.${entry.ti}.${entry.tc}.${entry.tp}`,
841
+ entry
842
+ });
843
+ }
844
+ return { shell: connectsSplit.text, shapes, connects };
845
+ }
419
846
  var readZip = (bytes) => JSZip__default.default.loadAsync(bytes);
420
847
  var zipText = async (zip, path) => zip.file(path)?.async("string");
421
848
  async function readLayout(zip) {
@@ -426,19 +853,25 @@ async function readLayout(zip) {
426
853
  const documentPath = resolveTarget("", root.target);
427
854
  const rels = parseRelationships(await zipText(zip, relsPathOf(documentPath)));
428
855
  const pages = rels.find((r) => r.type.endsWith("/pages"));
429
- return pages ? { documentPath, pagesPath: resolveTarget(dirName(documentPath), pages.target) } : void 0;
856
+ const masters = rels.find((r) => r.type.endsWith("/masters"));
857
+ const dir = dirName(documentPath);
858
+ return pages ? {
859
+ documentPath,
860
+ pagesPath: resolveTarget(dir, pages.target),
861
+ ...masters ? { mastersPath: resolveTarget(dir, masters.target) } : {}
862
+ } : void 0;
430
863
  }
431
- async function readLocalPages(zip, layout, pagesXml) {
432
- const box = scanContainer(pagesXml, "Pages");
864
+ async function readLocalItems(zip, listPath, xml, container, child) {
865
+ const box = scanContainer(xml, container);
433
866
  if (!box) return void 0;
434
867
  const rels = new Map(
435
- parseRelationships(await zipText(zip, relsPathOf(layout.pagesPath))).map((r) => [r.id, r])
868
+ parseRelationships(await zipText(zip, relsPathOf(listPath))).map((r) => [r.id, r])
436
869
  );
437
- const pages = [];
870
+ const items = [];
438
871
  for (const span of box.children) {
439
- if (span.name !== "Page") continue;
440
- const text = pagesXml.slice(span.start, span.end);
441
- const inner = scanContainer(text, "Page");
872
+ if (span.name !== child) continue;
873
+ const text = xml.slice(span.start, span.end);
874
+ const inner = scanContainer(text, child);
442
875
  const relSpan = inner?.children.find((c) => c.name === "Rel");
443
876
  if (!inner || !relSpan) return void 0;
444
877
  const relTag = text.slice(relSpan.start, relSpan.openEnd);
@@ -446,239 +879,268 @@ async function readLocalPages(zip, layout, pagesXml) {
446
879
  const target = rid ? rels.get(rid)?.target : void 0;
447
880
  const id = attrOf(text.slice(0, inner.openEnd), "ID");
448
881
  if (target === void 0 || id === void 0) return void 0;
449
- pages.push({
882
+ items.push({
450
883
  id,
451
884
  text,
452
- path: resolveTarget(dirName(layout.pagesPath), target),
885
+ path: resolveTarget(dirName(listPath), target),
453
886
  rel: { start: relSpan.start, end: relSpan.end }
454
887
  });
455
888
  }
456
- return { box, pages };
889
+ return { box, items };
457
890
  }
891
+ var withMark = (item) => item.text.slice(0, item.rel.start) + REL_MARK + item.text.slice(item.rel.end);
892
+
893
+ // visio/collab/snapshot-parts.ts
894
+ async function snapshotMasters(zip, layout, keys, derived) {
895
+ const masters = [];
896
+ let mastersOpen;
897
+ let mastersClose;
898
+ if (layout.mastersPath) {
899
+ const listXml = await zipText(zip, layout.mastersPath) ?? "";
900
+ const list = await readLocalItems(zip, layout.mastersPath, listXml, "Masters", "Master");
901
+ if (list) {
902
+ derived.add(layout.mastersPath).add(relsPathOf(layout.mastersPath));
903
+ mastersOpen = listXml.slice(0, list.box.openEnd);
904
+ mastersClose = listXml.slice(list.box.closeStart);
905
+ for (const item of list.items) {
906
+ const content = await zipText(zip, item.path);
907
+ if (content === void 0) continue;
908
+ derived.add(item.path).add(relsPathOf(item.path));
909
+ const key = keys.masterKey(item.id);
910
+ keys.masterPaths.set(key, item.path);
911
+ const rels = await zipText(zip, relsPathOf(item.path));
912
+ const { shell, shapes, connects } = splitContents(content, masterScope(key), keys);
913
+ masters.push({
914
+ key,
915
+ id: item.id,
916
+ xml: withMark(item),
917
+ path: item.path,
918
+ part: encoder.encode(shell),
919
+ ...rels !== void 0 ? { rels } : {},
920
+ shapes,
921
+ connects
922
+ });
923
+ }
924
+ }
925
+ }
926
+ return { masters, mastersOpen, mastersClose };
927
+ }
928
+ async function snapshotRest(zip, derived, limit) {
929
+ const parts = /* @__PURE__ */ new Map();
930
+ const media = [];
931
+ const typesXml = await zipText(zip, CONTENT_TYPES) ?? "";
932
+ const mediaPaths = /* @__PURE__ */ new Set();
933
+ let total = 0;
934
+ for (const path of Object.keys(zip.files)) {
935
+ const file = zip.files[path];
936
+ if (file.dir || derived.has(path) || isLocalOnlyPart(path)) continue;
937
+ const data = await file.async("uint8array");
938
+ total += data.length;
939
+ if (total > limit) throw new Error("The package parts exceed the shared size limit.");
940
+ const declared = isMediaPart(path) ? declaredType(typesXml, path) : void 0;
941
+ if (declared) {
942
+ mediaPaths.add(path);
943
+ media.push({
944
+ path,
945
+ hash: contentHash(data),
946
+ ct: declared.type,
947
+ d: declared.byDefault,
948
+ data
949
+ });
950
+ } else parts.set(path, data);
951
+ }
952
+ const types = parts.get(CONTENT_TYPES);
953
+ if (types)
954
+ parts.set(
955
+ CONTENT_TYPES,
956
+ encoder.encode(
957
+ stripOverrides(decoder.decode(types), [PAGE_CONTENT_TYPE, MASTER_CONTENT_TYPE], mediaPaths)
958
+ )
959
+ );
960
+ return { parts, media };
961
+ }
962
+
963
+ // visio/collab/snapshot.ts
964
+ var DEFAULT_MAX_PART_BYTES = 48 * 1024 * 1024;
458
965
  async function snapshotDrawing(bytes, keys, options = {}) {
459
966
  const zip = await readZip(bytes);
460
967
  const layout = await readLayout(zip);
461
968
  if (!layout) throw new Error("The package has no Visio pages part.");
462
969
  const pagesXml = await zipText(zip, layout.pagesPath) ?? "";
463
- const local = await readLocalPages(zip, layout, pagesXml);
970
+ const local = await readLocalItems(zip, layout.pagesPath, pagesXml, "Pages", "Page");
464
971
  if (!local) throw new Error("The pages part cannot be split into pages.");
465
972
  const derived = /* @__PURE__ */ new Set([layout.pagesPath, relsPathOf(layout.pagesPath)]);
466
- const idToKey = new Map(local.pages.map((p) => [p.id, keys.pageKey(p.id)]));
973
+ const idToKey = new Map(local.items.map((p) => [p.id, keys.pageKey(p.id)]));
467
974
  const pages = [];
468
- for (const page of local.pages) {
975
+ for (const page of local.items) {
469
976
  const key = idToKey.get(page.id);
470
977
  derived.add(page.path).add(relsPathOf(page.path));
471
978
  const head = page.text.slice(0, scanContainer(page.text, "Page").openEnd);
472
979
  const backId = attrOf(head, "BackPage");
473
- const xml = page.text.slice(0, page.rel.start) + REL_MARK + page.text.slice(page.rel.end);
474
980
  const content = await zipText(zip, page.path) ?? "";
475
981
  const rels = await zipText(zip, relsPathOf(page.path));
476
- const shapesSplit = splitList(content, "Shapes", SHAPES_MARK, "Shape");
477
- const connectsSplit = splitList(shapesSplit.text, "Connects", CONNECTS_MARK, "Connect");
478
- const owner = /* @__PURE__ */ new Map();
479
- const shapes = [];
480
- for (const text of shapesSplit.items) {
481
- const ids = shapeIds(text);
482
- const id = ids[0];
483
- if (id === void 0) continue;
484
- const shapeKey = keys.shapeKey(key, id);
485
- for (const nested of ids) owner.set(nested, shapeKey);
486
- shapes.push({ key: shapeKey, id, xml: text });
487
- }
488
- const connects = [];
489
- for (const text of connectsSplit.items) {
490
- const a = (name) => attrOf(text, name) ?? "";
491
- const entry = {
492
- fk: owner.get(a("FromSheet")) ?? "",
493
- fi: a("FromSheet"),
494
- tk: owner.get(a("ToSheet")) ?? "",
495
- ti: a("ToSheet"),
496
- fc: a("FromCell"),
497
- tc: a("ToCell"),
498
- fp: a("FromPart"),
499
- tp: a("ToPart")
500
- };
501
- connects.push({
502
- key: `${key}/${entry.fk}.${entry.fi}.${entry.fc}.${entry.fp}>${entry.tk}.${entry.ti}.${entry.tc}.${entry.tp}`,
503
- entry
504
- });
505
- }
982
+ const { shell, shapes, connects } = splitContents(content, key, keys);
506
983
  keys.pagePaths.set(key, page.path);
507
984
  pages.push({
508
985
  key,
509
986
  id: page.id,
510
987
  ...backId !== void 0 && idToKey.has(backId) ? { back: idToKey.get(backId) } : {},
511
- xml,
512
- shell: connectsSplit.text,
988
+ xml: withMark(page),
989
+ shell,
513
990
  ...rels !== void 0 ? { rels } : {},
514
991
  path: page.path,
515
992
  shapes,
516
993
  connects
517
994
  });
518
995
  }
519
- const parts = /* @__PURE__ */ new Map();
520
- let total = 0;
521
- const limit = options.maxPartBytes ?? DEFAULT_MAX_PART_BYTES;
522
- for (const path of Object.keys(zip.files)) {
523
- const file = zip.files[path];
524
- if (file.dir || derived.has(path) || isLocalOnlyPart(path)) continue;
525
- let data = await file.async("uint8array");
526
- if (path === CONTENT_TYPES) data = encoder.encode(stripPageOverrides(decoder.decode(data)));
527
- total += data.length;
528
- if (total > limit) throw new Error("The package parts exceed the shared size limit.");
529
- parts.set(path, data);
530
- }
996
+ const { masters, mastersOpen, mastersClose } = await snapshotMasters(zip, layout, keys, derived);
997
+ const { parts, media } = await snapshotRest(
998
+ zip,
999
+ derived,
1000
+ options.maxPartBytes ?? DEFAULT_MAX_PART_BYTES
1001
+ );
531
1002
  return {
532
1003
  pagesPath: layout.pagesPath,
533
1004
  pagesOpen: pagesXml.slice(0, local.box.openEnd),
534
1005
  pagesClose: pagesXml.slice(local.box.closeStart),
535
1006
  pages,
1007
+ ...mastersOpen !== void 0 && mastersClose !== void 0 && layout.mastersPath ? { mastersPath: layout.mastersPath, mastersOpen, mastersClose } : {},
1008
+ masters,
1009
+ media,
536
1010
  parts
537
1011
  };
538
1012
  }
539
1013
 
540
- // visio/collab/order.ts
541
- function assignPositions(order, current) {
542
- const result = /* @__PURE__ */ new Map();
543
- const kept = [];
544
- let last = -Infinity;
545
- for (const key of order) {
546
- const pos = current(key);
547
- if (pos !== void 0 && pos > last) {
548
- kept.push(pos);
549
- last = pos;
550
- } else kept.push(void 0);
551
- }
552
- let i = 0;
553
- while (i < order.length) {
554
- const known = kept[i];
555
- if (known !== void 0) {
556
- result.set(order[i], known);
557
- i++;
558
- continue;
559
- }
560
- let end = i;
561
- while (end < order.length && kept[end] === void 0) end++;
562
- const lo = i > 0 ? kept[i - 1] : void 0;
563
- const hi = end < order.length ? kept[end] : void 0;
564
- const count = end - i;
565
- for (let j = 0; j < count; j++) {
566
- const key = order[i + j];
567
- if (lo !== void 0 && hi !== void 0)
568
- result.set(key, lo + (hi - lo) * (j + 1) / (count + 1));
569
- else if (lo !== void 0) result.set(key, lo + j + 1);
570
- else if (hi !== void 0) result.set(key, hi - count + j);
571
- else result.set(key, j + 1);
1014
+ // visio/collab/compose-lists.ts
1015
+ var relTarget = (dir, path) => dir && path.startsWith(`${dir}/`) ? path.slice(dir.length + 1) : `/${path}`;
1016
+ async function placeList(options) {
1017
+ const { files, taken, localZip, items } = options;
1018
+ const dir = dirName(options.listPath);
1019
+ taken.add(options.listPath).add(relsPathOf(options.listPath));
1020
+ const paths = /* @__PURE__ */ new Map();
1021
+ for (const item of items) {
1022
+ const known = options.known.get(item.key);
1023
+ if (known && !taken.has(known) && localZip?.file(known)) {
1024
+ paths.set(item.key, known);
1025
+ taken.add(known);
572
1026
  }
573
- i = end;
574
1027
  }
575
- return result;
1028
+ let counter = 0;
1029
+ for (const item of items) {
1030
+ if (paths.has(item.key)) continue;
1031
+ let path;
1032
+ do
1033
+ path = `${dir ? `${dir}/` : ""}${options.stem}${++counter}.xml`;
1034
+ while (taken.has(path) || localZip?.file(path));
1035
+ paths.set(item.key, path);
1036
+ taken.add(path);
1037
+ }
1038
+ const others = parseRelationships(
1039
+ localZip ? await zipText(localZip, relsPathOf(options.listPath)) : void 0
1040
+ ).filter((r) => r.type !== options.relType);
1041
+ const usedIds = new Set(others.map((r) => r.id));
1042
+ let nextRel = 0;
1043
+ const rels = [];
1044
+ const elements = [];
1045
+ for (const item of items) {
1046
+ const path = paths.get(item.key);
1047
+ let id;
1048
+ do
1049
+ id = `rId${++nextRel}`;
1050
+ while (usedIds.has(id));
1051
+ usedIds.add(id);
1052
+ rels.push(
1053
+ `<Relationship Id="${id}" Type="${options.relType}" Target="${escapeAttr(relTarget(dir, path))}"/>`
1054
+ );
1055
+ const rel = `<Rel xmlns:r="${REL_NS}" r:id="${id}"/>`;
1056
+ elements.push(
1057
+ item.xml.includes(REL_MARK) ? item.xml.replace(REL_MARK, () => rel) : item.xml.slice(0, item.xml.lastIndexOf("</")) + rel + item.xml.slice(item.xml.lastIndexOf("</"))
1058
+ );
1059
+ files.set(path, item.part);
1060
+ if (item.rels !== void 0) files.set(relsPathOf(path), encoder.encode(item.rels));
1061
+ }
1062
+ files.set(options.listPath, encoder.encode(options.open + elements.join("") + options.close));
1063
+ files.set(
1064
+ relsPathOf(options.listPath),
1065
+ encoder.encode(
1066
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + others.map((r) => r.text).join("") + rels.join("") + "</Relationships>"
1067
+ )
1068
+ );
1069
+ return paths;
576
1070
  }
577
- function byPosition(items) {
578
- return items.sort((a, b) => a.pos - b.pos || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
1071
+ new TextDecoder("utf-8", { fatal: true });
1072
+ var crcTable = Uint32Array.from({ length: 256 }, (_, value) => {
1073
+ for (let i = 0; i < 8; i++) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
1074
+ return value >>> 0;
1075
+ });
1076
+ function crc32(bytes, crc = 4294967295) {
1077
+ for (const byte of bytes) crc = (crcTable[(crc ^ byte) & 255] ?? 0) ^ crc >>> 8;
1078
+ return crc >>> 0;
579
1079
  }
580
1080
 
581
- // visio/collab/write.ts
582
- var pageId = (key) => `p:${key}`;
583
- var bodyId = (key) => `b:${key}`;
584
- var shapeId = (page, key) => `s:${page}/${key}`;
585
- var connectId = (key) => `c:${key}`;
586
- var pageContent = (e) => JSON.stringify([e.id, e.back ?? null, canon(e.xml)]);
587
- var bodyContent = (e) => JSON.stringify([canon(e.shell), e.rels ?? null]);
588
- function writeSharedDrawing(shared, snapshot, keys) {
589
- let writes = 0;
590
- const set = (map, key, value) => {
591
- if (setIfChanged(map, key, value)) writes++;
592
- };
593
- set(shared.meta, "v", SCHEMA_VERSION);
594
- set(shared.meta, "pagesPath", snapshot.pagesPath);
595
- set(shared.meta, "pagesOpen", snapshot.pagesOpen);
596
- set(shared.meta, "pagesClose", snapshot.pagesClose);
597
- const now = /* @__PURE__ */ new Map();
598
- const changed = (id, content, room) => {
599
- const base = keys.known.get(id);
600
- return base === void 0 ? room !== content : base !== content;
601
- };
602
- const pagePos = assignPositions(
603
- snapshot.pages.map((p) => p.key),
604
- (key) => pageEntry(shared.pages.get(key))?.pos
605
- );
606
- for (const page of snapshot.pages) {
607
- const room = pageEntry(shared.pages.get(page.key));
608
- const content = pageContent(page);
609
- now.set(pageId(page.key), content);
610
- const own = changed(pageId(page.key), content, room && pageContent(room));
611
- const source = own || !room ? page : room;
612
- set(shared.pages, page.key, {
613
- pos: pagePos.get(page.key),
614
- id: source.id,
615
- ...source.back !== void 0 ? { back: source.back } : {},
616
- xml: source.xml
617
- });
618
- const roomBody = bodyEntry(shared.bodies.get(page.key));
619
- const bodyText = bodyContent(page);
620
- now.set(bodyId(page.key), bodyText);
621
- const ownBody = changed(bodyId(page.key), bodyText, roomBody && bodyContent(roomBody));
622
- const body = ownBody || !roomBody ? page : roomBody;
623
- set(shared.bodies, page.key, {
624
- shell: body.shell,
625
- ...body.rels !== void 0 ? { rels: body.rels } : {}
626
- });
627
- const shapePos = assignPositions(
628
- page.shapes.map((s) => s.key),
629
- (key) => shapeEntry(shared.shapes.get(`${page.key}/${key}`))?.pos
630
- );
631
- for (const shape of page.shapes) {
632
- const id = shapeId(page.key, shape.key);
633
- const roomShape = shapeEntry(shared.shapes.get(`${page.key}/${shape.key}`));
634
- const text = canon(shape.xml);
635
- now.set(id, text);
636
- const xml = changed(id, text, roomShape && canon(roomShape.xml)) || !roomShape ? shape.xml : roomShape.xml;
637
- set(shared.shapes, `${page.key}/${shape.key}`, { pos: shapePos.get(shape.key), xml });
638
- }
639
- for (const connect of page.connects) {
640
- now.set(connectId(connect.key), "");
641
- if (!keys.known.has(connectId(connect.key)) || !shared.connects.has(connect.key))
642
- set(shared.connects, connect.key, connect.entry);
1081
+ // visio/collab/zip-store.ts
1082
+ var encoder2 = new TextEncoder();
1083
+ var DOS_TIME = 0;
1084
+ var DOS_DATE = 33;
1085
+ function writeStoredZip(files, crcs) {
1086
+ const prepared = files.map(([name, data]) => {
1087
+ let crc = crcs.get(data);
1088
+ if (crc === void 0) {
1089
+ crc = (crc32(data) ^ 4294967295) >>> 0;
1090
+ crcs.set(data, crc);
643
1091
  }
1092
+ return { name: encoder2.encode(name), data, crc };
1093
+ });
1094
+ let local = 0;
1095
+ let central = 0;
1096
+ for (const f of prepared) {
1097
+ local += 30 + f.name.length + f.data.length;
1098
+ central += 46 + f.name.length;
644
1099
  }
645
- for (const id of keys.known.keys()) {
646
- if (now.has(id)) continue;
647
- const name = id.slice(2);
648
- if (id.startsWith("p:")) {
649
- shared.dead.set(name, true);
650
- for (const map of [shared.pages, shared.bodies]) map.delete(name);
651
- for (const map of [shared.shapes, shared.connects])
652
- for (const key of [...map.keys()]) if (key.startsWith(`${name}/`)) map.delete(key);
653
- keys.forgetPage(name);
654
- writes++;
655
- } else if (id.startsWith("s:")) {
656
- const slash = name.indexOf("/");
657
- const page = name.slice(0, slash);
658
- if (!now.has(pageId(page))) continue;
659
- shared.dead.set(name, true);
660
- shared.shapes.delete(name);
661
- keys.forgetShape(page, name.slice(slash + 1));
662
- writes++;
663
- } else if (id.startsWith("c:") && shared.connects.has(name)) {
664
- shared.connects.delete(name);
665
- writes++;
666
- }
1100
+ const out = new Uint8Array(local + central + 22);
1101
+ const view = new DataView(out.buffer);
1102
+ let at = 0;
1103
+ const offsets = [];
1104
+ for (const f of prepared) {
1105
+ offsets.push(at);
1106
+ view.setUint32(at, 67324752, true);
1107
+ view.setUint16(at + 4, 20, true);
1108
+ view.setUint16(at + 6, 2048, true);
1109
+ view.setUint16(at + 8, 0, true);
1110
+ view.setUint16(at + 10, DOS_TIME, true);
1111
+ view.setUint16(at + 12, DOS_DATE, true);
1112
+ view.setUint32(at + 14, f.crc, true);
1113
+ view.setUint32(at + 18, f.data.length, true);
1114
+ view.setUint32(at + 22, f.data.length, true);
1115
+ view.setUint16(at + 26, f.name.length, true);
1116
+ view.setUint16(at + 28, 0, true);
1117
+ out.set(f.name, at + 30);
1118
+ out.set(f.data, at + 30 + f.name.length);
1119
+ at += 30 + f.name.length + f.data.length;
667
1120
  }
668
- keys.known = now;
669
- for (const [path, data] of snapshot.parts) {
670
- const print = fingerprint(data);
671
- if (keys.partPrints.get(path) === print) continue;
672
- set(shared.parts, path, toBase64(data));
673
- keys.partPrints.set(path, print);
674
- }
675
- for (const path of [...keys.partPrints.keys()])
676
- if (!snapshot.parts.has(path)) {
677
- shared.parts.delete(path);
678
- keys.partPrints.delete(path);
679
- writes++;
680
- }
681
- return writes;
1121
+ const centralStart = at;
1122
+ prepared.forEach((f, i) => {
1123
+ view.setUint32(at, 33639248, true);
1124
+ view.setUint16(at + 4, 20, true);
1125
+ view.setUint16(at + 6, 20, true);
1126
+ view.setUint16(at + 8, 2048, true);
1127
+ view.setUint16(at + 10, 0, true);
1128
+ view.setUint16(at + 12, DOS_TIME, true);
1129
+ view.setUint16(at + 14, DOS_DATE, true);
1130
+ view.setUint32(at + 16, f.crc, true);
1131
+ view.setUint32(at + 20, f.data.length, true);
1132
+ view.setUint32(at + 24, f.data.length, true);
1133
+ view.setUint16(at + 28, f.name.length, true);
1134
+ view.setUint32(at + 42, offsets[i], true);
1135
+ out.set(f.name, at + 46);
1136
+ at += 46 + f.name.length;
1137
+ });
1138
+ view.setUint32(at, 101010256, true);
1139
+ view.setUint16(at + 8, prepared.length, true);
1140
+ view.setUint16(at + 10, prepared.length, true);
1141
+ view.setUint32(at + 12, at - centralStart, true);
1142
+ view.setUint32(at + 16, centralStart, true);
1143
+ return out;
682
1144
  }
683
1145
 
684
1146
  // visio/collab/compose.ts
@@ -694,32 +1156,51 @@ function connectXml(item) {
694
1156
  ];
695
1157
  return `<Connect ${attrs.filter(([, v]) => v !== "").map(([k, v]) => `${k}="${escapeAttr(v)}"`).join(" ")}/>`;
696
1158
  }
697
- function pagePartXml(page) {
698
- let shell = page.body.shell;
699
- const root = scanContainer(shell, "PageContents");
700
- if (page.shapes.length && !shell.includes(SHAPES_MARK) && root && !root.selfClosing)
701
- shell = shell.slice(0, root.openEnd) + `<Shapes>${SHAPES_MARK}</Shapes>` + shell.slice(root.openEnd);
702
- const root2 = scanContainer(shell, "PageContents");
703
- if (page.connects.length && !shell.includes(CONNECTS_MARK) && root2 && !root2.selfClosing)
704
- shell = shell.slice(0, root2.closeStart) + `<Connects>${CONNECTS_MARK}</Connects>` + shell.slice(root2.closeStart);
705
- return shell.replace(SHAPES_MARK, () => page.shapes.map((s) => s.xml).join("")).replace(CONNECTS_MARK, () => page.connects.map(connectXml).join(""));
706
- }
707
- function relTarget(pagesDir, path) {
708
- return pagesDir && path.startsWith(`${pagesDir}/`) ? path.slice(pagesDir.length + 1) : `/${path}`;
1159
+ function contentsXml(shell, root, shapesXml, hasShapes, connects) {
1160
+ const outer = scanContainer(shell, root);
1161
+ if (hasShapes && !shell.includes(SHAPES_MARK) && outer && !outer.selfClosing)
1162
+ shell = shell.slice(0, outer.openEnd) + `<Shapes>${SHAPES_MARK}</Shapes>` + shell.slice(outer.openEnd);
1163
+ const outer2 = scanContainer(shell, root);
1164
+ if (connects.length && !shell.includes(CONNECTS_MARK) && outer2 && !outer2.selfClosing)
1165
+ shell = shell.slice(0, outer2.closeStart) + `<Connects>${CONNECTS_MARK}</Connects>` + shell.slice(outer2.closeStart);
1166
+ return shell.replace(SHAPES_MARK, () => shapesXml).replace(CONNECTS_MARK, () => connects.map(connectXml).join(""));
709
1167
  }
1168
+ var pagePartXml = (page) => contentsXml(
1169
+ page.body.shell,
1170
+ "PageContents",
1171
+ page.shapesXml,
1172
+ page.shapes.length > 0,
1173
+ page.connects
1174
+ );
1175
+ var masterPartXml = (master) => contentsXml(
1176
+ decoder.decode(fromBase64(master.part)),
1177
+ "MasterContents",
1178
+ master.shapesXml,
1179
+ master.shapes.length > 0,
1180
+ master.connects
1181
+ );
710
1182
  async function composeDrawing(drawing, local, keys, options = {}) {
711
1183
  const localZip = local ? await readZip(local) : void 0;
712
1184
  const files = /* @__PURE__ */ new Map();
713
1185
  const prints = /* @__PURE__ */ new Map();
714
1186
  let total = 0;
715
1187
  const limit = options.maxPartBytes ?? 48 * 1024 * 1024;
716
- for (const [path, b64] of drawing.parts) {
717
- const data = fromBase64(b64);
1188
+ const cache = keys.cache.parts;
1189
+ const decode = (path, b64) => {
1190
+ const hit = cache.get(path);
1191
+ const data = hit && hit.b64 === b64 ? hit.data : fromBase64(b64);
1192
+ if (!hit || hit.b64 !== b64) cache.set(path, { b64, data });
718
1193
  total += data.length;
719
1194
  if (total > limit) throw new Error("The shared parts exceed the size limit.");
1195
+ return data;
1196
+ };
1197
+ for (const [path, b64] of drawing.parts) {
1198
+ const data = decode(path, b64);
720
1199
  files.set(path, data);
721
1200
  prints.set(path, fingerprint(data));
722
1201
  }
1202
+ for (const path of [...cache.keys()])
1203
+ if (!drawing.parts.has(path) && !path.startsWith("media:")) cache.delete(path);
723
1204
  if (localZip)
724
1205
  for (const path of Object.keys(localZip.files)) {
725
1206
  const file = localZip.files[path];
@@ -727,6 +1208,10 @@ async function composeDrawing(drawing, local, keys, options = {}) {
727
1208
  files.set(path, await file.async("uint8array"));
728
1209
  }
729
1210
  let contentTypes = files.get(CONTENT_TYPES) !== void 0 ? decoder.decode(files.get(CONTENT_TYPES)) : (localZip && await zipText(localZip, CONTENT_TYPES)) ?? DEFAULT_CONTENT_TYPES;
1211
+ for (const item of drawing.media) {
1212
+ files.set(item.path, decode(`media:${item.path}`, item.data));
1213
+ contentTypes = ensureType(contentTypes, item.path, item.declared);
1214
+ }
730
1215
  for (const [path, data] of [...files]) {
731
1216
  if (!path.endsWith(".rels") || typeof data === "string") continue;
732
1217
  const source = path.replace(/(^|\/)_rels\/([^/]+)\.rels$/, "$1$2");
@@ -745,91 +1230,119 @@ async function composeDrawing(drawing, local, keys, options = {}) {
745
1230
  });
746
1231
  if (next !== text) files.set(path, encoder.encode(next));
747
1232
  }
748
- const pagesDir = dirName(drawing.pagesPath);
749
- const taken = /* @__PURE__ */ new Set([
750
- ...files.keys(),
751
- drawing.pagesPath,
752
- relsPathOf(drawing.pagesPath)
753
- ]);
754
- const paths = /* @__PURE__ */ new Map();
755
- for (const page of drawing.pages) {
756
- const known = keys.pagePaths.get(page.key);
757
- if (known && !taken.has(known) && localZip?.file(known)) {
758
- paths.set(page.key, known);
759
- taken.add(known);
760
- }
761
- }
762
- let counter = 0;
763
- for (const page of drawing.pages) {
764
- if (paths.has(page.key)) continue;
765
- let path;
766
- do
767
- path = `${pagesDir ? `${pagesDir}/` : ""}page${++counter}.xml`;
768
- while (taken.has(path) || localZip?.file(path));
769
- paths.set(page.key, path);
770
- taken.add(path);
771
- }
772
- const others = parseRelationships(
773
- localZip ? await zipText(localZip, relsPathOf(drawing.pagesPath)) : void 0
774
- ).filter((r) => r.type !== PAGE_TYPE);
775
- const usedIds = new Set(others.map((r) => r.id));
776
- let nextRel = 0;
777
- const pageRels = [];
778
- const pageXml = [];
779
- for (const page of drawing.pages) {
780
- const path = paths.get(page.key);
781
- let id;
782
- do
783
- id = `rId${++nextRel}`;
784
- while (usedIds.has(id));
785
- usedIds.add(id);
786
- pageRels.push(
787
- `<Relationship Id="${id}" Type="${PAGE_TYPE}" Target="${escapeAttr(relTarget(pagesDir, path))}"/>`
788
- );
789
- const rel = `<Rel xmlns:r="${REL_NS}" r:id="${id}"/>`;
790
- pageXml.push(
791
- page.xml.includes(REL_MARK) ? page.xml.replace(REL_MARK, () => rel) : page.xml.slice(0, page.xml.lastIndexOf("</")) + rel + page.xml.slice(page.xml.lastIndexOf("</"))
792
- );
793
- files.set(path, encoder.encode(pagePartXml(page)));
794
- if (page.body.rels !== void 0) files.set(relsPathOf(path), encoder.encode(page.body.rels));
1233
+ const taken = new Set(files.keys());
1234
+ const pageCache = keys.cache.pageParts;
1235
+ const pageItems = drawing.pages.map((page) => {
1236
+ const hit = pageCache.get(page.key);
1237
+ const bytes2 = hit && hit.sig === page.signature ? hit.bytes : encoder.encode(pagePartXml(page));
1238
+ pageCache.set(page.key, { sig: page.signature, bytes: bytes2 });
1239
+ return {
1240
+ key: page.key,
1241
+ xml: page.xml,
1242
+ part: bytes2,
1243
+ ...page.body.rels !== void 0 ? { rels: page.body.rels } : {}
1244
+ };
1245
+ });
1246
+ for (const key of [...pageCache.keys()])
1247
+ if (!drawing.pages.some((p) => p.key === key)) pageCache.delete(key);
1248
+ const pagePaths = await placeList({
1249
+ listPath: drawing.pagesPath,
1250
+ open: drawing.pagesOpen,
1251
+ close: drawing.pagesClose,
1252
+ relType: PAGE_TYPE,
1253
+ stem: "page",
1254
+ items: pageItems,
1255
+ known: keys.pagePaths,
1256
+ files,
1257
+ taken,
1258
+ localZip
1259
+ });
1260
+ contentTypes = withPageOverrides(contentTypes, [...pagePaths.values()]);
1261
+ let masterPaths = /* @__PURE__ */ new Map();
1262
+ if (drawing.mastersPath !== void 0) {
1263
+ masterPaths = await placeList({
1264
+ listPath: drawing.mastersPath,
1265
+ open: drawing.mastersOpen ?? "<Masters>",
1266
+ close: drawing.mastersClose ?? "</Masters>",
1267
+ relType: MASTER_TYPE,
1268
+ stem: "master",
1269
+ items: drawing.masters.map((m) => ({
1270
+ key: m.key,
1271
+ xml: m.xml,
1272
+ part: encoder.encode(masterPartXml(m)),
1273
+ ...m.rels !== void 0 ? { rels: m.rels } : {}
1274
+ })),
1275
+ known: keys.masterPaths,
1276
+ files,
1277
+ taken,
1278
+ localZip
1279
+ });
1280
+ contentTypes = withOverrides(contentTypes, MASTER_CONTENT_TYPE, [...masterPaths.values()]);
795
1281
  }
796
- files.set(
797
- drawing.pagesPath,
798
- encoder.encode(drawing.pagesOpen + pageXml.join("") + drawing.pagesClose)
799
- );
800
- files.set(
801
- relsPathOf(drawing.pagesPath),
802
- encoder.encode(
803
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + others.map((r) => r.text).join("") + pageRels.join("") + "</Relationships>"
804
- )
805
- );
806
- files.set(CONTENT_TYPES, encoder.encode(withPageOverrides(contentTypes, [...paths.values()])));
807
- const zip = new JSZip__default.default();
1282
+ files.set(CONTENT_TYPES, encoder.encode(contentTypes));
808
1283
  const names = [...files.keys()].sort(
809
1284
  (a, b) => a === CONTENT_TYPES ? -1 : b === CONTENT_TYPES ? 1 : 0
810
1285
  );
811
- for (const name of names) zip.file(name, files.get(name), { createFolders: false });
812
- const bytes = await zip.generateAsync({ type: "uint8array", compression: "STORE" });
1286
+ const bytes = writeStoredZip(
1287
+ names.map((name) => {
1288
+ const data = files.get(name);
1289
+ return [name, typeof data === "string" ? encoder.encode(data) : data];
1290
+ }),
1291
+ keys.cache.crcs
1292
+ );
813
1293
  const commit = () => {
814
1294
  const pageIds = /* @__PURE__ */ new Map();
815
- const shapeIds2 = /* @__PURE__ */ new Map();
1295
+ const shapeIds = /* @__PURE__ */ new Map();
1296
+ const masterIds = /* @__PURE__ */ new Map();
816
1297
  const known = /* @__PURE__ */ new Map();
1298
+ const recordShapes = (scope, shapes, connects) => {
1299
+ shapeIds.set(scope, new Map(shapes.map((s) => [s.id, s.key])));
1300
+ for (const shape of shapes) {
1301
+ known.set(shapeId(scope, shape.key), shellContent(shape));
1302
+ for (const [path, entry] of shape.entries)
1303
+ known.set(cellId(scope, shape.key, path), entryContent(entry));
1304
+ }
1305
+ for (const connect of connects) known.set(connectId(connect.key), "");
1306
+ };
817
1307
  keys.pagePaths.clear();
1308
+ keys.masterPaths.clear();
1309
+ keys.mediaKeys.clear();
818
1310
  for (const page of drawing.pages) {
819
1311
  pageIds.set(page.id, page.key);
820
- keys.pagePaths.set(page.key, paths.get(page.key));
1312
+ keys.pagePaths.set(page.key, pagePaths.get(page.key));
821
1313
  known.set(pageId(page.key), pageContent(page));
822
1314
  known.set(bodyId(page.key), bodyContent(page.body));
823
- shapeIds2.set(page.key, new Map(page.shapes.map((s) => [s.id, s.key])));
824
- for (const shape of page.shapes) known.set(shapeId(page.key, shape.key), canon(shape.xml));
825
- for (const connect of page.connects) known.set(connectId(connect.key), "");
1315
+ recordShapes(page.key, page.shapes, page.connects);
1316
+ }
1317
+ for (const master of drawing.masters) {
1318
+ masterIds.set(master.id, master.key);
1319
+ recordShapes(masterScope(master.key), master.shapes, master.connects);
1320
+ const path = masterPaths.get(master.key);
1321
+ if (path) keys.masterPaths.set(master.key, path);
1322
+ known.set(
1323
+ masterId(master.key),
1324
+ masterContent({ ...master, print: fingerprint(fromBase64(master.part)) })
1325
+ );
826
1326
  }
827
- keys.reset(pageIds, shapeIds2);
1327
+ for (const item of drawing.media) {
1328
+ known.set(mediaId(item.key), "");
1329
+ keys.mediaKeys.set(item.path, item.key);
1330
+ }
1331
+ keys.reset(pageIds, shapeIds, masterIds);
828
1332
  keys.known = known;
829
1333
  keys.partPrints.clear();
830
1334
  for (const [path, print] of prints) keys.partPrints.set(path, print);
831
1335
  };
832
- return { bytes, commit };
1336
+ return { bytes, signature: drawing.signature, commit };
1337
+ }
1338
+
1339
+ // visio/collab/fixups.ts
1340
+ function applyFixups(shared, fixups) {
1341
+ let changed = 0;
1342
+ for (const fixup of fixups) {
1343
+ if (setIfChanged(shared.renum, fixup.key, fixup.value)) changed++;
1344
+ }
1345
+ return changed;
833
1346
  }
834
1347
 
835
1348
  // visio/collab/keys.ts
@@ -843,15 +1356,36 @@ var DrawingKeys = class {
843
1356
  seeding = false;
844
1357
  #pages = /* @__PURE__ */ new Map();
845
1358
  #shapes = /* @__PURE__ */ new Map();
1359
+ #masters = /* @__PURE__ */ new Map();
846
1360
  /** Content of each entry this peer last wrote or applied, to tell a local edit or deletion from a change it has not applied yet. */
847
1361
  known = /* @__PURE__ */ new Map();
848
1362
  /** Fingerprints of the parts this peer last wrote or applied. */
849
1363
  partPrints = /* @__PURE__ */ new Map();
850
1364
  /** The part path of each page key in the local package. */
851
1365
  pagePaths = /* @__PURE__ */ new Map();
1366
+ /** The part path of each master key in the local package. */
1367
+ masterPaths = /* @__PURE__ */ new Map();
1368
+ /** The room key of each media path in the local package. */
1369
+ mediaKeys = /* @__PURE__ */ new Map();
1370
+ /** Serialised page parts and decoded shared parts of the last rebuild, to skip unchanged work. */
1371
+ cache = {
1372
+ pageParts: /* @__PURE__ */ new Map(),
1373
+ parts: /* @__PURE__ */ new Map(),
1374
+ /** CRC-32 of the bytes of each stored part, by identity (see zip-store.ts). */
1375
+ crcs: /* @__PURE__ */ new WeakMap()
1376
+ };
1377
+ /**
1378
+ * What was last applied to the editor: the drawing signature, the editor version it produced,
1379
+ * the signature of everything but page content and the content signature of each page.
1380
+ */
1381
+ applied;
852
1382
  mint() {
853
1383
  return `${this.tag}.${(++this.#counter).toString(36)}`;
854
1384
  }
1385
+ /** A fresh id for one write batch: entries written together share it. */
1386
+ batch() {
1387
+ return this.mint();
1388
+ }
855
1389
  pageKey(id) {
856
1390
  let key = this.#pages.get(id);
857
1391
  if (key === void 0) {
@@ -870,6 +1404,14 @@ var DrawingKeys = class {
870
1404
  }
871
1405
  return key;
872
1406
  }
1407
+ masterKey(id) {
1408
+ let key = this.#masters.get(id);
1409
+ if (key === void 0) {
1410
+ key = this.seeding ? `s${id}` : this.mint();
1411
+ this.#masters.set(id, key);
1412
+ }
1413
+ return key;
1414
+ }
873
1415
  findPage(id) {
874
1416
  return this.#pages.get(id);
875
1417
  }
@@ -883,38 +1425,352 @@ var DrawingKeys = class {
883
1425
  for (const [id, k] of map) if (k === key) map.delete(id);
884
1426
  }
885
1427
  }
1428
+ forgetMaster(key) {
1429
+ for (const [id, k] of this.#masters) if (k === key) this.#masters.delete(id);
1430
+ this.#shapes.delete(masterScope(key));
1431
+ this.masterPaths.delete(key);
1432
+ }
886
1433
  /** Replaces the id-to-key tables with those of a freshly composed package. */
887
- reset(pages, shapes) {
1434
+ reset(pages, shapes, masters = /* @__PURE__ */ new Map()) {
888
1435
  this.#pages.clear();
889
1436
  this.#shapes.clear();
1437
+ this.#masters.clear();
890
1438
  for (const [id, key] of pages) this.#pages.set(id, key);
891
1439
  for (const [page, map] of shapes) this.#shapes.set(page, new Map(map));
1440
+ for (const [id, key] of masters) this.#masters.set(id, key);
892
1441
  }
893
1442
  };
894
1443
 
895
- // visio/collab/read.ts
1444
+ // visio/collab/order.ts
1445
+ function assignPositions(order, current) {
1446
+ const result = /* @__PURE__ */ new Map();
1447
+ const kept = [];
1448
+ let last = -Infinity;
1449
+ for (const key of order) {
1450
+ const pos = current(key);
1451
+ if (pos !== void 0 && pos > last) {
1452
+ kept.push(pos);
1453
+ last = pos;
1454
+ } else kept.push(void 0);
1455
+ }
1456
+ let i = 0;
1457
+ while (i < order.length) {
1458
+ const known = kept[i];
1459
+ if (known !== void 0) {
1460
+ result.set(order[i], known);
1461
+ i++;
1462
+ continue;
1463
+ }
1464
+ let end = i;
1465
+ while (end < order.length && kept[end] === void 0) end++;
1466
+ const lo = i > 0 ? kept[i - 1] : void 0;
1467
+ const hi = end < order.length ? kept[end] : void 0;
1468
+ const count = end - i;
1469
+ for (let j = 0; j < count; j++) {
1470
+ const key = order[i + j];
1471
+ if (lo !== void 0 && hi !== void 0)
1472
+ result.set(key, lo + (hi - lo) * (j + 1) / (count + 1));
1473
+ else if (lo !== void 0) result.set(key, lo + j + 1);
1474
+ else if (hi !== void 0) result.set(key, hi - count + j);
1475
+ else result.set(key, j + 1);
1476
+ }
1477
+ i = end;
1478
+ }
1479
+ return result;
1480
+ }
1481
+ function byPosition(items) {
1482
+ return items.sort((a, b) => a.pos - b.pos || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
1483
+ }
1484
+
1485
+ // visio/collab/read-ids.ts
896
1486
  var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
897
1487
  var numeric = (id) => /^\d+$/.test(id) ? Number(id) : 0;
1488
+ function assignIds(items) {
1489
+ const effective = (item) => item.fixed ?? item.id;
1490
+ let max = Math.max(0, ...items.map((item) => numeric(effective(item))));
1491
+ const order = [...items].sort(
1492
+ (a, b) => Number(b.fixed !== void 0) - Number(a.fixed !== void 0) || compare(a.key, b.key)
1493
+ );
1494
+ const ids = /* @__PURE__ */ new Map();
1495
+ const fresh = /* @__PURE__ */ new Map();
1496
+ const holder = /* @__PURE__ */ new Map();
1497
+ const claims = /* @__PURE__ */ new Set();
1498
+ for (const item of order) {
1499
+ let id = effective(item);
1500
+ const taken = holder.get(id);
1501
+ if (taken) {
1502
+ if (taken.fixed === void 0) claims.add(taken.key);
1503
+ id = String(++max);
1504
+ fresh.set(item.key, { from: item.id, to: id });
1505
+ }
1506
+ holder.set(id, item);
1507
+ ids.set(item.key, id);
1508
+ }
1509
+ return { ids, fresh, claims };
1510
+ }
1511
+ var fixedId = (renum, key, id) => {
1512
+ const pair = renum.get(key)?.i;
1513
+ return pair && pair[0] === id ? pair[1] : void 0;
1514
+ };
1515
+ function readRenum(shared) {
1516
+ const out = /* @__PURE__ */ new Map();
1517
+ for (const [key, value] of shared.renum) {
1518
+ const entry = renumEntry(value);
1519
+ if (entry) out.set(key, entry);
1520
+ }
1521
+ return out;
1522
+ }
1523
+ function renumRecord(renum, recordKey, item, change, claimed) {
1524
+ if (change) return { ...renum.get(recordKey), i: [change.from, change.to] };
1525
+ if (claimed) return { ...renum.get(recordKey), i: [item.id, item.id] };
1526
+ return void 0;
1527
+ }
1528
+
1529
+ // visio/collab/read-util.ts
1530
+ function hashTexts(texts) {
1531
+ let a = 2166136261;
1532
+ let b = 16777619 ^ 2654435769;
1533
+ for (const text of texts) {
1534
+ for (let i = 0; i < text.length; i++) {
1535
+ const c = text.charCodeAt(i);
1536
+ a = Math.imul(a ^ c, 16777619);
1537
+ b = Math.imul(b + c, 2246822507) ^ b >>> 13;
1538
+ }
1539
+ a = Math.imul(a ^ 255, 16777619);
1540
+ b = Math.imul(b ^ 255, 3266489909);
1541
+ }
1542
+ return `${(a >>> 0).toString(16)}${(b >>> 0).toString(16)}`;
1543
+ }
1544
+ var split = (key, depth) => {
1545
+ const out = [];
1546
+ let from = 0;
1547
+ for (let i = 0; i < depth; i++) {
1548
+ const slash = key.indexOf("/", from);
1549
+ if (slash < 0) return void 0;
1550
+ out.push(key.slice(from, slash));
1551
+ from = slash + 1;
1552
+ }
1553
+ out.push(key.slice(from));
1554
+ return out;
1555
+ };
1556
+ var connectSignature = (connects) => connects.flatMap((c) => [c.from, c.to, c.entry.fc, c.entry.tc, c.entry.fp, c.entry.tp]);
1557
+ function resolveConnects(list, shapes) {
1558
+ const byKey = new Map(shapes.map((s) => [s.key, s]));
1559
+ const out = [];
1560
+ for (const item of [...list ?? []].sort((a, b) => compare(a.key, b.key))) {
1561
+ const { entry } = item;
1562
+ const from = entry.fk ? byKey.get(entry.fk) : void 0;
1563
+ const to = entry.tk ? byKey.get(entry.tk) : void 0;
1564
+ if (entry.fk && !from || entry.tk && !to) continue;
1565
+ out.push({ key: item.key, entry, from: from?.id ?? entry.fi, to: to?.id ?? entry.ti });
1566
+ }
1567
+ return out;
1568
+ }
1569
+
1570
+ // visio/collab/read-shapes.ts
898
1571
  function setAttr(open, name, value) {
899
1572
  return open.replace(
900
1573
  new RegExp(String.raw`(\s${name}\s*=\s*)(?:"[^"]*"|'[^']*')`),
901
1574
  (_m, head) => `${head}"${value}"`
902
1575
  );
903
1576
  }
904
- function renumberShape(xml, remap) {
905
- if (!remap.size) return xml;
906
- return xml.replace(
907
- /<(?:\w+:)?Shape\s[^>]*>/g,
908
- (tag) => tag.replace(/(\bID\s*=\s*)(["'])(\d+)\2/, (m, head, q, id) => {
1577
+ function renumberFormulas(xml, remap) {
1578
+ if (!remap.size || !xml.includes("Sheet.")) return xml;
1579
+ return xml.replace(/(\sF\s*=\s*)("[^"]*"|'[^']*')/g, (_m, head, value) => {
1580
+ const body = value.slice(1, -1).replace(/Sheet\.(\d+)(?!\d)/g, (m, id) => {
909
1581
  const next = remap.get(id);
910
- return next === void 0 ? m : `${head}${q}${next}${q}`;
1582
+ return next === void 0 ? m : `Sheet.${next}`;
1583
+ });
1584
+ return `${head}${value[0]}${body}${value[0]}`;
1585
+ });
1586
+ }
1587
+ function referenced(r, finalId) {
1588
+ const out = /* @__PURE__ */ new Map();
1589
+ for (let i = 0; i + 1 < r.length; i += 2) {
1590
+ const next = finalId.get(r[i + 1]);
1591
+ if (next !== void 0) out.set(r[i], next);
1592
+ }
1593
+ return out;
1594
+ }
1595
+ function resolveShapes(input) {
1596
+ const raw = /* @__PURE__ */ new Map();
1597
+ for (const [key, entry] of input.shapes) {
1598
+ const id = attrOf(entry.open, "ID");
1599
+ if (id !== void 0) raw.set(key, { entry, id });
1600
+ }
1601
+ const state = /* @__PURE__ */ new Map();
1602
+ const valid = (key, seen = /* @__PURE__ */ new Set()) => {
1603
+ const known = state.get(key);
1604
+ if (known !== void 0) return known;
1605
+ const item = raw.get(key);
1606
+ const parent = item?.entry.parent;
1607
+ let ok = !!item;
1608
+ if (ok && parent !== void 0) ok = !seen.has(key) && valid(parent, seen.add(key));
1609
+ state.set(key, ok);
1610
+ return ok;
1611
+ };
1612
+ const live = [...raw.keys()].filter((k) => valid(k)).sort(compare);
1613
+ const {
1614
+ ids: finalId,
1615
+ fresh: renumbered,
1616
+ claims
1617
+ } = assignIds(
1618
+ live.map((key) => {
1619
+ const { id } = raw.get(key);
1620
+ return { key, id, fixed: fixedId(input.renum, key, id) };
911
1621
  })
912
- ).replace(/Sheet\.(\d+)(?!\d)/g, (m, id) => {
913
- const next = remap.get(id);
914
- return next === void 0 ? m : `Sheet.${next}`;
1622
+ );
1623
+ const children = /* @__PURE__ */ new Map();
1624
+ for (const key of live) {
1625
+ const parent = raw.get(key).entry.parent ?? "";
1626
+ children.set(parent, [...children.get(parent) ?? [], key]);
1627
+ }
1628
+ const sortSiblings = (keys) => keys.sort((a, b) => raw.get(a).entry.pos - raw.get(b).entry.pos || compare(a, b));
1629
+ const shapes = [];
1630
+ const fixups = [];
1631
+ const render = (key) => {
1632
+ const { entry } = raw.get(key);
1633
+ const id = finalId.get(key);
1634
+ let open = setAttr(entry.open, "ID", id);
1635
+ const idRecord = renumRecord(
1636
+ input.renum,
1637
+ `${input.scope}/${key}`,
1638
+ { id: raw.get(key).id },
1639
+ renumbered.get(key),
1640
+ claims.has(key)
1641
+ );
1642
+ const record = { ...idRecord ?? input.renum.get(key) };
1643
+ let dirty = idRecord !== void 0;
1644
+ const master = attrOf(open, "Master");
1645
+ const persisted = record.m && record.m[0] === master ? record.m[1] : void 0;
1646
+ const batched = master !== void 0 ? input.masterRemap.get(entry.b ?? "")?.get(master) : void 0;
1647
+ const next = persisted ?? batched;
1648
+ if (next !== void 0) open = setAttr(open, "Master", next);
1649
+ if (persisted === void 0 && batched !== void 0) {
1650
+ record.m = [master, batched];
1651
+ dirty = true;
1652
+ }
1653
+ if (dirty) fixups.push({ map: "renum", key: `${input.scope}/${key}`, value: record });
1654
+ const entries = /* @__PURE__ */ new Map();
1655
+ for (const [path, piece] of input.cells.get(key) ?? []) {
1656
+ const leaf = piece.xml !== void 0 && piece.r !== void 0;
1657
+ const xml2 = leaf ? renumberFormulas(piece.xml, referenced(piece.r, finalId)) : void 0;
1658
+ entries.set(path, xml2 !== void 0 && xml2 !== piece.xml ? { ...piece, xml: xml2 } : piece);
1659
+ }
1660
+ shapes.push({
1661
+ key,
1662
+ id,
1663
+ ...entry.parent !== void 0 ? { parent: entry.parent } : {},
1664
+ open,
1665
+ entries
1666
+ });
1667
+ const inner = sortSiblings(children.get(key) ?? []).map(render).join("");
1668
+ return buildShape(open, entries, inner ? `<Shapes>${inner}</Shapes>` : "");
1669
+ };
1670
+ const xml = sortSiblings(children.get("") ?? []).map(render).join("");
1671
+ return { shapes, xml, fixups };
1672
+ }
1673
+
1674
+ // visio/collab/read-parts.ts
1675
+ var compare2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
1676
+ function resolveMasters(shared, renum) {
1677
+ const alive = [];
1678
+ for (const [key, value] of shared.masters) {
1679
+ const entry = masterEntry(value);
1680
+ if (entry) alive.push({ key, entry });
1681
+ }
1682
+ const { ids, fresh, claims } = assignIds(
1683
+ alive.map(({ key, entry }) => ({
1684
+ key,
1685
+ id: entry.id,
1686
+ fixed: fixedId(renum, masterScope(key), entry.id)
1687
+ }))
1688
+ );
1689
+ const remap = /* @__PURE__ */ new Map();
1690
+ const fixups = [];
1691
+ for (const [key, change] of [...fresh].sort((a, b) => compare2(a[0], b[0]))) {
1692
+ const b = alive.find((m) => m.key === key).entry.b;
1693
+ if (b !== void 0) {
1694
+ const map = remap.get(b) ?? /* @__PURE__ */ new Map();
1695
+ map.set(change.from, change.to);
1696
+ remap.set(b, map);
1697
+ }
1698
+ }
1699
+ for (const { key, entry } of [...alive].sort((a, b) => compare2(a.key, b.key))) {
1700
+ const value = renumRecord(renum, masterScope(key), entry, fresh.get(key), claims.has(key));
1701
+ if (value) fixups.push({ map: "renum", key: masterScope(key), value });
1702
+ }
1703
+ alive.sort((a, b) => a.entry.pos - b.entry.pos || compare2(a.key, b.key));
1704
+ return {
1705
+ masters: alive.map(({ key, entry }) => {
1706
+ const id = ids.get(key);
1707
+ const open = /^<[^>]*>/.exec(entry.xml)?.[0];
1708
+ return {
1709
+ key,
1710
+ id,
1711
+ xml: open ? setAttr(open, "ID", id) + entry.xml.slice(open.length) : entry.xml,
1712
+ part: entry.part,
1713
+ ...entry.rels !== void 0 ? { rels: entry.rels } : {}
1714
+ };
1715
+ }),
1716
+ remap,
1717
+ fixups
1718
+ };
1719
+ }
1720
+ function resolveMedia(shared) {
1721
+ const items = [...shared.media].flatMap(([key, value]) => {
1722
+ const entry = mediaEntry(value);
1723
+ const data = entry ? str(shared.blobs.get(entry.hash)) : void 0;
1724
+ return entry && data !== void 0 ? [{ key, entry, data }] : [];
1725
+ }).sort((a, b) => compare2(a.key, b.key));
1726
+ const taken = /* @__PURE__ */ new Set();
1727
+ const first = /* @__PURE__ */ new Map();
1728
+ for (const item of items) if (!first.has(item.entry.path)) first.set(item.entry.path, item.key);
1729
+ for (const path of first.keys()) taken.add(path);
1730
+ const renames = /* @__PURE__ */ new Map();
1731
+ const media = [];
1732
+ for (const { key, entry, data } of items) {
1733
+ let path = entry.path;
1734
+ if (first.get(entry.path) !== key) {
1735
+ const dot = path.lastIndexOf(".");
1736
+ const stem = dot > path.lastIndexOf("/") ? path.slice(0, dot) : path;
1737
+ const ext = dot > path.lastIndexOf("/") ? path.slice(dot) : "";
1738
+ path = `${stem}-${entry.hash.slice(0, 8)}${ext}`;
1739
+ for (let n = 2; taken.has(path); n++) path = `${stem}-${entry.hash.slice(0, 8)}-${n}${ext}`;
1740
+ taken.add(path);
1741
+ if (entry.b !== void 0) {
1742
+ const map = renames.get(entry.b) ?? /* @__PURE__ */ new Map();
1743
+ map.set(entry.path, path);
1744
+ renames.set(entry.b, map);
1745
+ }
1746
+ }
1747
+ media.push({
1748
+ key,
1749
+ path,
1750
+ hash: entry.hash,
1751
+ declared: { type: entry.ct, byDefault: entry.d },
1752
+ data
1753
+ });
1754
+ }
1755
+ return { media, renames };
1756
+ }
1757
+ function renameTargets(rels, baseDir, renames) {
1758
+ return rels.replace(/<(?:\w+:)?Relationship\b[^>]*>/g, (tag) => {
1759
+ const target = attrOf(tag, "Target");
1760
+ if (target === void 0 || attrOf(tag, "TargetMode") === "External") return tag;
1761
+ const next = renames.get(resolveTarget(baseDir, target));
1762
+ if (next === void 0) return tag;
1763
+ const value = target.startsWith("/") ? `/${next}` : relativeTarget(baseDir, next);
1764
+ return tag.replace(
1765
+ /(\sTarget\s*=\s*)(?:"[^"]*"|'[^']*')/,
1766
+ (_m, head) => `${head}"${value}"`
1767
+ );
915
1768
  });
916
1769
  }
1770
+
1771
+ // visio/collab/read.ts
917
1772
  function readSharedDrawing(shared) {
1773
+ assertSchemaVersion(shared);
918
1774
  if (isSharedDrawingEmpty(shared)) return void 0;
919
1775
  const pagesPath = str(shared.meta.get("pagesPath"));
920
1776
  const pagesOpen = str(shared.meta.get("pagesOpen"));
@@ -926,25 +1782,52 @@ function readSharedDrawing(shared) {
926
1782
  const body = bodyEntry(shared.bodies.get(key));
927
1783
  return entry && body ? [{ key, pos: entry.pos, entry, body }] : [];
928
1784
  });
929
- const pageIds = /* @__PURE__ */ new Map();
930
- const taken = /* @__PURE__ */ new Set();
931
- let maxPage = Math.max(0, ...alive.map((p) => numeric(p.entry.id)));
932
- for (const page of [...alive].sort((a, b) => compare(a.key, b.key))) {
933
- let id = page.entry.id;
934
- if (taken.has(id)) id = String(++maxPage);
935
- taken.add(id);
936
- pageIds.set(page.key, id);
1785
+ const renum = readRenum(shared);
1786
+ const fixups = [];
1787
+ const {
1788
+ ids: pageIds,
1789
+ fresh: freshPages,
1790
+ claims: pageClaims
1791
+ } = assignIds(
1792
+ alive.map((p) => ({
1793
+ key: p.key,
1794
+ id: p.entry.id,
1795
+ fixed: fixedId(renum, p.key, p.entry.id)
1796
+ }))
1797
+ );
1798
+ for (const p of [...alive].sort((a, b) => compare(a.key, b.key))) {
1799
+ const value = renumRecord(renum, p.key, p.entry, freshPages.get(p.key), pageClaims.has(p.key));
1800
+ if (value) fixups.push({ map: "renum", key: p.key, value });
937
1801
  }
938
1802
  const shapesByPage = /* @__PURE__ */ new Map();
939
1803
  for (const [full, value] of shared.shapes) {
940
- const slash = full.indexOf("/");
941
- if (slash < 0 || shared.dead.has(full)) continue;
1804
+ const parts2 = split(full, 1);
1805
+ if (!parts2 || shared.dead.has(full)) continue;
942
1806
  const entry = shapeEntry(value);
943
1807
  if (!entry) continue;
944
- const page = full.slice(0, slash);
945
- const list = shapesByPage.get(page) ?? [];
946
- list.push({ key: full.slice(slash + 1), pos: entry.pos, xml: entry.xml });
947
- shapesByPage.set(page, list);
1808
+ const map = shapesByPage.get(parts2[0]) ?? /* @__PURE__ */ new Map();
1809
+ map.set(parts2[1], entry);
1810
+ shapesByPage.set(parts2[0], map);
1811
+ }
1812
+ const cellsByPage = /* @__PURE__ */ new Map();
1813
+ for (const [full, value] of shared.cells) {
1814
+ const parts2 = split(full, 2);
1815
+ const entry = parts2 && cellEntry(value);
1816
+ if (!parts2 || !entry) continue;
1817
+ const [page, shape, path] = parts2;
1818
+ const shapes = cellsByPage.get(page) ?? /* @__PURE__ */ new Map();
1819
+ const cells = shapes.get(shape) ?? /* @__PURE__ */ new Map();
1820
+ cells.set(path, entry);
1821
+ shapes.set(shape, cells);
1822
+ cellsByPage.set(page, shapes);
1823
+ }
1824
+ const renumByScope = /* @__PURE__ */ new Map();
1825
+ for (const [full, entry] of renum) {
1826
+ const parts2 = split(full, 1);
1827
+ if (!parts2) continue;
1828
+ const map = renumByScope.get(parts2[0]) ?? /* @__PURE__ */ new Map();
1829
+ map.set(parts2[1], entry);
1830
+ renumByScope.set(parts2[0], map);
948
1831
  }
949
1832
  const connectsByPage = /* @__PURE__ */ new Map();
950
1833
  for (const [full, value] of shared.connects) {
@@ -955,24 +1838,25 @@ function readSharedDrawing(shared) {
955
1838
  list.push({ key: full, entry });
956
1839
  connectsByPage.set(full.slice(0, slash), list);
957
1840
  }
1841
+ const { masters, remap: masterRemap, fixups: masterFixups } = resolveMasters(shared, renum);
1842
+ fixups.push(...masterFixups);
1843
+ const { media, renames } = resolveMedia(shared);
1844
+ const mastersPath = str(shared.meta.get("mastersPath"));
1845
+ const mastersOpen = str(shared.meta.get("mastersOpen"));
1846
+ const mastersClose = str(shared.meta.get("mastersClose"));
1847
+ const pagesDir = dirName(pagesPath);
958
1848
  const pages = [];
959
1849
  for (const page of byPosition(alive)) {
960
1850
  const finalId = pageIds.get(page.key);
961
- const shapes = resolveShapes(shapesByPage.get(page.key) ?? []);
962
- const byKey = new Map(shapes.map((s) => [s.key, s]));
963
- const connects = [];
964
- for (const item of (connectsByPage.get(page.key) ?? []).sort((a, b) => compare(a.key, b.key))) {
965
- const { entry } = item;
966
- const from = entry.fk ? byKey.get(entry.fk) : void 0;
967
- const to = entry.tk ? byKey.get(entry.tk) : void 0;
968
- if (entry.fk && !from || entry.tk && !to) continue;
969
- connects.push({
970
- key: item.key,
971
- entry,
972
- from: from?.remap.get(entry.fi) ?? entry.fi,
973
- to: to?.remap.get(entry.ti) ?? entry.ti
974
- });
975
- }
1851
+ const resolved = resolveShapes({
1852
+ scope: page.key,
1853
+ shapes: shapesByPage.get(page.key) ?? /* @__PURE__ */ new Map(),
1854
+ cells: cellsByPage.get(page.key) ?? /* @__PURE__ */ new Map(),
1855
+ renum: renumByScope.get(page.key) ?? /* @__PURE__ */ new Map(),
1856
+ masterRemap
1857
+ });
1858
+ fixups.push(...resolved.fixups);
1859
+ const connects = resolveConnects(connectsByPage.get(page.key), resolved.shapes);
976
1860
  let xml = page.entry.xml;
977
1861
  const open = /^<[^>]*>/.exec(xml)?.[0];
978
1862
  if (open) {
@@ -981,46 +1865,361 @@ function readSharedDrawing(shared) {
981
1865
  if (back !== void 0) next = setAttr(next, "BackPage", back);
982
1866
  xml = next + xml.slice(open.length);
983
1867
  }
1868
+ const rename = page.body.b !== void 0 ? renames.get(page.body.b) : void 0;
1869
+ const body = rename && page.body.rels !== void 0 ? { ...page.body, rels: renameTargets(page.body.rels, pagesDir, rename) } : page.body;
1870
+ const contentSignature = hashTexts([
1871
+ body.shell,
1872
+ body.rels ?? "\0",
1873
+ resolved.xml,
1874
+ ...connectSignature(connects)
1875
+ ]);
984
1876
  pages.push({
985
1877
  key: page.key,
986
1878
  id: finalId,
987
1879
  ...page.entry.back !== void 0 ? { back: page.entry.back } : {},
988
1880
  xml,
989
- body: page.body,
990
- shapes,
991
- connects
1881
+ body,
1882
+ shapes: resolved.shapes,
1883
+ shapesXml: resolved.xml,
1884
+ connects,
1885
+ signature: hashTexts([xml, contentSignature]),
1886
+ contentSignature
992
1887
  });
993
1888
  }
1889
+ const mastersDir = mastersPath !== void 0 ? dirName(mastersPath) : pagesDir;
1890
+ const finalMasters = masters.map((m) => {
1891
+ const batch = shared.masters.get(m.key)?.b;
1892
+ const rename = typeof batch === "string" ? renames.get(batch) : void 0;
1893
+ const scope = masterScope(m.key);
1894
+ const resolved = resolveShapes({
1895
+ scope,
1896
+ shapes: shapesByPage.get(scope) ?? /* @__PURE__ */ new Map(),
1897
+ cells: cellsByPage.get(scope) ?? /* @__PURE__ */ new Map(),
1898
+ renum: renumByScope.get(scope) ?? /* @__PURE__ */ new Map(),
1899
+ masterRemap: /* @__PURE__ */ new Map()
1900
+ });
1901
+ fixups.push(...resolved.fixups);
1902
+ return {
1903
+ ...m,
1904
+ ...rename && m.rels !== void 0 ? { rels: renameTargets(m.rels, mastersDir, rename) } : {},
1905
+ shapes: resolved.shapes,
1906
+ shapesXml: resolved.xml,
1907
+ connects: resolveConnects(connectsByPage.get(scope), resolved.shapes)
1908
+ };
1909
+ });
994
1910
  const parts = /* @__PURE__ */ new Map();
995
1911
  for (const [path, value] of shared.parts) if (typeof value === "string") parts.set(path, value);
996
- return { pagesPath, pagesOpen, pagesClose, pages, parts };
1912
+ const baseSignature = hashTexts([
1913
+ pagesPath,
1914
+ pagesOpen,
1915
+ pagesClose,
1916
+ mastersPath ?? "",
1917
+ mastersOpen ?? "",
1918
+ mastersClose ?? "",
1919
+ ...pages.map((p) => `${p.key}:${p.id}:${p.xml}`),
1920
+ ...finalMasters.flatMap((m) => [
1921
+ m.key,
1922
+ m.id,
1923
+ m.xml,
1924
+ m.part,
1925
+ m.rels ?? "\0",
1926
+ m.shapesXml,
1927
+ ...connectSignature(m.connects)
1928
+ ]),
1929
+ ...media.flatMap((m) => [m.path, m.hash, m.declared.type, String(m.declared.byDefault)]),
1930
+ ...[...parts].flatMap(([path, data]) => [path, data])
1931
+ ]);
1932
+ const signature = hashTexts([
1933
+ baseSignature,
1934
+ ...pages.map((p) => `${p.key}:${p.contentSignature}`)
1935
+ ]);
1936
+ return {
1937
+ pagesPath,
1938
+ pagesOpen,
1939
+ pagesClose,
1940
+ pages,
1941
+ ...mastersPath !== void 0 && mastersOpen !== void 0 && mastersClose !== void 0 ? { mastersPath, mastersOpen, mastersClose } : {},
1942
+ masters: finalMasters,
1943
+ media,
1944
+ parts,
1945
+ signature,
1946
+ baseSignature,
1947
+ fixups
1948
+ };
997
1949
  }
998
- function resolveShapes(entries) {
999
- const parsed = entries.map((entry) => ({ ...entry, ids: shapeIds(entry.xml) }));
1000
- let max = Math.max(0, ...parsed.flatMap((p) => p.ids.map(numeric)));
1001
- const used = /* @__PURE__ */ new Set();
1002
- const done = /* @__PURE__ */ new Map();
1003
- for (const item of [...parsed].sort((a, b) => compare(a.key, b.key))) {
1004
- const remap = /* @__PURE__ */ new Map();
1005
- for (const id of item.ids) {
1006
- if (used.has(id) || remap.has(id)) remap.set(id, String(++max));
1950
+
1951
+ // visio/collab/write-shapes.ts
1952
+ function syncEntry(ctx, map, mapKey, id, content, room, roomContent, local, stamp = false) {
1953
+ ctx.now.set(id, content);
1954
+ const base = ctx.keys.known.get(id);
1955
+ const own = base === void 0 ? !room || roomContent() !== content : base !== content;
1956
+ if (own || !room) {
1957
+ const value = local();
1958
+ ctx.write(map, mapKey, stamp ? { ...value, b: ctx.batch } : value);
1959
+ } else {
1960
+ const pos = local().pos;
1961
+ ctx.write(map, mapKey, pos === void 0 ? room : { ...room, pos });
1962
+ }
1963
+ }
1964
+ function groupPositions(items, current) {
1965
+ const groups = /* @__PURE__ */ new Map();
1966
+ for (const item of items) groups.set(item.group, [...groups.get(item.group) ?? [], item.key]);
1967
+ const out = /* @__PURE__ */ new Map();
1968
+ for (const list of groups.values())
1969
+ for (const [key, pos] of assignPositions(list, current)) out.set(key, pos);
1970
+ return out;
1971
+ }
1972
+ function syncConnects(ctx, connects) {
1973
+ for (const connect of connects) {
1974
+ ctx.now.set(connectId(connect.key), "");
1975
+ if (!ctx.keys.known.has(connectId(connect.key)) || !ctx.shared.connects.has(connect.key))
1976
+ ctx.write(ctx.shared.connects, connect.key, connect.entry);
1977
+ }
1978
+ }
1979
+ function syncShapes(ctx, page) {
1980
+ const { shared } = ctx;
1981
+ const shapePos = groupPositions(
1982
+ page.shapes.map((s) => ({ key: s.key, group: s.parent ?? "" })),
1983
+ (key) => shapeEntry(shared.shapes.get(`${page.key}/${key}`))?.pos
1984
+ );
1985
+ for (const shape of page.shapes) {
1986
+ const full = `${page.key}/${shape.key}`;
1987
+ const room = shapeEntry(shared.shapes.get(full));
1988
+ const parent = shape.parent;
1989
+ syncEntry(
1990
+ ctx,
1991
+ shared.shapes,
1992
+ full,
1993
+ shapeId(page.key, shape.key),
1994
+ shellContent({ parent, open: shape.open }),
1995
+ room,
1996
+ () => shellContent(room),
1997
+ () => ({
1998
+ pos: shapePos.get(shape.key),
1999
+ ...parent !== void 0 ? { parent } : {},
2000
+ open: shape.open,
2001
+ b: room?.b ?? ctx.batch
2002
+ })
2003
+ );
2004
+ const piecePos = groupPositions(
2005
+ shape.pieces.map((p) => ({ key: p.path, group: p.parent })),
2006
+ (path) => cellEntry(shared.cells.get(`${full}/${path}`))?.pos
2007
+ );
2008
+ for (const piece of shape.pieces) {
2009
+ const cellKey = `${full}/${piece.path}`;
2010
+ const roomCell = cellEntry(shared.cells.get(cellKey));
2011
+ const local = () => ({
2012
+ pos: piecePos.get(piece.path),
2013
+ ...piece.kind === "leaf" ? { xml: piece.text } : { open: piece.text },
2014
+ ...piece.refs ? { r: piece.refs } : {}
2015
+ });
2016
+ syncEntry(
2017
+ ctx,
2018
+ shared.cells,
2019
+ cellKey,
2020
+ cellId(page.key, shape.key, piece.path),
2021
+ entryContent(piece.kind === "leaf" ? { xml: piece.text } : { open: piece.text }),
2022
+ roomCell,
2023
+ () => entryContent(roomCell),
2024
+ local
2025
+ );
1007
2026
  }
1008
- const ids = item.ids.map((id) => remap.get(id) ?? id);
1009
- for (const id of ids) used.add(id);
1010
- done.set(item.key, {
1011
- key: item.key,
1012
- id: ids[0] ?? "",
1013
- xml: renumberShape(item.xml, remap),
1014
- remap,
1015
- ids
1016
- });
1017
2027
  }
1018
- return byPosition(parsed).map((item) => done.get(item.key));
2028
+ }
2029
+
2030
+ // visio/collab/write-parts.ts
2031
+ var mediaKey = (hash, path) => `${hash}|${path}`;
2032
+ function syncMasters(ctx, snapshot) {
2033
+ const { shared } = ctx;
2034
+ const pos = assignPositions(
2035
+ snapshot.masters.map((m) => m.key),
2036
+ (key) => masterEntry(shared.masters.get(key))?.pos
2037
+ );
2038
+ for (const master of snapshot.masters) {
2039
+ const room = masterEntry(shared.masters.get(master.key));
2040
+ syncEntry(
2041
+ ctx,
2042
+ shared.masters,
2043
+ master.key,
2044
+ masterId(master.key),
2045
+ masterContent({ ...master, print: fingerprint(master.part) }),
2046
+ room,
2047
+ () => masterContent({
2048
+ ...room,
2049
+ print: fingerprint(fromBase64(room.part))
2050
+ }),
2051
+ () => ({
2052
+ pos: pos.get(master.key),
2053
+ id: master.id,
2054
+ xml: master.xml,
2055
+ part: toBase64(master.part),
2056
+ ...master.rels !== void 0 ? { rels: master.rels } : {}
2057
+ }),
2058
+ true
2059
+ );
2060
+ syncShapes(ctx, { key: masterScope(master.key), shapes: master.shapes });
2061
+ syncConnects(ctx, master.connects);
2062
+ }
2063
+ }
2064
+ function syncMedia(ctx, snapshot) {
2065
+ const { shared } = ctx;
2066
+ for (const item of snapshot.media) {
2067
+ const known = ctx.keys.mediaKeys.get(item.path);
2068
+ const key = known?.startsWith(`${item.hash}|`) ? known : mediaKey(item.hash, item.path);
2069
+ ctx.now.set(mediaId(key), "");
2070
+ if (!mediaEntry(shared.media.get(key))) {
2071
+ ctx.write(shared.media, key, {
2072
+ path: item.path,
2073
+ hash: item.hash,
2074
+ ct: item.ct,
2075
+ d: item.d,
2076
+ b: ctx.batch
2077
+ });
2078
+ shared.blobs.set(item.hash, toBase64(item.data));
2079
+ } else if (!shared.blobs.has(item.hash)) shared.blobs.set(item.hash, toBase64(item.data));
2080
+ }
2081
+ }
2082
+ function syncParts(ctx, snapshot) {
2083
+ const { shared, keys } = ctx;
2084
+ for (const [path, data] of snapshot.parts) {
2085
+ const print = fingerprint(data);
2086
+ if (keys.partPrints.get(path) === print) continue;
2087
+ ctx.write(shared.parts, path, toBase64(data));
2088
+ keys.partPrints.set(path, print);
2089
+ }
2090
+ let removed = 0;
2091
+ for (const path of [...keys.partPrints.keys()])
2092
+ if (!snapshot.parts.has(path)) {
2093
+ shared.parts.delete(path);
2094
+ keys.partPrints.delete(path);
2095
+ removed++;
2096
+ }
2097
+ return removed;
2098
+ }
2099
+
2100
+ // visio/collab/write.ts
2101
+ function removeScope(shared, name) {
2102
+ shared.renum.delete(name);
2103
+ for (const map of [shared.shapes, shared.cells, shared.connects, shared.renum])
2104
+ for (const key of [...map.keys()]) if (key.startsWith(`${name}/`)) map.delete(key);
2105
+ }
2106
+ function removePage(shared, name) {
2107
+ shared.dead.set(name, true);
2108
+ for (const map of [shared.pages, shared.bodies]) map.delete(name);
2109
+ removeScope(shared, name);
2110
+ }
2111
+ function writeSharedDrawing(shared, snapshot, keys) {
2112
+ assertSchemaVersion(shared);
2113
+ let writes = 0;
2114
+ const write = (map, key, value) => {
2115
+ if (setIfChanged(map, key, value)) writes++;
2116
+ };
2117
+ const now = /* @__PURE__ */ new Map();
2118
+ const ctx = { shared, keys, now, batch: keys.batch(), write };
2119
+ write(shared.meta, "v", SCHEMA_VERSION);
2120
+ write(shared.meta, "pagesPath", snapshot.pagesPath);
2121
+ write(shared.meta, "pagesOpen", snapshot.pagesOpen);
2122
+ write(shared.meta, "pagesClose", snapshot.pagesClose);
2123
+ if (snapshot.mastersPath !== void 0) {
2124
+ write(shared.meta, "mastersPath", snapshot.mastersPath);
2125
+ write(shared.meta, "mastersOpen", snapshot.mastersOpen);
2126
+ write(shared.meta, "mastersClose", snapshot.mastersClose);
2127
+ }
2128
+ const pagePos = assignPositions(
2129
+ snapshot.pages.map((p) => p.key),
2130
+ (key) => pageEntry(shared.pages.get(key))?.pos
2131
+ );
2132
+ for (const page of snapshot.pages) {
2133
+ const room = pageEntry(shared.pages.get(page.key));
2134
+ syncEntry(
2135
+ ctx,
2136
+ shared.pages,
2137
+ page.key,
2138
+ pageId(page.key),
2139
+ pageContent(page),
2140
+ room,
2141
+ () => pageContent(room),
2142
+ () => ({
2143
+ pos: pagePos.get(page.key),
2144
+ id: page.id,
2145
+ ...page.back !== void 0 ? { back: page.back } : {},
2146
+ xml: page.xml
2147
+ })
2148
+ );
2149
+ const roomBody = bodyEntry(shared.bodies.get(page.key));
2150
+ syncEntry(
2151
+ ctx,
2152
+ shared.bodies,
2153
+ page.key,
2154
+ bodyId(page.key),
2155
+ bodyContent(page),
2156
+ roomBody,
2157
+ () => bodyContent(roomBody),
2158
+ () => ({ shell: page.shell, ...page.rels !== void 0 ? { rels: page.rels } : {} }),
2159
+ true
2160
+ );
2161
+ syncShapes(ctx, page);
2162
+ syncConnects(ctx, page.connects);
2163
+ }
2164
+ syncMasters(ctx, snapshot);
2165
+ syncMedia(ctx, snapshot);
2166
+ for (const id of keys.known.keys()) {
2167
+ if (now.has(id)) continue;
2168
+ const name = id.slice(2);
2169
+ switch (id.slice(0, 2)) {
2170
+ case "p:":
2171
+ removePage(shared, name);
2172
+ keys.forgetPage(name);
2173
+ writes++;
2174
+ break;
2175
+ case "s:": {
2176
+ const slash = name.indexOf("/");
2177
+ const page = name.slice(0, slash);
2178
+ if (!now.has(page.startsWith(masterScope("")) ? masterId(page.slice(2)) : pageId(page)))
2179
+ break;
2180
+ shared.dead.set(name, true);
2181
+ shared.shapes.delete(name);
2182
+ keys.forgetShape(page, name.slice(slash + 1));
2183
+ writes++;
2184
+ break;
2185
+ }
2186
+ case "f:":
2187
+ if (shared.cells.has(name)) {
2188
+ shared.cells.delete(name);
2189
+ writes++;
2190
+ }
2191
+ break;
2192
+ case "c:":
2193
+ if (shared.connects.has(name)) {
2194
+ shared.connects.delete(name);
2195
+ writes++;
2196
+ }
2197
+ break;
2198
+ case "m:":
2199
+ if (shared.masters.has(name)) {
2200
+ shared.masters.delete(name);
2201
+ removeScope(shared, masterScope(name));
2202
+ writes++;
2203
+ }
2204
+ keys.forgetMaster(name);
2205
+ break;
2206
+ case "i:":
2207
+ if (shared.media.has(name)) {
2208
+ shared.media.delete(name);
2209
+ writes++;
2210
+ }
2211
+ break;
2212
+ }
2213
+ }
2214
+ keys.known = now;
2215
+ writes += syncParts(ctx, snapshot);
2216
+ return writes;
1019
2217
  }
1020
2218
 
1021
2219
  // visio/collab/bind.ts
1022
2220
  var VISIO_EDIT_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:edit");
1023
2221
  var VISIO_SYNC_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:sync");
2222
+ var VISIO_FIXUP_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:fixup");
1024
2223
  function bindDrawingSession(host, editor, options = {}) {
1025
2224
  const { doc } = host;
1026
2225
  const shared = sharedDrawing(doc);
@@ -1040,6 +2239,12 @@ function bindDrawingSession(host, editor, options = {}) {
1040
2239
  let settled = false;
1041
2240
  let localDirty = false;
1042
2241
  let remoteDirty = false;
2242
+ let incompatible = false;
2243
+ let queued = false;
2244
+ let queuedDone;
2245
+ const schedule = options.schedule ?? ((run) => {
2246
+ setTimeout(run, 0);
2247
+ });
1043
2248
  let running;
1044
2249
  const report = (error) => options.onError?.(error);
1045
2250
  const publish = async () => {
@@ -1058,7 +2263,14 @@ function bindDrawingSession(host, editor, options = {}) {
1058
2263
  const rebuild = async () => {
1059
2264
  const resolved = readSharedDrawing(shared);
1060
2265
  if (!resolved) return;
2266
+ if (resolved.fixups.length && host.canWrite())
2267
+ doc.transact(() => applyFixups(shared, resolved.fixups), VISIO_FIXUP_ORIGIN);
1061
2268
  const version = editor.version();
2269
+ if (keys.applied?.signature === resolved.signature && keys.applied.version === version) return;
2270
+ const before = keys.applied;
2271
+ const change = before && before.version === version && before.base === resolved.baseSignature ? {
2272
+ pages: resolved.pages.filter((page) => before.pages.get(page.key) !== page.contentSignature).map((page) => page.id)
2273
+ } : void 0;
1062
2274
  const composed = await composeDrawing(resolved, editor.exportBytes(), keys);
1063
2275
  if (disposed) return;
1064
2276
  if (editor.busy() || editor.version() !== version) {
@@ -1066,15 +2278,21 @@ function bindDrawingSession(host, editor, options = {}) {
1066
2278
  return;
1067
2279
  }
1068
2280
  try {
1069
- await editor.applyRemote(composed.bytes);
2281
+ await editor.applyRemote(composed.bytes, change);
1070
2282
  } catch (error) {
1071
2283
  if (editor.busy()) remoteDirty = true;
1072
2284
  else report(error);
1073
2285
  return;
1074
2286
  }
1075
2287
  composed.commit();
2288
+ keys.applied = {
2289
+ signature: composed.signature,
2290
+ version: editor.version(),
2291
+ base: resolved.baseSignature,
2292
+ pages: new Map(resolved.pages.map((page) => [page.key, page.contentSignature]))
2293
+ };
1076
2294
  };
1077
- const blocked = () => disposed || !settled || editor.busy();
2295
+ const blocked = () => disposed || incompatible || !settled || editor.busy();
1078
2296
  const pending = () => !blocked() && (localDirty && host.canWrite() || remoteDirty && !localDirty);
1079
2297
  const loop = async () => {
1080
2298
  while (pending()) {
@@ -1087,6 +2305,7 @@ function bindDrawingSession(host, editor, options = {}) {
1087
2305
  await rebuild();
1088
2306
  }
1089
2307
  } catch (error) {
2308
+ if (error instanceof SchemaVersionError) incompatible = true;
1090
2309
  report(error);
1091
2310
  }
1092
2311
  }
@@ -1113,18 +2332,30 @@ function bindDrawingSession(host, editor, options = {}) {
1113
2332
  }
1114
2333
  pump();
1115
2334
  };
2335
+ const queueRemote = () => {
2336
+ if (queued) return;
2337
+ queued = true;
2338
+ queuedDone = new Promise(
2339
+ (resolve) => schedule(() => {
2340
+ queued = false;
2341
+ remoteDirty = true;
2342
+ resolve();
2343
+ pump();
2344
+ })
2345
+ );
2346
+ };
1116
2347
  const afterTransaction = (transaction) => {
1117
2348
  if (disposed) return;
1118
2349
  const origin = transaction.origin;
1119
- if (origin === VISIO_EDIT_ORIGIN || origin === VISIO_SYNC_ORIGIN) return;
2350
+ if (origin === VISIO_EDIT_ORIGIN || origin === VISIO_SYNC_ORIGIN || origin === VISIO_FIXUP_ORIGIN)
2351
+ return;
1120
2352
  const changed = transaction.changed;
1121
2353
  if (!types.some((type) => changed.has(type))) return;
1122
2354
  if (!settled) {
1123
2355
  if (!isSharedDrawingEmpty(shared)) settle();
1124
2356
  return;
1125
2357
  }
1126
- remoteDirty = true;
1127
- pump();
2358
+ queueRemote();
1128
2359
  };
1129
2360
  doc.on("afterTransaction", afterTransaction);
1130
2361
  const stops = [
@@ -1142,7 +2373,10 @@ function bindDrawingSession(host, editor, options = {}) {
1142
2373
  ];
1143
2374
  if (host.synced || host.canWrite()) settle();
1144
2375
  const idle = async () => {
1145
- while (running) await running;
2376
+ while (running || queued) {
2377
+ if (queued) await queuedDone;
2378
+ if (running) await running;
2379
+ }
1146
2380
  };
1147
2381
  const replay = async (kind) => {
1148
2382
  await idle();
@@ -1174,17 +2408,25 @@ function bindDrawingSession(host, editor, options = {}) {
1174
2408
  };
1175
2409
  }
1176
2410
 
2411
+ exports.BLOBS = BLOBS;
1177
2412
  exports.BODIES = BODIES;
2413
+ exports.CELLS = CELLS;
1178
2414
  exports.CONNECTS = CONNECTS;
1179
2415
  exports.DEAD = DEAD;
1180
2416
  exports.DrawingKeys = DrawingKeys;
2417
+ exports.MASTERS = MASTERS;
2418
+ exports.MEDIA = MEDIA;
1181
2419
  exports.META = META;
1182
2420
  exports.PAGES = PAGES;
1183
2421
  exports.PARTS = PARTS;
2422
+ exports.RENUM = RENUM;
1184
2423
  exports.SCHEMA_VERSION = SCHEMA_VERSION;
1185
2424
  exports.SHAPES = SHAPES;
2425
+ exports.SchemaVersionError = SchemaVersionError;
1186
2426
  exports.VISIO_EDIT_ORIGIN = VISIO_EDIT_ORIGIN;
2427
+ exports.VISIO_FIXUP_ORIGIN = VISIO_FIXUP_ORIGIN;
1187
2428
  exports.VISIO_SYNC_ORIGIN = VISIO_SYNC_ORIGIN;
2429
+ exports.applyFixups = applyFixups;
1188
2430
  exports.bindDrawingSession = bindDrawingSession;
1189
2431
  exports.composeDrawing = composeDrawing;
1190
2432
  exports.isSharedDrawingEmpty = isSharedDrawingEmpty;