kritzel-stencil 0.0.144 → 0.0.145

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