kritzel-stencil 0.0.156 → 0.0.158

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/dist/cjs/app-globals-V2Kpy_OQ.js +8 -0
  2. package/dist/cjs/app-globals-V2Kpy_OQ.js.map +1 -0
  3. package/dist/cjs/default-text-tool.config-BySzvIox.js +31267 -0
  4. package/dist/cjs/default-text-tool.config-BySzvIox.js.map +1 -0
  5. package/dist/cjs/index-Cj__YTlG.js +1650 -0
  6. package/dist/cjs/index-Cj__YTlG.js.map +1 -0
  7. package/dist/cjs/index.cjs.js +1465 -0
  8. package/dist/cjs/index.cjs.js.map +1 -0
  9. package/dist/cjs/kritzel-brush-style.cjs.entry.js +32 -0
  10. package/dist/cjs/kritzel-brush-style.entry.cjs.js.map +1 -0
  11. package/dist/cjs/kritzel-color_22.cjs.entry.js +20974 -0
  12. package/dist/cjs/loader.cjs.js +14 -0
  13. package/dist/cjs/loader.cjs.js.map +1 -0
  14. package/dist/cjs/stencil.cjs.js +26 -0
  15. package/dist/cjs/stencil.cjs.js.map +1 -0
  16. package/dist/collection/classes/core/core.class.js +470 -0
  17. package/dist/collection/classes/core/core.class.js.map +1 -0
  18. package/dist/collection/classes/core/reviver.class.js +71 -0
  19. package/dist/collection/classes/core/reviver.class.js.map +1 -0
  20. package/dist/collection/classes/core/store.class.js +72 -0
  21. package/dist/collection/classes/core/store.class.js.map +1 -0
  22. package/dist/collection/classes/core/viewport.class.js +190 -0
  23. package/dist/collection/classes/core/viewport.class.js.map +1 -0
  24. package/dist/collection/classes/core/workspace.class.js +41 -0
  25. package/dist/collection/classes/core/workspace.class.js.map +1 -0
  26. package/dist/collection/classes/handlers/base.handler.js +8 -0
  27. package/dist/collection/classes/handlers/base.handler.js.map +1 -0
  28. package/dist/collection/classes/handlers/context-menu.handler.js +62 -0
  29. package/dist/collection/classes/handlers/context-menu.handler.js.map +1 -0
  30. package/dist/collection/classes/handlers/hover.handler.js +19 -0
  31. package/dist/collection/classes/handlers/hover.handler.js.map +1 -0
  32. package/dist/collection/classes/handlers/key.handler.js +58 -0
  33. package/dist/collection/classes/handlers/key.handler.js.map +1 -0
  34. package/dist/collection/classes/handlers/move.handler.js +149 -0
  35. package/dist/collection/classes/handlers/move.handler.js.map +1 -0
  36. package/dist/collection/classes/handlers/resize.handler.js +184 -0
  37. package/dist/collection/classes/handlers/resize.handler.js.map +1 -0
  38. package/dist/collection/classes/handlers/rotation.handler.js +116 -0
  39. package/dist/collection/classes/handlers/rotation.handler.js.map +1 -0
  40. package/dist/collection/classes/handlers/selection.handler.js +246 -0
  41. package/dist/collection/classes/handlers/selection.handler.js.map +1 -0
  42. package/dist/collection/classes/objects/base-object.class.js +232 -0
  43. package/dist/collection/classes/objects/base-object.class.js.map +1 -0
  44. package/dist/collection/classes/objects/custom-element.class.js +62 -0
  45. package/dist/collection/classes/objects/custom-element.class.js.map +1 -0
  46. package/dist/collection/classes/objects/image.class.js +56 -0
  47. package/dist/collection/classes/objects/image.class.js.map +1 -0
  48. package/dist/collection/classes/objects/path.class.js +284 -0
  49. package/dist/collection/classes/objects/path.class.js.map +1 -0
  50. package/dist/collection/classes/objects/selection-box.class.js +19 -0
  51. package/dist/collection/classes/objects/selection-box.class.js.map +1 -0
  52. package/dist/collection/classes/objects/selection-group.class.js +226 -0
  53. package/dist/collection/classes/objects/selection-group.class.js.map +1 -0
  54. package/dist/collection/classes/objects/text.class.js +261 -0
  55. package/dist/collection/classes/objects/text.class.js.map +1 -0
  56. package/dist/collection/classes/providers/broadcast-sync-provider.class.js +93 -0
  57. package/dist/collection/classes/providers/broadcast-sync-provider.class.js.map +1 -0
  58. package/dist/collection/classes/providers/hocuspocus-sync-provider.class.js +232 -0
  59. package/dist/collection/classes/providers/hocuspocus-sync-provider.class.js.map +1 -0
  60. package/dist/collection/classes/providers/indexeddb-sync-provider.class.js +35 -0
  61. package/dist/collection/classes/providers/indexeddb-sync-provider.class.js.map +1 -0
  62. package/dist/collection/classes/providers/websocket-sync-provider.class.js +89 -0
  63. package/dist/collection/classes/providers/websocket-sync-provider.class.js.map +1 -0
  64. package/dist/{stencil/icon-registry.class-BtT8riKh.js → collection/classes/registries/icon-registry.class.js} +2 -6
  65. package/dist/collection/classes/registries/icon-registry.class.js.map +1 -0
  66. package/dist/collection/classes/registries/tool.registry.js +18 -0
  67. package/dist/collection/classes/registries/tool.registry.js.map +1 -0
  68. package/dist/collection/classes/structures/app-state-map.structure.js +189 -0
  69. package/dist/collection/classes/structures/app-state-map.structure.js.map +1 -0
  70. package/dist/collection/classes/structures/object-map.structure.js +328 -0
  71. package/dist/collection/classes/structures/object-map.structure.js.map +1 -0
  72. package/dist/collection/classes/structures/quadtree.structure.js +113 -0
  73. package/dist/collection/classes/structures/quadtree.structure.js.map +1 -0
  74. package/dist/collection/classes/tools/base-tool.class.js +38 -0
  75. package/dist/collection/classes/tools/base-tool.class.js.map +1 -0
  76. package/dist/collection/classes/tools/brush-tool.class.js +133 -0
  77. package/dist/collection/classes/tools/brush-tool.class.js.map +1 -0
  78. package/dist/collection/classes/tools/eraser-tool.class.js +85 -0
  79. package/dist/collection/classes/tools/eraser-tool.class.js.map +1 -0
  80. package/dist/collection/classes/tools/image-tool.class.js +83 -0
  81. package/dist/collection/classes/tools/image-tool.class.js.map +1 -0
  82. package/dist/collection/classes/tools/selection-tool.class.js +164 -0
  83. package/dist/collection/classes/tools/selection-tool.class.js.map +1 -0
  84. package/dist/collection/classes/tools/text-tool.class.js +108 -0
  85. package/dist/collection/classes/tools/text-tool.class.js.map +1 -0
  86. package/dist/collection/collection-manifest.json +34 -0
  87. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.css +10 -0
  88. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +153 -0
  89. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js.map +1 -0
  90. package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +34 -0
  91. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +928 -0
  92. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -0
  93. package/dist/collection/components/core/kritzel-engine/kritzel-engine.css +73 -0
  94. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +1630 -0
  95. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js.map +1 -0
  96. package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.css +44 -0
  97. package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.js +98 -0
  98. package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.js.map +1 -0
  99. package/dist/collection/components/shared/kritzel-color/kritzel-color.css +21 -0
  100. package/dist/collection/components/shared/kritzel-color/kritzel-color.js +107 -0
  101. package/dist/collection/components/shared/kritzel-color/kritzel-color.js.map +1 -0
  102. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.css +46 -0
  103. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +145 -0
  104. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js.map +1 -0
  105. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.css +53 -0
  106. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.js +218 -0
  107. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.js.map +1 -0
  108. package/dist/collection/components/shared/kritzel-font/kritzel-font.css +10 -0
  109. package/dist/collection/components/shared/kritzel-font/kritzel-font.js +90 -0
  110. package/dist/collection/components/shared/kritzel-font/kritzel-font.js.map +1 -0
  111. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.css +48 -0
  112. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js +114 -0
  113. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js.map +1 -0
  114. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.css +30 -0
  115. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +110 -0
  116. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js.map +1 -0
  117. package/dist/collection/components/shared/kritzel-icon/kritzel-icon.css +18 -0
  118. package/dist/collection/components/shared/kritzel-icon/kritzel-icon.js +94 -0
  119. package/dist/collection/components/shared/kritzel-icon/kritzel-icon.js.map +1 -0
  120. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.css +27 -0
  121. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +291 -0
  122. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js.map +1 -0
  123. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.css +145 -0
  124. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +280 -0
  125. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js.map +1 -0
  126. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +310 -0
  127. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js.map +1 -0
  128. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.css +78 -0
  129. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +406 -0
  130. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js.map +1 -0
  131. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.css +28 -0
  132. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +89 -0
  133. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js.map +1 -0
  134. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.css +17 -0
  135. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +251 -0
  136. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js.map +1 -0
  137. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.css +55 -0
  138. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +172 -0
  139. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js.map +1 -0
  140. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.css +19 -0
  141. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js +135 -0
  142. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js.map +1 -0
  143. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.css +19 -0
  144. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js +115 -0
  145. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js.map +1 -0
  146. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +127 -0
  147. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +312 -0
  148. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js.map +1 -0
  149. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.css +44 -0
  150. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +111 -0
  151. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js.map +1 -0
  152. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.css +5 -0
  153. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js +255 -0
  154. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js.map +1 -0
  155. package/dist/collection/configs/default-brush-tool.config.js +60 -0
  156. package/dist/collection/configs/default-brush-tool.config.js.map +1 -0
  157. package/dist/collection/configs/default-engine-config.js +53 -0
  158. package/dist/collection/configs/default-engine-config.js.map +1 -0
  159. package/dist/collection/configs/default-sync.config.js +10 -0
  160. package/dist/collection/configs/default-sync.config.js.map +1 -0
  161. package/dist/collection/configs/default-text-tool.config.js +32 -0
  162. package/dist/collection/configs/default-text-tool.config.js.map +1 -0
  163. package/dist/collection/constants/core.constants.js +2 -0
  164. package/dist/collection/constants/core.constants.js.map +1 -0
  165. package/dist/collection/constants/engine.constants.js +3 -0
  166. package/dist/collection/constants/engine.constants.js.map +1 -0
  167. package/dist/collection/enums/event-button.enum.js +7 -0
  168. package/dist/collection/enums/event-button.enum.js.map +1 -0
  169. package/dist/collection/enums/handle-type.enum.js +8 -0
  170. package/dist/collection/enums/handle-type.enum.js.map +1 -0
  171. package/dist/collection/helpers/class.helper.js +6 -0
  172. package/dist/collection/helpers/class.helper.js.map +1 -0
  173. package/dist/collection/helpers/devices.helper.js +26 -0
  174. package/dist/collection/helpers/devices.helper.js.map +1 -0
  175. package/dist/collection/helpers/event.helper.js +51 -0
  176. package/dist/collection/helpers/event.helper.js.map +1 -0
  177. package/dist/collection/helpers/geometry.helper.js +53 -0
  178. package/dist/collection/helpers/geometry.helper.js.map +1 -0
  179. package/dist/collection/helpers/html.helper.js +64 -0
  180. package/dist/{stencil/html.helper-C6qB08BS.js.map → collection/helpers/html.helper.js.map} +1 -1
  181. package/dist/collection/helpers/keyboard.helper.js +49 -0
  182. package/dist/collection/helpers/keyboard.helper.js.map +1 -0
  183. package/dist/collection/helpers/math.helper.js +6 -0
  184. package/dist/collection/helpers/math.helper.js.map +1 -0
  185. package/dist/collection/helpers/object.helper.js +12 -0
  186. package/dist/collection/helpers/object.helper.js.map +1 -0
  187. package/dist/collection/index.js +30 -0
  188. package/dist/collection/index.js.map +1 -0
  189. package/dist/collection/interfaces/bounding-box.interface.js +2 -0
  190. package/dist/collection/interfaces/bounding-box.interface.js.map +1 -0
  191. package/dist/collection/interfaces/clonable.interface.js +2 -0
  192. package/dist/collection/interfaces/clonable.interface.js.map +1 -0
  193. package/dist/collection/interfaces/context-menu-item.interface.js +2 -0
  194. package/dist/collection/interfaces/context-menu-item.interface.js.map +1 -0
  195. package/dist/collection/interfaces/debug-info.interface.js +2 -0
  196. package/dist/collection/interfaces/debug-info.interface.js.map +1 -0
  197. package/dist/collection/interfaces/engine-state.interface.js +2 -0
  198. package/dist/collection/interfaces/engine-state.interface.js.map +1 -0
  199. package/dist/collection/interfaces/menu-item.interface.js +2 -0
  200. package/dist/collection/interfaces/menu-item.interface.js.map +1 -0
  201. package/dist/collection/interfaces/object.interface.js +2 -0
  202. package/dist/collection/interfaces/object.interface.js.map +1 -0
  203. package/dist/collection/interfaces/path-options.interface.js +2 -0
  204. package/dist/collection/interfaces/path-options.interface.js.map +1 -0
  205. package/dist/collection/interfaces/point.interface.js +2 -0
  206. package/dist/collection/interfaces/point.interface.js.map +1 -0
  207. package/dist/collection/interfaces/polygon.interface.js +2 -0
  208. package/dist/collection/interfaces/polygon.interface.js.map +1 -0
  209. package/dist/collection/interfaces/selection-state.interface.js +2 -0
  210. package/dist/collection/interfaces/selection-state.interface.js.map +1 -0
  211. package/dist/collection/interfaces/serializable.interface.js +2 -0
  212. package/dist/collection/interfaces/serializable.interface.js.map +1 -0
  213. package/dist/collection/interfaces/shortcut.interface.js +2 -0
  214. package/dist/collection/interfaces/shortcut.interface.js.map +1 -0
  215. package/dist/collection/interfaces/sync-config.interface.js +2 -0
  216. package/dist/collection/interfaces/sync-config.interface.js.map +1 -0
  217. package/dist/collection/interfaces/sync-provider.interface.js +2 -0
  218. package/dist/collection/interfaces/sync-provider.interface.js.map +1 -0
  219. package/dist/collection/interfaces/tool.interface.js +2 -0
  220. package/dist/collection/interfaces/tool.interface.js.map +1 -0
  221. package/dist/collection/interfaces/toolbar-control.interface.js +2 -0
  222. package/dist/collection/interfaces/toolbar-control.interface.js.map +1 -0
  223. package/dist/collection/interfaces/undo-state.interface.js +2 -0
  224. package/dist/collection/interfaces/undo-state.interface.js.map +1 -0
  225. package/dist/collection/types/deep-readonly.type.js +2 -0
  226. package/dist/collection/types/deep-readonly.type.js.map +1 -0
  227. package/dist/collection/types/state.types.js +2 -0
  228. package/dist/collection/types/state.types.js.map +1 -0
  229. package/dist/components/index.js +1477 -0
  230. package/dist/components/index.js.map +1 -0
  231. package/dist/components/kritzel-brush-style.js +67 -0
  232. package/dist/components/kritzel-brush-style.js.map +1 -0
  233. package/dist/components/kritzel-color-palette.js +9 -0
  234. package/dist/components/kritzel-color-palette.js.map +1 -0
  235. package/dist/components/kritzel-color.js +9 -0
  236. package/dist/components/kritzel-color.js.map +1 -0
  237. package/dist/components/kritzel-context-menu.js +9 -0
  238. package/dist/components/kritzel-context-menu.js.map +1 -0
  239. package/dist/components/kritzel-control-brush-config.js +9 -0
  240. package/dist/components/kritzel-control-brush-config.js.map +1 -0
  241. package/dist/components/kritzel-control-text-config.js +9 -0
  242. package/dist/components/kritzel-control-text-config.js.map +1 -0
  243. package/dist/components/kritzel-controls.js +9 -0
  244. package/dist/components/kritzel-controls.js.map +1 -0
  245. package/dist/components/kritzel-cursor-trail.js +9 -0
  246. package/dist/components/kritzel-cursor-trail.js.map +1 -0
  247. package/dist/components/kritzel-dropdown.js +9 -0
  248. package/dist/components/kritzel-dropdown.js.map +1 -0
  249. package/dist/components/kritzel-editor.js +516 -0
  250. package/dist/components/kritzel-editor.js.map +1 -0
  251. package/dist/components/kritzel-engine.js +9 -0
  252. package/dist/components/kritzel-engine.js.map +1 -0
  253. package/dist/components/kritzel-font-family.js +9 -0
  254. package/dist/components/kritzel-font-family.js.map +1 -0
  255. package/dist/components/kritzel-font-size.js +9 -0
  256. package/dist/components/kritzel-font-size.js.map +1 -0
  257. package/dist/components/kritzel-font.js +9 -0
  258. package/dist/components/kritzel-font.js.map +1 -0
  259. package/dist/components/kritzel-icon.js +9 -0
  260. package/dist/components/kritzel-icon.js.map +1 -0
  261. package/dist/components/kritzel-menu-item.js +9 -0
  262. package/dist/components/kritzel-menu-item.js.map +1 -0
  263. package/dist/components/kritzel-menu.js +9 -0
  264. package/dist/components/kritzel-menu.js.map +1 -0
  265. package/dist/components/kritzel-portal.js +9 -0
  266. package/dist/components/kritzel-portal.js.map +1 -0
  267. package/dist/components/kritzel-split-button.js +9 -0
  268. package/dist/components/kritzel-split-button.js.map +1 -0
  269. package/dist/components/kritzel-stroke-size.js +9 -0
  270. package/dist/components/kritzel-stroke-size.js.map +1 -0
  271. package/dist/components/kritzel-tooltip.js +9 -0
  272. package/dist/components/kritzel-tooltip.js.map +1 -0
  273. package/dist/components/kritzel-utility-panel.js +9 -0
  274. package/dist/components/kritzel-utility-panel.js.map +1 -0
  275. package/dist/components/kritzel-workspace-manager.js +9 -0
  276. package/dist/components/kritzel-workspace-manager.js.map +1 -0
  277. package/dist/{stencil/kritzel-controls.entry.js → components/p-1lIHoOlH.js} +115 -17
  278. package/dist/components/p-1lIHoOlH.js.map +1 -0
  279. package/dist/{stencil/object.helper-B0kd2rUI.js → components/p-B0kd2rUI.js} +2 -2
  280. package/dist/components/p-B0kd2rUI.js.map +1 -0
  281. package/dist/components/p-B4kxkVe-.js +55 -0
  282. package/dist/components/p-B4kxkVe-.js.map +1 -0
  283. package/dist/components/p-BQg4YML7.js +106 -0
  284. package/dist/components/p-BQg4YML7.js.map +1 -0
  285. package/dist/{stencil/kritzel-font-family.entry.js → components/p-BgznZoBH.js} +37 -9
  286. package/dist/components/p-BgznZoBH.js.map +1 -0
  287. package/dist/components/p-Bhtn9qay.js +98 -0
  288. package/dist/components/p-Bhtn9qay.js.map +1 -0
  289. package/dist/{stencil/kritzel-context-menu-GdU9xEKC.js → components/p-C2sWlNsJ.js} +41 -12
  290. package/dist/components/p-C2sWlNsJ.js.map +1 -0
  291. package/dist/{stencil/html.helper-C6qB08BS.js → components/p-C6qB08BS.js} +2 -2
  292. package/dist/components/p-C6qB08BS.js.map +1 -0
  293. package/dist/{stencil/text-tool.class-C0GbC5zQ.js → components/p-CBYBurdY.js} +25 -729
  294. package/dist/components/p-CBYBurdY.js.map +1 -0
  295. package/dist/{stencil/kritzel-dropdown.entry.js → components/p-CIXPLjCu.js} +39 -9
  296. package/dist/components/p-CIXPLjCu.js.map +1 -0
  297. package/dist/{stencil/kritzel-workspace-manager.entry.js → components/p-CK6no3mi.js} +68 -13
  298. package/dist/components/p-CK6no3mi.js.map +1 -0
  299. package/dist/{stencil/kritzel-cursor-trail.entry.js → components/p-CLt3HMl6.js} +33 -10
  300. package/dist/components/p-CLt3HMl6.js.map +1 -0
  301. package/dist/{stencil/kritzel-tooltip.entry.js → components/p-CTP479Lf.js} +39 -11
  302. package/dist/components/p-CTP479Lf.js.map +1 -0
  303. package/dist/{stencil/kritzel-menu-item.entry.js → components/p-CsA9M6me.js} +174 -16
  304. package/dist/components/p-CsA9M6me.js.map +1 -0
  305. package/dist/components/p-CwkUrTy1.js +1367 -0
  306. package/dist/components/p-CwkUrTy1.js.map +1 -0
  307. package/dist/{stencil/kritzel-color-palette.entry.js → components/p-D1uj4A4F.js} +39 -9
  308. package/dist/components/p-D1uj4A4F.js.map +1 -0
  309. package/dist/{stencil/kritzel-color.entry.js → components/p-D4yvhd1d.js} +30 -8
  310. package/dist/components/p-D4yvhd1d.js.map +1 -0
  311. package/dist/{stencil/kritzel-portal.entry.js → components/p-D5Wq4x4r.js} +37 -11
  312. package/dist/components/p-D5Wq4x4r.js.map +1 -0
  313. package/dist/{stencil/event-button.enum-D8W6LE-c.js → components/p-D8W6LE-c.js} +2 -2
  314. package/dist/components/p-D8W6LE-c.js.map +1 -0
  315. package/dist/{stencil/kritzel-utility-panel.entry.js → components/p-DAfkuR8U.js} +38 -11
  316. package/dist/components/p-DAfkuR8U.js.map +1 -0
  317. package/dist/components/p-DDmSxM5f.js +57 -0
  318. package/dist/{stencil/kritzel-font-size.entry.esm.js.map → components/p-DDmSxM5f.js.map} +1 -1
  319. package/dist/components/p-Ddh40W3x.js +103 -0
  320. package/dist/components/p-Ddh40W3x.js.map +1 -0
  321. package/dist/components/p-DjTEcPMZ.js +35610 -0
  322. package/dist/components/p-DjTEcPMZ.js.map +1 -0
  323. package/dist/{stencil/kritzel-split-button.entry.js → components/p-TdCTkEu0.js} +72 -18
  324. package/dist/components/p-TdCTkEu0.js.map +1 -0
  325. package/dist/{stencil/devices.helper-l10It7Nm.js → components/p-l10It7Nm.js} +2 -2
  326. package/dist/components/p-l10It7Nm.js.map +1 -0
  327. package/dist/{stencil/workspace.class-n789Y3S-.js → components/p-n789Y3S-.js} +2 -2
  328. package/dist/components/p-n789Y3S-.js.map +1 -0
  329. package/dist/components/p-uuRJU2R1.js +46 -0
  330. package/dist/components/p-uuRJU2R1.js.map +1 -0
  331. package/dist/esm/app-globals-DQuL1Twl.js +6 -0
  332. package/dist/esm/app-globals-DQuL1Twl.js.map +1 -0
  333. package/dist/esm/default-text-tool.config-2YFQA3SF.js +31208 -0
  334. package/dist/esm/default-text-tool.config-2YFQA3SF.js.map +1 -0
  335. package/dist/esm/index-SGde3HXB.js +1623 -0
  336. package/dist/esm/index-SGde3HXB.js.map +1 -0
  337. package/dist/esm/index.js +1449 -0
  338. package/dist/esm/index.js.map +1 -0
  339. package/dist/{stencil → esm}/kritzel-brush-style.entry.js +3 -3
  340. package/dist/esm/kritzel-brush-style.entry.js.map +1 -0
  341. package/dist/{stencil/kritzel-engine.entry.js → esm/kritzel-color_22.entry.js} +1805 -72
  342. package/dist/esm/loader.js +12 -0
  343. package/dist/esm/loader.js.map +1 -0
  344. package/dist/esm/stencil.js +22 -0
  345. package/dist/esm/stencil.js.map +1 -0
  346. package/dist/index.cjs.js +1 -0
  347. package/dist/index.js +1 -0
  348. package/dist/stencil/index.esm.js +2 -18
  349. package/dist/stencil/index.esm.js.map +1 -1
  350. package/dist/stencil/loader.esm.js.map +1 -1
  351. package/dist/stencil/p-14102a0c.entry.js +10 -0
  352. package/dist/stencil/p-14102a0c.entry.js.map +1 -0
  353. package/dist/stencil/p-2YFQA3SF.js +2 -0
  354. package/dist/stencil/p-2YFQA3SF.js.map +1 -0
  355. package/dist/stencil/p-DQuL1Twl.js +2 -0
  356. package/dist/stencil/p-DQuL1Twl.js.map +1 -0
  357. package/dist/stencil/p-SGde3HXB.js +3 -0
  358. package/dist/stencil/p-SGde3HXB.js.map +1 -0
  359. package/dist/stencil/p-d702c5af.entry.js +2 -0
  360. package/dist/stencil/p-d702c5af.entry.js.map +1 -0
  361. package/dist/stencil/stencil.esm.js +2 -48
  362. package/dist/stencil/stencil.esm.js.map +1 -1
  363. package/package.json +1 -1
  364. package/dist/stencil/default-text-tool.config-DKpRP4XR.js +0 -1441
  365. package/dist/stencil/default-text-tool.config-DKpRP4XR.js.map +0 -1
  366. package/dist/stencil/devices.helper-l10It7Nm.js.map +0 -1
  367. package/dist/stencil/engine.constants-DsjjAmnl.js +0 -7
  368. package/dist/stencil/engine.constants-DsjjAmnl.js.map +0 -1
  369. package/dist/stencil/event-button.enum-D8W6LE-c.js.map +0 -1
  370. package/dist/stencil/icon-registry.class-BtT8riKh.js.map +0 -1
  371. package/dist/stencil/index-DniO_INI.js +0 -4395
  372. package/dist/stencil/index-DniO_INI.js.map +0 -1
  373. package/dist/stencil/kritzel-color-palette.entry.esm.js.map +0 -1
  374. package/dist/stencil/kritzel-color.entry.esm.js.map +0 -1
  375. package/dist/stencil/kritzel-context-menu-BYgOEy-i.js +0 -66
  376. package/dist/stencil/kritzel-context-menu-BYgOEy-i.js.map +0 -1
  377. package/dist/stencil/kritzel-context-menu-GdU9xEKC.js.map +0 -1
  378. package/dist/stencil/kritzel-context-menu.entry.esm.js.map +0 -1
  379. package/dist/stencil/kritzel-context-menu.entry.js +0 -3
  380. package/dist/stencil/kritzel-control-brush-config.entry.esm.js.map +0 -1
  381. package/dist/stencil/kritzel-control-brush-config.entry.js +0 -54
  382. package/dist/stencil/kritzel-control-text-config.entry.esm.js.map +0 -1
  383. package/dist/stencil/kritzel-control-text-config.entry.js +0 -42
  384. package/dist/stencil/kritzel-controls.entry.esm.js.map +0 -1
  385. package/dist/stencil/kritzel-cursor-trail.entry.esm.js.map +0 -1
  386. package/dist/stencil/kritzel-dropdown.entry.esm.js.map +0 -1
  387. package/dist/stencil/kritzel-editor.entry.esm.js.map +0 -1
  388. package/dist/stencil/kritzel-editor.entry.js +0 -248
  389. package/dist/stencil/kritzel-engine.entry.esm.js.map +0 -1
  390. package/dist/stencil/kritzel-font-family.entry.esm.js.map +0 -1
  391. package/dist/stencil/kritzel-font-size.entry.js +0 -28
  392. package/dist/stencil/kritzel-font.entry.esm.js.map +0 -1
  393. package/dist/stencil/kritzel-font.entry.js +0 -23
  394. package/dist/stencil/kritzel-icon.entry.esm.js.map +0 -1
  395. package/dist/stencil/kritzel-icon.entry.js +0 -29
  396. package/dist/stencil/kritzel-menu-item.entry.esm.js.map +0 -1
  397. package/dist/stencil/kritzel-menu.entry.esm.js.map +0 -1
  398. package/dist/stencil/kritzel-menu.entry.js +0 -72
  399. package/dist/stencil/kritzel-portal.entry.esm.js.map +0 -1
  400. package/dist/stencil/kritzel-split-button.entry.esm.js.map +0 -1
  401. package/dist/stencil/kritzel-stroke-size.entry.esm.js.map +0 -1
  402. package/dist/stencil/kritzel-stroke-size.entry.js +0 -27
  403. package/dist/stencil/kritzel-tooltip.entry.esm.js.map +0 -1
  404. package/dist/stencil/kritzel-utility-panel.entry.esm.js.map +0 -1
  405. package/dist/stencil/kritzel-workspace-manager.entry.esm.js.map +0 -1
  406. package/dist/stencil/object.helper-B0kd2rUI.js.map +0 -1
  407. package/dist/stencil/sync-config.interface-lKfyG1EN.js +0 -19839
  408. package/dist/stencil/sync-config.interface-lKfyG1EN.js.map +0 -1
  409. package/dist/stencil/text-tool.class-C0GbC5zQ.js.map +0 -1
  410. package/dist/stencil/workspace.class-n789Y3S-.js.map +0 -1
@@ -0,0 +1,1449 @@
1
+ import { w as writeVarUint, a as writeVarUint8Array, t as toUint8Array, r as readVarUint, b as readVarUint8Array, e as encodeStateAsUpdate, c as applyUpdate, d as encodeStateVector, f as createEncoder, g as createDecoder, s as setIfUndefined, h as create, i as fromBase64, v as varStorage, j as toBase64, o as onChange, k as createUint8ArrayFromArrayBuffer, l as offChange, m as readVarString, O as Observable, n as floor, p as getUnixTime, q as equalityDeep, u as writeVarString, x as map, y as ObservableV2, z as length, A as isNode, B as min, C as pow, H as HocuspocusProvider, D as HocuspocusProviderWebsocket } from './default-text-tool.config-2YFQA3SF.js';
2
+ export { R as DEFAULT_BRUSH_CONFIG, S as DEFAULT_TEXT_CONFIG, N as IndexedDBSyncProvider, P as KritzelAppStateMap, G as KritzelBrushTool, I as KritzelEraserTool, F as KritzelImage, J as KritzelImageTool, E as KritzelPath, M as KritzelSelectionTool, K as KritzelText, L as KritzelTextTool, Q as KritzelWorkspace } from './default-text-tool.config-2YFQA3SF.js';
3
+
4
+ /**
5
+ * BroadcastChannel sync provider for cross-tab synchronization
6
+ * This is a lightweight alternative to y-webrtc for browser-tab-only sync
7
+ */
8
+ class BroadcastSyncProvider {
9
+ doc;
10
+ channel;
11
+ _synced = false;
12
+ constructor(docName, doc, _options) {
13
+ this.doc = doc;
14
+ this.channel = new BroadcastChannel(docName);
15
+ // Handle incoming messages from other tabs
16
+ this.channel.onmessage = (event) => {
17
+ this.handleMessage(event.data);
18
+ };
19
+ // Listen to document updates and broadcast them
20
+ this.doc.on('update', this.handleDocUpdate);
21
+ // Send initial sync request
22
+ this.broadcastSync();
23
+ // Mark as synced after a short delay (to receive any pending updates)
24
+ setTimeout(() => {
25
+ this._synced = true;
26
+ }, 100);
27
+ console.info(`BroadcastChannel Provider initialized: ${docName}`);
28
+ }
29
+ handleDocUpdate = (update, origin) => {
30
+ // Don't broadcast updates that came from other tabs (to prevent loops)
31
+ if (origin !== this) {
32
+ const encoder = createEncoder();
33
+ writeVarUint(encoder, 0); // Message type: sync update
34
+ writeVarUint8Array(encoder, update);
35
+ this.channel.postMessage(toUint8Array(encoder));
36
+ }
37
+ };
38
+ handleMessage(message) {
39
+ const decoder = createDecoder(new Uint8Array(message));
40
+ const messageType = readVarUint(decoder);
41
+ switch (messageType) {
42
+ case 0: // Sync update
43
+ const update = readVarUint8Array(decoder);
44
+ applyUpdate(this.doc, update, this);
45
+ break;
46
+ case 1: // Sync request
47
+ this.broadcastSync();
48
+ break;
49
+ case 2: // Sync response
50
+ const stateVector = readVarUint8Array(decoder);
51
+ const updateResponse = encodeStateAsUpdate(this.doc, stateVector);
52
+ if (updateResponse.length > 0) {
53
+ const encoder = createEncoder();
54
+ writeVarUint(encoder, 0); // Send as regular update
55
+ writeVarUint8Array(encoder, updateResponse);
56
+ this.channel.postMessage(toUint8Array(encoder));
57
+ }
58
+ break;
59
+ }
60
+ }
61
+ broadcastSync() {
62
+ // Broadcast our current state vector to request missing updates
63
+ const encoder = createEncoder();
64
+ writeVarUint(encoder, 2); // Message type: sync response
65
+ writeVarUint8Array(encoder, encodeStateVector(this.doc));
66
+ this.channel.postMessage(toUint8Array(encoder));
67
+ }
68
+ async connect() {
69
+ // Wait for initial sync to complete
70
+ if (this._synced) {
71
+ return;
72
+ }
73
+ return new Promise((resolve) => {
74
+ const checkSync = () => {
75
+ if (this._synced) {
76
+ resolve();
77
+ }
78
+ else {
79
+ setTimeout(checkSync, 50);
80
+ }
81
+ };
82
+ checkSync();
83
+ });
84
+ }
85
+ disconnect() {
86
+ // BroadcastChannel doesn't have explicit disconnect
87
+ }
88
+ destroy() {
89
+ this.doc.off('update', this.handleDocUpdate);
90
+ this.channel.close();
91
+ }
92
+ }
93
+
94
+ /* eslint-env browser */
95
+
96
+
97
+ /**
98
+ * @typedef {Object} Channel
99
+ * @property {Set<function(any, any):any>} Channel.subs
100
+ * @property {any} Channel.bc
101
+ */
102
+
103
+ /**
104
+ * @type {Map<string, Channel>}
105
+ */
106
+ const channels = new Map();
107
+
108
+ /* c8 ignore start */
109
+ class LocalStoragePolyfill {
110
+ /**
111
+ * @param {string} room
112
+ */
113
+ constructor (room) {
114
+ this.room = room;
115
+ /**
116
+ * @type {null|function({data:ArrayBuffer}):void}
117
+ */
118
+ this.onmessage = null;
119
+ /**
120
+ * @param {any} e
121
+ */
122
+ this._onChange = e => e.key === room && this.onmessage !== null && this.onmessage({ data: fromBase64(e.newValue || '') });
123
+ onChange(this._onChange);
124
+ }
125
+
126
+ /**
127
+ * @param {ArrayBuffer} buf
128
+ */
129
+ postMessage (buf) {
130
+ varStorage.setItem(this.room, toBase64(createUint8ArrayFromArrayBuffer(buf)));
131
+ }
132
+
133
+ close () {
134
+ offChange(this._onChange);
135
+ }
136
+ }
137
+ /* c8 ignore stop */
138
+
139
+ // Use BroadcastChannel or Polyfill
140
+ /* c8 ignore next */
141
+ const BC = typeof BroadcastChannel === 'undefined' ? LocalStoragePolyfill : BroadcastChannel;
142
+
143
+ /**
144
+ * @param {string} room
145
+ * @return {Channel}
146
+ */
147
+ const getChannel = room =>
148
+ setIfUndefined(channels, room, () => {
149
+ const subs = create();
150
+ const bc = new BC(room);
151
+ /**
152
+ * @param {{data:ArrayBuffer}} e
153
+ */
154
+ /* c8 ignore next */
155
+ bc.onmessage = e => subs.forEach(sub => sub(e.data, 'broadcastchannel'));
156
+ return {
157
+ bc, subs
158
+ }
159
+ });
160
+
161
+ /**
162
+ * Subscribe to global `publish` events.
163
+ *
164
+ * @function
165
+ * @param {string} room
166
+ * @param {function(any, any):any} f
167
+ */
168
+ const subscribe = (room, f) => {
169
+ getChannel(room).subs.add(f);
170
+ return f
171
+ };
172
+
173
+ /**
174
+ * Unsubscribe from `publish` global events.
175
+ *
176
+ * @function
177
+ * @param {string} room
178
+ * @param {function(any, any):any} f
179
+ */
180
+ const unsubscribe = (room, f) => {
181
+ const channel = getChannel(room);
182
+ const unsubscribed = channel.subs.delete(f);
183
+ if (unsubscribed && channel.subs.size === 0) {
184
+ channel.bc.close();
185
+ channels.delete(room);
186
+ }
187
+ return unsubscribed
188
+ };
189
+
190
+ /**
191
+ * Publish data to all subscribers (including subscribers on this tab)
192
+ *
193
+ * @function
194
+ * @param {string} room
195
+ * @param {any} data
196
+ * @param {any} [origin]
197
+ */
198
+ const publish = (room, data, origin = null) => {
199
+ const c = getChannel(room);
200
+ c.bc.postMessage(data);
201
+ c.subs.forEach(sub => sub(data, origin));
202
+ };
203
+
204
+ /**
205
+ * @module sync-protocol
206
+ */
207
+
208
+
209
+ /**
210
+ * @typedef {Map<number, number>} StateMap
211
+ */
212
+
213
+ /**
214
+ * Core Yjs defines two message types:
215
+ * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.
216
+ * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it
217
+ * received all information from the remote client.
218
+ *
219
+ * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection
220
+ * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both
221
+ * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.
222
+ *
223
+ * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.
224
+ * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies
225
+ * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the
226
+ * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can
227
+ * easily be implemented on top of http and websockets. 2. The server should only reply to requests, and not initiate them.
228
+ * Therefore it is necessary that the client initiates the sync.
229
+ *
230
+ * Construction of a message:
231
+ * [messageType : varUint, message definition..]
232
+ *
233
+ * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!
234
+ *
235
+ * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)
236
+ */
237
+
238
+ const messageYjsSyncStep1 = 0;
239
+ const messageYjsSyncStep2 = 1;
240
+ const messageYjsUpdate = 2;
241
+
242
+ /**
243
+ * Create a sync step 1 message based on the state of the current shared document.
244
+ *
245
+ * @param {encoding.Encoder} encoder
246
+ * @param {Y.Doc} doc
247
+ */
248
+ const writeSyncStep1 = (encoder, doc) => {
249
+ writeVarUint(encoder, messageYjsSyncStep1);
250
+ const sv = encodeStateVector(doc);
251
+ writeVarUint8Array(encoder, sv);
252
+ };
253
+
254
+ /**
255
+ * @param {encoding.Encoder} encoder
256
+ * @param {Y.Doc} doc
257
+ * @param {Uint8Array} [encodedStateVector]
258
+ */
259
+ const writeSyncStep2 = (encoder, doc, encodedStateVector) => {
260
+ writeVarUint(encoder, messageYjsSyncStep2);
261
+ writeVarUint8Array(encoder, encodeStateAsUpdate(doc, encodedStateVector));
262
+ };
263
+
264
+ /**
265
+ * Read SyncStep1 message and reply with SyncStep2.
266
+ *
267
+ * @param {decoding.Decoder} decoder The reply to the received message
268
+ * @param {encoding.Encoder} encoder The received message
269
+ * @param {Y.Doc} doc
270
+ */
271
+ const readSyncStep1 = (decoder, encoder, doc) =>
272
+ writeSyncStep2(encoder, doc, readVarUint8Array(decoder));
273
+
274
+ /**
275
+ * Read and apply Structs and then DeleteStore to a y instance.
276
+ *
277
+ * @param {decoding.Decoder} decoder
278
+ * @param {Y.Doc} doc
279
+ * @param {any} transactionOrigin
280
+ */
281
+ const readSyncStep2 = (decoder, doc, transactionOrigin) => {
282
+ try {
283
+ applyUpdate(doc, readVarUint8Array(decoder), transactionOrigin);
284
+ } catch (error) {
285
+ // This catches errors that are thrown by event handlers
286
+ console.error('Caught error while handling a Yjs update', error);
287
+ }
288
+ };
289
+
290
+ /**
291
+ * @param {encoding.Encoder} encoder
292
+ * @param {Uint8Array} update
293
+ */
294
+ const writeUpdate = (encoder, update) => {
295
+ writeVarUint(encoder, messageYjsUpdate);
296
+ writeVarUint8Array(encoder, update);
297
+ };
298
+
299
+ /**
300
+ * Read and apply Structs and then DeleteStore to a y instance.
301
+ *
302
+ * @param {decoding.Decoder} decoder
303
+ * @param {Y.Doc} doc
304
+ * @param {any} transactionOrigin
305
+ */
306
+ const readUpdate = readSyncStep2;
307
+
308
+ /**
309
+ * @param {decoding.Decoder} decoder A message received from another client
310
+ * @param {encoding.Encoder} encoder The reply message. Does not need to be sent if empty.
311
+ * @param {Y.Doc} doc
312
+ * @param {any} transactionOrigin
313
+ */
314
+ const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
315
+ const messageType = readVarUint(decoder);
316
+ switch (messageType) {
317
+ case messageYjsSyncStep1:
318
+ readSyncStep1(decoder, encoder, doc);
319
+ break
320
+ case messageYjsSyncStep2:
321
+ readSyncStep2(decoder, doc, transactionOrigin);
322
+ break
323
+ case messageYjsUpdate:
324
+ readUpdate(decoder, doc, transactionOrigin);
325
+ break
326
+ default:
327
+ throw new Error('Unknown message type')
328
+ }
329
+ return messageType
330
+ };
331
+
332
+ const messagePermissionDenied = 0;
333
+
334
+ /**
335
+ * @callback PermissionDeniedHandler
336
+ * @param {any} y
337
+ * @param {string} reason
338
+ */
339
+
340
+ /**
341
+ *
342
+ * @param {decoding.Decoder} decoder
343
+ * @param {Y.Doc} y
344
+ * @param {PermissionDeniedHandler} permissionDeniedHandler
345
+ */
346
+ const readAuthMessage = (decoder, y, permissionDeniedHandler) => {
347
+ switch (readVarUint(decoder)) {
348
+ case messagePermissionDenied: permissionDeniedHandler(y, readVarString(decoder));
349
+ }
350
+ };
351
+
352
+ /**
353
+ * @module awareness-protocol
354
+ */
355
+
356
+
357
+ const outdatedTimeout = 30000;
358
+
359
+ /**
360
+ * @typedef {Object} MetaClientState
361
+ * @property {number} MetaClientState.clock
362
+ * @property {number} MetaClientState.lastUpdated unix timestamp
363
+ */
364
+
365
+ /**
366
+ * The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information
367
+ * (cursor, username, status, ..). Each client can update its own local state and listen to state changes of
368
+ * remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline.
369
+ *
370
+ * Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override
371
+ * its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is
372
+ * applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that
373
+ * a remote client is offline, it may propagate a message with
374
+ * `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a
375
+ * message is received, and the known clock of that client equals the received clock, it will override the state with `null`.
376
+ *
377
+ * Before a client disconnects, it should propagate a `null` state with an updated clock.
378
+ *
379
+ * Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state.
380
+ *
381
+ * @extends {Observable<string>}
382
+ */
383
+ class Awareness extends Observable {
384
+ /**
385
+ * @param {Y.Doc} doc
386
+ */
387
+ constructor (doc) {
388
+ super();
389
+ this.doc = doc;
390
+ /**
391
+ * @type {number}
392
+ */
393
+ this.clientID = doc.clientID;
394
+ /**
395
+ * Maps from client id to client state
396
+ * @type {Map<number, Object<string, any>>}
397
+ */
398
+ this.states = new Map();
399
+ /**
400
+ * @type {Map<number, MetaClientState>}
401
+ */
402
+ this.meta = new Map();
403
+ this._checkInterval = /** @type {any} */ (setInterval(() => {
404
+ const now = getUnixTime();
405
+ if (this.getLocalState() !== null && (outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(this.clientID)).lastUpdated)) {
406
+ // renew local clock
407
+ this.setLocalState(this.getLocalState());
408
+ }
409
+ /**
410
+ * @type {Array<number>}
411
+ */
412
+ const remove = [];
413
+ this.meta.forEach((meta, clientid) => {
414
+ if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid)) {
415
+ remove.push(clientid);
416
+ }
417
+ });
418
+ if (remove.length > 0) {
419
+ removeAwarenessStates(this, remove, 'timeout');
420
+ }
421
+ }, floor(outdatedTimeout / 10)));
422
+ doc.on('destroy', () => {
423
+ this.destroy();
424
+ });
425
+ this.setLocalState({});
426
+ }
427
+
428
+ destroy () {
429
+ this.emit('destroy', [this]);
430
+ this.setLocalState(null);
431
+ super.destroy();
432
+ clearInterval(this._checkInterval);
433
+ }
434
+
435
+ /**
436
+ * @return {Object<string,any>|null}
437
+ */
438
+ getLocalState () {
439
+ return this.states.get(this.clientID) || null
440
+ }
441
+
442
+ /**
443
+ * @param {Object<string,any>|null} state
444
+ */
445
+ setLocalState (state) {
446
+ const clientID = this.clientID;
447
+ const currLocalMeta = this.meta.get(clientID);
448
+ const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1;
449
+ const prevState = this.states.get(clientID);
450
+ if (state === null) {
451
+ this.states.delete(clientID);
452
+ } else {
453
+ this.states.set(clientID, state);
454
+ }
455
+ this.meta.set(clientID, {
456
+ clock,
457
+ lastUpdated: getUnixTime()
458
+ });
459
+ const added = [];
460
+ const updated = [];
461
+ const filteredUpdated = [];
462
+ const removed = [];
463
+ if (state === null) {
464
+ removed.push(clientID);
465
+ } else if (prevState == null) {
466
+ if (state != null) {
467
+ added.push(clientID);
468
+ }
469
+ } else {
470
+ updated.push(clientID);
471
+ if (!equalityDeep(prevState, state)) {
472
+ filteredUpdated.push(clientID);
473
+ }
474
+ }
475
+ if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
476
+ this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local']);
477
+ }
478
+ this.emit('update', [{ added, updated, removed }, 'local']);
479
+ }
480
+
481
+ /**
482
+ * @param {string} field
483
+ * @param {any} value
484
+ */
485
+ setLocalStateField (field, value) {
486
+ const state = this.getLocalState();
487
+ if (state !== null) {
488
+ this.setLocalState({
489
+ ...state,
490
+ [field]: value
491
+ });
492
+ }
493
+ }
494
+
495
+ /**
496
+ * @return {Map<number,Object<string,any>>}
497
+ */
498
+ getStates () {
499
+ return this.states
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Mark (remote) clients as inactive and remove them from the list of active peers.
505
+ * This change will be propagated to remote clients.
506
+ *
507
+ * @param {Awareness} awareness
508
+ * @param {Array<number>} clients
509
+ * @param {any} origin
510
+ */
511
+ const removeAwarenessStates = (awareness, clients, origin) => {
512
+ const removed = [];
513
+ for (let i = 0; i < clients.length; i++) {
514
+ const clientID = clients[i];
515
+ if (awareness.states.has(clientID)) {
516
+ awareness.states.delete(clientID);
517
+ if (clientID === awareness.clientID) {
518
+ const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID));
519
+ awareness.meta.set(clientID, {
520
+ clock: curMeta.clock + 1,
521
+ lastUpdated: getUnixTime()
522
+ });
523
+ }
524
+ removed.push(clientID);
525
+ }
526
+ }
527
+ if (removed.length > 0) {
528
+ awareness.emit('change', [{ added: [], updated: [], removed }, origin]);
529
+ awareness.emit('update', [{ added: [], updated: [], removed }, origin]);
530
+ }
531
+ };
532
+
533
+ /**
534
+ * @param {Awareness} awareness
535
+ * @param {Array<number>} clients
536
+ * @return {Uint8Array}
537
+ */
538
+ const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => {
539
+ const len = clients.length;
540
+ const encoder = createEncoder();
541
+ writeVarUint(encoder, len);
542
+ for (let i = 0; i < len; i++) {
543
+ const clientID = clients[i];
544
+ const state = states.get(clientID) || null;
545
+ const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock;
546
+ writeVarUint(encoder, clientID);
547
+ writeVarUint(encoder, clock);
548
+ writeVarString(encoder, JSON.stringify(state));
549
+ }
550
+ return toUint8Array(encoder)
551
+ };
552
+
553
+ /**
554
+ * @param {Awareness} awareness
555
+ * @param {Uint8Array} update
556
+ * @param {any} origin This will be added to the emitted change event
557
+ */
558
+ const applyAwarenessUpdate = (awareness, update, origin) => {
559
+ const decoder = createDecoder(update);
560
+ const timestamp = getUnixTime();
561
+ const added = [];
562
+ const updated = [];
563
+ const filteredUpdated = [];
564
+ const removed = [];
565
+ const len = readVarUint(decoder);
566
+ for (let i = 0; i < len; i++) {
567
+ const clientID = readVarUint(decoder);
568
+ let clock = readVarUint(decoder);
569
+ const state = JSON.parse(readVarString(decoder));
570
+ const clientMeta = awareness.meta.get(clientID);
571
+ const prevState = awareness.states.get(clientID);
572
+ const currClock = clientMeta === undefined ? 0 : clientMeta.clock;
573
+ if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) {
574
+ if (state === null) {
575
+ // never let a remote client remove this local state
576
+ if (clientID === awareness.clientID && awareness.getLocalState() != null) {
577
+ // remote client removed the local state. Do not remote state. Broadcast a message indicating
578
+ // that this client still exists by increasing the clock
579
+ clock++;
580
+ } else {
581
+ awareness.states.delete(clientID);
582
+ }
583
+ } else {
584
+ awareness.states.set(clientID, state);
585
+ }
586
+ awareness.meta.set(clientID, {
587
+ clock,
588
+ lastUpdated: timestamp
589
+ });
590
+ if (clientMeta === undefined && state !== null) {
591
+ added.push(clientID);
592
+ } else if (clientMeta !== undefined && state === null) {
593
+ removed.push(clientID);
594
+ } else if (state !== null) {
595
+ if (!equalityDeep(state, prevState)) {
596
+ filteredUpdated.push(clientID);
597
+ }
598
+ updated.push(clientID);
599
+ }
600
+ }
601
+ }
602
+ if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
603
+ awareness.emit('change', [{
604
+ added, updated: filteredUpdated, removed
605
+ }, origin]);
606
+ }
607
+ if (added.length > 0 || updated.length > 0 || removed.length > 0) {
608
+ awareness.emit('update', [{
609
+ added, updated, removed
610
+ }, origin]);
611
+ }
612
+ };
613
+
614
+ /**
615
+ * Utility module to work with urls.
616
+ *
617
+ * @module url
618
+ */
619
+
620
+
621
+ /**
622
+ * @param {Object<string,string>} params
623
+ * @return {string}
624
+ */
625
+ const encodeQueryParams = params =>
626
+ map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
627
+
628
+ /**
629
+ * @module provider/websocket
630
+ */
631
+
632
+
633
+ const messageSync = 0;
634
+ const messageQueryAwareness = 3;
635
+ const messageAwareness = 1;
636
+ const messageAuth = 2;
637
+
638
+ /**
639
+ * encoder, decoder, provider, emitSynced, messageType
640
+ * @type {Array<function(encoding.Encoder, decoding.Decoder, WebsocketProvider, boolean, number):void>}
641
+ */
642
+ const messageHandlers = [];
643
+
644
+ messageHandlers[messageSync] = (
645
+ encoder,
646
+ decoder,
647
+ provider,
648
+ emitSynced,
649
+ _messageType
650
+ ) => {
651
+ writeVarUint(encoder, messageSync);
652
+ const syncMessageType = readSyncMessage(
653
+ decoder,
654
+ encoder,
655
+ provider.doc,
656
+ provider
657
+ );
658
+ if (
659
+ emitSynced && syncMessageType === messageYjsSyncStep2 &&
660
+ !provider.synced
661
+ ) {
662
+ provider.synced = true;
663
+ }
664
+ };
665
+
666
+ messageHandlers[messageQueryAwareness] = (
667
+ encoder,
668
+ _decoder,
669
+ provider,
670
+ _emitSynced,
671
+ _messageType
672
+ ) => {
673
+ writeVarUint(encoder, messageAwareness);
674
+ writeVarUint8Array(
675
+ encoder,
676
+ encodeAwarenessUpdate(
677
+ provider.awareness,
678
+ Array.from(provider.awareness.getStates().keys())
679
+ )
680
+ );
681
+ };
682
+
683
+ messageHandlers[messageAwareness] = (
684
+ _encoder,
685
+ decoder,
686
+ provider,
687
+ _emitSynced,
688
+ _messageType
689
+ ) => {
690
+ applyAwarenessUpdate(
691
+ provider.awareness,
692
+ readVarUint8Array(decoder),
693
+ provider
694
+ );
695
+ };
696
+
697
+ messageHandlers[messageAuth] = (
698
+ _encoder,
699
+ decoder,
700
+ provider,
701
+ _emitSynced,
702
+ _messageType
703
+ ) => {
704
+ readAuthMessage(
705
+ decoder,
706
+ provider.doc,
707
+ (_ydoc, reason) => permissionDeniedHandler(provider, reason)
708
+ );
709
+ };
710
+
711
+ // @todo - this should depend on awareness.outdatedTime
712
+ const messageReconnectTimeout = 30000;
713
+
714
+ /**
715
+ * @param {WebsocketProvider} provider
716
+ * @param {string} reason
717
+ */
718
+ const permissionDeniedHandler = (provider, reason) =>
719
+ console.warn(`Permission denied to access ${provider.url}.\n${reason}`);
720
+
721
+ /**
722
+ * @param {WebsocketProvider} provider
723
+ * @param {Uint8Array} buf
724
+ * @param {boolean} emitSynced
725
+ * @return {encoding.Encoder}
726
+ */
727
+ const readMessage = (provider, buf, emitSynced) => {
728
+ const decoder = createDecoder(buf);
729
+ const encoder = createEncoder();
730
+ const messageType = readVarUint(decoder);
731
+ const messageHandler = provider.messageHandlers[messageType];
732
+ if (/** @type {any} */ (messageHandler)) {
733
+ messageHandler(encoder, decoder, provider, emitSynced, messageType);
734
+ } else {
735
+ console.error('Unable to compute message');
736
+ }
737
+ return encoder
738
+ };
739
+
740
+ /**
741
+ * Outsource this function so that a new websocket connection is created immediately.
742
+ * I suspect that the `ws.onclose` event is not always fired if there are network issues.
743
+ *
744
+ * @param {WebsocketProvider} provider
745
+ * @param {WebSocket} ws
746
+ * @param {CloseEvent | null} event
747
+ */
748
+ const closeWebsocketConnection = (provider, ws, event) => {
749
+ if (ws === provider.ws) {
750
+ provider.emit('connection-close', [event, provider]);
751
+ provider.ws = null;
752
+ ws.close();
753
+ provider.wsconnecting = false;
754
+ if (provider.wsconnected) {
755
+ provider.wsconnected = false;
756
+ provider.synced = false;
757
+ // update awareness (all users except local left)
758
+ removeAwarenessStates(
759
+ provider.awareness,
760
+ Array.from(provider.awareness.getStates().keys()).filter((client) =>
761
+ client !== provider.doc.clientID
762
+ ),
763
+ provider
764
+ );
765
+ provider.emit('status', [{
766
+ status: 'disconnected'
767
+ }]);
768
+ } else {
769
+ provider.wsUnsuccessfulReconnects++;
770
+ }
771
+ // Start with no reconnect timeout and increase timeout by
772
+ // using exponential backoff starting with 100ms
773
+ setTimeout(
774
+ setupWS,
775
+ min(
776
+ pow(2, provider.wsUnsuccessfulReconnects) * 100,
777
+ provider.maxBackoffTime
778
+ ),
779
+ provider
780
+ );
781
+ }
782
+ };
783
+
784
+ /**
785
+ * @param {WebsocketProvider} provider
786
+ */
787
+ const setupWS = (provider) => {
788
+ if (provider.shouldConnect && provider.ws === null) {
789
+ const websocket = new provider._WS(provider.url, provider.protocols);
790
+ websocket.binaryType = 'arraybuffer';
791
+ provider.ws = websocket;
792
+ provider.wsconnecting = true;
793
+ provider.wsconnected = false;
794
+ provider.synced = false;
795
+
796
+ websocket.onmessage = (event) => {
797
+ provider.wsLastMessageReceived = getUnixTime();
798
+ const encoder = readMessage(provider, new Uint8Array(event.data), true);
799
+ if (length(encoder) > 1) {
800
+ websocket.send(toUint8Array(encoder));
801
+ }
802
+ };
803
+ websocket.onerror = (event) => {
804
+ provider.emit('connection-error', [event, provider]);
805
+ };
806
+ websocket.onclose = (event) => {
807
+ closeWebsocketConnection(provider, websocket, event);
808
+ };
809
+ websocket.onopen = () => {
810
+ provider.wsLastMessageReceived = getUnixTime();
811
+ provider.wsconnecting = false;
812
+ provider.wsconnected = true;
813
+ provider.wsUnsuccessfulReconnects = 0;
814
+ provider.emit('status', [{
815
+ status: 'connected'
816
+ }]);
817
+ // always send sync step 1 when connected
818
+ const encoder = createEncoder();
819
+ writeVarUint(encoder, messageSync);
820
+ writeSyncStep1(encoder, provider.doc);
821
+ websocket.send(toUint8Array(encoder));
822
+ // broadcast local awareness state
823
+ if (provider.awareness.getLocalState() !== null) {
824
+ const encoderAwarenessState = createEncoder();
825
+ writeVarUint(encoderAwarenessState, messageAwareness);
826
+ writeVarUint8Array(
827
+ encoderAwarenessState,
828
+ encodeAwarenessUpdate(provider.awareness, [
829
+ provider.doc.clientID
830
+ ])
831
+ );
832
+ websocket.send(toUint8Array(encoderAwarenessState));
833
+ }
834
+ };
835
+ provider.emit('status', [{
836
+ status: 'connecting'
837
+ }]);
838
+ }
839
+ };
840
+
841
+ /**
842
+ * @param {WebsocketProvider} provider
843
+ * @param {ArrayBuffer} buf
844
+ */
845
+ const broadcastMessage = (provider, buf) => {
846
+ const ws = provider.ws;
847
+ if (provider.wsconnected && ws && ws.readyState === ws.OPEN) {
848
+ ws.send(buf);
849
+ }
850
+ if (provider.bcconnected) {
851
+ publish(provider.bcChannel, buf, provider);
852
+ }
853
+ };
854
+
855
+ /**
856
+ * Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.
857
+ * The document name is attached to the provided url. I.e. the following example
858
+ * creates a websocket connection to http://localhost:1234/my-document-name
859
+ *
860
+ * @example
861
+ * import * as Y from 'yjs'
862
+ * import { WebsocketProvider } from 'y-websocket'
863
+ * const doc = new Y.Doc()
864
+ * const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)
865
+ *
866
+ * @extends {ObservableV2<{ 'connection-close': (event: CloseEvent | null, provider: WebsocketProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: Event, provider: WebsocketProvider) => any, 'sync': (state: boolean) => any }>}
867
+ */
868
+ class WebsocketProvider extends ObservableV2 {
869
+ /**
870
+ * @param {string} serverUrl
871
+ * @param {string} roomname
872
+ * @param {Y.Doc} doc
873
+ * @param {object} opts
874
+ * @param {boolean} [opts.connect]
875
+ * @param {awarenessProtocol.Awareness} [opts.awareness]
876
+ * @param {Object<string,string>} [opts.params] specify url parameters
877
+ * @param {Array<string>} [opts.protocols] specify websocket protocols
878
+ * @param {typeof WebSocket} [opts.WebSocketPolyfill] Optionall provide a WebSocket polyfill
879
+ * @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds
880
+ * @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
881
+ * @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication
882
+ */
883
+ constructor (serverUrl, roomname, doc, {
884
+ connect = true,
885
+ awareness = new Awareness(doc),
886
+ params = {},
887
+ protocols = [],
888
+ WebSocketPolyfill = WebSocket,
889
+ resyncInterval = -1,
890
+ maxBackoffTime = 2500,
891
+ disableBc = false
892
+ } = {}) {
893
+ super();
894
+ // ensure that serverUrl does not end with /
895
+ while (serverUrl[serverUrl.length - 1] === '/') {
896
+ serverUrl = serverUrl.slice(0, serverUrl.length - 1);
897
+ }
898
+ this.serverUrl = serverUrl;
899
+ this.bcChannel = serverUrl + '/' + roomname;
900
+ this.maxBackoffTime = maxBackoffTime;
901
+ /**
902
+ * The specified url parameters. This can be safely updated. The changed parameters will be used
903
+ * when a new connection is established.
904
+ * @type {Object<string,string>}
905
+ */
906
+ this.params = params;
907
+ this.protocols = protocols;
908
+ this.roomname = roomname;
909
+ this.doc = doc;
910
+ this._WS = WebSocketPolyfill;
911
+ this.awareness = awareness;
912
+ this.wsconnected = false;
913
+ this.wsconnecting = false;
914
+ this.bcconnected = false;
915
+ this.disableBc = disableBc;
916
+ this.wsUnsuccessfulReconnects = 0;
917
+ this.messageHandlers = messageHandlers.slice();
918
+ /**
919
+ * @type {boolean}
920
+ */
921
+ this._synced = false;
922
+ /**
923
+ * @type {WebSocket?}
924
+ */
925
+ this.ws = null;
926
+ this.wsLastMessageReceived = 0;
927
+ /**
928
+ * Whether to connect to other peers or not
929
+ * @type {boolean}
930
+ */
931
+ this.shouldConnect = connect;
932
+
933
+ /**
934
+ * @type {number}
935
+ */
936
+ this._resyncInterval = 0;
937
+ if (resyncInterval > 0) {
938
+ this._resyncInterval = /** @type {any} */ (setInterval(() => {
939
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
940
+ // resend sync step 1
941
+ const encoder = createEncoder();
942
+ writeVarUint(encoder, messageSync);
943
+ writeSyncStep1(encoder, doc);
944
+ this.ws.send(toUint8Array(encoder));
945
+ }
946
+ }, resyncInterval));
947
+ }
948
+
949
+ /**
950
+ * @param {ArrayBuffer} data
951
+ * @param {any} origin
952
+ */
953
+ this._bcSubscriber = (data, origin) => {
954
+ if (origin !== this) {
955
+ const encoder = readMessage(this, new Uint8Array(data), false);
956
+ if (length(encoder) > 1) {
957
+ publish(this.bcChannel, toUint8Array(encoder), this);
958
+ }
959
+ }
960
+ };
961
+ /**
962
+ * Listens to Yjs updates and sends them to remote peers (ws and broadcastchannel)
963
+ * @param {Uint8Array} update
964
+ * @param {any} origin
965
+ */
966
+ this._updateHandler = (update, origin) => {
967
+ if (origin !== this) {
968
+ const encoder = createEncoder();
969
+ writeVarUint(encoder, messageSync);
970
+ writeUpdate(encoder, update);
971
+ broadcastMessage(this, toUint8Array(encoder));
972
+ }
973
+ };
974
+ this.doc.on('update', this._updateHandler);
975
+ /**
976
+ * @param {any} changed
977
+ * @param {any} _origin
978
+ */
979
+ this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {
980
+ const changedClients = added.concat(updated).concat(removed);
981
+ const encoder = createEncoder();
982
+ writeVarUint(encoder, messageAwareness);
983
+ writeVarUint8Array(
984
+ encoder,
985
+ encodeAwarenessUpdate(awareness, changedClients)
986
+ );
987
+ broadcastMessage(this, toUint8Array(encoder));
988
+ };
989
+ this._exitHandler = () => {
990
+ removeAwarenessStates(
991
+ this.awareness,
992
+ [doc.clientID],
993
+ 'app closed'
994
+ );
995
+ };
996
+ if (isNode && typeof process !== 'undefined') {
997
+ process.on('exit', this._exitHandler);
998
+ }
999
+ awareness.on('update', this._awarenessUpdateHandler);
1000
+ this._checkInterval = /** @type {any} */ (setInterval(() => {
1001
+ if (
1002
+ this.wsconnected &&
1003
+ messageReconnectTimeout <
1004
+ getUnixTime() - this.wsLastMessageReceived
1005
+ ) {
1006
+ // no message received in a long time - not even your own awareness
1007
+ // updates (which are updated every 15 seconds)
1008
+ closeWebsocketConnection(this, /** @type {WebSocket} */ (this.ws), null);
1009
+ }
1010
+ }, messageReconnectTimeout / 10));
1011
+ if (connect) {
1012
+ this.connect();
1013
+ }
1014
+ }
1015
+
1016
+ get url () {
1017
+ const encodedParams = encodeQueryParams(this.params);
1018
+ return this.serverUrl + '/' + this.roomname +
1019
+ (encodedParams.length === 0 ? '' : '?' + encodedParams)
1020
+ }
1021
+
1022
+ /**
1023
+ * @type {boolean}
1024
+ */
1025
+ get synced () {
1026
+ return this._synced
1027
+ }
1028
+
1029
+ set synced (state) {
1030
+ if (this._synced !== state) {
1031
+ this._synced = state;
1032
+ // @ts-ignore
1033
+ this.emit('synced', [state]);
1034
+ this.emit('sync', [state]);
1035
+ }
1036
+ }
1037
+
1038
+ destroy () {
1039
+ if (this._resyncInterval !== 0) {
1040
+ clearInterval(this._resyncInterval);
1041
+ }
1042
+ clearInterval(this._checkInterval);
1043
+ this.disconnect();
1044
+ if (isNode && typeof process !== 'undefined') {
1045
+ process.off('exit', this._exitHandler);
1046
+ }
1047
+ this.awareness.off('update', this._awarenessUpdateHandler);
1048
+ this.doc.off('update', this._updateHandler);
1049
+ super.destroy();
1050
+ }
1051
+
1052
+ connectBc () {
1053
+ if (this.disableBc) {
1054
+ return
1055
+ }
1056
+ if (!this.bcconnected) {
1057
+ subscribe(this.bcChannel, this._bcSubscriber);
1058
+ this.bcconnected = true;
1059
+ }
1060
+ // send sync step1 to bc
1061
+ // write sync step 1
1062
+ const encoderSync = createEncoder();
1063
+ writeVarUint(encoderSync, messageSync);
1064
+ writeSyncStep1(encoderSync, this.doc);
1065
+ publish(this.bcChannel, toUint8Array(encoderSync), this);
1066
+ // broadcast local state
1067
+ const encoderState = createEncoder();
1068
+ writeVarUint(encoderState, messageSync);
1069
+ writeSyncStep2(encoderState, this.doc);
1070
+ publish(this.bcChannel, toUint8Array(encoderState), this);
1071
+ // write queryAwareness
1072
+ const encoderAwarenessQuery = createEncoder();
1073
+ writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
1074
+ publish(
1075
+ this.bcChannel,
1076
+ toUint8Array(encoderAwarenessQuery),
1077
+ this
1078
+ );
1079
+ // broadcast local awareness state
1080
+ const encoderAwarenessState = createEncoder();
1081
+ writeVarUint(encoderAwarenessState, messageAwareness);
1082
+ writeVarUint8Array(
1083
+ encoderAwarenessState,
1084
+ encodeAwarenessUpdate(this.awareness, [
1085
+ this.doc.clientID
1086
+ ])
1087
+ );
1088
+ publish(
1089
+ this.bcChannel,
1090
+ toUint8Array(encoderAwarenessState),
1091
+ this
1092
+ );
1093
+ }
1094
+
1095
+ disconnectBc () {
1096
+ // broadcast message with local awareness state set to null (indicating disconnect)
1097
+ const encoder = createEncoder();
1098
+ writeVarUint(encoder, messageAwareness);
1099
+ writeVarUint8Array(
1100
+ encoder,
1101
+ encodeAwarenessUpdate(this.awareness, [
1102
+ this.doc.clientID
1103
+ ], new Map())
1104
+ );
1105
+ broadcastMessage(this, toUint8Array(encoder));
1106
+ if (this.bcconnected) {
1107
+ unsubscribe(this.bcChannel, this._bcSubscriber);
1108
+ this.bcconnected = false;
1109
+ }
1110
+ }
1111
+
1112
+ disconnect () {
1113
+ this.shouldConnect = false;
1114
+ this.disconnectBc();
1115
+ if (this.ws !== null) {
1116
+ closeWebsocketConnection(this, this.ws, null);
1117
+ }
1118
+ }
1119
+
1120
+ connect () {
1121
+ this.shouldConnect = true;
1122
+ if (!this.wsconnected && this.ws === null) {
1123
+ setupWS(this);
1124
+ this.connectBc();
1125
+ }
1126
+ }
1127
+ }
1128
+
1129
+ /**
1130
+ * WebSocket sync provider for real-time collaboration
1131
+ */
1132
+ class WebSocketSyncProvider {
1133
+ provider;
1134
+ isConnected = false;
1135
+ constructor(docName, doc, options) {
1136
+ const url = options?.url || 'ws://localhost:1234';
1137
+ const roomName = options?.roomName || docName;
1138
+ this.provider = new WebsocketProvider(url, roomName, doc, {
1139
+ params: options?.params,
1140
+ protocols: options?.protocols,
1141
+ WebSocketPolyfill: options?.WebSocketPolyfill,
1142
+ awareness: options?.awareness,
1143
+ maxBackoffTime: options?.maxBackoffTime,
1144
+ disableBc: true,
1145
+ });
1146
+ this.setupEventListeners();
1147
+ console.info(`WebSocket Provider initialized: ${url}/${roomName}`);
1148
+ }
1149
+ /**
1150
+ * Static factory method for creating WebSocketSyncProvider with configuration options
1151
+ * Returns a ProviderFactory that can be used in sync configuration
1152
+ */
1153
+ static with(options) {
1154
+ return {
1155
+ create: (docName, doc) => {
1156
+ return new WebSocketSyncProvider(docName, doc, options);
1157
+ },
1158
+ };
1159
+ }
1160
+ setupEventListeners() {
1161
+ this.provider.on('status', ({ status }) => {
1162
+ if (status === 'connected') {
1163
+ this.isConnected = true;
1164
+ console.info('WebSocket connected');
1165
+ }
1166
+ else if (status === 'disconnected') {
1167
+ this.isConnected = false;
1168
+ console.info('WebSocket disconnected');
1169
+ }
1170
+ });
1171
+ this.provider.on('sync', (synced) => {
1172
+ if (synced) {
1173
+ console.info('WebSocket synced');
1174
+ }
1175
+ });
1176
+ }
1177
+ async connect() {
1178
+ if (this.isConnected) {
1179
+ return;
1180
+ }
1181
+ return new Promise((resolve, reject) => {
1182
+ const timeout = setTimeout(() => {
1183
+ reject(new Error('WebSocket connection timeout'));
1184
+ }, 10000); // 10 second timeout
1185
+ const statusHandler = ({ status }) => {
1186
+ if (status === 'connected') {
1187
+ clearTimeout(timeout);
1188
+ this.provider.off('status', statusHandler);
1189
+ this.isConnected = true;
1190
+ resolve();
1191
+ }
1192
+ };
1193
+ this.provider.on('status', statusHandler);
1194
+ // If already connected, resolve immediately
1195
+ if (this.provider.wsconnected) {
1196
+ clearTimeout(timeout);
1197
+ this.provider.off('status', statusHandler);
1198
+ this.isConnected = true;
1199
+ resolve();
1200
+ }
1201
+ });
1202
+ }
1203
+ disconnect() {
1204
+ if (this.provider) {
1205
+ this.provider.disconnect();
1206
+ }
1207
+ this.isConnected = false;
1208
+ }
1209
+ destroy() {
1210
+ if (this.provider) {
1211
+ this.provider.destroy();
1212
+ }
1213
+ this.isConnected = false;
1214
+ }
1215
+ }
1216
+
1217
+ /**
1218
+ * Hocuspocus sync provider for real-time collaboration
1219
+ * Supports multiplexing - multiple documents can share the same WebSocket connection
1220
+ */
1221
+ class HocuspocusSyncProvider {
1222
+ provider;
1223
+ isConnected = false;
1224
+ isSynced = false;
1225
+ usesSharedSocket = false;
1226
+ // Static shared WebSocket instance for multiplexing
1227
+ static sharedWebSocketProvider = null;
1228
+ constructor(docName, doc, options) {
1229
+ const name = options?.name || docName;
1230
+ const url = options?.url || 'ws://localhost:1234';
1231
+ // Use provided websocketProvider or the static shared one
1232
+ const websocketProvider = options?.websocketProvider || HocuspocusSyncProvider.sharedWebSocketProvider;
1233
+ if (websocketProvider) {
1234
+ // Multiplexing mode - use shared WebSocket connection
1235
+ this.usesSharedSocket = true;
1236
+ const config = {
1237
+ websocketProvider,
1238
+ name,
1239
+ document: doc,
1240
+ token: options?.token || null,
1241
+ onConnect: () => {
1242
+ this.isConnected = true;
1243
+ if (!options?.quiet) {
1244
+ console.info(`Hocuspocus connected: ${name}`);
1245
+ }
1246
+ if (options?.onConnect) {
1247
+ options.onConnect();
1248
+ }
1249
+ },
1250
+ onDisconnect: () => {
1251
+ this.isConnected = false;
1252
+ this.isSynced = false;
1253
+ if (!options?.quiet) {
1254
+ console.info(`Hocuspocus disconnected: ${name}`);
1255
+ }
1256
+ if (options?.onDisconnect) {
1257
+ options.onDisconnect();
1258
+ }
1259
+ },
1260
+ onSynced: () => {
1261
+ this.isSynced = true;
1262
+ if (!options?.quiet) {
1263
+ console.info(`Hocuspocus synced: ${name}`);
1264
+ }
1265
+ if (options?.onSynced) {
1266
+ options.onSynced();
1267
+ }
1268
+ },
1269
+ };
1270
+ // Add optional settings
1271
+ if (options?.forceSyncInterval !== undefined) {
1272
+ config.forceSyncInterval = options.forceSyncInterval;
1273
+ }
1274
+ if (options?.onAuthenticationFailed) {
1275
+ config.onAuthenticationFailed = options.onAuthenticationFailed;
1276
+ }
1277
+ if (options?.onStatus) {
1278
+ config.onStatus = options.onStatus;
1279
+ }
1280
+ this.provider = new HocuspocusProvider(config);
1281
+ // Must call attach() explicitly when using shared socket
1282
+ this.provider.attach();
1283
+ if (!options?.quiet) {
1284
+ console.info(`Hocuspocus Provider initialized (multiplexed): ${name}`);
1285
+ }
1286
+ }
1287
+ else {
1288
+ // Standalone mode - create own WebSocket connection
1289
+ this.usesSharedSocket = false;
1290
+ const config = {
1291
+ url,
1292
+ name,
1293
+ document: doc,
1294
+ token: options?.token || null,
1295
+ onConnect: () => {
1296
+ this.isConnected = true;
1297
+ if (!options?.quiet) {
1298
+ console.info(`Hocuspocus connected: ${name}`);
1299
+ }
1300
+ if (options?.onConnect) {
1301
+ options.onConnect();
1302
+ }
1303
+ },
1304
+ onDisconnect: () => {
1305
+ this.isConnected = false;
1306
+ this.isSynced = false;
1307
+ if (!options?.quiet) {
1308
+ console.info(`Hocuspocus disconnected: ${name}`);
1309
+ }
1310
+ if (options?.onDisconnect) {
1311
+ options.onDisconnect();
1312
+ }
1313
+ },
1314
+ onSynced: () => {
1315
+ this.isSynced = true;
1316
+ if (!options?.quiet) {
1317
+ console.info(`Hocuspocus synced: ${name}`);
1318
+ }
1319
+ if (options?.onSynced) {
1320
+ options.onSynced();
1321
+ }
1322
+ },
1323
+ };
1324
+ // Add optional settings
1325
+ if (options?.forceSyncInterval !== undefined) {
1326
+ config.forceSyncInterval = options.forceSyncInterval;
1327
+ }
1328
+ if (options?.onAuthenticationFailed) {
1329
+ config.onAuthenticationFailed = options.onAuthenticationFailed;
1330
+ }
1331
+ if (options?.onStatus) {
1332
+ config.onStatus = options.onStatus;
1333
+ }
1334
+ if (options?.WebSocketPolyfill) {
1335
+ config.WebSocketPolyfill = options.WebSocketPolyfill;
1336
+ }
1337
+ this.provider = new HocuspocusProvider(config);
1338
+ if (!options?.quiet) {
1339
+ console.info(`Hocuspocus Provider initialized: ${url}/${name}`);
1340
+ }
1341
+ }
1342
+ }
1343
+ /**
1344
+ * Create a shared WebSocket connection for multiplexing
1345
+ * Call this once to create a shared connection that multiple providers can use
1346
+ */
1347
+ static createSharedWebSocket(options) {
1348
+ if (HocuspocusSyncProvider.sharedWebSocketProvider) {
1349
+ console.warn('Shared WebSocket already exists. Returning existing instance.');
1350
+ return HocuspocusSyncProvider.sharedWebSocketProvider;
1351
+ }
1352
+ const config = {
1353
+ url: options.url,
1354
+ };
1355
+ if (options.WebSocketPolyfill) {
1356
+ config.WebSocketPolyfill = options.WebSocketPolyfill;
1357
+ }
1358
+ if (options.onConnect) {
1359
+ config.onConnect = options.onConnect;
1360
+ }
1361
+ if (options.onDisconnect) {
1362
+ config.onDisconnect = options.onDisconnect;
1363
+ }
1364
+ if (options.onStatus) {
1365
+ config.onStatus = options.onStatus;
1366
+ }
1367
+ HocuspocusSyncProvider.sharedWebSocketProvider = new HocuspocusProviderWebsocket(config);
1368
+ console.info(`Shared Hocuspocus WebSocket created: ${options.url}`);
1369
+ return HocuspocusSyncProvider.sharedWebSocketProvider;
1370
+ }
1371
+ /**
1372
+ * Destroy the shared WebSocket connection
1373
+ * Call this when you're done with all multiplexed providers
1374
+ */
1375
+ static destroySharedWebSocket() {
1376
+ if (HocuspocusSyncProvider.sharedWebSocketProvider) {
1377
+ HocuspocusSyncProvider.sharedWebSocketProvider.destroy();
1378
+ HocuspocusSyncProvider.sharedWebSocketProvider = null;
1379
+ console.info('Shared Hocuspocus WebSocket destroyed');
1380
+ }
1381
+ }
1382
+ /**
1383
+ * Get the shared WebSocket provider instance (if it exists)
1384
+ */
1385
+ static getSharedWebSocket() {
1386
+ return HocuspocusSyncProvider.sharedWebSocketProvider;
1387
+ }
1388
+ /**
1389
+ * Static factory method for creating HocuspocusSyncProvider with configuration options
1390
+ * Returns a ProviderFactory that can be used in sync configuration
1391
+ */
1392
+ static with(options) {
1393
+ return {
1394
+ create: (docName, doc) => {
1395
+ return new HocuspocusSyncProvider(docName, doc, options);
1396
+ },
1397
+ };
1398
+ }
1399
+ async connect() {
1400
+ if (this.isSynced) {
1401
+ return;
1402
+ }
1403
+ return new Promise((resolve, reject) => {
1404
+ const timeout = setTimeout(() => {
1405
+ reject(new Error('Hocuspocus connection timeout'));
1406
+ }, 10000); // 10 second timeout
1407
+ const syncHandler = () => {
1408
+ clearTimeout(timeout);
1409
+ this.provider.off('synced', syncHandler);
1410
+ resolve();
1411
+ };
1412
+ this.provider.on('synced', syncHandler);
1413
+ // If already synced, resolve immediately
1414
+ if (this.provider.isSynced) {
1415
+ clearTimeout(timeout);
1416
+ this.provider.off('synced', syncHandler);
1417
+ resolve();
1418
+ return;
1419
+ }
1420
+ // Connect if not already connected (standalone mode only)
1421
+ if (!this.isConnected && !this.usesSharedSocket) {
1422
+ this.provider.connect();
1423
+ }
1424
+ });
1425
+ }
1426
+ disconnect() {
1427
+ if (this.provider) {
1428
+ if (this.usesSharedSocket) {
1429
+ // Detach from shared socket instead of disconnecting
1430
+ this.provider.detach();
1431
+ }
1432
+ else {
1433
+ this.provider.disconnect();
1434
+ }
1435
+ }
1436
+ this.isConnected = false;
1437
+ this.isSynced = false;
1438
+ }
1439
+ destroy() {
1440
+ if (this.provider) {
1441
+ this.provider.destroy();
1442
+ }
1443
+ this.isConnected = false;
1444
+ this.isSynced = false;
1445
+ }
1446
+ }
1447
+
1448
+ export { BroadcastSyncProvider, HocuspocusSyncProvider, WebSocketSyncProvider };
1449
+ //# sourceMappingURL=index.js.map