@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.
- package/README.md +75 -931
- package/package.json +26 -27
- package/src/api/anchor-conversion.ts +43 -0
- package/src/api/editor-state-types.ts +2 -1
- package/src/api/public-types.ts +504 -101
- package/src/api/session-state.ts +4 -0
- package/src/api/v3/README.md +91 -0
- package/src/api/v3/_create.ts +146 -0
- package/src/api/v3/_layer-metadata.ts +362 -0
- package/src/api/v3/_mocks.ts +84 -0
- package/src/api/v3/_runtime-handle.ts +162 -0
- package/src/api/v3/_ux-response.ts +73 -0
- package/src/api/v3/ai/_metadata-audit.ts +225 -0
- package/src/api/v3/ai/attach.ts +235 -0
- package/src/api/v3/ai/bundle.ts +132 -0
- package/src/api/v3/ai/explain.ts +144 -0
- package/src/api/v3/ai/export.ts +54 -0
- package/src/api/v3/ai/inspect.ts +118 -0
- package/src/api/v3/ai/policy.ts +77 -0
- package/src/api/v3/ai/replacement.ts +341 -0
- package/src/api/v3/ai/resolve.ts +133 -0
- package/src/api/v3/index.ts +79 -0
- package/src/api/v3/runtime/chart.ts +310 -0
- package/src/api/v3/runtime/clipboard.ts +81 -0
- package/src/api/v3/runtime/collab.ts +331 -0
- package/src/api/v3/runtime/content.ts +236 -0
- package/src/api/v3/runtime/document.ts +282 -0
- package/src/api/v3/runtime/formatting.ts +186 -0
- package/src/api/v3/runtime/geometry.ts +349 -0
- package/src/api/v3/runtime/layout.ts +108 -0
- package/src/api/v3/runtime/review.ts +129 -0
- package/src/api/v3/runtime/search.ts +74 -0
- package/src/api/v3/runtime/table.ts +63 -0
- package/src/api/v3/runtime/workflow.ts +434 -0
- package/src/api/v3/ui/_context.ts +86 -0
- package/src/api/v3/ui/_create.ts +65 -0
- package/src/api/v3/ui/_types.ts +520 -0
- package/src/api/v3/ui/chrome-composition.ts +342 -0
- package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
- package/src/api/v3/ui/chrome.ts +476 -0
- package/src/api/v3/ui/debug.ts +124 -0
- package/src/api/v3/ui/index.ts +64 -0
- package/src/api/v3/ui/overlays-visibility.ts +170 -0
- package/src/api/v3/ui/overlays.ts +427 -0
- package/src/api/v3/ui/scope.ts +71 -0
- package/src/api/v3/ui/session.ts +100 -0
- package/src/api/v3/ui/surface.ts +170 -0
- package/src/api/v3/ui/viewport.ts +303 -0
- package/src/core/commands/index.ts +28 -6
- package/src/core/commands/list-commands.ts +3 -2
- package/src/core/commands/section-layout-commands.ts +9 -8
- package/src/core/schema/text-schema.ts +16 -0
- package/src/core/selection/mapping.ts +33 -72
- package/src/core/state/editor-state.ts +96 -189
- package/src/index.ts +23 -4
- package/src/io/chart-preview-resolver.ts +1 -1
- package/src/io/docx-session.ts +36 -4795
- package/src/io/export/build-app-properties-xml.ts +1 -1
- package/src/io/export/serialize-comments.ts +1 -1
- package/src/io/export/serialize-headers-footers.ts +6 -1
- package/src/io/export/serialize-main-document.ts +45 -0
- package/src/io/export/serialize-run-formatting.ts +17 -2
- package/src/io/export/twip.ts +1 -1
- package/src/io/normalize/normalize-text.ts +27 -20
- package/src/io/ooxml/chart/parse-series.ts +1 -1
- package/src/io/ooxml/chart/resolve-color.ts +2 -2
- package/src/io/ooxml/chart/types.ts +1 -1
- package/src/io/ooxml/classify-embedding.ts +83 -33
- package/src/io/ooxml/parse-fill.ts +1 -1
- package/src/io/ooxml/parse-main-document.ts +71 -1
- package/src/io/ooxml/parse-object.ts +14 -10
- package/src/io/ooxml/parse-run-formatting.ts +47 -1
- package/src/io/ooxml/property-grab-bag.ts +2 -2
- package/src/io/ooxml/units.ts +11 -0
- package/src/io/ooxml/workflow-payload.ts +282 -7
- package/src/model/anchor.ts +85 -0
- package/src/model/canonical-document.ts +351 -15
- package/src/model/chart-types.ts +1 -1
- package/src/model/layout/index.ts +83 -0
- package/src/model/layout/page-graph-types.ts +181 -0
- package/src/model/layout/page-layout-snapshot.ts +105 -0
- package/src/model/layout/resolved-layout-types.ts +47 -0
- package/src/model/layout/runtime-page-graph-types.ts +102 -0
- package/src/model/paragraph-scope-ids.ts +72 -0
- package/src/model/review/comment-types.ts +112 -0
- package/src/model/review/index.ts +2 -0
- package/src/model/review/revision-types.ts +215 -0
- package/src/model/snapshot.ts +32 -0
- package/src/review/store/comment-store.ts +21 -47
- package/src/review/store/revision-types.ts +40 -198
- package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
- package/src/runtime/collab/runtime-collab-sync.ts +13 -3
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
- package/src/runtime/debug/event-ring-buffer.ts +64 -0
- package/src/runtime/debug/probability-sampler.ts +18 -0
- package/src/runtime/debug/runtime-debug-facet.ts +67 -0
- package/src/runtime/debug/stage-tokens.ts +31 -0
- package/src/runtime/debug/telemetry-bus.ts +271 -0
- package/src/runtime/debug/types.ts +275 -0
- package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
- package/src/runtime/document-layout.ts +8 -6
- package/src/runtime/document-runtime.ts +843 -1141
- package/src/runtime/document-search.ts +1 -1
- package/src/runtime/edit-ops/index.ts +1 -1
- package/src/runtime/external-send-runtime.ts +1 -1
- package/src/runtime/formatting/document-lookup.ts +235 -0
- package/src/runtime/formatting/field/registry.ts +41 -0
- package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
- package/src/runtime/formatting/font-resolution.ts +83 -0
- package/src/runtime/formatting/formatting-context.ts +903 -0
- package/src/runtime/formatting/formatting-types.ts +157 -0
- package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
- package/src/runtime/formatting/index.ts +125 -0
- package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
- package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
- package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
- package/src/runtime/formatting/projector.ts +75 -0
- package/src/runtime/formatting/resolve-effective.ts +407 -0
- package/src/runtime/formatting/revision-display.ts +105 -0
- package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
- package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
- package/src/runtime/formatting/telemetry-bridge.ts +106 -0
- package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
- package/src/runtime/geometry/caret-geometry.ts +164 -0
- package/src/runtime/geometry/geometry-facet.ts +364 -0
- package/src/runtime/geometry/geometry-types.ts +256 -0
- package/src/runtime/geometry/hit-test.ts +125 -0
- package/src/runtime/geometry/index.ts +71 -0
- package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
- package/src/runtime/geometry/invalidation.ts +35 -0
- package/src/runtime/geometry/object-handles.ts +77 -0
- package/src/runtime/geometry/overlay-rects.ts +85 -0
- package/src/runtime/geometry/project-anchors.ts +100 -0
- package/src/runtime/geometry/project-fragments.ts +216 -0
- package/src/runtime/geometry/projector.ts +129 -0
- package/src/runtime/geometry/replacement-envelope.ts +130 -0
- package/src/runtime/geometry/viewport.ts +218 -0
- package/src/runtime/layout/compat-input-ledger.ts +211 -0
- package/src/runtime/layout/index.ts +6 -1
- package/src/runtime/layout/inert-layout-facet.ts +12 -7
- package/src/runtime/layout/layout-engine-instance.ts +189 -11
- package/src/runtime/layout/layout-engine-version.ts +450 -1
- package/src/runtime/layout/layout-facet-types.ts +60 -0
- package/src/runtime/layout/layout-measurement-provider.ts +13 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
- package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
- package/src/runtime/layout/page-graph.ts +62 -209
- package/src/runtime/layout/page-story-resolver.ts +7 -12
- package/src/runtime/layout/paginated-layout-engine.ts +186 -11
- package/src/runtime/layout/project-block-fragments.ts +11 -0
- package/src/runtime/layout/projector.ts +90 -0
- package/src/runtime/layout/public-facet.ts +187 -442
- package/src/runtime/layout/resolved-formatting-state.ts +158 -26
- package/src/runtime/layout/table-render-plan.ts +1 -1
- package/src/runtime/prerender/cache-envelope.ts +6 -1
- package/src/runtime/prerender/prerender-document.ts +18 -23
- package/src/runtime/render/decoration-resolver.ts +1 -1
- package/src/runtime/render/render-frame-types.ts +20 -0
- package/src/runtime/render/render-kernel.ts +94 -25
- package/src/runtime/scopes/_formatting-seam.ts +262 -0
- package/src/runtime/scopes/_scope-dependencies.ts +49 -0
- package/src/runtime/scopes/action-validation.ts +356 -0
- package/src/runtime/scopes/attach-explanation.ts +102 -0
- package/src/runtime/scopes/audit-bundle.ts +71 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
- package/src/runtime/scopes/compile-scope.ts +262 -0
- package/src/runtime/scopes/compiler-service.ts +431 -0
- package/src/runtime/scopes/create-issue.ts +107 -0
- package/src/runtime/scopes/enumerate-scopes.ts +543 -0
- package/src/runtime/scopes/evidence.ts +233 -0
- package/src/runtime/scopes/index.ts +150 -0
- package/src/runtime/scopes/position-map.ts +214 -0
- package/src/runtime/scopes/preservation-boundary.ts +91 -0
- package/src/runtime/scopes/projector.ts +49 -0
- package/src/runtime/scopes/replaceability.ts +87 -0
- package/src/runtime/scopes/replacement/apply.ts +228 -0
- package/src/runtime/scopes/replacement/compile.ts +59 -0
- package/src/runtime/scopes/replacement/propose.ts +42 -0
- package/src/runtime/scopes/resolve-reference.ts +347 -0
- package/src/runtime/scopes/review-bundle.ts +141 -0
- package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
- package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
- package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
- package/src/runtime/scopes/scope-kinds/field.ts +65 -0
- package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
- package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
- package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
- package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
- package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
- package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
- package/src/runtime/scopes/scope-kinds/table.ts +55 -0
- package/src/runtime/scopes/scope-range.ts +208 -0
- package/src/runtime/scopes/semantic-scope-types.ts +454 -0
- package/src/runtime/scopes/workflow-overlap.ts +92 -0
- package/src/runtime/selection/index.ts +1 -1
- package/src/runtime/structure-ops/fragment-insert.ts +1 -1
- package/src/runtime/structure-ops/index.ts +1 -1
- package/src/runtime/surface-projection.ts +232 -262
- package/src/runtime/units.ts +4 -2
- package/src/runtime/workflow/coordinator.ts +1348 -0
- package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
- package/src/runtime/workflow/index.ts +25 -0
- package/src/runtime/workflow/markup-mode-policy.ts +98 -0
- package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
- package/src/runtime/workflow/metadata-persistence.ts +306 -0
- package/src/runtime/workflow/metadata-writer.ts +123 -0
- package/src/runtime/workflow/overlay-store.ts +690 -0
- package/src/runtime/workflow/projector.ts +127 -0
- package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
- package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
- package/src/runtime/workflow/rail/types.ts +198 -0
- package/src/runtime/workflow/scope-rail-composer.ts +39 -0
- package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
- package/src/runtime/workflow/scope-writer.ts +188 -0
- package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
- package/src/runtime/workflow/visibility-policy.ts +129 -0
- package/src/session/_sync-legacy.ts +66 -0
- package/src/session/export/embedded-reconstitute.ts +104 -0
- package/src/session/export/export-diagnostics.ts +85 -0
- package/src/session/export/export-validation.ts +110 -0
- package/src/session/export/index.ts +34 -0
- package/src/session/export/preservation-reattach.ts +30 -0
- package/src/session/export/serialize-dispatch.ts +165 -0
- package/src/session/export/stateful-export-pipeline.ts +432 -0
- package/src/session/export/stateful-export.ts +684 -0
- package/src/session/import/canonical-assembly.ts +227 -0
- package/src/session/import/diagnostics-session.ts +54 -0
- package/src/session/import/embedded-discovery.ts +225 -0
- package/src/session/import/embedded-offload.ts +337 -0
- package/src/session/import/import-diagnostics.ts +69 -0
- package/src/session/import/loader-types.ts +313 -0
- package/src/session/import/loader.ts +1834 -0
- package/src/session/import/normalize.ts +195 -0
- package/src/session/import/package-parts.ts +217 -0
- package/src/session/import/package-read.ts +195 -0
- package/src/session/import/parse-orchestration.ts +105 -0
- package/src/session/import/part-constants.ts +70 -0
- package/src/session/import/part-discovery.ts +94 -0
- package/src/session/import/preservation-index.ts +46 -0
- package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
- package/src/session/import/review-import.ts +508 -0
- package/src/session/import/styles-consolidation.ts +281 -0
- package/src/session/import/workflow-scope-import.ts +256 -0
- package/src/session/index.ts +37 -0
- package/src/session/session-state.ts +69 -0
- package/src/session/session.ts +532 -0
- package/src/session/shared/protection.ts +228 -0
- package/src/session/shared/session-utils.ts +82 -0
- package/src/session/types.ts +499 -0
- package/src/shell/chart-snapshots.ts +96 -0
- package/src/shell/media-previews.ts +85 -0
- package/src/shell/overlay-anchor-bridge.ts +53 -0
- package/src/shell/paste-adapter.ts +23 -0
- package/src/shell/ref-commands.ts +1697 -0
- package/src/shell/ref-utilities.ts +48 -0
- package/src/shell/search.ts +51 -0
- package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
- package/src/shell/ui-subscriber-channels.ts +81 -0
- package/src/shell/use-collab-sync.ts +116 -0
- package/src/ui/WordReviewEditor.tsx +496 -2051
- package/src/ui/editor-shell-view.tsx +30 -1
- package/src/ui/editor-surface-controller.tsx +49 -1
- package/src/ui/headless/revision-decoration-model.ts +83 -0
- package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
- package/src/ui/headless/scoped-chrome-policy.ts +2 -2
- package/src/ui/headless/selection-tool-context.ts +1 -1
- package/src/ui/headless/selection-tool-resolver.ts +1 -1
- package/src/ui/runtime-shortcut-dispatch.ts +46 -1
- package/src/ui/ui-controller-factory.ts +221 -0
- package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
- package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
- package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
- package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
- package/src/ui-tailwind/chart/render/area.tsx +3 -3
- package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
- package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
- package/src/ui-tailwind/chart/render/combo.tsx +2 -2
- package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
- package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
- package/src/ui-tailwind/chart/render/line.tsx +3 -3
- package/src/ui-tailwind/chart/render/pie.tsx +6 -6
- package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
- package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
- package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
- package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
- package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
- package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
- package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
- package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
- package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
- package/src/ui-tailwind/debug/README.md +57 -0
- package/src/ui-tailwind/debug/index.ts +3 -0
- package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
- package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
- package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
- package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
- package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
- package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
- package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
- package/src/ui-tailwind/index.ts +0 -5
- package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
- package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
- package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
- package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
- package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
- package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
- package/src/ui-tailwind/review-workspace/types.ts +408 -0
- package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
- package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
- package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
- package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
- package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
- package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
- package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
- package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
- package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
- package/src/ui-tailwind/theme/editor-theme.css +25 -0
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
- package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
- package/src/ui-tailwind/ui-api-context.tsx +43 -0
- package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
- package/src/validation/compatibility-engine.ts +6 -6
- package/src/runtime/styles-cascade.ts +0 -33
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
- /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
- /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
- /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @internal — Bounded ring buffer backing TelemetryBus channel tails.
|
|
2
|
+
//
|
|
3
|
+
// Fixed-size circular buffer. `push` drops the oldest when full. `tail(n)`
|
|
4
|
+
// returns the last `n` items in insertion order (oldest→newest). No
|
|
5
|
+
// allocation in the steady state once the buffer fills up — we overwrite
|
|
6
|
+
// in place.
|
|
7
|
+
//
|
|
8
|
+
// Browser + Node safe (no globals beyond standard JS). Imported by
|
|
9
|
+
// `src/runtime/debug/telemetry-bus.ts` and, transitively, by the Phase 2
|
|
10
|
+
// Railway-hosted `services/debug/` Next.js service via the in-process
|
|
11
|
+
// `runtime.debug.getBus()` accessor.
|
|
12
|
+
|
|
13
|
+
export class EventRingBuffer<T> {
|
|
14
|
+
private readonly capacity: number;
|
|
15
|
+
private buf: (T | undefined)[];
|
|
16
|
+
private writeIndex = 0;
|
|
17
|
+
private count = 0;
|
|
18
|
+
|
|
19
|
+
constructor(capacity: number) {
|
|
20
|
+
if (!Number.isInteger(capacity) || capacity <= 0) {
|
|
21
|
+
throw new Error(`EventRingBuffer capacity must be a positive integer, got ${capacity}`);
|
|
22
|
+
}
|
|
23
|
+
this.capacity = capacity;
|
|
24
|
+
this.buf = new Array(capacity);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
push(item: T): void {
|
|
28
|
+
this.buf[this.writeIndex] = item;
|
|
29
|
+
this.writeIndex = (this.writeIndex + 1) % this.capacity;
|
|
30
|
+
if (this.count < this.capacity) this.count += 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Returns last n items in insertion order (oldest first). */
|
|
34
|
+
tail(n: number): T[] {
|
|
35
|
+
const take = Math.min(n, this.count);
|
|
36
|
+
if (take <= 0) return [];
|
|
37
|
+
const out: T[] = new Array(take);
|
|
38
|
+
// Oldest in the current window lives `count` items behind writeIndex.
|
|
39
|
+
const start = (this.writeIndex - take + this.capacity) % this.capacity;
|
|
40
|
+
for (let i = 0; i < take; i += 1) {
|
|
41
|
+
out[i] = this.buf[(start + i) % this.capacity] as T;
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** All buffered items in insertion order (up to capacity). */
|
|
47
|
+
all(): T[] {
|
|
48
|
+
return this.tail(this.count);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
size(): number {
|
|
52
|
+
return this.count;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getCapacity(): number {
|
|
56
|
+
return this.capacity;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
clear(): void {
|
|
60
|
+
this.buf = new Array(this.capacity);
|
|
61
|
+
this.writeIndex = 0;
|
|
62
|
+
this.count = 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Probability-gated emit helper for telemetry channels whose full-volume
|
|
2
|
+
// emission would be unbounded (e.g. per-formatting-resolution samples).
|
|
3
|
+
//
|
|
4
|
+
// Contract: `shouldEmitSample(rate)` returns `true` with probability
|
|
5
|
+
// `rate`, `false` otherwise. Edge cases:
|
|
6
|
+
// - `rate <= 0` → always `false`
|
|
7
|
+
// - `rate >= 1` → always `true`
|
|
8
|
+
// - NaN or non-finite → always `false` (conservative)
|
|
9
|
+
//
|
|
10
|
+
// Not cryptographically random — uses Math.random. Suitable for
|
|
11
|
+
// telemetry sampling; NOT for security decisions.
|
|
12
|
+
|
|
13
|
+
export function shouldEmitSample(rate: number): boolean {
|
|
14
|
+
if (!Number.isFinite(rate)) return false;
|
|
15
|
+
if (rate <= 0) return false;
|
|
16
|
+
if (rate >= 1) return true;
|
|
17
|
+
return Math.random() < rate;
|
|
18
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @internal — `runtime.debug` facet.
|
|
2
|
+
//
|
|
3
|
+
// The one handle into the runtime's telemetry bus + the on-demand projector
|
|
4
|
+
// snapshot. Consumed by:
|
|
5
|
+
// - The harness dev drawer (`HarnessDebugPanel`), in-process.
|
|
6
|
+
// - The Phase 2 `services/debug/` Railway service, either in-process (Node
|
|
7
|
+
// executor) or through the hidden harness page's `window.__debug` RPC
|
|
8
|
+
// that proxies these methods.
|
|
9
|
+
//
|
|
10
|
+
// This module imports `TelemetryBus` + the projector. `DocumentRuntime`
|
|
11
|
+
// constructs a `RuntimeDebugFacet` via `createRuntimeDebugFacet(runtime, bus)`
|
|
12
|
+
// at the end of its factory and exposes it on the interface.
|
|
13
|
+
|
|
14
|
+
import type { DocumentRuntime } from "../document-runtime.ts";
|
|
15
|
+
import type { TelemetryBus } from "./telemetry-bus.ts";
|
|
16
|
+
import {
|
|
17
|
+
buildDebugInspectorSnapshot,
|
|
18
|
+
} from "./build-debug-inspector-snapshot.ts";
|
|
19
|
+
import type {
|
|
20
|
+
DebugInspectorQuery,
|
|
21
|
+
DebugInspectorSnapshot,
|
|
22
|
+
RuntimeTelemetryEvent,
|
|
23
|
+
TelemetryChannel,
|
|
24
|
+
} from "./types.ts";
|
|
25
|
+
|
|
26
|
+
export interface RuntimeDebugFacet {
|
|
27
|
+
/** The live bus. Callers emit / subscribe / toggle channels here. */
|
|
28
|
+
readonly bus: TelemetryBus;
|
|
29
|
+
/** Compose a full `DebugInspectorSnapshot` on demand. */
|
|
30
|
+
getSnapshot(query?: DebugInspectorQuery): DebugInspectorSnapshot;
|
|
31
|
+
/** Read the last `n` events across all channels. */
|
|
32
|
+
tail(n?: number): RuntimeTelemetryEvent[];
|
|
33
|
+
/** Read the last `n` events from one channel. */
|
|
34
|
+
tailChannel(channel: TelemetryChannel, n?: number): RuntimeTelemetryEvent[];
|
|
35
|
+
/**
|
|
36
|
+
* Bulk-apply a partial channel record; returns the resulting channel
|
|
37
|
+
* state. Mirrors the `services/debug/` session API.
|
|
38
|
+
*/
|
|
39
|
+
setChannels(flags: Partial<Record<TelemetryChannel, boolean>>): Record<TelemetryChannel, boolean>;
|
|
40
|
+
/** Current channel state. */
|
|
41
|
+
getChannels(): Record<TelemetryChannel, boolean>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createRuntimeDebugFacet(
|
|
45
|
+
getRuntime: () => DocumentRuntime,
|
|
46
|
+
bus: TelemetryBus,
|
|
47
|
+
): RuntimeDebugFacet {
|
|
48
|
+
return {
|
|
49
|
+
bus,
|
|
50
|
+
getSnapshot(query) {
|
|
51
|
+
return buildDebugInspectorSnapshot(getRuntime(), query, { bus });
|
|
52
|
+
},
|
|
53
|
+
tail(n = 64) {
|
|
54
|
+
return bus.tailAll(n);
|
|
55
|
+
},
|
|
56
|
+
tailChannel(channel, n = 64) {
|
|
57
|
+
return bus.tail(channel, n);
|
|
58
|
+
},
|
|
59
|
+
setChannels(flags) {
|
|
60
|
+
bus.setChannels(flags);
|
|
61
|
+
return bus.getChannels();
|
|
62
|
+
},
|
|
63
|
+
getChannels() {
|
|
64
|
+
return bus.getChannels();
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TelemetryBus } from "./telemetry-bus.ts";
|
|
2
|
+
import type { TelemetryChannel } from "./types.ts";
|
|
3
|
+
|
|
4
|
+
let tokenSeq = 0;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Bitmap-gated: no-ops when `channel` is disabled. When enabled, emits
|
|
8
|
+
* a stage-token event recording the crossing of a runtime boundary.
|
|
9
|
+
* Powers D1 lineage — the chain commit.start → commit.apply.complete
|
|
10
|
+
* proves no silent short-circuit swallowed a mutation.
|
|
11
|
+
*/
|
|
12
|
+
export function emitStageToken(
|
|
13
|
+
bus: TelemetryBus,
|
|
14
|
+
channel: TelemetryChannel,
|
|
15
|
+
stage: string,
|
|
16
|
+
inputs: Record<string, unknown>,
|
|
17
|
+
): void {
|
|
18
|
+
if (!bus.isEnabled(channel)) return;
|
|
19
|
+
bus.emit({
|
|
20
|
+
channel,
|
|
21
|
+
type: stage,
|
|
22
|
+
t: typeof performance !== "undefined" && typeof performance.now === "function"
|
|
23
|
+
? performance.now()
|
|
24
|
+
: Date.now(),
|
|
25
|
+
payload: {
|
|
26
|
+
stageTokenId: String(++tokenSeq),
|
|
27
|
+
emittedAtUtc: new Date().toISOString(),
|
|
28
|
+
inputs: { ...inputs },
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// @internal — TelemetryBus.
|
|
2
|
+
//
|
|
3
|
+
// Session-scoped runtime telemetry channel hub. Consumed by:
|
|
4
|
+
// 1. `DocumentRuntime` — owns one bus per runtime; exposes it via
|
|
5
|
+
// `runtime.debug.getBus()`. Hook-points (parse/serialize/api/scope/
|
|
6
|
+
// warning/commit/…) call `bus.emit(...)` or `bus.emitLazy(...)`.
|
|
7
|
+
// 2. The harness dev drawer — reads `bus.tail(channel, n)` for the live
|
|
8
|
+
// event trace card.
|
|
9
|
+
// 3. The Phase 2 `services/debug/` Railway service — the hidden
|
|
10
|
+
// `/session/[id]` page exposes `window.__debug.setChannels({...})`
|
|
11
|
+
// and `window.__debug.tailTelemetry(n)` that proxy to the bus.
|
|
12
|
+
//
|
|
13
|
+
// Performance contract (CLAUDE.md perf invariants 1/4/7):
|
|
14
|
+
// - All channels default to OFF.
|
|
15
|
+
// - `isEnabled(channel)` is a single integer bitmask AND.
|
|
16
|
+
// - `emit(ev)` early-returns when the channel bit is off before doing any
|
|
17
|
+
// work beyond the check.
|
|
18
|
+
// - `emitLazy(channel, factory)` does NOT invoke the factory when the
|
|
19
|
+
// channel is off; used at hot hook-points where building the payload
|
|
20
|
+
// would itself allocate (e.g. stringifying args, computing digests).
|
|
21
|
+
// - Ring buffer writes overwrite in place — no allocation in steady state.
|
|
22
|
+
//
|
|
23
|
+
// Browser + Node safe. No DOM / no performance.now dependency (uses a small
|
|
24
|
+
// `now()` helper that falls back to `Date.now()` when performance is absent).
|
|
25
|
+
|
|
26
|
+
import { EventRingBuffer } from "./event-ring-buffer.ts";
|
|
27
|
+
import type { RuntimeTelemetryEvent, TelemetryChannel } from "./types.ts";
|
|
28
|
+
|
|
29
|
+
// The fixed channel order defines each channel's bit position in the bitmap.
|
|
30
|
+
// Changing the order is a break — consumers of recorded traces rely on it.
|
|
31
|
+
//
|
|
32
|
+
// F-2: `render` / `command` / `commit` / `collab` / `layout` are RESERVED —
|
|
33
|
+
// present in the union so `setChannels()` stays API-stable, but no emit sites
|
|
34
|
+
// exist yet. Phase C wires them. See TelemetryChannel docstring for details.
|
|
35
|
+
export const TELEMETRY_CHANNELS: readonly TelemetryChannel[] = [
|
|
36
|
+
"api",
|
|
37
|
+
"parse",
|
|
38
|
+
"serialize",
|
|
39
|
+
"render",
|
|
40
|
+
"command",
|
|
41
|
+
"scope",
|
|
42
|
+
"warning",
|
|
43
|
+
"selection",
|
|
44
|
+
"commit",
|
|
45
|
+
"collab",
|
|
46
|
+
"layout",
|
|
47
|
+
"io",
|
|
48
|
+
"formatting",
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
const CHANNEL_BIT: Record<TelemetryChannel, number> = (() => {
|
|
52
|
+
const bits: Partial<Record<TelemetryChannel, number>> = {};
|
|
53
|
+
for (let i = 0; i < TELEMETRY_CHANNELS.length; i += 1) {
|
|
54
|
+
bits[TELEMETRY_CHANNELS[i]] = 1 << i;
|
|
55
|
+
}
|
|
56
|
+
return bits as Record<TelemetryChannel, number>;
|
|
57
|
+
})();
|
|
58
|
+
|
|
59
|
+
function now(): number {
|
|
60
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
61
|
+
return performance.now();
|
|
62
|
+
}
|
|
63
|
+
return Date.now();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface TelemetryBusOptions {
|
|
67
|
+
/** Default ring size applied to every channel. Defaults to 256. */
|
|
68
|
+
readonly defaultRingSize?: number;
|
|
69
|
+
/** Channels to enable on construction. Default: none. */
|
|
70
|
+
readonly initialChannels?: readonly TelemetryChannel[];
|
|
71
|
+
/**
|
|
72
|
+
* Optional monotonic clock override. Defaults to `performance.now()` when
|
|
73
|
+
* available, else `Date.now()`. Used by tests for determinism.
|
|
74
|
+
*/
|
|
75
|
+
readonly clock?: () => number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type TelemetryListener = (ev: RuntimeTelemetryEvent) => void;
|
|
79
|
+
|
|
80
|
+
interface Subscription {
|
|
81
|
+
readonly mask: number;
|
|
82
|
+
readonly listener: TelemetryListener;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class TelemetryBus {
|
|
86
|
+
private enabledMask = 0;
|
|
87
|
+
private readonly rings: Map<TelemetryChannel, EventRingBuffer<RuntimeTelemetryEvent>> = new Map();
|
|
88
|
+
private readonly subscriptions: Set<Subscription> = new Set();
|
|
89
|
+
private readonly defaultRingSize: number;
|
|
90
|
+
private readonly clock: () => number;
|
|
91
|
+
private seq = 0;
|
|
92
|
+
|
|
93
|
+
constructor(options: TelemetryBusOptions = {}) {
|
|
94
|
+
this.defaultRingSize = options.defaultRingSize ?? 256;
|
|
95
|
+
this.clock = options.clock ?? now;
|
|
96
|
+
for (const ch of TELEMETRY_CHANNELS) {
|
|
97
|
+
this.rings.set(ch, new EventRingBuffer<RuntimeTelemetryEvent>(this.defaultRingSize));
|
|
98
|
+
}
|
|
99
|
+
if (options.initialChannels) {
|
|
100
|
+
for (const ch of options.initialChannels) this.enable(ch);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
enable(channel: TelemetryChannel): void {
|
|
105
|
+
this.enabledMask |= CHANNEL_BIT[channel];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
disable(channel: TelemetryChannel): void {
|
|
109
|
+
this.enabledMask &= ~CHANNEL_BIT[channel];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Bulk-apply a partial channel record — `{parse: true, render: false}`.
|
|
114
|
+
* Absent keys are left unchanged.
|
|
115
|
+
*/
|
|
116
|
+
setChannels(channels: Partial<Record<TelemetryChannel, boolean>>): void {
|
|
117
|
+
for (const ch of TELEMETRY_CHANNELS) {
|
|
118
|
+
const flag = channels[ch];
|
|
119
|
+
if (flag === true) this.enable(ch);
|
|
120
|
+
else if (flag === false) this.disable(ch);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Snapshot of the current channel flags. */
|
|
125
|
+
getChannels(): Record<TelemetryChannel, boolean> {
|
|
126
|
+
const out = {} as Record<TelemetryChannel, boolean>;
|
|
127
|
+
for (const ch of TELEMETRY_CHANNELS) {
|
|
128
|
+
out[ch] = (this.enabledMask & CHANNEL_BIT[ch]) !== 0;
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
isEnabled(channel: TelemetryChannel): boolean {
|
|
134
|
+
return (this.enabledMask & CHANNEL_BIT[channel]) !== 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Emit a pre-built event. The `t` + `seq` fields are filled in by the
|
|
139
|
+
* bus if absent on the input.
|
|
140
|
+
*
|
|
141
|
+
* Call sites that would otherwise allocate a payload before checking the
|
|
142
|
+
* channel flag should prefer `emitLazy(channel, factory)`.
|
|
143
|
+
*/
|
|
144
|
+
emit(event: RuntimeTelemetryEvent): void {
|
|
145
|
+
const channel = event.channel;
|
|
146
|
+
if ((this.enabledMask & CHANNEL_BIT[channel]) === 0) return;
|
|
147
|
+
const stamped: RuntimeTelemetryEvent = {
|
|
148
|
+
...event,
|
|
149
|
+
t: typeof event.t === "number" ? event.t : this.clock(),
|
|
150
|
+
seq: this.seq++,
|
|
151
|
+
} as RuntimeTelemetryEvent & { seq: number };
|
|
152
|
+
this.rings.get(channel)!.push(stamped);
|
|
153
|
+
this.dispatchToSubscribers(stamped);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Hot-path emit: the factory runs only when the channel is on. Used by
|
|
158
|
+
* parse/serialize/api hook-points that would otherwise pay the
|
|
159
|
+
* serialization cost every keystroke.
|
|
160
|
+
*/
|
|
161
|
+
emitLazy(
|
|
162
|
+
channel: TelemetryChannel,
|
|
163
|
+
factory: () => Omit<RuntimeTelemetryEvent, "channel" | "t" | "seq">,
|
|
164
|
+
): void {
|
|
165
|
+
if ((this.enabledMask & CHANNEL_BIT[channel]) === 0) return;
|
|
166
|
+
const base = factory();
|
|
167
|
+
const stamped: RuntimeTelemetryEvent = {
|
|
168
|
+
channel,
|
|
169
|
+
type: base.type,
|
|
170
|
+
payload: base.payload,
|
|
171
|
+
t: this.clock(),
|
|
172
|
+
seq: this.seq++,
|
|
173
|
+
} as RuntimeTelemetryEvent & { seq: number };
|
|
174
|
+
this.rings.get(channel)!.push(stamped);
|
|
175
|
+
this.dispatchToSubscribers(stamped);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
subscribe(channels: readonly TelemetryChannel[], listener: TelemetryListener): () => void {
|
|
179
|
+
let mask = 0;
|
|
180
|
+
for (const ch of channels) mask |= CHANNEL_BIT[ch];
|
|
181
|
+
const sub: Subscription = { mask, listener };
|
|
182
|
+
this.subscriptions.add(sub);
|
|
183
|
+
return () => {
|
|
184
|
+
this.subscriptions.delete(sub);
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Returns last n events from a channel, oldest first. */
|
|
189
|
+
tail(channel: TelemetryChannel, n: number): RuntimeTelemetryEvent[] {
|
|
190
|
+
return this.rings.get(channel)!.tail(n);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Returns last n events across all channels, merged and sorted by `seq`
|
|
195
|
+
* ascending (i.e. oldest emission first). When `n` exceeds the total,
|
|
196
|
+
* all buffered events are returned.
|
|
197
|
+
*/
|
|
198
|
+
tailAll(n: number): RuntimeTelemetryEvent[] {
|
|
199
|
+
const merged: RuntimeTelemetryEvent[] = [];
|
|
200
|
+
for (const ring of this.rings.values()) {
|
|
201
|
+
const items = ring.all();
|
|
202
|
+
for (const it of items) merged.push(it);
|
|
203
|
+
}
|
|
204
|
+
merged.sort((a, b) => ((a as { seq?: number }).seq ?? 0) - ((b as { seq?: number }).seq ?? 0));
|
|
205
|
+
if (merged.length <= n) return merged;
|
|
206
|
+
return merged.slice(merged.length - n);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
setRingSize(channel: TelemetryChannel, size: number): void {
|
|
210
|
+
if (!Number.isInteger(size) || size <= 0) {
|
|
211
|
+
throw new Error(`TelemetryBus ring size must be a positive integer, got ${size}`);
|
|
212
|
+
}
|
|
213
|
+
const existing = this.rings.get(channel)!.all();
|
|
214
|
+
const next = new EventRingBuffer<RuntimeTelemetryEvent>(size);
|
|
215
|
+
const carry = existing.slice(Math.max(0, existing.length - size));
|
|
216
|
+
for (const ev of carry) next.push(ev);
|
|
217
|
+
this.rings.set(channel, next);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
clear(channel?: TelemetryChannel): void {
|
|
221
|
+
if (channel) {
|
|
222
|
+
this.rings.get(channel)!.clear();
|
|
223
|
+
} else {
|
|
224
|
+
for (const ring of this.rings.values()) ring.clear();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private dispatchToSubscribers(ev: RuntimeTelemetryEvent): void {
|
|
229
|
+
const bit = CHANNEL_BIT[ev.channel];
|
|
230
|
+
for (const sub of this.subscriptions) {
|
|
231
|
+
if ((sub.mask & bit) !== 0) {
|
|
232
|
+
try {
|
|
233
|
+
sub.listener(ev);
|
|
234
|
+
} catch {
|
|
235
|
+
// Subscriber failures must not take down emitters.
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Shared no-op bus for code paths that run before the runtime is
|
|
244
|
+
* instantiated (loader probes, error boundaries). `isEnabled` always
|
|
245
|
+
* returns false; `emit`/`emitLazy` do nothing; `subscribe` returns a
|
|
246
|
+
* no-op unsubscriber.
|
|
247
|
+
*/
|
|
248
|
+
export const NOOP_TELEMETRY_BUS: Pick<
|
|
249
|
+
TelemetryBus,
|
|
250
|
+
"emit" | "emitLazy" | "isEnabled" | "subscribe" | "tail" | "tailAll" | "getChannels"
|
|
251
|
+
> = {
|
|
252
|
+
emit() {},
|
|
253
|
+
emitLazy() {},
|
|
254
|
+
isEnabled() {
|
|
255
|
+
return false;
|
|
256
|
+
},
|
|
257
|
+
subscribe() {
|
|
258
|
+
return () => {};
|
|
259
|
+
},
|
|
260
|
+
tail() {
|
|
261
|
+
return [];
|
|
262
|
+
},
|
|
263
|
+
tailAll() {
|
|
264
|
+
return [];
|
|
265
|
+
},
|
|
266
|
+
getChannels() {
|
|
267
|
+
const out = {} as Record<TelemetryChannel, boolean>;
|
|
268
|
+
for (const ch of TELEMETRY_CHANNELS) out[ch] = false;
|
|
269
|
+
return out;
|
|
270
|
+
},
|
|
271
|
+
};
|