@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.
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +476 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/boot/auth-flip.saga.ts.html +271 -0
- package/coverage/lcov-report/src/boot/boot.saga.ts.html +469 -0
- package/coverage/lcov-report/src/boot/bucket-switch.saga.ts.html +430 -0
- package/coverage/lcov-report/src/boot/index.html +161 -0
- package/coverage/lcov-report/src/boot/preload.saga.ts.html +178 -0
- package/coverage/lcov-report/src/client/bucket-handle.ts.html +766 -0
- package/coverage/lcov-report/src/client/index.html +161 -0
- package/coverage/lcov-report/src/client/router.ts.html +367 -0
- package/coverage/lcov-report/src/client/runtime.ts.html +940 -0
- package/coverage/lcov-report/src/client/sp00ky-client.ts.html +1531 -0
- package/coverage/lcov-report/src/events/index.html +116 -0
- package/coverage/lcov-report/src/events/index.ts.html +877 -0
- package/coverage/lcov-report/src/index.html +146 -0
- package/coverage/lcov-report/src/index.ts.html +202 -0
- package/coverage/lcov-report/src/kernel/constants.ts.html +247 -0
- package/coverage/lcov-report/src/kernel/effects.ts.html +562 -0
- package/coverage/lcov-report/src/kernel/events.ts.html +250 -0
- package/coverage/lcov-report/src/kernel/index.html +176 -0
- package/coverage/lcov-report/src/kernel/interpreter.ts.html +514 -0
- package/coverage/lcov-report/src/kernel/saga.ts.html +304 -0
- package/coverage/lcov-report/src/modules/app-release/index.html +116 -0
- package/coverage/lcov-report/src/modules/app-release/index.ts.html +712 -0
- package/coverage/lcov-report/src/modules/auth/events/index.html +116 -0
- package/coverage/lcov-report/src/modules/auth/events/index.ts.html +142 -0
- package/coverage/lcov-report/src/modules/auth/index.html +116 -0
- package/coverage/lcov-report/src/modules/auth/index.ts.html +1225 -0
- package/coverage/lcov-report/src/modules/crdt/crdt-field.ts.html +967 -0
- package/coverage/lcov-report/src/modules/crdt/index.html +146 -0
- package/coverage/lcov-report/src/modules/crdt/index.ts.html +1474 -0
- package/coverage/lcov-report/src/modules/crdt/loro-loader.ts.html +160 -0
- package/coverage/lcov-report/src/modules/devtools/flags.ts.html +1132 -0
- package/coverage/lcov-report/src/modules/devtools/index.html +161 -0
- package/coverage/lcov-report/src/modules/devtools/index.ts.html +2413 -0
- package/coverage/lcov-report/src/modules/devtools/storage-info.ts.html +589 -0
- package/coverage/lcov-report/src/modules/devtools/versions.ts.html +415 -0
- package/coverage/lcov-report/src/modules/feature-flag/index.html +116 -0
- package/coverage/lcov-report/src/modules/feature-flag/index.ts.html +1033 -0
- package/coverage/lcov-report/src/modules/index.html +116 -0
- package/coverage/lcov-report/src/modules/ref-tables.ts.html +349 -0
- package/coverage/lcov-report/src/mutation/index.html +191 -0
- package/coverage/lcov-report/src/mutation/jobs.ts.html +208 -0
- package/coverage/lcov-report/src/mutation/mutation-id.ts.html +190 -0
- package/coverage/lcov-report/src/mutation/push.saga.ts.html +730 -0
- package/coverage/lcov-report/src/mutation/rows.ts.html +1216 -0
- package/coverage/lcov-report/src/mutation/tray.saga.ts.html +229 -0
- package/coverage/lcov-report/src/mutation/write.saga.ts.html +583 -0
- package/coverage/lcov-report/src/otel/index.html +116 -0
- package/coverage/lcov-report/src/otel/index.ts.html +466 -0
- package/coverage/lcov-report/src/query/env.ts.html +253 -0
- package/coverage/lcov-report/src/query/fetch.saga.ts.html +412 -0
- package/coverage/lcov-report/src/query/hash.ts.html +139 -0
- package/coverage/lcov-report/src/query/index.html +281 -0
- package/coverage/lcov-report/src/query/lifecycle.saga.ts.html +388 -0
- package/coverage/lcov-report/src/query/materialize.saga.ts.html +310 -0
- package/coverage/lcov-report/src/query/materialize.ts.html +217 -0
- package/coverage/lcov-report/src/query/membership.saga.ts.html +709 -0
- package/coverage/lcov-report/src/query/membership.ts.html +559 -0
- package/coverage/lcov-report/src/query/register.saga.ts.html +655 -0
- package/coverage/lcov-report/src/query/render-set.ts.html +265 -0
- package/coverage/lcov-report/src/query/sql.ts.html +322 -0
- package/coverage/lcov-report/src/query/window-query.ts.html +670 -0
- package/coverage/lcov-report/src/services/blobs/blob-cache.ts.html +1894 -0
- package/coverage/lcov-report/src/services/blobs/blob-manifest.ts.html +766 -0
- package/coverage/lcov-report/src/services/blobs/blob-store.ts.html +1162 -0
- package/coverage/lcov-report/src/services/blobs/index.html +161 -0
- package/coverage/lcov-report/src/services/blobs/index.ts.html +295 -0
- package/coverage/lcov-report/src/services/database/cache-engine.ts.html +664 -0
- package/coverage/lcov-report/src/services/database/connection-supervisor.ts.html +1330 -0
- package/coverage/lcov-report/src/services/database/database.ts.html +658 -0
- package/coverage/lcov-report/src/services/database/engine-factory.ts.html +184 -0
- package/coverage/lcov-report/src/services/database/errors.ts.html +187 -0
- package/coverage/lcov-report/src/services/database/events/index.html +116 -0
- package/coverage/lcov-report/src/services/database/events/index.ts.html +184 -0
- package/coverage/lcov-report/src/services/database/index.html +386 -0
- package/coverage/lcov-report/src/services/database/index.ts.html +121 -0
- package/coverage/lcov-report/src/services/database/local-migrator.ts.html +703 -0
- package/coverage/lcov-report/src/services/database/local.ts.html +1633 -0
- package/coverage/lcov-report/src/services/database/plan-render.ts.html +409 -0
- package/coverage/lcov-report/src/services/database/relation-resolver.ts.html +682 -0
- package/coverage/lcov-report/src/services/database/remote.ts.html +1036 -0
- package/coverage/lcov-report/src/services/database/sqlite-cache-engine.ts.html +4132 -0
- package/coverage/lcov-report/src/services/database/sqlite-lock-verify.ts.html +220 -0
- package/coverage/lcov-report/src/services/database/sqlite-open.ts.html +577 -0
- package/coverage/lcov-report/src/services/database/sqlite-plan-sql.ts.html +499 -0
- package/coverage/lcov-report/src/services/database/sqlite-select.ts.html +478 -0
- package/coverage/lcov-report/src/services/database/sqlite-transport.ts.html +757 -0
- package/coverage/lcov-report/src/services/database/surql-translate.ts.html +1333 -0
- package/coverage/lcov-report/src/services/database/surreal-cache-engine.ts.html +568 -0
- package/coverage/lcov-report/src/services/logger/index.html +116 -0
- package/coverage/lcov-report/src/services/logger/index.ts.html +154 -0
- package/coverage/lcov-report/src/services/persistence/index.html +146 -0
- package/coverage/lcov-report/src/services/persistence/localstorage.ts.html +163 -0
- package/coverage/lcov-report/src/services/persistence/resilient.ts.html +208 -0
- package/coverage/lcov-report/src/services/persistence/surrealdb.ts.html +271 -0
- package/coverage/lcov-report/src/services/stream-processor/index.html +146 -0
- package/coverage/lcov-report/src/services/stream-processor/index.ts.html +3313 -0
- package/coverage/lcov-report/src/services/stream-processor/permissions.ts.html +244 -0
- package/coverage/lcov-report/src/services/stream-processor/wasm-types.ts.html +346 -0
- package/coverage/lcov-report/src/services/tabs/broker-client.ts.html +934 -0
- package/coverage/lcov-report/src/services/tabs/coordinator.ts.html +1984 -0
- package/coverage/lcov-report/src/services/tabs/index.html +191 -0
- package/coverage/lcov-report/src/services/tabs/leader-locks.ts.html +310 -0
- package/coverage/lcov-report/src/services/tabs/protocol.ts.html +871 -0
- package/coverage/lcov-report/src/services/tabs/support.ts.html +193 -0
- package/coverage/lcov-report/src/services/tabs/tabs-broker-worker.ts.html +2005 -0
- package/coverage/lcov-report/src/sp00ky.ts.html +100 -0
- package/coverage/lcov-report/src/state/client-state.ts.html +637 -0
- package/coverage/lcov-report/src/state/index.html +161 -0
- package/coverage/lcov-report/src/state/lifecycle.ts.html +343 -0
- package/coverage/lcov-report/src/state/reducers.ts.html +1471 -0
- package/coverage/lcov-report/src/state/selectors.ts.html +637 -0
- package/coverage/lcov-report/src/sync/connection.saga.ts.html +343 -0
- package/coverage/lcov-report/src/sync/index.html +176 -0
- package/coverage/lcov-report/src/sync/live.saga.ts.html +232 -0
- package/coverage/lcov-report/src/sync/policy.ts.html +1606 -0
- package/coverage/lcov-report/src/sync/poll.saga.ts.html +193 -0
- package/coverage/lcov-report/src/sync/tabs.saga.ts.html +361 -0
- package/coverage/lcov-report/src/types.ts.html +2419 -0
- package/coverage/lcov-report/src/utils/blurhash.ts.html +355 -0
- package/coverage/lcov-report/src/utils/error-classification.ts.html +244 -0
- package/coverage/lcov-report/src/utils/index.html +191 -0
- package/coverage/lcov-report/src/utils/index.ts.html +820 -0
- package/coverage/lcov-report/src/utils/parser.ts.html +313 -0
- package/coverage/lcov-report/src/utils/semver.ts.html +175 -0
- package/coverage/lcov-report/src/utils/surql.ts.html +667 -0
- package/coverage/lcov.info +19079 -0
- package/dist/index.js +3 -3
- package/dist/sqlite-open.js +20 -1
- package/package.json +3 -3
- package/src/services/database/relation-resolver.test.ts +55 -1
- package/src/services/database/relation-resolver.ts +0 -0
|
@@ -0,0 +1,1633 @@
|
|
|
1
|
+
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<title>Code coverage report for src/services/database/local.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/services/database</a> local.ts</h1>
|
|
23
|
+
<div class='clearfix'>
|
|
24
|
+
|
|
25
|
+
<div class='fl pad1y space-right2'>
|
|
26
|
+
<span class="strong">8.23% </span>
|
|
27
|
+
<span class="quiet">Statements</span>
|
|
28
|
+
<span class='fraction'>29/352</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'>11/11</span>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<div class='fl pad1y space-right2'>
|
|
40
|
+
<span class="strong">30.76% </span>
|
|
41
|
+
<span class="quiet">Functions</span>
|
|
42
|
+
<span class='fraction'>4/13</span>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<div class='fl pad1y space-right2'>
|
|
47
|
+
<span class="strong">8.23% </span>
|
|
48
|
+
<span class="quiet">Lines</span>
|
|
49
|
+
<span class='fraction'>29/352</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 low'></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>
|
|
444
|
+
<a name='L379'></a><a href='#L379'>379</a>
|
|
445
|
+
<a name='L380'></a><a href='#L380'>380</a>
|
|
446
|
+
<a name='L381'></a><a href='#L381'>381</a>
|
|
447
|
+
<a name='L382'></a><a href='#L382'>382</a>
|
|
448
|
+
<a name='L383'></a><a href='#L383'>383</a>
|
|
449
|
+
<a name='L384'></a><a href='#L384'>384</a>
|
|
450
|
+
<a name='L385'></a><a href='#L385'>385</a>
|
|
451
|
+
<a name='L386'></a><a href='#L386'>386</a>
|
|
452
|
+
<a name='L387'></a><a href='#L387'>387</a>
|
|
453
|
+
<a name='L388'></a><a href='#L388'>388</a>
|
|
454
|
+
<a name='L389'></a><a href='#L389'>389</a>
|
|
455
|
+
<a name='L390'></a><a href='#L390'>390</a>
|
|
456
|
+
<a name='L391'></a><a href='#L391'>391</a>
|
|
457
|
+
<a name='L392'></a><a href='#L392'>392</a>
|
|
458
|
+
<a name='L393'></a><a href='#L393'>393</a>
|
|
459
|
+
<a name='L394'></a><a href='#L394'>394</a>
|
|
460
|
+
<a name='L395'></a><a href='#L395'>395</a>
|
|
461
|
+
<a name='L396'></a><a href='#L396'>396</a>
|
|
462
|
+
<a name='L397'></a><a href='#L397'>397</a>
|
|
463
|
+
<a name='L398'></a><a href='#L398'>398</a>
|
|
464
|
+
<a name='L399'></a><a href='#L399'>399</a>
|
|
465
|
+
<a name='L400'></a><a href='#L400'>400</a>
|
|
466
|
+
<a name='L401'></a><a href='#L401'>401</a>
|
|
467
|
+
<a name='L402'></a><a href='#L402'>402</a>
|
|
468
|
+
<a name='L403'></a><a href='#L403'>403</a>
|
|
469
|
+
<a name='L404'></a><a href='#L404'>404</a>
|
|
470
|
+
<a name='L405'></a><a href='#L405'>405</a>
|
|
471
|
+
<a name='L406'></a><a href='#L406'>406</a>
|
|
472
|
+
<a name='L407'></a><a href='#L407'>407</a>
|
|
473
|
+
<a name='L408'></a><a href='#L408'>408</a>
|
|
474
|
+
<a name='L409'></a><a href='#L409'>409</a>
|
|
475
|
+
<a name='L410'></a><a href='#L410'>410</a>
|
|
476
|
+
<a name='L411'></a><a href='#L411'>411</a>
|
|
477
|
+
<a name='L412'></a><a href='#L412'>412</a>
|
|
478
|
+
<a name='L413'></a><a href='#L413'>413</a>
|
|
479
|
+
<a name='L414'></a><a href='#L414'>414</a>
|
|
480
|
+
<a name='L415'></a><a href='#L415'>415</a>
|
|
481
|
+
<a name='L416'></a><a href='#L416'>416</a>
|
|
482
|
+
<a name='L417'></a><a href='#L417'>417</a>
|
|
483
|
+
<a name='L418'></a><a href='#L418'>418</a>
|
|
484
|
+
<a name='L419'></a><a href='#L419'>419</a>
|
|
485
|
+
<a name='L420'></a><a href='#L420'>420</a>
|
|
486
|
+
<a name='L421'></a><a href='#L421'>421</a>
|
|
487
|
+
<a name='L422'></a><a href='#L422'>422</a>
|
|
488
|
+
<a name='L423'></a><a href='#L423'>423</a>
|
|
489
|
+
<a name='L424'></a><a href='#L424'>424</a>
|
|
490
|
+
<a name='L425'></a><a href='#L425'>425</a>
|
|
491
|
+
<a name='L426'></a><a href='#L426'>426</a>
|
|
492
|
+
<a name='L427'></a><a href='#L427'>427</a>
|
|
493
|
+
<a name='L428'></a><a href='#L428'>428</a>
|
|
494
|
+
<a name='L429'></a><a href='#L429'>429</a>
|
|
495
|
+
<a name='L430'></a><a href='#L430'>430</a>
|
|
496
|
+
<a name='L431'></a><a href='#L431'>431</a>
|
|
497
|
+
<a name='L432'></a><a href='#L432'>432</a>
|
|
498
|
+
<a name='L433'></a><a href='#L433'>433</a>
|
|
499
|
+
<a name='L434'></a><a href='#L434'>434</a>
|
|
500
|
+
<a name='L435'></a><a href='#L435'>435</a>
|
|
501
|
+
<a name='L436'></a><a href='#L436'>436</a>
|
|
502
|
+
<a name='L437'></a><a href='#L437'>437</a>
|
|
503
|
+
<a name='L438'></a><a href='#L438'>438</a>
|
|
504
|
+
<a name='L439'></a><a href='#L439'>439</a>
|
|
505
|
+
<a name='L440'></a><a href='#L440'>440</a>
|
|
506
|
+
<a name='L441'></a><a href='#L441'>441</a>
|
|
507
|
+
<a name='L442'></a><a href='#L442'>442</a>
|
|
508
|
+
<a name='L443'></a><a href='#L443'>443</a>
|
|
509
|
+
<a name='L444'></a><a href='#L444'>444</a>
|
|
510
|
+
<a name='L445'></a><a href='#L445'>445</a>
|
|
511
|
+
<a name='L446'></a><a href='#L446'>446</a>
|
|
512
|
+
<a name='L447'></a><a href='#L447'>447</a>
|
|
513
|
+
<a name='L448'></a><a href='#L448'>448</a>
|
|
514
|
+
<a name='L449'></a><a href='#L449'>449</a>
|
|
515
|
+
<a name='L450'></a><a href='#L450'>450</a>
|
|
516
|
+
<a name='L451'></a><a href='#L451'>451</a>
|
|
517
|
+
<a name='L452'></a><a href='#L452'>452</a>
|
|
518
|
+
<a name='L453'></a><a href='#L453'>453</a>
|
|
519
|
+
<a name='L454'></a><a href='#L454'>454</a>
|
|
520
|
+
<a name='L455'></a><a href='#L455'>455</a>
|
|
521
|
+
<a name='L456'></a><a href='#L456'>456</a>
|
|
522
|
+
<a name='L457'></a><a href='#L457'>457</a>
|
|
523
|
+
<a name='L458'></a><a href='#L458'>458</a>
|
|
524
|
+
<a name='L459'></a><a href='#L459'>459</a>
|
|
525
|
+
<a name='L460'></a><a href='#L460'>460</a>
|
|
526
|
+
<a name='L461'></a><a href='#L461'>461</a>
|
|
527
|
+
<a name='L462'></a><a href='#L462'>462</a>
|
|
528
|
+
<a name='L463'></a><a href='#L463'>463</a>
|
|
529
|
+
<a name='L464'></a><a href='#L464'>464</a>
|
|
530
|
+
<a name='L465'></a><a href='#L465'>465</a>
|
|
531
|
+
<a name='L466'></a><a href='#L466'>466</a>
|
|
532
|
+
<a name='L467'></a><a href='#L467'>467</a>
|
|
533
|
+
<a name='L468'></a><a href='#L468'>468</a>
|
|
534
|
+
<a name='L469'></a><a href='#L469'>469</a>
|
|
535
|
+
<a name='L470'></a><a href='#L470'>470</a>
|
|
536
|
+
<a name='L471'></a><a href='#L471'>471</a>
|
|
537
|
+
<a name='L472'></a><a href='#L472'>472</a>
|
|
538
|
+
<a name='L473'></a><a href='#L473'>473</a>
|
|
539
|
+
<a name='L474'></a><a href='#L474'>474</a>
|
|
540
|
+
<a name='L475'></a><a href='#L475'>475</a>
|
|
541
|
+
<a name='L476'></a><a href='#L476'>476</a>
|
|
542
|
+
<a name='L477'></a><a href='#L477'>477</a>
|
|
543
|
+
<a name='L478'></a><a href='#L478'>478</a>
|
|
544
|
+
<a name='L479'></a><a href='#L479'>479</a>
|
|
545
|
+
<a name='L480'></a><a href='#L480'>480</a>
|
|
546
|
+
<a name='L481'></a><a href='#L481'>481</a>
|
|
547
|
+
<a name='L482'></a><a href='#L482'>482</a>
|
|
548
|
+
<a name='L483'></a><a href='#L483'>483</a>
|
|
549
|
+
<a name='L484'></a><a href='#L484'>484</a>
|
|
550
|
+
<a name='L485'></a><a href='#L485'>485</a>
|
|
551
|
+
<a name='L486'></a><a href='#L486'>486</a>
|
|
552
|
+
<a name='L487'></a><a href='#L487'>487</a>
|
|
553
|
+
<a name='L488'></a><a href='#L488'>488</a>
|
|
554
|
+
<a name='L489'></a><a href='#L489'>489</a>
|
|
555
|
+
<a name='L490'></a><a href='#L490'>490</a>
|
|
556
|
+
<a name='L491'></a><a href='#L491'>491</a>
|
|
557
|
+
<a name='L492'></a><a href='#L492'>492</a>
|
|
558
|
+
<a name='L493'></a><a href='#L493'>493</a>
|
|
559
|
+
<a name='L494'></a><a href='#L494'>494</a>
|
|
560
|
+
<a name='L495'></a><a href='#L495'>495</a>
|
|
561
|
+
<a name='L496'></a><a href='#L496'>496</a>
|
|
562
|
+
<a name='L497'></a><a href='#L497'>497</a>
|
|
563
|
+
<a name='L498'></a><a href='#L498'>498</a>
|
|
564
|
+
<a name='L499'></a><a href='#L499'>499</a>
|
|
565
|
+
<a name='L500'></a><a href='#L500'>500</a>
|
|
566
|
+
<a name='L501'></a><a href='#L501'>501</a>
|
|
567
|
+
<a name='L502'></a><a href='#L502'>502</a>
|
|
568
|
+
<a name='L503'></a><a href='#L503'>503</a>
|
|
569
|
+
<a name='L504'></a><a href='#L504'>504</a>
|
|
570
|
+
<a name='L505'></a><a href='#L505'>505</a>
|
|
571
|
+
<a name='L506'></a><a href='#L506'>506</a>
|
|
572
|
+
<a name='L507'></a><a href='#L507'>507</a>
|
|
573
|
+
<a name='L508'></a><a href='#L508'>508</a>
|
|
574
|
+
<a name='L509'></a><a href='#L509'>509</a>
|
|
575
|
+
<a name='L510'></a><a href='#L510'>510</a>
|
|
576
|
+
<a name='L511'></a><a href='#L511'>511</a>
|
|
577
|
+
<a name='L512'></a><a href='#L512'>512</a>
|
|
578
|
+
<a name='L513'></a><a href='#L513'>513</a>
|
|
579
|
+
<a name='L514'></a><a href='#L514'>514</a>
|
|
580
|
+
<a name='L515'></a><a href='#L515'>515</a>
|
|
581
|
+
<a name='L516'></a><a href='#L516'>516</a>
|
|
582
|
+
<a name='L517'></a><a href='#L517'>517</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
|
|
583
|
+
<span class="cline-any cline-neutral"> </span>
|
|
584
|
+
<span class="cline-any cline-neutral"> </span>
|
|
585
|
+
<span class="cline-any cline-neutral"> </span>
|
|
586
|
+
<span class="cline-any cline-neutral"> </span>
|
|
587
|
+
<span class="cline-any cline-neutral"> </span>
|
|
588
|
+
<span class="cline-any cline-neutral"> </span>
|
|
589
|
+
<span class="cline-any cline-neutral"> </span>
|
|
590
|
+
<span class="cline-any cline-neutral"> </span>
|
|
591
|
+
<span class="cline-any cline-neutral"> </span>
|
|
592
|
+
<span class="cline-any cline-neutral"> </span>
|
|
593
|
+
<span class="cline-any cline-neutral"> </span>
|
|
594
|
+
<span class="cline-any cline-neutral"> </span>
|
|
595
|
+
<span class="cline-any cline-neutral"> </span>
|
|
596
|
+
<span class="cline-any cline-yes">1x</span>
|
|
597
|
+
<span class="cline-any cline-yes">1x</span>
|
|
598
|
+
<span class="cline-any cline-no"> </span>
|
|
599
|
+
<span class="cline-any cline-no"> </span>
|
|
600
|
+
<span class="cline-any cline-no"> </span>
|
|
601
|
+
<span class="cline-any cline-yes">1x</span>
|
|
602
|
+
<span class="cline-any cline-neutral"> </span>
|
|
603
|
+
<span class="cline-any cline-neutral"> </span>
|
|
604
|
+
<span class="cline-any cline-neutral"> </span>
|
|
605
|
+
<span class="cline-any cline-yes">1x</span>
|
|
606
|
+
<span class="cline-any cline-yes">2x</span>
|
|
607
|
+
<span class="cline-any cline-yes">2x</span>
|
|
608
|
+
<span class="cline-any cline-neutral"> </span>
|
|
609
|
+
<span class="cline-any cline-neutral"> </span>
|
|
610
|
+
<span class="cline-any cline-yes">1x</span>
|
|
611
|
+
<span class="cline-any cline-yes">3x</span>
|
|
612
|
+
<span class="cline-any cline-yes">3x</span>
|
|
613
|
+
<span class="cline-any cline-neutral"> </span>
|
|
614
|
+
<span class="cline-any cline-neutral"> </span>
|
|
615
|
+
<span class="cline-any cline-yes">1x</span>
|
|
616
|
+
<span class="cline-any cline-yes">1x</span>
|
|
617
|
+
<span class="cline-any cline-no"> </span>
|
|
618
|
+
<span class="cline-any cline-no"> </span>
|
|
619
|
+
<span class="cline-any cline-no"> </span>
|
|
620
|
+
<span class="cline-any cline-neutral"> </span>
|
|
621
|
+
<span class="cline-any cline-no"> </span>
|
|
622
|
+
<span class="cline-any cline-no"> </span>
|
|
623
|
+
<span class="cline-any cline-no"> </span>
|
|
624
|
+
<span class="cline-any cline-neutral"> </span>
|
|
625
|
+
<span class="cline-any cline-no"> </span>
|
|
626
|
+
<span class="cline-any cline-no"> </span>
|
|
627
|
+
<span class="cline-any cline-yes">1x</span>
|
|
628
|
+
<span class="cline-any cline-neutral"> </span>
|
|
629
|
+
<span class="cline-any cline-neutral"> </span>
|
|
630
|
+
<span class="cline-any cline-neutral"> </span>
|
|
631
|
+
<span class="cline-any cline-neutral"> </span>
|
|
632
|
+
<span class="cline-any cline-neutral"> </span>
|
|
633
|
+
<span class="cline-any cline-neutral"> </span>
|
|
634
|
+
<span class="cline-any cline-neutral"> </span>
|
|
635
|
+
<span class="cline-any cline-neutral"> </span>
|
|
636
|
+
<span class="cline-any cline-no"> </span>
|
|
637
|
+
<span class="cline-any cline-no"> </span>
|
|
638
|
+
<span class="cline-any cline-no"> </span>
|
|
639
|
+
<span class="cline-any cline-neutral"> </span>
|
|
640
|
+
<span class="cline-any cline-neutral"> </span>
|
|
641
|
+
<span class="cline-any cline-neutral"> </span>
|
|
642
|
+
<span class="cline-any cline-neutral"> </span>
|
|
643
|
+
<span class="cline-any cline-neutral"> </span>
|
|
644
|
+
<span class="cline-any cline-neutral"> </span>
|
|
645
|
+
<span class="cline-any cline-no"> </span>
|
|
646
|
+
<span class="cline-any cline-no"> </span>
|
|
647
|
+
<span class="cline-any cline-no"> </span>
|
|
648
|
+
<span class="cline-any cline-no"> </span>
|
|
649
|
+
<span class="cline-any cline-no"> </span>
|
|
650
|
+
<span class="cline-any cline-no"> </span>
|
|
651
|
+
<span class="cline-any cline-no"> </span>
|
|
652
|
+
<span class="cline-any cline-no"> </span>
|
|
653
|
+
<span class="cline-any cline-no"> </span>
|
|
654
|
+
<span class="cline-any cline-no"> </span>
|
|
655
|
+
<span class="cline-any cline-no"> </span>
|
|
656
|
+
<span class="cline-any cline-no"> </span>
|
|
657
|
+
<span class="cline-any cline-no"> </span>
|
|
658
|
+
<span class="cline-any cline-no"> </span>
|
|
659
|
+
<span class="cline-any cline-no"> </span>
|
|
660
|
+
<span class="cline-any cline-no"> </span>
|
|
661
|
+
<span class="cline-any cline-no"> </span>
|
|
662
|
+
<span class="cline-any cline-no"> </span>
|
|
663
|
+
<span class="cline-any cline-no"> </span>
|
|
664
|
+
<span class="cline-any cline-no"> </span>
|
|
665
|
+
<span class="cline-any cline-no"> </span>
|
|
666
|
+
<span class="cline-any cline-no"> </span>
|
|
667
|
+
<span class="cline-any cline-no"> </span>
|
|
668
|
+
<span class="cline-any cline-no"> </span>
|
|
669
|
+
<span class="cline-any cline-neutral"> </span>
|
|
670
|
+
<span class="cline-any cline-yes">1x</span>
|
|
671
|
+
<span class="cline-any cline-no"> </span>
|
|
672
|
+
<span class="cline-any cline-no"> </span>
|
|
673
|
+
<span class="cline-any cline-neutral"> </span>
|
|
674
|
+
<span class="cline-any cline-neutral"> </span>
|
|
675
|
+
<span class="cline-any cline-no"> </span>
|
|
676
|
+
<span class="cline-any cline-neutral"> </span>
|
|
677
|
+
<span class="cline-any cline-neutral"> </span>
|
|
678
|
+
<span class="cline-any cline-neutral"> </span>
|
|
679
|
+
<span class="cline-any cline-neutral"> </span>
|
|
680
|
+
<span class="cline-any cline-neutral"> </span>
|
|
681
|
+
<span class="cline-any cline-neutral"> </span>
|
|
682
|
+
<span class="cline-any cline-neutral"> </span>
|
|
683
|
+
<span class="cline-any cline-no"> </span>
|
|
684
|
+
<span class="cline-any cline-neutral"> </span>
|
|
685
|
+
<span class="cline-any cline-no"> </span>
|
|
686
|
+
<span class="cline-any cline-neutral"> </span>
|
|
687
|
+
<span class="cline-any cline-no"> </span>
|
|
688
|
+
<span class="cline-any cline-neutral"> </span>
|
|
689
|
+
<span class="cline-any cline-no"> </span>
|
|
690
|
+
<span class="cline-any cline-no"> </span>
|
|
691
|
+
<span class="cline-any cline-neutral"> </span>
|
|
692
|
+
<span class="cline-any cline-neutral"> </span>
|
|
693
|
+
<span class="cline-any cline-no"> </span>
|
|
694
|
+
<span class="cline-any cline-no"> </span>
|
|
695
|
+
<span class="cline-any cline-no"> </span>
|
|
696
|
+
<span class="cline-any cline-no"> </span>
|
|
697
|
+
<span class="cline-any cline-neutral"> </span>
|
|
698
|
+
<span class="cline-any cline-no"> </span>
|
|
699
|
+
<span class="cline-any cline-no"> </span>
|
|
700
|
+
<span class="cline-any cline-no"> </span>
|
|
701
|
+
<span class="cline-any cline-neutral"> </span>
|
|
702
|
+
<span class="cline-any cline-no"> </span>
|
|
703
|
+
<span class="cline-any cline-no"> </span>
|
|
704
|
+
<span class="cline-any cline-no"> </span>
|
|
705
|
+
<span class="cline-any cline-neutral"> </span>
|
|
706
|
+
<span class="cline-any cline-no"> </span>
|
|
707
|
+
<span class="cline-any cline-no"> </span>
|
|
708
|
+
<span class="cline-any cline-no"> </span>
|
|
709
|
+
<span class="cline-any cline-neutral"> </span>
|
|
710
|
+
<span class="cline-any cline-no"> </span>
|
|
711
|
+
<span class="cline-any cline-no"> </span>
|
|
712
|
+
<span class="cline-any cline-no"> </span>
|
|
713
|
+
<span class="cline-any cline-neutral"> </span>
|
|
714
|
+
<span class="cline-any cline-neutral"> </span>
|
|
715
|
+
<span class="cline-any cline-neutral"> </span>
|
|
716
|
+
<span class="cline-any cline-neutral"> </span>
|
|
717
|
+
<span class="cline-any cline-neutral"> </span>
|
|
718
|
+
<span class="cline-any cline-neutral"> </span>
|
|
719
|
+
<span class="cline-any cline-neutral"> </span>
|
|
720
|
+
<span class="cline-any cline-neutral"> </span>
|
|
721
|
+
<span class="cline-any cline-no"> </span>
|
|
722
|
+
<span class="cline-any cline-no"> </span>
|
|
723
|
+
<span class="cline-any cline-no"> </span>
|
|
724
|
+
<span class="cline-any cline-no"> </span>
|
|
725
|
+
<span class="cline-any cline-no"> </span>
|
|
726
|
+
<span class="cline-any cline-no"> </span>
|
|
727
|
+
<span class="cline-any cline-no"> </span>
|
|
728
|
+
<span class="cline-any cline-neutral"> </span>
|
|
729
|
+
<span class="cline-any cline-no"> </span>
|
|
730
|
+
<span class="cline-any cline-no"> </span>
|
|
731
|
+
<span class="cline-any cline-no"> </span>
|
|
732
|
+
<span class="cline-any cline-no"> </span>
|
|
733
|
+
<span class="cline-any cline-no"> </span>
|
|
734
|
+
<span class="cline-any cline-no"> </span>
|
|
735
|
+
<span class="cline-any cline-neutral"> </span>
|
|
736
|
+
<span class="cline-any cline-neutral"> </span>
|
|
737
|
+
<span class="cline-any cline-neutral"> </span>
|
|
738
|
+
<span class="cline-any cline-no"> </span>
|
|
739
|
+
<span class="cline-any cline-no"> </span>
|
|
740
|
+
<span class="cline-any cline-no"> </span>
|
|
741
|
+
<span class="cline-any cline-no"> </span>
|
|
742
|
+
<span class="cline-any cline-no"> </span>
|
|
743
|
+
<span class="cline-any cline-neutral"> </span>
|
|
744
|
+
<span class="cline-any cline-no"> </span>
|
|
745
|
+
<span class="cline-any cline-no"> </span>
|
|
746
|
+
<span class="cline-any cline-no"> </span>
|
|
747
|
+
<span class="cline-any cline-no"> </span>
|
|
748
|
+
<span class="cline-any cline-no"> </span>
|
|
749
|
+
<span class="cline-any cline-no"> </span>
|
|
750
|
+
<span class="cline-any cline-no"> </span>
|
|
751
|
+
<span class="cline-any cline-no"> </span>
|
|
752
|
+
<span class="cline-any cline-neutral"> </span>
|
|
753
|
+
<span class="cline-any cline-neutral"> </span>
|
|
754
|
+
<span class="cline-any cline-neutral"> </span>
|
|
755
|
+
<span class="cline-any cline-no"> </span>
|
|
756
|
+
<span class="cline-any cline-no"> </span>
|
|
757
|
+
<span class="cline-any cline-no"> </span>
|
|
758
|
+
<span class="cline-any cline-neutral"> </span>
|
|
759
|
+
<span class="cline-any cline-no"> </span>
|
|
760
|
+
<span class="cline-any cline-no"> </span>
|
|
761
|
+
<span class="cline-any cline-no"> </span>
|
|
762
|
+
<span class="cline-any cline-no"> </span>
|
|
763
|
+
<span class="cline-any cline-no"> </span>
|
|
764
|
+
<span class="cline-any cline-no"> </span>
|
|
765
|
+
<span class="cline-any cline-no"> </span>
|
|
766
|
+
<span class="cline-any cline-no"> </span>
|
|
767
|
+
<span class="cline-any cline-no"> </span>
|
|
768
|
+
<span class="cline-any cline-neutral"> </span>
|
|
769
|
+
<span class="cline-any cline-no"> </span>
|
|
770
|
+
<span class="cline-any cline-neutral"> </span>
|
|
771
|
+
<span class="cline-any cline-neutral"> </span>
|
|
772
|
+
<span class="cline-any cline-neutral"> </span>
|
|
773
|
+
<span class="cline-any cline-no"> </span>
|
|
774
|
+
<span class="cline-any cline-no"> </span>
|
|
775
|
+
<span class="cline-any cline-no"> </span>
|
|
776
|
+
<span class="cline-any cline-neutral"> </span>
|
|
777
|
+
<span class="cline-any cline-neutral"> </span>
|
|
778
|
+
<span class="cline-any cline-neutral"> </span>
|
|
779
|
+
<span class="cline-any cline-neutral"> </span>
|
|
780
|
+
<span class="cline-any cline-neutral"> </span>
|
|
781
|
+
<span class="cline-any cline-neutral"> </span>
|
|
782
|
+
<span class="cline-any cline-neutral"> </span>
|
|
783
|
+
<span class="cline-any cline-neutral"> </span>
|
|
784
|
+
<span class="cline-any cline-neutral"> </span>
|
|
785
|
+
<span class="cline-any cline-neutral"> </span>
|
|
786
|
+
<span class="cline-any cline-neutral"> </span>
|
|
787
|
+
<span class="cline-any cline-no"> </span>
|
|
788
|
+
<span class="cline-any cline-no"> </span>
|
|
789
|
+
<span class="cline-any cline-no"> </span>
|
|
790
|
+
<span class="cline-any cline-no"> </span>
|
|
791
|
+
<span class="cline-any cline-no"> </span>
|
|
792
|
+
<span class="cline-any cline-neutral"> </span>
|
|
793
|
+
<span class="cline-any cline-no"> </span>
|
|
794
|
+
<span class="cline-any cline-neutral"> </span>
|
|
795
|
+
<span class="cline-any cline-neutral"> </span>
|
|
796
|
+
<span class="cline-any cline-no"> </span>
|
|
797
|
+
<span class="cline-any cline-no"> </span>
|
|
798
|
+
<span class="cline-any cline-no"> </span>
|
|
799
|
+
<span class="cline-any cline-neutral"> </span>
|
|
800
|
+
<span class="cline-any cline-no"> </span>
|
|
801
|
+
<span class="cline-any cline-no"> </span>
|
|
802
|
+
<span class="cline-any cline-no"> </span>
|
|
803
|
+
<span class="cline-any cline-no"> </span>
|
|
804
|
+
<span class="cline-any cline-no"> </span>
|
|
805
|
+
<span class="cline-any cline-no"> </span>
|
|
806
|
+
<span class="cline-any cline-no"> </span>
|
|
807
|
+
<span class="cline-any cline-no"> </span>
|
|
808
|
+
<span class="cline-any cline-no"> </span>
|
|
809
|
+
<span class="cline-any cline-neutral"> </span>
|
|
810
|
+
<span class="cline-any cline-no"> </span>
|
|
811
|
+
<span class="cline-any cline-no"> </span>
|
|
812
|
+
<span class="cline-any cline-no"> </span>
|
|
813
|
+
<span class="cline-any cline-no"> </span>
|
|
814
|
+
<span class="cline-any cline-no"> </span>
|
|
815
|
+
<span class="cline-any cline-no"> </span>
|
|
816
|
+
<span class="cline-any cline-no"> </span>
|
|
817
|
+
<span class="cline-any cline-no"> </span>
|
|
818
|
+
<span class="cline-any cline-no"> </span>
|
|
819
|
+
<span class="cline-any cline-no"> </span>
|
|
820
|
+
<span class="cline-any cline-no"> </span>
|
|
821
|
+
<span class="cline-any cline-no"> </span>
|
|
822
|
+
<span class="cline-any cline-no"> </span>
|
|
823
|
+
<span class="cline-any cline-no"> </span>
|
|
824
|
+
<span class="cline-any cline-neutral"> </span>
|
|
825
|
+
<span class="cline-any cline-no"> </span>
|
|
826
|
+
<span class="cline-any cline-no"> </span>
|
|
827
|
+
<span class="cline-any cline-no"> </span>
|
|
828
|
+
<span class="cline-any cline-no"> </span>
|
|
829
|
+
<span class="cline-any cline-no"> </span>
|
|
830
|
+
<span class="cline-any cline-no"> </span>
|
|
831
|
+
<span class="cline-any cline-neutral"> </span>
|
|
832
|
+
<span class="cline-any cline-no"> </span>
|
|
833
|
+
<span class="cline-any cline-no"> </span>
|
|
834
|
+
<span class="cline-any cline-no"> </span>
|
|
835
|
+
<span class="cline-any cline-no"> </span>
|
|
836
|
+
<span class="cline-any cline-no"> </span>
|
|
837
|
+
<span class="cline-any cline-no"> </span>
|
|
838
|
+
<span class="cline-any cline-neutral"> </span>
|
|
839
|
+
<span class="cline-any cline-neutral"> </span>
|
|
840
|
+
<span class="cline-any cline-neutral"> </span>
|
|
841
|
+
<span class="cline-any cline-neutral"> </span>
|
|
842
|
+
<span class="cline-any cline-neutral"> </span>
|
|
843
|
+
<span class="cline-any cline-neutral"> </span>
|
|
844
|
+
<span class="cline-any cline-neutral"> </span>
|
|
845
|
+
<span class="cline-any cline-neutral"> </span>
|
|
846
|
+
<span class="cline-any cline-neutral"> </span>
|
|
847
|
+
<span class="cline-any cline-no"> </span>
|
|
848
|
+
<span class="cline-any cline-no"> </span>
|
|
849
|
+
<span class="cline-any cline-no"> </span>
|
|
850
|
+
<span class="cline-any cline-no"> </span>
|
|
851
|
+
<span class="cline-any cline-no"> </span>
|
|
852
|
+
<span class="cline-any cline-no"> </span>
|
|
853
|
+
<span class="cline-any cline-no"> </span>
|
|
854
|
+
<span class="cline-any cline-no"> </span>
|
|
855
|
+
<span class="cline-any cline-no"> </span>
|
|
856
|
+
<span class="cline-any cline-no"> </span>
|
|
857
|
+
<span class="cline-any cline-no"> </span>
|
|
858
|
+
<span class="cline-any cline-no"> </span>
|
|
859
|
+
<span class="cline-any cline-no"> </span>
|
|
860
|
+
<span class="cline-any cline-no"> </span>
|
|
861
|
+
<span class="cline-any cline-no"> </span>
|
|
862
|
+
<span class="cline-any cline-no"> </span>
|
|
863
|
+
<span class="cline-any cline-neutral"> </span>
|
|
864
|
+
<span class="cline-any cline-neutral"> </span>
|
|
865
|
+
<span class="cline-any cline-neutral"> </span>
|
|
866
|
+
<span class="cline-any cline-neutral"> </span>
|
|
867
|
+
<span class="cline-any cline-no"> </span>
|
|
868
|
+
<span class="cline-any cline-no"> </span>
|
|
869
|
+
<span class="cline-any cline-no"> </span>
|
|
870
|
+
<span class="cline-any cline-no"> </span>
|
|
871
|
+
<span class="cline-any cline-no"> </span>
|
|
872
|
+
<span class="cline-any cline-no"> </span>
|
|
873
|
+
<span class="cline-any cline-no"> </span>
|
|
874
|
+
<span class="cline-any cline-no"> </span>
|
|
875
|
+
<span class="cline-any cline-no"> </span>
|
|
876
|
+
<span class="cline-any cline-no"> </span>
|
|
877
|
+
<span class="cline-any cline-no"> </span>
|
|
878
|
+
<span class="cline-any cline-no"> </span>
|
|
879
|
+
<span class="cline-any cline-neutral"> </span>
|
|
880
|
+
<span class="cline-any cline-neutral"> </span>
|
|
881
|
+
<span class="cline-any cline-neutral"> </span>
|
|
882
|
+
<span class="cline-any cline-neutral"> </span>
|
|
883
|
+
<span class="cline-any cline-neutral"> </span>
|
|
884
|
+
<span class="cline-any cline-neutral"> </span>
|
|
885
|
+
<span class="cline-any cline-neutral"> </span>
|
|
886
|
+
<span class="cline-any cline-no"> </span>
|
|
887
|
+
<span class="cline-any cline-no"> </span>
|
|
888
|
+
<span class="cline-any cline-no"> </span>
|
|
889
|
+
<span class="cline-any cline-no"> </span>
|
|
890
|
+
<span class="cline-any cline-neutral"> </span>
|
|
891
|
+
<span class="cline-any cline-no"> </span>
|
|
892
|
+
<span class="cline-any cline-no"> </span>
|
|
893
|
+
<span class="cline-any cline-no"> </span>
|
|
894
|
+
<span class="cline-any cline-no"> </span>
|
|
895
|
+
<span class="cline-any cline-no"> </span>
|
|
896
|
+
<span class="cline-any cline-no"> </span>
|
|
897
|
+
<span class="cline-any cline-no"> </span>
|
|
898
|
+
<span class="cline-any cline-no"> </span>
|
|
899
|
+
<span class="cline-any cline-no"> </span>
|
|
900
|
+
<span class="cline-any cline-no"> </span>
|
|
901
|
+
<span class="cline-any cline-no"> </span>
|
|
902
|
+
<span class="cline-any cline-no"> </span>
|
|
903
|
+
<span class="cline-any cline-no"> </span>
|
|
904
|
+
<span class="cline-any cline-no"> </span>
|
|
905
|
+
<span class="cline-any cline-no"> </span>
|
|
906
|
+
<span class="cline-any cline-no"> </span>
|
|
907
|
+
<span class="cline-any cline-neutral"> </span>
|
|
908
|
+
<span class="cline-any cline-neutral"> </span>
|
|
909
|
+
<span class="cline-any cline-neutral"> </span>
|
|
910
|
+
<span class="cline-any cline-neutral"> </span>
|
|
911
|
+
<span class="cline-any cline-no"> </span>
|
|
912
|
+
<span class="cline-any cline-no"> </span>
|
|
913
|
+
<span class="cline-any cline-no"> </span>
|
|
914
|
+
<span class="cline-any cline-neutral"> </span>
|
|
915
|
+
<span class="cline-any cline-no"> </span>
|
|
916
|
+
<span class="cline-any cline-no"> </span>
|
|
917
|
+
<span class="cline-any cline-neutral"> </span>
|
|
918
|
+
<span class="cline-any cline-no"> </span>
|
|
919
|
+
<span class="cline-any cline-no"> </span>
|
|
920
|
+
<span class="cline-any cline-no"> </span>
|
|
921
|
+
<span class="cline-any cline-no"> </span>
|
|
922
|
+
<span class="cline-any cline-no"> </span>
|
|
923
|
+
<span class="cline-any cline-no"> </span>
|
|
924
|
+
<span class="cline-any cline-no"> </span>
|
|
925
|
+
<span class="cline-any cline-neutral"> </span>
|
|
926
|
+
<span class="cline-any cline-neutral"> </span>
|
|
927
|
+
<span class="cline-any cline-neutral"> </span>
|
|
928
|
+
<span class="cline-any cline-no"> </span>
|
|
929
|
+
<span class="cline-any cline-no"> </span>
|
|
930
|
+
<span class="cline-any cline-no"> </span>
|
|
931
|
+
<span class="cline-any cline-no"> </span>
|
|
932
|
+
<span class="cline-any cline-no"> </span>
|
|
933
|
+
<span class="cline-any cline-no"> </span>
|
|
934
|
+
<span class="cline-any cline-no"> </span>
|
|
935
|
+
<span class="cline-any cline-neutral"> </span>
|
|
936
|
+
<span class="cline-any cline-no"> </span>
|
|
937
|
+
<span class="cline-any cline-no"> </span>
|
|
938
|
+
<span class="cline-any cline-no"> </span>
|
|
939
|
+
<span class="cline-any cline-no"> </span>
|
|
940
|
+
<span class="cline-any cline-no"> </span>
|
|
941
|
+
<span class="cline-any cline-no"> </span>
|
|
942
|
+
<span class="cline-any cline-no"> </span>
|
|
943
|
+
<span class="cline-any cline-no"> </span>
|
|
944
|
+
<span class="cline-any cline-neutral"> </span>
|
|
945
|
+
<span class="cline-any cline-no"> </span>
|
|
946
|
+
<span class="cline-any cline-neutral"> </span>
|
|
947
|
+
<span class="cline-any cline-neutral"> </span>
|
|
948
|
+
<span class="cline-any cline-neutral"> </span>
|
|
949
|
+
<span class="cline-any cline-neutral"> </span>
|
|
950
|
+
<span class="cline-any cline-neutral"> </span>
|
|
951
|
+
<span class="cline-any cline-neutral"> </span>
|
|
952
|
+
<span class="cline-any cline-neutral"> </span>
|
|
953
|
+
<span class="cline-any cline-neutral"> </span>
|
|
954
|
+
<span class="cline-any cline-neutral"> </span>
|
|
955
|
+
<span class="cline-any cline-neutral"> </span>
|
|
956
|
+
<span class="cline-any cline-neutral"> </span>
|
|
957
|
+
<span class="cline-any cline-neutral"> </span>
|
|
958
|
+
<span class="cline-any cline-no"> </span>
|
|
959
|
+
<span class="cline-any cline-no"> </span>
|
|
960
|
+
<span class="cline-any cline-no"> </span>
|
|
961
|
+
<span class="cline-any cline-no"> </span>
|
|
962
|
+
<span class="cline-any cline-no"> </span>
|
|
963
|
+
<span class="cline-any cline-no"> </span>
|
|
964
|
+
<span class="cline-any cline-no"> </span>
|
|
965
|
+
<span class="cline-any cline-neutral"> </span>
|
|
966
|
+
<span class="cline-any cline-no"> </span>
|
|
967
|
+
<span class="cline-any cline-no"> </span>
|
|
968
|
+
<span class="cline-any cline-no"> </span>
|
|
969
|
+
<span class="cline-any cline-no"> </span>
|
|
970
|
+
<span class="cline-any cline-neutral"> </span>
|
|
971
|
+
<span class="cline-any cline-no"> </span>
|
|
972
|
+
<span class="cline-any cline-no"> </span>
|
|
973
|
+
<span class="cline-any cline-no"> </span>
|
|
974
|
+
<span class="cline-any cline-no"> </span>
|
|
975
|
+
<span class="cline-any cline-no"> </span>
|
|
976
|
+
<span class="cline-any cline-neutral"> </span>
|
|
977
|
+
<span class="cline-any cline-no"> </span>
|
|
978
|
+
<span class="cline-any cline-no"> </span>
|
|
979
|
+
<span class="cline-any cline-no"> </span>
|
|
980
|
+
<span class="cline-any cline-no"> </span>
|
|
981
|
+
<span class="cline-any cline-no"> </span>
|
|
982
|
+
<span class="cline-any cline-no"> </span>
|
|
983
|
+
<span class="cline-any cline-no"> </span>
|
|
984
|
+
<span class="cline-any cline-no"> </span>
|
|
985
|
+
<span class="cline-any cline-no"> </span>
|
|
986
|
+
<span class="cline-any cline-no"> </span>
|
|
987
|
+
<span class="cline-any cline-no"> </span>
|
|
988
|
+
<span class="cline-any cline-no"> </span>
|
|
989
|
+
<span class="cline-any cline-no"> </span>
|
|
990
|
+
<span class="cline-any cline-no"> </span>
|
|
991
|
+
<span class="cline-any cline-no"> </span>
|
|
992
|
+
<span class="cline-any cline-no"> </span>
|
|
993
|
+
<span class="cline-any cline-no"> </span>
|
|
994
|
+
<span class="cline-any cline-no"> </span>
|
|
995
|
+
<span class="cline-any cline-no"> </span>
|
|
996
|
+
<span class="cline-any cline-no"> </span>
|
|
997
|
+
<span class="cline-any cline-no"> </span>
|
|
998
|
+
<span class="cline-any cline-no"> </span>
|
|
999
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1000
|
+
<span class="cline-any cline-no"> </span>
|
|
1001
|
+
<span class="cline-any cline-no"> </span>
|
|
1002
|
+
<span class="cline-any cline-no"> </span>
|
|
1003
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1004
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1005
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1006
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1007
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1008
|
+
<span class="cline-any cline-yes">10x</span>
|
|
1009
|
+
<span class="cline-any cline-yes">10x</span>
|
|
1010
|
+
<span class="cline-any cline-yes">10x</span>
|
|
1011
|
+
<span class="cline-any cline-yes">7x</span>
|
|
1012
|
+
<span class="cline-any cline-yes">6x</span>
|
|
1013
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1014
|
+
<span class="cline-any cline-yes">10x</span>
|
|
1015
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1016
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1017
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1018
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1019
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1020
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1021
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1022
|
+
<span class="cline-any cline-no"> </span>
|
|
1023
|
+
<span class="cline-any cline-no"> </span>
|
|
1024
|
+
<span class="cline-any cline-no"> </span>
|
|
1025
|
+
<span class="cline-any cline-no"> </span>
|
|
1026
|
+
<span class="cline-any cline-no"> </span>
|
|
1027
|
+
<span class="cline-any cline-no"> </span>
|
|
1028
|
+
<span class="cline-any cline-no"> </span>
|
|
1029
|
+
<span class="cline-any cline-no"> </span>
|
|
1030
|
+
<span class="cline-any cline-no"> </span>
|
|
1031
|
+
<span class="cline-any cline-no"> </span>
|
|
1032
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1033
|
+
<span class="cline-any cline-no"> </span>
|
|
1034
|
+
<span class="cline-any cline-no"> </span>
|
|
1035
|
+
<span class="cline-any cline-no"> </span>
|
|
1036
|
+
<span class="cline-any cline-no"> </span>
|
|
1037
|
+
<span class="cline-any cline-no"> </span>
|
|
1038
|
+
<span class="cline-any cline-no"> </span>
|
|
1039
|
+
<span class="cline-any cline-no"> </span>
|
|
1040
|
+
<span class="cline-any cline-no"> </span>
|
|
1041
|
+
<span class="cline-any cline-no"> </span>
|
|
1042
|
+
<span class="cline-any cline-no"> </span>
|
|
1043
|
+
<span class="cline-any cline-no"> </span>
|
|
1044
|
+
<span class="cline-any cline-no"> </span>
|
|
1045
|
+
<span class="cline-any cline-no"> </span>
|
|
1046
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1047
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1048
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1049
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1050
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1051
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1052
|
+
<span class="cline-any cline-yes">8x</span>
|
|
1053
|
+
<span class="cline-any cline-yes">8x</span>
|
|
1054
|
+
<span class="cline-any cline-yes">8x</span>
|
|
1055
|
+
<span class="cline-any cline-yes">8x</span>
|
|
1056
|
+
<span class="cline-any cline-yes">5x</span>
|
|
1057
|
+
<span class="cline-any cline-yes">8x</span>
|
|
1058
|
+
<span class="cline-any cline-yes">8x</span>
|
|
1059
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1060
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1061
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1062
|
+
<span class="cline-any cline-no"> </span>
|
|
1063
|
+
<span class="cline-any cline-no"> </span>
|
|
1064
|
+
<span class="cline-any cline-no"> </span>
|
|
1065
|
+
<span class="cline-any cline-no"> </span>
|
|
1066
|
+
<span class="cline-any cline-no"> </span>
|
|
1067
|
+
<span class="cline-any cline-no"> </span>
|
|
1068
|
+
<span class="cline-any cline-no"> </span>
|
|
1069
|
+
<span class="cline-any cline-no"> </span>
|
|
1070
|
+
<span class="cline-any cline-no"> </span>
|
|
1071
|
+
<span class="cline-any cline-no"> </span>
|
|
1072
|
+
<span class="cline-any cline-no"> </span>
|
|
1073
|
+
<span class="cline-any cline-no"> </span>
|
|
1074
|
+
<span class="cline-any cline-no"> </span>
|
|
1075
|
+
<span class="cline-any cline-no"> </span>
|
|
1076
|
+
<span class="cline-any cline-no"> </span>
|
|
1077
|
+
<span class="cline-any cline-no"> </span>
|
|
1078
|
+
<span class="cline-any cline-no"> </span>
|
|
1079
|
+
<span class="cline-any cline-no"> </span>
|
|
1080
|
+
<span class="cline-any cline-no"> </span>
|
|
1081
|
+
<span class="cline-any cline-no"> </span>
|
|
1082
|
+
<span class="cline-any cline-no"> </span>
|
|
1083
|
+
<span class="cline-any cline-no"> </span>
|
|
1084
|
+
<span class="cline-any cline-no"> </span>
|
|
1085
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1086
|
+
<span class="cline-any cline-no"> </span>
|
|
1087
|
+
<span class="cline-any cline-no"> </span>
|
|
1088
|
+
<span class="cline-any cline-no"> </span>
|
|
1089
|
+
<span class="cline-any cline-no"> </span>
|
|
1090
|
+
<span class="cline-any cline-no"> </span>
|
|
1091
|
+
<span class="cline-any cline-no"> </span>
|
|
1092
|
+
<span class="cline-any cline-no"> </span>
|
|
1093
|
+
<span class="cline-any cline-no"> </span>
|
|
1094
|
+
<span class="cline-any cline-no"> </span>
|
|
1095
|
+
<span class="cline-any cline-no"> </span>
|
|
1096
|
+
<span class="cline-any cline-no"> </span>
|
|
1097
|
+
<span class="cline-any cline-no"> </span>
|
|
1098
|
+
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">import type { Diagnostic} from 'surrealdb';
|
|
1099
|
+
import { DEFAULT_LOCAL_OP_TIMEOUT_MS, LocalOpTimeoutError } from './errors';
|
|
1100
|
+
import { applyDiagnostics, DateTime, RecordId, Surreal } from 'surrealdb';
|
|
1101
|
+
import type { Sp00kyConfig } from '../../types';
|
|
1102
|
+
import type { Logger } from '../logger/index';
|
|
1103
|
+
import { AbstractDatabaseService } from './database';
|
|
1104
|
+
import { createDatabaseEventSystem, DatabaseEventTypes } from './events/index';
|
|
1105
|
+
import { encodeRecordId } from '../../utils/index';
|
|
1106
|
+
import { ANON_USER_ID } from '../../modules/ref-tables';
|
|
1107
|
+
import type { SealedQuery } from '../../utils/surql';
|
|
1108
|
+
|
|
1109
|
+
/** Thrown when a query carries an `epoch` from before a bucket switch. The
|
|
1110
|
+
* caller's chain read from the previous user's store; its write must be
|
|
1111
|
+
* dropped, not applied to the new bucket. */
|
|
1112
|
+
export class StaleEpochError extends Error {
|
|
1113
|
+
<span class="fstat-no" title="function not covered" > constructor() {</span>
|
|
1114
|
+
<span class="cstat-no" title="statement not covered" > super('Local store epoch changed (bucket switch); stale write dropped');</span>
|
|
1115
|
+
<span class="cstat-no" title="statement not covered" > this.name = 'StaleEpochError';</span>
|
|
1116
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/** Store URL for a local bucket. One IndexedDB store per user (`anon` for
|
|
1120
|
+
* signed-out) so cached rows never leak across accounts on a shared device. */
|
|
1121
|
+
export function bucketStoreUrl(bucketId: string): string {
|
|
1122
|
+
return `indxdb://${bucketStoreName(bucketId)}`;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/** The IndexedDB database name SurrealDB-WASM derives from the store URL. */
|
|
1126
|
+
export function bucketStoreName(bucketId: string): string {
|
|
1127
|
+
return `sp00ky-${bucketId}`;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
/** Shared codec: mirrors SurrealDB RecordId/DateTime into our own encodings. */
|
|
1131
|
+
const localCodecOptions = {
|
|
1132
|
+
<span class="fstat-no" title="function not covered" > valueDecodeVisitor(value: unknown) {</span>
|
|
1133
|
+
<span class="cstat-no" title="statement not covered" > if (value instanceof RecordId) {</span>
|
|
1134
|
+
<span class="cstat-no" title="statement not covered" > return encodeRecordId(value);</span>
|
|
1135
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1136
|
+
|
|
1137
|
+
<span class="cstat-no" title="statement not covered" > if (value instanceof DateTime) {</span>
|
|
1138
|
+
<span class="cstat-no" title="statement not covered" > return value.toDate();</span>
|
|
1139
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1140
|
+
|
|
1141
|
+
<span class="cstat-no" title="statement not covered" > return value;</span>
|
|
1142
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* Engine-less Surreal client used as the constructor placeholder. Building this
|
|
1147
|
+
* pulls in NO `@surrealdb/wasm` — the ~6 MB wasm engine is deferred to
|
|
1148
|
+
* {@link createLocalSurrealClient}, which runs lazily in `connect`/`switchStore`.
|
|
1149
|
+
* `connect()` replaces `this.client` with an engine-backed client before any
|
|
1150
|
+
* query runs, so this bare client is never actually opened against a store.
|
|
1151
|
+
*/
|
|
1152
|
+
<span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >function createBareSurrealClient(): Surreal {</span></span>
|
|
1153
|
+
<span class="cstat-no" title="statement not covered" > return new Surreal({ codecOptions: localCodecOptions });</span>
|
|
1154
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Engine-backed client. Dynamically imports `@surrealdb/wasm` so the wasm engine
|
|
1158
|
+
* only enters the graph as a separate chunk fetched on first connect (module-
|
|
1159
|
+
* cached thereafter — `switchStore`'s await is instant).
|
|
1160
|
+
*/
|
|
1161
|
+
<span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >async function createLocalSurrealClient(logger: Logger): Promise<Surreal> {</span></span>
|
|
1162
|
+
<span class="cstat-no" title="statement not covered" > const { createWasmWorkerEngines } = await import('@surrealdb/wasm');</span>
|
|
1163
|
+
<span class="cstat-no" title="statement not covered" > return new Surreal({</span>
|
|
1164
|
+
<span class="cstat-no" title="statement not covered" > codecOptions: localCodecOptions,</span>
|
|
1165
|
+
<span class="cstat-no" title="statement not covered" > engines: applyDiagnostics(</span>
|
|
1166
|
+
<span class="cstat-no" title="statement not covered" > createWasmWorkerEngines(),</span>
|
|
1167
|
+
<span class="cstat-no" title="statement not covered" > ({ key, type, phase, ...other }: Diagnostic) => {</span>
|
|
1168
|
+
<span class="cstat-no" title="statement not covered" > if (phase === 'progress' || phase === 'after') {</span>
|
|
1169
|
+
<span class="cstat-no" title="statement not covered" > logger.trace(</span>
|
|
1170
|
+
<span class="cstat-no" title="statement not covered" > {</span>
|
|
1171
|
+
<span class="cstat-no" title="statement not covered" > ...other,</span>
|
|
1172
|
+
<span class="cstat-no" title="statement not covered" > key,</span>
|
|
1173
|
+
<span class="cstat-no" title="statement not covered" > type,</span>
|
|
1174
|
+
<span class="cstat-no" title="statement not covered" > phase,</span>
|
|
1175
|
+
<span class="cstat-no" title="statement not covered" > service: 'surrealdb:local',</span>
|
|
1176
|
+
<span class="cstat-no" title="statement not covered" > Category: 'sp00ky-client::LocalDatabaseService::diagnostics',</span>
|
|
1177
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1178
|
+
<span class="cstat-no" title="statement not covered" > `Local SurrealDB diagnostics captured ${type}:${phase}`</span>
|
|
1179
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1180
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1181
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1182
|
+
<span class="cstat-no" title="statement not covered" > ),</span>
|
|
1183
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1184
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1185
|
+
|
|
1186
|
+
export class LocalDatabaseService extends AbstractDatabaseService <span class="fstat-no" title="function not covered" >{</span>
|
|
1187
|
+
<span class="cstat-no" title="statement not covered" > private config: Sp00kyConfig<any>['database'];</span>
|
|
1188
|
+
<span class="cstat-no" title="statement not covered" > protected eventType = DatabaseEventTypes.LocalQuery;</span>
|
|
1189
|
+
|
|
1190
|
+
/** Bucket currently open. Set by `connect`/`switchStore`. */
|
|
1191
|
+
<span class="cstat-no" title="statement not covered" > private bucketId: string = ANON_USER_ID;</span>
|
|
1192
|
+
/**
|
|
1193
|
+
* Monotonic store generation. Bumped on every `switchStore`. Async chains
|
|
1194
|
+
* that read from the store, await something remote, and then write back
|
|
1195
|
+
* (sync poll, SSP stream updates) capture this at chain start and drop
|
|
1196
|
+
* their write when it no longer matches — a stale-epoch write would land
|
|
1197
|
+
* another user's data in the new bucket.
|
|
1198
|
+
*/
|
|
1199
|
+
<span class="cstat-no" title="statement not covered" > private storeEpoch = 0;</span>
|
|
1200
|
+
/** Gate that `query()`/`execute()` await; closed for the switch window. */
|
|
1201
|
+
<span class="cstat-no" title="statement not covered" > private gate: Promise<void> = Promise.resolve();</span>
|
|
1202
|
+
/** The incoming client while a switch is in flight (for unload cleanup). */
|
|
1203
|
+
<span class="cstat-no" title="statement not covered" > private pendingSwitchClient: Surreal | null = null;</span>
|
|
1204
|
+
|
|
1205
|
+
<span class="cstat-no" title="statement not covered" > constructor(config: Sp00kyConfig<any>['database'], logger: Logger) {</span>
|
|
1206
|
+
<span class="cstat-no" title="statement not covered" > const events = createDatabaseEventSystem();</span>
|
|
1207
|
+
// Placeholder client with no wasm engine; `connect()` swaps in the real
|
|
1208
|
+
// engine-backed client (built lazily) before any query is issued.
|
|
1209
|
+
<span class="cstat-no" title="statement not covered" > super(createBareSurrealClient(), logger, events);</span>
|
|
1210
|
+
<span class="cstat-no" title="statement not covered" > this.config = config;</span>
|
|
1211
|
+
<span class="cstat-no" title="statement not covered" > this.queryTimeoutMs = Math.max(0, config.localOpTimeoutMs ?? DEFAULT_LOCAL_OP_TIMEOUT_MS);</span>
|
|
1212
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1213
|
+
|
|
1214
|
+
<span class="cstat-no" title="statement not covered" > protected override timeoutError(query: string): Error {</span>
|
|
1215
|
+
<span class="cstat-no" title="statement not covered" > return new LocalOpTimeoutError(query.slice(0, 80), this.queryTimeoutMs);</span>
|
|
1216
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1217
|
+
|
|
1218
|
+
<span class="cstat-no" title="statement not covered" > getConfig(): Sp00kyConfig<any>['database'] {</span>
|
|
1219
|
+
<span class="cstat-no" title="statement not covered" > return this.config;</span>
|
|
1220
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1221
|
+
|
|
1222
|
+
<span class="cstat-no" title="statement not covered" > get currentBucketId(): string {</span>
|
|
1223
|
+
<span class="cstat-no" title="statement not covered" > return this.bucketId;</span>
|
|
1224
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1225
|
+
|
|
1226
|
+
<span class="cstat-no" title="statement not covered" > get epoch(): number {</span>
|
|
1227
|
+
<span class="cstat-no" title="statement not covered" > return this.storeEpoch;</span>
|
|
1228
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Close the query gate for a bucket switch. Every `query()`/`execute()`
|
|
1232
|
+
* issued after this waits until the returned release fn runs — so work
|
|
1233
|
+
* triggered mid-switch (sibling auth subscribers registering queries)
|
|
1234
|
+
* lands on the NEW bucket instead of racing the swap. The migrator uses
|
|
1235
|
+
* `queryUngated()` to provision the new bucket while the gate is closed.
|
|
1236
|
+
*/
|
|
1237
|
+
<span class="cstat-no" title="statement not covered" > beginSwitch(): () => void {</span>
|
|
1238
|
+
<span class="cstat-no" title="statement not covered" > let release!: () => void;</span>
|
|
1239
|
+
<span class="cstat-no" title="statement not covered" > this.gate = new Promise<void>((resolve) => {</span>
|
|
1240
|
+
<span class="cstat-no" title="statement not covered" > release = resolve;</span>
|
|
1241
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1242
|
+
<span class="cstat-no" title="statement not covered" > return release;</span>
|
|
1243
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1244
|
+
|
|
1245
|
+
<span class="cstat-no" title="statement not covered" > override async query<T extends unknown[]>(</span>
|
|
1246
|
+
<span class="cstat-no" title="statement not covered" > query: string,</span>
|
|
1247
|
+
<span class="cstat-no" title="statement not covered" > vars?: Record<string, unknown>,</span>
|
|
1248
|
+
<span class="cstat-no" title="statement not covered" > opts?: { epoch?: number }</span>
|
|
1249
|
+
<span class="cstat-no" title="statement not covered" > ): Promise<T> {</span>
|
|
1250
|
+
<span class="cstat-no" title="statement not covered" > await this.gate;</span>
|
|
1251
|
+
// A write whose async chain started before a bucket switch must not land
|
|
1252
|
+
// in the new bucket — that would be another user's data. Callers on such
|
|
1253
|
+
// chains pass the epoch they captured at chain start; mismatches throw.
|
|
1254
|
+
<span class="cstat-no" title="statement not covered" > if (opts?.epoch !== undefined && opts.epoch !== this.storeEpoch) {</span>
|
|
1255
|
+
<span class="cstat-no" title="statement not covered" > throw new StaleEpochError();</span>
|
|
1256
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1257
|
+
<span class="cstat-no" title="statement not covered" > return super.query(query, vars);</span>
|
|
1258
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1259
|
+
|
|
1260
|
+
<span class="cstat-no" title="statement not covered" > override async execute<T>(</span>
|
|
1261
|
+
<span class="cstat-no" title="statement not covered" > query: SealedQuery<T>,</span>
|
|
1262
|
+
<span class="cstat-no" title="statement not covered" > vars?: Record<string, unknown>,</span>
|
|
1263
|
+
<span class="cstat-no" title="statement not covered" > opts?: { epoch?: number }</span>
|
|
1264
|
+
<span class="cstat-no" title="statement not covered" > ): Promise<T> {</span>
|
|
1265
|
+
<span class="cstat-no" title="statement not covered" > const raw = await this.query<unknown[]>(query.sql, vars, opts);</span>
|
|
1266
|
+
<span class="cstat-no" title="statement not covered" > return query.extract(raw);</span>
|
|
1267
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1268
|
+
|
|
1269
|
+
/** Gate-bypassing query — ONLY for the switch path itself (schema
|
|
1270
|
+
* provisioning must run while the gate is closed, or it deadlocks). */
|
|
1271
|
+
<span class="cstat-no" title="statement not covered" > queryUngated<T extends unknown[]>(query: string, vars?: Record<string, unknown>): Promise<T> {</span>
|
|
1272
|
+
<span class="cstat-no" title="statement not covered" > return super.query(query, vars);</span>
|
|
1273
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1274
|
+
|
|
1275
|
+
<span class="cstat-no" title="statement not covered" > async connect(bucketId: string = ANON_USER_ID): Promise<void> {</span>
|
|
1276
|
+
<span class="cstat-no" title="statement not covered" > const { namespace, database } = this.getConfig();</span>
|
|
1277
|
+
<span class="cstat-no" title="statement not covered" > const store = this.getConfig().store ?? 'memory';</span>
|
|
1278
|
+
<span class="cstat-no" title="statement not covered" > this.bucketId = bucketId;</span>
|
|
1279
|
+
<span class="cstat-no" title="statement not covered" > const storeUrl = store === 'memory' ? 'mem://' : bucketStoreUrl(bucketId);</span>
|
|
1280
|
+
<span class="cstat-no" title="statement not covered" > this.logger.info(</span>
|
|
1281
|
+
<span class="cstat-no" title="statement not covered" > { namespace, database, storeUrl, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1282
|
+
<span class="cstat-no" title="statement not covered" > 'Connecting to local database'</span>
|
|
1283
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1284
|
+
|
|
1285
|
+
<span class="cstat-no" title="statement not covered" > this.registerUnloadClose();</span>
|
|
1286
|
+
// Build the real engine-backed client lazily here (first `@surrealdb/wasm`
|
|
1287
|
+
// load), replacing the constructor's engine-less placeholder before any
|
|
1288
|
+
// query runs.
|
|
1289
|
+
<span class="cstat-no" title="statement not covered" > this.client = await createLocalSurrealClient(this.logger);</span>
|
|
1290
|
+
<span class="cstat-no" title="statement not covered" > await this.openWithRecovery(this.client, storeUrl, namespace, database, bucketId, store);</span>
|
|
1291
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Switch the local store to another user's bucket. Opens the NEW bucket on a
|
|
1295
|
+
* second client first (with the same 3-tier recovery), then atomically swaps
|
|
1296
|
+
* `this.client` and closes the old one — a failed open never leaves the
|
|
1297
|
+
* service on a dead client. Bumps the store epoch so in-flight old-bucket
|
|
1298
|
+
* async chains can detect they're stale.
|
|
1299
|
+
*
|
|
1300
|
+
* Callers own the drain/rebind choreography (close the gate, quiesce sync +
|
|
1301
|
+
* timers BEFORE calling this; re-provision + rebind AFTER).
|
|
1302
|
+
*/
|
|
1303
|
+
<span class="cstat-no" title="statement not covered" > async switchStore(bucketId: string): Promise<void> {</span>
|
|
1304
|
+
<span class="cstat-no" title="statement not covered" > if (bucketId === this.bucketId) return;</span>
|
|
1305
|
+
<span class="cstat-no" title="statement not covered" > const { namespace, database } = this.getConfig();</span>
|
|
1306
|
+
<span class="cstat-no" title="statement not covered" > const store = this.getConfig().store ?? 'memory';</span>
|
|
1307
|
+
<span class="cstat-no" title="statement not covered" > this.storeEpoch++;</span>
|
|
1308
|
+
|
|
1309
|
+
<span class="cstat-no" title="statement not covered" > if (store === 'memory') {</span>
|
|
1310
|
+
// mem:// has no per-user persistence; close + reopen the same client
|
|
1311
|
+
// yields a fresh empty store, which is exactly the reset we want.
|
|
1312
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1313
|
+
<span class="cstat-no" title="statement not covered" > await this.client.close();</span>
|
|
1314
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1315
|
+
/* ignore */
|
|
1316
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1317
|
+
<span class="cstat-no" title="statement not covered" > await this.openStore(this.client, 'mem://', namespace, database);</span>
|
|
1318
|
+
<span class="cstat-no" title="statement not covered" > this.bucketId = bucketId;</span>
|
|
1319
|
+
<span class="cstat-no" title="statement not covered" > this.logger.info(</span>
|
|
1320
|
+
<span class="cstat-no" title="statement not covered" > { bucketId, Category: 'sp00ky-client::LocalDatabaseService::switchStore' },</span>
|
|
1321
|
+
<span class="cstat-no" title="statement not covered" > 'Reset in-memory local store for bucket switch'</span>
|
|
1322
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1323
|
+
<span class="cstat-no" title="statement not covered" > return;</span>
|
|
1324
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1325
|
+
|
|
1326
|
+
<span class="cstat-no" title="statement not covered" > const next = await createLocalSurrealClient(this.logger);</span>
|
|
1327
|
+
<span class="cstat-no" title="statement not covered" > this.pendingSwitchClient = next;</span>
|
|
1328
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1329
|
+
<span class="cstat-no" title="statement not covered" > await this.openWithRecovery(</span>
|
|
1330
|
+
<span class="cstat-no" title="statement not covered" > next,</span>
|
|
1331
|
+
<span class="cstat-no" title="statement not covered" > bucketStoreUrl(bucketId),</span>
|
|
1332
|
+
<span class="cstat-no" title="statement not covered" > namespace,</span>
|
|
1333
|
+
<span class="cstat-no" title="statement not covered" > database,</span>
|
|
1334
|
+
<span class="cstat-no" title="statement not covered" > bucketId,</span>
|
|
1335
|
+
<span class="cstat-no" title="statement not covered" > store</span>
|
|
1336
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1337
|
+
<span class="cstat-no" title="statement not covered" > } finally {</span>
|
|
1338
|
+
<span class="cstat-no" title="statement not covered" > this.pendingSwitchClient = null;</span>
|
|
1339
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1340
|
+
|
|
1341
|
+
<span class="cstat-no" title="statement not covered" > const old = this.client;</span>
|
|
1342
|
+
<span class="cstat-no" title="statement not covered" > this.client = next;</span>
|
|
1343
|
+
<span class="cstat-no" title="statement not covered" > this.bucketId = bucketId;</span>
|
|
1344
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1345
|
+
<span class="cstat-no" title="statement not covered" > await old.close();</span>
|
|
1346
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1347
|
+
/* best-effort — the old store's handle is released on unload regardless */
|
|
1348
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1349
|
+
<span class="cstat-no" title="statement not covered" > this.logger.info(</span>
|
|
1350
|
+
<span class="cstat-no" title="statement not covered" > { bucketId, Category: 'sp00ky-client::LocalDatabaseService::switchStore' },</span>
|
|
1351
|
+
<span class="cstat-no" title="statement not covered" > 'Switched local store bucket'</span>
|
|
1352
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1353
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1354
|
+
|
|
1355
|
+
/**
|
|
1356
|
+
* Open `storeUrl` on `client` with tiered recovery:
|
|
1357
|
+
* tier 1 retries the same store (transient idb-handle races — preserves the
|
|
1358
|
+
* cache), tier 2 drops THIS bucket's IndexedDB store and reconnects fresh,
|
|
1359
|
+
* tier 3 falls back to `mem://` for the session. Only ever drops the bucket
|
|
1360
|
+
* being opened — other users' buckets hold their own caches AND un-pushed
|
|
1361
|
+
* mutation outboxes, which must survive another bucket's corruption.
|
|
1362
|
+
*/
|
|
1363
|
+
<span class="cstat-no" title="statement not covered" > private async openWithRecovery(</span>
|
|
1364
|
+
<span class="cstat-no" title="statement not covered" > client: Surreal,</span>
|
|
1365
|
+
<span class="cstat-no" title="statement not covered" > storeUrl: string,</span>
|
|
1366
|
+
<span class="cstat-no" title="statement not covered" > namespace: string,</span>
|
|
1367
|
+
<span class="cstat-no" title="statement not covered" > database: string,</span>
|
|
1368
|
+
<span class="cstat-no" title="statement not covered" > bucketId: string,</span>
|
|
1369
|
+
<span class="cstat-no" title="statement not covered" > store: string</span>
|
|
1370
|
+
<span class="cstat-no" title="statement not covered" > ): Promise<void> {</span>
|
|
1371
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1372
|
+
<span class="cstat-no" title="statement not covered" > await this.openStore(client, storeUrl, namespace, database);</span>
|
|
1373
|
+
<span class="cstat-no" title="statement not covered" > this.logger.info(</span>
|
|
1374
|
+
<span class="cstat-no" title="statement not covered" > { Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1375
|
+
<span class="cstat-no" title="statement not covered" > 'Connected to local database'</span>
|
|
1376
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1377
|
+
<span class="cstat-no" title="statement not covered" > return;</span>
|
|
1378
|
+
<span class="cstat-no" title="statement not covered" > } catch (err) {</span>
|
|
1379
|
+
// A persistent (IndexedDB) local store can fail to open if it was left
|
|
1380
|
+
// corrupt or version-incompatible by a prior session/crash/engine bump.
|
|
1381
|
+
// The local store is only a cache (everything re-syncs from the server),
|
|
1382
|
+
// so recover by dropping it and reconnecting rather than bricking startup.
|
|
1383
|
+
<span class="cstat-no" title="statement not covered" > if (store === 'memory' || !isLocalStoreOpenError(err)) {</span>
|
|
1384
|
+
<span class="cstat-no" title="statement not covered" > this.logger.error(</span>
|
|
1385
|
+
<span class="cstat-no" title="statement not covered" > { err, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1386
|
+
<span class="cstat-no" title="statement not covered" > 'Failed to connect to local database'</span>
|
|
1387
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1388
|
+
<span class="cstat-no" title="statement not covered" > throw err;</span>
|
|
1389
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1390
|
+
<span class="cstat-no" title="statement not covered" > this.logger.warn(</span>
|
|
1391
|
+
<span class="cstat-no" title="statement not covered" > { err, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1392
|
+
<span class="cstat-no" title="statement not covered" > 'Local IndexedDB store failed to open; retrying before clearing'</span>
|
|
1393
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1394
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1395
|
+
|
|
1396
|
+
// Tier 1 — RETRY the SAME store WITHOUT dropping. The idb open/`use` failure
|
|
1397
|
+
// is often transient (a not-yet-released handle from the previous page, or a
|
|
1398
|
+
// first-open WAL-recovery race), not real corruption. Closing and reopening
|
|
1399
|
+
// frequently succeeds — and crucially PRESERVES the cache, so a warm load
|
|
1400
|
+
// stays warm. Dropping the store every time (the old behavior) silently wiped
|
|
1401
|
+
// the cache on every reload, making warm loads as slow as cold ones.
|
|
1402
|
+
<span class="cstat-no" title="statement not covered" > for (let attempt = 1; attempt <= 2; attempt++) {</span>
|
|
1403
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1404
|
+
<span class="cstat-no" title="statement not covered" > await client.close();</span>
|
|
1405
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1406
|
+
/* ignore */
|
|
1407
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1408
|
+
<span class="cstat-no" title="statement not covered" > await delay(150 * attempt);</span>
|
|
1409
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1410
|
+
<span class="cstat-no" title="statement not covered" > await this.openStore(client, storeUrl, namespace, database);</span>
|
|
1411
|
+
<span class="cstat-no" title="statement not covered" > this.logger.info(</span>
|
|
1412
|
+
<span class="cstat-no" title="statement not covered" > { attempt, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1413
|
+
<span class="cstat-no" title="statement not covered" > 'Connected to local database on retry (cache preserved)'</span>
|
|
1414
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1415
|
+
<span class="cstat-no" title="statement not covered" > return;</span>
|
|
1416
|
+
<span class="cstat-no" title="statement not covered" > } catch (retryErr) {</span>
|
|
1417
|
+
<span class="cstat-no" title="statement not covered" > this.logger.warn(</span>
|
|
1418
|
+
<span class="cstat-no" title="statement not covered" > { err: retryErr, attempt, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1419
|
+
<span class="cstat-no" title="statement not covered" > 'Local store retry failed'</span>
|
|
1420
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1421
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1422
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1423
|
+
|
|
1424
|
+
// Tier 2 — the store is genuinely unopenable; drop THIS bucket and reconnect
|
|
1425
|
+
// fresh. This loses the bucket's cache (re-syncs from the server), so it's
|
|
1426
|
+
// the last resort before in-memory.
|
|
1427
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1428
|
+
<span class="cstat-no" title="statement not covered" > await client.close();</span>
|
|
1429
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1430
|
+
/* ignore — closing a half-open connection is best-effort */
|
|
1431
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1432
|
+
<span class="cstat-no" title="statement not covered" > await dropLocalIndexedDbStores(this.logger, bucketStoreName(bucketId));</span>
|
|
1433
|
+
|
|
1434
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1435
|
+
<span class="cstat-no" title="statement not covered" > await this.openStore(client, storeUrl, namespace, database);</span>
|
|
1436
|
+
<span class="cstat-no" title="statement not covered" > this.logger.info(</span>
|
|
1437
|
+
<span class="cstat-no" title="statement not covered" > { Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1438
|
+
<span class="cstat-no" title="statement not covered" > 'Reconnected to local database after clearing the corrupt store'</span>
|
|
1439
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1440
|
+
<span class="cstat-no" title="statement not covered" > } catch (retryErr) {</span>
|
|
1441
|
+
// Last resort: run in-memory so the app still loads. No local persistence
|
|
1442
|
+
// this session; the freshly-dropped IndexedDB is recreated cleanly next
|
|
1443
|
+
// load, and all data re-syncs from the server regardless.
|
|
1444
|
+
<span class="cstat-no" title="statement not covered" > this.logger.error(</span>
|
|
1445
|
+
<span class="cstat-no" title="statement not covered" > { err: retryErr, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1446
|
+
<span class="cstat-no" title="statement not covered" > 'Local store still failing after clear; falling back to in-memory'</span>
|
|
1447
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1448
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1449
|
+
<span class="cstat-no" title="statement not covered" > await client.close();</span>
|
|
1450
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1451
|
+
/* ignore */
|
|
1452
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1453
|
+
<span class="cstat-no" title="statement not covered" > await this.openStore(client, 'mem://', namespace, database);</span>
|
|
1454
|
+
<span class="cstat-no" title="statement not covered" > this.logger.warn(</span>
|
|
1455
|
+
<span class="cstat-no" title="statement not covered" > { Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1456
|
+
<span class="cstat-no" title="statement not covered" > 'Connected to local database (in-memory fallback)'</span>
|
|
1457
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1458
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1459
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1460
|
+
|
|
1461
|
+
<span class="cstat-no" title="statement not covered" > private unloadCloseRegistered = false;</span>
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* Close the local DB on page unload so the SurrealDB-WASM worker releases its
|
|
1465
|
+
* IndexedDB connection cleanly. Without this, the previous page's connection
|
|
1466
|
+
* lingers; the next load's `client.connect` opens the store but the first
|
|
1467
|
+
* write transaction in `client.use` hits an "IndexedDB error" — which then
|
|
1468
|
+
* (mis)triggered the corrupt-store recovery and WIPED the cache on every
|
|
1469
|
+
* reload, making warm loads as slow as cold ones. `pagehide` is the reliable
|
|
1470
|
+
* unload signal (fires on bfcache + normal navigation); `close()` is async but
|
|
1471
|
+
* the WASM worker initiates the IndexedDB connection teardown synchronously.
|
|
1472
|
+
* Also closes a mid-switch incoming client so its fresh handle doesn't linger.
|
|
1473
|
+
*/
|
|
1474
|
+
<span class="cstat-no" title="statement not covered" > private registerUnloadClose(): void {</span>
|
|
1475
|
+
<span class="cstat-no" title="statement not covered" > if (this.unloadCloseRegistered || typeof window === 'undefined') return;</span>
|
|
1476
|
+
<span class="cstat-no" title="statement not covered" > this.unloadCloseRegistered = true;</span>
|
|
1477
|
+
<span class="cstat-no" title="statement not covered" > const close = () => {</span>
|
|
1478
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1479
|
+
<span class="cstat-no" title="statement not covered" > void this.client.close();</span>
|
|
1480
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1481
|
+
/* best-effort */
|
|
1482
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1483
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1484
|
+
<span class="cstat-no" title="statement not covered" > void this.pendingSwitchClient?.close();</span>
|
|
1485
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1486
|
+
/* best-effort */
|
|
1487
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1488
|
+
<span class="cstat-no" title="statement not covered" > };</span>
|
|
1489
|
+
<span class="cstat-no" title="statement not covered" > window.addEventListener('pagehide', close);</span>
|
|
1490
|
+
<span class="cstat-no" title="statement not covered" > window.addEventListener('beforeunload', close);</span>
|
|
1491
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1492
|
+
|
|
1493
|
+
<span class="cstat-no" title="statement not covered" > private async openStore(</span>
|
|
1494
|
+
<span class="cstat-no" title="statement not covered" > client: Surreal,</span>
|
|
1495
|
+
<span class="cstat-no" title="statement not covered" > storeUrl: string,</span>
|
|
1496
|
+
<span class="cstat-no" title="statement not covered" > namespace: string,</span>
|
|
1497
|
+
<span class="cstat-no" title="statement not covered" > database: string</span>
|
|
1498
|
+
<span class="cstat-no" title="statement not covered" > ): Promise<void> {</span>
|
|
1499
|
+
<span class="cstat-no" title="statement not covered" > this.logger.debug(</span>
|
|
1500
|
+
<span class="cstat-no" title="statement not covered" > { storeUrl, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1501
|
+
<span class="cstat-no" title="statement not covered" > '[LocalDatabaseService] Calling client.connect'</span>
|
|
1502
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1503
|
+
<span class="cstat-no" title="statement not covered" > await client.connect(storeUrl, {});</span>
|
|
1504
|
+
<span class="cstat-no" title="statement not covered" > this.logger.debug(</span>
|
|
1505
|
+
<span class="cstat-no" title="statement not covered" > { namespace, database, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1506
|
+
<span class="cstat-no" title="statement not covered" > '[LocalDatabaseService] client.connect returned. Calling client.use'</span>
|
|
1507
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1508
|
+
<span class="cstat-no" title="statement not covered" > await client.use({ namespace, database });</span>
|
|
1509
|
+
<span class="cstat-no" title="statement not covered" > this.logger.debug(</span>
|
|
1510
|
+
<span class="cstat-no" title="statement not covered" > { Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1511
|
+
<span class="cstat-no" title="statement not covered" > '[LocalDatabaseService] client.use returned'</span>
|
|
1512
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1513
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1514
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1515
|
+
|
|
1516
|
+
<span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >function delay(ms: number): Promise<void> {</span></span>
|
|
1517
|
+
<span class="cstat-no" title="statement not covered" > return new Promise((resolve) => setTimeout(resolve, ms));</span>
|
|
1518
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1519
|
+
|
|
1520
|
+
/** True for the SurrealDB-WASM error raised when its IndexedDB-backed key-value
|
|
1521
|
+
* store can't be opened (corrupt / version-incompatible / blocked). Exported
|
|
1522
|
+
* for unit testing the error-message match. */
|
|
1523
|
+
export function isLocalStoreOpenError(err: unknown): boolean {
|
|
1524
|
+
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
1525
|
+
return (
|
|
1526
|
+
msg.includes('indexeddb') ||
|
|
1527
|
+
msg.includes('idb error') ||
|
|
1528
|
+
msg.includes('key-value store')
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
/** Best-effort delete of ONE bucket's IndexedDB store(s). SurrealDB-WASM backs
|
|
1533
|
+
* `indxdb://<name>` with one or more IndexedDB databases whose names include
|
|
1534
|
+
* `<name>`. Scoped to the given store name — never wipe by the bare `sp00ky`
|
|
1535
|
+
* substring, that would take every user's bucket (and their un-pushed mutation
|
|
1536
|
+
* outboxes) down with one corrupt store. Resolves even on error/blocked so
|
|
1537
|
+
* startup can proceed. No-op outside a browser. Exported for unit tests. */
|
|
1538
|
+
<span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >export async function dropLocalIndexedDbStores(logger: Logger, storeName: string): Promise<void> {</span></span>
|
|
1539
|
+
<span class="cstat-no" title="statement not covered" > if (typeof indexedDB === 'undefined') return;</span>
|
|
1540
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1541
|
+
<span class="cstat-no" title="statement not covered" > let names: string[] = [];</span>
|
|
1542
|
+
<span class="cstat-no" title="statement not covered" > if (typeof indexedDB.databases === 'function') {</span>
|
|
1543
|
+
<span class="cstat-no" title="statement not covered" > const dbs = await indexedDB.databases();</span>
|
|
1544
|
+
<span class="cstat-no" title="statement not covered" > names = dbs</span>
|
|
1545
|
+
<span class="cstat-no" title="statement not covered" > .map((d) => d.name)</span>
|
|
1546
|
+
<span class="cstat-no" title="statement not covered" > .filter((n): n is string => !!n && matchesBucketStore(n, storeName));</span>
|
|
1547
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1548
|
+
// Fall back to the known store name if enumeration is unavailable/empty.
|
|
1549
|
+
<span class="cstat-no" title="statement not covered" > if (names.length === 0) names = [storeName];</span>
|
|
1550
|
+
<span class="cstat-no" title="statement not covered" > await Promise.all(names.map(deleteIndexedDb));</span>
|
|
1551
|
+
<span class="cstat-no" title="statement not covered" > logger.info(</span>
|
|
1552
|
+
<span class="cstat-no" title="statement not covered" > { names, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1553
|
+
<span class="cstat-no" title="statement not covered" > 'Cleared local IndexedDB store(s)'</span>
|
|
1554
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1555
|
+
<span class="cstat-no" title="statement not covered" > } catch (e) {</span>
|
|
1556
|
+
<span class="cstat-no" title="statement not covered" > logger.warn(</span>
|
|
1557
|
+
<span class="cstat-no" title="statement not covered" > { err: e, Category: 'sp00ky-client::LocalDatabaseService::connect' },</span>
|
|
1558
|
+
<span class="cstat-no" title="statement not covered" > 'Failed to enumerate/clear IndexedDB; proceeding anyway'</span>
|
|
1559
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1560
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1561
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1562
|
+
|
|
1563
|
+
/** True when idb database `name` belongs to the bucket store `storeName` —
|
|
1564
|
+
* exact match or a derived name (`<storeName>`, `<storeName>-*`, `*<storeName>*`
|
|
1565
|
+
* with a non-alphanumeric boundary so `sp00ky-abc` never matches
|
|
1566
|
+
* `sp00ky-abcdef`'s store). Exported for unit tests. */
|
|
1567
|
+
export function matchesBucketStore(name: string, storeName: string): boolean {
|
|
1568
|
+
const lower = name.toLowerCase();
|
|
1569
|
+
const target = storeName.toLowerCase();
|
|
1570
|
+
const idx = lower.indexOf(target);
|
|
1571
|
+
if (idx === -1) return false;
|
|
1572
|
+
const after = lower[idx + target.length];
|
|
1573
|
+
return after === undefined || !/[a-z0-9_]/.test(after);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
/** Nuke EVERY sp00ky local bucket on this device (manual full reset only —
|
|
1577
|
+
* the automated corruption recovery is scoped to one bucket). */
|
|
1578
|
+
<span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >export async function dropAllSp00kyIndexedDbStores(logger: Logger): Promise<void> {</span></span>
|
|
1579
|
+
<span class="cstat-no" title="statement not covered" > if (typeof indexedDB === 'undefined') return;</span>
|
|
1580
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1581
|
+
<span class="cstat-no" title="statement not covered" > let names: string[] = [];</span>
|
|
1582
|
+
<span class="cstat-no" title="statement not covered" > if (typeof indexedDB.databases === 'function') {</span>
|
|
1583
|
+
<span class="cstat-no" title="statement not covered" > const dbs = await indexedDB.databases();</span>
|
|
1584
|
+
<span class="cstat-no" title="statement not covered" > names = dbs</span>
|
|
1585
|
+
<span class="cstat-no" title="statement not covered" > .map((d) => d.name)</span>
|
|
1586
|
+
<span class="cstat-no" title="statement not covered" > .filter((n): n is string => !!n && n.toLowerCase().includes('sp00ky'));</span>
|
|
1587
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1588
|
+
<span class="cstat-no" title="statement not covered" > if (names.length === 0) names = ['sp00ky'];</span>
|
|
1589
|
+
<span class="cstat-no" title="statement not covered" > await Promise.all(names.map(deleteIndexedDb));</span>
|
|
1590
|
+
<span class="cstat-no" title="statement not covered" > logger.info(</span>
|
|
1591
|
+
<span class="cstat-no" title="statement not covered" > { names, Category: 'sp00ky-client::LocalDatabaseService::reset' },</span>
|
|
1592
|
+
<span class="cstat-no" title="statement not covered" > 'Cleared ALL sp00ky IndexedDB stores'</span>
|
|
1593
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1594
|
+
<span class="cstat-no" title="statement not covered" > } catch (e) {</span>
|
|
1595
|
+
<span class="cstat-no" title="statement not covered" > logger.warn(</span>
|
|
1596
|
+
<span class="cstat-no" title="statement not covered" > { err: e, Category: 'sp00ky-client::LocalDatabaseService::reset' },</span>
|
|
1597
|
+
<span class="cstat-no" title="statement not covered" > 'Failed to enumerate/clear IndexedDB; proceeding anyway'</span>
|
|
1598
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1599
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1600
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1601
|
+
|
|
1602
|
+
<span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >function deleteIndexedDb(name: string): Promise<void> {</span></span>
|
|
1603
|
+
<span class="cstat-no" title="statement not covered" > return new Promise((resolve) => {</span>
|
|
1604
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1605
|
+
<span class="cstat-no" title="statement not covered" > const req = indexedDB.deleteDatabase(name);</span>
|
|
1606
|
+
<span class="cstat-no" title="statement not covered" > req.onsuccess = () => resolve();</span>
|
|
1607
|
+
<span class="cstat-no" title="statement not covered" > req.onerror = () => resolve();</span>
|
|
1608
|
+
<span class="cstat-no" title="statement not covered" > req.onblocked = () => resolve();</span>
|
|
1609
|
+
<span class="cstat-no" title="statement not covered" > } catch {</span>
|
|
1610
|
+
<span class="cstat-no" title="statement not covered" > resolve();</span>
|
|
1611
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1612
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1613
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1614
|
+
</pre></td></tr></table></pre>
|
|
1615
|
+
|
|
1616
|
+
<div class='push'></div><!-- for sticky footer -->
|
|
1617
|
+
</div><!-- /wrapper -->
|
|
1618
|
+
<div class='footer quiet pad2 space-top1 center small'>
|
|
1619
|
+
Code coverage generated by
|
|
1620
|
+
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
1621
|
+
at 2026-09-09T09:49:51.780Z
|
|
1622
|
+
</div>
|
|
1623
|
+
<script src="../../../prettify.js"></script>
|
|
1624
|
+
<script>
|
|
1625
|
+
window.onload = function () {
|
|
1626
|
+
prettyPrint();
|
|
1627
|
+
};
|
|
1628
|
+
</script>
|
|
1629
|
+
<script src="../../../sorter.js"></script>
|
|
1630
|
+
<script src="../../../block-navigation.js"></script>
|
|
1631
|
+
</body>
|
|
1632
|
+
</html>
|
|
1633
|
+
|