@spooky-sync/core 0.0.1-canary.239 → 0.0.1-canary.240

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 (139) hide show
  1. package/coverage/lcov-report/base.css +224 -0
  2. package/coverage/lcov-report/block-navigation.js +87 -0
  3. package/coverage/lcov-report/favicon.png +0 -0
  4. package/coverage/lcov-report/index.html +476 -0
  5. package/coverage/lcov-report/prettify.css +1 -0
  6. package/coverage/lcov-report/prettify.js +2 -0
  7. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  8. package/coverage/lcov-report/sorter.js +210 -0
  9. package/coverage/lcov-report/src/boot/auth-flip.saga.ts.html +271 -0
  10. package/coverage/lcov-report/src/boot/boot.saga.ts.html +469 -0
  11. package/coverage/lcov-report/src/boot/bucket-switch.saga.ts.html +430 -0
  12. package/coverage/lcov-report/src/boot/index.html +161 -0
  13. package/coverage/lcov-report/src/boot/preload.saga.ts.html +178 -0
  14. package/coverage/lcov-report/src/client/bucket-handle.ts.html +766 -0
  15. package/coverage/lcov-report/src/client/index.html +161 -0
  16. package/coverage/lcov-report/src/client/router.ts.html +367 -0
  17. package/coverage/lcov-report/src/client/runtime.ts.html +940 -0
  18. package/coverage/lcov-report/src/client/sp00ky-client.ts.html +1531 -0
  19. package/coverage/lcov-report/src/events/index.html +116 -0
  20. package/coverage/lcov-report/src/events/index.ts.html +877 -0
  21. package/coverage/lcov-report/src/index.html +146 -0
  22. package/coverage/lcov-report/src/index.ts.html +202 -0
  23. package/coverage/lcov-report/src/kernel/constants.ts.html +247 -0
  24. package/coverage/lcov-report/src/kernel/effects.ts.html +562 -0
  25. package/coverage/lcov-report/src/kernel/events.ts.html +250 -0
  26. package/coverage/lcov-report/src/kernel/index.html +176 -0
  27. package/coverage/lcov-report/src/kernel/interpreter.ts.html +514 -0
  28. package/coverage/lcov-report/src/kernel/saga.ts.html +304 -0
  29. package/coverage/lcov-report/src/modules/app-release/index.html +116 -0
  30. package/coverage/lcov-report/src/modules/app-release/index.ts.html +712 -0
  31. package/coverage/lcov-report/src/modules/auth/events/index.html +116 -0
  32. package/coverage/lcov-report/src/modules/auth/events/index.ts.html +142 -0
  33. package/coverage/lcov-report/src/modules/auth/index.html +116 -0
  34. package/coverage/lcov-report/src/modules/auth/index.ts.html +1225 -0
  35. package/coverage/lcov-report/src/modules/crdt/crdt-field.ts.html +967 -0
  36. package/coverage/lcov-report/src/modules/crdt/index.html +146 -0
  37. package/coverage/lcov-report/src/modules/crdt/index.ts.html +1474 -0
  38. package/coverage/lcov-report/src/modules/crdt/loro-loader.ts.html +160 -0
  39. package/coverage/lcov-report/src/modules/devtools/flags.ts.html +1132 -0
  40. package/coverage/lcov-report/src/modules/devtools/index.html +161 -0
  41. package/coverage/lcov-report/src/modules/devtools/index.ts.html +2413 -0
  42. package/coverage/lcov-report/src/modules/devtools/storage-info.ts.html +589 -0
  43. package/coverage/lcov-report/src/modules/devtools/versions.ts.html +415 -0
  44. package/coverage/lcov-report/src/modules/feature-flag/index.html +116 -0
  45. package/coverage/lcov-report/src/modules/feature-flag/index.ts.html +1033 -0
  46. package/coverage/lcov-report/src/modules/index.html +116 -0
  47. package/coverage/lcov-report/src/modules/ref-tables.ts.html +349 -0
  48. package/coverage/lcov-report/src/mutation/index.html +191 -0
  49. package/coverage/lcov-report/src/mutation/jobs.ts.html +208 -0
  50. package/coverage/lcov-report/src/mutation/mutation-id.ts.html +190 -0
  51. package/coverage/lcov-report/src/mutation/push.saga.ts.html +730 -0
  52. package/coverage/lcov-report/src/mutation/rows.ts.html +1216 -0
  53. package/coverage/lcov-report/src/mutation/tray.saga.ts.html +229 -0
  54. package/coverage/lcov-report/src/mutation/write.saga.ts.html +583 -0
  55. package/coverage/lcov-report/src/otel/index.html +116 -0
  56. package/coverage/lcov-report/src/otel/index.ts.html +466 -0
  57. package/coverage/lcov-report/src/query/env.ts.html +253 -0
  58. package/coverage/lcov-report/src/query/fetch.saga.ts.html +412 -0
  59. package/coverage/lcov-report/src/query/hash.ts.html +139 -0
  60. package/coverage/lcov-report/src/query/index.html +281 -0
  61. package/coverage/lcov-report/src/query/lifecycle.saga.ts.html +388 -0
  62. package/coverage/lcov-report/src/query/materialize.saga.ts.html +310 -0
  63. package/coverage/lcov-report/src/query/materialize.ts.html +217 -0
  64. package/coverage/lcov-report/src/query/membership.saga.ts.html +709 -0
  65. package/coverage/lcov-report/src/query/membership.ts.html +559 -0
  66. package/coverage/lcov-report/src/query/register.saga.ts.html +655 -0
  67. package/coverage/lcov-report/src/query/render-set.ts.html +265 -0
  68. package/coverage/lcov-report/src/query/sql.ts.html +322 -0
  69. package/coverage/lcov-report/src/query/window-query.ts.html +670 -0
  70. package/coverage/lcov-report/src/services/blobs/blob-cache.ts.html +1894 -0
  71. package/coverage/lcov-report/src/services/blobs/blob-manifest.ts.html +766 -0
  72. package/coverage/lcov-report/src/services/blobs/blob-store.ts.html +1162 -0
  73. package/coverage/lcov-report/src/services/blobs/index.html +161 -0
  74. package/coverage/lcov-report/src/services/blobs/index.ts.html +295 -0
  75. package/coverage/lcov-report/src/services/database/cache-engine.ts.html +664 -0
  76. package/coverage/lcov-report/src/services/database/connection-supervisor.ts.html +1330 -0
  77. package/coverage/lcov-report/src/services/database/database.ts.html +658 -0
  78. package/coverage/lcov-report/src/services/database/engine-factory.ts.html +184 -0
  79. package/coverage/lcov-report/src/services/database/errors.ts.html +187 -0
  80. package/coverage/lcov-report/src/services/database/events/index.html +116 -0
  81. package/coverage/lcov-report/src/services/database/events/index.ts.html +184 -0
  82. package/coverage/lcov-report/src/services/database/index.html +386 -0
  83. package/coverage/lcov-report/src/services/database/index.ts.html +121 -0
  84. package/coverage/lcov-report/src/services/database/local-migrator.ts.html +703 -0
  85. package/coverage/lcov-report/src/services/database/local.ts.html +1633 -0
  86. package/coverage/lcov-report/src/services/database/plan-render.ts.html +409 -0
  87. package/coverage/lcov-report/src/services/database/relation-resolver.ts.html +682 -0
  88. package/coverage/lcov-report/src/services/database/remote.ts.html +1036 -0
  89. package/coverage/lcov-report/src/services/database/sqlite-cache-engine.ts.html +4132 -0
  90. package/coverage/lcov-report/src/services/database/sqlite-lock-verify.ts.html +220 -0
  91. package/coverage/lcov-report/src/services/database/sqlite-open.ts.html +577 -0
  92. package/coverage/lcov-report/src/services/database/sqlite-plan-sql.ts.html +499 -0
  93. package/coverage/lcov-report/src/services/database/sqlite-select.ts.html +478 -0
  94. package/coverage/lcov-report/src/services/database/sqlite-transport.ts.html +757 -0
  95. package/coverage/lcov-report/src/services/database/surql-translate.ts.html +1333 -0
  96. package/coverage/lcov-report/src/services/database/surreal-cache-engine.ts.html +568 -0
  97. package/coverage/lcov-report/src/services/logger/index.html +116 -0
  98. package/coverage/lcov-report/src/services/logger/index.ts.html +154 -0
  99. package/coverage/lcov-report/src/services/persistence/index.html +146 -0
  100. package/coverage/lcov-report/src/services/persistence/localstorage.ts.html +163 -0
  101. package/coverage/lcov-report/src/services/persistence/resilient.ts.html +208 -0
  102. package/coverage/lcov-report/src/services/persistence/surrealdb.ts.html +271 -0
  103. package/coverage/lcov-report/src/services/stream-processor/index.html +146 -0
  104. package/coverage/lcov-report/src/services/stream-processor/index.ts.html +3313 -0
  105. package/coverage/lcov-report/src/services/stream-processor/permissions.ts.html +244 -0
  106. package/coverage/lcov-report/src/services/stream-processor/wasm-types.ts.html +346 -0
  107. package/coverage/lcov-report/src/services/tabs/broker-client.ts.html +934 -0
  108. package/coverage/lcov-report/src/services/tabs/coordinator.ts.html +1984 -0
  109. package/coverage/lcov-report/src/services/tabs/index.html +191 -0
  110. package/coverage/lcov-report/src/services/tabs/leader-locks.ts.html +310 -0
  111. package/coverage/lcov-report/src/services/tabs/protocol.ts.html +871 -0
  112. package/coverage/lcov-report/src/services/tabs/support.ts.html +193 -0
  113. package/coverage/lcov-report/src/services/tabs/tabs-broker-worker.ts.html +2005 -0
  114. package/coverage/lcov-report/src/sp00ky.ts.html +100 -0
  115. package/coverage/lcov-report/src/state/client-state.ts.html +637 -0
  116. package/coverage/lcov-report/src/state/index.html +161 -0
  117. package/coverage/lcov-report/src/state/lifecycle.ts.html +343 -0
  118. package/coverage/lcov-report/src/state/reducers.ts.html +1471 -0
  119. package/coverage/lcov-report/src/state/selectors.ts.html +637 -0
  120. package/coverage/lcov-report/src/sync/connection.saga.ts.html +343 -0
  121. package/coverage/lcov-report/src/sync/index.html +176 -0
  122. package/coverage/lcov-report/src/sync/live.saga.ts.html +232 -0
  123. package/coverage/lcov-report/src/sync/policy.ts.html +1606 -0
  124. package/coverage/lcov-report/src/sync/poll.saga.ts.html +193 -0
  125. package/coverage/lcov-report/src/sync/tabs.saga.ts.html +361 -0
  126. package/coverage/lcov-report/src/types.ts.html +2419 -0
  127. package/coverage/lcov-report/src/utils/blurhash.ts.html +355 -0
  128. package/coverage/lcov-report/src/utils/error-classification.ts.html +244 -0
  129. package/coverage/lcov-report/src/utils/index.html +191 -0
  130. package/coverage/lcov-report/src/utils/index.ts.html +820 -0
  131. package/coverage/lcov-report/src/utils/parser.ts.html +313 -0
  132. package/coverage/lcov-report/src/utils/semver.ts.html +175 -0
  133. package/coverage/lcov-report/src/utils/surql.ts.html +667 -0
  134. package/coverage/lcov.info +19079 -0
  135. package/dist/index.js +3 -3
  136. package/dist/sqlite-open.js +20 -1
  137. package/package.json +3 -3
  138. package/src/services/database/relation-resolver.test.ts +55 -1
  139. package/src/services/database/relation-resolver.ts +0 -0
@@ -0,0 +1,1216 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/mutation/rows.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/mutation</a> rows.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>257/257</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'>120/120</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>22/22</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'>257/257</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>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
444
+ <span class="cline-any cline-neutral">&nbsp;</span>
445
+ <span class="cline-any cline-neutral">&nbsp;</span>
446
+ <span class="cline-any cline-neutral">&nbsp;</span>
447
+ <span class="cline-any cline-neutral">&nbsp;</span>
448
+ <span class="cline-any cline-neutral">&nbsp;</span>
449
+ <span class="cline-any cline-neutral">&nbsp;</span>
450
+ <span class="cline-any cline-neutral">&nbsp;</span>
451
+ <span class="cline-any cline-neutral">&nbsp;</span>
452
+ <span class="cline-any cline-neutral">&nbsp;</span>
453
+ <span class="cline-any cline-yes">1x</span>
454
+ <span class="cline-any cline-yes">1x</span>
455
+ <span class="cline-any cline-yes">1x</span>
456
+ <span class="cline-any cline-neutral">&nbsp;</span>
457
+ <span class="cline-any cline-neutral">&nbsp;</span>
458
+ <span class="cline-any cline-neutral">&nbsp;</span>
459
+ <span class="cline-any cline-neutral">&nbsp;</span>
460
+ <span class="cline-any cline-neutral">&nbsp;</span>
461
+ <span class="cline-any cline-neutral">&nbsp;</span>
462
+ <span class="cline-any cline-neutral">&nbsp;</span>
463
+ <span class="cline-any cline-neutral">&nbsp;</span>
464
+ <span class="cline-any cline-neutral">&nbsp;</span>
465
+ <span class="cline-any cline-neutral">&nbsp;</span>
466
+ <span class="cline-any cline-neutral">&nbsp;</span>
467
+ <span class="cline-any cline-neutral">&nbsp;</span>
468
+ <span class="cline-any cline-neutral">&nbsp;</span>
469
+ <span class="cline-any cline-neutral">&nbsp;</span>
470
+ <span class="cline-any cline-neutral">&nbsp;</span>
471
+ <span class="cline-any cline-neutral">&nbsp;</span>
472
+ <span class="cline-any cline-neutral">&nbsp;</span>
473
+ <span class="cline-any cline-neutral">&nbsp;</span>
474
+ <span class="cline-any cline-neutral">&nbsp;</span>
475
+ <span class="cline-any cline-neutral">&nbsp;</span>
476
+ <span class="cline-any cline-neutral">&nbsp;</span>
477
+ <span class="cline-any cline-neutral">&nbsp;</span>
478
+ <span class="cline-any cline-neutral">&nbsp;</span>
479
+ <span class="cline-any cline-neutral">&nbsp;</span>
480
+ <span class="cline-any cline-neutral">&nbsp;</span>
481
+ <span class="cline-any cline-neutral">&nbsp;</span>
482
+ <span class="cline-any cline-neutral">&nbsp;</span>
483
+ <span class="cline-any cline-neutral">&nbsp;</span>
484
+ <span class="cline-any cline-neutral">&nbsp;</span>
485
+ <span class="cline-any cline-neutral">&nbsp;</span>
486
+ <span class="cline-any cline-neutral">&nbsp;</span>
487
+ <span class="cline-any cline-yes">1x</span>
488
+ <span class="cline-any cline-yes">100x</span>
489
+ <span class="cline-any cline-yes">100x</span>
490
+ <span class="cline-any cline-yes">100x</span>
491
+ <span class="cline-any cline-yes">100x</span>
492
+ <span class="cline-any cline-yes">100x</span>
493
+ <span class="cline-any cline-neutral">&nbsp;</span>
494
+ <span class="cline-any cline-neutral">&nbsp;</span>
495
+ <span class="cline-any cline-yes">1x</span>
496
+ <span class="cline-any cline-yes">43x</span>
497
+ <span class="cline-any cline-yes">41x</span>
498
+ <span class="cline-any cline-yes">41x</span>
499
+ <span class="cline-any cline-yes">41x</span>
500
+ <span class="cline-any cline-neutral">&nbsp;</span>
501
+ <span class="cline-any cline-neutral">&nbsp;</span>
502
+ <span class="cline-any cline-yes">1x</span>
503
+ <span class="cline-any cline-yes">15x</span>
504
+ <span class="cline-any cline-yes">15x</span>
505
+ <span class="cline-any cline-yes">15x</span>
506
+ <span class="cline-any cline-yes">15x</span>
507
+ <span class="cline-any cline-neutral">&nbsp;</span>
508
+ <span class="cline-any cline-neutral">&nbsp;</span>
509
+ <span class="cline-any cline-neutral">&nbsp;</span>
510
+ <span class="cline-any cline-neutral">&nbsp;</span>
511
+ <span class="cline-any cline-neutral">&nbsp;</span>
512
+ <span class="cline-any cline-neutral">&nbsp;</span>
513
+ <span class="cline-any cline-yes">1x</span>
514
+ <span class="cline-any cline-yes">40x</span>
515
+ <span class="cline-any cline-yes">38x</span>
516
+ <span class="cline-any cline-yes">38x</span>
517
+ <span class="cline-any cline-yes">40x</span>
518
+ <span class="cline-any cline-yes">40x</span>
519
+ <span class="cline-any cline-yes">34x</span>
520
+ <span class="cline-any cline-yes">40x</span>
521
+ <span class="cline-any cline-yes">40x</span>
522
+ <span class="cline-any cline-yes">40x</span>
523
+ <span class="cline-any cline-yes">32x</span>
524
+ <span class="cline-any cline-yes">32x</span>
525
+ <span class="cline-any cline-yes">32x</span>
526
+ <span class="cline-any cline-yes">32x</span>
527
+ <span class="cline-any cline-yes">40x</span>
528
+ <span class="cline-any cline-yes">40x</span>
529
+ <span class="cline-any cline-yes">40x</span>
530
+ <span class="cline-any cline-yes">40x</span>
531
+ <span class="cline-any cline-yes">40x</span>
532
+ <span class="cline-any cline-yes">40x</span>
533
+ <span class="cline-any cline-yes">40x</span>
534
+ <span class="cline-any cline-yes">40x</span>
535
+ <span class="cline-any cline-neutral">&nbsp;</span>
536
+ <span class="cline-any cline-neutral">&nbsp;</span>
537
+ <span class="cline-any cline-neutral">&nbsp;</span>
538
+ <span class="cline-any cline-neutral">&nbsp;</span>
539
+ <span class="cline-any cline-neutral">&nbsp;</span>
540
+ <span class="cline-any cline-neutral">&nbsp;</span>
541
+ <span class="cline-any cline-neutral">&nbsp;</span>
542
+ <span class="cline-any cline-neutral">&nbsp;</span>
543
+ <span class="cline-any cline-yes">1x</span>
544
+ <span class="cline-any cline-yes">32x</span>
545
+ <span class="cline-any cline-yes">20x</span>
546
+ <span class="cline-any cline-yes">20x</span>
547
+ <span class="cline-any cline-yes">32x</span>
548
+ <span class="cline-any cline-yes">1x</span>
549
+ <span class="cline-any cline-yes">1x</span>
550
+ <span class="cline-any cline-yes">32x</span>
551
+ <span class="cline-any cline-neutral">&nbsp;</span>
552
+ <span class="cline-any cline-yes">1x</span>
553
+ <span class="cline-any cline-yes">2x</span>
554
+ <span class="cline-any cline-yes">2x</span>
555
+ <span class="cline-any cline-yes">2x</span>
556
+ <span class="cline-any cline-yes">2x</span>
557
+ <span class="cline-any cline-yes">2x</span>
558
+ <span class="cline-any cline-yes">2x</span>
559
+ <span class="cline-any cline-yes">2x</span>
560
+ <span class="cline-any cline-yes">2x</span>
561
+ <span class="cline-any cline-neutral">&nbsp;</span>
562
+ <span class="cline-any cline-yes">1x</span>
563
+ <span class="cline-any cline-yes">1x</span>
564
+ <span class="cline-any cline-neutral">&nbsp;</span>
565
+ <span class="cline-any cline-neutral">&nbsp;</span>
566
+ <span class="cline-any cline-neutral">&nbsp;</span>
567
+ <span class="cline-any cline-neutral">&nbsp;</span>
568
+ <span class="cline-any cline-neutral">&nbsp;</span>
569
+ <span class="cline-any cline-neutral">&nbsp;</span>
570
+ <span class="cline-any cline-neutral">&nbsp;</span>
571
+ <span class="cline-any cline-neutral">&nbsp;</span>
572
+ <span class="cline-any cline-yes">1x</span>
573
+ <span class="cline-any cline-yes">22x</span>
574
+ <span class="cline-any cline-yes">22x</span>
575
+ <span class="cline-any cline-yes">22x</span>
576
+ <span class="cline-any cline-yes">22x</span>
577
+ <span class="cline-any cline-yes">22x</span>
578
+ <span class="cline-any cline-yes">22x</span>
579
+ <span class="cline-any cline-yes">22x</span>
580
+ <span class="cline-any cline-yes">22x</span>
581
+ <span class="cline-any cline-yes">22x</span>
582
+ <span class="cline-any cline-yes">22x</span>
583
+ <span class="cline-any cline-yes">22x</span>
584
+ <span class="cline-any cline-neutral">&nbsp;</span>
585
+ <span class="cline-any cline-neutral">&nbsp;</span>
586
+ <span class="cline-any cline-neutral">&nbsp;</span>
587
+ <span class="cline-any cline-neutral">&nbsp;</span>
588
+ <span class="cline-any cline-neutral">&nbsp;</span>
589
+ <span class="cline-any cline-neutral">&nbsp;</span>
590
+ <span class="cline-any cline-neutral">&nbsp;</span>
591
+ <span class="cline-any cline-neutral">&nbsp;</span>
592
+ <span class="cline-any cline-neutral">&nbsp;</span>
593
+ <span class="cline-any cline-neutral">&nbsp;</span>
594
+ <span class="cline-any cline-neutral">&nbsp;</span>
595
+ <span class="cline-any cline-yes">1x</span>
596
+ <span class="cline-any cline-yes">7x</span>
597
+ <span class="cline-any cline-yes">7x</span>
598
+ <span class="cline-any cline-yes">7x</span>
599
+ <span class="cline-any cline-yes">7x</span>
600
+ <span class="cline-any cline-yes">7x</span>
601
+ <span class="cline-any cline-yes">7x</span>
602
+ <span class="cline-any cline-yes">7x</span>
603
+ <span class="cline-any cline-yes">7x</span>
604
+ <span class="cline-any cline-yes">7x</span>
605
+ <span class="cline-any cline-yes">7x</span>
606
+ <span class="cline-any cline-yes">7x</span>
607
+ <span class="cline-any cline-neutral">&nbsp;</span>
608
+ <span class="cline-any cline-neutral">&nbsp;</span>
609
+ <span class="cline-any cline-yes">1x</span>
610
+ <span class="cline-any cline-yes">5x</span>
611
+ <span class="cline-any cline-yes">5x</span>
612
+ <span class="cline-any cline-yes">5x</span>
613
+ <span class="cline-any cline-yes">5x</span>
614
+ <span class="cline-any cline-yes">5x</span>
615
+ <span class="cline-any cline-yes">5x</span>
616
+ <span class="cline-any cline-yes">5x</span>
617
+ <span class="cline-any cline-yes">5x</span>
618
+ <span class="cline-any cline-yes">5x</span>
619
+ <span class="cline-any cline-yes">5x</span>
620
+ <span class="cline-any cline-yes">5x</span>
621
+ <span class="cline-any cline-yes">5x</span>
622
+ <span class="cline-any cline-yes">5x</span>
623
+ <span class="cline-any cline-yes">5x</span>
624
+ <span class="cline-any cline-yes">5x</span>
625
+ <span class="cline-any cline-yes">5x</span>
626
+ <span class="cline-any cline-yes">5x</span>
627
+ <span class="cline-any cline-yes">5x</span>
628
+ <span class="cline-any cline-yes">5x</span>
629
+ <span class="cline-any cline-neutral">&nbsp;</span>
630
+ <span class="cline-any cline-neutral">&nbsp;</span>
631
+ <span class="cline-any cline-yes">1x</span>
632
+ <span class="cline-any cline-yes">5x</span>
633
+ <span class="cline-any cline-yes">5x</span>
634
+ <span class="cline-any cline-yes">5x</span>
635
+ <span class="cline-any cline-yes">5x</span>
636
+ <span class="cline-any cline-yes">5x</span>
637
+ <span class="cline-any cline-yes">5x</span>
638
+ <span class="cline-any cline-yes">5x</span>
639
+ <span class="cline-any cline-yes">5x</span>
640
+ <span class="cline-any cline-yes">5x</span>
641
+ <span class="cline-any cline-yes">5x</span>
642
+ <span class="cline-any cline-yes">5x</span>
643
+ <span class="cline-any cline-neutral">&nbsp;</span>
644
+ <span class="cline-any cline-neutral">&nbsp;</span>
645
+ <span class="cline-any cline-yes">1x</span>
646
+ <span class="cline-any cline-yes">6x</span>
647
+ <span class="cline-any cline-yes">6x</span>
648
+ <span class="cline-any cline-yes">6x</span>
649
+ <span class="cline-any cline-yes">6x</span>
650
+ <span class="cline-any cline-yes">6x</span>
651
+ <span class="cline-any cline-yes">6x</span>
652
+ <span class="cline-any cline-yes">6x</span>
653
+ <span class="cline-any cline-yes">6x</span>
654
+ <span class="cline-any cline-yes">6x</span>
655
+ <span class="cline-any cline-yes">6x</span>
656
+ <span class="cline-any cline-yes">6x</span>
657
+ <span class="cline-any cline-neutral">&nbsp;</span>
658
+ <span class="cline-any cline-neutral">&nbsp;</span>
659
+ <span class="cline-any cline-yes">1x</span>
660
+ <span class="cline-any cline-yes">5x</span>
661
+ <span class="cline-any cline-yes">5x</span>
662
+ <span class="cline-any cline-yes">5x</span>
663
+ <span class="cline-any cline-yes">5x</span>
664
+ <span class="cline-any cline-yes">5x</span>
665
+ <span class="cline-any cline-yes">5x</span>
666
+ <span class="cline-any cline-yes">5x</span>
667
+ <span class="cline-any cline-yes">5x</span>
668
+ <span class="cline-any cline-yes">5x</span>
669
+ <span class="cline-any cline-yes">5x</span>
670
+ <span class="cline-any cline-yes">5x</span>
671
+ <span class="cline-any cline-yes">5x</span>
672
+ <span class="cline-any cline-neutral">&nbsp;</span>
673
+ <span class="cline-any cline-neutral">&nbsp;</span>
674
+ <span class="cline-any cline-neutral">&nbsp;</span>
675
+ <span class="cline-any cline-neutral">&nbsp;</span>
676
+ <span class="cline-any cline-neutral">&nbsp;</span>
677
+ <span class="cline-any cline-neutral">&nbsp;</span>
678
+ <span class="cline-any cline-neutral">&nbsp;</span>
679
+ <span class="cline-any cline-neutral">&nbsp;</span>
680
+ <span class="cline-any cline-neutral">&nbsp;</span>
681
+ <span class="cline-any cline-neutral">&nbsp;</span>
682
+ <span class="cline-any cline-neutral">&nbsp;</span>
683
+ <span class="cline-any cline-neutral">&nbsp;</span>
684
+ <span class="cline-any cline-yes">1x</span>
685
+ <span class="cline-any cline-yes">18x</span>
686
+ <span class="cline-any cline-yes">18x</span>
687
+ <span class="cline-any cline-yes">33x</span>
688
+ <span class="cline-any cline-yes">33x</span>
689
+ <span class="cline-any cline-yes">33x</span>
690
+ <span class="cline-any cline-yes">33x</span>
691
+ <span class="cline-any cline-yes">20x</span>
692
+ <span class="cline-any cline-yes">20x</span>
693
+ <span class="cline-any cline-yes">19x</span>
694
+ <span class="cline-any cline-yes">19x</span>
695
+ <span class="cline-any cline-yes">20x</span>
696
+ <span class="cline-any cline-yes">20x</span>
697
+ <span class="cline-any cline-yes">20x</span>
698
+ <span class="cline-any cline-yes">33x</span>
699
+ <span class="cline-any cline-yes">2x</span>
700
+ <span class="cline-any cline-yes">2x</span>
701
+ <span class="cline-any cline-yes">33x</span>
702
+ <span class="cline-any cline-yes">11x</span>
703
+ <span class="cline-any cline-yes">33x</span>
704
+ <span class="cline-any cline-yes">18x</span>
705
+ <span class="cline-any cline-yes">18x</span>
706
+ <span class="cline-any cline-yes">18x</span>
707
+ <span class="cline-any cline-neutral">&nbsp;</span>
708
+ <span class="cline-any cline-neutral">&nbsp;</span>
709
+ <span class="cline-any cline-neutral">&nbsp;</span>
710
+ <span class="cline-any cline-neutral">&nbsp;</span>
711
+ <span class="cline-any cline-neutral">&nbsp;</span>
712
+ <span class="cline-any cline-neutral">&nbsp;</span>
713
+ <span class="cline-any cline-neutral">&nbsp;</span>
714
+ <span class="cline-any cline-neutral">&nbsp;</span>
715
+ <span class="cline-any cline-neutral">&nbsp;</span>
716
+ <span class="cline-any cline-neutral">&nbsp;</span>
717
+ <span class="cline-any cline-neutral">&nbsp;</span>
718
+ <span class="cline-any cline-neutral">&nbsp;</span>
719
+ <span class="cline-any cline-neutral">&nbsp;</span>
720
+ <span class="cline-any cline-neutral">&nbsp;</span>
721
+ <span class="cline-any cline-yes">1x</span>
722
+ <span class="cline-any cline-yes">18x</span>
723
+ <span class="cline-any cline-yes">18x</span>
724
+ <span class="cline-any cline-yes">8x</span>
725
+ <span class="cline-any cline-yes">8x</span>
726
+ <span class="cline-any cline-yes">8x</span>
727
+ <span class="cline-any cline-yes">8x</span>
728
+ <span class="cline-any cline-yes">8x</span>
729
+ <span class="cline-any cline-yes">8x</span>
730
+ <span class="cline-any cline-yes">18x</span>
731
+ <span class="cline-any cline-yes">4x</span>
732
+ <span class="cline-any cline-yes">4x</span>
733
+ <span class="cline-any cline-yes">4x</span>
734
+ <span class="cline-any cline-yes">4x</span>
735
+ <span class="cline-any cline-yes">4x</span>
736
+ <span class="cline-any cline-yes">4x</span>
737
+ <span class="cline-any cline-yes">6x</span>
738
+ <span class="cline-any cline-yes">6x</span>
739
+ <span class="cline-any cline-yes">6x</span>
740
+ <span class="cline-any cline-yes">6x</span>
741
+ <span class="cline-any cline-yes">6x</span>
742
+ <span class="cline-any cline-yes">18x</span>
743
+ <span class="cline-any cline-yes">18x</span>
744
+ <span class="cline-any cline-yes">18x</span>
745
+ <span class="cline-any cline-yes">18x</span>
746
+ <span class="cline-any cline-yes">18x</span>
747
+ <span class="cline-any cline-yes">18x</span>
748
+ <span class="cline-any cline-yes">18x</span>
749
+ <span class="cline-any cline-neutral">&nbsp;</span>
750
+ <span class="cline-any cline-yes">1x</span>
751
+ <span class="cline-any cline-yes">23x</span>
752
+ <span class="cline-any cline-neutral">&nbsp;</span>
753
+ <span class="cline-any cline-yes">1x</span>
754
+ <span class="cline-any cline-yes">14x</span>
755
+ <span class="cline-any cline-yes">14x</span>
756
+ <span class="cline-any cline-yes">14x</span>
757
+ <span class="cline-any cline-yes">14x</span>
758
+ <span class="cline-any cline-yes">14x</span>
759
+ <span class="cline-any cline-yes">14x</span>
760
+ <span class="cline-any cline-yes">14x</span>
761
+ <span class="cline-any cline-yes">14x</span>
762
+ <span class="cline-any cline-yes">14x</span>
763
+ <span class="cline-any cline-yes">14x</span>
764
+ <span class="cline-any cline-yes">14x</span>
765
+ <span class="cline-any cline-yes">14x</span>
766
+ <span class="cline-any cline-yes">14x</span>
767
+ <span class="cline-any cline-yes">14x</span>
768
+ <span class="cline-any cline-yes">14x</span>
769
+ <span class="cline-any cline-yes">14x</span>
770
+ <span class="cline-any cline-yes">14x</span>
771
+ <span class="cline-any cline-yes">14x</span>
772
+ <span class="cline-any cline-yes">14x</span>
773
+ <span class="cline-any cline-yes">14x</span>
774
+ <span class="cline-any cline-yes">14x</span>
775
+ <span class="cline-any cline-neutral">&nbsp;</span>
776
+ <span class="cline-any cline-neutral">&nbsp;</span>
777
+ <span class="cline-any cline-yes">1x</span>
778
+ <span class="cline-any cline-yes">14x</span>
779
+ <span class="cline-any cline-yes">14x</span>
780
+ <span class="cline-any cline-yes">14x</span>
781
+ <span class="cline-any cline-yes">14x</span>
782
+ <span class="cline-any cline-yes">14x</span>
783
+ <span class="cline-any cline-yes">14x</span>
784
+ <span class="cline-any cline-neutral">&nbsp;</span>
785
+ <span class="cline-any cline-yes">1x</span>
786
+ <span class="cline-any cline-yes">10x</span>
787
+ <span class="cline-any cline-yes">10x</span>
788
+ <span class="cline-any cline-yes">10x</span>
789
+ <span class="cline-any cline-neutral">&nbsp;</span>
790
+ <span class="cline-any cline-yes">1x</span>
791
+ <span class="cline-any cline-yes">3x</span>
792
+ <span class="cline-any cline-yes">3x</span>
793
+ <span class="cline-any cline-yes">3x</span>
794
+ <span class="cline-any cline-neutral">&nbsp;</span>
795
+ <span class="cline-any cline-yes">1x</span>
796
+ <span class="cline-any cline-yes">10x</span>
797
+ <span class="cline-any cline-yes">9x</span>
798
+ <span class="cline-any cline-yes">9x</span>
799
+ <span class="cline-any cline-yes">10x</span>
800
+ <span class="cline-any cline-yes">10x</span>
801
+ <span class="cline-any cline-yes">10x</span>
802
+ <span class="cline-any cline-yes">10x</span>
803
+ <span class="cline-any cline-yes">10x</span>
804
+ <span class="cline-any cline-yes">10x</span>
805
+ <span class="cline-any cline-yes">10x</span>
806
+ <span class="cline-any cline-yes">10x</span>
807
+ <span class="cline-any cline-yes">10x</span>
808
+ <span class="cline-any cline-yes">10x</span>
809
+ <span class="cline-any cline-yes">10x</span>
810
+ <span class="cline-any cline-yes">10x</span>
811
+ <span class="cline-any cline-yes">10x</span>
812
+ <span class="cline-any cline-yes">10x</span>
813
+ <span class="cline-any cline-yes">10x</span>
814
+ <span class="cline-any cline-yes">10x</span>
815
+ <span class="cline-any cline-yes">10x</span>
816
+ <span class="cline-any cline-yes">10x</span>
817
+ <span class="cline-any cline-yes">10x</span>
818
+ <span class="cline-any cline-yes">10x</span>
819
+ <span class="cline-any cline-yes">10x</span>
820
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { RecordId } from 'surrealdb';
821
+ import type { MutationEventType } from '../types';
822
+ import type { Vars } from '../kernel/effects';
823
+ import type { IngestRecord } from '../services/stream-processor/index';
824
+ import type { OutboxItem } from '../state/client-state';
825
+ import { surql } from '../utils/surql';
826
+ import type { SealedQuery } from '../utils/surql';
827
+ import { extractTablePart, parseRecordIdString } from '../utils/index';
828
+ import { parseQueryParams } from '../utils/parser';
829
+ &nbsp;
830
+ export const PENDING_TABLE = '_00_pending_mutations';
831
+ export const FAILED_TABLE = '_00_failed_mutations';
832
+ export const PENDING_ROW_VERSION = 2;
833
+ &nbsp;
834
+ /** One `_00_pending_mutations` row as this client writes it (v2). */
835
+ export interface PendingMutationRow {
836
+ id: string;
837
+ mutationType: MutationEventType;
838
+ recordId: string;
839
+ tableName: string;
840
+ data?: Record&lt;string, unknown&gt;;
841
+ beforeRecord?: Record&lt;string, unknown&gt; | null;
842
+ createdAt: number;
843
+ v: number;
844
+ }
845
+ &nbsp;
846
+ export interface FailedMutationRow {
847
+ id: string;
848
+ mutationType: MutationEventType;
849
+ recordId: string;
850
+ tableName: string;
851
+ data?: Record&lt;string, unknown&gt;;
852
+ beforeRecord?: Record&lt;string, unknown&gt; | null;
853
+ error: { message: string; kind: 'application' | 'unreplayable' };
854
+ attempts: number;
855
+ createdAt: number;
856
+ failedAt: number;
857
+ revert: 'full' | 'partial' | 'none';
858
+ }
859
+ &nbsp;
860
+ /**
861
+ * Parse a record id READ BACK FROM THE STORE, stripping SurrealDB's `⟨⟩`
862
+ * escaping (outbox ids contain `_`, so they come back escaped).
863
+ */
864
+ export function parseStoredRecordId(id: string): RecordId&lt;string&gt; {
865
+ const [table, ...rest] = id.split(':');
866
+ let raw = rest.join(':');
867
+ if (raw.startsWith('⟨') &amp;&amp; raw.endsWith('⟩')) raw = raw.slice(1, -1);
868
+ return new RecordId(table, raw);
869
+ }
870
+ &nbsp;
871
+ /** Stable `table:id` string for an id read from the store, escaping removed. */
872
+ export const storedIdString = (id: unknown): string =&gt; {
873
+ if (id instanceof RecordId) return `${id.table}:${String(id.id)}`;
874
+ const rid = parseStoredRecordId(String(id));
875
+ return `${rid.table}:${rid.id}`;
876
+ };
877
+ &nbsp;
878
+ /** Timestamp prefix of a v1/v2 mutation id, or `null` for a legacy numeric id. */
879
+ export function createdAtFromId(id: string): number | null {
880
+ const raw = id.includes(':') ? id.slice(id.indexOf(':') + 1) : id;
881
+ const m = /^⟨?(\d{13})/.exec(raw);
882
+ return m ? Number(m[1]) : null;
883
+ }
884
+ &nbsp;
885
+ /**
886
+ * Read any row shape this table ever had. Legacy rows (`v` missing) lack
887
+ * `tableName`, `createdAt` and `beforeRecord`. A create without `data` is not
888
+ * replayable and returns `null`.
889
+ */
890
+ export function parsePendingRow(row: unknown): PendingMutationRow | null {
891
+ if (!row || typeof row !== 'object') return null;
892
+ const r = row as Record&lt;string, unknown&gt;;
893
+ const type = r.mutationType;
894
+ if (type !== 'create' &amp;&amp; type !== 'update' &amp;&amp; type !== 'delete') return null;
895
+ if (typeof r.recordId !== 'string' &amp;&amp; !(r.recordId instanceof RecordId)) return null;
896
+ const id = storedIdString(r.id);
897
+ const recordId = typeof r.recordId === 'string' ? r.recordId : storedIdString(r.recordId);
898
+ const data = r.data &amp;&amp; typeof r.data === 'object' ? (r.data as Record&lt;string, unknown&gt;) : undefined;
899
+ if (type === 'create' &amp;&amp; !data) return null;
900
+ return {
901
+ id,
902
+ mutationType: type,
903
+ recordId,
904
+ tableName: typeof r.tableName === 'string' ? r.tableName : extractTablePart(recordId),
905
+ data,
906
+ beforeRecord:
907
+ r.beforeRecord &amp;&amp; typeof r.beforeRecord === 'object' ? (r.beforeRecord as Record&lt;string, unknown&gt;) : undefined,
908
+ createdAt: typeof r.createdAt === 'number' ? r.createdAt : (createdAtFromId(id) ?? 0),
909
+ v: typeof r.v === 'number' ? r.v : 1,
910
+ };
911
+ }
912
+ &nbsp;
913
+ /**
914
+ * Re-type a stored row's payload from the schema before it is pushed. The
915
+ * store keeps JSON, so a `record&lt;user&gt;` field comes back as `'user:x'` and a
916
+ * datetime as a string; the server coerces neither. Unknown keys stay as they
917
+ * are, and a payload the schema rejects is sent raw so the server's answer,
918
+ * not a local throw, decides its fate.
919
+ */
920
+ export function hydrateRowData(row: PendingMutationRow, columns: Record&lt;string, unknown&gt; | null): PendingMutationRow {
921
+ if (!row.data || !columns) return row;
922
+ try {
923
+ return { ...row, data: parseQueryParams(columns as never, row.data) };
924
+ } catch {
925
+ return row;
926
+ }
927
+ }
928
+ &nbsp;
929
+ export const toOutboxItem = (row: PendingMutationRow): OutboxItem =&gt; ({
930
+ id: row.id,
931
+ type: row.mutationType,
932
+ recordId: row.recordId,
933
+ table: row.tableName,
934
+ status: 'pending',
935
+ ackedAt: null,
936
+ attempts: 0,
937
+ });
938
+ &nbsp;
939
+ export const loadPendingRows = (): string =&gt; `SELECT * FROM ${PENDING_TABLE} ORDER BY id ASC`;
940
+ export const loadFailedRows = (): string =&gt; `SELECT * FROM ${FAILED_TABLE} ORDER BY failedAt ASC`;
941
+ &nbsp;
942
+ // ---- local write transactions ------------------------------------------------
943
+ &nbsp;
944
+ export interface LocalTx {
945
+ query: SealedQuery&lt;unknown&gt;;
946
+ vars: Vars;
947
+ }
948
+ &nbsp;
949
+ const pendingInsert = (type: MutationEventType, withData: boolean, withBefore: boolean): string =&gt; {
950
+ const fields = [
951
+ `mutationType = '${type}'`,
952
+ 'recordId = $id',
953
+ 'tableName = $table',
954
+ 'createdAt = $createdAt',
955
+ `v = ${PENDING_ROW_VERSION}`,
956
+ ];
957
+ if (withData) fields.push('data = $data');
958
+ if (withBefore) fields.push('beforeRecord = $before');
959
+ return `CREATE ONLY $mid SET ${fields.join(', ')}`;
960
+ };
961
+ &nbsp;
962
+ export interface WritePlanInput {
963
+ recordId: RecordId&lt;string&gt;;
964
+ mutationId: RecordId&lt;string&gt;;
965
+ table: string;
966
+ data?: Record&lt;string, unknown&gt;;
967
+ before?: Record&lt;string, unknown&gt; | null;
968
+ now: number;
969
+ }
970
+ &nbsp;
971
+ /** `CREATE` the row and its outbox entry in one transaction; result index 0 is the row. */
972
+ export function planCreateTx(input: WritePlanInput): LocalTx {
973
+ const data = input.data ?? {};
974
+ const keys = Object.keys(data).map((key) =&gt; ({ key, variable: `data_${key}` }));
975
+ const vars: Vars = { id: input.recordId, mid: input.mutationId, table: input.table, createdAt: input.now, data };
976
+ for (const { key, variable } of keys) vars[variable] = data[key];
977
+ return {
978
+ query: surql.seal&lt;unknown&gt;(surql.tx([surql.createSet('id', keys), pendingInsert('create', true, false)]), {
979
+ resultIndex: 0,
980
+ }),
981
+ vars,
982
+ };
983
+ }
984
+ &nbsp;
985
+ /** Bump `_00_rv`, MERGE the patch, write the outbox row (with `beforeRecord`); returns `{ target }`. */
986
+ export function planUpdateTx(input: WritePlanInput): LocalTx {
987
+ return {
988
+ query: surql.seal&lt;unknown&gt;(
989
+ surql.tx([
990
+ surql.updateSet('id', [{ statement: '_00_rv += 1' }]),
991
+ surql.let('updated', surql.updateMerge('id', 'data')),
992
+ pendingInsert('update', true, true),
993
+ surql.returnObject([{ key: 'target', variable: 'updated' }]),
994
+ ])
995
+ ),
996
+ vars: {
997
+ id: input.recordId,
998
+ mid: input.mutationId,
999
+ table: input.table,
1000
+ createdAt: input.now,
1001
+ data: input.data ?? {},
1002
+ before: input.before ?? null,
1003
+ },
1004
+ };
1005
+ }
1006
+ &nbsp;
1007
+ /** DELETE the row and write the outbox entry (with `beforeRecord`). */
1008
+ export function planDeleteTx(input: WritePlanInput): LocalTx {
1009
+ return {
1010
+ query: surql.seal&lt;unknown&gt;(surql.tx([surql.delete('id'), pendingInsert('delete', false, true)])),
1011
+ vars: {
1012
+ id: input.recordId,
1013
+ mid: input.mutationId,
1014
+ table: input.table,
1015
+ createdAt: input.now,
1016
+ before: input.before ?? null,
1017
+ },
1018
+ };
1019
+ }
1020
+ &nbsp;
1021
+ /** Debounced update: bump `_00_rv` and MERGE now; the outbox row comes later. */
1022
+ export function planLocalOnlyUpdateTx(input: { recordId: RecordId&lt;string&gt;; data: Record&lt;string, unknown&gt; }): LocalTx {
1023
+ return {
1024
+ query: surql.seal&lt;unknown&gt;(
1025
+ surql.tx([
1026
+ surql.updateSet('id', [{ statement: '_00_rv += 1' }]),
1027
+ surql.let('updated', surql.updateMerge('id', 'data')),
1028
+ surql.returnObject([{ key: 'target', variable: 'updated' }]),
1029
+ ])
1030
+ ),
1031
+ vars: { id: input.recordId, data: input.data },
1032
+ };
1033
+ }
1034
+ &nbsp;
1035
+ /** The outbox row of a flushed debounced update, on its own. */
1036
+ export function planDeferredOutboxRowTx(input: WritePlanInput): LocalTx {
1037
+ return {
1038
+ query: surql.seal&lt;unknown&gt;(surql.tx([pendingInsert('update', true, true)])),
1039
+ vars: {
1040
+ id: input.recordId,
1041
+ mid: input.mutationId,
1042
+ table: input.table,
1043
+ createdAt: input.now,
1044
+ data: input.data ?? {},
1045
+ before: input.before ?? null,
1046
+ },
1047
+ };
1048
+ }
1049
+ &nbsp;
1050
+ // ---- remote push -------------------------------------------------------------
1051
+ &nbsp;
1052
+ export interface RemoteBatch {
1053
+ sql: string;
1054
+ vars: Vars;
1055
+ }
1056
+ &nbsp;
1057
+ /**
1058
+ * Many outbox rows as ONE multi-statement request. Statement i answers row i.
1059
+ * Each statement is its own transaction on the server, as before.
1060
+ */
1061
+ export function remoteBatch(rows: ReadonlyArray&lt;PendingMutationRow&gt;): RemoteBatch {
1062
+ const vars: Vars = {};
1063
+ const stmts = rows.map((row, i) =&gt; {
1064
+ const rid = parseRecordIdString(row.recordId);
1065
+ vars[`id${i}`] = rid;
1066
+ switch (row.mutationType) {
1067
+ case 'create': {
1068
+ const data = row.data ?? {};
1069
+ const sets = Object.keys(data).map((key) =&gt; {
1070
+ vars[`d${i}_${key}`] = data[key];
1071
+ return `${key} = $d${i}_${key}`;
1072
+ });
1073
+ return `CREATE ONLY $id${i} SET ${sets.join(', ')}`;
1074
+ }
1075
+ case 'update':
1076
+ vars[`data${i}`] = row.data ?? {};
1077
+ return `UPDATE $id${i} MERGE $data${i}`;
1078
+ case 'delete':
1079
+ return `DELETE $id${i}`;
1080
+ }
1081
+ });
1082
+ return { sql: stmts.join(';\n'), vars };
1083
+ }
1084
+ &nbsp;
1085
+ // ---- rollback ----------------------------------------------------------------
1086
+ &nbsp;
1087
+ export interface RevertPlan {
1088
+ tx: LocalTx | null;
1089
+ circuit: IngestRecord;
1090
+ revert: FailedMutationRow['revert'];
1091
+ }
1092
+ &nbsp;
1093
+ /**
1094
+ * How to undo a rejected mutation locally. A create is deleted; an update or
1095
+ * delete is restored from `beforeRecord` (REPLACE, so the pre-bump `_00_rv`
1096
+ * comes back). Without a `beforeRecord` nothing can be restored.
1097
+ */
1098
+ export function planRevert(row: PendingMutationRow, before: Record&lt;string, unknown&gt; | null): RevertPlan {
1099
+ const rid = parseRecordIdString(row.recordId);
1100
+ if (row.mutationType === 'create') {
1101
+ return {
1102
+ tx: { query: surql.seal&lt;unknown&gt;(surql.tx([surql.delete('id')])), vars: { id: rid } },
1103
+ circuit: { table: row.tableName, op: 'DELETE', id: row.recordId, record: row.data ?? {} },
1104
+ revert: 'full',
1105
+ };
1106
+ }
1107
+ if (!before) {
1108
+ return {
1109
+ tx: null,
1110
+ circuit: { table: row.tableName, op: 'UPDATE', id: row.recordId, record: {} },
1111
+ revert: 'partial',
1112
+ };
1113
+ }
1114
+ const { id: _id, ...content } = before;
1115
+ return {
1116
+ tx: { query: surql.seal&lt;unknown&gt;(surql.tx([surql.upsert('id', 'content')])), vars: { id: rid, content } },
1117
+ circuit: {
1118
+ table: row.tableName,
1119
+ op: row.mutationType === 'delete' ? 'CREATE' : 'UPDATE',
1120
+ id: row.recordId,
1121
+ record: { ...before, id: rid },
1122
+ },
1123
+ revert: 'full',
1124
+ };
1125
+ }
1126
+ &nbsp;
1127
+ export const failedRecordId = (mutationId: string): RecordId&lt;string&gt; =&gt;
1128
+ new RecordId(FAILED_TABLE, mutationId.slice(mutationId.indexOf(':') + 1));
1129
+ &nbsp;
1130
+ export function buildFailedRow(
1131
+ row: PendingMutationRow,
1132
+ error: { message: string; kind: 'application' | 'unreplayable' },
1133
+ before: Record&lt;string, unknown&gt; | null,
1134
+ attempts: number,
1135
+ now: number,
1136
+ revert: FailedMutationRow['revert']
1137
+ ): FailedMutationRow {
1138
+ return {
1139
+ id: row.id,
1140
+ mutationType: row.mutationType,
1141
+ recordId: row.recordId,
1142
+ tableName: row.tableName,
1143
+ data: row.data,
1144
+ beforeRecord: before,
1145
+ error,
1146
+ attempts,
1147
+ createdAt: row.createdAt,
1148
+ failedAt: now,
1149
+ revert,
1150
+ };
1151
+ }
1152
+ &nbsp;
1153
+ /** ONE transaction: write the tray row, delete the pending row. */
1154
+ export function moveToFailedTx(failed: FailedMutationRow): LocalTx {
1155
+ const { id: _id, ...content } = failed;
1156
+ return {
1157
+ query: surql.seal&lt;unknown&gt;(surql.tx([surql.create('fid', 'failed'), surql.delete('mid')])),
1158
+ vars: { fid: failedRecordId(failed.id), failed: content, mid: parseStoredRecordId(failed.id) },
1159
+ };
1160
+ }
1161
+ &nbsp;
1162
+ export const deletePendingRow = (mutationId: string): { sql: string; vars: Vars } =&gt; ({
1163
+ sql: 'DELETE $mid',
1164
+ vars: { mid: parseStoredRecordId(mutationId) },
1165
+ });
1166
+ &nbsp;
1167
+ export const deleteFailedRow = (mutationId: string): { sql: string; vars: Vars } =&gt; ({
1168
+ sql: 'DELETE $fid',
1169
+ vars: { fid: failedRecordId(mutationId) },
1170
+ });
1171
+ &nbsp;
1172
+ export function parseFailedRow(row: unknown): FailedMutationRow | null {
1173
+ if (!row || typeof row !== 'object') return null;
1174
+ const r = row as Record&lt;string, unknown&gt;;
1175
+ const type = r.mutationType;
1176
+ if (type !== 'create' &amp;&amp; type !== 'update' &amp;&amp; type !== 'delete') return null;
1177
+ if (typeof r.recordId !== 'string') return null;
1178
+ const err = (r.error ?? {}) as Record&lt;string, unknown&gt;;
1179
+ return {
1180
+ id: storedIdString(r.id).replace(`${FAILED_TABLE}:`, `${PENDING_TABLE}:`),
1181
+ mutationType: type,
1182
+ recordId: r.recordId,
1183
+ tableName: typeof r.tableName === 'string' ? r.tableName : extractTablePart(r.recordId),
1184
+ data: r.data &amp;&amp; typeof r.data === 'object' ? (r.data as Record&lt;string, unknown&gt;) : undefined,
1185
+ beforeRecord:
1186
+ r.beforeRecord &amp;&amp; typeof r.beforeRecord === 'object' ? (r.beforeRecord as Record&lt;string, unknown&gt;) : null,
1187
+ error: {
1188
+ message: typeof err.message === 'string' ? err.message : 'unknown',
1189
+ kind: err.kind === 'unreplayable' ? 'unreplayable' : 'application',
1190
+ },
1191
+ attempts: typeof r.attempts === 'number' ? r.attempts : 0,
1192
+ createdAt: typeof r.createdAt === 'number' ? r.createdAt : 0,
1193
+ failedAt: typeof r.failedAt === 'number' ? r.failedAt : 0,
1194
+ revert: r.revert === 'partial' || r.revert === 'none' ? r.revert : 'full',
1195
+ };
1196
+ }
1197
+ &nbsp;</pre></td></tr></table></pre>
1198
+
1199
+ <div class='push'></div><!-- for sticky footer -->
1200
+ </div><!-- /wrapper -->
1201
+ <div class='footer quiet pad2 space-top1 center small'>
1202
+ Code coverage generated by
1203
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1204
+ at 2026-09-09T09:49:51.780Z
1205
+ </div>
1206
+ <script src="../../prettify.js"></script>
1207
+ <script>
1208
+ window.onload = function () {
1209
+ prettyPrint();
1210
+ };
1211
+ </script>
1212
+ <script src="../../sorter.js"></script>
1213
+ <script src="../../block-navigation.js"></script>
1214
+ </body>
1215
+ </html>
1216
+