@beyondwork/docx-react-component 1.0.105 → 1.0.108

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 (193) hide show
  1. package/package.json +19 -5
  2. package/src/api/geometry-overlay-rects.ts +5 -0
  3. package/src/api/package-version.ts +1 -1
  4. package/src/api/page-anchor-id.ts +5 -0
  5. package/src/api/public-types.ts +16 -9
  6. package/src/api/table-node-specs.ts +6 -0
  7. package/src/api/v3/_create.ts +10 -2
  8. package/src/api/v3/_page-anchor-id.ts +52 -0
  9. package/src/api/v3/_runtime-handle.ts +92 -1
  10. package/src/api/v3/ai/_audit-reference.ts +28 -0
  11. package/src/api/v3/ai/_audit-time.ts +5 -0
  12. package/src/api/v3/ai/_pe2-evidence.ts +310 -6
  13. package/src/api/v3/ai/attach.ts +29 -4
  14. package/src/api/v3/ai/bundle.ts +6 -2
  15. package/src/api/v3/ai/inspect.ts +6 -2
  16. package/src/api/v3/ai/replacement.ts +112 -18
  17. package/src/api/v3/ai/resolve.ts +2 -2
  18. package/src/api/v3/ai/review.ts +177 -3
  19. package/src/api/v3/index.ts +8 -0
  20. package/src/api/v3/runtime/collab.ts +462 -0
  21. package/src/api/v3/runtime/document.ts +503 -20
  22. package/src/api/v3/runtime/geometry.ts +97 -0
  23. package/src/api/v3/runtime/layout.ts +744 -0
  24. package/src/api/v3/runtime/perf-probe.ts +14 -0
  25. package/src/api/v3/runtime/viewport.ts +9 -8
  26. package/src/api/v3/ui/_types.ts +202 -55
  27. package/src/api/v3/ui/chrome-preset-model.ts +5 -5
  28. package/src/api/v3/ui/debug.ts +115 -2
  29. package/src/api/v3/ui/index.ts +17 -0
  30. package/src/api/v3/ui/overlays.ts +0 -8
  31. package/src/api/v3/ui/surface.ts +56 -0
  32. package/src/api/v3/ui/viewport.ts +119 -9
  33. package/src/core/commands/image-commands.ts +1 -0
  34. package/src/core/commands/index.ts +6 -0
  35. package/src/core/schema/text-schema.ts +43 -5
  36. package/src/core/selection/mapping.ts +8 -1
  37. package/src/core/selection/review-anchors.ts +5 -1
  38. package/src/core/state/text-transaction.ts +8 -2
  39. package/src/io/export/serialize-revisions.ts +149 -1
  40. package/src/io/normalize/normalize-text.ts +6 -0
  41. package/src/io/ooxml/parse-bookmark-references.ts +55 -0
  42. package/src/io/ooxml/parse-fields.ts +24 -2
  43. package/src/io/ooxml/parse-headers-footers.ts +38 -5
  44. package/src/io/ooxml/parse-main-document.ts +153 -9
  45. package/src/io/ooxml/parse-numbering.ts +20 -0
  46. package/src/io/ooxml/parse-revisions.ts +19 -8
  47. package/src/io/opc/package-reader.ts +98 -8
  48. package/src/model/anchor.ts +4 -3
  49. package/src/model/canonical-document.ts +220 -2
  50. package/src/model/canonical-hash.ts +221 -0
  51. package/src/model/canonical-layout-inputs.ts +245 -6
  52. package/src/model/layout/index.ts +1 -0
  53. package/src/model/layout/page-graph-types.ts +147 -1
  54. package/src/model/review/revision-types.ts +14 -3
  55. package/src/preservation/store.ts +20 -4
  56. package/src/review/README.md +1 -1
  57. package/src/review/store/revision-actions.ts +14 -2
  58. package/src/runtime/collab/event-types.ts +67 -1
  59. package/src/runtime/collab/runtime-collab-sync.ts +177 -5
  60. package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
  61. package/src/runtime/document-heading-outline.ts +147 -0
  62. package/src/runtime/document-navigation.ts +8 -243
  63. package/src/runtime/document-runtime.ts +279 -115
  64. package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
  65. package/src/runtime/formatting/layout-inputs.ts +38 -5
  66. package/src/runtime/formatting/numbering/geometry.ts +28 -2
  67. package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
  68. package/src/runtime/geometry/caret-geometry.ts +5 -6
  69. package/src/runtime/geometry/geometry-facet.ts +60 -10
  70. package/src/runtime/geometry/geometry-index.ts +661 -16
  71. package/src/runtime/geometry/geometry-types.ts +59 -0
  72. package/src/runtime/geometry/hit-test.ts +11 -1
  73. package/src/runtime/geometry/overlay-rects.ts +5 -3
  74. package/src/runtime/geometry/project-anchors.ts +1 -1
  75. package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
  76. package/src/runtime/layout/index.ts +6 -0
  77. package/src/runtime/layout/layout-engine-instance.ts +6 -1
  78. package/src/runtime/layout/layout-engine-version.ts +188 -16
  79. package/src/runtime/layout/layout-facet-types.ts +6 -0
  80. package/src/runtime/layout/page-graph.ts +23 -4
  81. package/src/runtime/layout/paginated-layout-engine.ts +149 -15
  82. package/src/runtime/layout/project-block-fragments.ts +351 -14
  83. package/src/runtime/layout/public-facet.ts +162 -24
  84. package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
  85. package/src/runtime/layout/table-row-split.ts +92 -35
  86. package/src/runtime/prerender/cache-envelope.ts +2 -2
  87. package/src/runtime/prerender/cache-key.ts +5 -4
  88. package/src/runtime/prerender/customxml-cache.ts +0 -1
  89. package/src/runtime/render/render-kernel.ts +1 -1
  90. package/src/runtime/revision-runtime.ts +112 -10
  91. package/src/runtime/scopes/_scope-dependencies.ts +1 -0
  92. package/src/runtime/scopes/action-validation.ts +22 -2
  93. package/src/runtime/scopes/capabilities.ts +316 -0
  94. package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
  95. package/src/runtime/scopes/compiler-service.ts +108 -4
  96. package/src/runtime/scopes/content-control-evidence.ts +79 -0
  97. package/src/runtime/scopes/create-issue.ts +5 -5
  98. package/src/runtime/scopes/evidence.ts +91 -0
  99. package/src/runtime/scopes/formatting/apply.ts +2 -0
  100. package/src/runtime/scopes/geometry-evidence.ts +130 -0
  101. package/src/runtime/scopes/index.ts +54 -0
  102. package/src/runtime/scopes/issue-lifecycle.ts +224 -0
  103. package/src/runtime/scopes/layout-evidence.ts +374 -0
  104. package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
  105. package/src/runtime/scopes/preservation-boundary.ts +7 -1
  106. package/src/runtime/scopes/replacement/apply.ts +97 -34
  107. package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
  108. package/src/runtime/scopes/semantic-scope-types.ts +242 -3
  109. package/src/runtime/scopes/visualization.ts +28 -0
  110. package/src/runtime/surface-projection.ts +44 -5
  111. package/src/runtime/telemetry/perf-probe.ts +216 -0
  112. package/src/runtime/virtualized-rendering.ts +36 -1
  113. package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
  114. package/src/runtime/workflow/coordinator.ts +39 -11
  115. package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
  116. package/src/runtime/workflow/index.ts +4 -0
  117. package/src/runtime/workflow/overlay-lane-types.ts +58 -0
  118. package/src/runtime/workflow/overlay-lanes.ts +386 -0
  119. package/src/runtime/workflow/overlay-store.ts +2 -2
  120. package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
  121. package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
  122. package/src/session/_sync-legacy.ts +17 -27
  123. package/src/session/import/loader.ts +6 -4
  124. package/src/session/import/source-package-evidence.ts +186 -2
  125. package/src/session/index.ts +5 -6
  126. package/src/session/session.ts +30 -56
  127. package/src/session/types.ts +8 -13
  128. package/src/shell/session-bootstrap.ts +155 -81
  129. package/src/ui/WordReviewEditor.tsx +520 -12
  130. package/src/ui/editor-shell-view.tsx +14 -4
  131. package/src/ui/editor-surface-controller.tsx +5 -3
  132. package/src/ui/headless/selection-tool-resolver.ts +1 -2
  133. package/src/ui/presence-overlay-lane.ts +130 -0
  134. package/src/ui/ui-controller-factory.ts +17 -0
  135. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
  136. package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
  137. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
  138. package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
  139. package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
  140. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
  141. package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
  142. package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
  143. package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
  144. package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
  145. package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
  146. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
  147. package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
  148. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
  149. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
  150. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
  151. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
  152. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
  153. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
  154. package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
  155. package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
  156. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
  157. package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
  158. package/src/ui-tailwind/debug/README.md +4 -1
  159. package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
  160. package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
  161. package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
  162. package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
  163. package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
  164. package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
  165. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
  166. package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
  167. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
  168. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
  169. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
  170. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
  171. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
  172. package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
  173. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
  174. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
  175. package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
  176. package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
  177. package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
  178. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
  179. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
  180. package/src/ui-tailwind/review-workspace/types.ts +26 -12
  181. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
  182. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
  183. package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
  184. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
  185. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
  186. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
  187. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
  188. package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
  189. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
  190. package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
  191. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
  192. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
  193. package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `DocxSession` — the reserved Layer-01 public entry class.
2
+ * `DocxSession` — the Layer-01 package/session public entry class.
3
3
  *
4
4
  * Shape matches `docs/architecture/01-package-session.md` § Public
5
5
  * entry points:
@@ -8,49 +8,28 @@
8
8
  * export(doc, opts?) → Promise<ExportResult>
9
9
  * validate(doc, opts?) → ValidationReport
10
10
  *
11
- * Slice-4 state: `open()` is wired and additionally attaches a
12
- * module-private legacy view (accessed via
13
- * `src/session/_internal-legacy.ts`) for in-tree services that still
14
- * need the stateful `exportDocx` closure. `export()` and `validate()`
15
- * throw `SessionNotWiredError` — the architecture reserves them as
16
- * stateless, which requires a new pipeline that lands in Slice 5.
11
+ * Current state: `open()`, `export()`, `validate()`, and
12
+ * `reopenFromSnapshot()` are wired against in-session loader/export
13
+ * implementations. `OpenResult` carries the open-time export/dispose
14
+ * handles directly.
17
15
  *
18
16
  * P6 discipline: `src/session` must not import from `src/runtime`,
19
- * `src/ui` / `src/ui-tailwind`, `src/core`, or `src/review`. This file transits
20
- * `src/io/docx-session.ts` (legacy integration orchestrator) under a
21
- * documented debt exception the legacy file itself still imports
22
- * forbidden runtime/review surfaces (see `src/io/docx-session.ts:35–43`
23
- * and architecture doc §P6 "debt exception"). The exception closes in
24
- * Slice 5 when the legacy file is deleted; the purity checker warns
25
- * (not errors) on this specific transit, and a session-transit test
26
- * pins the exception so any accidental reintroduction is caught.
17
+ * `src/ui` / `src/ui-tailwind`, `src/shell`, `src/core`, or
18
+ * `src/review`. The purity checker enforces this with zero debt
19
+ * exceptions; runtime/presentation hooks enter through typed options.
27
20
  */
28
21
 
29
22
  import type { CanonicalDocument } from "../model/canonical-document.ts";
30
23
  import { buildCompatibilityReport } from "../validation/compatibility-engine.ts";
31
- // Slice 5e-8.a: session.ts now reaches the load pipeline directly
32
- // via `src/session/import/loader.ts` (in-layer). The legacy transit
33
- // through `src/io/docx-session.ts` is retired along with the
34
- // debt-exception entry for this file in the purity CI guard.
24
+ // Session reaches the load pipeline directly through the in-layer
25
+ // loader. The `src/io/docx-session.ts` path is a back-compat shim, not
26
+ // a dependency of this class.
35
27
  import { loadDocxSessionAsync } from "./import/loader.ts";
36
28
  import type { LoadDocxEditorSessionAsyncOptions } from "./import/loader-types.ts";
37
29
  import { createLoadScheduler } from "../io/load-scheduler.ts";
38
- // P6 debt exception: the laycache probe lives in
39
- // `src/runtime/prerender/` because its `CacheEnvelope` type
40
- // transitively references `CompatibilityReport` (core) and
41
- // `RuntimePageGraph` (runtime/layout). Relocating those shared
42
- // types is a layer-04/05 concern. The transit is pinned in
43
- // `scripts/ci-check-session-layer-purity.mjs::DEBT_EXCEPTIONS` so
44
- // CI surfaces the debt on every run.
45
- // Slice 5e-11 item-1: the laycache probe is now dependency-injected
46
- // via `OpenOptions.laycacheProbe` — session no longer imports from
47
- // `src/runtime/prerender/**`. This retires the last P6 debt
48
- // exception for Layer 01. See `docs/plans/cross-layer-coord-01.md §1`.
49
- // Slice 5e-11 item-4: the WeakMap-backed `_internal-legacy.ts`
50
- // accessor has been retired. `initialSnapshot`,
51
- // `initialEditorStatePayload?`, `exportDocx`, and `dispose?` are
52
- // public fields on `OpenResult` now; `DocxSession.export` + `dispose`
53
- // route through the captured `lastOpenResult` directly.
30
+ // Runtime-facing hooks are dependency-injected. `OpenOptions.laycacheProbe`
31
+ // prevents a direct runtime/prerender import, and `OpenResult` carries
32
+ // the open-time export/dispose handles directly.
54
33
  import type { EditorSessionState } from "./session-state.ts";
55
34
  import type {
56
35
  EmbeddedDocumentManifest,
@@ -117,9 +96,9 @@ export const SessionNotWiredError = SessionNotOpenError;
117
96
  * runs against an already-loaded canonical document.
118
97
  *
119
98
  * Session-bound export model: `open()` captures the `OpenResult`
120
- * handle (which carries the `LegacyOpenView.exportDocx` closure +
121
- * `ImportedDocxState`). `export(sessionState, opts)` dispatches
122
- * through that captured closure with the caller-supplied session
99
+ * handle, including the stateful `exportDocx` function produced by
100
+ * the in-session loader/export pipeline. `export(sessionState, opts)`
101
+ * dispatches through that captured function with the caller-supplied session
123
102
  * state — the runtime's current state, carrying any
124
103
  * `workflowOverlay` / `workflowMetadata` edits made between open and
125
104
  * export. A session instance that has not been `open`ed throws
@@ -134,8 +113,8 @@ export const SessionNotWiredError = SessionNotOpenError;
134
113
  export class DocxSession {
135
114
  /**
136
115
  * Most recent `open()` result — captured so `export(sessionState)`
137
- * can reach the `LegacyOpenView.exportDocx` closure via the
138
- * `src/session/_internal-legacy.ts` WeakMap. Cleared on `dispose()`.
116
+ * can reach the captured `OpenResult.exportDocx` function. Cleared
117
+ * on `dispose()`.
139
118
  *
140
119
  * The caller's `sessionState` argument to `export()` is passed
141
120
  * through verbatim; this slot is only the dispatch anchor, not a
@@ -149,11 +128,9 @@ export class DocxSession {
149
128
  * the embedded-document manifest list populated from
150
129
  * `collectEmbeddedDocuments` (P8).
151
130
  *
152
- * Implementation delegates to the legacy async loader
153
- * (`loadDocxEditorSessionAsync`) while Slices 2–4 extract parse/
154
- * serialize orchestration into `src/session/import/**` +
155
- * `src/session/export/**`. The signature here is stable — the body
156
- * can swap to the new orchestrator without consumers noticing.
131
+ * Implementation delegates to the in-layer async loader in
132
+ * `src/session/import/loader.ts`; callers do not reach into the
133
+ * back-compat `src/io/docx-session.ts` shim.
157
134
  */
158
135
  async open(
159
136
  bytes: Uint8Array | ArrayBuffer,
@@ -295,9 +272,9 @@ export class DocxSession {
295
272
  };
296
273
 
297
274
  // Capture the open result so `export(sessionState)` can reach the
298
- // legacy view's stateful `exportDocx` closure without the caller
299
- // threading the `OpenResult` back through. Overwritten on re-open;
300
- // cleared by `dispose()`.
275
+ // stateful `exportDocx` function without the caller threading the
276
+ // `OpenResult` back through. Overwritten on re-open; cleared by
277
+ // `dispose()`.
301
278
  this.lastOpenResult = result;
302
279
 
303
280
  return result;
@@ -316,8 +293,8 @@ export class DocxSession {
316
293
  * passes `sessionState` straight through to the stateful export
317
294
  * pipeline — no splice, no hidden state-carry.
318
295
  *
319
- * Dispatch: the method reaches the `LegacyOpenView.exportDocx`
320
- * closure captured during the most recent `open()` on this instance.
296
+ * Dispatch: the method reaches the `OpenResult.exportDocx` function
297
+ * captured during the most recent `open()` on this instance.
321
298
  * That closure holds the `ImportedDocxState` (source bytes,
322
299
  * `OpcPackage`, per-part relationships, preserved-part manifest)
323
300
  * that the pipeline needs in order to round-trip. When
@@ -332,12 +309,9 @@ export class DocxSession {
332
309
  * this instance never saw) is a later Layer-01 follow-up: it needs a
333
310
  * byte-free preservation contract that has not shipped.
334
311
  *
335
- * P6 discipline: dispatch goes through `getLegacyOpenView(result).
336
- * exportDocx(...)` the WeakMap-backed accessor at
337
- * `src/session/_internal-legacy.ts`. No direct import of
338
- * `exportDocxEditorSession` from `src/io/docx-session.ts` is added
339
- * beyond the `session.ts → docx-session.ts` debt exception already
340
- * present for `open()`'s legacy transit.
312
+ * P6 discipline: dispatch goes through the captured `OpenResult`
313
+ * field. The session layer does not import the compatibility
314
+ * `src/io/docx-session.ts` shim or any runtime/presentation module.
341
315
  */
342
316
  async export(
343
317
  sessionState: EditorSessionState,
@@ -4,8 +4,8 @@
4
4
  * These types mirror the reserved shape in
5
5
  * `docs/architecture/01-package-session.md` § "Public entry points".
6
6
  * They are the contract consumers see; the implementation in
7
- * `src/session/session.ts` may still delegate transitionally to the
8
- * legacy `src/io/docx-session.ts` while the extraction completes.
7
+ * `src/session/session.ts` delegates to in-layer loader/export
8
+ * modules.
9
9
  *
10
10
  * P6 clean: imports only from `src/api/**` (type-only), `src/model/**`,
11
11
  * `src/io/**`, and `src/preservation/**`.
@@ -31,10 +31,9 @@ import type { LoadSchedulerBackend } from "../io/load-scheduler.ts";
31
31
  import type { PreservationStore } from "../model/canonical-document.ts";
32
32
  import type { EditorSessionState } from "./session-state.ts";
33
33
 
34
- // Re-export legacy types so downstream consumers that still need them
35
- // during the transition can reach them from the session barrel. These
36
- // are explicitly transitional and scheduled for removal in Slice 5 once
37
- // the legacy `src/io/docx-session.ts` is deleted.
34
+ // Re-export back-compat public types so downstream consumers can reach
35
+ // them from the session barrel instead of the `src/io/docx-session.ts`
36
+ // shim.
38
37
  export type {
39
38
  EditorHostAdapter,
40
39
  ExportDocxOptions,
@@ -307,13 +306,9 @@ export type PreservationSnapshot = PreservationStore;
307
306
  * doc exactly: session state + canonical document + compatibility
308
307
  * report + preservation snapshot + embedded-document manifest (P8).
309
308
  *
310
- * Every field here is part of the reserved Layer-01 public contract.
311
- * The transitional legacy-session handle that in-tree services still
312
- * need during the Slice-4 Slice-5 migration is carried through a
313
- * WeakMap-backed accessor (`getLegacyOpenView`) in the
314
- * `src/session/_internal-legacy.ts` module — NOT as a public field on
315
- * this shape. The architecture doc has no `_legacy` escape hatch,
316
- * and public consumers must not see one.
309
+ * Every field here is part of the Layer-01 public contract. The
310
+ * open-time export/dispose handles are explicit fields so callers do
311
+ * not need any private legacy escape hatch.
317
312
  */
318
313
  export interface OpenResult {
319
314
  readonly sessionState: EditorSessionState;
@@ -52,28 +52,27 @@ import {
52
52
  type RuntimeDebugFacet,
53
53
  } from "../runtime/debug/runtime-debug-facet.ts";
54
54
  // Slice 5c flipped the async DOM warm path to `DocxSession.open()`.
55
- // The two remaining sync call sites (SSR/Node `createRuntime`
56
- // fallback + `resolvePackageBackedExportSession`) were isolated
57
- // behind `src/session/_sync-legacy.ts` in Slice 5e-3 so the UI layer
58
- // no longer imports directly from the legacy file. The shim + its
59
- // debt exception in `ci-check-session-layer-purity.mjs` go away at
60
- // Slice 5e-9 together with the legacy file.
55
+ // The remaining sync call site is the SSR/Node `createRuntime`
56
+ // fallback for raw DOCX bytes. Snapshot/session source-package reopen
57
+ // is async via `DocxSession.reopenFromSnapshot()` so presentation
58
+ // surfaces never decode persisted package bytes themselves.
61
59
  import type { CacheEnvelope } from "../runtime/prerender/cache-envelope.ts";
62
60
  import { tryReadLaycacheEnvelope } from "../runtime/prerender/customxml-probe.ts";
63
61
  import { createEditorSurfaceSnapshot } from "../runtime/surface-projection.ts";
64
62
  import { MAIN_STORY_TARGET } from "../core/selection/mapping.ts";
65
63
  import type { ProgressiveSurfaceProjector } from "../session/types.ts";
66
- import { DocxSession } from "../session/index.ts";
64
+ import {
65
+ DocxSession,
66
+ isReopenBarrier,
67
+ type OpenResult,
68
+ type ReopenBarrier,
69
+ } from "../session/index.ts";
67
70
  // Slice 5e-11 item-4: `_internal-legacy.ts` retired. All fields that
68
71
  // were reached through `getLegacyOpenView` are now public on
69
72
  // `OpenResult` directly; a tiny local adapter maps `OpenResult` into
70
73
  // the `LoadedDocxEditorSession` shape the downstream shell code
71
74
  // still expects.
72
75
  import { openDocxSync } from "../session/_sync-legacy.ts";
73
- import {
74
- decodePersistedSourcePackageBytes,
75
- hasValidPersistedSourcePackageDigest,
76
- } from "../io/source-package-provenance.ts";
77
76
  import {
78
77
  createEditorViewStateSnapshot,
79
78
  createViewState,
@@ -81,7 +80,7 @@ import {
81
80
  import { hydrateEditorStateFromEnvelope } from "../runtime/editor-state-integration.ts";
82
81
  import {
83
82
  recordPerfSample,
84
- } from "../ui-tailwind/editor-surface/perf-probe.ts";
83
+ } from "../runtime/telemetry/perf-probe.ts";
85
84
  import {
86
85
  downloadExportResult,
87
86
  withExportDelivery,
@@ -100,7 +99,15 @@ export interface ResolvedSource {
100
99
  * load. Undefined in SSR / Node test fallback — `createRuntime` then
101
100
  * does the classic synchronous load.
102
101
  */
103
- preloadedDocxSession?: ReturnType<typeof openDocxSync>;
102
+ preloadedDocxSession?: LoadedDocxEditorSession;
103
+ preloadedDocxDispose?: () => void;
104
+ /**
105
+ * Snapshot/session sources must be reopened asynchronously before the
106
+ * runtime paints. When Layer 01 returns a typed barrier, keep it here
107
+ * so the sync runtime can expose an export-blocking compatibility
108
+ * posture without trying a second legacy reopen.
109
+ */
110
+ preloadedSnapshotExportBarrier?: SnapshotExportBarrier;
104
111
  /**
105
112
  * L7 Phase 2.7 — when the editor-runtime-boundary probe finds a
106
113
  * laycache envelope in `/customXml/item1.xml`, its `graph` is stashed
@@ -149,11 +156,13 @@ type InternalWordReviewEditorRuntime = WordReviewEditorRuntime & {
149
156
  };
150
157
 
151
158
  type PackageBackedDocxSession = ReturnType<typeof openDocxSync>;
159
+ type LoadedDocxEditorSession = ReturnType<typeof openDocxSync>;
152
160
 
153
161
  interface SnapshotExportBarrier {
154
162
  reason:
155
163
  | "missing_source_package_provenance"
156
- | "invalid_source_package_provenance";
164
+ | "invalid_source_package_provenance"
165
+ | "snapshot_reopen_unavailable";
157
166
  message: string;
158
167
  }
159
168
 
@@ -302,6 +311,81 @@ export async function __resolveWordReviewEditorSource(
302
311
  };
303
312
  }
304
313
 
314
+ function adaptOpenResultToLoadedSession(
315
+ openResult: OpenResult,
316
+ ): LoadedDocxEditorSession {
317
+ return {
318
+ initialSessionState: openResult.sessionState,
319
+ initialSnapshot: openResult.initialSnapshot,
320
+ readOnly: openResult.readOnly,
321
+ ...(openResult.fatalError !== undefined
322
+ ? { fatalError: openResult.fatalError }
323
+ : {}),
324
+ protectionSnapshot: openResult.protectionSnapshot,
325
+ exportDocx: openResult.exportDocx,
326
+ embeddedDocumentManifests: openResult.embeddedDocuments,
327
+ ...(openResult.initialEditorStatePayload !== undefined
328
+ ? {
329
+ initialEditorStatePayload:
330
+ openResult.initialEditorStatePayload as NonNullable<
331
+ LoadedDocxEditorSession["initialEditorStatePayload"]
332
+ >,
333
+ }
334
+ : {}),
335
+ };
336
+ }
337
+
338
+ function snapshotExportBarrierFromReopenBarrier(
339
+ barrier: ReopenBarrier,
340
+ ): SnapshotExportBarrier {
341
+ if (barrier.reason === "no-source-package") {
342
+ return {
343
+ reason: "missing_source_package_provenance",
344
+ message:
345
+ "DOCX export is blocked because this session was loaded without embedded source package provenance.",
346
+ };
347
+ }
348
+ return {
349
+ reason: "invalid_source_package_provenance",
350
+ message: barrier.message,
351
+ };
352
+ }
353
+
354
+ export async function __preloadSnapshotSourceForRuntime(args: {
355
+ documentId: string;
356
+ source: ResolvedSource;
357
+ editorBuild?: string;
358
+ }): Promise<void> {
359
+ if (args.source.initialDocx !== undefined || args.source.preloadedDocxSession) {
360
+ return;
361
+ }
362
+
363
+ const snapshot =
364
+ args.source.initialSessionState ?? args.source.initialSnapshot;
365
+ if (!snapshot) {
366
+ args.source.preloadedSnapshotExportBarrier = {
367
+ reason: "missing_source_package_provenance",
368
+ message:
369
+ "DOCX export is blocked because this session does not carry a snapshot or session state to reopen.",
370
+ };
371
+ return;
372
+ }
373
+
374
+ const reopened = await new DocxSession().reopenFromSnapshot(snapshot, {
375
+ documentId: args.documentId,
376
+ sourceLabel: args.source.sourceLabel,
377
+ editorBuild: args.editorBuild ?? "dev",
378
+ });
379
+ if (isReopenBarrier(reopened)) {
380
+ args.source.preloadedSnapshotExportBarrier =
381
+ snapshotExportBarrierFromReopenBarrier(reopened);
382
+ return;
383
+ }
384
+
385
+ args.source.preloadedDocxSession = adaptOpenResultToLoadedSession(reopened);
386
+ args.source.preloadedDocxDispose = reopened.dispose;
387
+ }
388
+
305
389
  export function __createFallbackRuntime(args: CreateRuntimeArgs): WordReviewEditorRuntime {
306
390
  return createRuntime(args);
307
391
  }
@@ -545,30 +629,7 @@ export function useEditorRuntimeBoundary(
545
629
  });
546
630
  },
547
631
  });
548
- // Slice 5e-11 item-4: adapter maps `OpenResult` → the
549
- // `LoadedDocxEditorSession` shape the downstream shell
550
- // code expects. Two field-name mismatches exist:
551
- // `sessionState` / `initialSessionState`, and
552
- // `embeddedDocuments` / `embeddedDocumentManifests`.
553
- const preloadView: ReturnType<typeof openDocxSync> = {
554
- initialSessionState: openResult.sessionState,
555
- initialSnapshot: openResult.initialSnapshot,
556
- readOnly: openResult.readOnly,
557
- ...(openResult.fatalError !== undefined
558
- ? { fatalError: openResult.fatalError }
559
- : {}),
560
- protectionSnapshot: openResult.protectionSnapshot,
561
- exportDocx: openResult.exportDocx,
562
- embeddedDocumentManifests: openResult.embeddedDocuments,
563
- ...(openResult.initialEditorStatePayload !== undefined
564
- ? {
565
- initialEditorStatePayload:
566
- openResult.initialEditorStatePayload as NonNullable<
567
- ReturnType<typeof openDocxSync>["initialEditorStatePayload"]
568
- >,
569
- }
570
- : {}),
571
- };
632
+ const preloadView = adaptOpenResultToLoadedSession(openResult);
572
633
  loadDisposeRef.current = openResult.dispose ?? null;
573
634
  if (cancelled) {
574
635
  openResult.dispose?.();
@@ -577,6 +638,7 @@ export function useEditorRuntimeBoundary(
577
638
  }
578
639
  recordPerfSample("loadSession.laycacheProbe");
579
640
  source.preloadedDocxSession = preloadView;
641
+ source.preloadedDocxDispose = openResult.dispose;
580
642
  if (pendingChartPreviewDocRef.current) {
581
643
  source.preloadedDocxSession.initialSessionState = {
582
644
  ...source.preloadedDocxSession.initialSessionState,
@@ -594,6 +656,27 @@ export function useEditorRuntimeBoundary(
594
656
  }
595
657
  }
596
658
 
659
+ if (
660
+ source.initialDocx === undefined &&
661
+ source.preloadedDocxSession === undefined &&
662
+ (source.initialSessionState !== undefined ||
663
+ source.initialSnapshot !== undefined)
664
+ ) {
665
+ await __preloadSnapshotSourceForRuntime({
666
+ documentId,
667
+ source,
668
+ editorBuild: "dev",
669
+ });
670
+ if (cancelled) {
671
+ source.preloadedDocxDispose?.();
672
+ source.preloadedDocxSession = undefined;
673
+ source.preloadedDocxDispose = undefined;
674
+ return;
675
+ }
676
+ loadDisposeRef.current =
677
+ source.preloadedDocxDispose ?? loadDisposeRef.current;
678
+ }
679
+
597
680
  const nextRuntime = createRuntime(
598
681
  {
599
682
  documentId,
@@ -822,10 +905,10 @@ function createRuntime(
822
905
  : undefined;
823
906
  const initialSessionState =
824
907
  args.source.initialSessionState ??
825
- docxSession?.initialSessionState ??
826
908
  (args.source.initialSnapshot
827
909
  ? editorSessionStateFromPersistedSnapshot(args.source.initialSnapshot)
828
- : editorSessionStateFromPersistedSnapshot(
910
+ : docxSession?.initialSessionState ??
911
+ editorSessionStateFromPersistedSnapshot(
829
912
  createFallbackPersistedSnapshot(
830
913
  args.documentId,
831
914
  args.source.sourceLabel ?? "Generated shell snapshot",
@@ -1087,6 +1170,7 @@ function createLoadingRuntimeBridge(input: {
1087
1170
  subscribeToEvents: () => () => undefined,
1088
1171
  emitBlockedCommand: () => undefined,
1089
1172
  emitTransientWarning: () => undefined,
1173
+ now: () => new Date().toISOString(),
1090
1174
  getRenderSnapshot: () => {
1091
1175
  const progressive = input.progressiveSurfaceRef?.current;
1092
1176
  if (progressive == null) return input.snapshot;
@@ -1177,6 +1261,22 @@ function createLoadingRuntimeBridge(input: {
1177
1261
  getRailSegments: () => [],
1178
1262
  getAllRailSegments: () => [],
1179
1263
  getAllScopeCardModels: () => [],
1264
+ getReviewOverlayLane: (kind) => ({
1265
+ kind,
1266
+ status: "unavailable",
1267
+ entries: [],
1268
+ revision: 0,
1269
+ source: "unavailable",
1270
+ reason: "overlay lanes are unavailable before runtime hydration",
1271
+ }),
1272
+ subscribeReviewOverlayLane: (kind) => {
1273
+ if (kind === "presence") {
1274
+ throw new Error(
1275
+ "runtime.workflow.subscribeReviewOverlayLane: presence is awareness-owned; use the awareness-backed presence lane source",
1276
+ );
1277
+ }
1278
+ return () => undefined;
1279
+ },
1180
1280
  },
1181
1281
  geometry: inertGeometryFacet,
1182
1282
  getLayoutFacet: () => inertLayoutFacet,
@@ -1888,6 +1988,14 @@ function resolvePackageBackedExportSession(args: CreateRuntimeArgs): {
1888
1988
  session?: PackageBackedDocxSession;
1889
1989
  barrier?: SnapshotExportBarrier;
1890
1990
  } {
1991
+ if (args.source.preloadedDocxSession) {
1992
+ return { session: args.source.preloadedDocxSession };
1993
+ }
1994
+
1995
+ if (args.source.preloadedSnapshotExportBarrier) {
1996
+ return { barrier: args.source.preloadedSnapshotExportBarrier };
1997
+ }
1998
+
1891
1999
  const sourcePackage =
1892
2000
  args.source.initialSessionState?.sourcePackage ??
1893
2001
  args.source.initialSnapshot?.sourcePackage;
@@ -1901,47 +2009,13 @@ function resolvePackageBackedExportSession(args: CreateRuntimeArgs): {
1901
2009
  };
1902
2010
  }
1903
2011
 
1904
- try {
1905
- const bytes = decodePersistedSourcePackageBytes(sourcePackage);
1906
- if (!hasValidPersistedSourcePackageDigest(sourcePackage, bytes)) {
1907
- return {
1908
- barrier: {
1909
- reason: "invalid_source_package_provenance",
1910
- message:
1911
- "DOCX export is blocked because the embedded source package provenance failed its integrity check.",
1912
- },
1913
- };
1914
- }
1915
-
1916
- const session = openDocxSync({
1917
- documentId: args.documentId,
1918
- sourceLabel: sourcePackage.sourceLabel ?? args.source.sourceLabel,
1919
- bytes,
1920
- editorBuild:
1921
- args.source.initialSessionState?.editorBuild ??
1922
- args.source.initialSnapshot?.editorBuild ??
1923
- "dev",
1924
- });
1925
- if (session.readOnly || session.fatalError) {
1926
- return {
1927
- barrier: {
1928
- reason: "invalid_source_package_provenance",
1929
- message:
1930
- "DOCX export is blocked because the embedded source package provenance is no longer loadable as a valid package-backed session.",
1931
- },
1932
- };
1933
- }
1934
-
1935
- return { session };
1936
- } catch {
1937
- return {
1938
- barrier: {
1939
- reason: "invalid_source_package_provenance",
1940
- message:
1941
- "DOCX export is blocked because the embedded source package provenance could not be decoded into a package-backed session.",
1942
- },
1943
- };
1944
- }
2012
+ return {
2013
+ barrier: {
2014
+ reason: "snapshot_reopen_unavailable",
2015
+ message:
2016
+ "DOCX export is blocked because the snapshot source package was not reopened before runtime creation.",
2017
+ },
2018
+ };
1945
2019
  }
1946
2020
 
1947
2021
  function applySessionExportBarrier(