@beyondwork/docx-react-component 1.0.66 → 1.0.69

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 (384) hide show
  1. package/README.md +75 -931
  2. package/package.json +26 -27
  3. package/src/api/anchor-conversion.ts +43 -0
  4. package/src/api/editor-state-types.ts +2 -1
  5. package/src/api/public-types.ts +504 -101
  6. package/src/api/session-state.ts +4 -0
  7. package/src/api/v3/README.md +91 -0
  8. package/src/api/v3/_create.ts +146 -0
  9. package/src/api/v3/_layer-metadata.ts +362 -0
  10. package/src/api/v3/_mocks.ts +84 -0
  11. package/src/api/v3/_runtime-handle.ts +162 -0
  12. package/src/api/v3/_ux-response.ts +73 -0
  13. package/src/api/v3/ai/_metadata-audit.ts +225 -0
  14. package/src/api/v3/ai/attach.ts +235 -0
  15. package/src/api/v3/ai/bundle.ts +132 -0
  16. package/src/api/v3/ai/explain.ts +144 -0
  17. package/src/api/v3/ai/export.ts +54 -0
  18. package/src/api/v3/ai/inspect.ts +118 -0
  19. package/src/api/v3/ai/policy.ts +77 -0
  20. package/src/api/v3/ai/replacement.ts +341 -0
  21. package/src/api/v3/ai/resolve.ts +133 -0
  22. package/src/api/v3/index.ts +79 -0
  23. package/src/api/v3/runtime/chart.ts +310 -0
  24. package/src/api/v3/runtime/clipboard.ts +81 -0
  25. package/src/api/v3/runtime/collab.ts +331 -0
  26. package/src/api/v3/runtime/content.ts +236 -0
  27. package/src/api/v3/runtime/document.ts +282 -0
  28. package/src/api/v3/runtime/formatting.ts +186 -0
  29. package/src/api/v3/runtime/geometry.ts +349 -0
  30. package/src/api/v3/runtime/layout.ts +108 -0
  31. package/src/api/v3/runtime/review.ts +129 -0
  32. package/src/api/v3/runtime/search.ts +74 -0
  33. package/src/api/v3/runtime/table.ts +63 -0
  34. package/src/api/v3/runtime/workflow.ts +434 -0
  35. package/src/api/v3/ui/_context.ts +86 -0
  36. package/src/api/v3/ui/_create.ts +65 -0
  37. package/src/api/v3/ui/_types.ts +520 -0
  38. package/src/api/v3/ui/chrome-composition.ts +342 -0
  39. package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
  40. package/src/api/v3/ui/chrome.ts +476 -0
  41. package/src/api/v3/ui/debug.ts +124 -0
  42. package/src/api/v3/ui/index.ts +64 -0
  43. package/src/api/v3/ui/overlays-visibility.ts +170 -0
  44. package/src/api/v3/ui/overlays.ts +427 -0
  45. package/src/api/v3/ui/scope.ts +71 -0
  46. package/src/api/v3/ui/session.ts +100 -0
  47. package/src/api/v3/ui/surface.ts +170 -0
  48. package/src/api/v3/ui/viewport.ts +303 -0
  49. package/src/core/commands/index.ts +28 -6
  50. package/src/core/commands/list-commands.ts +3 -2
  51. package/src/core/commands/section-layout-commands.ts +9 -8
  52. package/src/core/schema/text-schema.ts +16 -0
  53. package/src/core/selection/mapping.ts +33 -72
  54. package/src/core/state/editor-state.ts +96 -189
  55. package/src/index.ts +23 -4
  56. package/src/io/chart-preview-resolver.ts +1 -1
  57. package/src/io/docx-session.ts +36 -4795
  58. package/src/io/export/build-app-properties-xml.ts +1 -1
  59. package/src/io/export/serialize-comments.ts +1 -1
  60. package/src/io/export/serialize-headers-footers.ts +6 -1
  61. package/src/io/export/serialize-main-document.ts +45 -0
  62. package/src/io/export/serialize-run-formatting.ts +17 -2
  63. package/src/io/export/twip.ts +1 -1
  64. package/src/io/normalize/normalize-text.ts +27 -20
  65. package/src/io/ooxml/chart/parse-series.ts +1 -1
  66. package/src/io/ooxml/chart/resolve-color.ts +2 -2
  67. package/src/io/ooxml/chart/types.ts +1 -1
  68. package/src/io/ooxml/classify-embedding.ts +83 -33
  69. package/src/io/ooxml/parse-fill.ts +1 -1
  70. package/src/io/ooxml/parse-main-document.ts +71 -1
  71. package/src/io/ooxml/parse-object.ts +14 -10
  72. package/src/io/ooxml/parse-run-formatting.ts +47 -1
  73. package/src/io/ooxml/property-grab-bag.ts +2 -2
  74. package/src/io/ooxml/units.ts +11 -0
  75. package/src/io/ooxml/workflow-payload.ts +282 -7
  76. package/src/model/anchor.ts +85 -0
  77. package/src/model/canonical-document.ts +351 -15
  78. package/src/model/chart-types.ts +1 -1
  79. package/src/model/layout/index.ts +83 -0
  80. package/src/model/layout/page-graph-types.ts +181 -0
  81. package/src/model/layout/page-layout-snapshot.ts +105 -0
  82. package/src/model/layout/resolved-layout-types.ts +47 -0
  83. package/src/model/layout/runtime-page-graph-types.ts +102 -0
  84. package/src/model/paragraph-scope-ids.ts +72 -0
  85. package/src/model/review/comment-types.ts +112 -0
  86. package/src/model/review/index.ts +2 -0
  87. package/src/model/review/revision-types.ts +215 -0
  88. package/src/model/snapshot.ts +32 -0
  89. package/src/review/store/comment-store.ts +21 -47
  90. package/src/review/store/revision-types.ts +40 -198
  91. package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
  92. package/src/runtime/collab/runtime-collab-sync.ts +13 -3
  93. package/src/runtime/collab-session.ts +1 -1
  94. package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
  95. package/src/runtime/debug/event-ring-buffer.ts +64 -0
  96. package/src/runtime/debug/probability-sampler.ts +18 -0
  97. package/src/runtime/debug/runtime-debug-facet.ts +67 -0
  98. package/src/runtime/debug/stage-tokens.ts +31 -0
  99. package/src/runtime/debug/telemetry-bus.ts +271 -0
  100. package/src/runtime/debug/types.ts +275 -0
  101. package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
  102. package/src/runtime/document-layout.ts +8 -6
  103. package/src/runtime/document-runtime.ts +843 -1141
  104. package/src/runtime/document-search.ts +1 -1
  105. package/src/runtime/edit-ops/index.ts +1 -1
  106. package/src/runtime/external-send-runtime.ts +1 -1
  107. package/src/runtime/formatting/document-lookup.ts +235 -0
  108. package/src/runtime/formatting/field/registry.ts +41 -0
  109. package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
  110. package/src/runtime/formatting/font-resolution.ts +83 -0
  111. package/src/runtime/formatting/formatting-context.ts +903 -0
  112. package/src/runtime/formatting/formatting-types.ts +157 -0
  113. package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
  114. package/src/runtime/formatting/index.ts +125 -0
  115. package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
  116. package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
  117. package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
  118. package/src/runtime/formatting/projector.ts +75 -0
  119. package/src/runtime/formatting/resolve-effective.ts +407 -0
  120. package/src/runtime/formatting/revision-display.ts +105 -0
  121. package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
  122. package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
  123. package/src/runtime/formatting/telemetry-bridge.ts +106 -0
  124. package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
  125. package/src/runtime/geometry/caret-geometry.ts +164 -0
  126. package/src/runtime/geometry/geometry-facet.ts +364 -0
  127. package/src/runtime/geometry/geometry-types.ts +256 -0
  128. package/src/runtime/geometry/hit-test.ts +125 -0
  129. package/src/runtime/geometry/index.ts +71 -0
  130. package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
  131. package/src/runtime/geometry/invalidation.ts +35 -0
  132. package/src/runtime/geometry/object-handles.ts +77 -0
  133. package/src/runtime/geometry/overlay-rects.ts +85 -0
  134. package/src/runtime/geometry/project-anchors.ts +100 -0
  135. package/src/runtime/geometry/project-fragments.ts +216 -0
  136. package/src/runtime/geometry/projector.ts +129 -0
  137. package/src/runtime/geometry/replacement-envelope.ts +130 -0
  138. package/src/runtime/geometry/viewport.ts +218 -0
  139. package/src/runtime/layout/compat-input-ledger.ts +211 -0
  140. package/src/runtime/layout/index.ts +6 -1
  141. package/src/runtime/layout/inert-layout-facet.ts +12 -7
  142. package/src/runtime/layout/layout-engine-instance.ts +189 -11
  143. package/src/runtime/layout/layout-engine-version.ts +450 -1
  144. package/src/runtime/layout/layout-facet-types.ts +60 -0
  145. package/src/runtime/layout/layout-measurement-provider.ts +13 -0
  146. package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
  147. package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
  148. package/src/runtime/layout/page-graph.ts +62 -209
  149. package/src/runtime/layout/page-story-resolver.ts +7 -12
  150. package/src/runtime/layout/paginated-layout-engine.ts +186 -11
  151. package/src/runtime/layout/project-block-fragments.ts +11 -0
  152. package/src/runtime/layout/projector.ts +90 -0
  153. package/src/runtime/layout/public-facet.ts +187 -442
  154. package/src/runtime/layout/resolved-formatting-state.ts +158 -26
  155. package/src/runtime/layout/table-render-plan.ts +1 -1
  156. package/src/runtime/prerender/cache-envelope.ts +6 -1
  157. package/src/runtime/prerender/prerender-document.ts +18 -23
  158. package/src/runtime/render/decoration-resolver.ts +1 -1
  159. package/src/runtime/render/render-frame-types.ts +20 -0
  160. package/src/runtime/render/render-kernel.ts +94 -25
  161. package/src/runtime/scopes/_formatting-seam.ts +262 -0
  162. package/src/runtime/scopes/_scope-dependencies.ts +49 -0
  163. package/src/runtime/scopes/action-validation.ts +356 -0
  164. package/src/runtime/scopes/attach-explanation.ts +102 -0
  165. package/src/runtime/scopes/audit-bundle.ts +71 -0
  166. package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
  167. package/src/runtime/scopes/compile-scope.ts +262 -0
  168. package/src/runtime/scopes/compiler-service.ts +431 -0
  169. package/src/runtime/scopes/create-issue.ts +107 -0
  170. package/src/runtime/scopes/enumerate-scopes.ts +543 -0
  171. package/src/runtime/scopes/evidence.ts +233 -0
  172. package/src/runtime/scopes/index.ts +150 -0
  173. package/src/runtime/scopes/position-map.ts +214 -0
  174. package/src/runtime/scopes/preservation-boundary.ts +91 -0
  175. package/src/runtime/scopes/projector.ts +49 -0
  176. package/src/runtime/scopes/replaceability.ts +87 -0
  177. package/src/runtime/scopes/replacement/apply.ts +228 -0
  178. package/src/runtime/scopes/replacement/compile.ts +59 -0
  179. package/src/runtime/scopes/replacement/propose.ts +42 -0
  180. package/src/runtime/scopes/resolve-reference.ts +347 -0
  181. package/src/runtime/scopes/review-bundle.ts +141 -0
  182. package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
  183. package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
  184. package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
  185. package/src/runtime/scopes/scope-kinds/field.ts +65 -0
  186. package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
  187. package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
  188. package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
  189. package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
  190. package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
  191. package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
  192. package/src/runtime/scopes/scope-kinds/table.ts +55 -0
  193. package/src/runtime/scopes/scope-range.ts +208 -0
  194. package/src/runtime/scopes/semantic-scope-types.ts +454 -0
  195. package/src/runtime/scopes/workflow-overlap.ts +92 -0
  196. package/src/runtime/selection/index.ts +1 -1
  197. package/src/runtime/structure-ops/fragment-insert.ts +1 -1
  198. package/src/runtime/structure-ops/index.ts +1 -1
  199. package/src/runtime/surface-projection.ts +232 -262
  200. package/src/runtime/units.ts +4 -2
  201. package/src/runtime/workflow/coordinator.ts +1348 -0
  202. package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
  203. package/src/runtime/workflow/index.ts +25 -0
  204. package/src/runtime/workflow/markup-mode-policy.ts +98 -0
  205. package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
  206. package/src/runtime/workflow/metadata-persistence.ts +306 -0
  207. package/src/runtime/workflow/metadata-writer.ts +123 -0
  208. package/src/runtime/workflow/overlay-store.ts +690 -0
  209. package/src/runtime/workflow/projector.ts +127 -0
  210. package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
  211. package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
  212. package/src/runtime/workflow/rail/types.ts +198 -0
  213. package/src/runtime/workflow/scope-rail-composer.ts +39 -0
  214. package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
  215. package/src/runtime/workflow/scope-writer.ts +188 -0
  216. package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
  217. package/src/runtime/workflow/visibility-policy.ts +129 -0
  218. package/src/session/_sync-legacy.ts +66 -0
  219. package/src/session/export/embedded-reconstitute.ts +104 -0
  220. package/src/session/export/export-diagnostics.ts +85 -0
  221. package/src/session/export/export-validation.ts +110 -0
  222. package/src/session/export/index.ts +34 -0
  223. package/src/session/export/preservation-reattach.ts +30 -0
  224. package/src/session/export/serialize-dispatch.ts +165 -0
  225. package/src/session/export/stateful-export-pipeline.ts +432 -0
  226. package/src/session/export/stateful-export.ts +684 -0
  227. package/src/session/import/canonical-assembly.ts +227 -0
  228. package/src/session/import/diagnostics-session.ts +54 -0
  229. package/src/session/import/embedded-discovery.ts +225 -0
  230. package/src/session/import/embedded-offload.ts +337 -0
  231. package/src/session/import/import-diagnostics.ts +69 -0
  232. package/src/session/import/loader-types.ts +313 -0
  233. package/src/session/import/loader.ts +1834 -0
  234. package/src/session/import/normalize.ts +195 -0
  235. package/src/session/import/package-parts.ts +217 -0
  236. package/src/session/import/package-read.ts +195 -0
  237. package/src/session/import/parse-orchestration.ts +105 -0
  238. package/src/session/import/part-constants.ts +70 -0
  239. package/src/session/import/part-discovery.ts +94 -0
  240. package/src/session/import/preservation-index.ts +46 -0
  241. package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
  242. package/src/session/import/review-import.ts +508 -0
  243. package/src/session/import/styles-consolidation.ts +281 -0
  244. package/src/session/import/workflow-scope-import.ts +256 -0
  245. package/src/session/index.ts +37 -0
  246. package/src/session/session-state.ts +69 -0
  247. package/src/session/session.ts +532 -0
  248. package/src/session/shared/protection.ts +228 -0
  249. package/src/session/shared/session-utils.ts +82 -0
  250. package/src/session/types.ts +499 -0
  251. package/src/shell/chart-snapshots.ts +96 -0
  252. package/src/shell/media-previews.ts +85 -0
  253. package/src/shell/overlay-anchor-bridge.ts +53 -0
  254. package/src/shell/paste-adapter.ts +23 -0
  255. package/src/shell/ref-commands.ts +1697 -0
  256. package/src/shell/ref-utilities.ts +48 -0
  257. package/src/shell/search.ts +51 -0
  258. package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
  259. package/src/shell/ui-subscriber-channels.ts +81 -0
  260. package/src/shell/use-collab-sync.ts +116 -0
  261. package/src/ui/WordReviewEditor.tsx +496 -2051
  262. package/src/ui/editor-shell-view.tsx +30 -1
  263. package/src/ui/editor-surface-controller.tsx +49 -1
  264. package/src/ui/headless/revision-decoration-model.ts +83 -0
  265. package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
  266. package/src/ui/headless/scoped-chrome-policy.ts +2 -2
  267. package/src/ui/headless/selection-tool-context.ts +1 -1
  268. package/src/ui/headless/selection-tool-resolver.ts +1 -1
  269. package/src/ui/runtime-shortcut-dispatch.ts +46 -1
  270. package/src/ui/ui-controller-factory.ts +221 -0
  271. package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
  272. package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
  273. package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
  274. package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
  275. package/src/ui-tailwind/chart/render/area.tsx +3 -3
  276. package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
  277. package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
  278. package/src/ui-tailwind/chart/render/combo.tsx +2 -2
  279. package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
  280. package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
  281. package/src/ui-tailwind/chart/render/line.tsx +3 -3
  282. package/src/ui-tailwind/chart/render/pie.tsx +6 -6
  283. package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
  284. package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
  285. package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
  286. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
  287. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
  288. package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
  289. package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
  290. package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
  291. package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
  292. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
  293. package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
  294. package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
  295. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
  296. package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
  297. package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
  298. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
  299. package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
  300. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
  301. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
  302. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
  303. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
  304. package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
  305. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
  306. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
  307. package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
  308. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
  309. package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
  310. package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
  311. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
  312. package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
  313. package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
  314. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
  315. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
  316. package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
  317. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
  318. package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
  319. package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
  320. package/src/ui-tailwind/debug/README.md +57 -0
  321. package/src/ui-tailwind/debug/index.ts +3 -0
  322. package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
  323. package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
  324. package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
  325. package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
  326. package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
  327. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
  328. package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
  329. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
  330. package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
  331. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
  332. package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
  333. package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
  334. package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
  335. package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
  336. package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
  337. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
  338. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
  339. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
  340. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
  341. package/src/ui-tailwind/index.ts +0 -5
  342. package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
  343. package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
  344. package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
  345. package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
  346. package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
  347. package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
  348. package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
  349. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
  350. package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
  351. package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
  352. package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
  353. package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
  354. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
  355. package/src/ui-tailwind/review-workspace/types.ts +408 -0
  356. package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
  357. package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
  358. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
  359. package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
  360. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
  361. package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
  362. package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
  363. package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
  364. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
  365. package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
  366. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
  367. package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
  368. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
  369. package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
  370. package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
  371. package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
  372. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
  373. package/src/ui-tailwind/theme/editor-theme.css +25 -0
  374. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
  375. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
  376. package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
  377. package/src/ui-tailwind/ui-api-context.tsx +43 -0
  378. package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
  379. package/src/validation/compatibility-engine.ts +6 -6
  380. package/src/runtime/styles-cascade.ts +0 -33
  381. package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
  382. /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
  383. /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
  384. /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
@@ -15,6 +15,7 @@ import type {
15
15
  import type {
16
16
  CanonicalDocument as CanonicalDocumentEnvelope,
17
17
  ColumnProperties,
18
+ MutableCanonicalDocument,
18
19
  PageMargins,
19
20
  PageNumbering,
20
21
  PageSize,
@@ -128,7 +129,7 @@ export function insertSectionBreak(
128
129
  breakType: SectionBreakType,
129
130
  _context: SectionLayoutCommandContext,
130
131
  ): SectionLayoutMutationResult {
131
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
132
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
132
133
  const surface = snapshot.surface;
133
134
 
134
135
  if (!surface) {
@@ -168,7 +169,7 @@ export function insertSectionBreakAfterSectionIndex(
168
169
  breakType: SectionBreakType,
169
170
  context: SectionLayoutCommandContext,
170
171
  ): SectionLayoutMutationResult {
171
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
172
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
172
173
  const insertionIndex = findSectionInsertionIndex(cloned, sectionIndex);
173
174
  if (insertionIndex < 0) {
174
175
  return noopResult(document, createSelectionSnapshot(0, 0));
@@ -207,7 +208,7 @@ export function deleteSectionBreak(
207
208
  snapshot: RuntimeRenderSnapshot,
208
209
  _context: SectionLayoutCommandContext,
209
210
  ): SectionLayoutMutationResult {
210
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
211
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
211
212
 
212
213
  const breakIndex = findNearestSectionBreak(cloned, snapshot);
213
214
  if (breakIndex < 0) {
@@ -240,7 +241,7 @@ export function deleteSectionBreakAtSectionIndex(
240
241
  return noopResult(document, createSelectionSnapshot(0, 0));
241
242
  }
242
243
 
243
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
244
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
244
245
  const breakIndex = findSectionBreakNodeIndexForSection(cloned, sectionIndex);
245
246
  if (breakIndex < 0) {
246
247
  return noopResult(document, createSelectionSnapshot(0, 0));
@@ -269,7 +270,7 @@ export function updateSectionLayout(
269
270
  patch: SectionLayoutPatch,
270
271
  _context: SectionLayoutCommandContext,
271
272
  ): SectionLayoutMutationResult {
272
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
273
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
273
274
  const surface = snapshot.surface;
274
275
 
275
276
  if (!surface) {
@@ -317,7 +318,7 @@ export function updateSectionLayoutAtSectionIndex(
317
318
  patch: SectionLayoutPatch,
318
319
  context: SectionLayoutCommandContext,
319
320
  ): SectionLayoutMutationResult {
320
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
321
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
321
322
  const target = resolveSectionPropertiesOwner(cloned, sectionIndex);
322
323
  if (!target) {
323
324
  return noopResult(document, createSelectionSnapshot(0, 0));
@@ -355,7 +356,7 @@ export function setSectionPageNumberingAtSectionIndex(
355
356
  pageNumbering: Partial<PageNumbering> | null,
356
357
  context: SectionLayoutCommandContext,
357
358
  ): SectionLayoutMutationResult {
358
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
359
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
359
360
  const target = resolveSectionPropertiesOwner(cloned, sectionIndex);
360
361
  if (!target) {
361
362
  return noopResult(document, createSelectionSnapshot(0, 0));
@@ -402,7 +403,7 @@ export function setHeaderFooterLinkAtSectionIndex(
402
403
  patch: SectionLinkPatch,
403
404
  context: SectionLayoutCommandContext,
404
405
  ): SectionLayoutMutationResult {
405
- const cloned = structuredClone(document) as CanonicalDocumentEnvelope;
406
+ const cloned = structuredClone(document) as MutableCanonicalDocument;
406
407
  const target = resolveSectionPropertiesOwner(cloned, sectionIndex);
407
408
  if (!target) {
408
409
  return noopResult(document, createSelectionSnapshot(0, 0));
@@ -11,6 +11,13 @@ import type {
11
11
  export interface ParagraphProperties {
12
12
  styleId?: string;
13
13
  numbering?: ParagraphNode["numbering"];
14
+ /**
15
+ * w14:paraId / w14:textId — stable across reopen. Must round-trip
16
+ * through the text-transaction rebuild so paragraph-kind scope ids
17
+ * (see `src/runtime/scopes/enumerate-scopes.ts:204`) survive a text
18
+ * replace. Fix for coord-08 §11 / harness finding B2.
19
+ */
20
+ wordExtensionIds?: ParagraphNode["wordExtensionIds"];
14
21
  }
15
22
 
16
23
  export interface TextStory {
@@ -451,6 +458,9 @@ export function cloneParagraphProperties(
451
458
  },
452
459
  }
453
460
  : {}),
461
+ ...(properties.wordExtensionIds
462
+ ? { wordExtensionIds: { ...properties.wordExtensionIds } }
463
+ : {}),
454
464
  };
455
465
  }
456
466
 
@@ -553,6 +563,9 @@ function extractParagraphProperties(paragraph: ParagraphNode): ParagraphProperti
553
563
  },
554
564
  }
555
565
  : {}),
566
+ ...(paragraph.wordExtensionIds
567
+ ? { wordExtensionIds: { ...paragraph.wordExtensionIds } }
568
+ : {}),
556
569
  };
557
570
  }
558
571
 
@@ -568,6 +581,9 @@ function createParagraph(properties: ParagraphProperties): ParagraphNode {
568
581
  },
569
582
  }
570
583
  : {}),
584
+ ...(properties.wordExtensionIds
585
+ ? { wordExtensionIds: { ...properties.wordExtensionIds } }
586
+ : {}),
571
587
  children: [],
572
588
  };
573
589
  }
@@ -1,54 +1,37 @@
1
1
  import type { EditorStoryTarget } from "../../api/public-types";
2
-
3
- export type Position = number;
4
- export type Assoc = -1 | 1;
5
-
6
- export interface DocRange {
7
- from: Position;
8
- to: Position;
9
- }
10
-
11
- export interface BoundaryAssoc {
12
- start: Assoc;
13
- end: Assoc;
14
- }
15
-
16
- export interface RangeAnchor {
17
- kind: "range";
18
- range: DocRange;
19
- assoc: BoundaryAssoc;
20
- }
21
-
22
- export interface NodeAnchor {
23
- kind: "node";
24
- at: Position;
25
- assoc: Assoc;
26
- }
27
-
28
- export interface DetachedAnchor {
29
- kind: "detached";
30
- lastKnownRange: DocRange;
31
- reason: "deleted" | "invalidatedByStructureChange" | "importAmbiguity";
32
- }
33
-
34
- /**
35
- * Internal representation of an anchor projection — uses `DocRange` so
36
- * mapping helpers compose ranges independently of assoc semantics. The
37
- * public-facing shape lives at `src/api/public-types.ts` (same simple name
38
- * `EditorAnchorProjection`) and is flat (`{ kind: "range", from, to, assoc }`).
39
- * Conversion between the two goes through `src/core/selection/anchor-conversion.ts`.
40
- */
41
- export type InternalEditorAnchorProjection = RangeAnchor | NodeAnchor | DetachedAnchor;
42
-
43
- /**
44
- * @deprecated X3 Phase 5 — prefer `InternalEditorAnchorProjection` to avoid
45
- * name-collision with the public `EditorAnchorProjection` from
46
- * `src/api/public-types.ts`. Internal call-sites have migrated (via
47
- * `import type { EditorAnchorProjection as InternalEditorAnchorProjection }`
48
- * aliasing in `document-runtime.ts`). This alias stays for one release cycle
49
- * so third-party internal consumers don't break. Remove in v2.1+.
50
- */
51
- export type EditorAnchorProjection = InternalEditorAnchorProjection;
2
+ import {
3
+ createDetachedAnchor,
4
+ DEFAULT_BOUNDARY_ASSOC,
5
+ normalizeRange,
6
+ type Assoc,
7
+ type BoundaryAssoc,
8
+ type DetachedAnchor,
9
+ type DocRange,
10
+ type EditorAnchorProjection,
11
+ type InternalEditorAnchorProjection,
12
+ type NodeAnchor,
13
+ type Position,
14
+ type RangeAnchor,
15
+ } from "../../model/anchor.ts";
16
+
17
+ // Anchor data shapes + pure factories live at `src/model/anchor.ts`.
18
+ // Re-exported here for back-compat with every site that already imports
19
+ // anchor types / createDetachedAnchor from `core/selection/mapping`. The
20
+ // mapping machinery below operates on them.
21
+ export {
22
+ createDetachedAnchor,
23
+ DEFAULT_BOUNDARY_ASSOC,
24
+ normalizeRange,
25
+ type Assoc,
26
+ type BoundaryAssoc,
27
+ type DetachedAnchor,
28
+ type DocRange,
29
+ type EditorAnchorProjection,
30
+ type InternalEditorAnchorProjection,
31
+ type NodeAnchor,
32
+ type Position,
33
+ type RangeAnchor,
34
+ };
52
35
 
53
36
  export interface MappingStep {
54
37
  from: Position;
@@ -78,11 +61,6 @@ export interface TransactionMapping {
78
61
  };
79
62
  }
80
63
 
81
- export const DEFAULT_BOUNDARY_ASSOC: BoundaryAssoc = {
82
- start: 1,
83
- end: -1,
84
- };
85
-
86
64
  export function createRangeAnchor(
87
65
  from: Position,
88
66
  to = from,
@@ -103,29 +81,12 @@ export function createNodeAnchor(at: Position, assoc: Assoc = 1): NodeAnchor {
103
81
  };
104
82
  }
105
83
 
106
- export function createDetachedAnchor(
107
- lastKnownRange: DocRange,
108
- reason: DetachedAnchor["reason"],
109
- ): DetachedAnchor {
110
- return {
111
- kind: "detached",
112
- lastKnownRange: normalizeRange(lastKnownRange),
113
- reason,
114
- };
115
- }
116
-
117
84
  export function createEmptyMapping(): TransactionMapping {
118
85
  return {
119
86
  steps: [],
120
87
  };
121
88
  }
122
89
 
123
- export function normalizeRange(range: DocRange): DocRange {
124
- return range.from <= range.to
125
- ? { from: range.from, to: range.to }
126
- : { from: range.to, to: range.from };
127
- }
128
-
129
90
  export function getEffectiveRange(anchor: EditorAnchorProjection): DocRange {
130
91
  if (anchor.kind === "range") {
131
92
  return anchor.range;
@@ -3,9 +3,14 @@ import {
3
3
  createDetachedAnchor,
4
4
  createNodeAnchor,
5
5
  createRangeAnchor,
6
- type EditorAnchorProjection,
6
+ type EditorAnchorProjection as InternalEditorAnchorProjection,
7
7
  } from "../selection/mapping.ts";
8
- import { isUuid } from "../../model/cds-1.0.0.ts";
8
+ import {
9
+ createPublicDetachedAnchor,
10
+ createPublicNodeAnchor,
11
+ createPublicRangeAnchor,
12
+ } from "../selection/anchor-conversion.ts";
13
+ import type { EditorAnchorProjection } from "../../api/public-types.ts";
9
14
  import {
10
15
  assertPersistedEditorSnapshot as assertModelPersistedEditorSnapshot,
11
16
  createPersistedEditorSnapshot as createModelPersistedEditorSnapshot,
@@ -15,6 +20,9 @@ import {
15
20
  } from "../../model/snapshot.ts";
16
21
  import {
17
22
  assertCanonicalDocument,
23
+ createCanonicalDocumentId,
24
+ createEmptyCanonicalDocument as createEmptyCanonicalDocumentModel,
25
+ repairCanonicalDocumentEnvelope,
18
26
  type CanonicalDocument,
19
27
  type CommentEntry as ModelCommentEntry,
20
28
  type CommentResolution as ModelCommentResolution,
@@ -23,75 +31,53 @@ import {
23
31
  type RevisionRecord as ModelRevisionRecord,
24
32
  } from "../../model/canonical-document.ts";
25
33
 
34
+ export { createCanonicalDocumentId };
35
+
26
36
  export type RuntimePhase = "loading" | "ready" | "error";
27
- export type EditorWarningCode =
28
- | "unsupported_ooxml_preserved"
29
- | "unsupported_ooxml_locked"
30
- | "import_normalized"
31
- | "export_roundtrip_risk"
32
- | "comment_anchor_detached"
33
- | "revision_anchor_detached"
34
- | "workflow_scope_invalidated"
35
- | "large_document_degraded"
36
- | "font_substitution"
37
- | "image_missing"
38
- | "review_target_not_found";
39
-
40
- export interface EditorWarning {
41
- warningId: string;
42
- code: EditorWarningCode;
43
- severity: "info" | "warning";
44
- message: string;
45
- source:
46
- | "import"
47
- | "runtime"
48
- | "review"
49
- | "preservation"
50
- | "validation"
51
- | "export";
52
- affectedAnchor?: EditorAnchorProjection;
53
- featureEntryId?: string;
54
- details?: Record<string, unknown>;
55
- diagnostic?: import("../../api/public-types.ts").EditorDiagnostic;
56
- }
57
-
58
- export interface EditorError {
59
- errorId: string;
60
- code:
61
- | "import_failed"
62
- | "export_failed"
63
- | "package_corrupt"
64
- | "validation_failed"
65
- | "datastore_failed"
66
- | "internal_invariant";
67
- message: string;
68
- isFatal: boolean;
69
- source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
70
- details?: Record<string, unknown>;
71
- }
72
-
73
- export type CompatibilityFeatureClass =
74
- | "supported-roundtrip"
75
- | "preserve-only"
76
- | "unsupported-fatal";
77
-
78
- export interface CompatibilityFeatureEntry {
79
- featureEntryId: string;
80
- featureKey: string;
81
- featureClass: CompatibilityFeatureClass;
82
- message: string;
83
- affectedAnchor?: EditorAnchorProjection;
84
- details?: Record<string, unknown>;
85
- }
86
-
87
- export interface CompatibilityReport {
88
- reportVersion: "compatibility-report/1";
89
- generatedAt: string;
90
- blockExport: boolean;
91
- featureEntries: CompatibilityFeatureEntry[];
92
- warnings: EditorWarning[];
93
- errors: EditorError[];
94
- }
37
+
38
+ /**
39
+ * Review-record types — `EditorWarning`, `EditorError`,
40
+ * `CompatibilityFeatureEntry`, `CompatibilityReport`,
41
+ * `CompatibilityFeatureClass`, and the code enums — are re-exports of
42
+ * the public shapes in `src/api/public-types.ts`. Until 2026-04-22 the
43
+ * runtime held distinct `Internal*`-flavored copies that differed from
44
+ * the public types *only* on `affectedAnchor` (nested
45
+ * `{range: {from, to}}` vs flat `{from, to}`). That drift forced
46
+ * `src/api/diagnostic-conversion.ts` at every boundary between the
47
+ * runtime and the public API.
48
+ *
49
+ * Resolution: flatten at the **record-attachment boundary**. Internal
50
+ * code that constructs records with nested anchors now wraps with
51
+ * `createPublicRangeAnchor` / `toPublicAnchorProjection` at the
52
+ * construction site — the resulting record carries a flat anchor
53
+ * end-to-end. The nested shape remains the authoritative mapping-
54
+ * composition format inside `src/core/selection/mapping.ts`; the flat
55
+ * shape is the record-attachment format. `src/core/selection/anchor-
56
+ * conversion.ts` is kept as the named seam; `src/api/diagnostic-
57
+ * conversion.ts` was deleted because the record-type conversion
58
+ * became identity.
59
+ *
60
+ * See `docs/plans/cross-layer-coord-02.md §8`.
61
+ */
62
+ import type {
63
+ EditorWarning,
64
+ EditorError,
65
+ EditorWarningCode,
66
+ EditorErrorCode,
67
+ CompatibilityFeatureClass,
68
+ CompatibilityFeatureEntry,
69
+ CompatibilityReport,
70
+ } from "../../api/public-types.ts";
71
+
72
+ export type {
73
+ EditorWarning,
74
+ EditorError,
75
+ EditorWarningCode,
76
+ EditorErrorCode,
77
+ CompatibilityFeatureClass,
78
+ CompatibilityFeatureEntry,
79
+ CompatibilityReport,
80
+ };
95
81
 
96
82
  export type CommentEntryRecord = ModelCommentEntry;
97
83
  export type CommentResolutionRecord = ModelCommentResolution;
@@ -105,7 +91,15 @@ export interface SelectionSnapshot {
105
91
  anchor: number;
106
92
  head: number;
107
93
  isCollapsed: boolean;
108
- activeRange: EditorAnchorProjection;
94
+ /**
95
+ * Internal nested-range shape (`{kind:"range", range:{from,to}, assoc}`).
96
+ * SelectionSnapshot is runtime-internal state used for mapping composition
97
+ * through `src/core/selection/mapping.ts`; the nested shape is load-bearing
98
+ * for `DocRange`-unit remap helpers. Public surfaces that expose a
99
+ * selection convert to the public flat shape via `toPublicAnchorProjection`
100
+ * at the boundary.
101
+ */
102
+ activeRange: InternalEditorAnchorProjection;
109
103
  }
110
104
 
111
105
  export interface DocumentStats {
@@ -218,40 +212,16 @@ export function createDefaultCanonicalDocument(
218
212
  documentId: string,
219
213
  timestamp: string,
220
214
  ): CanonicalDocumentEnvelope {
221
- return {
222
- schemaVersion: "cds/1.0.0",
215
+ // Thin wrapper around the model-layer factory. The canonical shape of
216
+ // "an empty document" belongs to Layer 02 so every construction path
217
+ // agrees on the default envelope; this file's remaining responsibility
218
+ // is to derive a stable per-session `docId` from the host's
219
+ // `documentId` (not a model concern — the hash is a session-layer
220
+ // convention that happens to resolve to a UUID-shaped string).
221
+ return createEmptyCanonicalDocumentModel({
223
222
  docId: createCanonicalDocumentId(documentId),
224
223
  createdAt: timestamp,
225
- updatedAt: timestamp,
226
- metadata: {
227
- customProperties: {},
228
- },
229
- styles: {
230
- paragraphs: {},
231
- characters: {},
232
- tables: {},
233
- },
234
- numbering: {
235
- abstractDefinitions: {},
236
- instances: {},
237
- },
238
- media: {
239
- items: {},
240
- },
241
- content: {
242
- type: "doc",
243
- children: [{ type: "paragraph", children: [] }],
244
- },
245
- review: createEmptyReviewStore(),
246
- preservation: {
247
- opaqueFragments: {},
248
- packageParts: {},
249
- },
250
- diagnostics: {
251
- warnings: [],
252
- errors: [],
253
- },
254
- };
224
+ });
255
225
  }
256
226
 
257
227
  export function createSelectionSnapshot(anchor = 0, head = anchor): SelectionSnapshot {
@@ -385,63 +355,16 @@ function normalizeCanonicalDocumentEnvelope(
385
355
  documentId: string,
386
356
  timestamp: string,
387
357
  ): CanonicalDocumentEnvelope {
388
- const base = createDefaultCanonicalDocument(documentId, timestamp);
389
- const record = isRecord(value) ? value : {};
390
- const metadata = isRecord(record.metadata) ? record.metadata : {};
391
-
392
- return {
393
- ...base,
394
- ...record,
395
- schemaVersion: "cds/1.0.0",
396
- docId: isUuid(record.docId) ? record.docId : createCanonicalDocumentId(documentId),
397
- createdAt:
398
- typeof record.createdAt === "string" && record.createdAt.length > 0
399
- ? record.createdAt
400
- : base.createdAt,
401
- updatedAt:
402
- typeof record.updatedAt === "string" && record.updatedAt.length > 0
403
- ? record.updatedAt
404
- : base.updatedAt,
405
- metadata: {
406
- ...base.metadata,
407
- ...metadata,
408
- customProperties: isRecord(metadata.customProperties)
409
- ? (Object.fromEntries(
410
- Object.entries(metadata.customProperties).filter(([, entry]) => typeof entry === "string"),
411
- ) as Record<string, string>)
412
- : {},
413
- },
414
- styles:
415
- record.styles === undefined
416
- ? base.styles
417
- : (record.styles as CanonicalDocumentEnvelope["styles"]),
418
- numbering:
419
- record.numbering === undefined
420
- ? base.numbering
421
- : (record.numbering as CanonicalDocumentEnvelope["numbering"]),
422
- media:
423
- record.media === undefined
424
- ? base.media
425
- : (record.media as CanonicalDocumentEnvelope["media"]),
426
- content: isRecord(record.content)
427
- ? (record.content as unknown as CanonicalDocumentEnvelope["content"])
428
- : base.content,
429
- review:
430
- record.review === undefined
431
- ? base.review
432
- : (record.review as CanonicalDocumentEnvelope["review"]),
433
- preservation:
434
- record.preservation === undefined
435
- ? base.preservation
436
- : (record.preservation as CanonicalDocumentEnvelope["preservation"]),
437
- diagnostics:
438
- record.diagnostics === undefined
439
- ? base.diagnostics
440
- : (record.diagnostics as CanonicalDocumentEnvelope["diagnostics"]),
441
- ...(isRecord(record.subParts)
442
- ? { subParts: record.subParts as unknown as CanonicalDocumentEnvelope["subParts"] }
443
- : {}),
444
- };
358
+ // Delegated to the model layer so the repair path recognises every
359
+ // optional field the canonical envelope actually owns — `subParts`,
360
+ // `fieldRegistry`, and `fontTable`. The previous local copy dropped
361
+ // `fieldRegistry` and `fontTable`, which silently lost canonical data
362
+ // on any load-persist-reload cycle.
363
+ return repairCanonicalDocumentEnvelope(value, {
364
+ fallbackDocId: createCanonicalDocumentId(documentId),
365
+ fallbackCreatedAt: timestamp,
366
+ fallbackUpdatedAt: timestamp,
367
+ });
445
368
  }
446
369
 
447
370
  function coerceCompatibilityReport(
@@ -692,6 +615,14 @@ function normalizeCompatibilityReport(report: CompatibilityReport): Compatibilit
692
615
  };
693
616
  }
694
617
 
618
+ /**
619
+ * Defensive anchor-projection normalizer — accepts either shape
620
+ * (public flat `{kind:"range", from, to, assoc}` *or* legacy nested
621
+ * `{kind:"range", range:{from,to}, assoc}` from pre-2026-04-22
622
+ * snapshots) and returns the canonical public flat shape. Records
623
+ * carry flat anchors by contract, but this normalizer still copes with
624
+ * the nested shape from older persisted snapshots.
625
+ */
695
626
  function normalizeAnchorProjection(anchor: EditorAnchorProjection): EditorAnchorProjection {
696
627
  switch (anchor.kind) {
697
628
  case "range": {
@@ -702,13 +633,13 @@ function normalizeAnchorProjection(anchor: EditorAnchorProjection): EditorAnchor
702
633
  assoc: { start: -1 | 1; end: -1 | 1 };
703
634
  };
704
635
  return rangeAnchor.range
705
- ? createRangeAnchor(rangeAnchor.range.from, rangeAnchor.range.to, rangeAnchor.assoc)
706
- : createRangeAnchor(rangeAnchor.from ?? 0, rangeAnchor.to ?? 0, rangeAnchor.assoc);
636
+ ? createPublicRangeAnchor(rangeAnchor.range.from, rangeAnchor.range.to, rangeAnchor.assoc)
637
+ : createPublicRangeAnchor(rangeAnchor.from ?? 0, rangeAnchor.to ?? 0, rangeAnchor.assoc);
707
638
  }
708
639
  case "node":
709
- return createNodeAnchor(anchor.at, anchor.assoc);
640
+ return createPublicNodeAnchor(anchor.at, anchor.assoc);
710
641
  case "detached":
711
- return createDetachedAnchor(anchor.lastKnownRange, anchor.reason);
642
+ return createPublicDetachedAnchor(anchor.lastKnownRange, anchor.reason);
712
643
  }
713
644
  }
714
645
 
@@ -735,30 +666,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
735
666
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
736
667
  }
737
668
 
738
- export function createCanonicalDocumentId(documentId: string): string {
739
- const hashWord = (seed: string): string => {
740
- let hash = 0x811c9dc5;
741
- for (const char of seed) {
742
- hash ^= char.charCodeAt(0);
743
- hash = Math.imul(hash, 0x01000193);
744
- }
745
- return (hash >>> 0).toString(16).padStart(8, "0");
746
- };
747
-
748
- const raw =
749
- hashWord(`${documentId}:0`) +
750
- hashWord(`${documentId}:1`) +
751
- hashWord(`${documentId}:2`) +
752
- hashWord(`${documentId}:3`);
753
-
754
- return [
755
- raw.slice(0, 8),
756
- raw.slice(8, 12),
757
- `4${raw.slice(13, 16)}`,
758
- `8${raw.slice(17, 20)}`,
759
- raw.slice(20, 32),
760
- ].join("-");
761
- }
762
669
 
763
670
  export function normalizeCommentThreadRecord(value: unknown): CommentThreadRecord {
764
671
  const record = isRecord(value) ? value : {};
@@ -858,7 +765,7 @@ export function normalizeCommentThreadRecord(value: unknown): CommentThreadRecor
858
765
  : "comment-generated",
859
766
  anchor:
860
767
  isRecord(record.anchor) && typeof record.anchor.kind === "string"
861
- ? (record.anchor as unknown as EditorAnchorProjection)
768
+ ? (record.anchor as unknown as InternalEditorAnchorProjection)
862
769
  : createDetachedAnchor({ from: 0, to: 0 }, "importAmbiguity"),
863
770
  createdAt,
864
771
  createdBy: authorId,
package/src/index.ts CHANGED
@@ -7,19 +7,38 @@ export {
7
7
  validateEditorSessionState,
8
8
  EDITOR_SESSION_STATE_VERSION,
9
9
  } from "./api/session-state.ts";
10
+
11
+ // Layer 01 — package/session seam. Host consumers open documents
12
+ // through this class rather than reaching into `src/io/docx-session.ts`.
13
+ // See `docs/architecture/01-package-session.md` § Public entry points.
14
+ export {
15
+ DocxSession,
16
+ SessionNotOpenError,
17
+ SessionNotWiredError,
18
+ } from "./session/index.ts";
19
+ export type {
20
+ OpenOptions,
21
+ OpenResult,
22
+ ExportOptions,
23
+ ValidateOptions,
24
+ ValidationReport,
25
+ ValidationFinding,
26
+ PreservationSnapshot,
27
+ EmbeddedDocumentManifest,
28
+ } from "./session/index.ts";
10
29
  // R2 — issue metadata id for scope-card-overlay P1.
11
30
  // K1-light — review-action metadata id for scope-card-overlay P2.
12
31
  export { ISSUE_METADATA_ID, REVIEW_ACTION_METADATA_ID } from "./api/public-types.ts";
13
32
  // P17 — metadata persistence error class.
14
33
  export { MetadataResolverMissingError } from "./api/public-types.ts";
15
34
 
16
- // Collab substrate (P1 – P8f + P14). See docs/plans/lane-4-collab-clm-vallor.md
35
+ // Collab substrate (P1 – P8f + P14). See CLAUDE.md (lane status table)
17
36
  // for the shipped-slice table. Surfaces are stable for host integration;
18
37
  // the chrome preset + markdown renderer land in P9 / P10.
19
38
  export { createCollabSession } from "./runtime/collab-session.ts";
20
39
  export { createCollabSessionBridge } from "./runtime/collab-session-bridge.ts";
21
40
  export { createCollabSessionFacet } from "./runtime/collab-session-facet.ts";
22
- export { createTamperGate } from "./runtime/tamper-gate.ts";
41
+ export { createTamperGate } from "./runtime/workflow/tamper-gate.ts";
23
42
  export { resignPayload } from "./runtime/resign-payload.ts";
24
43
  export {
25
44
  setLocalIdentity,
@@ -61,7 +80,7 @@ export type {
61
80
  TamperGateArgs,
62
81
  AttachArgs as TamperGateAttachArgs,
63
82
  GuardResult as TamperGateGuardResult,
64
- } from "./runtime/tamper-gate.ts";
83
+ } from "./runtime/workflow/tamper-gate.ts";
65
84
  export type {
66
85
  RuntimeSendToExternalArgs,
67
86
  RuntimeSendToExternalResult,
@@ -309,7 +328,7 @@ export type {
309
328
  // L7 Phase 2.5 — prerender cache public API. Platforms / ingest workers
310
329
  // call `prerenderDocument(buffer)` on template upload to populate the
311
330
  // cache; end-user opens read the cache and skip the layout pass. See
312
- // docs/plans/lane-2-render-performance.md §Phase 2.5.
331
+ // CLAUDE.md (lane status table) §Phase 2.5.
313
332
  export { prerenderDocument } from "./runtime/prerender/prerender-document.ts";
314
333
  export type {
315
334
  PrerenderOptions,
@@ -13,7 +13,7 @@
13
13
  * (runs at import time only) so §Performance Invariants in CLAUDE.md
14
14
  * about synchronous layout reads do not apply.
15
15
  *
16
- * See docs/plans/lane-5-charts.md §2 Task 2.
16
+ * See CLAUDE.md (lane status table) §2 Task 2.
17
17
  */
18
18
 
19
19
  import type {