@prabhask5/stellar-engine 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -18
- package/dist/actions/remoteChange.d.ts +143 -18
- package/dist/actions/remoteChange.d.ts.map +1 -1
- package/dist/actions/remoteChange.js +182 -58
- package/dist/actions/remoteChange.js.map +1 -1
- package/dist/actions/truncateTooltip.d.ts +26 -12
- package/dist/actions/truncateTooltip.d.ts.map +1 -1
- package/dist/actions/truncateTooltip.js +89 -34
- package/dist/actions/truncateTooltip.js.map +1 -1
- package/dist/auth/crypto.d.ts +35 -8
- package/dist/auth/crypto.d.ts.map +1 -1
- package/dist/auth/crypto.js +38 -10
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/deviceVerification.d.ts +236 -20
- package/dist/auth/deviceVerification.d.ts.map +1 -1
- package/dist/auth/deviceVerification.js +293 -40
- package/dist/auth/deviceVerification.js.map +1 -1
- package/dist/auth/displayUtils.d.ts +98 -0
- package/dist/auth/displayUtils.d.ts.map +1 -0
- package/dist/auth/displayUtils.js +133 -0
- package/dist/auth/displayUtils.js.map +1 -0
- package/dist/auth/loginGuard.d.ts +103 -16
- package/dist/auth/loginGuard.d.ts.map +1 -1
- package/dist/auth/loginGuard.js +163 -76
- package/dist/auth/loginGuard.js.map +1 -1
- package/dist/auth/offlineCredentials.d.ts +88 -24
- package/dist/auth/offlineCredentials.d.ts.map +1 -1
- package/dist/auth/offlineCredentials.js +114 -73
- package/dist/auth/offlineCredentials.js.map +1 -1
- package/dist/auth/offlineSession.d.ts +83 -9
- package/dist/auth/offlineSession.d.ts.map +1 -1
- package/dist/auth/offlineSession.js +104 -13
- package/dist/auth/offlineSession.js.map +1 -1
- package/dist/auth/resolveAuthState.d.ts +67 -9
- package/dist/auth/resolveAuthState.d.ts.map +1 -1
- package/dist/auth/resolveAuthState.js +125 -71
- package/dist/auth/resolveAuthState.js.map +1 -1
- package/dist/auth/singleUser.d.ts +390 -37
- package/dist/auth/singleUser.d.ts.map +1 -1
- package/dist/auth/singleUser.js +504 -103
- package/dist/auth/singleUser.js.map +1 -1
- package/dist/bin/install-pwa.d.ts +18 -2
- package/dist/bin/install-pwa.d.ts.map +1 -1
- package/dist/bin/install-pwa.js +2624 -77
- package/dist/bin/install-pwa.js.map +1 -1
- package/dist/config.d.ts +131 -15
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +87 -9
- package/dist/config.js.map +1 -1
- package/dist/conflicts.d.ts +246 -23
- package/dist/conflicts.d.ts.map +1 -1
- package/dist/conflicts.js +495 -46
- package/dist/conflicts.js.map +1 -1
- package/dist/data.d.ts +338 -18
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +385 -34
- package/dist/data.js.map +1 -1
- package/dist/database.d.ts +72 -14
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +120 -29
- package/dist/database.js.map +1 -1
- package/dist/debug.d.ts +77 -1
- package/dist/debug.d.ts.map +1 -1
- package/dist/debug.js +88 -1
- package/dist/debug.js.map +1 -1
- package/dist/deviceId.d.ts +38 -7
- package/dist/deviceId.d.ts.map +1 -1
- package/dist/deviceId.js +68 -10
- package/dist/deviceId.js.map +1 -1
- package/dist/engine.d.ts +175 -3
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +756 -109
- package/dist/engine.js.map +1 -1
- package/dist/entries/actions.d.ts +13 -0
- package/dist/entries/actions.d.ts.map +1 -1
- package/dist/entries/actions.js +26 -1
- package/dist/entries/actions.js.map +1 -1
- package/dist/entries/auth.d.ts +15 -4
- package/dist/entries/auth.d.ts.map +1 -1
- package/dist/entries/auth.js +47 -4
- package/dist/entries/auth.js.map +1 -1
- package/dist/entries/config.d.ts +12 -0
- package/dist/entries/config.d.ts.map +1 -1
- package/dist/entries/config.js +18 -1
- package/dist/entries/config.js.map +1 -1
- package/dist/entries/kit.d.ts +11 -0
- package/dist/entries/kit.d.ts.map +1 -1
- package/dist/entries/kit.js +52 -2
- package/dist/entries/kit.js.map +1 -1
- package/dist/entries/stores.d.ts +11 -0
- package/dist/entries/stores.d.ts.map +1 -1
- package/dist/entries/stores.js +43 -2
- package/dist/entries/stores.js.map +1 -1
- package/dist/entries/types.d.ts +10 -1
- package/dist/entries/types.d.ts.map +1 -1
- package/dist/entries/types.js +10 -0
- package/dist/entries/types.js.map +1 -1
- package/dist/entries/utils.d.ts +6 -0
- package/dist/entries/utils.d.ts.map +1 -1
- package/dist/entries/utils.js +22 -1
- package/dist/entries/utils.js.map +1 -1
- package/dist/entries/vite.d.ts +17 -0
- package/dist/entries/vite.d.ts.map +1 -1
- package/dist/entries/vite.js +24 -1
- package/dist/entries/vite.js.map +1 -1
- package/dist/index.d.ts +32 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +166 -23
- package/dist/index.js.map +1 -1
- package/dist/kit/auth.d.ts +60 -5
- package/dist/kit/auth.d.ts.map +1 -1
- package/dist/kit/auth.js +45 -4
- package/dist/kit/auth.js.map +1 -1
- package/dist/kit/confirm.d.ts +93 -12
- package/dist/kit/confirm.d.ts.map +1 -1
- package/dist/kit/confirm.js +103 -16
- package/dist/kit/confirm.js.map +1 -1
- package/dist/kit/loads.d.ts +148 -23
- package/dist/kit/loads.d.ts.map +1 -1
- package/dist/kit/loads.js +136 -28
- package/dist/kit/loads.js.map +1 -1
- package/dist/kit/server.d.ts +142 -10
- package/dist/kit/server.d.ts.map +1 -1
- package/dist/kit/server.js +158 -15
- package/dist/kit/server.js.map +1 -1
- package/dist/kit/sw.d.ts +152 -23
- package/dist/kit/sw.d.ts.map +1 -1
- package/dist/kit/sw.js +182 -26
- package/dist/kit/sw.js.map +1 -1
- package/dist/queue.d.ts +274 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +556 -38
- package/dist/queue.js.map +1 -1
- package/dist/realtime.d.ts +241 -27
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +633 -109
- package/dist/realtime.js.map +1 -1
- package/dist/runtime/runtimeConfig.d.ts +91 -8
- package/dist/runtime/runtimeConfig.d.ts.map +1 -1
- package/dist/runtime/runtimeConfig.js +146 -19
- package/dist/runtime/runtimeConfig.js.map +1 -1
- package/dist/stores/authState.d.ts +150 -11
- package/dist/stores/authState.d.ts.map +1 -1
- package/dist/stores/authState.js +169 -17
- package/dist/stores/authState.js.map +1 -1
- package/dist/stores/network.d.ts +39 -0
- package/dist/stores/network.d.ts.map +1 -1
- package/dist/stores/network.js +169 -16
- package/dist/stores/network.js.map +1 -1
- package/dist/stores/remoteChanges.d.ts +327 -52
- package/dist/stores/remoteChanges.d.ts.map +1 -1
- package/dist/stores/remoteChanges.js +337 -75
- package/dist/stores/remoteChanges.js.map +1 -1
- package/dist/stores/sync.d.ts +130 -0
- package/dist/stores/sync.d.ts.map +1 -1
- package/dist/stores/sync.js +167 -7
- package/dist/stores/sync.js.map +1 -1
- package/dist/supabase/auth.d.ts +186 -46
- package/dist/supabase/auth.d.ts.map +1 -1
- package/dist/supabase/auth.js +238 -190
- package/dist/supabase/auth.js.map +1 -1
- package/dist/supabase/client.d.ts +79 -6
- package/dist/supabase/client.d.ts.map +1 -1
- package/dist/supabase/client.js +158 -15
- package/dist/supabase/client.js.map +1 -1
- package/dist/supabase/validate.d.ts +101 -7
- package/dist/supabase/validate.d.ts.map +1 -1
- package/dist/supabase/validate.js +117 -8
- package/dist/supabase/validate.js.map +1 -1
- package/dist/sw/build/vite-plugin.d.ts +55 -10
- package/dist/sw/build/vite-plugin.d.ts.map +1 -1
- package/dist/sw/build/vite-plugin.js +77 -18
- package/dist/sw/build/vite-plugin.js.map +1 -1
- package/dist/sw/sw.js +99 -44
- package/dist/types.d.ts +150 -26
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -10
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +55 -13
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +83 -22
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/dist/auth/admin.d.ts +0 -12
- package/dist/auth/admin.d.ts.map +0 -1
- package/dist/auth/admin.js +0 -26
- package/dist/auth/admin.js.map +0 -1
- package/dist/auth/offlineLogin.d.ts +0 -34
- package/dist/auth/offlineLogin.d.ts.map +0 -1
- package/dist/auth/offlineLogin.js +0 -75
- package/dist/auth/offlineLogin.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authState.d.ts","sourceRoot":"","sources":["../../src/stores/authState.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authState.d.ts","sourceRoot":"","sources":["../../src/stores/authState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMrD;;;GAGG;AACH,UAAU,SAAS;IACjB,iDAAiD;IACjD,IAAI,EAAE,QAAQ,CAAC;IAEf,wEAAwE;IACxE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAExB,0EAA0E;IAC1E,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAE1C,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AA8OD,gFAAgF;AAChF,eAAO,MAAM,SAAS;;IA3MlB;;;;;;;;;;;;;OAaG;6BACsB,OAAO,GAAG,IAAI;IAWvC;;;;;;;;;;;;;OAaG;4BACqB,kBAAkB,GAAG,IAAI;IAWjD;;;;;;;;;;;;;;;;;OAiBG;8BACuB,MAAM,GAAG,IAAI;IAWvC;;;;;;;OAOG;0BACmB,OAAO,GAAG,IAAI;IAIpC;;;;;OAKG;0BACmB,IAAI;IAI1B;;;;;;;;;;;OAWG;2BACoB,OAAO,GAAG,IAAI,GAAG,IAAI;IAkB5C;;;;;;;;;;;;;;OAcG;+BACwB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAiCzD;;;;;;OAMG;aACM,IAAI;CAiB8B,CAAC;AAMhD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,OAAO,CAG7C,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC;IACrC,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAeN,CAAC"}
|
package/dist/stores/authState.js
CHANGED
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview Authentication State Store
|
|
3
|
+
*
|
|
4
|
+
* Manages the current authentication mode and session data for the application.
|
|
5
|
+
* Supports three distinct authentication modes:
|
|
6
|
+
* - **supabase**: Online authentication via Supabase with a full session object
|
|
7
|
+
* - **offline**: Local/cached authentication using stored credentials
|
|
8
|
+
* - **none**: Unauthenticated state (login screen)
|
|
9
|
+
*
|
|
10
|
+
* **Svelte Store Pattern:**
|
|
11
|
+
* Uses a custom writable store created via the factory function `createAuthStateStore()`.
|
|
12
|
+
* The store exposes the standard `subscribe` method for reactivity, plus imperative
|
|
13
|
+
* mutation methods (e.g., `setSupabaseAuth`, `setOfflineAuth`) that internally call
|
|
14
|
+
* `update()` to ensure immutable state transitions.
|
|
15
|
+
*
|
|
16
|
+
* **Reactive Architecture:**
|
|
17
|
+
* Two derived stores (`isAuthenticated`, `userDisplayInfo`) project slices of the
|
|
18
|
+
* auth state for UI consumption, keeping components decoupled from the raw state shape.
|
|
19
|
+
* Components subscribe to these derived stores rather than inspecting the full auth
|
|
20
|
+
* state, which simplifies rendering logic and reduces unnecessary re-renders.
|
|
21
|
+
*
|
|
22
|
+
* @see {@link ../types} for AuthMode and OfflineCredentials type definitions
|
|
23
|
+
* @see {@link @supabase/supabase-js} for the Session type
|
|
4
24
|
*/
|
|
5
25
|
import { writable, derived } from 'svelte/store';
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Store Factory
|
|
28
|
+
// =============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Creates the singleton authentication state store.
|
|
31
|
+
*
|
|
32
|
+
* The store starts in a loading state (`mode: 'none', isLoading: true`) and
|
|
33
|
+
* transitions to a concrete mode once the auth subsystem determines whether
|
|
34
|
+
* a Supabase session, offline credentials, or neither are available.
|
|
35
|
+
*
|
|
36
|
+
* @returns A Svelte-compatible store with auth-specific mutation methods
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* // In the auth initialization flow:
|
|
41
|
+
* authState.setSupabaseAuth(session);
|
|
42
|
+
*
|
|
43
|
+
* // On logout or session expiry:
|
|
44
|
+
* authState.setNoAuth('Your session has expired.');
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
6
47
|
function createAuthStateStore() {
|
|
7
48
|
const { subscribe, set, update } = writable({
|
|
8
49
|
mode: 'none',
|
|
@@ -14,33 +55,70 @@ function createAuthStateStore() {
|
|
|
14
55
|
return {
|
|
15
56
|
subscribe,
|
|
16
57
|
/**
|
|
17
|
-
*
|
|
58
|
+
* Transition to Supabase-authenticated mode.
|
|
59
|
+
*
|
|
60
|
+
* Clears any offline profile and kicked message, sets loading to false,
|
|
61
|
+
* and stores the provided Supabase session.
|
|
62
|
+
*
|
|
63
|
+
* @param session - The active Supabase session object from sign-in or token refresh
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const { data } = await supabase.auth.signInWithPassword({ email, password });
|
|
68
|
+
* if (data.session) authState.setSupabaseAuth(data.session);
|
|
69
|
+
* ```
|
|
18
70
|
*/
|
|
19
71
|
setSupabaseAuth(session) {
|
|
20
72
|
update((state) => ({
|
|
21
73
|
...state,
|
|
22
74
|
mode: 'supabase',
|
|
23
75
|
session,
|
|
24
|
-
offlineProfile: null
|
|
76
|
+
offlineProfile: null /* Clear offline data to avoid stale cross-mode references */,
|
|
25
77
|
isLoading: false,
|
|
26
78
|
authKickedMessage: null
|
|
27
79
|
}));
|
|
28
80
|
},
|
|
29
81
|
/**
|
|
30
|
-
*
|
|
82
|
+
* Transition to offline-authenticated mode.
|
|
83
|
+
*
|
|
84
|
+
* Used when the app detects valid cached credentials but no network
|
|
85
|
+
* connectivity for Supabase verification.
|
|
86
|
+
*
|
|
87
|
+
* @param profile - The locally-cached offline credentials
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const cached = await loadCachedCredentials();
|
|
92
|
+
* if (cached) authState.setOfflineAuth(cached);
|
|
93
|
+
* ```
|
|
31
94
|
*/
|
|
32
95
|
setOfflineAuth(profile) {
|
|
33
96
|
update((state) => ({
|
|
34
97
|
...state,
|
|
35
98
|
mode: 'offline',
|
|
36
|
-
session: null
|
|
99
|
+
session: null /* Clear Supabase session since we're operating offline */,
|
|
37
100
|
offlineProfile: profile,
|
|
38
101
|
isLoading: false,
|
|
39
102
|
authKickedMessage: null
|
|
40
103
|
}));
|
|
41
104
|
},
|
|
42
105
|
/**
|
|
43
|
-
*
|
|
106
|
+
* Transition to unauthenticated mode.
|
|
107
|
+
*
|
|
108
|
+
* Clears all session and profile data. Optionally stores a human-readable
|
|
109
|
+
* message explaining why the user was signed out, which the login UI can
|
|
110
|
+
* display as a banner or toast.
|
|
111
|
+
*
|
|
112
|
+
* @param kickedMessage - Optional explanation for the forced sign-out
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* // Voluntary logout
|
|
117
|
+
* authState.setNoAuth();
|
|
118
|
+
*
|
|
119
|
+
* // Forced sign-out with reason
|
|
120
|
+
* authState.setNoAuth('Your session has expired.');
|
|
121
|
+
* ```
|
|
44
122
|
*/
|
|
45
123
|
setNoAuth(kickedMessage) {
|
|
46
124
|
update((state) => ({
|
|
@@ -53,25 +131,42 @@ function createAuthStateStore() {
|
|
|
53
131
|
}));
|
|
54
132
|
},
|
|
55
133
|
/**
|
|
56
|
-
*
|
|
134
|
+
* Update only the loading flag without altering the auth mode or session.
|
|
135
|
+
*
|
|
136
|
+
* Useful during initialization when the auth subsystem needs to signal
|
|
137
|
+
* that it is still resolving the session state.
|
|
138
|
+
*
|
|
139
|
+
* @param isLoading - Whether the auth subsystem is currently loading
|
|
57
140
|
*/
|
|
58
141
|
setLoading(isLoading) {
|
|
59
142
|
update((state) => ({ ...state, isLoading }));
|
|
60
143
|
},
|
|
61
144
|
/**
|
|
62
|
-
*
|
|
145
|
+
* Dismiss the kicked message without changing auth mode.
|
|
146
|
+
*
|
|
147
|
+
* Typically called after the login UI has displayed the kicked banner
|
|
148
|
+
* and the user has acknowledged it.
|
|
63
149
|
*/
|
|
64
150
|
clearKickedMessage() {
|
|
65
151
|
update((state) => ({ ...state, authKickedMessage: null }));
|
|
66
152
|
},
|
|
67
153
|
/**
|
|
68
|
-
* Update the Supabase session (
|
|
154
|
+
* Update the Supabase session in-place (e.g., after a token refresh).
|
|
155
|
+
*
|
|
156
|
+
* If the new session is `null`, the session field is cleared but the mode
|
|
157
|
+
* is **not** changed here. The caller (typically the auth listener) is
|
|
158
|
+
* responsible for deciding whether to fall back to offline or no-auth mode.
|
|
159
|
+
*
|
|
160
|
+
* @param session - The refreshed Supabase session, or null if invalidated
|
|
161
|
+
*
|
|
162
|
+
* @see setNoAuth for transitioning to unauthenticated mode
|
|
163
|
+
* @see setOfflineAuth for falling back to offline mode
|
|
69
164
|
*/
|
|
70
165
|
updateSession(session) {
|
|
71
166
|
update((state) => {
|
|
72
167
|
if (!session) {
|
|
73
|
-
|
|
74
|
-
|
|
168
|
+
/* Session was cleared - if online, set no auth
|
|
169
|
+
* If offline and was in supabase mode, we'll check offline session elsewhere */
|
|
75
170
|
return {
|
|
76
171
|
...state,
|
|
77
172
|
session: null
|
|
@@ -85,12 +180,24 @@ function createAuthStateStore() {
|
|
|
85
180
|
});
|
|
86
181
|
},
|
|
87
182
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
183
|
+
* Merge updated profile fields into the current user metadata.
|
|
184
|
+
*
|
|
185
|
+
* Handles both Supabase and offline modes so UI components that display
|
|
186
|
+
* user profile info (avatar, display name, etc.) update immediately
|
|
187
|
+
* without waiting for a round-trip.
|
|
188
|
+
*
|
|
189
|
+
* @param profile - Key-value pairs to merge into the existing profile metadata
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* // After saving profile changes to the server:
|
|
194
|
+
* authState.updateUserProfile({ display_name: 'New Name', avatar_url: newUrl });
|
|
195
|
+
* ```
|
|
90
196
|
*/
|
|
91
197
|
updateUserProfile(profile) {
|
|
92
198
|
update((state) => {
|
|
93
199
|
if (state.mode === 'supabase' && state.session) {
|
|
200
|
+
/* Deep-merge into Supabase's user_metadata so existing fields are preserved */
|
|
94
201
|
return {
|
|
95
202
|
...state,
|
|
96
203
|
session: {
|
|
@@ -106,6 +213,8 @@ function createAuthStateStore() {
|
|
|
106
213
|
};
|
|
107
214
|
}
|
|
108
215
|
if (state.mode === 'offline' && state.offlineProfile) {
|
|
216
|
+
/* For offline mode, replace the profile object wholesale since
|
|
217
|
+
* offline credentials use a simpler profile structure */
|
|
109
218
|
return {
|
|
110
219
|
...state,
|
|
111
220
|
offlineProfile: {
|
|
@@ -118,7 +227,11 @@ function createAuthStateStore() {
|
|
|
118
227
|
});
|
|
119
228
|
},
|
|
120
229
|
/**
|
|
121
|
-
* Reset to initial state
|
|
230
|
+
* Reset the store to its initial loading state.
|
|
231
|
+
*
|
|
232
|
+
* Called during app teardown or when reinitializing the auth subsystem.
|
|
233
|
+
* The `isLoading: true` default ensures the UI shows a loading indicator
|
|
234
|
+
* until the auth flow completes again.
|
|
122
235
|
*/
|
|
123
236
|
reset() {
|
|
124
237
|
set({
|
|
@@ -131,10 +244,49 @@ function createAuthStateStore() {
|
|
|
131
244
|
}
|
|
132
245
|
};
|
|
133
246
|
}
|
|
247
|
+
// =============================================================================
|
|
248
|
+
// Singleton Store Instance
|
|
249
|
+
// =============================================================================
|
|
250
|
+
/** The singleton authentication state store used throughout the application. */
|
|
134
251
|
export const authState = createAuthStateStore();
|
|
135
|
-
//
|
|
252
|
+
// =============================================================================
|
|
253
|
+
// Derived Stores
|
|
254
|
+
// =============================================================================
|
|
255
|
+
/**
|
|
256
|
+
* Derived store that resolves to `true` when the user is authenticated
|
|
257
|
+
* in any mode (Supabase or offline) and the auth subsystem has finished loading.
|
|
258
|
+
*
|
|
259
|
+
* Use this for route guards and conditional rendering of authenticated content.
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```svelte
|
|
263
|
+
* {#if $isAuthenticated}
|
|
264
|
+
* <Dashboard />
|
|
265
|
+
* {:else}
|
|
266
|
+
* <LoginScreen />
|
|
267
|
+
* {/if}
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* @see authState for the underlying state
|
|
271
|
+
*/
|
|
136
272
|
export const isAuthenticated = derived(authState, ($authState) => $authState.mode !== 'none' && !$authState.isLoading);
|
|
137
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Derived store that projects the user's display-friendly profile info
|
|
275
|
+
* (email and metadata) regardless of the current auth mode.
|
|
276
|
+
*
|
|
277
|
+
* Returns `null` when unauthenticated, allowing components to use a simple
|
|
278
|
+
* null check rather than inspecting the auth mode directly.
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```svelte
|
|
282
|
+
* {#if $userDisplayInfo}
|
|
283
|
+
* <Avatar profile={$userDisplayInfo.profile} />
|
|
284
|
+
* <span>{$userDisplayInfo.email}</span>
|
|
285
|
+
* {/if}
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* @see authState for the underlying state
|
|
289
|
+
*/
|
|
138
290
|
export const userDisplayInfo = derived(authState, ($authState) => {
|
|
139
291
|
if ($authState.mode === 'supabase' && $authState.session) {
|
|
140
292
|
const user = $authState.session.user;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authState.js","sourceRoot":"","sources":["../../src/stores/authState.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authState.js","sourceRoot":"","sources":["../../src/stores/authState.ts"],"names":[],"mappings":"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"}
|
package/dist/stores/network.d.ts
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Network Connectivity Store
|
|
3
|
+
*
|
|
4
|
+
* Provides a reactive boolean store (`isOnline`) that tracks whether the browser
|
|
5
|
+
* currently has network connectivity. Components subscribe to this store to
|
|
6
|
+
* conditionally enable/disable features that require a network connection
|
|
7
|
+
* (e.g., sync, realtime subscriptions, remote API calls).
|
|
8
|
+
*
|
|
9
|
+
* **Svelte Store Pattern:**
|
|
10
|
+
* Uses a custom writable store that exposes the standard `subscribe` method
|
|
11
|
+
* (making it a valid Svelte `Readable<boolean>`) plus imperative methods for
|
|
12
|
+
* initialization and callback registration. The store value is a simple boolean:
|
|
13
|
+
* `true` = online, `false` = offline.
|
|
14
|
+
*
|
|
15
|
+
* **Reactive Architecture:**
|
|
16
|
+
* The store listens to three browser events for comprehensive coverage:
|
|
17
|
+
* 1. `online` / `offline` - Standard connectivity events (works on desktop browsers)
|
|
18
|
+
* 2. `visibilitychange` - Catches iOS PWA edge cases where online/offline events
|
|
19
|
+
* do not fire reliably when the app returns from background
|
|
20
|
+
*
|
|
21
|
+
* Registered callbacks (via `onReconnect` / `onDisconnect`) are executed sequentially
|
|
22
|
+
* to ensure ordering guarantees (e.g., auth validation must complete before sync).
|
|
23
|
+
*
|
|
24
|
+
* @see {@link ./sync} for the sync store that depends on network state
|
|
25
|
+
* @see {@link ./authState} for auth state that may need revalidation on reconnect
|
|
26
|
+
*/
|
|
1
27
|
import { type Readable } from 'svelte/store';
|
|
28
|
+
/**
|
|
29
|
+
* Callback function registered for network state transitions.
|
|
30
|
+
* May be synchronous or asynchronous; async callbacks are properly awaited
|
|
31
|
+
* before the next callback in the sequence executes.
|
|
32
|
+
*/
|
|
2
33
|
type NetworkCallback = () => void | Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Singleton network connectivity store.
|
|
36
|
+
*
|
|
37
|
+
* Readable as a boolean (`true` = online, `false` = offline) and provides
|
|
38
|
+
* methods for initialization and callback registration.
|
|
39
|
+
*
|
|
40
|
+
* @see {@link createNetworkStore} for implementation details
|
|
41
|
+
*/
|
|
3
42
|
export declare const isOnline: Readable<boolean> & {
|
|
4
43
|
init: () => void;
|
|
5
44
|
onReconnect: (callback: NetworkCallback) => () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/stores/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/stores/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAQvD;;;;GAIG;AACH,KAAK,eAAe,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAqPlD;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ;UA7Nb,MAAM,IAAI;iBACH,CAAC,QAAQ,EAAE,eAAe,KAAK,MAAM,IAAI;kBACxC,CAAC,QAAQ,EAAE,eAAe,KAAK,MAAM,IAAI;CA2Nb,CAAC"}
|
package/dist/stores/network.js
CHANGED
|
@@ -1,22 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Network Connectivity Store
|
|
3
|
+
*
|
|
4
|
+
* Provides a reactive boolean store (`isOnline`) that tracks whether the browser
|
|
5
|
+
* currently has network connectivity. Components subscribe to this store to
|
|
6
|
+
* conditionally enable/disable features that require a network connection
|
|
7
|
+
* (e.g., sync, realtime subscriptions, remote API calls).
|
|
8
|
+
*
|
|
9
|
+
* **Svelte Store Pattern:**
|
|
10
|
+
* Uses a custom writable store that exposes the standard `subscribe` method
|
|
11
|
+
* (making it a valid Svelte `Readable<boolean>`) plus imperative methods for
|
|
12
|
+
* initialization and callback registration. The store value is a simple boolean:
|
|
13
|
+
* `true` = online, `false` = offline.
|
|
14
|
+
*
|
|
15
|
+
* **Reactive Architecture:**
|
|
16
|
+
* The store listens to three browser events for comprehensive coverage:
|
|
17
|
+
* 1. `online` / `offline` - Standard connectivity events (works on desktop browsers)
|
|
18
|
+
* 2. `visibilitychange` - Catches iOS PWA edge cases where online/offline events
|
|
19
|
+
* do not fire reliably when the app returns from background
|
|
20
|
+
*
|
|
21
|
+
* Registered callbacks (via `onReconnect` / `onDisconnect`) are executed sequentially
|
|
22
|
+
* to ensure ordering guarantees (e.g., auth validation must complete before sync).
|
|
23
|
+
*
|
|
24
|
+
* @see {@link ./sync} for the sync store that depends on network state
|
|
25
|
+
* @see {@link ./authState} for auth state that may need revalidation on reconnect
|
|
26
|
+
*/
|
|
1
27
|
import { writable } from 'svelte/store';
|
|
2
28
|
const browser = typeof window !== 'undefined';
|
|
3
29
|
import { debugError } from '../debug';
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// Store Factory
|
|
32
|
+
// =============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Creates the singleton network connectivity store.
|
|
35
|
+
*
|
|
36
|
+
* The store must be explicitly initialized via `init()` to attach browser event
|
|
37
|
+
* listeners. This is intentional: it allows server-side rendering (SSR) contexts
|
|
38
|
+
* to import the store without triggering browser API calls.
|
|
39
|
+
*
|
|
40
|
+
* @returns A Svelte-readable boolean store extended with `init`, `onReconnect`,
|
|
41
|
+
* and `onDisconnect` methods
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* // During app initialization:
|
|
46
|
+
* isOnline.init();
|
|
47
|
+
*
|
|
48
|
+
* // Register a reconnect handler (returns an unsubscribe function):
|
|
49
|
+
* const unsub = isOnline.onReconnect(async () => {
|
|
50
|
+
* await revalidateAuth();
|
|
51
|
+
* await triggerSync();
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* // In a Svelte component:
|
|
55
|
+
* $: if ($isOnline) { enableRealtimeFeatures(); }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
4
58
|
function createNetworkStore() {
|
|
5
59
|
const { subscribe, set } = writable(true);
|
|
60
|
+
/** Set of callbacks to invoke when connectivity is restored */
|
|
6
61
|
const reconnectCallbacks = new Set();
|
|
62
|
+
/** Set of callbacks to invoke when connectivity is lost */
|
|
7
63
|
const disconnectCallbacks = new Set();
|
|
64
|
+
/** Tracks whether we were offline so reconnect callbacks only fire on actual transitions */
|
|
8
65
|
let wasOffline = false;
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
66
|
+
/** Tracks current value to prevent redundant store updates and re-renders */
|
|
67
|
+
let currentValue = true;
|
|
68
|
+
/** Guards against double-initialization (e.g., HMR in development) */
|
|
69
|
+
let initialized = false;
|
|
70
|
+
/**
|
|
71
|
+
* Guards against duplicate reconnect callback invocations.
|
|
72
|
+
* iOS PWAs can fire both `online` and `visibilitychange` events simultaneously
|
|
73
|
+
* when returning from background, which would otherwise trigger reconnect
|
|
74
|
+
* callbacks twice.
|
|
75
|
+
*/
|
|
76
|
+
let reconnectPending = false;
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// Internal Helpers
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
/**
|
|
81
|
+
* Conditionally updates the store value only when it actually changes.
|
|
82
|
+
* Prevents unnecessary Svelte re-renders for redundant state transitions.
|
|
83
|
+
*
|
|
84
|
+
* @param value - The new online/offline boolean state
|
|
85
|
+
*/
|
|
12
86
|
function setIfChanged(value) {
|
|
13
87
|
if (value !== currentValue) {
|
|
14
88
|
currentValue = value;
|
|
15
89
|
set(value);
|
|
16
90
|
}
|
|
17
91
|
}
|
|
18
|
-
|
|
19
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Executes a set of callbacks one-by-one, awaiting each before proceeding.
|
|
94
|
+
*
|
|
95
|
+
* Sequential execution is critical here: for example, the auth revalidation
|
|
96
|
+
* callback must complete before the sync callback fires, since sync depends
|
|
97
|
+
* on a valid session token.
|
|
98
|
+
*
|
|
99
|
+
* @param callbacks - The set of callbacks to execute in registration order
|
|
100
|
+
* @param label - A human-readable label for error logging (e.g., 'Reconnect', 'Disconnect')
|
|
101
|
+
*/
|
|
20
102
|
async function runCallbacksSequentially(callbacks, label) {
|
|
21
103
|
for (const callback of callbacks) {
|
|
22
104
|
try {
|
|
@@ -27,47 +109,68 @@ function createNetworkStore() {
|
|
|
27
109
|
}
|
|
28
110
|
}
|
|
29
111
|
}
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Public API
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
/**
|
|
116
|
+
* Attach browser event listeners for connectivity tracking.
|
|
117
|
+
*
|
|
118
|
+
* Must be called once during app startup (client-side only). Subsequent
|
|
119
|
+
* calls are no-ops to ensure idempotency.
|
|
120
|
+
*
|
|
121
|
+
* @see {@link createNetworkStore} for the full lifecycle description
|
|
122
|
+
*/
|
|
30
123
|
function init() {
|
|
31
124
|
if (!browser)
|
|
32
125
|
return;
|
|
33
126
|
if (initialized)
|
|
34
|
-
return;
|
|
127
|
+
return; /* Idempotent - safe to call multiple times */
|
|
35
128
|
initialized = true;
|
|
36
|
-
|
|
129
|
+
/* Set initial state from the browser's navigator.onLine property */
|
|
37
130
|
const initiallyOnline = navigator.onLine;
|
|
38
131
|
currentValue = initiallyOnline;
|
|
39
132
|
set(initiallyOnline);
|
|
40
133
|
wasOffline = !initiallyOnline;
|
|
41
|
-
//
|
|
134
|
+
// -------------------------------------------------------------------------
|
|
135
|
+
// Event: Going Offline
|
|
136
|
+
// -------------------------------------------------------------------------
|
|
42
137
|
window.addEventListener('offline', () => {
|
|
43
138
|
const wasOnline = currentValue;
|
|
44
139
|
wasOffline = true;
|
|
45
140
|
setIfChanged(false);
|
|
46
|
-
|
|
141
|
+
/* Only fire disconnect callbacks on an actual online->offline transition */
|
|
47
142
|
if (wasOnline) {
|
|
48
143
|
runCallbacksSequentially(disconnectCallbacks, 'Disconnect');
|
|
49
144
|
}
|
|
50
145
|
});
|
|
51
|
-
//
|
|
146
|
+
// -------------------------------------------------------------------------
|
|
147
|
+
// Event: Coming Back Online
|
|
148
|
+
// -------------------------------------------------------------------------
|
|
52
149
|
window.addEventListener('online', () => {
|
|
53
150
|
setIfChanged(true);
|
|
54
|
-
|
|
151
|
+
/* Guard against duplicate firing (iOS PWA fires both online + visibilitychange) */
|
|
55
152
|
if (wasOffline && !reconnectPending) {
|
|
56
153
|
wasOffline = false;
|
|
57
154
|
reconnectPending = true;
|
|
58
|
-
|
|
155
|
+
/* Small delay (500ms) to ensure the network connection has stabilized
|
|
156
|
+
* before triggering potentially expensive operations like sync */
|
|
59
157
|
setTimeout(() => {
|
|
60
158
|
reconnectPending = false;
|
|
61
159
|
runCallbacksSequentially(reconnectCallbacks, 'Reconnect');
|
|
62
160
|
}, 500);
|
|
63
161
|
}
|
|
64
162
|
});
|
|
65
|
-
//
|
|
163
|
+
// -------------------------------------------------------------------------
|
|
164
|
+
// Event: Visibility Change (iOS PWA Workaround)
|
|
165
|
+
// -------------------------------------------------------------------------
|
|
166
|
+
/* iOS PWAs often do not fire online/offline events when the app is
|
|
167
|
+
* backgrounded and resumed. The visibilitychange event catches these
|
|
168
|
+
* cases and ensures the store reflects the actual connectivity state. */
|
|
66
169
|
document.addEventListener('visibilitychange', () => {
|
|
67
170
|
if (document.visibilityState === 'visible') {
|
|
68
171
|
const nowOnline = navigator.onLine;
|
|
69
|
-
setIfChanged(nowOnline);
|
|
70
|
-
|
|
172
|
+
setIfChanged(nowOnline); /* Only triggers a store update if value actually changed */
|
|
173
|
+
/* If we're coming back online after being hidden (guard against duplicate firing) */
|
|
71
174
|
if (nowOnline && wasOffline && !reconnectPending) {
|
|
72
175
|
wasOffline = false;
|
|
73
176
|
reconnectPending = true;
|
|
@@ -78,15 +181,54 @@ function createNetworkStore() {
|
|
|
78
181
|
}
|
|
79
182
|
}
|
|
80
183
|
else {
|
|
81
|
-
|
|
184
|
+
/* When going to background, conservatively mark as potentially offline
|
|
185
|
+
* so that reconnect callbacks fire if needed when the tab becomes visible again */
|
|
82
186
|
wasOffline = !navigator.onLine;
|
|
83
187
|
}
|
|
84
188
|
});
|
|
85
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Register a callback to be invoked when network connectivity is restored.
|
|
192
|
+
*
|
|
193
|
+
* Callbacks are executed sequentially in registration order and properly
|
|
194
|
+
* awaited if async. Use this for operations that must happen on reconnect
|
|
195
|
+
* (auth revalidation, sync trigger, realtime re-subscription).
|
|
196
|
+
*
|
|
197
|
+
* @param callback - The function to call on reconnect (may be sync or async)
|
|
198
|
+
* @returns An unsubscribe function that removes the callback from the set
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* const unsub = isOnline.onReconnect(async () => {
|
|
203
|
+
* await authState.revalidate();
|
|
204
|
+
* await syncEngine.pushPendingChanges();
|
|
205
|
+
* });
|
|
206
|
+
* // Later, to stop listening:
|
|
207
|
+
* unsub();
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
86
210
|
function onReconnect(callback) {
|
|
87
211
|
reconnectCallbacks.add(callback);
|
|
88
212
|
return () => reconnectCallbacks.delete(callback);
|
|
89
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Register a callback to be invoked when network connectivity is lost.
|
|
216
|
+
*
|
|
217
|
+
* Callbacks are executed sequentially in registration order and properly
|
|
218
|
+
* awaited if async. Use this for graceful degradation (pausing sync,
|
|
219
|
+
* switching to offline mode, showing offline indicators).
|
|
220
|
+
*
|
|
221
|
+
* @param callback - The function to call on disconnect (may be sync or async)
|
|
222
|
+
* @returns An unsubscribe function that removes the callback from the set
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* const unsub = isOnline.onDisconnect(() => {
|
|
227
|
+
* realtimeChannel.unsubscribe();
|
|
228
|
+
* showOfflineBanner();
|
|
229
|
+
* });
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
90
232
|
function onDisconnect(callback) {
|
|
91
233
|
disconnectCallbacks.add(callback);
|
|
92
234
|
return () => disconnectCallbacks.delete(callback);
|
|
@@ -98,5 +240,16 @@ function createNetworkStore() {
|
|
|
98
240
|
onDisconnect
|
|
99
241
|
};
|
|
100
242
|
}
|
|
243
|
+
// =============================================================================
|
|
244
|
+
// Singleton Store Instance
|
|
245
|
+
// =============================================================================
|
|
246
|
+
/**
|
|
247
|
+
* Singleton network connectivity store.
|
|
248
|
+
*
|
|
249
|
+
* Readable as a boolean (`true` = online, `false` = offline) and provides
|
|
250
|
+
* methods for initialization and callback registration.
|
|
251
|
+
*
|
|
252
|
+
* @see {@link createNetworkStore} for implementation details
|
|
253
|
+
*/
|
|
101
254
|
export const isOnline = createNetworkStore();
|
|
102
255
|
//# sourceMappingURL=network.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/stores/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiB,MAAM,cAAc,CAAC;AACvD,MAAM,OAAO,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/stores/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,QAAQ,EAAiB,MAAM,cAAc,CAAC;AACvD,MAAM,OAAO,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAatC,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAS,kBAAkB;IAKzB,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAC;IAEnD,+DAA+D;IAC/D,MAAM,kBAAkB,GAAyB,IAAI,GAAG,EAAE,CAAC;IAE3D,2DAA2D;IAC3D,MAAM,mBAAmB,GAAyB,IAAI,GAAG,EAAE,CAAC;IAE5D,4FAA4F;IAC5F,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,6EAA6E;IAC7E,IAAI,YAAY,GAAG,IAAI,CAAC;IAExB,sEAAsE;IACtE,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB;;;;;OAKG;IACH,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,8EAA8E;IAC9E,mBAAmB;IACnB,8EAA8E;IAE9E;;;;;OAKG;IACH,SAAS,YAAY,CAAC,KAAc;QAClC,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;YAC3B,YAAY,GAAG,KAAK,CAAC;YACrB,GAAG,CAAC,KAAK,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,UAAU,wBAAwB,CACrC,SAA+B,EAC/B,KAAa;QAEb,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,QAAQ,EAAE,CAAC;YACnB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,UAAU,CAAC,aAAa,KAAK,kBAAkB,EAAE,CAAC,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,aAAa;IACb,8EAA8E;IAE9E;;;;;;;OAOG;IACH,SAAS,IAAI;QACX,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,WAAW;YAAE,OAAO,CAAC,8CAA8C;QACvE,WAAW,GAAG,IAAI,CAAC;QAEnB,oEAAoE;QACpE,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC;QACzC,YAAY,GAAG,eAAe,CAAC;QAC/B,GAAG,CAAC,eAAe,CAAC,CAAC;QACrB,UAAU,GAAG,CAAC,eAAe,CAAC;QAE9B,4EAA4E;QAC5E,uBAAuB;QACvB,4EAA4E;QAC5E,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE;YACtC,MAAM,SAAS,GAAG,YAAY,CAAC;YAC/B,UAAU,GAAG,IAAI,CAAC;YAClB,YAAY,CAAC,KAAK,CAAC,CAAC;YAEpB,4EAA4E;YAC5E,IAAI,SAAS,EAAE,CAAC;gBACd,wBAAwB,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,4EAA4E;QAC5E,4BAA4B;QAC5B,4EAA4E;QAC5E,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;YACrC,YAAY,CAAC,IAAI,CAAC,CAAC;YAEnB,mFAAmF;YACnF,IAAI,UAAU,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACpC,UAAU,GAAG,KAAK,CAAC;gBACnB,gBAAgB,GAAG,IAAI,CAAC;gBACxB;kFACkE;gBAClE,UAAU,CAAC,GAAG,EAAE;oBACd,gBAAgB,GAAG,KAAK,CAAC;oBACzB,wBAAwB,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;gBAC5D,CAAC,EAAE,GAAG,CAAC,CAAC;YACV,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,4EAA4E;QAC5E,gDAAgD;QAChD,4EAA4E;QAC5E;;iFAEyE;QACzE,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;YACjD,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;gBAC3C,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC;gBACnC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,4DAA4D;gBAErF,qFAAqF;gBACrF,IAAI,SAAS,IAAI,UAAU,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACjD,UAAU,GAAG,KAAK,CAAC;oBACnB,gBAAgB,GAAG,IAAI,CAAC;oBACxB,UAAU,CAAC,GAAG,EAAE;wBACd,gBAAgB,GAAG,KAAK,CAAC;wBACzB,wBAAwB,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;oBAC5D,CAAC,EAAE,GAAG,CAAC,CAAC;gBACV,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN;mGACmF;gBACnF,UAAU,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC;YACjC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,WAAW,CAAC,QAAyB;QAC5C,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjC,OAAO,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,YAAY,CAAC,QAAyB;QAC7C,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO,GAAG,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpD,CAAC;IAED,OAAO;QACL,SAAS;QACT,IAAI;QACJ,WAAW;QACX,YAAY;KACb,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,2BAA2B;AAC3B,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC"}
|