@prabhask5/stellar-engine 1.1.6 → 1.1.8

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 (265) hide show
  1. package/README.md +68 -25
  2. package/dist/actions/remoteChange.d.ts +143 -18
  3. package/dist/actions/remoteChange.d.ts.map +1 -1
  4. package/dist/actions/remoteChange.js +182 -58
  5. package/dist/actions/remoteChange.js.map +1 -1
  6. package/dist/actions/truncateTooltip.d.ts +56 -0
  7. package/dist/actions/truncateTooltip.d.ts.map +1 -0
  8. package/dist/actions/truncateTooltip.js +312 -0
  9. package/dist/actions/truncateTooltip.js.map +1 -0
  10. package/dist/auth/admin.d.ts +40 -3
  11. package/dist/auth/admin.d.ts.map +1 -1
  12. package/dist/auth/admin.js +45 -5
  13. package/dist/auth/admin.js.map +1 -1
  14. package/dist/auth/crypto.d.ts +55 -5
  15. package/dist/auth/crypto.d.ts.map +1 -1
  16. package/dist/auth/crypto.js +58 -5
  17. package/dist/auth/crypto.js.map +1 -1
  18. package/dist/auth/deviceVerification.d.ts +236 -20
  19. package/dist/auth/deviceVerification.d.ts.map +1 -1
  20. package/dist/auth/deviceVerification.js +293 -40
  21. package/dist/auth/deviceVerification.js.map +1 -1
  22. package/dist/auth/displayUtils.d.ts +98 -0
  23. package/dist/auth/displayUtils.d.ts.map +1 -0
  24. package/dist/auth/displayUtils.js +133 -0
  25. package/dist/auth/displayUtils.js.map +1 -0
  26. package/dist/auth/loginGuard.d.ts +108 -14
  27. package/dist/auth/loginGuard.d.ts.map +1 -1
  28. package/dist/auth/loginGuard.js +153 -31
  29. package/dist/auth/loginGuard.js.map +1 -1
  30. package/dist/auth/offlineCredentials.d.ts +132 -15
  31. package/dist/auth/offlineCredentials.d.ts.map +1 -1
  32. package/dist/auth/offlineCredentials.js +167 -23
  33. package/dist/auth/offlineCredentials.js.map +1 -1
  34. package/dist/auth/offlineLogin.d.ts +96 -10
  35. package/dist/auth/offlineLogin.d.ts.map +1 -1
  36. package/dist/auth/offlineLogin.js +82 -15
  37. package/dist/auth/offlineLogin.js.map +1 -1
  38. package/dist/auth/offlineSession.d.ts +83 -9
  39. package/dist/auth/offlineSession.d.ts.map +1 -1
  40. package/dist/auth/offlineSession.js +104 -13
  41. package/dist/auth/offlineSession.js.map +1 -1
  42. package/dist/auth/resolveAuthState.d.ts +70 -8
  43. package/dist/auth/resolveAuthState.d.ts.map +1 -1
  44. package/dist/auth/resolveAuthState.js +142 -46
  45. package/dist/auth/resolveAuthState.js.map +1 -1
  46. package/dist/auth/singleUser.d.ts +390 -37
  47. package/dist/auth/singleUser.d.ts.map +1 -1
  48. package/dist/auth/singleUser.js +505 -133
  49. package/dist/auth/singleUser.js.map +1 -1
  50. package/dist/bin/install-pwa.d.ts +25 -0
  51. package/dist/bin/install-pwa.d.ts.map +1 -0
  52. package/dist/bin/install-pwa.js +2197 -0
  53. package/dist/bin/install-pwa.js.map +1 -0
  54. package/dist/config.d.ts +132 -12
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +87 -9
  57. package/dist/config.js.map +1 -1
  58. package/dist/conflicts.d.ts +246 -23
  59. package/dist/conflicts.d.ts.map +1 -1
  60. package/dist/conflicts.js +495 -46
  61. package/dist/conflicts.js.map +1 -1
  62. package/dist/data.d.ts +338 -18
  63. package/dist/data.d.ts.map +1 -1
  64. package/dist/data.js +385 -34
  65. package/dist/data.js.map +1 -1
  66. package/dist/database.d.ts +72 -14
  67. package/dist/database.d.ts.map +1 -1
  68. package/dist/database.js +120 -29
  69. package/dist/database.js.map +1 -1
  70. package/dist/debug.d.ts +77 -1
  71. package/dist/debug.d.ts.map +1 -1
  72. package/dist/debug.js +88 -1
  73. package/dist/debug.js.map +1 -1
  74. package/dist/deviceId.d.ts +38 -7
  75. package/dist/deviceId.d.ts.map +1 -1
  76. package/dist/deviceId.js +68 -10
  77. package/dist/deviceId.js.map +1 -1
  78. package/dist/engine.d.ts +175 -3
  79. package/dist/engine.d.ts.map +1 -1
  80. package/dist/engine.js +831 -110
  81. package/dist/engine.js.map +1 -1
  82. package/dist/entries/actions.d.ts +14 -0
  83. package/dist/entries/actions.d.ts.map +1 -1
  84. package/dist/entries/actions.js +27 -1
  85. package/dist/entries/actions.js.map +1 -1
  86. package/dist/entries/auth.d.ts +16 -0
  87. package/dist/entries/auth.d.ts.map +1 -1
  88. package/dist/entries/auth.js +73 -1
  89. package/dist/entries/auth.js.map +1 -1
  90. package/dist/entries/config.d.ts +12 -0
  91. package/dist/entries/config.d.ts.map +1 -1
  92. package/dist/entries/config.js +18 -1
  93. package/dist/entries/config.js.map +1 -1
  94. package/dist/entries/kit.d.ts +21 -9
  95. package/dist/entries/kit.d.ts.map +1 -1
  96. package/dist/entries/kit.js +57 -8
  97. package/dist/entries/kit.js.map +1 -1
  98. package/dist/entries/stores.d.ts +11 -0
  99. package/dist/entries/stores.d.ts.map +1 -1
  100. package/dist/entries/stores.js +43 -2
  101. package/dist/entries/stores.js.map +1 -1
  102. package/dist/entries/types.d.ts +11 -1
  103. package/dist/entries/types.d.ts.map +1 -1
  104. package/dist/entries/types.js +10 -0
  105. package/dist/entries/types.js.map +1 -1
  106. package/dist/entries/utils.d.ts +7 -1
  107. package/dist/entries/utils.d.ts.map +1 -1
  108. package/dist/entries/utils.js +23 -2
  109. package/dist/entries/utils.js.map +1 -1
  110. package/dist/entries/vite.d.ts +20 -0
  111. package/dist/entries/vite.d.ts.map +1 -0
  112. package/dist/entries/vite.js +26 -0
  113. package/dist/entries/vite.js.map +1 -0
  114. package/dist/index.d.ts +33 -2
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +176 -21
  117. package/dist/index.js.map +1 -1
  118. package/dist/kit/auth.d.ts +80 -0
  119. package/dist/kit/auth.d.ts.map +1 -0
  120. package/dist/kit/auth.js +72 -0
  121. package/dist/kit/auth.js.map +1 -0
  122. package/dist/kit/confirm.d.ts +111 -0
  123. package/dist/kit/confirm.d.ts.map +1 -0
  124. package/dist/kit/confirm.js +169 -0
  125. package/dist/kit/confirm.js.map +1 -0
  126. package/dist/kit/loads.d.ts +189 -0
  127. package/dist/kit/loads.d.ts.map +1 -0
  128. package/dist/kit/loads.js +205 -0
  129. package/dist/kit/loads.js.map +1 -0
  130. package/dist/kit/server.d.ts +175 -0
  131. package/dist/kit/server.d.ts.map +1 -0
  132. package/dist/kit/server.js +297 -0
  133. package/dist/kit/server.js.map +1 -0
  134. package/dist/kit/sw.d.ts +176 -0
  135. package/dist/kit/sw.d.ts.map +1 -0
  136. package/dist/kit/sw.js +320 -0
  137. package/dist/kit/sw.js.map +1 -0
  138. package/dist/queue.d.ts +274 -0
  139. package/dist/queue.d.ts.map +1 -1
  140. package/dist/queue.js +556 -38
  141. package/dist/queue.js.map +1 -1
  142. package/dist/realtime.d.ts +241 -27
  143. package/dist/realtime.d.ts.map +1 -1
  144. package/dist/realtime.js +633 -109
  145. package/dist/realtime.js.map +1 -1
  146. package/dist/runtime/runtimeConfig.d.ts +91 -16
  147. package/dist/runtime/runtimeConfig.d.ts.map +1 -1
  148. package/dist/runtime/runtimeConfig.js +146 -19
  149. package/dist/runtime/runtimeConfig.js.map +1 -1
  150. package/dist/stores/authState.d.ts +150 -11
  151. package/dist/stores/authState.d.ts.map +1 -1
  152. package/dist/stores/authState.js +169 -17
  153. package/dist/stores/authState.js.map +1 -1
  154. package/dist/stores/network.d.ts +39 -0
  155. package/dist/stores/network.d.ts.map +1 -1
  156. package/dist/stores/network.js +169 -16
  157. package/dist/stores/network.js.map +1 -1
  158. package/dist/stores/remoteChanges.d.ts +327 -52
  159. package/dist/stores/remoteChanges.d.ts.map +1 -1
  160. package/dist/stores/remoteChanges.js +337 -75
  161. package/dist/stores/remoteChanges.js.map +1 -1
  162. package/dist/stores/sync.d.ts +130 -0
  163. package/dist/stores/sync.d.ts.map +1 -1
  164. package/dist/stores/sync.js +167 -7
  165. package/dist/stores/sync.js.map +1 -1
  166. package/dist/supabase/auth.d.ts +326 -19
  167. package/dist/supabase/auth.d.ts.map +1 -1
  168. package/dist/supabase/auth.js +374 -26
  169. package/dist/supabase/auth.js.map +1 -1
  170. package/dist/supabase/client.d.ts +79 -6
  171. package/dist/supabase/client.d.ts.map +1 -1
  172. package/dist/supabase/client.js +158 -15
  173. package/dist/supabase/client.js.map +1 -1
  174. package/dist/supabase/validate.d.ts +101 -7
  175. package/dist/supabase/validate.d.ts.map +1 -1
  176. package/dist/supabase/validate.js +117 -8
  177. package/dist/supabase/validate.js.map +1 -1
  178. package/dist/sw/build/vite-plugin.d.ts +74 -0
  179. package/dist/sw/build/vite-plugin.d.ts.map +1 -0
  180. package/dist/sw/build/vite-plugin.js +183 -0
  181. package/dist/sw/build/vite-plugin.js.map +1 -0
  182. package/dist/sw/sw.js +669 -0
  183. package/dist/types.d.ts +150 -45
  184. package/dist/types.d.ts.map +1 -1
  185. package/dist/types.js +12 -10
  186. package/dist/types.js.map +1 -1
  187. package/dist/utils.d.ts +55 -13
  188. package/dist/utils.d.ts.map +1 -1
  189. package/dist/utils.js +83 -22
  190. package/dist/utils.js.map +1 -1
  191. package/package.json +20 -22
  192. package/src/components/DeferredChangesBanner.svelte +477 -0
  193. package/src/components/SyncStatus.svelte +1732 -0
  194. package/dist/crdt/awareness.d.ts +0 -54
  195. package/dist/crdt/awareness.d.ts.map +0 -1
  196. package/dist/crdt/awareness.js +0 -219
  197. package/dist/crdt/awareness.js.map +0 -1
  198. package/dist/crdt/doc.d.ts +0 -56
  199. package/dist/crdt/doc.d.ts.map +0 -1
  200. package/dist/crdt/doc.js +0 -130
  201. package/dist/crdt/doc.js.map +0 -1
  202. package/dist/crdt/index.d.ts +0 -15
  203. package/dist/crdt/index.d.ts.map +0 -1
  204. package/dist/crdt/index.js +0 -20
  205. package/dist/crdt/index.js.map +0 -1
  206. package/dist/crdt/offline.d.ts +0 -91
  207. package/dist/crdt/offline.d.ts.map +0 -1
  208. package/dist/crdt/offline.js +0 -353
  209. package/dist/crdt/offline.js.map +0 -1
  210. package/dist/crdt/sync.d.ts +0 -58
  211. package/dist/crdt/sync.d.ts.map +0 -1
  212. package/dist/crdt/sync.js +0 -399
  213. package/dist/crdt/sync.js.map +0 -1
  214. package/dist/crdt/types.d.ts +0 -62
  215. package/dist/crdt/types.d.ts.map +0 -1
  216. package/dist/crdt/types.js +0 -7
  217. package/dist/crdt/types.js.map +0 -1
  218. package/dist/email/sendEmail.d.ts +0 -31
  219. package/dist/email/sendEmail.d.ts.map +0 -1
  220. package/dist/email/sendEmail.js +0 -39
  221. package/dist/email/sendEmail.js.map +0 -1
  222. package/dist/email/validateSmtp.d.ts +0 -18
  223. package/dist/email/validateSmtp.d.ts.map +0 -1
  224. package/dist/email/validateSmtp.js +0 -33
  225. package/dist/email/validateSmtp.js.map +0 -1
  226. package/dist/entries/crdt.d.ts +0 -3
  227. package/dist/entries/crdt.d.ts.map +0 -1
  228. package/dist/entries/crdt.js +0 -13
  229. package/dist/entries/crdt.js.map +0 -1
  230. package/dist/entries/email.d.ts +0 -4
  231. package/dist/entries/email.d.ts.map +0 -1
  232. package/dist/entries/email.js +0 -4
  233. package/dist/entries/email.js.map +0 -1
  234. package/dist/kit/authPresets.d.ts +0 -28
  235. package/dist/kit/authPresets.d.ts.map +0 -1
  236. package/dist/kit/authPresets.js +0 -23
  237. package/dist/kit/authPresets.js.map +0 -1
  238. package/dist/kit/configEndpoint.d.ts +0 -18
  239. package/dist/kit/configEndpoint.d.ts.map +0 -1
  240. package/dist/kit/configEndpoint.js +0 -27
  241. package/dist/kit/configEndpoint.js.map +0 -1
  242. package/dist/kit/deployEndpoint.d.ts +0 -22
  243. package/dist/kit/deployEndpoint.d.ts.map +0 -1
  244. package/dist/kit/deployEndpoint.js +0 -79
  245. package/dist/kit/deployEndpoint.js.map +0 -1
  246. package/dist/kit/layoutLoad.d.ts +0 -23
  247. package/dist/kit/layoutLoad.d.ts.map +0 -1
  248. package/dist/kit/layoutLoad.js +0 -41
  249. package/dist/kit/layoutLoad.js.map +0 -1
  250. package/dist/kit/protectedLoad.d.ts +0 -16
  251. package/dist/kit/protectedLoad.d.ts.map +0 -1
  252. package/dist/kit/protectedLoad.js +0 -28
  253. package/dist/kit/protectedLoad.js.map +0 -1
  254. package/dist/kit/setupLoad.d.ts +0 -11
  255. package/dist/kit/setupLoad.d.ts.map +0 -1
  256. package/dist/kit/setupLoad.js +0 -28
  257. package/dist/kit/setupLoad.js.map +0 -1
  258. package/dist/kit/validateEndpoint.d.ts +0 -9
  259. package/dist/kit/validateEndpoint.d.ts.map +0 -1
  260. package/dist/kit/validateEndpoint.js +0 -25
  261. package/dist/kit/validateEndpoint.js.map +0 -1
  262. package/dist/kit/vercelApi.d.ts +0 -6
  263. package/dist/kit/vercelApi.d.ts.map +0 -1
  264. package/dist/kit/vercelApi.js +0 -48
  265. package/dist/kit/vercelApi.js.map +0 -1
@@ -0,0 +1,312 @@
1
+ /**
2
+ * @fileoverview Svelte action for truncated-text tooltips.
3
+ *
4
+ * Provides a `use:truncateTooltip` directive that enforces CSS text-overflow
5
+ * ellipsis on the target element and shows a floating tooltip with the
6
+ * **full** text whenever the content is visually truncated.
7
+ *
8
+ * **Behaviour by device type:**
9
+ * - **Desktop** — tooltip appears on `mouseenter`, hides on `mouseleave`.
10
+ * Only shown when `scrollWidth > clientWidth` (text is actually clipped).
11
+ * - **Mobile** — tooltip appears on `touchstart` (tap), dismisses on
12
+ * tap-outside or after a 3-second auto-dismiss timeout.
13
+ *
14
+ * A **singleton** tooltip `<div>` is lazily appended to `document.body` and
15
+ * reused across all instances of the action to avoid DOM bloat.
16
+ *
17
+ * @example
18
+ * ```svelte
19
+ * <span class="my-text" use:truncateTooltip>{longText}</span>
20
+ * ```
21
+ *
22
+ * @see {@link truncateTooltip} for the Svelte action export
23
+ * @see {@link showTooltip} for the display logic
24
+ * @see {@link positionTooltip} for the positioning algorithm
25
+ */
26
+ // =============================================================================
27
+ // SINGLETON TOOLTIP STATE
28
+ // =============================================================================
29
+ /**
30
+ * The shared tooltip DOM element — lazily created by {@link getTooltip}.
31
+ * Only one tooltip element exists in the entire document, regardless of
32
+ * how many `use:truncateTooltip` instances are active.
33
+ */
34
+ let tooltipEl = null;
35
+ /**
36
+ * Handle for the mobile auto-dismiss `setTimeout`.
37
+ * Cleared on manual hide to prevent stale timeouts from
38
+ * dismissing a newly-shown tooltip.
39
+ */
40
+ let hideTimeout = null;
41
+ /**
42
+ * The DOM element that currently "owns" the visible tooltip.
43
+ * Used to prevent hide events from one element dismissing another's tooltip,
44
+ * and to implement tap-toggle behaviour on mobile (tap same element = hide).
45
+ */
46
+ let currentOwner = null;
47
+ // =============================================================================
48
+ // TOOLTIP ELEMENT MANAGEMENT
49
+ // =============================================================================
50
+ /**
51
+ * Return the singleton tooltip element, creating it on first call.
52
+ *
53
+ * The element is given the CSS class `truncate-tooltip` and an ARIA
54
+ * `role="tooltip"` attribute for accessibility. The consuming app must
55
+ * provide CSS for `.truncate-tooltip` (positioning, background, etc.)
56
+ * and a `.visible` modifier class to control opacity/display.
57
+ *
58
+ * @returns The shared tooltip `HTMLElement`.
59
+ */
60
+ function getTooltip() {
61
+ if (!tooltipEl) {
62
+ tooltipEl = document.createElement('div');
63
+ tooltipEl.className = 'truncate-tooltip';
64
+ tooltipEl.setAttribute('role', 'tooltip');
65
+ document.body.appendChild(tooltipEl);
66
+ }
67
+ return tooltipEl;
68
+ }
69
+ // =============================================================================
70
+ // TRUNCATION DETECTION
71
+ // =============================================================================
72
+ /**
73
+ * Check whether an element's text content is visually truncated.
74
+ *
75
+ * Compares `scrollWidth` (full content width including overflow) against
76
+ * `clientWidth` (visible width). When `scrollWidth` exceeds `clientWidth`,
77
+ * the CSS `text-overflow: ellipsis` rule is hiding part of the text.
78
+ *
79
+ * @param el - The DOM element to test.
80
+ * @returns `true` if the text overflows its container.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * if (isTruncated(spanElement)) {
85
+ * showTooltip(spanElement);
86
+ * }
87
+ * ```
88
+ */
89
+ function isTruncated(el) {
90
+ return el.scrollWidth > el.clientWidth;
91
+ }
92
+ // =============================================================================
93
+ // TOOLTIP POSITIONING
94
+ // =============================================================================
95
+ /**
96
+ * Position the tooltip relative to an anchor element.
97
+ *
98
+ * Default placement is **centred above** the anchor with an 8 px gap.
99
+ * Two edge-case corrections are applied:
100
+ * 1. If the tooltip would overflow the **top** of the viewport, it flips
101
+ * to appear **below** the anchor instead.
102
+ * 2. The horizontal position is clamped to keep the tooltip within the
103
+ * viewport (8 px padding on each side).
104
+ *
105
+ * @param tooltip - The tooltip element to reposition.
106
+ * @param anchor - The element the tooltip should point at.
107
+ */
108
+ function positionTooltip(tooltip, anchor) {
109
+ const rect = anchor.getBoundingClientRect();
110
+ const tooltipRect = tooltip.getBoundingClientRect();
111
+ /* ── Default: centred above the anchor ──── */
112
+ let left = rect.left + rect.width / 2 - tooltipRect.width / 2;
113
+ let top = rect.top - tooltipRect.height - 8;
114
+ /* Flip below if tooltip would overflow the top edge */
115
+ if (top < 4) {
116
+ top = rect.bottom + 8;
117
+ }
118
+ /* ── Horizontal clamping ──── */
119
+ const maxLeft = window.innerWidth - tooltipRect.width - 8;
120
+ left = Math.max(8, Math.min(left, maxLeft));
121
+ tooltip.style.left = `${left}px`;
122
+ tooltip.style.top = `${top}px`;
123
+ }
124
+ // =============================================================================
125
+ // SHOW / HIDE LOGIC
126
+ // =============================================================================
127
+ /**
128
+ * Show the tooltip for the given anchor element.
129
+ *
130
+ * Exits early if the anchor's text is **not** truncated (no tooltip needed).
131
+ * Positioning is deferred to the next animation frame so that the tooltip's
132
+ * dimensions are accurate after its `textContent` is set.
133
+ *
134
+ * @param anchor - The element whose full text should be displayed in the tooltip.
135
+ */
136
+ function showTooltip(anchor) {
137
+ if (!isTruncated(anchor))
138
+ return;
139
+ const tooltip = getTooltip();
140
+ const fullText = anchor.textContent?.trim() || '';
141
+ if (!fullText)
142
+ return;
143
+ /* Cancel any pending auto-dismiss from a previous mobile tap */
144
+ if (hideTimeout) {
145
+ clearTimeout(hideTimeout);
146
+ hideTimeout = null;
147
+ }
148
+ tooltip.textContent = fullText;
149
+ tooltip.classList.add('visible');
150
+ currentOwner = anchor;
151
+ /* Position after content is set so dimensions are correct */
152
+ requestAnimationFrame(() => {
153
+ positionTooltip(tooltip, anchor);
154
+ });
155
+ }
156
+ /**
157
+ * Hide the tooltip and reset ownership state.
158
+ *
159
+ * Safe to call even when no tooltip is visible — the function is a no-op
160
+ * in that case. Also clears any pending auto-dismiss timeout.
161
+ */
162
+ function hideTooltip() {
163
+ if (tooltipEl) {
164
+ tooltipEl.classList.remove('visible');
165
+ }
166
+ currentOwner = null;
167
+ if (hideTimeout) {
168
+ clearTimeout(hideTimeout);
169
+ hideTimeout = null;
170
+ }
171
+ }
172
+ // =============================================================================
173
+ // DEVICE DETECTION
174
+ // =============================================================================
175
+ /**
176
+ * Detect whether the current device supports touch input.
177
+ *
178
+ * Uses feature detection (`ontouchstart` in `window` or `maxTouchPoints`)
179
+ * rather than user-agent sniffing, which is more reliable across browsers
180
+ * and avoids false negatives on hybrid devices.
181
+ *
182
+ * @returns `true` on touch-capable devices.
183
+ */
184
+ function isTouchDevice() {
185
+ return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
186
+ }
187
+ // =============================================================================
188
+ // SVELTE ACTION EXPORT
189
+ // =============================================================================
190
+ /**
191
+ * Svelte action that applies truncation-aware tooltips to an element.
192
+ *
193
+ * **On mount the action:**
194
+ * 1. Forces CSS `overflow: hidden`, `text-overflow: ellipsis`, and
195
+ * `white-space: nowrap` on the node to guarantee ellipsis rendering.
196
+ * 2. Registers `mouseenter` / `mouseleave` handlers for desktop hover.
197
+ * 3. Registers `touchstart` handlers for mobile tap-to-show behaviour.
198
+ * 4. Registers a document-level `touchstart` listener for tap-outside
199
+ * dismissal on mobile.
200
+ *
201
+ * The returned `destroy` callback cleans up all listeners and hides the
202
+ * tooltip if the destroyed node was its current owner.
203
+ *
204
+ * @param node - The DOM element to enhance with truncation tooltips.
205
+ * @returns A Svelte action lifecycle object with a `destroy` method.
206
+ *
207
+ * @example
208
+ * ```svelte
209
+ * <span class="my-text" use:truncateTooltip>{longText}</span>
210
+ * ```
211
+ */
212
+ export function truncateTooltip(node) {
213
+ /* ── Apply ellipsis CSS ──── */
214
+ node.style.overflow = 'hidden';
215
+ node.style.textOverflow = 'ellipsis';
216
+ node.style.whiteSpace = 'nowrap';
217
+ // ---------------------------------------------------------------------------
218
+ // DESKTOP: HOVER HANDLERS
219
+ // ---------------------------------------------------------------------------
220
+ /**
221
+ * Show tooltip on mouse enter (desktop only).
222
+ * Skips on touch devices to avoid double-triggering with touch handlers.
223
+ */
224
+ function handleMouseEnter() {
225
+ if (isTouchDevice())
226
+ return;
227
+ showTooltip(node);
228
+ }
229
+ /**
230
+ * Hide tooltip on mouse leave, but only if this node owns the tooltip.
231
+ * Prevents one element's mouseleave from dismissing another's tooltip.
232
+ */
233
+ function handleMouseLeave() {
234
+ if (currentOwner === node) {
235
+ hideTooltip();
236
+ }
237
+ }
238
+ // ---------------------------------------------------------------------------
239
+ // MOBILE: TAP HANDLERS
240
+ // ---------------------------------------------------------------------------
241
+ /**
242
+ * Toggle tooltip on tap (mobile only).
243
+ *
244
+ * Prevents default to avoid triggering navigation or text selection.
245
+ * Stops propagation to prevent the document-level tap-outside handler
246
+ * from immediately dismissing the tooltip.
247
+ * Auto-dismisses after 3 seconds.
248
+ *
249
+ * @param e - The touch event.
250
+ */
251
+ function handleTap(e) {
252
+ if (!isTouchDevice())
253
+ return;
254
+ if (!isTruncated(node))
255
+ return;
256
+ e.preventDefault();
257
+ e.stopPropagation();
258
+ /* Toggle off if already showing for this node */
259
+ if (currentOwner === node) {
260
+ hideTooltip();
261
+ return;
262
+ }
263
+ showTooltip(node);
264
+ /* Auto-dismiss after 3 s on mobile */
265
+ hideTimeout = setTimeout(hideTooltip, 3000);
266
+ }
267
+ /**
268
+ * Dismiss the tooltip when the user taps outside the anchor or tooltip
269
+ * (mobile only). Ignores taps on the anchor itself or inside the tooltip
270
+ * to prevent unintended dismissal.
271
+ *
272
+ * @param e - The document-level touch event.
273
+ */
274
+ function handleTapOutside(e) {
275
+ if (!currentOwner || currentOwner !== node)
276
+ return;
277
+ const target = e.target;
278
+ if (target === node || node.contains(target))
279
+ return;
280
+ if (tooltipEl && (target === tooltipEl || tooltipEl.contains(target)))
281
+ return;
282
+ hideTooltip();
283
+ }
284
+ // ---------------------------------------------------------------------------
285
+ // EVENT LISTENER REGISTRATION
286
+ // ---------------------------------------------------------------------------
287
+ node.addEventListener('mouseenter', handleMouseEnter);
288
+ node.addEventListener('mouseleave', handleMouseLeave);
289
+ node.addEventListener('touchstart', handleTap, { passive: false });
290
+ document.addEventListener('touchstart', handleTapOutside, { passive: true });
291
+ // ---------------------------------------------------------------------------
292
+ // SVELTE ACTION LIFECYCLE
293
+ // ---------------------------------------------------------------------------
294
+ return {
295
+ /**
296
+ * Cleanup handler — removes all event listeners and hides the tooltip
297
+ * if this node was the active owner. Prevents memory leaks from
298
+ * orphaned document-level listeners.
299
+ */
300
+ destroy() {
301
+ node.removeEventListener('mouseenter', handleMouseEnter);
302
+ node.removeEventListener('mouseleave', handleMouseLeave);
303
+ node.removeEventListener('touchstart', handleTap);
304
+ document.removeEventListener('touchstart', handleTapOutside);
305
+ /* Clean up tooltip if this node was the active owner */
306
+ if (currentOwner === node) {
307
+ hideTooltip();
308
+ }
309
+ }
310
+ };
311
+ }
312
+ //# sourceMappingURL=truncateTooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncateTooltip.js","sourceRoot":"","sources":["../../src/actions/truncateTooltip.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,49 @@
1
1
  /**
2
- * Admin Check
2
+ * @fileoverview Admin Privilege Resolution
3
3
  *
4
- * Delegates to config.auth.adminCheck or returns false.
4
+ * Provides a single entry point for determining whether a given Supabase user
5
+ * holds administrative privileges within the application.
6
+ *
7
+ * Architecture:
8
+ * - Delegates entirely to the host application's `config.auth.adminCheck` callback.
9
+ * - In single-user mode, every authenticated user is implicitly an admin (there is
10
+ * only one user, so restricting admin access would be meaningless).
11
+ * - If the engine has not been initialized yet (e.g., during early bootstrap),
12
+ * the function silently returns `false` rather than throwing, ensuring safe
13
+ * usage in guards and UI conditionals before full initialization.
14
+ *
15
+ * Security considerations:
16
+ * - This is a **client-side convenience check** only. It must NOT be relied upon
17
+ * as an authorization boundary -- server-side RLS policies and edge-function
18
+ * guards are the true security layer.
19
+ * - The `adminCheck` callback is provided by the host app and can inspect any
20
+ * property on the Supabase `User` object (e.g., `app_metadata.role`).
21
+ *
22
+ * @module auth/admin
5
23
  */
6
24
  import type { User } from '@supabase/supabase-js';
7
25
  /**
8
26
  * Check if a user has admin privileges.
9
- * Uses the adminCheck function from engine config if provided.
27
+ *
28
+ * Uses the `adminCheck` function from engine config if provided.
29
+ * Falls back to `false` when no check is configured or the engine
30
+ * is not yet initialized.
31
+ *
32
+ * @param user - The Supabase user object to evaluate, or `null` if no user
33
+ * is currently authenticated.
34
+ * @returns `true` if the user is considered an admin, `false` otherwise.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { isAdmin } from 'stellar-engine/auth/admin';
39
+ *
40
+ * const admin = isAdmin(currentUser);
41
+ * if (admin) {
42
+ * showAdminPanel();
43
+ * }
44
+ * ```
45
+ *
46
+ * @see {@link getEngineConfig} for how the admin check callback is registered.
10
47
  */
11
48
  export declare function isAdmin(user: User | null): boolean;
12
49
  //# sourceMappingURL=admin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/auth/admin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAGlD;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAYlD"}
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/auth/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAOlD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAclD"}
@@ -1,17 +1,57 @@
1
1
  /**
2
- * Admin Check
2
+ * @fileoverview Admin Privilege Resolution
3
3
  *
4
- * Delegates to config.auth.adminCheck or returns false.
4
+ * Provides a single entry point for determining whether a given Supabase user
5
+ * holds administrative privileges within the application.
6
+ *
7
+ * Architecture:
8
+ * - Delegates entirely to the host application's `config.auth.adminCheck` callback.
9
+ * - In single-user mode, every authenticated user is implicitly an admin (there is
10
+ * only one user, so restricting admin access would be meaningless).
11
+ * - If the engine has not been initialized yet (e.g., during early bootstrap),
12
+ * the function silently returns `false` rather than throwing, ensuring safe
13
+ * usage in guards and UI conditionals before full initialization.
14
+ *
15
+ * Security considerations:
16
+ * - This is a **client-side convenience check** only. It must NOT be relied upon
17
+ * as an authorization boundary -- server-side RLS policies and edge-function
18
+ * guards are the true security layer.
19
+ * - The `adminCheck` callback is provided by the host app and can inspect any
20
+ * property on the Supabase `User` object (e.g., `app_metadata.role`).
21
+ *
22
+ * @module auth/admin
5
23
  */
6
24
  import { getEngineConfig } from '../config';
25
+ // =============================================================================
26
+ // PUBLIC API
27
+ // =============================================================================
7
28
  /**
8
29
  * Check if a user has admin privileges.
9
- * Uses the adminCheck function from engine config if provided.
30
+ *
31
+ * Uses the `adminCheck` function from engine config if provided.
32
+ * Falls back to `false` when no check is configured or the engine
33
+ * is not yet initialized.
34
+ *
35
+ * @param user - The Supabase user object to evaluate, or `null` if no user
36
+ * is currently authenticated.
37
+ * @returns `true` if the user is considered an admin, `false` otherwise.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import { isAdmin } from 'stellar-engine/auth/admin';
42
+ *
43
+ * const admin = isAdmin(currentUser);
44
+ * if (admin) {
45
+ * showAdminPanel();
46
+ * }
47
+ * ```
48
+ *
49
+ * @see {@link getEngineConfig} for how the admin check callback is registered.
10
50
  */
11
51
  export function isAdmin(user) {
12
52
  try {
13
53
  const config = getEngineConfig();
14
- // Single-user mode: always admin
54
+ /* Single-user mode: the sole user owns everything, so admin is implicit. */
15
55
  if (config.auth?.mode === 'single-user')
16
56
  return true;
17
57
  if (config.auth?.adminCheck) {
@@ -19,7 +59,7 @@ export function isAdmin(user) {
19
59
  }
20
60
  }
21
61
  catch {
22
- // Engine not initialized yet
62
+ /* Engine not initialized yet -- safe to swallow; callers expect a boolean. */
23
63
  }
24
64
  return false;
25
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/auth/admin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,IAAiB;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,iCAAiC;QACjC,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,KAAK,aAAa;YAAE,OAAO,IAAI,CAAC;QACrD,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC;YAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/auth/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,OAAO,CAAC,IAAiB;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QAEjC,4EAA4E;QAC5E,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,KAAK,aAAa;YAAE,OAAO,IAAI,CAAC;QAErD,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC;YAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8EAA8E;IAChF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1,14 +1,64 @@
1
1
  /**
2
- * Shared Crypto Utilities
3
- * SHA-256 hashing for passwords, codes, and other values.
2
+ * @fileoverview Shared Cryptographic Utilities
3
+ *
4
+ * Provides deterministic, one-way hashing primitives used throughout the auth
5
+ * subsystem for password storage, gate-code verification, and credential caching.
6
+ *
7
+ * Architecture:
8
+ * - Uses the Web Crypto API (`crypto.subtle`) which is available in all modern
9
+ * browsers, Web Workers, and server-side runtimes (Node 15+, Deno, Bun).
10
+ * - Hashing is always SHA-256, producing a 64-character lowercase hex digest.
11
+ * This is NOT a password-hashing algorithm (bcrypt/argon2); it is used only
12
+ * for **local** cache comparisons. The server-side Supabase auth layer uses
13
+ * bcrypt for actual credential storage.
14
+ *
15
+ * Security considerations:
16
+ * - SHA-256 is collision-resistant but NOT suitable for brute-force-resistant
17
+ * password storage on its own. It is acceptable here because the hashed values
18
+ * are only stored in the client-side IndexedDB for offline pre-checking and
19
+ * are never transmitted to a server.
20
+ * - The `isAlreadyHashed` helper uses a regex heuristic (64-char hex). If a
21
+ * user's actual password happens to be a 64-char hex string, it will be
22
+ * misidentified as already hashed. This is an acceptable edge case given the
23
+ * vanishingly low probability and the local-only usage context.
24
+ *
25
+ * @module auth/crypto
4
26
  */
5
27
  /**
6
- * Hash a value using SHA-256 via Web Crypto API.
7
- * Returns a 64-character hex string.
28
+ * Hash a value using SHA-256 via the Web Crypto API.
29
+ *
30
+ * Encodes the input string as UTF-8, computes the SHA-256 digest, and returns
31
+ * the result as a 64-character lowercase hexadecimal string.
32
+ *
33
+ * @param value - The plaintext string to hash (e.g., a password or gate code).
34
+ * @returns A promise that resolves to a 64-character hex string representing
35
+ * the SHA-256 digest.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const hashed = await hashValue('my-secret-password');
40
+ * // hashed === 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' (example)
41
+ * ```
42
+ *
43
+ * @see {@link isAlreadyHashed} to check whether a string is already a hex digest.
8
44
  */
9
45
  export declare function hashValue(value: string): Promise<string>;
10
46
  /**
11
- * Check if a stored value is already hashed (64-char hex string).
47
+ * Check if a stored value is already hashed (64-character hex string).
48
+ *
49
+ * Used to distinguish between legacy plaintext credentials and modern
50
+ * SHA-256-hashed credentials in IndexedDB, enabling backward-compatible
51
+ * verification without a migration step.
52
+ *
53
+ * @param value - The string to test.
54
+ * @returns `true` if the value matches the pattern of a SHA-256 hex digest
55
+ * (exactly 64 lowercase hexadecimal characters), `false` otherwise.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * isAlreadyHashed('abc123'); // false
60
+ * isAlreadyHashed('e3b0c442...b855'); // true (64-char hex)
61
+ * ```
12
62
  */
13
63
  export declare function isAlreadyHashed(value: string): boolean;
14
64
  //# sourceMappingURL=crypto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/auth/crypto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD"}
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/auth/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD"}
@@ -1,10 +1,49 @@
1
1
  /**
2
- * Shared Crypto Utilities
3
- * SHA-256 hashing for passwords, codes, and other values.
2
+ * @fileoverview Shared Cryptographic Utilities
3
+ *
4
+ * Provides deterministic, one-way hashing primitives used throughout the auth
5
+ * subsystem for password storage, gate-code verification, and credential caching.
6
+ *
7
+ * Architecture:
8
+ * - Uses the Web Crypto API (`crypto.subtle`) which is available in all modern
9
+ * browsers, Web Workers, and server-side runtimes (Node 15+, Deno, Bun).
10
+ * - Hashing is always SHA-256, producing a 64-character lowercase hex digest.
11
+ * This is NOT a password-hashing algorithm (bcrypt/argon2); it is used only
12
+ * for **local** cache comparisons. The server-side Supabase auth layer uses
13
+ * bcrypt for actual credential storage.
14
+ *
15
+ * Security considerations:
16
+ * - SHA-256 is collision-resistant but NOT suitable for brute-force-resistant
17
+ * password storage on its own. It is acceptable here because the hashed values
18
+ * are only stored in the client-side IndexedDB for offline pre-checking and
19
+ * are never transmitted to a server.
20
+ * - The `isAlreadyHashed` helper uses a regex heuristic (64-char hex). If a
21
+ * user's actual password happens to be a 64-char hex string, it will be
22
+ * misidentified as already hashed. This is an acceptable edge case given the
23
+ * vanishingly low probability and the local-only usage context.
24
+ *
25
+ * @module auth/crypto
4
26
  */
27
+ // =============================================================================
28
+ // PUBLIC API
29
+ // =============================================================================
5
30
  /**
6
- * Hash a value using SHA-256 via Web Crypto API.
7
- * Returns a 64-character hex string.
31
+ * Hash a value using SHA-256 via the Web Crypto API.
32
+ *
33
+ * Encodes the input string as UTF-8, computes the SHA-256 digest, and returns
34
+ * the result as a 64-character lowercase hexadecimal string.
35
+ *
36
+ * @param value - The plaintext string to hash (e.g., a password or gate code).
37
+ * @returns A promise that resolves to a 64-character hex string representing
38
+ * the SHA-256 digest.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const hashed = await hashValue('my-secret-password');
43
+ * // hashed === 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' (example)
44
+ * ```
45
+ *
46
+ * @see {@link isAlreadyHashed} to check whether a string is already a hex digest.
8
47
  */
9
48
  export async function hashValue(value) {
10
49
  const encoder = new TextEncoder();
@@ -14,7 +53,21 @@ export async function hashValue(value) {
14
53
  return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
15
54
  }
16
55
  /**
17
- * Check if a stored value is already hashed (64-char hex string).
56
+ * Check if a stored value is already hashed (64-character hex string).
57
+ *
58
+ * Used to distinguish between legacy plaintext credentials and modern
59
+ * SHA-256-hashed credentials in IndexedDB, enabling backward-compatible
60
+ * verification without a migration step.
61
+ *
62
+ * @param value - The string to test.
63
+ * @returns `true` if the value matches the pattern of a SHA-256 hex digest
64
+ * (exactly 64 lowercase hexadecimal characters), `false` otherwise.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * isAlreadyHashed('abc123'); // false
69
+ * isAlreadyHashed('e3b0c442...b855'); // true (64-char hex)
70
+ * ```
18
71
  */
19
72
  export function isAlreadyHashed(value) {
20
73
  return /^[0-9a-f]{64}$/.test(value);
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/auth/crypto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa;IAC3C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IACzD,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/auth/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa;IAC3C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IACzD,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC"}