ooxml-core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +3 -0
- package/README.md +125 -0
- package/THIRD-PARTY-LICENSES +26 -0
- package/dist/collab/assets.d.ts +42 -0
- package/dist/collab/assets.d.ts.map +1 -0
- package/dist/collab/awareness.d.ts +65 -0
- package/dist/collab/awareness.d.ts.map +1 -0
- package/dist/collab/binding.d.ts +36 -0
- package/dist/collab/binding.d.ts.map +1 -0
- package/dist/collab/codec.d.ts +37 -0
- package/dist/collab/codec.d.ts.map +1 -0
- package/dist/collab/emitter.d.ts +11 -0
- package/dist/collab/emitter.d.ts.map +1 -0
- package/dist/collab/external-provider.d.ts +50 -0
- package/dist/collab/external-provider.d.ts.map +1 -0
- package/dist/collab/identity.d.ts +48 -0
- package/dist/collab/identity.d.ts.map +1 -0
- package/dist/collab/index.cjs +1328 -0
- package/dist/collab/index.d.ts +18 -0
- package/dist/collab/index.d.ts.map +1 -0
- package/dist/collab/index.mjs +1225 -0
- package/dist/collab/lifecycle.d.ts +62 -0
- package/dist/collab/lifecycle.d.ts.map +1 -0
- package/dist/collab/memory-transport.d.ts +19 -0
- package/dist/collab/memory-transport.d.ts.map +1 -0
- package/dist/collab/ordering.d.ts +53 -0
- package/dist/collab/ordering.d.ts.map +1 -0
- package/dist/collab/policy.d.ts +39 -0
- package/dist/collab/policy.d.ts.map +1 -0
- package/dist/collab/presence.d.ts +61 -0
- package/dist/collab/presence.d.ts.map +1 -0
- package/dist/collab/provider.d.ts +55 -0
- package/dist/collab/provider.d.ts.map +1 -0
- package/dist/collab/session.d.ts +70 -0
- package/dist/collab/session.d.ts.map +1 -0
- package/dist/collab/transport-provider.d.ts +13 -0
- package/dist/collab/transport-provider.d.ts.map +1 -0
- package/dist/collab/validation.d.ts +38 -0
- package/dist/collab/validation.d.ts.map +1 -0
- package/dist/collab/websocket-transport.d.ts +33 -0
- package/dist/collab/websocket-transport.d.ts.map +1 -0
- package/dist/color/color-linear.d.ts +5 -0
- package/dist/color/color-linear.d.ts.map +1 -0
- package/dist/color/color-primitives.d.ts +183 -0
- package/dist/color/color-primitives.d.ts.map +1 -0
- package/dist/color/index.cjs +177 -0
- package/dist/color/index.d.ts +3 -0
- package/dist/color/index.d.ts.map +1 -0
- package/dist/color/index.mjs +161 -0
- package/dist/diagram/attributes.d.ts +12 -0
- package/dist/diagram/attributes.d.ts.map +1 -0
- package/dist/diagram/data-model.d.ts +18 -0
- package/dist/diagram/data-model.d.ts.map +1 -0
- package/dist/diagram/definitions.d.ts +14 -0
- package/dist/diagram/definitions.d.ts.map +1 -0
- package/dist/diagram/dom.d.ts +15 -0
- package/dist/diagram/dom.d.ts.map +1 -0
- package/dist/diagram/drawing-color.d.ts +28 -0
- package/dist/diagram/drawing-color.d.ts.map +1 -0
- package/dist/diagram/drawing-fill.d.ts +9 -0
- package/dist/diagram/drawing-fill.d.ts.map +1 -0
- package/dist/diagram/drawing-geometry.d.ts +23 -0
- package/dist/diagram/drawing-geometry.d.ts.map +1 -0
- package/dist/diagram/drawing-text.d.ts +5 -0
- package/dist/diagram/drawing-text.d.ts.map +1 -0
- package/dist/diagram/drawing.d.ts +7 -0
- package/dist/diagram/drawing.d.ts.map +1 -0
- package/dist/diagram/index.cjs +1193 -0
- package/dist/diagram/index.d.ts +14 -0
- package/dist/diagram/index.d.ts.map +1 -0
- package/dist/diagram/index.mjs +1161 -0
- package/dist/diagram/layout-category.d.ts +8 -0
- package/dist/diagram/layout-category.d.ts.map +1 -0
- package/dist/diagram/load.d.ts +36 -0
- package/dist/diagram/load.d.ts.map +1 -0
- package/dist/diagram/relationships.d.ts +35 -0
- package/dist/diagram/relationships.d.ts.map +1 -0
- package/dist/diagram/types.d.ts +306 -0
- package/dist/diagram/types.d.ts.map +1 -0
- package/dist/docx/block-parser.d.ts +13 -0
- package/dist/docx/block-parser.d.ts.map +1 -0
- package/dist/docx/bookmarks.d.ts +18 -0
- package/dist/docx/bookmarks.d.ts.map +1 -0
- package/dist/docx/breaks.d.ts +11 -0
- package/dist/docx/breaks.d.ts.map +1 -0
- package/dist/docx/character-styles.d.ts +4 -0
- package/dist/docx/character-styles.d.ts.map +1 -0
- package/dist/docx/comment-spans.d.ts +19 -0
- package/dist/docx/comment-spans.d.ts.map +1 -0
- package/dist/docx/comments.d.ts +4 -0
- package/dist/docx/comments.d.ts.map +1 -0
- package/dist/docx/core-properties.d.ts +18 -0
- package/dist/docx/core-properties.d.ts.map +1 -0
- package/dist/docx/default-styles.d.ts +8 -0
- package/dist/docx/default-styles.d.ts.map +1 -0
- package/dist/docx/defined-props.d.ts +9 -0
- package/dist/docx/defined-props.d.ts.map +1 -0
- package/dist/docx/diagram-document.d.ts +9 -0
- package/dist/docx/diagram-document.d.ts.map +1 -0
- package/dist/docx/diagram-theme.d.ts +8 -0
- package/dist/docx/diagram-theme.d.ts.map +1 -0
- package/dist/docx/diagram.d.ts +89 -0
- package/dist/docx/diagram.d.ts.map +1 -0
- package/dist/docx/docpr-ids.d.ts +14 -0
- package/dist/docx/docpr-ids.d.ts.map +1 -0
- package/dist/docx/document-parts.d.ts +18 -0
- package/dist/docx/document-parts.d.ts.map +1 -0
- package/dist/docx/drawing.d.ts +13 -0
- package/dist/docx/drawing.d.ts.map +1 -0
- package/dist/docx/element-order.d.ts +13 -0
- package/dist/docx/element-order.d.ts.map +1 -0
- package/dist/docx/embedded.cjs +7646 -0
- package/dist/docx/embedded.d.ts +5 -0
- package/dist/docx/embedded.d.ts.map +1 -0
- package/dist/docx/embedded.mjs +7639 -0
- package/dist/docx/expect-defined.d.ts +3 -0
- package/dist/docx/expect-defined.d.ts.map +1 -0
- package/dist/docx/field-date.d.ts +10 -0
- package/dist/docx/field-date.d.ts.map +1 -0
- package/dist/docx/field-runs.d.ts +10 -0
- package/dist/docx/field-runs.d.ts.map +1 -0
- package/dist/docx/generated/wml-simple-types.d.ts +298 -0
- package/dist/docx/generated/wml-simple-types.d.ts.map +1 -0
- package/dist/docx/heading-list-kinds.d.ts +10 -0
- package/dist/docx/heading-list-kinds.d.ts.map +1 -0
- package/dist/docx/highlight.d.ts +5 -0
- package/dist/docx/highlight.d.ts.map +1 -0
- package/dist/docx/hyperlink.d.ts +8 -0
- package/dist/docx/hyperlink.d.ts.map +1 -0
- package/dist/docx/index.cjs +9784 -0
- package/dist/docx/index.d.ts +40 -0
- package/dist/docx/index.d.ts.map +1 -0
- package/dist/docx/index.mjs +9456 -0
- package/dist/docx/inline-model.d.ts +68 -0
- package/dist/docx/inline-model.d.ts.map +1 -0
- package/dist/docx/language.d.ts +3 -0
- package/dist/docx/language.d.ts.map +1 -0
- package/dist/docx/layout/adapt-drop-cap.d.ts +10 -0
- package/dist/docx/layout/adapt-drop-cap.d.ts.map +1 -0
- package/dist/docx/layout/adapt-floats.d.ts +8 -0
- package/dist/docx/layout/adapt-floats.d.ts.map +1 -0
- package/dist/docx/layout/adapt-notes.d.ts +13 -0
- package/dist/docx/layout/adapt-notes.d.ts.map +1 -0
- package/dist/docx/layout/adapt-paragraph-box.d.ts +12 -0
- package/dist/docx/layout/adapt-paragraph-box.d.ts.map +1 -0
- package/dist/docx/layout/adapt-table.d.ts +12 -0
- package/dist/docx/layout/adapt-table.d.ts.map +1 -0
- package/dist/docx/layout/adapter.d.ts +5 -0
- package/dist/docx/layout/adapter.d.ts.map +1 -0
- package/dist/docx/layout/floats.d.ts +20 -0
- package/dist/docx/layout/floats.d.ts.map +1 -0
- package/dist/docx/layout/flow-paragraph.d.ts +26 -0
- package/dist/docx/layout/flow-paragraph.d.ts.map +1 -0
- package/dist/docx/layout/flow-table.d.ts +12 -0
- package/dist/docx/layout/flow-table.d.ts.map +1 -0
- package/dist/docx/layout/fonts.d.ts +3 -0
- package/dist/docx/layout/fonts.d.ts.map +1 -0
- package/dist/docx/layout/index.cjs +2537 -0
- package/dist/docx/layout/index.d.ts +20 -0
- package/dist/docx/layout/index.d.ts.map +1 -0
- package/dist/docx/layout/index.mjs +2503 -0
- package/dist/docx/layout/input.d.ts +206 -0
- package/dist/docx/layout/input.d.ts.map +1 -0
- package/dist/docx/layout/keep-rules.d.ts +24 -0
- package/dist/docx/layout/keep-rules.d.ts.map +1 -0
- package/dist/docx/layout/layout.d.ts +9 -0
- package/dist/docx/layout/layout.d.ts.map +1 -0
- package/dist/docx/layout/ligatures.d.ts +4 -0
- package/dist/docx/layout/ligatures.d.ts.map +1 -0
- package/dist/docx/layout/line-metrics.d.ts +21 -0
- package/dist/docx/layout/line-metrics.d.ts.map +1 -0
- package/dist/docx/layout/measure.d.ts +34 -0
- package/dist/docx/layout/measure.d.ts.map +1 -0
- package/dist/docx/layout/page-cursor.d.ts +45 -0
- package/dist/docx/layout/page-cursor.d.ts.map +1 -0
- package/dist/docx/layout/page-flow.d.ts +7 -0
- package/dist/docx/layout/page-flow.d.ts.map +1 -0
- package/dist/docx/layout/paragraph-fragments.d.ts +6 -0
- package/dist/docx/layout/paragraph-fragments.d.ts.map +1 -0
- package/dist/docx/layout/paragraph-layout.d.ts +37 -0
- package/dist/docx/layout/paragraph-layout.d.ts.map +1 -0
- package/dist/docx/layout/paragraph-tokens.d.ts +27 -0
- package/dist/docx/layout/paragraph-tokens.d.ts.map +1 -0
- package/dist/docx/layout/result.d.ts +139 -0
- package/dist/docx/layout/result.d.ts.map +1 -0
- package/dist/docx/layout/tab-stops.d.ts +14 -0
- package/dist/docx/layout/tab-stops.d.ts.map +1 -0
- package/dist/docx/layout/table-layout.d.ts +30 -0
- package/dist/docx/layout/table-layout.d.ts.map +1 -0
- package/dist/docx/layout/test-helpers.d.ts +3 -0
- package/dist/docx/layout/test-helpers.d.ts.map +1 -0
- package/dist/docx/layout/text-breaks.d.ts +56 -0
- package/dist/docx/layout/text-breaks.d.ts.map +1 -0
- package/dist/docx/layout/units.d.ts +17 -0
- package/dist/docx/layout/units.d.ts.map +1 -0
- package/dist/docx/layout/wrap.d.ts +22 -0
- package/dist/docx/layout/wrap.d.ts.map +1 -0
- package/dist/docx/ligatures.d.ts +9 -0
- package/dist/docx/ligatures.d.ts.map +1 -0
- package/dist/docx/load/detect.d.ts +6 -0
- package/dist/docx/load/detect.d.ts.map +1 -0
- package/dist/docx/load/index.cjs +8869 -0
- package/dist/docx/load/index.d.ts +3 -0
- package/dist/docx/load/index.d.ts.map +1 -0
- package/dist/docx/load/index.mjs +8860 -0
- package/dist/docx/load/legacy-doc.d.ts +7 -0
- package/dist/docx/load/legacy-doc.d.ts.map +1 -0
- package/dist/docx/model-paragraph.d.ts +100 -0
- package/dist/docx/model-paragraph.d.ts.map +1 -0
- package/dist/docx/model-run.d.ts +110 -0
- package/dist/docx/model-run.d.ts.map +1 -0
- package/dist/docx/model.d.ts +114 -0
- package/dist/docx/model.d.ts.map +1 -0
- package/dist/docx/notes.d.ts +9 -0
- package/dist/docx/notes.d.ts.map +1 -0
- package/dist/docx/numbering-editing.d.ts +30 -0
- package/dist/docx/numbering-editing.d.ts.map +1 -0
- package/dist/docx/numbering-format.d.ts +17 -0
- package/dist/docx/numbering-format.d.ts.map +1 -0
- package/dist/docx/numbering-model.d.ts +73 -0
- package/dist/docx/numbering-model.d.ts.map +1 -0
- package/dist/docx/numbering-package.d.ts +12 -0
- package/dist/docx/numbering-package.d.ts.map +1 -0
- package/dist/docx/numbering-parse.d.ts +8 -0
- package/dist/docx/numbering-parse.d.ts.map +1 -0
- package/dist/docx/numbering-parts.d.ts +4 -0
- package/dist/docx/numbering-parts.d.ts.map +1 -0
- package/dist/docx/numbering-text.d.ts +20 -0
- package/dist/docx/numbering-text.d.ts.map +1 -0
- package/dist/docx/numbering-write.d.ts +5 -0
- package/dist/docx/numbering-write.d.ts.map +1 -0
- package/dist/docx/package-parts.d.ts +4 -0
- package/dist/docx/package-parts.d.ts.map +1 -0
- package/dist/docx/page-background.d.ts +9 -0
- package/dist/docx/page-background.d.ts.map +1 -0
- package/dist/docx/page-borders.d.ts +9 -0
- package/dist/docx/page-borders.d.ts.map +1 -0
- package/dist/docx/paragraph-alignment.d.ts +21 -0
- package/dist/docx/paragraph-alignment.d.ts.map +1 -0
- package/dist/docx/paragraph-styles.d.ts +15 -0
- package/dist/docx/paragraph-styles.d.ts.map +1 -0
- package/dist/docx/parse-diagnostics.d.ts +10 -0
- package/dist/docx/parse-diagnostics.d.ts.map +1 -0
- package/dist/docx/parse-revisions.d.ts +36 -0
- package/dist/docx/parse-revisions.d.ts.map +1 -0
- package/dist/docx/parse-table.d.ts +5 -0
- package/dist/docx/parse-table.d.ts.map +1 -0
- package/dist/docx/parse-warnings.d.ts +9 -0
- package/dist/docx/parse-warnings.d.ts.map +1 -0
- package/dist/docx/parse.d.ts +13 -0
- package/dist/docx/parse.d.ts.map +1 -0
- package/dist/docx/part-relationships.d.ts +12 -0
- package/dist/docx/part-relationships.d.ts.map +1 -0
- package/dist/docx/relationship-allocator.d.ts +32 -0
- package/dist/docx/relationship-allocator.d.ts.map +1 -0
- package/dist/docx/relationships.d.ts +3 -0
- package/dist/docx/relationships.d.ts.map +1 -0
- package/dist/docx/resolve-table.d.ts +8 -0
- package/dist/docx/resolve-table.d.ts.map +1 -0
- package/dist/docx/revision-commands.d.ts +27 -0
- package/dist/docx/revision-commands.d.ts.map +1 -0
- package/dist/docx/revision-ids.d.ts +10 -0
- package/dist/docx/revision-ids.d.ts.map +1 -0
- package/dist/docx/run-formatting.d.ts +16 -0
- package/dist/docx/run-formatting.d.ts.map +1 -0
- package/dist/docx/run-properties.d.ts +5 -0
- package/dist/docx/run-properties.d.ts.map +1 -0
- package/dist/docx/run-style-model.d.ts +21 -0
- package/dist/docx/run-style-model.d.ts.map +1 -0
- package/dist/docx/save.d.ts +5 -0
- package/dist/docx/save.d.ts.map +1 -0
- package/dist/docx/section-model.d.ts +97 -0
- package/dist/docx/section-model.d.ts.map +1 -0
- package/dist/docx/sections.d.ts +18 -0
- package/dist/docx/sections.d.ts.map +1 -0
- package/dist/docx/settings.d.ts +11 -0
- package/dist/docx/settings.d.ts.map +1 -0
- package/dist/docx/simple-types.d.ts +37 -0
- package/dist/docx/simple-types.d.ts.map +1 -0
- package/dist/docx/style-numbering-package.d.ts +11 -0
- package/dist/docx/style-numbering-package.d.ts.map +1 -0
- package/dist/docx/tab-stops.d.ts +8 -0
- package/dist/docx/tab-stops.d.ts.map +1 -0
- package/dist/docx/table-borders.d.ts +15 -0
- package/dist/docx/table-borders.d.ts.map +1 -0
- package/dist/docx/table-cell-write.d.ts +12 -0
- package/dist/docx/table-cell-write.d.ts.map +1 -0
- package/dist/docx/table-defaults.d.ts +20 -0
- package/dist/docx/table-defaults.d.ts.map +1 -0
- package/dist/docx/table-model.d.ts +101 -0
- package/dist/docx/table-model.d.ts.map +1 -0
- package/dist/docx/table-of-contents.d.ts +67 -0
- package/dist/docx/table-of-contents.d.ts.map +1 -0
- package/dist/docx/table-of-figures.d.ts +10 -0
- package/dist/docx/table-of-figures.d.ts.map +1 -0
- package/dist/docx/table-styles.d.ts +4 -0
- package/dist/docx/table-styles.d.ts.map +1 -0
- package/dist/docx/table-visuals.d.ts +22 -0
- package/dist/docx/table-visuals.d.ts.map +1 -0
- package/dist/docx/test-support/access.d.ts +14 -0
- package/dist/docx/test-support/access.d.ts.map +1 -0
- package/dist/docx/test-support/heading-numbering-fixture.d.ts +5 -0
- package/dist/docx/test-support/heading-numbering-fixture.d.ts.map +1 -0
- package/dist/docx/test-support/restart-fixture.d.ts +17 -0
- package/dist/docx/test-support/restart-fixture.d.ts.map +1 -0
- package/dist/docx/test-support/schema-validation.d.ts +24 -0
- package/dist/docx/test-support/schema-validation.d.ts.map +1 -0
- package/dist/docx/theme-color.d.ts +16 -0
- package/dist/docx/theme-color.d.ts.map +1 -0
- package/dist/docx/theme-model.d.ts +31 -0
- package/dist/docx/theme-model.d.ts.map +1 -0
- package/dist/docx/theme.d.ts +6 -0
- package/dist/docx/theme.d.ts.map +1 -0
- package/dist/docx/underline.d.ts +5 -0
- package/dist/docx/underline.d.ts.map +1 -0
- package/dist/docx/units.d.ts +2 -0
- package/dist/docx/units.d.ts.map +1 -0
- package/dist/docx/validate-issues.d.ts +40 -0
- package/dist/docx/validate-issues.d.ts.map +1 -0
- package/dist/docx/validate-model.d.ts +8 -0
- package/dist/docx/validate-model.d.ts.map +1 -0
- package/dist/docx/validate-paragraph.d.ts +10 -0
- package/dist/docx/validate-paragraph.d.ts.map +1 -0
- package/dist/docx/validate-structure.d.ts +10 -0
- package/dist/docx/validate-structure.d.ts.map +1 -0
- package/dist/docx/watermark.d.ts +14 -0
- package/dist/docx/watermark.d.ts.map +1 -0
- package/dist/docx/write-comments.d.ts +12 -0
- package/dist/docx/write-comments.d.ts.map +1 -0
- package/dist/docx/write-drawing.d.ts +12 -0
- package/dist/docx/write-drawing.d.ts.map +1 -0
- package/dist/docx/write-header-footer.d.ts +21 -0
- package/dist/docx/write-header-footer.d.ts.map +1 -0
- package/dist/docx/write-inline.d.ts +23 -0
- package/dist/docx/write-inline.d.ts.map +1 -0
- package/dist/docx/write-notes.d.ts +5 -0
- package/dist/docx/write-notes.d.ts.map +1 -0
- package/dist/docx/write-paragraph-decoration.d.ts +5 -0
- package/dist/docx/write-paragraph-decoration.d.ts.map +1 -0
- package/dist/docx/write-paragraph-properties.d.ts +4 -0
- package/dist/docx/write-paragraph-properties.d.ts.map +1 -0
- package/dist/docx/write-paragraph.d.ts +8 -0
- package/dist/docx/write-paragraph.d.ts.map +1 -0
- package/dist/docx/write-ranges.d.ts +42 -0
- package/dist/docx/write-ranges.d.ts.map +1 -0
- package/dist/docx/write-revisions.d.ts +10 -0
- package/dist/docx/write-revisions.d.ts.map +1 -0
- package/dist/docx/write-run-extra.d.ts +5 -0
- package/dist/docx/write-run-extra.d.ts.map +1 -0
- package/dist/docx/write-run-validation.d.ts +4 -0
- package/dist/docx/write-run-validation.d.ts.map +1 -0
- package/dist/docx/write-run.d.ts +7 -0
- package/dist/docx/write-run.d.ts.map +1 -0
- package/dist/docx/write-sections.d.ts +10 -0
- package/dist/docx/write-sections.d.ts.map +1 -0
- package/dist/docx/write-table-properties.d.ts +13 -0
- package/dist/docx/write-table-properties.d.ts.map +1 -0
- package/dist/docx/write-table.d.ts +9 -0
- package/dist/docx/write-table.d.ts.map +1 -0
- package/dist/docx/write-text-box.d.ts +15 -0
- package/dist/docx/write-text-box.d.ts.map +1 -0
- package/dist/docx/write.d.ts +25 -0
- package/dist/docx/write.d.ts.map +1 -0
- package/dist/docx/xml.d.ts +14 -0
- package/dist/docx/xml.d.ts.map +1 -0
- package/dist/docx/zip-parts.d.ts +5 -0
- package/dist/docx/zip-parts.d.ts.map +1 -0
- package/dist/geometry/adjustment-aware-shapes.d.ts +63 -0
- package/dist/geometry/adjustment-aware-shapes.d.ts.map +1 -0
- package/dist/geometry/callout-geometry.d.ts +65 -0
- package/dist/geometry/callout-geometry.d.ts.map +1 -0
- package/dist/geometry/cloud-bezier-paths.d.ts +55 -0
- package/dist/geometry/cloud-bezier-paths.d.ts.map +1 -0
- package/dist/geometry/com-avlst-ground-truth.d.ts +48 -0
- package/dist/geometry/com-avlst-ground-truth.d.ts.map +1 -0
- package/dist/geometry/connector-elbow-geometry.d.ts +41 -0
- package/dist/geometry/connector-elbow-geometry.d.ts.map +1 -0
- package/dist/geometry/guide-formula-api.d.ts +55 -0
- package/dist/geometry/guide-formula-api.d.ts.map +1 -0
- package/dist/geometry/guide-formula-eval.d.ts +85 -0
- package/dist/geometry/guide-formula-eval.d.ts.map +1 -0
- package/dist/geometry/index.cjs +15031 -0
- package/dist/geometry/index.d.ts +80 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/index.mjs +14897 -0
- package/dist/geometry/indexed.d.ts +6 -0
- package/dist/geometry/indexed.d.ts.map +1 -0
- package/dist/geometry/preset-clip-paths-core.d.ts +20 -0
- package/dist/geometry/preset-clip-paths-core.d.ts.map +1 -0
- package/dist/geometry/preset-clip-paths-extended.d.ts +19 -0
- package/dist/geometry/preset-clip-paths-extended.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-action-buttons.d.ts +14 -0
- package/dist/geometry/preset-connection-sites-action-buttons.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-arrows-curved.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-arrows-curved.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-arrows-misc.d.ts +13 -0
- package/dist/geometry/preset-connection-sites-arrows-misc.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-arrows.d.ts +13 -0
- package/dist/geometry/preset-connection-sites-arrows.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-basic-a.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-basic-a.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-basic-b.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-basic-b.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-braces.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-braces.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-callouts-arrow.d.ts +14 -0
- package/dist/geometry/preset-connection-sites-callouts-arrow.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-callouts-basic.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-callouts-basic.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-circular-arrow.d.ts +14 -0
- package/dist/geometry/preset-connection-sites-circular-arrow.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-flowchart.d.ts +19 -0
- package/dist/geometry/preset-connection-sites-flowchart.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-gear9.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-gear9.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-left-circular-arrow.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-left-circular-arrow.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-left-right-circular-arrow.d.ts +13 -0
- package/dist/geometry/preset-connection-sites-left-right-circular-arrow.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-math.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-math.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-misc.d.ts +14 -0
- package/dist/geometry/preset-connection-sites-misc.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-polygons.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-polygons.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-quads.d.ts +14 -0
- package/dist/geometry/preset-connection-sites-quads.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-rects.d.ts +14 -0
- package/dist/geometry/preset-connection-sites-rects.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-ribbons.d.ts +12 -0
- package/dist/geometry/preset-connection-sites-ribbons.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-stars.d.ts +13 -0
- package/dist/geometry/preset-connection-sites-stars.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-table.d.ts +23 -0
- package/dist/geometry/preset-connection-sites-table.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-tabs.d.ts +11 -0
- package/dist/geometry/preset-connection-sites-tabs.d.ts.map +1 -0
- package/dist/geometry/preset-connection-sites-types.d.ts +52 -0
- package/dist/geometry/preset-connection-sites-types.d.ts.map +1 -0
- package/dist/geometry/preset-geometry-names.d.ts +53 -0
- package/dist/geometry/preset-geometry-names.d.ts.map +1 -0
- package/dist/geometry/preset-shape-clip-paths.d.ts +13 -0
- package/dist/geometry/preset-shape-clip-paths.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-action-buttons.d.ts +45 -0
- package/dist/geometry/preset-shape-definitions-action-buttons.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-arrow-callouts.d.ts +55 -0
- package/dist/geometry/preset-shape-definitions-arrow-callouts.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-arrows-refined.d.ts +45 -0
- package/dist/geometry/preset-shape-definitions-arrows-refined.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-arrows.d.ts +52 -0
- package/dist/geometry/preset-shape-definitions-arrows.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-chart-marks.d.ts +23 -0
- package/dist/geometry/preset-shape-definitions-chart-marks.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-cloud-callout.d.ts +28 -0
- package/dist/geometry/preset-shape-definitions-cloud-callout.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-connectors-brackets.d.ts +37 -0
- package/dist/geometry/preset-shape-definitions-connectors-brackets.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-curved-arrows-connectors.d.ts +43 -0
- package/dist/geometry/preset-shape-definitions-curved-arrows-connectors.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-curved-arrows-exact.d.ts +30 -0
- package/dist/geometry/preset-shape-definitions-curved-arrows-exact.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-flowchart.d.ts +29 -0
- package/dist/geometry/preset-shape-definitions-flowchart.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-gear6.d.ts +38 -0
- package/dist/geometry/preset-shape-definitions-gear6.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-gear9.d.ts +24 -0
- package/dist/geometry/preset-shape-definitions-gear9.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-misc.d.ts +38 -0
- package/dist/geometry/preset-shape-definitions-misc.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-rects-snips.d.ts +28 -0
- package/dist/geometry/preset-shape-definitions-rects-snips.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-scrolls-accent-callouts.d.ts +45 -0
- package/dist/geometry/preset-shape-definitions-scrolls-accent-callouts.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-table.d.ts +121 -0
- package/dist/geometry/preset-shape-definitions-table.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions-tabs-decorations.d.ts +48 -0
- package/dist/geometry/preset-shape-definitions-tabs-decorations.d.ts.map +1 -0
- package/dist/geometry/preset-shape-definitions.d.ts +28 -0
- package/dist/geometry/preset-shape-definitions.d.ts.map +1 -0
- package/dist/geometry/preset-shape-paths.d.ts +13 -0
- package/dist/geometry/preset-shape-paths.d.ts.map +1 -0
- package/dist/geometry/preset-shape-types.d.ts +33 -0
- package/dist/geometry/preset-shape-types.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-action-buttons.d.ts +13 -0
- package/dist/geometry/preset-text-rect-action-buttons.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-arrows.d.ts +3 -0
- package/dist/geometry/preset-text-rect-arrows.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-braces.d.ts +3 -0
- package/dist/geometry/preset-text-rect-braces.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-callouts.d.ts +3 -0
- package/dist/geometry/preset-text-rect-callouts.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-circular-arrows.d.ts +3 -0
- package/dist/geometry/preset-text-rect-circular-arrows.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-flowchart.d.ts +3 -0
- package/dist/geometry/preset-text-rect-flowchart.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-misc-a.d.ts +3 -0
- package/dist/geometry/preset-text-rect-misc-a.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-misc-b.d.ts +3 -0
- package/dist/geometry/preset-text-rect-misc-b.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-polygons.d.ts +3 -0
- package/dist/geometry/preset-text-rect-polygons.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-quads.d.ts +3 -0
- package/dist/geometry/preset-text-rect-quads.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-ribbons.d.ts +3 -0
- package/dist/geometry/preset-text-rect-ribbons.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-stars.d.ts +3 -0
- package/dist/geometry/preset-text-rect-stars.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-table.d.ts +20 -0
- package/dist/geometry/preset-text-rect-table.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-tabs.d.ts +3 -0
- package/dist/geometry/preset-text-rect-tabs.d.ts.map +1 -0
- package/dist/geometry/preset-text-rect-types.d.ts +46 -0
- package/dist/geometry/preset-text-rect-types.d.ts.map +1 -0
- package/dist/geometry/shape-boolean-clipping.d.ts +70 -0
- package/dist/geometry/shape-boolean-clipping.d.ts.map +1 -0
- package/dist/geometry/shape-boolean-ops.d.ts +142 -0
- package/dist/geometry/shape-boolean-ops.d.ts.map +1 -0
- package/dist/geometry/shape-boolean-svg.d.ts +31 -0
- package/dist/geometry/shape-boolean-svg.d.ts.map +1 -0
- package/dist/geometry/shape-boolean-types.d.ts +91 -0
- package/dist/geometry/shape-boolean-types.d.ts.map +1 -0
- package/dist/geometry/shape-boolean-union.d.ts +79 -0
- package/dist/geometry/shape-boolean-union.d.ts.map +1 -0
- package/dist/geometry/shape-boolean.d.ts +22 -0
- package/dist/geometry/shape-boolean.d.ts.map +1 -0
- package/dist/geometry/shape-definitions-extended.d.ts +18 -0
- package/dist/geometry/shape-definitions-extended.d.ts.map +1 -0
- package/dist/geometry/shape-definitions-primary.d.ts +19 -0
- package/dist/geometry/shape-definitions-primary.d.ts.map +1 -0
- package/dist/index.cjs +16618 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +16611 -0
- package/dist/opc/content-types.d.ts +14 -0
- package/dist/opc/content-types.d.ts.map +1 -0
- package/dist/opc/index.cjs +228 -0
- package/dist/opc/index.d.ts +6 -0
- package/dist/opc/index.d.ts.map +1 -0
- package/dist/opc/index.mjs +212 -0
- package/dist/opc/package.d.ts +14 -0
- package/dist/opc/package.d.ts.map +1 -0
- package/dist/opc/relationship-types.d.ts +34 -0
- package/dist/opc/relationship-types.d.ts.map +1 -0
- package/dist/opc/relationships.d.ts +29 -0
- package/dist/opc/relationships.d.ts.map +1 -0
- package/dist/opc/safe-href.d.ts +3 -0
- package/dist/opc/safe-href.d.ts.map +1 -0
- package/dist/pptx/chunks/index-CojJtI77.d.ts +9627 -0
- package/dist/pptx/chunks/index-CojJtI77.d.ts.map +1 -0
- package/dist/pptx/chunks/signature-inspection-status-Bh2oap7B.d.ts +220 -0
- package/dist/pptx/chunks/signature-inspection-status-Bh2oap7B.d.ts.map +1 -0
- package/dist/pptx/chunks/text-operations-IlJiffp7.d.ts +11122 -0
- package/dist/pptx/chunks/text-operations-IlJiffp7.d.ts.map +1 -0
- package/dist/pptx/cli/index.cjs +138457 -0
- package/dist/pptx/cli/index.d.ts +139 -0
- package/dist/pptx/cli/index.d.ts.map +1 -0
- package/dist/pptx/cli/index.mjs +138424 -0
- package/dist/pptx/converter/index.cjs +32084 -0
- package/dist/pptx/converter/index.d.ts +2 -0
- package/dist/pptx/converter/index.mjs +32060 -0
- package/dist/pptx/index.cjs +172307 -0
- package/dist/pptx/index.d.ts +9692 -0
- package/dist/pptx/index.d.ts.map +1 -0
- package/dist/pptx/index.mjs +171623 -0
- package/dist/pptx/signature-node/index.cjs +1299 -0
- package/dist/pptx/signature-node/index.d.ts +172 -0
- package/dist/pptx/signature-node/index.d.ts.map +1 -0
- package/dist/pptx/signature-node/index.mjs +1236 -0
- package/dist/units/constants.d.ts +13 -0
- package/dist/units/constants.d.ts.map +1 -0
- package/dist/units/index.cjs +76 -0
- package/dist/units/index.d.ts +3 -0
- package/dist/units/index.d.ts.map +1 -0
- package/dist/units/index.mjs +45 -0
- package/dist/units/units.d.ts +52 -0
- package/dist/units/units.d.ts.map +1 -0
- package/dist/xml/index.cjs +98 -0
- package/dist/xml/index.d.ts +3 -0
- package/dist/xml/index.d.ts.map +1 -0
- package/dist/xml/index.mjs +85 -0
- package/dist/xml/namespaces.d.ts +47 -0
- package/dist/xml/namespaces.d.ts.map +1 -0
- package/dist/xml/xml.d.ts +31 -0
- package/dist/xml/xml.d.ts.map +1 -0
- package/package.json +192 -0
|
@@ -0,0 +1,1225 @@
|
|
|
1
|
+
import * as Y from 'yjs';
|
|
2
|
+
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
3
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
4
|
+
import * as decoding from 'lib0/decoding';
|
|
5
|
+
import * as encoding from 'lib0/encoding';
|
|
6
|
+
|
|
7
|
+
// src/collab/assets.ts
|
|
8
|
+
var isPayload = (value) => typeof value === "string" && value.length > 0;
|
|
9
|
+
function createAssetSync(spec) {
|
|
10
|
+
const suffix = spec.versionSuffix ?? "__v";
|
|
11
|
+
const fieldNames = Object.keys(spec.fields);
|
|
12
|
+
const refToField = new Map(Object.entries(spec.fields).map(([field, ref]) => [ref, field]));
|
|
13
|
+
const assetKey = (ownerId, field) => `${ownerId}:${field}`;
|
|
14
|
+
const versionKey = (field) => `${field}${suffix}`;
|
|
15
|
+
const refOf = (field) => spec.fields[field];
|
|
16
|
+
return {
|
|
17
|
+
spec,
|
|
18
|
+
isAssetField: (field) => field in spec.fields,
|
|
19
|
+
isRefKey: (key) => refToField.has(key),
|
|
20
|
+
isVersionKey: (key) => key.endsWith(suffix) && key.slice(0, -suffix.length) in spec.fields,
|
|
21
|
+
assetKey,
|
|
22
|
+
getMap: (doc) => doc.getMap(spec.mapName),
|
|
23
|
+
write(ownerId, record, owner, assets) {
|
|
24
|
+
for (const field of fieldNames) {
|
|
25
|
+
const value = record[field];
|
|
26
|
+
if (!isPayload(value)) continue;
|
|
27
|
+
const key = assetKey(ownerId, field);
|
|
28
|
+
if (assets.get(key) !== value) assets.set(key, value);
|
|
29
|
+
owner.set(refOf(field), key);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
reconcile(ownerId, record, owner, assets) {
|
|
33
|
+
for (const field of fieldNames) {
|
|
34
|
+
const refKey = refOf(field);
|
|
35
|
+
const value = record[field];
|
|
36
|
+
if (isPayload(value)) {
|
|
37
|
+
const key = assetKey(ownerId, field);
|
|
38
|
+
if (assets.get(key) !== value) {
|
|
39
|
+
assets.set(key, value);
|
|
40
|
+
const current = owner.get(versionKey(field));
|
|
41
|
+
owner.set(versionKey(field), (typeof current === "number" ? current : 0) + 1);
|
|
42
|
+
}
|
|
43
|
+
if (owner.get(refKey) !== key) owner.set(refKey, key);
|
|
44
|
+
} else {
|
|
45
|
+
const existing = owner.get(refKey);
|
|
46
|
+
if (typeof existing === "string") {
|
|
47
|
+
owner.delete(refKey);
|
|
48
|
+
assets.delete(existing);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
read(owner, assets, target) {
|
|
54
|
+
for (const [refKey, field] of refToField) {
|
|
55
|
+
const ref = owner.get(refKey);
|
|
56
|
+
if (typeof ref !== "string") continue;
|
|
57
|
+
const value = assets.get(ref);
|
|
58
|
+
if (typeof value === "string") target[field] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/collab/validation.ts
|
|
65
|
+
var DEFAULT_COLOR = "#4c8bf5";
|
|
66
|
+
var ROOM_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/u;
|
|
67
|
+
var HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/u;
|
|
68
|
+
var CONTROL_CHARS = /[\u0000-\u001f\u007f]/u;
|
|
69
|
+
function isValidRoomId(roomId) {
|
|
70
|
+
return typeof roomId === "string" && ROOM_ID_REGEX.test(roomId);
|
|
71
|
+
}
|
|
72
|
+
function validateRoomId(roomId) {
|
|
73
|
+
if (!isValidRoomId(roomId)) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Invalid collaboration room ID: "${String(roomId)}". Must be 1-128 alphanumeric characters, hyphens, or underscores.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return roomId;
|
|
79
|
+
}
|
|
80
|
+
function isValidId(value, max = 160) {
|
|
81
|
+
return typeof value === "string" && value.length > 0 && value.length <= max;
|
|
82
|
+
}
|
|
83
|
+
function isNonNegativeSafeInteger(value) {
|
|
84
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
85
|
+
}
|
|
86
|
+
function stripHtmlTags(text) {
|
|
87
|
+
let result = "";
|
|
88
|
+
let insideTag = false;
|
|
89
|
+
for (const char of text) {
|
|
90
|
+
if (char === "<") insideTag = true;
|
|
91
|
+
else if (char === ">") insideTag = false;
|
|
92
|
+
else if (!insideTag) result += char;
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
function sanitizeUserName(name, fallback = "Anonymous") {
|
|
97
|
+
if (typeof name !== "string") return fallback;
|
|
98
|
+
const trimmed = stripHtmlTags(name).trim().slice(0, 64);
|
|
99
|
+
return trimmed || fallback;
|
|
100
|
+
}
|
|
101
|
+
function validateDisplayName(name) {
|
|
102
|
+
const trimmed = name.trim();
|
|
103
|
+
if (!trimmed || trimmed.length > 80 || CONTROL_CHARS.test(trimmed))
|
|
104
|
+
throw new Error("Display name must contain 1 to 80 printable characters");
|
|
105
|
+
return trimmed;
|
|
106
|
+
}
|
|
107
|
+
function sanitizeColor(color, fallback = DEFAULT_COLOR) {
|
|
108
|
+
return typeof color === "string" && HEX_COLOR_REGEX.test(color) ? color : fallback;
|
|
109
|
+
}
|
|
110
|
+
function sanitizeAvatarUrl(url) {
|
|
111
|
+
if (typeof url !== "string") return void 0;
|
|
112
|
+
try {
|
|
113
|
+
const { protocol } = new URL(url);
|
|
114
|
+
if (protocol === "https:" || protocol === "http:" || protocol === "data:") return url;
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
function sanitizeIndex(value) {
|
|
120
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0;
|
|
121
|
+
return Math.max(0, Math.floor(value));
|
|
122
|
+
}
|
|
123
|
+
function clampCoordinate(value, min, max, margin = 20) {
|
|
124
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0;
|
|
125
|
+
return Math.max(min - margin, Math.min(max + margin, value));
|
|
126
|
+
}
|
|
127
|
+
var LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
|
|
128
|
+
function isMixedContentBlocked(serverUrl, pageProtocol = globalThis.location?.protocol) {
|
|
129
|
+
if (pageProtocol !== "https:") return false;
|
|
130
|
+
let parsed;
|
|
131
|
+
try {
|
|
132
|
+
parsed = new URL(serverUrl);
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return parsed.protocol === "ws:" && !LOOPBACK_HOSTS.includes(parsed.hostname);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/collab/identity.ts
|
|
140
|
+
var COLLABORATION_ROLES = [
|
|
141
|
+
"owner",
|
|
142
|
+
"collaborator",
|
|
143
|
+
"viewer"
|
|
144
|
+
];
|
|
145
|
+
function sanitizeRole(value) {
|
|
146
|
+
return COLLABORATION_ROLES.includes(value) ? value : void 0;
|
|
147
|
+
}
|
|
148
|
+
function canWrite(role) {
|
|
149
|
+
return role !== "viewer";
|
|
150
|
+
}
|
|
151
|
+
var CURSOR_PALETTE = [
|
|
152
|
+
"#ef4444",
|
|
153
|
+
"#f97316",
|
|
154
|
+
"#eab308",
|
|
155
|
+
"#22c55e",
|
|
156
|
+
"#06b6d4",
|
|
157
|
+
"#3b82f6",
|
|
158
|
+
"#8b5cf6",
|
|
159
|
+
"#ec4899"
|
|
160
|
+
];
|
|
161
|
+
var MAX_LABEL_CHARS = 20;
|
|
162
|
+
function assignUserColor(seed, palette = CURSOR_PALETTE) {
|
|
163
|
+
if (palette.length === 0) return DEFAULT_COLOR;
|
|
164
|
+
let hash = 0;
|
|
165
|
+
const text = String(seed);
|
|
166
|
+
for (let i = 0; i < text.length; i++) hash = hash * 31 + text.charCodeAt(i) | 0;
|
|
167
|
+
return palette[Math.abs(hash) % palette.length] ?? DEFAULT_COLOR;
|
|
168
|
+
}
|
|
169
|
+
function formatCursorLabel(userName, maxChars = MAX_LABEL_CHARS) {
|
|
170
|
+
if (userName.length <= maxChars) return userName;
|
|
171
|
+
return `${userName.slice(0, Math.max(0, maxChars - 3))}...`;
|
|
172
|
+
}
|
|
173
|
+
function getUserInitials(name) {
|
|
174
|
+
const trimmed = name.trim();
|
|
175
|
+
const parts = trimmed.split(/\s+/u).filter(Boolean);
|
|
176
|
+
const first = parts[0];
|
|
177
|
+
const last = parts[parts.length - 1];
|
|
178
|
+
if (parts.length >= 2 && first && last) return (first[0] + last[0]).toUpperCase();
|
|
179
|
+
return trimmed.slice(0, 2).toUpperCase();
|
|
180
|
+
}
|
|
181
|
+
function createClientId() {
|
|
182
|
+
const cryptoApi = globalThis.crypto;
|
|
183
|
+
if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
|
|
184
|
+
return `c${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
185
|
+
}
|
|
186
|
+
function clientKey(clientId) {
|
|
187
|
+
if (!isValidId(clientId)) throw new Error("Invalid collaboration client ID");
|
|
188
|
+
return Array.from(clientId, (character) => character.codePointAt(0).toString(16)).join("_");
|
|
189
|
+
}
|
|
190
|
+
function createIdGenerator(clientId, prefix = "cid") {
|
|
191
|
+
const key = clientKey(clientId);
|
|
192
|
+
let counter = 0;
|
|
193
|
+
return (kind) => {
|
|
194
|
+
const safeKind = kind.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 24) || "item";
|
|
195
|
+
return `${prefix}-${safeKind}-${key}-${++counter}`;
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function buildRoster(params) {
|
|
199
|
+
const customInitials = params.localUserInitials?.trim();
|
|
200
|
+
const local = {
|
|
201
|
+
id: "local",
|
|
202
|
+
name: params.localUserName,
|
|
203
|
+
initials: customInitials ? customInitials.slice(0, 2).toUpperCase() : getUserInitials(params.localUserName),
|
|
204
|
+
color: params.localUserColor ?? "#6366f1",
|
|
205
|
+
isLocal: true
|
|
206
|
+
};
|
|
207
|
+
const remote = params.remoteUsers.map((user) => {
|
|
208
|
+
const entry = {
|
|
209
|
+
id: String(user.clientId),
|
|
210
|
+
name: user.userName,
|
|
211
|
+
initials: getUserInitials(user.userName),
|
|
212
|
+
color: user.userColor,
|
|
213
|
+
isLocal: false
|
|
214
|
+
};
|
|
215
|
+
if (user.userAvatar) entry.avatarUrl = user.userAvatar;
|
|
216
|
+
return entry;
|
|
217
|
+
});
|
|
218
|
+
return [local, ...remote];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/collab/presence.ts
|
|
222
|
+
var PRESENCE_FIELD = "presence";
|
|
223
|
+
var STALE_PRESENCE_MS = 3e4;
|
|
224
|
+
var PRESENCE_HEARTBEAT_MS = 1e4;
|
|
225
|
+
var BROADCAST_THROTTLE_MS = 50;
|
|
226
|
+
function sanitizeIdentity(raw) {
|
|
227
|
+
return {
|
|
228
|
+
userName: sanitizeUserName(raw.userName),
|
|
229
|
+
userColor: sanitizeColor(raw.userColor, DEFAULT_COLOR),
|
|
230
|
+
userAvatar: sanitizeAvatarUrl(raw.userAvatar),
|
|
231
|
+
role: sanitizeRole(raw.role)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function isPresenceFresh(lastUpdated, now = Date.now(), staleMs = STALE_PRESENCE_MS) {
|
|
235
|
+
const updatedAt = new Date(lastUpdated).getTime();
|
|
236
|
+
return !Number.isNaN(updatedAt) && now - updatedAt <= staleMs;
|
|
237
|
+
}
|
|
238
|
+
function derivePresence(states, localClientId, sanitizePayload, options = {}) {
|
|
239
|
+
const { now = Date.now(), staleMs = STALE_PRESENCE_MS } = options;
|
|
240
|
+
const users = [];
|
|
241
|
+
for (const [clientId, state] of states) {
|
|
242
|
+
if (clientId === localClientId) continue;
|
|
243
|
+
const raw = state?.[PRESENCE_FIELD];
|
|
244
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
245
|
+
const record = raw;
|
|
246
|
+
const payload = sanitizePayload(record);
|
|
247
|
+
if (!payload) continue;
|
|
248
|
+
const lastUpdated = typeof record.lastUpdated === "string" ? record.lastUpdated : "";
|
|
249
|
+
if (!isPresenceFresh(lastUpdated, now, staleMs)) continue;
|
|
250
|
+
users.push({ ...sanitizeIdentity(record), clientId, lastUpdated, ...payload });
|
|
251
|
+
}
|
|
252
|
+
return users;
|
|
253
|
+
}
|
|
254
|
+
function sanitizeCanvasPayload(raw, canvasWidth, canvasHeight) {
|
|
255
|
+
return {
|
|
256
|
+
activeSlideIndex: sanitizeIndex(raw.activeSlideIndex),
|
|
257
|
+
cursorX: clampCoordinate(raw.cursorX, 0, canvasWidth),
|
|
258
|
+
cursorY: clampCoordinate(raw.cursorY, 0, canvasHeight),
|
|
259
|
+
selectedElementId: typeof raw.selectedElementId === "string" ? raw.selectedElementId.slice(0, 128) : void 0
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function deriveCanvasPresence(states, localClientId, canvasWidth, canvasHeight, options = {}) {
|
|
263
|
+
return derivePresence(
|
|
264
|
+
states,
|
|
265
|
+
localClientId,
|
|
266
|
+
(raw) => sanitizeCanvasPayload(raw, canvasWidth, canvasHeight),
|
|
267
|
+
options
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
function presenceToCursors(presence, activeSlideIndex) {
|
|
271
|
+
const cursors = [];
|
|
272
|
+
for (const user of presence) {
|
|
273
|
+
if (activeSlideIndex !== void 0 && user.activeSlideIndex !== activeSlideIndex) continue;
|
|
274
|
+
const cursor = {
|
|
275
|
+
clientId: user.clientId,
|
|
276
|
+
userName: user.userName,
|
|
277
|
+
color: user.userColor,
|
|
278
|
+
x: user.cursorX,
|
|
279
|
+
y: user.cursorY
|
|
280
|
+
};
|
|
281
|
+
if (user.selectedElementId) cursor.selectionIds = [user.selectedElementId];
|
|
282
|
+
cursors.push(cursor);
|
|
283
|
+
}
|
|
284
|
+
return cursors;
|
|
285
|
+
}
|
|
286
|
+
function asSelectionIds(value) {
|
|
287
|
+
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/collab/awareness.ts
|
|
291
|
+
function createPresencePublisher(awareness, identity, initial, options = {}) {
|
|
292
|
+
const throttleMs = options.throttleMs ?? BROADCAST_THROTTLE_MS;
|
|
293
|
+
const clock = options.now ?? Date.now;
|
|
294
|
+
const local = { ...initial };
|
|
295
|
+
let lastBroadcast = 0;
|
|
296
|
+
let pending = null;
|
|
297
|
+
const publish = () => {
|
|
298
|
+
lastBroadcast = clock();
|
|
299
|
+
awareness.setLocalStateField(PRESENCE_FIELD, {
|
|
300
|
+
...identity,
|
|
301
|
+
...local,
|
|
302
|
+
lastUpdated: new Date(clock()).toISOString()
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
const cancel = () => {
|
|
306
|
+
if (pending !== null) clearTimeout(pending);
|
|
307
|
+
pending = null;
|
|
308
|
+
};
|
|
309
|
+
const update = (patch) => {
|
|
310
|
+
const keys = Object.keys(patch);
|
|
311
|
+
if (!keys.some((key) => patch[key] !== local[key])) return;
|
|
312
|
+
Object.assign(local, patch);
|
|
313
|
+
const elapsed = clock() - lastBroadcast;
|
|
314
|
+
if (elapsed >= throttleMs) {
|
|
315
|
+
cancel();
|
|
316
|
+
publish();
|
|
317
|
+
} else if (pending === null) {
|
|
318
|
+
pending = setTimeout(() => {
|
|
319
|
+
pending = null;
|
|
320
|
+
publish();
|
|
321
|
+
}, throttleMs - elapsed);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
publish();
|
|
325
|
+
lastBroadcast = 0;
|
|
326
|
+
return {
|
|
327
|
+
update,
|
|
328
|
+
flush: () => {
|
|
329
|
+
cancel();
|
|
330
|
+
publish();
|
|
331
|
+
},
|
|
332
|
+
dispose: cancel
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function borrowAwareness(host) {
|
|
336
|
+
let disposed = false;
|
|
337
|
+
let ownsPresence = false;
|
|
338
|
+
let hadPresence = false;
|
|
339
|
+
let previousPresence;
|
|
340
|
+
let lastPresence;
|
|
341
|
+
const awareness = {
|
|
342
|
+
clientID: host.clientID,
|
|
343
|
+
getStates: () => host.getStates(),
|
|
344
|
+
on: (event, callback) => host.on(event, callback),
|
|
345
|
+
off: (event, callback) => host.off(event, callback),
|
|
346
|
+
setLocalStateField: (field, value) => {
|
|
347
|
+
if (disposed) return;
|
|
348
|
+
const state = host.getLocalState();
|
|
349
|
+
if (state === null) return;
|
|
350
|
+
if (field === PRESENCE_FIELD) {
|
|
351
|
+
if (!ownsPresence || state[PRESENCE_FIELD] !== lastPresence) {
|
|
352
|
+
hadPresence = Object.hasOwn(state, PRESENCE_FIELD);
|
|
353
|
+
previousPresence = state[PRESENCE_FIELD];
|
|
354
|
+
}
|
|
355
|
+
lastPresence = value;
|
|
356
|
+
ownsPresence = true;
|
|
357
|
+
}
|
|
358
|
+
host.setLocalStateField(field, value);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
return {
|
|
362
|
+
awareness,
|
|
363
|
+
dispose: () => {
|
|
364
|
+
if (disposed) return;
|
|
365
|
+
disposed = true;
|
|
366
|
+
const current = host.getLocalState();
|
|
367
|
+
if (!ownsPresence || current === null || current[PRESENCE_FIELD] !== lastPresence) return;
|
|
368
|
+
const restored = { ...current };
|
|
369
|
+
if (hadPresence) restored[PRESENCE_FIELD] = previousPresence;
|
|
370
|
+
else delete restored[PRESENCE_FIELD];
|
|
371
|
+
host.setLocalState(restored);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function clearLocalAwareness(awareness) {
|
|
376
|
+
awareness?.setLocalState?.(null);
|
|
377
|
+
}
|
|
378
|
+
function removeAwarenessStatesLocally(awareness, clients) {
|
|
379
|
+
const states = awareness?.states;
|
|
380
|
+
if (!awareness || !states) return [];
|
|
381
|
+
const removed = clients.filter((clientId) => states.delete(clientId));
|
|
382
|
+
if (removed.length > 0) {
|
|
383
|
+
const change = { added: [], updated: [], removed };
|
|
384
|
+
awareness.emit?.("change", [change, "peer-departed"]);
|
|
385
|
+
awareness.emit?.("update", [change, "peer-departed"]);
|
|
386
|
+
}
|
|
387
|
+
return removed;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/collab/policy.ts
|
|
391
|
+
var INITIAL_SYNC_GRACE_MS = 3e3;
|
|
392
|
+
function createSyncGate(onOpen, graceMs = INITIAL_SYNC_GRACE_MS) {
|
|
393
|
+
let opened = false;
|
|
394
|
+
let timer = null;
|
|
395
|
+
const clear = () => {
|
|
396
|
+
if (timer !== null) clearTimeout(timer);
|
|
397
|
+
timer = null;
|
|
398
|
+
};
|
|
399
|
+
const open = () => {
|
|
400
|
+
clear();
|
|
401
|
+
if (opened) return;
|
|
402
|
+
opened = true;
|
|
403
|
+
onOpen();
|
|
404
|
+
};
|
|
405
|
+
return {
|
|
406
|
+
isOpen: () => opened,
|
|
407
|
+
arm: () => {
|
|
408
|
+
clear();
|
|
409
|
+
if (!opened) timer = setTimeout(open, graceMs);
|
|
410
|
+
},
|
|
411
|
+
open,
|
|
412
|
+
reset: () => {
|
|
413
|
+
clear();
|
|
414
|
+
opened = false;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function shouldRoomReplaceLoad(origin, roomIsNonEmpty) {
|
|
419
|
+
return (origin ?? "user") === "bootstrap" && roomIsNonEmpty;
|
|
420
|
+
}
|
|
421
|
+
function shouldAutoFollowBroadcaster(input) {
|
|
422
|
+
return input.localRole === "viewer" && input.broadcasterRole === "owner";
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/collab/binding.ts
|
|
426
|
+
var LOCAL_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:collab:local");
|
|
427
|
+
function bindDocument(session, adapter, options) {
|
|
428
|
+
let disposed = false;
|
|
429
|
+
const adoptRoom = () => options.onRemoteModel(adapter.read(session.doc));
|
|
430
|
+
const stopObserving = adapter.observe(session.doc, (origin) => {
|
|
431
|
+
if (disposed || origin === LOCAL_ORIGIN) return;
|
|
432
|
+
adoptRoom();
|
|
433
|
+
});
|
|
434
|
+
const settle = () => {
|
|
435
|
+
if (disposed) return;
|
|
436
|
+
if (adapter.isEmpty(session.doc)) {
|
|
437
|
+
if (session.canWrite()) adapter.write(session.doc, options.getLocalModel(), LOCAL_ORIGIN);
|
|
438
|
+
} else adoptRoom();
|
|
439
|
+
};
|
|
440
|
+
const stopReady = session.on("ready", settle);
|
|
441
|
+
if (session.canWrite()) settle();
|
|
442
|
+
return {
|
|
443
|
+
push: (model) => {
|
|
444
|
+
if (disposed || !session.canWrite()) return false;
|
|
445
|
+
adapter.write(session.doc, model, LOCAL_ORIGIN);
|
|
446
|
+
return true;
|
|
447
|
+
},
|
|
448
|
+
handleLoad: (origin, model) => {
|
|
449
|
+
if (disposed) return false;
|
|
450
|
+
if (shouldRoomReplaceLoad(origin, !adapter.isEmpty(session.doc))) {
|
|
451
|
+
adoptRoom();
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
if (session.canWrite()) adapter.write(session.doc, model, LOCAL_ORIGIN);
|
|
455
|
+
return false;
|
|
456
|
+
},
|
|
457
|
+
dispose: () => {
|
|
458
|
+
disposed = true;
|
|
459
|
+
stopObserving();
|
|
460
|
+
stopReady();
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
var MAX_UPDATE_BYTES = 32 * 1024 * 1024;
|
|
465
|
+
function encodeSnapshot(doc) {
|
|
466
|
+
return Y.encodeStateAsUpdate(doc);
|
|
467
|
+
}
|
|
468
|
+
function encodeDiff(doc, peerStateVector) {
|
|
469
|
+
return Y.encodeStateAsUpdate(doc, peerStateVector);
|
|
470
|
+
}
|
|
471
|
+
function encodeStateVector2(doc) {
|
|
472
|
+
return Y.encodeStateVector(doc);
|
|
473
|
+
}
|
|
474
|
+
function validateUpdate(update, maxBytes = MAX_UPDATE_BYTES) {
|
|
475
|
+
if (!(update instanceof Uint8Array)) return { ok: false, reason: "update must be a Uint8Array" };
|
|
476
|
+
if (update.byteLength === 0) return { ok: false, reason: "update is empty" };
|
|
477
|
+
if (update.byteLength > maxBytes)
|
|
478
|
+
return { ok: false, reason: `update exceeds the ${maxBytes} byte limit` };
|
|
479
|
+
try {
|
|
480
|
+
Y.decodeUpdate(update);
|
|
481
|
+
return { ok: true };
|
|
482
|
+
} catch (cause) {
|
|
483
|
+
return {
|
|
484
|
+
ok: false,
|
|
485
|
+
reason: `malformed update: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function applyUpdateSafe(doc, update, origin, options = {}) {
|
|
490
|
+
const checked = options.validate === false ? update instanceof Uint8Array && update.byteLength <= (options.maxBytes ?? MAX_UPDATE_BYTES) ? { ok: true } : { ok: false, reason: "invalid or oversized update" } : validateUpdate(update, options.maxBytes);
|
|
491
|
+
if (!checked.ok) return checked;
|
|
492
|
+
try {
|
|
493
|
+
Y.applyUpdate(doc, update, origin);
|
|
494
|
+
return { ok: true };
|
|
495
|
+
} catch (cause) {
|
|
496
|
+
return {
|
|
497
|
+
ok: false,
|
|
498
|
+
reason: `could not apply update: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function restoreSnapshot(snapshot, options = {}) {
|
|
503
|
+
const doc = new Y.Doc();
|
|
504
|
+
const result = applyUpdateSafe(doc, snapshot, "snapshot", options);
|
|
505
|
+
if (!result.ok) {
|
|
506
|
+
doc.destroy();
|
|
507
|
+
throw new Error(result.reason);
|
|
508
|
+
}
|
|
509
|
+
return doc;
|
|
510
|
+
}
|
|
511
|
+
function mergeUpdates2(updates) {
|
|
512
|
+
return Y.mergeUpdates([...updates]);
|
|
513
|
+
}
|
|
514
|
+
var CHUNK = 32768;
|
|
515
|
+
function toBase64(bytes) {
|
|
516
|
+
let binary = "";
|
|
517
|
+
for (let i = 0; i < bytes.length; i += CHUNK)
|
|
518
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
519
|
+
return btoa(binary);
|
|
520
|
+
}
|
|
521
|
+
function fromBase64(text) {
|
|
522
|
+
try {
|
|
523
|
+
const binary = atob(text);
|
|
524
|
+
const bytes = new Uint8Array(binary.length);
|
|
525
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
526
|
+
return bytes;
|
|
527
|
+
} catch {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// src/collab/emitter.ts
|
|
533
|
+
var Emitter = class {
|
|
534
|
+
listeners = /* @__PURE__ */ new Map();
|
|
535
|
+
on(event, listener) {
|
|
536
|
+
let set = this.listeners.get(event);
|
|
537
|
+
if (!set) this.listeners.set(event, set = /* @__PURE__ */ new Set());
|
|
538
|
+
set.add(listener);
|
|
539
|
+
return () => this.off(event, listener);
|
|
540
|
+
}
|
|
541
|
+
off(event, listener) {
|
|
542
|
+
this.listeners.get(event)?.delete(listener);
|
|
543
|
+
}
|
|
544
|
+
emit(event, payload) {
|
|
545
|
+
for (const listener of [...this.listeners.get(event) ?? []]) {
|
|
546
|
+
try {
|
|
547
|
+
listener(payload);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
queueMicrotask(() => {
|
|
550
|
+
throw error;
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
clear() {
|
|
556
|
+
this.listeners.clear();
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// src/collab/external-provider.ts
|
|
561
|
+
function adaptYjsProvider(provider) {
|
|
562
|
+
const events = new Emitter();
|
|
563
|
+
let status = provider.wsconnected || provider.connected ? "connected" : "disconnected";
|
|
564
|
+
let synced = Boolean(provider.synced);
|
|
565
|
+
const subscriptions = [];
|
|
566
|
+
const listen = (name, handler) => {
|
|
567
|
+
const wrapped = handler;
|
|
568
|
+
provider.on(name, wrapped);
|
|
569
|
+
subscriptions.push([name, wrapped]);
|
|
570
|
+
};
|
|
571
|
+
const setStatus = (next) => {
|
|
572
|
+
if (next === status) return;
|
|
573
|
+
status = next;
|
|
574
|
+
events.emit("status", next);
|
|
575
|
+
};
|
|
576
|
+
const setSynced = (next) => {
|
|
577
|
+
if (next === synced) return;
|
|
578
|
+
synced = next;
|
|
579
|
+
events.emit("synced", next);
|
|
580
|
+
};
|
|
581
|
+
listen("status", (payload) => {
|
|
582
|
+
if (typeof payload.connected === "boolean")
|
|
583
|
+
return setStatus(payload.connected ? "connected" : "disconnected");
|
|
584
|
+
if (payload.status === "connected" || payload.status === "connecting")
|
|
585
|
+
setStatus(payload.status);
|
|
586
|
+
else if (payload.status === "disconnected") {
|
|
587
|
+
setSynced(false);
|
|
588
|
+
setStatus("disconnected");
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
listen("sync", (value) => setSynced(Boolean(value)));
|
|
592
|
+
listen("synced", (value) => setSynced(Boolean(value.synced)));
|
|
593
|
+
listen("connection-error", (cause) => {
|
|
594
|
+
setStatus("error");
|
|
595
|
+
events.emit("error", cause instanceof Error ? cause : new Error("Provider connection error"));
|
|
596
|
+
});
|
|
597
|
+
return {
|
|
598
|
+
get status() {
|
|
599
|
+
return status;
|
|
600
|
+
},
|
|
601
|
+
get synced() {
|
|
602
|
+
return synced;
|
|
603
|
+
},
|
|
604
|
+
connect: () => {
|
|
605
|
+
setStatus("connecting");
|
|
606
|
+
provider.connect?.();
|
|
607
|
+
},
|
|
608
|
+
disconnect: () => provider.disconnect?.(),
|
|
609
|
+
destroy: () => {
|
|
610
|
+
for (const [name, handler] of subscriptions) provider.off?.(name, handler);
|
|
611
|
+
subscriptions.length = 0;
|
|
612
|
+
events.clear();
|
|
613
|
+
provider.destroy?.();
|
|
614
|
+
},
|
|
615
|
+
on: (event, listener) => events.on(event, listener)
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function observeExternalSession(session, onSnapshot) {
|
|
619
|
+
let active = true;
|
|
620
|
+
let subscribing = true;
|
|
621
|
+
let previous;
|
|
622
|
+
let unsubscribe;
|
|
623
|
+
const notify = () => {
|
|
624
|
+
if (!active || subscribing) return;
|
|
625
|
+
const snapshot = session.getSnapshot();
|
|
626
|
+
if (previous?.status === snapshot.status && previous.synced === snapshot.synced) return;
|
|
627
|
+
previous = { status: snapshot.status, synced: snapshot.synced };
|
|
628
|
+
onSnapshot(previous);
|
|
629
|
+
};
|
|
630
|
+
const dispose = () => {
|
|
631
|
+
if (!active) return;
|
|
632
|
+
active = false;
|
|
633
|
+
unsubscribe?.();
|
|
634
|
+
};
|
|
635
|
+
try {
|
|
636
|
+
unsubscribe = session.subscribe(notify);
|
|
637
|
+
subscribing = false;
|
|
638
|
+
notify();
|
|
639
|
+
} catch (error) {
|
|
640
|
+
dispose();
|
|
641
|
+
throw error;
|
|
642
|
+
}
|
|
643
|
+
return dispose;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/collab/lifecycle.ts
|
|
647
|
+
var COLLAB_LEAVE_MESSAGE = "ooxml-core:collab-leave";
|
|
648
|
+
var DEPARTURE_CHANNEL = "ooxml-core:collab-departures";
|
|
649
|
+
var LEGACY_PPTX_LEAVE_MESSAGE = "pptx-viewer:collab-leave";
|
|
650
|
+
var LEGACY_PPTX_DEPARTURE_CHANNEL = "pptx-viewer:collab-departures";
|
|
651
|
+
function isLeaveMessage(data, expected) {
|
|
652
|
+
if (typeof data === "string") return data === expected;
|
|
653
|
+
return typeof data === "object" && data !== null && data.type === expected;
|
|
654
|
+
}
|
|
655
|
+
function registerTeardown(options) {
|
|
656
|
+
const target = options.target ?? globalThis.window;
|
|
657
|
+
if (!target) return () => {
|
|
658
|
+
};
|
|
659
|
+
const { leave, rejoin } = options;
|
|
660
|
+
const leaveMessage = options.leaveMessage ?? COLLAB_LEAVE_MESSAGE;
|
|
661
|
+
let left = false;
|
|
662
|
+
const doLeave = () => {
|
|
663
|
+
if (left) return;
|
|
664
|
+
left = true;
|
|
665
|
+
leave();
|
|
666
|
+
};
|
|
667
|
+
const onPageHide = (event) => {
|
|
668
|
+
if (event.persisted === true && !rejoin) return;
|
|
669
|
+
doLeave();
|
|
670
|
+
};
|
|
671
|
+
const onBeforeUnload = () => {
|
|
672
|
+
const allowed = typeof options.leaveOnBeforeUnload === "function" ? options.leaveOnBeforeUnload() : options.leaveOnBeforeUnload !== false;
|
|
673
|
+
if (allowed) doLeave();
|
|
674
|
+
};
|
|
675
|
+
const onPageShow = (event) => {
|
|
676
|
+
if (event.persisted !== true || !left || !rejoin) return;
|
|
677
|
+
left = false;
|
|
678
|
+
rejoin();
|
|
679
|
+
};
|
|
680
|
+
const onMessage = (event) => {
|
|
681
|
+
if (isLeaveMessage(event.data, leaveMessage)) doLeave();
|
|
682
|
+
};
|
|
683
|
+
const listeners = {
|
|
684
|
+
pagehide: onPageHide,
|
|
685
|
+
beforeunload: onBeforeUnload,
|
|
686
|
+
pageshow: onPageShow,
|
|
687
|
+
message: onMessage
|
|
688
|
+
};
|
|
689
|
+
for (const [type, listener] of Object.entries(listeners)) target.addEventListener(type, listener);
|
|
690
|
+
return () => {
|
|
691
|
+
for (const [type, listener] of Object.entries(listeners))
|
|
692
|
+
target.removeEventListener(type, listener);
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function defaultFactory(name) {
|
|
696
|
+
const scope = globalThis;
|
|
697
|
+
return scope.BroadcastChannel ? new scope.BroadcastChannel(name) : null;
|
|
698
|
+
}
|
|
699
|
+
function createDepartureChannel(roomId, awareness, factory, channelName = DEPARTURE_CHANNEL) {
|
|
700
|
+
const channel = factory ? factory(channelName) : defaultFactory(channelName);
|
|
701
|
+
if (!channel) return { announce: () => {
|
|
702
|
+
}, dispose: () => {
|
|
703
|
+
} };
|
|
704
|
+
const selfId = awareness.clientID;
|
|
705
|
+
channel.onmessage = (event) => {
|
|
706
|
+
const data = event.data;
|
|
707
|
+
if (typeof data !== "object" || data === null) return;
|
|
708
|
+
const notice = data;
|
|
709
|
+
if (notice.channel !== channelName || notice.roomId !== roomId) return;
|
|
710
|
+
if (typeof notice.clientId !== "number" || notice.clientId === selfId) return;
|
|
711
|
+
removeAwarenessStatesLocally(awareness, [notice.clientId]);
|
|
712
|
+
};
|
|
713
|
+
let closed = false;
|
|
714
|
+
return {
|
|
715
|
+
announce: () => {
|
|
716
|
+
if (closed || typeof selfId !== "number") return;
|
|
717
|
+
channel.postMessage({ channel: channelName, roomId, clientId: selfId });
|
|
718
|
+
},
|
|
719
|
+
dispose: () => {
|
|
720
|
+
if (closed) return;
|
|
721
|
+
closed = true;
|
|
722
|
+
channel.onmessage = null;
|
|
723
|
+
channel.close();
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// src/collab/memory-transport.ts
|
|
729
|
+
function createMemoryHub(options = {}) {
|
|
730
|
+
const rooms = /* @__PURE__ */ new Map();
|
|
731
|
+
let nextId = 0;
|
|
732
|
+
const deliver = (task) => {
|
|
733
|
+
if (options.async) queueMicrotask(task);
|
|
734
|
+
else task();
|
|
735
|
+
};
|
|
736
|
+
return {
|
|
737
|
+
size: (roomId) => rooms.get(roomId)?.size ?? 0,
|
|
738
|
+
createTransport(roomId) {
|
|
739
|
+
const id = nextId++;
|
|
740
|
+
let endpoint = null;
|
|
741
|
+
const peers = () => {
|
|
742
|
+
let room = rooms.get(roomId);
|
|
743
|
+
if (!room) rooms.set(roomId, room = /* @__PURE__ */ new Set());
|
|
744
|
+
return room;
|
|
745
|
+
};
|
|
746
|
+
return {
|
|
747
|
+
get connected() {
|
|
748
|
+
return endpoint !== null;
|
|
749
|
+
},
|
|
750
|
+
connect(handlers) {
|
|
751
|
+
if (endpoint) peers().delete(endpoint);
|
|
752
|
+
const self = { id, handlers };
|
|
753
|
+
const others = [...peers()];
|
|
754
|
+
peers().add(self);
|
|
755
|
+
endpoint = self;
|
|
756
|
+
deliver(() => {
|
|
757
|
+
if (endpoint !== self) return;
|
|
758
|
+
handlers.open();
|
|
759
|
+
for (const other of others) other.handlers.peer?.();
|
|
760
|
+
});
|
|
761
|
+
},
|
|
762
|
+
send(data) {
|
|
763
|
+
const self = endpoint;
|
|
764
|
+
if (!self || options.filter && !options.filter(data, id)) return;
|
|
765
|
+
for (const other of [...peers()])
|
|
766
|
+
if (other !== self) deliver(() => other.handlers.message(data.slice()));
|
|
767
|
+
},
|
|
768
|
+
disconnect() {
|
|
769
|
+
const self = endpoint;
|
|
770
|
+
if (!self) return;
|
|
771
|
+
endpoint = null;
|
|
772
|
+
peers().delete(self);
|
|
773
|
+
self.handlers.close("disconnected");
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// src/collab/ordering.ts
|
|
781
|
+
function classifyVersion(messageVersion, currentVersion) {
|
|
782
|
+
if (!isNonNegativeSafeInteger(messageVersion) || !isNonNegativeSafeInteger(currentVersion))
|
|
783
|
+
return "invalid";
|
|
784
|
+
if (messageVersion < currentVersion) return "stale";
|
|
785
|
+
return messageVersion > currentVersion ? "out-of-order" : "apply";
|
|
786
|
+
}
|
|
787
|
+
var BoundedMap = class {
|
|
788
|
+
constructor(limit) {
|
|
789
|
+
this.limit = limit;
|
|
790
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new Error("limit must be positive");
|
|
791
|
+
}
|
|
792
|
+
limit;
|
|
793
|
+
entries = /* @__PURE__ */ new Map();
|
|
794
|
+
get size() {
|
|
795
|
+
return this.entries.size;
|
|
796
|
+
}
|
|
797
|
+
get(key) {
|
|
798
|
+
return this.entries.get(key);
|
|
799
|
+
}
|
|
800
|
+
has(key) {
|
|
801
|
+
return this.entries.has(key);
|
|
802
|
+
}
|
|
803
|
+
set(key, value) {
|
|
804
|
+
this.entries.delete(key);
|
|
805
|
+
this.entries.set(key, value);
|
|
806
|
+
if (this.entries.size > this.limit) {
|
|
807
|
+
const oldest = this.entries.keys().next();
|
|
808
|
+
if (!oldest.done) this.entries.delete(oldest.value);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
delete(key) {
|
|
812
|
+
return this.entries.delete(key);
|
|
813
|
+
}
|
|
814
|
+
clear() {
|
|
815
|
+
this.entries.clear();
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
var IdempotencyCache = class {
|
|
819
|
+
seen;
|
|
820
|
+
constructor(limit = 5e3) {
|
|
821
|
+
this.seen = new BoundedMap(limit);
|
|
822
|
+
}
|
|
823
|
+
check(clientId, messageId, fingerprint) {
|
|
824
|
+
const prior = this.seen.get(`${clientId}\0${messageId}`);
|
|
825
|
+
if (!prior) return { status: "fresh" };
|
|
826
|
+
return prior.fingerprint === fingerprint ? { status: "duplicate", value: prior.value } : { status: "reused" };
|
|
827
|
+
}
|
|
828
|
+
remember(clientId, messageId, fingerprint, value) {
|
|
829
|
+
this.seen.set(`${clientId}\0${messageId}`, { fingerprint, value });
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
var SequenceTracker = class {
|
|
833
|
+
last;
|
|
834
|
+
constructor(limit = 200) {
|
|
835
|
+
this.last = new BoundedMap(limit);
|
|
836
|
+
}
|
|
837
|
+
/** Classify without recording; call {@link commit} once the message was actually applied. */
|
|
838
|
+
classify(peerId, sequence, fingerprint) {
|
|
839
|
+
if (!isNonNegativeSafeInteger(sequence) || sequence < 1) return "invalid";
|
|
840
|
+
const previous = this.last.get(peerId);
|
|
841
|
+
if (!previous || sequence > previous.sequence) return "apply";
|
|
842
|
+
if (sequence < previous.sequence) return "stale";
|
|
843
|
+
return previous.fingerprint === fingerprint ? "duplicate" : "invalid";
|
|
844
|
+
}
|
|
845
|
+
commit(peerId, sequence, fingerprint) {
|
|
846
|
+
this.last.set(peerId, { sequence, fingerprint });
|
|
847
|
+
}
|
|
848
|
+
forget(peerId) {
|
|
849
|
+
this.last.delete(peerId);
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
function freezeDeep(value) {
|
|
853
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
854
|
+
for (const child of Object.values(value)) freezeDeep(child);
|
|
855
|
+
Object.freeze(value);
|
|
856
|
+
}
|
|
857
|
+
return value;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// src/collab/provider.ts
|
|
861
|
+
var CONNECTION_TIMEOUT_MS = 3e4;
|
|
862
|
+
function createCollabSession(options) {
|
|
863
|
+
const roomId = validateRoomId(options.roomId);
|
|
864
|
+
const ownsDoc = !options.doc;
|
|
865
|
+
const doc = options.doc ?? new Y.Doc();
|
|
866
|
+
const awareness = new Awareness(doc);
|
|
867
|
+
const events = new Emitter();
|
|
868
|
+
const role = options.user.role;
|
|
869
|
+
const identity = {
|
|
870
|
+
userName: sanitizeUserName(options.user.name),
|
|
871
|
+
userColor: sanitizeColor(options.user.color, assignUserColor(doc.clientID)),
|
|
872
|
+
userAvatar: options.user.avatar,
|
|
873
|
+
role
|
|
874
|
+
};
|
|
875
|
+
const sanitizePayload = options.sanitizePayload ?? (() => ({}));
|
|
876
|
+
const publisher = createPresencePublisher(
|
|
877
|
+
awareness,
|
|
878
|
+
identity,
|
|
879
|
+
options.initialPresence ?? {}
|
|
880
|
+
);
|
|
881
|
+
let destroyed = false;
|
|
882
|
+
let timeout = null;
|
|
883
|
+
const gate = createSyncGate(() => {
|
|
884
|
+
if (destroyed) return;
|
|
885
|
+
options.onReady?.({ synced: provider.synced });
|
|
886
|
+
events.emit("ready", void 0);
|
|
887
|
+
}, options.syncGraceMs ?? INITIAL_SYNC_GRACE_MS);
|
|
888
|
+
const peers = () => derivePresence(awareness.getStates(), doc.clientID, sanitizePayload);
|
|
889
|
+
const emitPeers = () => events.emit("peers", peers());
|
|
890
|
+
awareness.on("change", emitPeers);
|
|
891
|
+
const provider = options.provider({ doc, awareness, roomId });
|
|
892
|
+
const clearTimeoutTimer = () => {
|
|
893
|
+
if (timeout !== null) clearTimeout(timeout);
|
|
894
|
+
timeout = null;
|
|
895
|
+
};
|
|
896
|
+
provider.on("status", (status) => {
|
|
897
|
+
clearTimeoutTimer();
|
|
898
|
+
events.emit("status", status);
|
|
899
|
+
if (status === "connecting")
|
|
900
|
+
timeout = setTimeout(() => {
|
|
901
|
+
events.emit("error", new Error("Collaboration connection timed out"));
|
|
902
|
+
events.emit("status", "error");
|
|
903
|
+
}, options.connectionTimeoutMs ?? CONNECTION_TIMEOUT_MS);
|
|
904
|
+
if (status === "connected") gate.arm();
|
|
905
|
+
});
|
|
906
|
+
provider.on("synced", (synced) => {
|
|
907
|
+
events.emit("synced", synced);
|
|
908
|
+
if (synced) gate.open();
|
|
909
|
+
});
|
|
910
|
+
provider.on("error", (error) => events.emit("error", error));
|
|
911
|
+
const heartbeatMs = options.heartbeatMs ?? PRESENCE_HEARTBEAT_MS;
|
|
912
|
+
const heartbeat = heartbeatMs > 0 ? setInterval(() => {
|
|
913
|
+
publisher.flush();
|
|
914
|
+
emitPeers();
|
|
915
|
+
}, heartbeatMs) : null;
|
|
916
|
+
heartbeat?.unref?.();
|
|
917
|
+
const departure = createDepartureChannel(roomId, awareness);
|
|
918
|
+
const leave = () => {
|
|
919
|
+
departure.announce();
|
|
920
|
+
publisher.dispose();
|
|
921
|
+
awareness.setLocalState(null);
|
|
922
|
+
provider.disconnect();
|
|
923
|
+
};
|
|
924
|
+
const unregisterTeardown = options.teardown ? registerTeardown({
|
|
925
|
+
leave,
|
|
926
|
+
rejoin: () => {
|
|
927
|
+
publisher.flush();
|
|
928
|
+
provider.connect();
|
|
929
|
+
},
|
|
930
|
+
...typeof options.teardown === "object" ? options.teardown : {}
|
|
931
|
+
}) : () => {
|
|
932
|
+
};
|
|
933
|
+
const session = {
|
|
934
|
+
roomId,
|
|
935
|
+
doc,
|
|
936
|
+
awareness,
|
|
937
|
+
clientId: doc.clientID,
|
|
938
|
+
role,
|
|
939
|
+
identity,
|
|
940
|
+
gate,
|
|
941
|
+
provider,
|
|
942
|
+
get status() {
|
|
943
|
+
return provider.status;
|
|
944
|
+
},
|
|
945
|
+
get synced() {
|
|
946
|
+
return provider.synced;
|
|
947
|
+
},
|
|
948
|
+
canWrite: () => !destroyed && gate.isOpen() && canWrite(role),
|
|
949
|
+
peers,
|
|
950
|
+
updatePresence: (patch) => publisher.update(patch),
|
|
951
|
+
on: (event, listener) => events.on(event, listener),
|
|
952
|
+
connect: () => {
|
|
953
|
+
if (!destroyed) provider.connect();
|
|
954
|
+
},
|
|
955
|
+
disconnect: () => {
|
|
956
|
+
clearTimeoutTimer();
|
|
957
|
+
gate.reset();
|
|
958
|
+
provider.disconnect();
|
|
959
|
+
},
|
|
960
|
+
destroy: () => {
|
|
961
|
+
if (destroyed) return;
|
|
962
|
+
departure.announce();
|
|
963
|
+
unregisterTeardown();
|
|
964
|
+
clearTimeoutTimer();
|
|
965
|
+
if (heartbeat !== null) clearInterval(heartbeat);
|
|
966
|
+
publisher.dispose();
|
|
967
|
+
gate.reset();
|
|
968
|
+
awareness.setLocalState(null);
|
|
969
|
+
provider.destroy();
|
|
970
|
+
departure.dispose();
|
|
971
|
+
awareness.off("change", emitPeers);
|
|
972
|
+
awareness.destroy();
|
|
973
|
+
destroyed = true;
|
|
974
|
+
events.clear();
|
|
975
|
+
if (ownsDoc) doc.destroy();
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
if (options.autoConnect !== false) provider.connect();
|
|
979
|
+
return session;
|
|
980
|
+
}
|
|
981
|
+
var MESSAGE_SYNC = 0;
|
|
982
|
+
var MESSAGE_AWARENESS = 1;
|
|
983
|
+
var MESSAGE_QUERY_AWARENESS = 3;
|
|
984
|
+
var SYNC_STEP1 = 0;
|
|
985
|
+
var SYNC_STEP2 = 1;
|
|
986
|
+
var SYNC_UPDATE = 2;
|
|
987
|
+
function transportProvider(options) {
|
|
988
|
+
return (context) => createTransportProvider(context, options);
|
|
989
|
+
}
|
|
990
|
+
function createTransportProvider({ doc, awareness }, { transport, maxMessageBytes = MAX_UPDATE_BYTES }) {
|
|
991
|
+
const events = new Emitter();
|
|
992
|
+
let status = "disconnected";
|
|
993
|
+
let synced = false;
|
|
994
|
+
let open = false;
|
|
995
|
+
let destroyed = false;
|
|
996
|
+
const origin = {};
|
|
997
|
+
const setStatus = (next) => {
|
|
998
|
+
if (status === next) return;
|
|
999
|
+
status = next;
|
|
1000
|
+
events.emit("status", next);
|
|
1001
|
+
};
|
|
1002
|
+
const setSynced = (next) => {
|
|
1003
|
+
if (synced === next) return;
|
|
1004
|
+
synced = next;
|
|
1005
|
+
events.emit("synced", next);
|
|
1006
|
+
};
|
|
1007
|
+
const fail = (reason) => events.emit("error", new Error(reason));
|
|
1008
|
+
const send = (encoder) => {
|
|
1009
|
+
if (open) transport.send(encoding.toUint8Array(encoder));
|
|
1010
|
+
};
|
|
1011
|
+
const sendStep1 = () => {
|
|
1012
|
+
const encoder = encoding.createEncoder();
|
|
1013
|
+
encoding.writeVarUint(encoder, MESSAGE_SYNC);
|
|
1014
|
+
encoding.writeVarUint(encoder, SYNC_STEP1);
|
|
1015
|
+
encoding.writeVarUint8Array(encoder, Y.encodeStateVector(doc));
|
|
1016
|
+
send(encoder);
|
|
1017
|
+
};
|
|
1018
|
+
const sendAwareness = (clients) => {
|
|
1019
|
+
if (clients.length === 0) return;
|
|
1020
|
+
const encoder = encoding.createEncoder();
|
|
1021
|
+
encoding.writeVarUint(encoder, MESSAGE_AWARENESS);
|
|
1022
|
+
encoding.writeVarUint8Array(
|
|
1023
|
+
encoder,
|
|
1024
|
+
awarenessProtocol.encodeAwarenessUpdate(awareness, clients)
|
|
1025
|
+
);
|
|
1026
|
+
send(encoder);
|
|
1027
|
+
};
|
|
1028
|
+
const handshake = () => {
|
|
1029
|
+
sendStep1();
|
|
1030
|
+
const local = awareness.getLocalState();
|
|
1031
|
+
if (local !== null) awareness.setLocalState(local);
|
|
1032
|
+
};
|
|
1033
|
+
const onDocUpdate = (update, updateOrigin) => {
|
|
1034
|
+
if (updateOrigin === origin || !open) return;
|
|
1035
|
+
const encoder = encoding.createEncoder();
|
|
1036
|
+
encoding.writeVarUint(encoder, MESSAGE_SYNC);
|
|
1037
|
+
encoding.writeVarUint(encoder, SYNC_UPDATE);
|
|
1038
|
+
encoding.writeVarUint8Array(encoder, update);
|
|
1039
|
+
send(encoder);
|
|
1040
|
+
};
|
|
1041
|
+
const onAwarenessUpdate = (change, updateOrigin) => {
|
|
1042
|
+
if (updateOrigin === origin) return;
|
|
1043
|
+
sendAwareness([...change.added, ...change.updated, ...change.removed]);
|
|
1044
|
+
};
|
|
1045
|
+
const readSync = (decoder) => {
|
|
1046
|
+
const kind = decoding.readVarUint(decoder);
|
|
1047
|
+
const payload = decoding.readVarUint8Array(decoder);
|
|
1048
|
+
if (kind === SYNC_STEP1) {
|
|
1049
|
+
const encoder = encoding.createEncoder();
|
|
1050
|
+
encoding.writeVarUint(encoder, MESSAGE_SYNC);
|
|
1051
|
+
encoding.writeVarUint(encoder, SYNC_STEP2);
|
|
1052
|
+
let diff;
|
|
1053
|
+
try {
|
|
1054
|
+
diff = Y.encodeStateAsUpdate(doc, payload);
|
|
1055
|
+
} catch {
|
|
1056
|
+
return fail("malformed state vector");
|
|
1057
|
+
}
|
|
1058
|
+
encoding.writeVarUint8Array(encoder, diff);
|
|
1059
|
+
return send(encoder);
|
|
1060
|
+
}
|
|
1061
|
+
if (kind !== SYNC_STEP2 && kind !== SYNC_UPDATE) return fail(`unknown sync message ${kind}`);
|
|
1062
|
+
const result = applyUpdateSafe(doc, payload, origin, { maxBytes: maxMessageBytes });
|
|
1063
|
+
if (!result.ok) return fail(result.reason);
|
|
1064
|
+
if (kind === SYNC_STEP2) setSynced(true);
|
|
1065
|
+
};
|
|
1066
|
+
const onMessage = (data) => {
|
|
1067
|
+
if (destroyed) return;
|
|
1068
|
+
if (!(data instanceof Uint8Array) || data.byteLength === 0 || data.byteLength > maxMessageBytes)
|
|
1069
|
+
return fail("message is empty, not binary, or too large");
|
|
1070
|
+
try {
|
|
1071
|
+
const decoder = decoding.createDecoder(data);
|
|
1072
|
+
const type = decoding.readVarUint(decoder);
|
|
1073
|
+
if (type === MESSAGE_SYNC) readSync(decoder);
|
|
1074
|
+
else if (type === MESSAGE_AWARENESS)
|
|
1075
|
+
awarenessProtocol.applyAwarenessUpdate(
|
|
1076
|
+
awareness,
|
|
1077
|
+
decoding.readVarUint8Array(decoder),
|
|
1078
|
+
origin
|
|
1079
|
+
);
|
|
1080
|
+
else if (type === MESSAGE_QUERY_AWARENESS) sendAwareness([...awareness.getStates().keys()]);
|
|
1081
|
+
} catch (cause) {
|
|
1082
|
+
fail(`malformed message: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
const dropRemotePeers = () => {
|
|
1086
|
+
const remote = [...awareness.getStates().keys()].filter((id) => id !== doc.clientID);
|
|
1087
|
+
if (remote.length > 0) awarenessProtocol.removeAwarenessStates(awareness, remote, origin);
|
|
1088
|
+
};
|
|
1089
|
+
const connect = () => {
|
|
1090
|
+
if (destroyed) return;
|
|
1091
|
+
setStatus("connecting");
|
|
1092
|
+
transport.connect({
|
|
1093
|
+
open: () => {
|
|
1094
|
+
if (destroyed) return;
|
|
1095
|
+
open = true;
|
|
1096
|
+
setStatus("connected");
|
|
1097
|
+
handshake();
|
|
1098
|
+
},
|
|
1099
|
+
close: () => {
|
|
1100
|
+
open = false;
|
|
1101
|
+
setSynced(false);
|
|
1102
|
+
dropRemotePeers();
|
|
1103
|
+
if (!destroyed) setStatus("disconnected");
|
|
1104
|
+
},
|
|
1105
|
+
message: onMessage,
|
|
1106
|
+
error: (error) => {
|
|
1107
|
+
events.emit("error", error);
|
|
1108
|
+
if (!open) setStatus("error");
|
|
1109
|
+
},
|
|
1110
|
+
peer: () => {
|
|
1111
|
+
if (open && !destroyed) handshake();
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
};
|
|
1115
|
+
doc.on("update", onDocUpdate);
|
|
1116
|
+
awareness.on("update", onAwarenessUpdate);
|
|
1117
|
+
return {
|
|
1118
|
+
get status() {
|
|
1119
|
+
return status;
|
|
1120
|
+
},
|
|
1121
|
+
get synced() {
|
|
1122
|
+
return synced;
|
|
1123
|
+
},
|
|
1124
|
+
connect,
|
|
1125
|
+
disconnect: () => {
|
|
1126
|
+
if (destroyed) return;
|
|
1127
|
+
const local = awareness.getLocalState();
|
|
1128
|
+
if (open && local !== null) awareness.setLocalState(null);
|
|
1129
|
+
transport.disconnect();
|
|
1130
|
+
open = false;
|
|
1131
|
+
if (local !== null) awareness.setLocalState(local);
|
|
1132
|
+
setSynced(false);
|
|
1133
|
+
dropRemotePeers();
|
|
1134
|
+
setStatus("disconnected");
|
|
1135
|
+
},
|
|
1136
|
+
destroy: () => {
|
|
1137
|
+
if (destroyed) return;
|
|
1138
|
+
if (open) awareness.setLocalState(null);
|
|
1139
|
+
destroyed = true;
|
|
1140
|
+
open = false;
|
|
1141
|
+
doc.off("update", onDocUpdate);
|
|
1142
|
+
awareness.off("update", onAwarenessUpdate);
|
|
1143
|
+
transport.disconnect();
|
|
1144
|
+
events.clear();
|
|
1145
|
+
},
|
|
1146
|
+
on: (event, listener) => events.on(event, listener)
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// src/collab/websocket-transport.ts
|
|
1151
|
+
var OPEN = 1;
|
|
1152
|
+
function roomUrl(server, roomId) {
|
|
1153
|
+
return `${server.replace(/\/+$/u, "")}/${encodeURIComponent(roomId)}`;
|
|
1154
|
+
}
|
|
1155
|
+
function createWebSocketTransport(options) {
|
|
1156
|
+
const { baseDelayMs = 250, maxDelayMs = 1e4, maxRetries = Infinity } = options;
|
|
1157
|
+
let socket = null;
|
|
1158
|
+
let handlers = null;
|
|
1159
|
+
let timer = null;
|
|
1160
|
+
let failures = 0;
|
|
1161
|
+
let stopped = true;
|
|
1162
|
+
const open = () => {
|
|
1163
|
+
if (stopped || !handlers) return;
|
|
1164
|
+
const active = handlers;
|
|
1165
|
+
const Impl = options.WebSocket ?? globalThis.WebSocket;
|
|
1166
|
+
if (!Impl) return active.error(new Error("No WebSocket implementation available"));
|
|
1167
|
+
if (isMixedContentBlocked(options.url, options.pageProtocol)) {
|
|
1168
|
+
stopped = true;
|
|
1169
|
+
return active.error(new Error("Insecure ws:// connection blocked from an https page"));
|
|
1170
|
+
}
|
|
1171
|
+
const ws = new Impl(options.url);
|
|
1172
|
+
socket = ws;
|
|
1173
|
+
ws.binaryType = "arraybuffer";
|
|
1174
|
+
ws.onopen = () => {
|
|
1175
|
+
failures = 0;
|
|
1176
|
+
active.open();
|
|
1177
|
+
};
|
|
1178
|
+
ws.onmessage = (event) => {
|
|
1179
|
+
const data = event.data;
|
|
1180
|
+
if (data instanceof ArrayBuffer) active.message(new Uint8Array(data));
|
|
1181
|
+
else if (data instanceof Uint8Array) active.message(data);
|
|
1182
|
+
else active.error(new Error("Received a non-binary WebSocket message"));
|
|
1183
|
+
};
|
|
1184
|
+
ws.onerror = () => active.error(new Error("WebSocket error"));
|
|
1185
|
+
ws.onclose = (event) => {
|
|
1186
|
+
if (socket !== ws) return;
|
|
1187
|
+
socket = null;
|
|
1188
|
+
active.close(event.reason);
|
|
1189
|
+
if (stopped) return;
|
|
1190
|
+
if (++failures > maxRetries) {
|
|
1191
|
+
stopped = true;
|
|
1192
|
+
return active.error(new Error("WebSocket reconnect attempts exhausted"));
|
|
1193
|
+
}
|
|
1194
|
+
timer = setTimeout(open, Math.min(maxDelayMs, baseDelayMs * 2 ** (failures - 1)));
|
|
1195
|
+
};
|
|
1196
|
+
};
|
|
1197
|
+
return {
|
|
1198
|
+
connect(next) {
|
|
1199
|
+
handlers = next;
|
|
1200
|
+
stopped = false;
|
|
1201
|
+
failures = 0;
|
|
1202
|
+
if (timer !== null) clearTimeout(timer);
|
|
1203
|
+
timer = null;
|
|
1204
|
+
if (socket) socket.close();
|
|
1205
|
+
open();
|
|
1206
|
+
},
|
|
1207
|
+
send(data) {
|
|
1208
|
+
if (socket && socket.readyState === OPEN) socket.send(data);
|
|
1209
|
+
},
|
|
1210
|
+
disconnect() {
|
|
1211
|
+
stopped = true;
|
|
1212
|
+
if (timer !== null) clearTimeout(timer);
|
|
1213
|
+
timer = null;
|
|
1214
|
+
const ws = socket;
|
|
1215
|
+
socket = null;
|
|
1216
|
+
if (ws) {
|
|
1217
|
+
ws.onclose = null;
|
|
1218
|
+
ws.close();
|
|
1219
|
+
handlers?.close("disconnected");
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
export { BROADCAST_THROTTLE_MS, BoundedMap, COLLABORATION_ROLES, COLLAB_LEAVE_MESSAGE, CONNECTION_TIMEOUT_MS, CURSOR_PALETTE, DEFAULT_COLOR, DEPARTURE_CHANNEL, Emitter, INITIAL_SYNC_GRACE_MS, IdempotencyCache, LEGACY_PPTX_DEPARTURE_CHANNEL, LEGACY_PPTX_LEAVE_MESSAGE, LOCAL_ORIGIN, MAX_LABEL_CHARS, MAX_UPDATE_BYTES, MESSAGE_AWARENESS, MESSAGE_QUERY_AWARENESS, MESSAGE_SYNC, PRESENCE_FIELD, PRESENCE_HEARTBEAT_MS, STALE_PRESENCE_MS, SequenceTracker, adaptYjsProvider, applyUpdateSafe, asSelectionIds, assignUserColor, bindDocument, borrowAwareness, buildRoster, canWrite, clampCoordinate, classifyVersion, clearLocalAwareness, createAssetSync, createClientId, createCollabSession, createDepartureChannel, createIdGenerator, createMemoryHub, createPresencePublisher, createSyncGate, createTransportProvider, createWebSocketTransport, deriveCanvasPresence, derivePresence, encodeDiff, encodeSnapshot, encodeStateVector2 as encodeStateVector, formatCursorLabel, freezeDeep, fromBase64, getUserInitials, isMixedContentBlocked, isNonNegativeSafeInteger, isPresenceFresh, isValidId, isValidRoomId, mergeUpdates2 as mergeUpdates, observeExternalSession, presenceToCursors, registerTeardown, removeAwarenessStatesLocally, restoreSnapshot, roomUrl, sanitizeAvatarUrl, sanitizeCanvasPayload, sanitizeColor, sanitizeIdentity, sanitizeIndex, sanitizeRole, sanitizeUserName, shouldAutoFollowBroadcaster, shouldRoomReplaceLoad, stripHtmlTags, toBase64, transportProvider, validateDisplayName, validateRoomId, validateUpdate };
|