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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/coverage/lcov-report/base.css +224 -0
  2. package/coverage/lcov-report/block-navigation.js +87 -0
  3. package/coverage/lcov-report/favicon.png +0 -0
  4. package/coverage/lcov-report/index.html +476 -0
  5. package/coverage/lcov-report/prettify.css +1 -0
  6. package/coverage/lcov-report/prettify.js +2 -0
  7. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  8. package/coverage/lcov-report/sorter.js +210 -0
  9. package/coverage/lcov-report/src/boot/auth-flip.saga.ts.html +271 -0
  10. package/coverage/lcov-report/src/boot/boot.saga.ts.html +469 -0
  11. package/coverage/lcov-report/src/boot/bucket-switch.saga.ts.html +430 -0
  12. package/coverage/lcov-report/src/boot/index.html +161 -0
  13. package/coverage/lcov-report/src/boot/preload.saga.ts.html +178 -0
  14. package/coverage/lcov-report/src/client/bucket-handle.ts.html +766 -0
  15. package/coverage/lcov-report/src/client/index.html +161 -0
  16. package/coverage/lcov-report/src/client/router.ts.html +367 -0
  17. package/coverage/lcov-report/src/client/runtime.ts.html +940 -0
  18. package/coverage/lcov-report/src/client/sp00ky-client.ts.html +1531 -0
  19. package/coverage/lcov-report/src/events/index.html +116 -0
  20. package/coverage/lcov-report/src/events/index.ts.html +877 -0
  21. package/coverage/lcov-report/src/index.html +146 -0
  22. package/coverage/lcov-report/src/index.ts.html +202 -0
  23. package/coverage/lcov-report/src/kernel/constants.ts.html +247 -0
  24. package/coverage/lcov-report/src/kernel/effects.ts.html +562 -0
  25. package/coverage/lcov-report/src/kernel/events.ts.html +250 -0
  26. package/coverage/lcov-report/src/kernel/index.html +176 -0
  27. package/coverage/lcov-report/src/kernel/interpreter.ts.html +514 -0
  28. package/coverage/lcov-report/src/kernel/saga.ts.html +304 -0
  29. package/coverage/lcov-report/src/modules/app-release/index.html +116 -0
  30. package/coverage/lcov-report/src/modules/app-release/index.ts.html +712 -0
  31. package/coverage/lcov-report/src/modules/auth/events/index.html +116 -0
  32. package/coverage/lcov-report/src/modules/auth/events/index.ts.html +142 -0
  33. package/coverage/lcov-report/src/modules/auth/index.html +116 -0
  34. package/coverage/lcov-report/src/modules/auth/index.ts.html +1225 -0
  35. package/coverage/lcov-report/src/modules/crdt/crdt-field.ts.html +967 -0
  36. package/coverage/lcov-report/src/modules/crdt/index.html +146 -0
  37. package/coverage/lcov-report/src/modules/crdt/index.ts.html +1474 -0
  38. package/coverage/lcov-report/src/modules/crdt/loro-loader.ts.html +160 -0
  39. package/coverage/lcov-report/src/modules/devtools/flags.ts.html +1132 -0
  40. package/coverage/lcov-report/src/modules/devtools/index.html +161 -0
  41. package/coverage/lcov-report/src/modules/devtools/index.ts.html +2413 -0
  42. package/coverage/lcov-report/src/modules/devtools/storage-info.ts.html +589 -0
  43. package/coverage/lcov-report/src/modules/devtools/versions.ts.html +415 -0
  44. package/coverage/lcov-report/src/modules/feature-flag/index.html +116 -0
  45. package/coverage/lcov-report/src/modules/feature-flag/index.ts.html +1033 -0
  46. package/coverage/lcov-report/src/modules/index.html +116 -0
  47. package/coverage/lcov-report/src/modules/ref-tables.ts.html +349 -0
  48. package/coverage/lcov-report/src/mutation/index.html +191 -0
  49. package/coverage/lcov-report/src/mutation/jobs.ts.html +208 -0
  50. package/coverage/lcov-report/src/mutation/mutation-id.ts.html +190 -0
  51. package/coverage/lcov-report/src/mutation/push.saga.ts.html +730 -0
  52. package/coverage/lcov-report/src/mutation/rows.ts.html +1216 -0
  53. package/coverage/lcov-report/src/mutation/tray.saga.ts.html +229 -0
  54. package/coverage/lcov-report/src/mutation/write.saga.ts.html +583 -0
  55. package/coverage/lcov-report/src/otel/index.html +116 -0
  56. package/coverage/lcov-report/src/otel/index.ts.html +466 -0
  57. package/coverage/lcov-report/src/query/env.ts.html +253 -0
  58. package/coverage/lcov-report/src/query/fetch.saga.ts.html +412 -0
  59. package/coverage/lcov-report/src/query/hash.ts.html +139 -0
  60. package/coverage/lcov-report/src/query/index.html +281 -0
  61. package/coverage/lcov-report/src/query/lifecycle.saga.ts.html +388 -0
  62. package/coverage/lcov-report/src/query/materialize.saga.ts.html +310 -0
  63. package/coverage/lcov-report/src/query/materialize.ts.html +217 -0
  64. package/coverage/lcov-report/src/query/membership.saga.ts.html +709 -0
  65. package/coverage/lcov-report/src/query/membership.ts.html +559 -0
  66. package/coverage/lcov-report/src/query/register.saga.ts.html +655 -0
  67. package/coverage/lcov-report/src/query/render-set.ts.html +265 -0
  68. package/coverage/lcov-report/src/query/sql.ts.html +322 -0
  69. package/coverage/lcov-report/src/query/window-query.ts.html +670 -0
  70. package/coverage/lcov-report/src/services/blobs/blob-cache.ts.html +1894 -0
  71. package/coverage/lcov-report/src/services/blobs/blob-manifest.ts.html +766 -0
  72. package/coverage/lcov-report/src/services/blobs/blob-store.ts.html +1162 -0
  73. package/coverage/lcov-report/src/services/blobs/index.html +161 -0
  74. package/coverage/lcov-report/src/services/blobs/index.ts.html +295 -0
  75. package/coverage/lcov-report/src/services/database/cache-engine.ts.html +664 -0
  76. package/coverage/lcov-report/src/services/database/connection-supervisor.ts.html +1330 -0
  77. package/coverage/lcov-report/src/services/database/database.ts.html +658 -0
  78. package/coverage/lcov-report/src/services/database/engine-factory.ts.html +184 -0
  79. package/coverage/lcov-report/src/services/database/errors.ts.html +187 -0
  80. package/coverage/lcov-report/src/services/database/events/index.html +116 -0
  81. package/coverage/lcov-report/src/services/database/events/index.ts.html +184 -0
  82. package/coverage/lcov-report/src/services/database/index.html +386 -0
  83. package/coverage/lcov-report/src/services/database/index.ts.html +121 -0
  84. package/coverage/lcov-report/src/services/database/local-migrator.ts.html +703 -0
  85. package/coverage/lcov-report/src/services/database/local.ts.html +1633 -0
  86. package/coverage/lcov-report/src/services/database/plan-render.ts.html +409 -0
  87. package/coverage/lcov-report/src/services/database/relation-resolver.ts.html +682 -0
  88. package/coverage/lcov-report/src/services/database/remote.ts.html +1036 -0
  89. package/coverage/lcov-report/src/services/database/sqlite-cache-engine.ts.html +4132 -0
  90. package/coverage/lcov-report/src/services/database/sqlite-lock-verify.ts.html +220 -0
  91. package/coverage/lcov-report/src/services/database/sqlite-open.ts.html +577 -0
  92. package/coverage/lcov-report/src/services/database/sqlite-plan-sql.ts.html +499 -0
  93. package/coverage/lcov-report/src/services/database/sqlite-select.ts.html +478 -0
  94. package/coverage/lcov-report/src/services/database/sqlite-transport.ts.html +757 -0
  95. package/coverage/lcov-report/src/services/database/surql-translate.ts.html +1333 -0
  96. package/coverage/lcov-report/src/services/database/surreal-cache-engine.ts.html +568 -0
  97. package/coverage/lcov-report/src/services/logger/index.html +116 -0
  98. package/coverage/lcov-report/src/services/logger/index.ts.html +154 -0
  99. package/coverage/lcov-report/src/services/persistence/index.html +146 -0
  100. package/coverage/lcov-report/src/services/persistence/localstorage.ts.html +163 -0
  101. package/coverage/lcov-report/src/services/persistence/resilient.ts.html +208 -0
  102. package/coverage/lcov-report/src/services/persistence/surrealdb.ts.html +271 -0
  103. package/coverage/lcov-report/src/services/stream-processor/index.html +146 -0
  104. package/coverage/lcov-report/src/services/stream-processor/index.ts.html +3313 -0
  105. package/coverage/lcov-report/src/services/stream-processor/permissions.ts.html +244 -0
  106. package/coverage/lcov-report/src/services/stream-processor/wasm-types.ts.html +346 -0
  107. package/coverage/lcov-report/src/services/tabs/broker-client.ts.html +934 -0
  108. package/coverage/lcov-report/src/services/tabs/coordinator.ts.html +1984 -0
  109. package/coverage/lcov-report/src/services/tabs/index.html +191 -0
  110. package/coverage/lcov-report/src/services/tabs/leader-locks.ts.html +310 -0
  111. package/coverage/lcov-report/src/services/tabs/protocol.ts.html +871 -0
  112. package/coverage/lcov-report/src/services/tabs/support.ts.html +193 -0
  113. package/coverage/lcov-report/src/services/tabs/tabs-broker-worker.ts.html +2005 -0
  114. package/coverage/lcov-report/src/sp00ky.ts.html +100 -0
  115. package/coverage/lcov-report/src/state/client-state.ts.html +637 -0
  116. package/coverage/lcov-report/src/state/index.html +161 -0
  117. package/coverage/lcov-report/src/state/lifecycle.ts.html +343 -0
  118. package/coverage/lcov-report/src/state/reducers.ts.html +1471 -0
  119. package/coverage/lcov-report/src/state/selectors.ts.html +637 -0
  120. package/coverage/lcov-report/src/sync/connection.saga.ts.html +343 -0
  121. package/coverage/lcov-report/src/sync/index.html +176 -0
  122. package/coverage/lcov-report/src/sync/live.saga.ts.html +232 -0
  123. package/coverage/lcov-report/src/sync/policy.ts.html +1606 -0
  124. package/coverage/lcov-report/src/sync/poll.saga.ts.html +193 -0
  125. package/coverage/lcov-report/src/sync/tabs.saga.ts.html +361 -0
  126. package/coverage/lcov-report/src/types.ts.html +2419 -0
  127. package/coverage/lcov-report/src/utils/blurhash.ts.html +355 -0
  128. package/coverage/lcov-report/src/utils/error-classification.ts.html +244 -0
  129. package/coverage/lcov-report/src/utils/index.html +191 -0
  130. package/coverage/lcov-report/src/utils/index.ts.html +820 -0
  131. package/coverage/lcov-report/src/utils/parser.ts.html +313 -0
  132. package/coverage/lcov-report/src/utils/semver.ts.html +175 -0
  133. package/coverage/lcov-report/src/utils/surql.ts.html +667 -0
  134. package/coverage/lcov.info +19079 -0
  135. package/dist/index.js +3 -3
  136. package/dist/sqlite-open.js +20 -1
  137. package/package.json +3 -3
  138. package/src/services/database/relation-resolver.test.ts +55 -1
  139. package/src/services/database/relation-resolver.ts +0 -0
@@ -0,0 +1,1225 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/modules/auth/index.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/modules/auth</a> index.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">56.88% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>128/225</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">62.79% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>27/43</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">50% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>8/16</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">56.88% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>128/225</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 medium'></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></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
447
+ <span class="cline-any cline-neutral">&nbsp;</span>
448
+ <span class="cline-any cline-neutral">&nbsp;</span>
449
+ <span class="cline-any cline-neutral">&nbsp;</span>
450
+ <span class="cline-any cline-neutral">&nbsp;</span>
451
+ <span class="cline-any cline-neutral">&nbsp;</span>
452
+ <span class="cline-any cline-neutral">&nbsp;</span>
453
+ <span class="cline-any cline-neutral">&nbsp;</span>
454
+ <span class="cline-any cline-neutral">&nbsp;</span>
455
+ <span class="cline-any cline-neutral">&nbsp;</span>
456
+ <span class="cline-any cline-neutral">&nbsp;</span>
457
+ <span class="cline-any cline-neutral">&nbsp;</span>
458
+ <span class="cline-any cline-neutral">&nbsp;</span>
459
+ <span class="cline-any cline-neutral">&nbsp;</span>
460
+ <span class="cline-any cline-neutral">&nbsp;</span>
461
+ <span class="cline-any cline-neutral">&nbsp;</span>
462
+ <span class="cline-any cline-neutral">&nbsp;</span>
463
+ <span class="cline-any cline-neutral">&nbsp;</span>
464
+ <span class="cline-any cline-neutral">&nbsp;</span>
465
+ <span class="cline-any cline-neutral">&nbsp;</span>
466
+ <span class="cline-any cline-neutral">&nbsp;</span>
467
+ <span class="cline-any cline-neutral">&nbsp;</span>
468
+ <span class="cline-any cline-neutral">&nbsp;</span>
469
+ <span class="cline-any cline-neutral">&nbsp;</span>
470
+ <span class="cline-any cline-neutral">&nbsp;</span>
471
+ <span class="cline-any cline-neutral">&nbsp;</span>
472
+ <span class="cline-any cline-neutral">&nbsp;</span>
473
+ <span class="cline-any cline-neutral">&nbsp;</span>
474
+ <span class="cline-any cline-neutral">&nbsp;</span>
475
+ <span class="cline-any cline-neutral">&nbsp;</span>
476
+ <span class="cline-any cline-neutral">&nbsp;</span>
477
+ <span class="cline-any cline-neutral">&nbsp;</span>
478
+ <span class="cline-any cline-neutral">&nbsp;</span>
479
+ <span class="cline-any cline-neutral">&nbsp;</span>
480
+ <span class="cline-any cline-neutral">&nbsp;</span>
481
+ <span class="cline-any cline-neutral">&nbsp;</span>
482
+ <span class="cline-any cline-neutral">&nbsp;</span>
483
+ <span class="cline-any cline-neutral">&nbsp;</span>
484
+ <span class="cline-any cline-neutral">&nbsp;</span>
485
+ <span class="cline-any cline-neutral">&nbsp;</span>
486
+ <span class="cline-any cline-neutral">&nbsp;</span>
487
+ <span class="cline-any cline-neutral">&nbsp;</span>
488
+ <span class="cline-any cline-neutral">&nbsp;</span>
489
+ <span class="cline-any cline-neutral">&nbsp;</span>
490
+ <span class="cline-any cline-neutral">&nbsp;</span>
491
+ <span class="cline-any cline-neutral">&nbsp;</span>
492
+ <span class="cline-any cline-neutral">&nbsp;</span>
493
+ <span class="cline-any cline-neutral">&nbsp;</span>
494
+ <span class="cline-any cline-neutral">&nbsp;</span>
495
+ <span class="cline-any cline-neutral">&nbsp;</span>
496
+ <span class="cline-any cline-yes">8x</span>
497
+ <span class="cline-any cline-yes">8x</span>
498
+ <span class="cline-any cline-yes">8x</span>
499
+ <span class="cline-any cline-yes">8x</span>
500
+ <span class="cline-any cline-yes">7x</span>
501
+ <span class="cline-any cline-yes">7x</span>
502
+ <span class="cline-any cline-yes">7x</span>
503
+ <span class="cline-any cline-yes">8x</span>
504
+ <span class="cline-any cline-yes">8x</span>
505
+ <span class="cline-any cline-yes">8x</span>
506
+ <span class="cline-any cline-yes">8x</span>
507
+ <span class="cline-any cline-yes">8x</span>
508
+ <span class="cline-any cline-yes">8x</span>
509
+ <span class="cline-any cline-yes">8x</span>
510
+ <span class="cline-any cline-yes">8x</span>
511
+ <span class="cline-any cline-yes">8x</span>
512
+ <span class="cline-any cline-no">&nbsp;</span>
513
+ <span class="cline-any cline-no">&nbsp;</span>
514
+ <span class="cline-any cline-yes">8x</span>
515
+ <span class="cline-any cline-neutral">&nbsp;</span>
516
+ <span class="cline-any cline-no">&nbsp;</span>
517
+ <span class="cline-any cline-no">&nbsp;</span>
518
+ <span class="cline-any cline-no">&nbsp;</span>
519
+ <span class="cline-any cline-neutral">&nbsp;</span>
520
+ <span class="cline-any cline-yes">1x</span>
521
+ <span class="cline-any cline-neutral">&nbsp;</span>
522
+ <span class="cline-any cline-yes">10x</span>
523
+ <span class="cline-any cline-yes">10x</span>
524
+ <span class="cline-any cline-yes">10x</span>
525
+ <span class="cline-any cline-neutral">&nbsp;</span>
526
+ <span class="cline-any cline-neutral">&nbsp;</span>
527
+ <span class="cline-any cline-neutral">&nbsp;</span>
528
+ <span class="cline-any cline-neutral">&nbsp;</span>
529
+ <span class="cline-any cline-neutral">&nbsp;</span>
530
+ <span class="cline-any cline-neutral">&nbsp;</span>
531
+ <span class="cline-any cline-yes">10x</span>
532
+ <span class="cline-any cline-yes">10x</span>
533
+ <span class="cline-any cline-neutral">&nbsp;</span>
534
+ <span class="cline-any cline-yes">10x</span>
535
+ <span class="cline-any cline-neutral">&nbsp;</span>
536
+ <span class="cline-any cline-yes">10x</span>
537
+ <span class="cline-any cline-no">&nbsp;</span>
538
+ <span class="cline-any cline-no">&nbsp;</span>
539
+ <span class="cline-any cline-neutral">&nbsp;</span>
540
+ <span class="cline-any cline-yes">10x</span>
541
+ <span class="cline-any cline-yes">10x</span>
542
+ <span class="cline-any cline-yes">10x</span>
543
+ <span class="cline-any cline-yes">10x</span>
544
+ <span class="cline-any cline-yes">10x</span>
545
+ <span class="cline-any cline-yes">10x</span>
546
+ <span class="cline-any cline-neutral">&nbsp;</span>
547
+ <span class="cline-any cline-yes">10x</span>
548
+ <span class="cline-any cline-no">&nbsp;</span>
549
+ <span class="cline-any cline-no">&nbsp;</span>
550
+ <span class="cline-any cline-neutral">&nbsp;</span>
551
+ <span class="cline-any cline-yes">10x</span>
552
+ <span class="cline-any cline-no">&nbsp;</span>
553
+ <span class="cline-any cline-no">&nbsp;</span>
554
+ <span class="cline-any cline-neutral">&nbsp;</span>
555
+ <span class="cline-any cline-neutral">&nbsp;</span>
556
+ <span class="cline-any cline-neutral">&nbsp;</span>
557
+ <span class="cline-any cline-neutral">&nbsp;</span>
558
+ <span class="cline-any cline-neutral">&nbsp;</span>
559
+ <span class="cline-any cline-yes">10x</span>
560
+ <span class="cline-any cline-neutral">&nbsp;</span>
561
+ <span class="cline-any cline-yes">1x</span>
562
+ <span class="cline-any cline-neutral">&nbsp;</span>
563
+ <span class="cline-any cline-yes">1x</span>
564
+ <span class="cline-any cline-yes">1x</span>
565
+ <span class="cline-any cline-yes">1x</span>
566
+ <span class="cline-any cline-neutral">&nbsp;</span>
567
+ <span class="cline-any cline-yes">1x</span>
568
+ <span class="cline-any cline-no">&nbsp;</span>
569
+ <span class="cline-any cline-no">&nbsp;</span>
570
+ <span class="cline-any cline-yes">1x</span>
571
+ <span class="cline-any cline-neutral">&nbsp;</span>
572
+ <span class="cline-any cline-yes">10x</span>
573
+ <span class="cline-any cline-yes">9x</span>
574
+ <span class="cline-any cline-yes">9x</span>
575
+ <span class="cline-any cline-yes">9x</span>
576
+ <span class="cline-any cline-neutral">&nbsp;</span>
577
+ <span class="cline-any cline-neutral">&nbsp;</span>
578
+ <span class="cline-any cline-neutral">&nbsp;</span>
579
+ <span class="cline-any cline-neutral">&nbsp;</span>
580
+ <span class="cline-any cline-neutral">&nbsp;</span>
581
+ <span class="cline-any cline-neutral">&nbsp;</span>
582
+ <span class="cline-any cline-neutral">&nbsp;</span>
583
+ <span class="cline-any cline-neutral">&nbsp;</span>
584
+ <span class="cline-any cline-neutral">&nbsp;</span>
585
+ <span class="cline-any cline-neutral">&nbsp;</span>
586
+ <span class="cline-any cline-neutral">&nbsp;</span>
587
+ <span class="cline-any cline-neutral">&nbsp;</span>
588
+ <span class="cline-any cline-neutral">&nbsp;</span>
589
+ <span class="cline-any cline-neutral">&nbsp;</span>
590
+ <span class="cline-any cline-neutral">&nbsp;</span>
591
+ <span class="cline-any cline-neutral">&nbsp;</span>
592
+ <span class="cline-any cline-neutral">&nbsp;</span>
593
+ <span class="cline-any cline-neutral">&nbsp;</span>
594
+ <span class="cline-any cline-yes">10x</span>
595
+ <span class="cline-any cline-yes">9x</span>
596
+ <span class="cline-any cline-yes">9x</span>
597
+ <span class="cline-any cline-yes">8x</span>
598
+ <span class="cline-any cline-yes">9x</span>
599
+ <span class="cline-any cline-neutral">&nbsp;</span>
600
+ <span class="cline-any cline-yes">6x</span>
601
+ <span class="cline-any cline-neutral">&nbsp;</span>
602
+ <span class="cline-any cline-neutral">&nbsp;</span>
603
+ <span class="cline-any cline-neutral">&nbsp;</span>
604
+ <span class="cline-any cline-neutral">&nbsp;</span>
605
+ <span class="cline-any cline-yes">6x</span>
606
+ <span class="cline-any cline-neutral">&nbsp;</span>
607
+ <span class="cline-any cline-neutral">&nbsp;</span>
608
+ <span class="cline-any cline-neutral">&nbsp;</span>
609
+ <span class="cline-any cline-yes">6x</span>
610
+ <span class="cline-any cline-yes">6x</span>
611
+ <span class="cline-any cline-yes">9x</span>
612
+ <span class="cline-any cline-yes">9x</span>
613
+ <span class="cline-any cline-yes">9x</span>
614
+ <span class="cline-any cline-yes">9x</span>
615
+ <span class="cline-any cline-yes">9x</span>
616
+ <span class="cline-any cline-yes">9x</span>
617
+ <span class="cline-any cline-yes">9x</span>
618
+ <span class="cline-any cline-yes">9x</span>
619
+ <span class="cline-any cline-neutral">&nbsp;</span>
620
+ <span class="cline-any cline-neutral">&nbsp;</span>
621
+ <span class="cline-any cline-neutral">&nbsp;</span>
622
+ <span class="cline-any cline-neutral">&nbsp;</span>
623
+ <span class="cline-any cline-yes">10x</span>
624
+ <span class="cline-any cline-yes">3x</span>
625
+ <span class="cline-any cline-neutral">&nbsp;</span>
626
+ <span class="cline-any cline-yes">3x</span>
627
+ <span class="cline-any cline-yes">3x</span>
628
+ <span class="cline-any cline-neutral">&nbsp;</span>
629
+ <span class="cline-any cline-yes">3x</span>
630
+ <span class="cline-any cline-no">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-no">&nbsp;</span>
637
+ <span class="cline-any cline-no">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-neutral">&nbsp;</span>
640
+ <span class="cline-any cline-neutral">&nbsp;</span>
641
+ <span class="cline-any cline-neutral">&nbsp;</span>
642
+ <span class="cline-any cline-neutral">&nbsp;</span>
643
+ <span class="cline-any cline-yes">3x</span>
644
+ <span class="cline-any cline-yes">3x</span>
645
+ <span class="cline-any cline-neutral">&nbsp;</span>
646
+ <span class="cline-any cline-neutral">&nbsp;</span>
647
+ <span class="cline-any cline-yes">1x</span>
648
+ <span class="cline-any cline-neutral">&nbsp;</span>
649
+ <span class="cline-any cline-yes">3x</span>
650
+ <span class="cline-any cline-yes">3x</span>
651
+ <span class="cline-any cline-neutral">&nbsp;</span>
652
+ <span class="cline-any cline-yes">3x</span>
653
+ <span class="cline-any cline-no">&nbsp;</span>
654
+ <span class="cline-any cline-no">&nbsp;</span>
655
+ <span class="cline-any cline-no">&nbsp;</span>
656
+ <span class="cline-any cline-no">&nbsp;</span>
657
+ <span class="cline-any cline-no">&nbsp;</span>
658
+ <span class="cline-any cline-yes">3x</span>
659
+ <span class="cline-any cline-yes">1x</span>
660
+ <span class="cline-any cline-yes">1x</span>
661
+ <span class="cline-any cline-yes">1x</span>
662
+ <span class="cline-any cline-yes">1x</span>
663
+ <span class="cline-any cline-neutral">&nbsp;</span>
664
+ <span class="cline-any cline-yes">1x</span>
665
+ <span class="cline-any cline-yes">1x</span>
666
+ <span class="cline-any cline-yes">1x</span>
667
+ <span class="cline-any cline-yes">1x</span>
668
+ <span class="cline-any cline-yes">1x</span>
669
+ <span class="cline-any cline-yes">1x</span>
670
+ <span class="cline-any cline-no">&nbsp;</span>
671
+ <span class="cline-any cline-yes">1x</span>
672
+ <span class="cline-any cline-neutral">&nbsp;</span>
673
+ <span class="cline-any cline-yes">1x</span>
674
+ <span class="cline-any cline-no">&nbsp;</span>
675
+ <span class="cline-any cline-no">&nbsp;</span>
676
+ <span class="cline-any cline-no">&nbsp;</span>
677
+ <span class="cline-any cline-no">&nbsp;</span>
678
+ <span class="cline-any cline-no">&nbsp;</span>
679
+ <span class="cline-any cline-yes">1x</span>
680
+ <span class="cline-any cline-yes">1x</span>
681
+ <span class="cline-any cline-yes">1x</span>
682
+ <span class="cline-any cline-yes">1x</span>
683
+ <span class="cline-any cline-yes">1x</span>
684
+ <span class="cline-any cline-yes">1x</span>
685
+ <span class="cline-any cline-yes">1x</span>
686
+ <span class="cline-any cline-yes">1x</span>
687
+ <span class="cline-any cline-yes">3x</span>
688
+ <span class="cline-any cline-neutral">&nbsp;</span>
689
+ <span class="cline-any cline-neutral">&nbsp;</span>
690
+ <span class="cline-any cline-neutral">&nbsp;</span>
691
+ <span class="cline-any cline-neutral">&nbsp;</span>
692
+ <span class="cline-any cline-neutral">&nbsp;</span>
693
+ <span class="cline-any cline-yes">2x</span>
694
+ <span class="cline-any cline-yes">1x</span>
695
+ <span class="cline-any cline-yes">1x</span>
696
+ <span class="cline-any cline-yes">1x</span>
697
+ <span class="cline-any cline-yes">1x</span>
698
+ <span class="cline-any cline-yes">1x</span>
699
+ <span class="cline-any cline-yes">1x</span>
700
+ <span class="cline-any cline-yes">1x</span>
701
+ <span class="cline-any cline-yes">1x</span>
702
+ <span class="cline-any cline-yes">1x</span>
703
+ <span class="cline-any cline-yes">1x</span>
704
+ <span class="cline-any cline-yes">1x</span>
705
+ <span class="cline-any cline-yes">3x</span>
706
+ <span class="cline-any cline-yes">3x</span>
707
+ <span class="cline-any cline-yes">3x</span>
708
+ <span class="cline-any cline-yes">3x</span>
709
+ <span class="cline-any cline-neutral">&nbsp;</span>
710
+ <span class="cline-any cline-neutral">&nbsp;</span>
711
+ <span class="cline-any cline-neutral">&nbsp;</span>
712
+ <span class="cline-any cline-neutral">&nbsp;</span>
713
+ <span class="cline-any cline-yes">10x</span>
714
+ <span class="cline-any cline-yes">3x</span>
715
+ <span class="cline-any cline-yes">3x</span>
716
+ <span class="cline-any cline-yes">3x</span>
717
+ <span class="cline-any cline-yes">3x</span>
718
+ <span class="cline-any cline-yes">3x</span>
719
+ <span class="cline-any cline-neutral">&nbsp;</span>
720
+ <span class="cline-any cline-yes">3x</span>
721
+ <span class="cline-any cline-neutral">&nbsp;</span>
722
+ <span class="cline-any cline-yes">3x</span>
723
+ <span class="cline-any cline-yes">3x</span>
724
+ <span class="cline-any cline-yes">3x</span>
725
+ <span class="cline-any cline-neutral">&nbsp;</span>
726
+ <span class="cline-any cline-no">&nbsp;</span>
727
+ <span class="cline-any cline-neutral">&nbsp;</span>
728
+ <span class="cline-any cline-yes">3x</span>
729
+ <span class="cline-any cline-yes">3x</span>
730
+ <span class="cline-any cline-neutral">&nbsp;</span>
731
+ <span class="cline-any cline-yes">10x</span>
732
+ <span class="cline-any cline-no">&nbsp;</span>
733
+ <span class="cline-any cline-no">&nbsp;</span>
734
+ <span class="cline-any cline-no">&nbsp;</span>
735
+ <span class="cline-any cline-no">&nbsp;</span>
736
+ <span class="cline-any cline-neutral">&nbsp;</span>
737
+ <span class="cline-any cline-neutral">&nbsp;</span>
738
+ <span class="cline-any cline-neutral">&nbsp;</span>
739
+ <span class="cline-any cline-no">&nbsp;</span>
740
+ <span class="cline-any cline-no">&nbsp;</span>
741
+ <span class="cline-any cline-no">&nbsp;</span>
742
+ <span class="cline-any cline-no">&nbsp;</span>
743
+ <span class="cline-any cline-neutral">&nbsp;</span>
744
+ <span class="cline-any cline-neutral">&nbsp;</span>
745
+ <span class="cline-any cline-neutral">&nbsp;</span>
746
+ <span class="cline-any cline-yes">10x</span>
747
+ <span class="cline-any cline-no">&nbsp;</span>
748
+ <span class="cline-any cline-no">&nbsp;</span>
749
+ <span class="cline-any cline-no">&nbsp;</span>
750
+ <span class="cline-any cline-neutral">&nbsp;</span>
751
+ <span class="cline-any cline-yes">10x</span>
752
+ <span class="cline-any cline-no">&nbsp;</span>
753
+ <span class="cline-any cline-no">&nbsp;</span>
754
+ <span class="cline-any cline-no">&nbsp;</span>
755
+ <span class="cline-any cline-no">&nbsp;</span>
756
+ <span class="cline-any cline-no">&nbsp;</span>
757
+ <span class="cline-any cline-neutral">&nbsp;</span>
758
+ <span class="cline-any cline-neutral">&nbsp;</span>
759
+ <span class="cline-any cline-neutral">&nbsp;</span>
760
+ <span class="cline-any cline-no">&nbsp;</span>
761
+ <span class="cline-any cline-neutral">&nbsp;</span>
762
+ <span class="cline-any cline-no">&nbsp;</span>
763
+ <span class="cline-any cline-no">&nbsp;</span>
764
+ <span class="cline-any cline-no">&nbsp;</span>
765
+ <span class="cline-any cline-neutral">&nbsp;</span>
766
+ <span class="cline-any cline-no">&nbsp;</span>
767
+ <span class="cline-any cline-no">&nbsp;</span>
768
+ <span class="cline-any cline-no">&nbsp;</span>
769
+ <span class="cline-any cline-no">&nbsp;</span>
770
+ <span class="cline-any cline-no">&nbsp;</span>
771
+ <span class="cline-any cline-neutral">&nbsp;</span>
772
+ <span class="cline-any cline-no">&nbsp;</span>
773
+ <span class="cline-any cline-no">&nbsp;</span>
774
+ <span class="cline-any cline-no">&nbsp;</span>
775
+ <span class="cline-any cline-no">&nbsp;</span>
776
+ <span class="cline-any cline-neutral">&nbsp;</span>
777
+ <span class="cline-any cline-no">&nbsp;</span>
778
+ <span class="cline-any cline-no">&nbsp;</span>
779
+ <span class="cline-any cline-no">&nbsp;</span>
780
+ <span class="cline-any cline-no">&nbsp;</span>
781
+ <span class="cline-any cline-neutral">&nbsp;</span>
782
+ <span class="cline-any cline-no">&nbsp;</span>
783
+ <span class="cline-any cline-no">&nbsp;</span>
784
+ <span class="cline-any cline-no">&nbsp;</span>
785
+ <span class="cline-any cline-no">&nbsp;</span>
786
+ <span class="cline-any cline-neutral">&nbsp;</span>
787
+ <span class="cline-any cline-neutral">&nbsp;</span>
788
+ <span class="cline-any cline-neutral">&nbsp;</span>
789
+ <span class="cline-any cline-neutral">&nbsp;</span>
790
+ <span class="cline-any cline-no">&nbsp;</span>
791
+ <span class="cline-any cline-no">&nbsp;</span>
792
+ <span class="cline-any cline-neutral">&nbsp;</span>
793
+ <span class="cline-any cline-yes">10x</span>
794
+ <span class="cline-any cline-no">&nbsp;</span>
795
+ <span class="cline-any cline-no">&nbsp;</span>
796
+ <span class="cline-any cline-no">&nbsp;</span>
797
+ <span class="cline-any cline-no">&nbsp;</span>
798
+ <span class="cline-any cline-no">&nbsp;</span>
799
+ <span class="cline-any cline-neutral">&nbsp;</span>
800
+ <span class="cline-any cline-no">&nbsp;</span>
801
+ <span class="cline-any cline-neutral">&nbsp;</span>
802
+ <span class="cline-any cline-neutral">&nbsp;</span>
803
+ <span class="cline-any cline-no">&nbsp;</span>
804
+ <span class="cline-any cline-no">&nbsp;</span>
805
+ <span class="cline-any cline-no">&nbsp;</span>
806
+ <span class="cline-any cline-neutral">&nbsp;</span>
807
+ <span class="cline-any cline-no">&nbsp;</span>
808
+ <span class="cline-any cline-no">&nbsp;</span>
809
+ <span class="cline-any cline-no">&nbsp;</span>
810
+ <span class="cline-any cline-no">&nbsp;</span>
811
+ <span class="cline-any cline-no">&nbsp;</span>
812
+ <span class="cline-any cline-neutral">&nbsp;</span>
813
+ <span class="cline-any cline-no">&nbsp;</span>
814
+ <span class="cline-any cline-no">&nbsp;</span>
815
+ <span class="cline-any cline-no">&nbsp;</span>
816
+ <span class="cline-any cline-no">&nbsp;</span>
817
+ <span class="cline-any cline-neutral">&nbsp;</span>
818
+ <span class="cline-any cline-no">&nbsp;</span>
819
+ <span class="cline-any cline-no">&nbsp;</span>
820
+ <span class="cline-any cline-no">&nbsp;</span>
821
+ <span class="cline-any cline-no">&nbsp;</span>
822
+ <span class="cline-any cline-neutral">&nbsp;</span>
823
+ <span class="cline-any cline-no">&nbsp;</span>
824
+ <span class="cline-any cline-no">&nbsp;</span>
825
+ <span class="cline-any cline-yes">10x</span>
826
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { RemoteDatabaseService } from '../../services/database/remote';
827
+ import type {
828
+ SchemaStructure,
829
+ AccessDefinition,
830
+ ColumnSchema,
831
+ TypeNameToTypeMap,
832
+ } from '@spooky-sync/query-builder';
833
+ import type { Logger } from '../../services/logger/index';
834
+ export * from './events/index';
835
+ import { AuthEventTypes, createAuthEventSystem } from './events/index';
836
+ import type { PersistenceClient } from '../../types';
837
+ import { classifySyncError } from '../../utils/error-classification';
838
+ &nbsp;
839
+ // Helper to pretty print types
840
+ type Prettify&lt;T&gt; = {
841
+ [K in keyof T]: T[K];
842
+ } &amp; {};
843
+ &nbsp;
844
+ // Map ColumnSchema (value type string) to actual Typescript type
845
+ type MapColumnType&lt;T extends ColumnSchema&gt; = T['optional'] extends true
846
+ ? TypeNameToTypeMap[T['type']] | undefined
847
+ : TypeNameToTypeMap[T['type']];
848
+ &nbsp;
849
+ // Extract params object from SchemaStructure based on access name and method (signIn/signup)
850
+ type ExtractAccessParams&lt;
851
+ S extends SchemaStructure,
852
+ Name extends keyof S['access'],
853
+ Method extends 'signIn' | 'signup',
854
+ &gt; = S['access'] extends undefined
855
+ ? never
856
+ : S['access'][Name] extends AccessDefinition
857
+ ? Prettify&lt;{
858
+ [K in keyof S['access'][Name][Method]['params']]: MapColumnType&lt;
859
+ S['access'][Name][Method]['params'][K]
860
+ &gt;;
861
+ }&gt;
862
+ : never;
863
+ &nbsp;
864
+ /**
865
+ * Read the claims of a SurrealDB record-access JWT WITHOUT verifying it. The
866
+ * server still enforces the token on every request; this is only so the client
867
+ * can act on what it already holds before a round trip completes.
868
+ *
869
+ * `AC` is the access-method name — the in-browser SSP needs it to resolve
870
+ * `$access` in table permission predicates (mirrors the session's `$access`
871
+ * that the server's `fn::query::register` reads). `ID` is the `$auth.id` record
872
+ * id, which is what lets a warm boot restore a session locally.
873
+ *
874
+ * Returns nulls on any malformed input.
875
+ */
876
+ function decodeTokenClaims(token: string): { access: string | null; userId: string | null } {
877
+ try {
878
+ const payload = token.split('.')[1];
879
+ if (!payload) return { access: null, userId: null };
880
+ let b64 = payload.replace(/-/g, '+').replace(/_/g, '/');
881
+ b64 += '='.repeat((4 - (b64.length % 4)) % 4);
882
+ const json =
883
+ typeof atob === 'function' ? atob(b64<span class="branch-0 cbranch-no" title="branch not covered" >) : Buffer.from(b64, 'base64').toString('binary');</span>
884
+ const claims = JSON.parse(json) as Record&lt;string, unknown&gt;;
885
+ const ac = claims.<span class="branch-0 cbranch-no" title="branch not covered" >AC ?? claims.ac;</span>
886
+ const id = claims.ID ?? claims.id;
887
+ return {
888
+ access: typeof ac === 'string' ? <span class="branch-0 cbranch-no" title="branch not covered" >ac : null,</span>
889
+ userId: typeof id === 'string' ? id : null,
890
+ };
891
+ <span class="branch-0 cbranch-no" title="branch not covered" > } catch {</span>
892
+ <span class="cstat-no" title="statement not covered" > return { access: null, userId: null };</span>
893
+ <span class="cstat-no" title="statement not covered" > }</span>
894
+ }
895
+ &nbsp;
896
+ <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >function decodeAccessFromToken(token: string): string | null {</span></span>
897
+ <span class="cstat-no" title="statement not covered" > return decodeTokenClaims(token).access;</span>
898
+ <span class="cstat-no" title="statement not covered" >}</span>
899
+ &nbsp;
900
+ export class AuthService&lt;S extends SchemaStructure&gt; {
901
+ // State
902
+ public token: string | null = null;
903
+ public currentUser: any | null = null;
904
+ public isAuthenticated: boolean = false;
905
+ /**
906
+ * The record-access method name for the current session (e.g. `"account"`),
907
+ * derived from the token's `AC` claim. Consumed by the in-browser SSP's
908
+ * permission injection so `$access`-gated table predicates resolve locally,
909
+ * mirroring the server's `$access`. Null when logged out.
910
+ */
911
+ public access: string | null = null;
912
+ public isLoading: boolean = true;
913
+ &nbsp;
914
+ private events = createAuthEventSystem();
915
+ &nbsp;
916
+ <span class="fstat-no" title="function not covered" > public get eventSystem() {</span>
917
+ <span class="cstat-no" title="statement not covered" > return this.events;</span>
918
+ <span class="cstat-no" title="statement not covered" > }</span>
919
+ &nbsp;
920
+ constructor(
921
+ private schema: S,
922
+ private remote: RemoteDatabaseService,
923
+ private persistenceClient: PersistenceClient,
924
+ private logger: Logger
925
+ ) {}
926
+ &nbsp;
927
+ <span class="fstat-no" title="function not covered" > async init() {</span>
928
+ <span class="cstat-no" title="statement not covered" > await this.check();</span>
929
+ <span class="cstat-no" title="statement not covered" > }</span>
930
+ &nbsp;
931
+ <span class="fstat-no" title="function not covered" > getAccessDefinition&lt;Name extends keyof S['access']&gt;(name: Name): AccessDefinition | undefined {</span>
932
+ <span class="cstat-no" title="statement not covered" > return this.schema.access?.[name as string];</span>
933
+ <span class="cstat-no" title="statement not covered" > }</span>
934
+ &nbsp;
935
+ /**
936
+ * Subscribe to auth state changes.
937
+ * callback is called immediately with current value and whenever validation status changes.
938
+ */
939
+ subscribe(cb: (userId: string | null) =&gt; void): () =&gt; void {
940
+ // Immediate callback
941
+ cb(this.<span class="branch-0 cbranch-no" title="branch not covered" >currentUser?.id || n</span>ull);
942
+ &nbsp;
943
+ const id = this.events.subscribe(AuthEventTypes.AuthStateChanged, (event) =&gt; {
944
+ cb(event.payload);
945
+ });
946
+ &nbsp;
947
+ return () =&gt; {
948
+ <span class="cstat-no" title="statement not covered" > this.events.unsubscribe(id);</span>
949
+ <span class="cstat-no" title="statement not covered" > };</span>
950
+ }
951
+ &nbsp;
952
+ private notifyListeners() {
953
+ const userId = this.currentUser?.id || null;
954
+ this.events.emit(AuthEventTypes.AuthStateChanged, userId);
955
+ }
956
+ &nbsp;
957
+ /**
958
+ * Restore a session from the locally cached JWT, with NO network.
959
+ *
960
+ * This is what makes a warm boot paint instantly and what makes an offline
961
+ * boot possible at all: the token is in local storage, and it already carries
962
+ * both the access method and the `$auth.id` record id. Everything the client
963
+ * needs to route queries (`setCurrentUserId`) and to satisfy `$auth`-gated
964
+ * permission predicates in the in-browser SSP (`setSessionAuth`) is therefore
965
+ * available before a socket exists.
966
+ *
967
+ * The session is OPTIMISTIC: the token is unverified here. `check()` runs
968
+ * afterwards in the background and downgrades to a real sign-out if the
969
+ * server rejects it. Nothing is trusted that the server has not also seen -
970
+ * the local store only ever holds rows the server previously sent.
971
+ *
972
+ * Returns the restored user id, or null when there is no usable token.
973
+ */
974
+ async restoreSessionFromToken(): Promise&lt;string | null&gt; {
975
+ const token = await this.persistenceClient.get&lt;string&gt;('sp00ky_auth_token');
976
+ if (!token) return null;
977
+ const { access, userId } = decodeTokenClaims(token);
978
+ if (!userId) return null;
979
+ &nbsp;
980
+ this.token = token;
981
+ // Hand it to the transport too, so a socket rebuilt from scratch later
982
+ // (the supervisor's revive loop) comes back authenticated. Without this the
983
+ // page kept reporting this user while its session was anonymous, and every
984
+ // view registered afterwards was stamped with an empty identity.
985
+ this.remote.setAuthToken(token);
986
+ // Only the id: the full row is not in the token. It lands from the local
987
+ // cache when the app's own `user` query paints, and is replaced wholesale
988
+ // by `check()` once the server answers.
989
+ this.currentUser = { id: userId };
990
+ this.isAuthenticated = true;
991
+ this.access = <span class="branch-0 cbranch-no" title="branch not covered" >access ?? this.defaultAccessName();</span>
992
+ this.notifyListeners();
993
+ this.logger.debug(
994
+ { userId, Category: 'sp00ky-client::AuthService::restoreSessionFromToken' },
995
+ 'Session restored optimistically from cached token'
996
+ );
997
+ return userId;
998
+ }
999
+ &nbsp;
1000
+ /**
1001
+ * Check for existing session and validate
1002
+ */
1003
+ async check(accessToken?: string) {
1004
+ this.isLoading = true;
1005
+ &nbsp;
1006
+ try {
1007
+ const token = accessToken || (await this.persistenceClient.get&lt;string&gt;('sp00ky_auth_token'));
1008
+ &nbsp;
1009
+ if (!token) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1010
+ <span class="cstat-no" title="statement not covered" > this.logger.debug(</span>
1011
+ <span class="cstat-no" title="statement not covered" > { Category: 'sp00ky-client::AuthService::check' },</span>
1012
+ <span class="cstat-no" title="statement not covered" > 'No token found in storage or arguments'</span>
1013
+ <span class="cstat-no" title="statement not covered" > );</span>
1014
+ <span class="cstat-no" title="statement not covered" > this.isLoading = false;</span>
1015
+ <span class="cstat-no" title="statement not covered" > this.isAuthenticated = false;</span>
1016
+ <span class="cstat-no" title="statement not covered" > this.notifyListeners();</span>
1017
+ <span class="cstat-no" title="statement not covered" > return;</span>
1018
+ <span class="cstat-no" title="statement not covered" > }</span>
1019
+ &nbsp;
1020
+ // Authenticate with the token, and record it for future connects so a
1021
+ // socket rebuilt from scratch reproduces this identity (see
1022
+ // `RemoteDatabaseService.setAuthToken`).
1023
+ this.remote.setAuthToken(token);
1024
+ await this.remote.getClient().authenticate(token);
1025
+ &nbsp;
1026
+ // Verify the session by fetching the full user record using $auth.id
1027
+ const result = await this.remote.query('SELECT * FROM ONLY $auth.id');
1028
+ &nbsp;
1029
+ const items = Array.isArray(result) &amp;&amp; Array.isArray(result[0]) ? result[0<span class="branch-0 cbranch-no" title="branch not covered" >] : result;</span>
1030
+ const user = Array.isArray(items) ? items[0<span class="branch-0 cbranch-no" title="branch not covered" >] : items;</span>
1031
+ &nbsp;
1032
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >user &amp;&amp; user.id) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
1033
+ <span class="cstat-no" title="statement not covered" > this.logger.info(</span>
1034
+ <span class="cstat-no" title="statement not covered" > { user, Category: 'sp00ky-client::AuthService::check' },</span>
1035
+ <span class="cstat-no" title="statement not covered" > 'Auth check complete (via $auth.id)'</span>
1036
+ <span class="cstat-no" title="statement not covered" > );</span>
1037
+ <span class="cstat-no" title="statement not covered" > await this.setSession(token, user);</span>
1038
+ } else {
1039
+ this.logger.warn(
1040
+ { Category: 'sp00ky-client::AuthService::check' },
1041
+ '$auth.id empty, attempting manual user fetch'
1042
+ );
1043
+ &nbsp;
1044
+ const manualResult = await this.remote.query(
1045
+ 'SELECT * FROM user WHERE id = $auth.id LIMIT 1'
1046
+ );
1047
+ const manualItems =
1048
+ Array.isArray(manualResult) &amp;&amp; Array.isArray(manualResult[0])
1049
+ ? manualResult[0<span class="branch-0 cbranch-no" title="branch not covered" >]</span>
1050
+ <span class="cstat-no" title="statement not covered" > : manualResult;</span>
1051
+ const manualUser = Array.isArray(manualItems) ? manualItems[0<span class="branch-0 cbranch-no" title="branch not covered" >] : manualItems;</span>
1052
+ &nbsp;
1053
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >manualUser &amp;&amp; manualUser.id) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
1054
+ <span class="cstat-no" title="statement not covered" > this.logger.info(</span>
1055
+ <span class="cstat-no" title="statement not covered" > { user: manualUser, Category: 'sp00ky-client::AuthService::check' },</span>
1056
+ <span class="cstat-no" title="statement not covered" > 'Auth check complete (via manual fetch)'</span>
1057
+ <span class="cstat-no" title="statement not covered" > );</span>
1058
+ <span class="cstat-no" title="statement not covered" > await this.setSession(token, manualUser);</span>
1059
+ } else {
1060
+ this.logger.warn(
1061
+ { Category: 'sp00ky-client::AuthService::check' },
1062
+ 'Token valid but user not found via fallback'
1063
+ );
1064
+ await this.signOut();
1065
+ }
1066
+ }
1067
+ } catch (error) {
1068
+ // A REACHABILITY failure is not a rejected token. This catch used to call
1069
+ // signOut() unconditionally, which deletes `sp00ky_auth_token` - so a
1070
+ // blip on boot silently logged the user out, and an offline boot could
1071
+ // never stay signed in. Only an application error (the server answered,
1072
+ // and the answer was "no") ends the session.
1073
+ if (classifySyncError(error) === 'network') {
1074
+ this.logger.warn(
1075
+ { error, Category: 'sp00ky-client::AuthService::check' },
1076
+ 'Auth check unreachable; keeping the cached session and retrying later'
1077
+ );
1078
+ } else {
1079
+ this.logger.error(
1080
+ { error, stack: (error as Error).stack, Category: 'sp00ky-client::AuthService::check' },
1081
+ 'Auth check failed'
1082
+ );
1083
+ await this.signOut();
1084
+ }
1085
+ } finally {
1086
+ this.isLoading = false;
1087
+ }
1088
+ }
1089
+ &nbsp;
1090
+ /**
1091
+ * Sign out and clear session
1092
+ */
1093
+ async signOut() {
1094
+ this.token = null;
1095
+ this.remote.setAuthToken(null);
1096
+ this.currentUser = null;
1097
+ this.isAuthenticated = false;
1098
+ this.access = null;
1099
+ &nbsp;
1100
+ await this.persistenceClient.remove('sp00ky_auth_token');
1101
+ &nbsp;
1102
+ try {
1103
+ await this.remote.getClient().invalidate();
1104
+ <span class="branch-0 cbranch-no" title="branch not covered" > } catch (_e) {</span>
1105
+ // Ignore invalidation errors
1106
+ <span class="cstat-no" title="statement not covered" > }</span>
1107
+ &nbsp;
1108
+ this.notifyListeners();
1109
+ }
1110
+ &nbsp;
1111
+ <span class="fstat-no" title="function not covered" > private async setSession(token: string, user: any) {</span>
1112
+ <span class="cstat-no" title="statement not covered" > this.token = token;</span>
1113
+ <span class="cstat-no" title="statement not covered" > this.remote.setAuthToken(token);</span>
1114
+ <span class="cstat-no" title="statement not covered" > this.currentUser = user;</span>
1115
+ <span class="cstat-no" title="statement not covered" > this.isAuthenticated = true;</span>
1116
+ // Resolve the access-method name (e.g. "account") for in-browser SSP
1117
+ // permission injection. Prefer the token's `AC` claim; fall back to the
1118
+ // schema's sole record-access method if the claim is absent.
1119
+ <span class="cstat-no" title="statement not covered" > this.access = decodeAccessFromToken(token) ?? this.defaultAccessName();</span>
1120
+ <span class="cstat-no" title="statement not covered" > await this.persistenceClient.set('sp00ky_auth_token', token);</span>
1121
+ <span class="cstat-no" title="statement not covered" > this.notifyListeners();</span>
1122
+ <span class="cstat-no" title="statement not covered" > }</span>
1123
+ &nbsp;
1124
+ /** Fallback when the token carries no `AC` claim: if the schema defines
1125
+ * exactly one record-access method, assume the session used it. */
1126
+ private <span class="fstat-no" title="function not covered" >defaultAccessName(): string | null {</span>
1127
+ <span class="cstat-no" title="statement not covered" > const names = Object.keys(this.schema.access ?? {});</span>
1128
+ <span class="cstat-no" title="statement not covered" > return names.length === 1 ? names[0] : null;</span>
1129
+ <span class="cstat-no" title="statement not covered" > }</span>
1130
+ &nbsp;
1131
+ <span class="fstat-no" title="function not covered" > async signUp&lt;Name extends keyof S['access'] &amp; string&gt;(</span>
1132
+ <span class="cstat-no" title="statement not covered" > accessName: Name,</span>
1133
+ <span class="cstat-no" title="statement not covered" > params: ExtractAccessParams&lt;S, Name, 'signup'&gt;</span>
1134
+ <span class="cstat-no" title="statement not covered" > ) {</span>
1135
+ <span class="cstat-no" title="statement not covered" > const def = this.getAccessDefinition(accessName);</span>
1136
+ <span class="cstat-no" title="statement not covered" > if (!def) throw new Error(`Access definition '${accessName}' not found`);</span>
1137
+ &nbsp;
1138
+ // Verify all required params are present
1139
+ // Safe cast params to Record&lt;string, any&gt; for runtime check
1140
+ <span class="cstat-no" title="statement not covered" > const runtimeParams = params as Record&lt;string, any&gt;;</span>
1141
+ &nbsp;
1142
+ <span class="cstat-no" title="statement not covered" > const missingParams = Object.entries(def.signup.params)</span>
1143
+ <span class="cstat-no" title="statement not covered" > .filter(([name, schema]) =&gt; !schema.optional &amp;&amp; !(name in runtimeParams))</span>
1144
+ <span class="cstat-no" title="statement not covered" > .map(([name]) =&gt; name);</span>
1145
+ &nbsp;
1146
+ <span class="cstat-no" title="statement not covered" > if (missingParams.length &gt; 0) {</span>
1147
+ <span class="cstat-no" title="statement not covered" > throw new Error(</span>
1148
+ <span class="cstat-no" title="statement not covered" > `Missing required signup params for '${accessName}': ${missingParams.join(', ')}`</span>
1149
+ <span class="cstat-no" title="statement not covered" > );</span>
1150
+ <span class="cstat-no" title="statement not covered" > }</span>
1151
+ &nbsp;
1152
+ <span class="cstat-no" title="statement not covered" > this.logger.info(</span>
1153
+ <span class="cstat-no" title="statement not covered" > { accessName, runtimeParams, Category: 'sp00ky-client::AuthService::signUp' },</span>
1154
+ <span class="cstat-no" title="statement not covered" > 'Attempting signup'</span>
1155
+ <span class="cstat-no" title="statement not covered" > );</span>
1156
+ &nbsp;
1157
+ <span class="cstat-no" title="statement not covered" > const { access } = await this.remote.getClient().signup({</span>
1158
+ <span class="cstat-no" title="statement not covered" > access: accessName,</span>
1159
+ <span class="cstat-no" title="statement not covered" > variables: runtimeParams,</span>
1160
+ <span class="cstat-no" title="statement not covered" > });</span>
1161
+ &nbsp;
1162
+ <span class="cstat-no" title="statement not covered" > this.logger.info(</span>
1163
+ <span class="cstat-no" title="statement not covered" > { Category: 'sp00ky-client::AuthService::signUp' },</span>
1164
+ <span class="cstat-no" title="statement not covered" > 'Signup successful, token received'</span>
1165
+ <span class="cstat-no" title="statement not covered" > );</span>
1166
+ &nbsp;
1167
+ // After signup, we usually get a token.
1168
+ // We should also fetch the user or trust the token works.
1169
+ // For now, let's just trigger a check() to fully hydrate state
1170
+ <span class="cstat-no" title="statement not covered" > await this.check(access);</span>
1171
+ <span class="cstat-no" title="statement not covered" > }</span>
1172
+ &nbsp;
1173
+ <span class="fstat-no" title="function not covered" > async signIn&lt;Name extends keyof S['access'] &amp; string&gt;(</span>
1174
+ <span class="cstat-no" title="statement not covered" > accessName: Name,</span>
1175
+ <span class="cstat-no" title="statement not covered" > params: ExtractAccessParams&lt;S, Name, 'signIn'&gt;</span>
1176
+ <span class="cstat-no" title="statement not covered" > ) {</span>
1177
+ <span class="cstat-no" title="statement not covered" > const def = this.getAccessDefinition(accessName);</span>
1178
+ <span class="cstat-no" title="statement not covered" > if (!def) throw new Error(`Access definition '${accessName}' not found`);</span>
1179
+ &nbsp;
1180
+ <span class="cstat-no" title="statement not covered" > const runtimeParams = params as Record&lt;string, any&gt;;</span>
1181
+ &nbsp;
1182
+ // Verify all required params are present
1183
+ <span class="cstat-no" title="statement not covered" > const missingParams = Object.entries(def.signIn.params)</span>
1184
+ <span class="cstat-no" title="statement not covered" > .filter(([name, schema]) =&gt; !schema.optional &amp;&amp; !(name in runtimeParams))</span>
1185
+ <span class="cstat-no" title="statement not covered" > .map(([name]) =&gt; name);</span>
1186
+ &nbsp;
1187
+ <span class="cstat-no" title="statement not covered" > if (missingParams.length &gt; 0) {</span>
1188
+ <span class="cstat-no" title="statement not covered" > throw new Error(</span>
1189
+ <span class="cstat-no" title="statement not covered" > `Missing required signin params for '${accessName}': ${missingParams.join(', ')}`</span>
1190
+ <span class="cstat-no" title="statement not covered" > );</span>
1191
+ <span class="cstat-no" title="statement not covered" > }</span>
1192
+ &nbsp;
1193
+ <span class="cstat-no" title="statement not covered" > this.logger.info(</span>
1194
+ <span class="cstat-no" title="statement not covered" > { accessName, Category: 'sp00ky-client::AuthService::signIn' },</span>
1195
+ <span class="cstat-no" title="statement not covered" > 'Attempting signin'</span>
1196
+ <span class="cstat-no" title="statement not covered" > );</span>
1197
+ &nbsp;
1198
+ <span class="cstat-no" title="statement not covered" > const { access } = await this.remote.getClient().signin({</span>
1199
+ <span class="cstat-no" title="statement not covered" > access: accessName,</span>
1200
+ <span class="cstat-no" title="statement not covered" > variables: runtimeParams,</span>
1201
+ <span class="cstat-no" title="statement not covered" > });</span>
1202
+ &nbsp;
1203
+ <span class="cstat-no" title="statement not covered" > await this.check(access);</span>
1204
+ <span class="cstat-no" title="statement not covered" > }</span>
1205
+ }
1206
+ &nbsp;</pre></td></tr></table></pre>
1207
+
1208
+ <div class='push'></div><!-- for sticky footer -->
1209
+ </div><!-- /wrapper -->
1210
+ <div class='footer quiet pad2 space-top1 center small'>
1211
+ Code coverage generated by
1212
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1213
+ at 2026-09-09T09:49:51.780Z
1214
+ </div>
1215
+ <script src="../../../prettify.js"></script>
1216
+ <script>
1217
+ window.onload = function () {
1218
+ prettyPrint();
1219
+ };
1220
+ </script>
1221
+ <script src="../../../sorter.js"></script>
1222
+ <script src="../../../block-navigation.js"></script>
1223
+ </body>
1224
+ </html>
1225
+