@nebutra/collab 0.2.2 → 0.2.4

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 (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +0 -0
  3. package/dist/{chunk-S2HTNEZN.js → chunk-PMIKORQM.js} +1 -1
  4. package/dist/chunk-PMIKORQM.js.map +1 -0
  5. package/dist/index.d.ts +0 -0
  6. package/dist/index.js +3 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/transport/loopback.d.ts +0 -0
  9. package/dist/transport/loopback.js +1 -1
  10. package/package.json +18 -8
  11. package/.turbo/turbo-build.log +0 -28
  12. package/.turbo/turbo-test.log +0 -14
  13. package/.turbo/turbo-typecheck.log +0 -4
  14. package/coverage/base.css +0 -224
  15. package/coverage/block-navigation.js +0 -87
  16. package/coverage/clover.xml +0 -156
  17. package/coverage/coverage-final.json +0 -7
  18. package/coverage/favicon.png +0 -0
  19. package/coverage/index.html +0 -146
  20. package/coverage/prettify.css +0 -1
  21. package/coverage/prettify.js +0 -2
  22. package/coverage/sort-arrow-sprite.png +0 -0
  23. package/coverage/sorter.js +0 -210
  24. package/coverage/src/errors.ts.html +0 -211
  25. package/coverage/src/hub.ts.html +0 -619
  26. package/coverage/src/index.html +0 -161
  27. package/coverage/src/index.ts.html +0 -211
  28. package/coverage/src/room.ts.html +0 -529
  29. package/coverage/src/store/index.html +0 -116
  30. package/coverage/src/store/memory.ts.html +0 -235
  31. package/coverage/src/transport/index.html +0 -116
  32. package/coverage/src/transport/loopback.ts.html +0 -0
  33. package/dist/chunk-S2HTNEZN.js.map +0 -1
  34. package/examples/snapshot-restore.ts +0 -39
  35. package/examples/tenant-isolation.ts +0 -42
  36. package/examples/zero-config-convergence.ts +0 -43
  37. package/src/__tests__/collab.test.ts +0 -240
  38. package/src/cli.ts +0 -27
  39. package/src/errors.ts +0 -42
  40. package/src/hub.ts +0 -0
  41. package/src/index.ts +0 -42
  42. package/src/room.ts +0 -130
  43. package/src/store/memory.ts +0 -43
  44. package/src/transport/loopback.ts +0 -0
  45. package/src/types.ts +0 -64
  46. package/tsconfig.json +0 -12
  47. package/tsup.config.ts +0 -11
@@ -1,529 +0,0 @@
1
-
2
- <!doctype html>
3
- <html lang="en">
4
-
5
- <head>
6
- <title>Code coverage report for src/room.ts</title>
7
- <meta charset="utf-8" />
8
- <link rel="stylesheet" href="../prettify.css" />
9
- <link rel="stylesheet" href="../base.css" />
10
- <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
- <meta name="viewport" content="width=device-width, initial-scale=1" />
12
- <style type='text/css'>
13
- .coverage-summary .sorter {
14
- background-image: url(../sort-arrow-sprite.png);
15
- }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <div class='wrapper'>
21
- <div class='pad1'>
22
- <h1><a href="../index.html">All files</a> / <a href="index.html">src</a> room.ts</h1>
23
- <div class='clearfix'>
24
-
25
- <div class='fl pad1y space-right2'>
26
- <span class="strong">95.45% </span>
27
- <span class="quiet">Statements</span>
28
- <span class='fraction'>42/44</span>
29
- </div>
30
-
31
-
32
- <div class='fl pad1y space-right2'>
33
- <span class="strong">70% </span>
34
- <span class="quiet">Branches</span>
35
- <span class='fraction'>7/10</span>
36
- </div>
37
-
38
-
39
- <div class='fl pad1y space-right2'>
40
- <span class="strong">92.3% </span>
41
- <span class="quiet">Functions</span>
42
- <span class='fraction'>12/13</span>
43
- </div>
44
-
45
-
46
- <div class='fl pad1y space-right2'>
47
- <span class="strong">100% </span>
48
- <span class="quiet">Lines</span>
49
- <span class='fraction'>40/40</span>
50
- </div>
51
-
52
-
53
- </div>
54
- <p class="quiet">
55
- Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
- </p>
57
- <template id="filterTemplate">
58
- <div class="quiet">
59
- Filter:
60
- <input type="search" id="fileSearch">
61
- </div>
62
- </template>
63
- </div>
64
- <div class='status-line high'></div>
65
- <pre><table class="coverage">
66
- <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
- <a name='L2'></a><a href='#L2'>2</a>
68
- <a name='L3'></a><a href='#L3'>3</a>
69
- <a name='L4'></a><a href='#L4'>4</a>
70
- <a name='L5'></a><a href='#L5'>5</a>
71
- <a name='L6'></a><a href='#L6'>6</a>
72
- <a name='L7'></a><a href='#L7'>7</a>
73
- <a name='L8'></a><a href='#L8'>8</a>
74
- <a name='L9'></a><a href='#L9'>9</a>
75
- <a name='L10'></a><a href='#L10'>10</a>
76
- <a name='L11'></a><a href='#L11'>11</a>
77
- <a name='L12'></a><a href='#L12'>12</a>
78
- <a name='L13'></a><a href='#L13'>13</a>
79
- <a name='L14'></a><a href='#L14'>14</a>
80
- <a name='L15'></a><a href='#L15'>15</a>
81
- <a name='L16'></a><a href='#L16'>16</a>
82
- <a name='L17'></a><a href='#L17'>17</a>
83
- <a name='L18'></a><a href='#L18'>18</a>
84
- <a name='L19'></a><a href='#L19'>19</a>
85
- <a name='L20'></a><a href='#L20'>20</a>
86
- <a name='L21'></a><a href='#L21'>21</a>
87
- <a name='L22'></a><a href='#L22'>22</a>
88
- <a name='L23'></a><a href='#L23'>23</a>
89
- <a name='L24'></a><a href='#L24'>24</a>
90
- <a name='L25'></a><a href='#L25'>25</a>
91
- <a name='L26'></a><a href='#L26'>26</a>
92
- <a name='L27'></a><a href='#L27'>27</a>
93
- <a name='L28'></a><a href='#L28'>28</a>
94
- <a name='L29'></a><a href='#L29'>29</a>
95
- <a name='L30'></a><a href='#L30'>30</a>
96
- <a name='L31'></a><a href='#L31'>31</a>
97
- <a name='L32'></a><a href='#L32'>32</a>
98
- <a name='L33'></a><a href='#L33'>33</a>
99
- <a name='L34'></a><a href='#L34'>34</a>
100
- <a name='L35'></a><a href='#L35'>35</a>
101
- <a name='L36'></a><a href='#L36'>36</a>
102
- <a name='L37'></a><a href='#L37'>37</a>
103
- <a name='L38'></a><a href='#L38'>38</a>
104
- <a name='L39'></a><a href='#L39'>39</a>
105
- <a name='L40'></a><a href='#L40'>40</a>
106
- <a name='L41'></a><a href='#L41'>41</a>
107
- <a name='L42'></a><a href='#L42'>42</a>
108
- <a name='L43'></a><a href='#L43'>43</a>
109
- <a name='L44'></a><a href='#L44'>44</a>
110
- <a name='L45'></a><a href='#L45'>45</a>
111
- <a name='L46'></a><a href='#L46'>46</a>
112
- <a name='L47'></a><a href='#L47'>47</a>
113
- <a name='L48'></a><a href='#L48'>48</a>
114
- <a name='L49'></a><a href='#L49'>49</a>
115
- <a name='L50'></a><a href='#L50'>50</a>
116
- <a name='L51'></a><a href='#L51'>51</a>
117
- <a name='L52'></a><a href='#L52'>52</a>
118
- <a name='L53'></a><a href='#L53'>53</a>
119
- <a name='L54'></a><a href='#L54'>54</a>
120
- <a name='L55'></a><a href='#L55'>55</a>
121
- <a name='L56'></a><a href='#L56'>56</a>
122
- <a name='L57'></a><a href='#L57'>57</a>
123
- <a name='L58'></a><a href='#L58'>58</a>
124
- <a name='L59'></a><a href='#L59'>59</a>
125
- <a name='L60'></a><a href='#L60'>60</a>
126
- <a name='L61'></a><a href='#L61'>61</a>
127
- <a name='L62'></a><a href='#L62'>62</a>
128
- <a name='L63'></a><a href='#L63'>63</a>
129
- <a name='L64'></a><a href='#L64'>64</a>
130
- <a name='L65'></a><a href='#L65'>65</a>
131
- <a name='L66'></a><a href='#L66'>66</a>
132
- <a name='L67'></a><a href='#L67'>67</a>
133
- <a name='L68'></a><a href='#L68'>68</a>
134
- <a name='L69'></a><a href='#L69'>69</a>
135
- <a name='L70'></a><a href='#L70'>70</a>
136
- <a name='L71'></a><a href='#L71'>71</a>
137
- <a name='L72'></a><a href='#L72'>72</a>
138
- <a name='L73'></a><a href='#L73'>73</a>
139
- <a name='L74'></a><a href='#L74'>74</a>
140
- <a name='L75'></a><a href='#L75'>75</a>
141
- <a name='L76'></a><a href='#L76'>76</a>
142
- <a name='L77'></a><a href='#L77'>77</a>
143
- <a name='L78'></a><a href='#L78'>78</a>
144
- <a name='L79'></a><a href='#L79'>79</a>
145
- <a name='L80'></a><a href='#L80'>80</a>
146
- <a name='L81'></a><a href='#L81'>81</a>
147
- <a name='L82'></a><a href='#L82'>82</a>
148
- <a name='L83'></a><a href='#L83'>83</a>
149
- <a name='L84'></a><a href='#L84'>84</a>
150
- <a name='L85'></a><a href='#L85'>85</a>
151
- <a name='L86'></a><a href='#L86'>86</a>
152
- <a name='L87'></a><a href='#L87'>87</a>
153
- <a name='L88'></a><a href='#L88'>88</a>
154
- <a name='L89'></a><a href='#L89'>89</a>
155
- <a name='L90'></a><a href='#L90'>90</a>
156
- <a name='L91'></a><a href='#L91'>91</a>
157
- <a name='L92'></a><a href='#L92'>92</a>
158
- <a name='L93'></a><a href='#L93'>93</a>
159
- <a name='L94'></a><a href='#L94'>94</a>
160
- <a name='L95'></a><a href='#L95'>95</a>
161
- <a name='L96'></a><a href='#L96'>96</a>
162
- <a name='L97'></a><a href='#L97'>97</a>
163
- <a name='L98'></a><a href='#L98'>98</a>
164
- <a name='L99'></a><a href='#L99'>99</a>
165
- <a name='L100'></a><a href='#L100'>100</a>
166
- <a name='L101'></a><a href='#L101'>101</a>
167
- <a name='L102'></a><a href='#L102'>102</a>
168
- <a name='L103'></a><a href='#L103'>103</a>
169
- <a name='L104'></a><a href='#L104'>104</a>
170
- <a name='L105'></a><a href='#L105'>105</a>
171
- <a name='L106'></a><a href='#L106'>106</a>
172
- <a name='L107'></a><a href='#L107'>107</a>
173
- <a name='L108'></a><a href='#L108'>108</a>
174
- <a name='L109'></a><a href='#L109'>109</a>
175
- <a name='L110'></a><a href='#L110'>110</a>
176
- <a name='L111'></a><a href='#L111'>111</a>
177
- <a name='L112'></a><a href='#L112'>112</a>
178
- <a name='L113'></a><a href='#L113'>113</a>
179
- <a name='L114'></a><a href='#L114'>114</a>
180
- <a name='L115'></a><a href='#L115'>115</a>
181
- <a name='L116'></a><a href='#L116'>116</a>
182
- <a name='L117'></a><a href='#L117'>117</a>
183
- <a name='L118'></a><a href='#L118'>118</a>
184
- <a name='L119'></a><a href='#L119'>119</a>
185
- <a name='L120'></a><a href='#L120'>120</a>
186
- <a name='L121'></a><a href='#L121'>121</a>
187
- <a name='L122'></a><a href='#L122'>122</a>
188
- <a name='L123'></a><a href='#L123'>123</a>
189
- <a name='L124'></a><a href='#L124'>124</a>
190
- <a name='L125'></a><a href='#L125'>125</a>
191
- <a name='L126'></a><a href='#L126'>126</a>
192
- <a name='L127'></a><a href='#L127'>127</a>
193
- <a name='L128'></a><a href='#L128'>128</a>
194
- <a name='L129'></a><a href='#L129'>129</a>
195
- <a name='L130'></a><a href='#L130'>130</a>
196
- <a name='L131'></a><a href='#L131'>131</a>
197
- <a name='L132'></a><a href='#L132'>132</a>
198
- <a name='L133'></a><a href='#L133'>133</a>
199
- <a name='L134'></a><a href='#L134'>134</a>
200
- <a name='L135'></a><a href='#L135'>135</a>
201
- <a name='L136'></a><a href='#L136'>136</a>
202
- <a name='L137'></a><a href='#L137'>137</a>
203
- <a name='L138'></a><a href='#L138'>138</a>
204
- <a name='L139'></a><a href='#L139'>139</a>
205
- <a name='L140'></a><a href='#L140'>140</a>
206
- <a name='L141'></a><a href='#L141'>141</a>
207
- <a name='L142'></a><a href='#L142'>142</a>
208
- <a name='L143'></a><a href='#L143'>143</a>
209
- <a name='L144'></a><a href='#L144'>144</a>
210
- <a name='L145'></a><a href='#L145'>145</a>
211
- <a name='L146'></a><a href='#L146'>146</a>
212
- <a name='L147'></a><a href='#L147'>147</a>
213
- <a name='L148'></a><a href='#L148'>148</a>
214
- <a name='L149'></a><a href='#L149'>149</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
215
- <span class="cline-any cline-neutral">&nbsp;</span>
216
- <span class="cline-any cline-neutral">&nbsp;</span>
217
- <span class="cline-any cline-neutral">&nbsp;</span>
218
- <span class="cline-any cline-neutral">&nbsp;</span>
219
- <span class="cline-any cline-neutral">&nbsp;</span>
220
- <span class="cline-any cline-neutral">&nbsp;</span>
221
- <span class="cline-any cline-neutral">&nbsp;</span>
222
- <span class="cline-any cline-neutral">&nbsp;</span>
223
- <span class="cline-any cline-neutral">&nbsp;</span>
224
- <span class="cline-any cline-neutral">&nbsp;</span>
225
- <span class="cline-any cline-neutral">&nbsp;</span>
226
- <span class="cline-any cline-neutral">&nbsp;</span>
227
- <span class="cline-any cline-neutral">&nbsp;</span>
228
- <span class="cline-any cline-neutral">&nbsp;</span>
229
- <span class="cline-any cline-neutral">&nbsp;</span>
230
- <span class="cline-any cline-neutral">&nbsp;</span>
231
- <span class="cline-any cline-neutral">&nbsp;</span>
232
- <span class="cline-any cline-neutral">&nbsp;</span>
233
- <span class="cline-any cline-neutral">&nbsp;</span>
234
- <span class="cline-any cline-neutral">&nbsp;</span>
235
- <span class="cline-any cline-neutral">&nbsp;</span>
236
- <span class="cline-any cline-yes">1x</span>
237
- <span class="cline-any cline-neutral">&nbsp;</span>
238
- <span class="cline-any cline-neutral">&nbsp;</span>
239
- <span class="cline-any cline-neutral">&nbsp;</span>
240
- <span class="cline-any cline-yes">16x</span>
241
- <span class="cline-any cline-neutral">&nbsp;</span>
242
- <span class="cline-any cline-yes">16x</span>
243
- <span class="cline-any cline-neutral">&nbsp;</span>
244
- <span class="cline-any cline-neutral">&nbsp;</span>
245
- <span class="cline-any cline-yes">16x</span>
246
- <span class="cline-any cline-yes">16x</span>
247
- <span class="cline-any cline-yes">16x</span>
248
- <span class="cline-any cline-yes">16x</span>
249
- <span class="cline-any cline-neutral">&nbsp;</span>
250
- <span class="cline-any cline-yes">16x</span>
251
- <span class="cline-any cline-neutral">&nbsp;</span>
252
- <span class="cline-any cline-neutral">&nbsp;</span>
253
- <span class="cline-any cline-neutral">&nbsp;</span>
254
- <span class="cline-any cline-neutral">&nbsp;</span>
255
- <span class="cline-any cline-yes">16x</span>
256
- <span class="cline-any cline-yes">14x</span>
257
- <span class="cline-any cline-yes">14x</span>
258
- <span class="cline-any cline-yes">11x</span>
259
- <span class="cline-any cline-neutral">&nbsp;</span>
260
- <span class="cline-any cline-neutral">&nbsp;</span>
261
- <span class="cline-any cline-neutral">&nbsp;</span>
262
- <span class="cline-any cline-neutral">&nbsp;</span>
263
- <span class="cline-any cline-neutral">&nbsp;</span>
264
- <span class="cline-any cline-neutral">&nbsp;</span>
265
- <span class="cline-any cline-neutral">&nbsp;</span>
266
- <span class="cline-any cline-neutral">&nbsp;</span>
267
- <span class="cline-any cline-neutral">&nbsp;</span>
268
- <span class="cline-any cline-neutral">&nbsp;</span>
269
- <span class="cline-any cline-yes">16x</span>
270
- <span class="cline-any cline-neutral">&nbsp;</span>
271
- <span class="cline-any cline-neutral">&nbsp;</span>
272
- <span class="cline-any cline-neutral">&nbsp;</span>
273
- <span class="cline-any cline-yes">13x</span>
274
- <span class="cline-any cline-yes">13x</span>
275
- <span class="cline-any cline-neutral">&nbsp;</span>
276
- <span class="cline-any cline-neutral">&nbsp;</span>
277
- <span class="cline-any cline-neutral">&nbsp;</span>
278
- <span class="cline-any cline-neutral">&nbsp;</span>
279
- <span class="cline-any cline-neutral">&nbsp;</span>
280
- <span class="cline-any cline-yes">2x</span>
281
- <span class="cline-any cline-yes">2x</span>
282
- <span class="cline-any cline-neutral">&nbsp;</span>
283
- <span class="cline-any cline-neutral">&nbsp;</span>
284
- <span class="cline-any cline-neutral">&nbsp;</span>
285
- <span class="cline-any cline-yes">6x</span>
286
- <span class="cline-any cline-yes">6x</span>
287
- <span class="cline-any cline-neutral">&nbsp;</span>
288
- <span class="cline-any cline-neutral">&nbsp;</span>
289
- <span class="cline-any cline-neutral">&nbsp;</span>
290
- <span class="cline-any cline-yes">2x</span>
291
- <span class="cline-any cline-yes">2x</span>
292
- <span class="cline-any cline-yes">2x</span>
293
- <span class="cline-any cline-yes">1x</span>
294
- <span class="cline-any cline-neutral">&nbsp;</span>
295
- <span class="cline-any cline-neutral">&nbsp;</span>
296
- <span class="cline-any cline-neutral">&nbsp;</span>
297
- <span class="cline-any cline-neutral">&nbsp;</span>
298
- <span class="cline-any cline-yes">3x</span>
299
- <span class="cline-any cline-yes">3x</span>
300
- <span class="cline-any cline-yes">3x</span>
301
- <span class="cline-any cline-neutral">&nbsp;</span>
302
- <span class="cline-any cline-neutral">&nbsp;</span>
303
- <span class="cline-any cline-yes">3x</span>
304
- <span class="cline-any cline-yes">3x</span>
305
- <span class="cline-any cline-neutral">&nbsp;</span>
306
- <span class="cline-any cline-neutral">&nbsp;</span>
307
- <span class="cline-any cline-yes">1x</span>
308
- <span class="cline-any cline-neutral">&nbsp;</span>
309
- <span class="cline-any cline-neutral">&nbsp;</span>
310
- <span class="cline-any cline-neutral">&nbsp;</span>
311
- <span class="cline-any cline-neutral">&nbsp;</span>
312
- <span class="cline-any cline-neutral">&nbsp;</span>
313
- <span class="cline-any cline-neutral">&nbsp;</span>
314
- <span class="cline-any cline-neutral">&nbsp;</span>
315
- <span class="cline-any cline-neutral">&nbsp;</span>
316
- <span class="cline-any cline-neutral">&nbsp;</span>
317
- <span class="cline-any cline-neutral">&nbsp;</span>
318
- <span class="cline-any cline-neutral">&nbsp;</span>
319
- <span class="cline-any cline-neutral">&nbsp;</span>
320
- <span class="cline-any cline-neutral">&nbsp;</span>
321
- <span class="cline-any cline-neutral">&nbsp;</span>
322
- <span class="cline-any cline-neutral">&nbsp;</span>
323
- <span class="cline-any cline-yes">2x</span>
324
- <span class="cline-any cline-yes">2x</span>
325
- <span class="cline-any cline-yes">1x</span>
326
- <span class="cline-any cline-neutral">&nbsp;</span>
327
- <span class="cline-any cline-yes">1x</span>
328
- <span class="cline-any cline-neutral">&nbsp;</span>
329
- <span class="cline-any cline-neutral">&nbsp;</span>
330
- <span class="cline-any cline-neutral">&nbsp;</span>
331
- <span class="cline-any cline-neutral">&nbsp;</span>
332
- <span class="cline-any cline-neutral">&nbsp;</span>
333
- <span class="cline-any cline-neutral">&nbsp;</span>
334
- <span class="cline-any cline-neutral">&nbsp;</span>
335
- <span class="cline-any cline-neutral">&nbsp;</span>
336
- <span class="cline-any cline-neutral">&nbsp;</span>
337
- <span class="cline-any cline-neutral">&nbsp;</span>
338
- <span class="cline-any cline-neutral">&nbsp;</span>
339
- <span class="cline-any cline-neutral">&nbsp;</span>
340
- <span class="cline-any cline-neutral">&nbsp;</span>
341
- <span class="cline-any cline-yes">3x</span>
342
- <span class="cline-any cline-yes">3x</span>
343
- <span class="cline-any cline-yes">3x</span>
344
- <span class="cline-any cline-yes">3x</span>
345
- <span class="cline-any cline-yes">3x</span>
346
- <span class="cline-any cline-neutral">&nbsp;</span>
347
- <span class="cline-any cline-neutral">&nbsp;</span>
348
- <span class="cline-any cline-neutral">&nbsp;</span>
349
- <span class="cline-any cline-yes">13x</span>
350
- <span class="cline-any cline-yes">1x</span>
351
- <span class="cline-any cline-neutral">&nbsp;</span>
352
- <span class="cline-any cline-neutral">&nbsp;</span>
353
- <span class="cline-any cline-neutral">&nbsp;</span>
354
- <span class="cline-any cline-neutral">&nbsp;</span>
355
- <span class="cline-any cline-neutral">&nbsp;</span>
356
- <span class="cline-any cline-neutral">&nbsp;</span>
357
- <span class="cline-any cline-neutral">&nbsp;</span>
358
- <span class="cline-any cline-neutral">&nbsp;</span>
359
- <span class="cline-any cline-neutral">&nbsp;</span>
360
- <span class="cline-any cline-neutral">&nbsp;</span>
361
- <span class="cline-any cline-neutral">&nbsp;</span>
362
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">/**
363
- * A single tenant-scoped CRDT room. One `Y.Doc` per (tenant, room). The hub
364
- * owns the partitioning; this class assumes its `tenantId`/`roomId` are
365
- * already the partition it belongs to and never reaches outside them.
366
- *
367
- * Snapshot persistence is serialized through `withTenantLock(tenantId,
368
- * roomId, ...)` borrowed from `@nebutra/tenant-store` rather than a
369
- * hand-rolled mutex — same primitive used by canvas/reel, so a future swap
370
- * to a distributed lock changes one place.
371
- */
372
- &nbsp;
373
- import { withTenantLock } from "@nebutra/tenant-store";
374
- import * as Y from "yjs";
375
- import { CollabError } from "./errors";
376
- import type {
377
- CollabRoom,
378
- CollabTransport,
379
- SnapshotStore,
380
- UpdateListener,
381
- } from "./types";
382
- &nbsp;
383
- /** Origin tag used when applying remote updates so we don't echo them back. */
384
- const REMOTE_ORIGIN = Symbol("collab.remote");
385
- &nbsp;
386
- export class Room implements CollabRoom {
387
- readonly doc: Y.Doc;
388
- private readonly listeners = new Set&lt;UpdateListener&gt;();
389
- private readonly unsubTransport: () =&gt; void;
390
- private destroyed = false;
391
- &nbsp;
392
- constructor(
393
- readonly tenantId: string,
394
- readonly roomId: string,
395
- private readonly store: SnapshotStore,
396
- private readonly transport: CollabTransport,
397
- ) {
398
- this.doc = new Y.Doc();
399
- &nbsp;
400
- // Fan local updates out to: registered listeners + the transport. The
401
- // transport echo is guarded by origin so a remote-applied update is not
402
- // re-broadcast into a loop.
403
- this.doc.on("update", (update: Uint8Array, origin: unknown) =&gt; {
404
- for (const cb of [...this.listeners]) cb(update, origin);
405
- if (origin !== REMOTE_ORIGIN) {
406
- void Promise.resolve(
407
- this.transport.broadcast(this.tenantId, this.roomId, update),
408
- ).catch(<span class="fstat-no" title="function not covered" >() =&gt; {</span>
409
- // Transport delivery is best-effort; CRDT state stays correct and
410
- // converges on the next exchanged update. Swallowing here avoids
411
- // an unhandled rejection from a flaky network adapter.
412
- });
413
- }
414
- });
415
- &nbsp;
416
- // Remote updates for THIS tenant-scoped channel only.
417
- this.unsubTransport = this.transport.subscribe(
418
- this.tenantId,
419
- this.roomId,
420
- (update) =&gt; {
421
- <span class="missing-if-branch" title="if path not taken" >I</span>if (this.destroyed) <span class="cstat-no" title="statement not covered" >return;</span>
422
- Y.applyUpdate(this.doc, update, REMOTE_ORIGIN);
423
- },
424
- );
425
- }
426
- &nbsp;
427
- applyUpdate(update: Uint8Array, origin?: unknown): void {
428
- this.assertLive();
429
- Y.applyUpdate(this.doc, update, origin);
430
- }
431
- &nbsp;
432
- encodeState(): Uint8Array {
433
- this.assertLive();
434
- return Y.encodeStateAsUpdate(this.doc);
435
- }
436
- &nbsp;
437
- onUpdate(cb: UpdateListener): () =&gt; void {
438
- this.assertLive();
439
- this.listeners.add(cb);
440
- return () =&gt; {
441
- this.listeners.delete(cb);
442
- };
443
- }
444
- &nbsp;
445
- async snapshot(): Promise&lt;void&gt; {
446
- this.assertLive();
447
- const state = this.encodeState();
448
- try {
449
- // Serialize concurrent snapshots of the SAME room; different rooms (or
450
- // the same room under another tenant) persist in parallel.
451
- await withTenantLock(this.tenantId, this.roomId, () =&gt;
452
- this.store.save(this.tenantId, this.roomId, state),
453
- );
454
- } catch (cause) {
455
- throw new CollabError(
456
- `Failed to persist snapshot for room "${this.roomId}".`,
457
- {
458
- code: "COLLAB_SNAPSHOT_FAILED",
459
- suggestion:
460
- "Verify the configured SnapshotStore is reachable (DB/Redis up, " +
461
- "credentials valid). The in-memory default never fails; a custom " +
462
- "adapter likely threw.",
463
- cause,
464
- },
465
- );
466
- }
467
- }
468
- &nbsp;
469
- /** Hydrate this doc from persisted state, if any. Internal to the hub. */
470
- async _restore(): Promise&lt;void&gt; {
471
- try {
472
- const persisted = await this.store.load(this.tenantId, this.roomId);
473
- <span class="missing-if-branch" title="else path not taken" >E</span>if (persisted) Y.applyUpdate(this.doc, persisted, REMOTE_ORIGIN);
474
- } catch (cause) {
475
- throw new CollabError(
476
- `Failed to restore room "${this.roomId}" from snapshot store.`,
477
- {
478
- code: "COLLAB_RESTORE_FAILED",
479
- suggestion:
480
- "Check the SnapshotStore adapter's load() — it should resolve " +
481
- "null (not throw) when no snapshot exists for the tenant+room.",
482
- cause,
483
- },
484
- );
485
- }
486
- }
487
- &nbsp;
488
- destroy(): void {
489
- <span class="missing-if-branch" title="if path not taken" >I</span>if (this.destroyed) <span class="cstat-no" title="statement not covered" >return;</span>
490
- this.destroyed = true;
491
- this.unsubTransport();
492
- this.listeners.clear();
493
- this.doc.destroy();
494
- }
495
- &nbsp;
496
- private assertLive(): void {
497
- if (this.destroyed) {
498
- throw new CollabError(
499
- `Room "${this.roomId}" was destroyed and can no longer be used.`,
500
- {
501
- code: "COLLAB_DESTROYED",
502
- suggestion:
503
- "Acquire a fresh room via hub.room(tenantId, roomId) instead of " +
504
- "reusing a destroyed instance.",
505
- },
506
- );
507
- }
508
- }
509
- }
510
- &nbsp;</pre></td></tr></table></pre>
511
-
512
- <div class='push'></div><!-- for sticky footer -->
513
- </div><!-- /wrapper -->
514
- <div class='footer quiet pad2 space-top1 center small'>
515
- Code coverage generated by
516
- <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
517
- at 2026-05-17T09:08:52.337Z
518
- </div>
519
- <script src="../prettify.js"></script>
520
- <script>
521
- window.onload = function () {
522
- prettyPrint();
523
- };
524
- </script>
525
- <script src="../sorter.js"></script>
526
- <script src="../block-navigation.js"></script>
527
- </body>
528
- </html>
529
-
@@ -1,116 +0,0 @@
1
-
2
- <!doctype html>
3
- <html lang="en">
4
-
5
- <head>
6
- <title>Code coverage report for src/store</title>
7
- <meta charset="utf-8" />
8
- <link rel="stylesheet" href="../../prettify.css" />
9
- <link rel="stylesheet" href="../../base.css" />
10
- <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
- <meta name="viewport" content="width=device-width, initial-scale=1" />
12
- <style type='text/css'>
13
- .coverage-summary .sorter {
14
- background-image: url(../../sort-arrow-sprite.png);
15
- }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <div class='wrapper'>
21
- <div class='pad1'>
22
- <h1><a href="../../index.html">All files</a> src/store</h1>
23
- <div class='clearfix'>
24
-
25
- <div class='fl pad1y space-right2'>
26
- <span class="strong">80% </span>
27
- <span class="quiet">Statements</span>
28
- <span class='fraction'>4/5</span>
29
- </div>
30
-
31
-
32
- <div class='fl pad1y space-right2'>
33
- <span class="strong">100% </span>
34
- <span class="quiet">Branches</span>
35
- <span class='fraction'>2/2</span>
36
- </div>
37
-
38
-
39
- <div class='fl pad1y space-right2'>
40
- <span class="strong">66.66% </span>
41
- <span class="quiet">Functions</span>
42
- <span class='fraction'>2/3</span>
43
- </div>
44
-
45
-
46
- <div class='fl pad1y space-right2'>
47
- <span class="strong">80% </span>
48
- <span class="quiet">Lines</span>
49
- <span class='fraction'>4/5</span>
50
- </div>
51
-
52
-
53
- </div>
54
- <p class="quiet">
55
- Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
- </p>
57
- <template id="filterTemplate">
58
- <div class="quiet">
59
- Filter:
60
- <input type="search" id="fileSearch">
61
- </div>
62
- </template>
63
- </div>
64
- <div class='status-line high'></div>
65
- <div class="pad1">
66
- <table class="coverage-summary">
67
- <thead>
68
- <tr>
69
- <th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
70
- <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
71
- <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
72
- <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
73
- <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
74
- <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
75
- <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
76
- <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
77
- <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
78
- <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
79
- </tr>
80
- </thead>
81
- <tbody><tr>
82
- <td class="file high" data-value="memory.ts"><a href="memory.ts.html">memory.ts</a></td>
83
- <td data-value="80" class="pic high">
84
- <div class="chart"><div class="cover-fill" style="width: 80%"></div><div class="cover-empty" style="width: 20%"></div></div>
85
- </td>
86
- <td data-value="80" class="pct high">80%</td>
87
- <td data-value="5" class="abs high">4/5</td>
88
- <td data-value="100" class="pct high">100%</td>
89
- <td data-value="2" class="abs high">2/2</td>
90
- <td data-value="66.66" class="pct medium">66.66%</td>
91
- <td data-value="3" class="abs medium">2/3</td>
92
- <td data-value="80" class="pct high">80%</td>
93
- <td data-value="5" class="abs high">4/5</td>
94
- </tr>
95
-
96
- </tbody>
97
- </table>
98
- </div>
99
- <div class='push'></div><!-- for sticky footer -->
100
- </div><!-- /wrapper -->
101
- <div class='footer quiet pad2 space-top1 center small'>
102
- Code coverage generated by
103
- <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
- at 2026-05-17T09:08:52.337Z
105
- </div>
106
- <script src="../../prettify.js"></script>
107
- <script>
108
- window.onload = function () {
109
- prettyPrint();
110
- };
111
- </script>
112
- <script src="../../sorter.js"></script>
113
- <script src="../../block-navigation.js"></script>
114
- </body>
115
- </html>
116
-