@oxyhq/services 13.0.3 → 13.1.0

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 (61) hide show
  1. package/lib/commonjs/index.js +18 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/ProfileButton.js +233 -0
  4. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -0
  5. package/lib/commonjs/ui/components/ProfileMenu.js +374 -0
  6. package/lib/commonjs/ui/components/ProfileMenu.js.map +1 -0
  7. package/lib/commonjs/ui/context/OxyContext.js +99 -18
  8. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  9. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +28 -1
  10. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  11. package/lib/commonjs/ui/index.js +14 -0
  12. package/lib/commonjs/ui/index.js.map +1 -1
  13. package/lib/commonjs/ui/utils/activeAuthuser.js +76 -8
  14. package/lib/commonjs/ui/utils/activeAuthuser.js.map +1 -1
  15. package/lib/module/index.js +5 -0
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/ui/components/ProfileButton.js +228 -0
  18. package/lib/module/ui/components/ProfileButton.js.map +1 -0
  19. package/lib/module/ui/components/ProfileMenu.js +370 -0
  20. package/lib/module/ui/components/ProfileMenu.js.map +1 -0
  21. package/lib/module/ui/context/OxyContext.js +100 -19
  22. package/lib/module/ui/context/OxyContext.js.map +1 -1
  23. package/lib/module/ui/context/hooks/useAuthOperations.js +29 -2
  24. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  25. package/lib/module/ui/index.js +2 -0
  26. package/lib/module/ui/index.js.map +1 -1
  27. package/lib/module/ui/utils/activeAuthuser.js +74 -9
  28. package/lib/module/ui/utils/activeAuthuser.js.map +1 -1
  29. package/lib/typescript/commonjs/index.d.ts +4 -0
  30. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  31. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +46 -0
  32. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -0
  33. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +39 -0
  34. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +1 -0
  35. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  37. package/lib/typescript/commonjs/ui/index.d.ts +2 -0
  38. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts +24 -0
  40. package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts.map +1 -1
  41. package/lib/typescript/module/index.d.ts +4 -0
  42. package/lib/typescript/module/index.d.ts.map +1 -1
  43. package/lib/typescript/module/ui/components/ProfileButton.d.ts +46 -0
  44. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -0
  45. package/lib/typescript/module/ui/components/ProfileMenu.d.ts +39 -0
  46. package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +1 -0
  47. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  48. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  49. package/lib/typescript/module/ui/index.d.ts +2 -0
  50. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  51. package/lib/typescript/module/ui/utils/activeAuthuser.d.ts +24 -0
  52. package/lib/typescript/module/ui/utils/activeAuthuser.d.ts.map +1 -1
  53. package/package.json +3 -3
  54. package/src/index.ts +8 -0
  55. package/src/ui/components/ProfileButton.tsx +270 -0
  56. package/src/ui/components/ProfileMenu.tsx +416 -0
  57. package/src/ui/context/OxyContext.tsx +100 -18
  58. package/src/ui/context/hooks/useAuthOperations.ts +35 -2
  59. package/src/ui/index.ts +2 -0
  60. package/src/ui/utils/__tests__/activeAuthuser.test.ts +75 -0
  61. package/src/ui/utils/activeAuthuser.ts +74 -8
@@ -0,0 +1,374 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = require("react");
8
+ var _reactNative = require("react-native");
9
+ var _vectorIcons = require("@expo/vector-icons");
10
+ var _avatar = require("@oxyhq/bloom/avatar");
11
+ var _typography = require("@oxyhq/bloom/typography");
12
+ var _theme = require("@oxyhq/bloom/theme");
13
+ var _bloom = require("@oxyhq/bloom");
14
+ var _divider = require("@oxyhq/bloom/divider");
15
+ var _core = require("@oxyhq/core");
16
+ var _OxyContext = require("../context/OxyContext.js");
17
+ var _useI18n = require("../hooks/useI18n.js");
18
+ var _useDeviceAccounts = require("../hooks/useDeviceAccounts.js");
19
+ var _jsxRuntime = require("react/jsx-runtime");
20
+ const isWeb = _reactNative.Platform.OS === 'web';
21
+
22
+ /** Fixed popover width on web. `ProfileButton` mirrors this when anchoring. */
23
+ const MENU_WIDTH = 300;
24
+
25
+ /**
26
+ * Web-only anchor. `ProfileButton` measures its trigger and anchors the panel's
27
+ * BOTTOM-LEFT corner so the menu opens UPWARD from the sidebar footer. Native
28
+ * ignores the anchor and docks the panel to the bottom as a sheet.
29
+ */
30
+
31
+ /**
32
+ * Clean device-account switcher, modeled on the inbox `AccountMenu` but written
33
+ * fresh with NativeWind classNames + Bloom primitives. Lists every account
34
+ * signed in on this device (from {@link useDeviceAccounts}); tapping a row
35
+ * switches, and each inactive row carries a sign-out icon. Below the list:
36
+ * Add account, Manage account, optional View profile, and Sign out of all.
37
+ *
38
+ * Renders as an upward-opening popover anchored to the trigger on web, and a
39
+ * bottom-sheet style modal on native.
40
+ */
41
+ const ProfileMenu = ({
42
+ open,
43
+ onClose,
44
+ anchor,
45
+ onNavigateManage,
46
+ onAddAccount,
47
+ onNavigateProfile,
48
+ onBeforeSessionChange
49
+ }) => {
50
+ const {
51
+ activeSessionId,
52
+ switchSession,
53
+ logoutAll,
54
+ removeSession
55
+ } = (0, _OxyContext.useOxy)();
56
+ const {
57
+ t
58
+ } = (0, _useI18n.useI18n)();
59
+ const {
60
+ colors
61
+ } = (0, _theme.useTheme)();
62
+ const {
63
+ accounts
64
+ } = (0, _useDeviceAccounts.useDeviceAccounts)();
65
+ const [busySessionId, setBusySessionId] = (0, _react.useState)(null);
66
+ const [removingSessionId, setRemovingSessionId] = (0, _react.useState)(null);
67
+ const [signingOutAll, setSigningOutAll] = (0, _react.useState)(false);
68
+ const signOutAllDialog = (0, _bloom.useDialogControl)();
69
+ const isSwitching = busySessionId !== null;
70
+ const actionDisabled = isSwitching || removingSessionId !== null || signingOutAll;
71
+
72
+ // Switch to a non-active account through the SDK's canonical switch path.
73
+ const handleSwitch = (0, _react.useCallback)(async sessionId => {
74
+ if (sessionId === activeSessionId || busySessionId) {
75
+ return;
76
+ }
77
+ setBusySessionId(sessionId);
78
+ try {
79
+ await onBeforeSessionChange?.();
80
+ await switchSession(sessionId);
81
+ _bloom.toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched account');
82
+ onClose();
83
+ } catch (error) {
84
+ if (!(0, _core.isDev)()) {
85
+ _core.logger.warn('Switch account failed', {
86
+ component: 'ProfileMenu'
87
+ }, error);
88
+ }
89
+ _bloom.toast.error(t('accountSwitcher.toasts.switchFailed') || 'Failed to switch account');
90
+ } finally {
91
+ setBusySessionId(null);
92
+ }
93
+ }, [activeSessionId, busySessionId, switchSession, t, onClose, onBeforeSessionChange]);
94
+
95
+ // Sign out a specific inactive account without switching/clearing the active
96
+ // one. The menu stays open so the user can keep managing accounts.
97
+ const handleRemove = (0, _react.useCallback)(async sessionId => {
98
+ if (sessionId === activeSessionId || removingSessionId) {
99
+ return;
100
+ }
101
+ setRemovingSessionId(sessionId);
102
+ try {
103
+ await removeSession(sessionId);
104
+ _bloom.toast.success(t('common.actions.signedOut') || 'Signed out');
105
+ } catch (error) {
106
+ _core.logger.warn('Remove account failed', {
107
+ component: 'ProfileMenu'
108
+ }, error);
109
+ _bloom.toast.error(t('common.errors.signOutFailed') || 'Failed to sign out');
110
+ } finally {
111
+ setRemovingSessionId(null);
112
+ }
113
+ }, [activeSessionId, removingSessionId, removeSession, t]);
114
+ const performSignOutAll = (0, _react.useCallback)(async () => {
115
+ if (signingOutAll) {
116
+ return;
117
+ }
118
+ setSigningOutAll(true);
119
+ try {
120
+ await onBeforeSessionChange?.();
121
+ await logoutAll();
122
+ _bloom.toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'Signed out of all accounts');
123
+ onClose();
124
+ } catch (error) {
125
+ _core.logger.warn('Sign out all failed', {
126
+ component: 'ProfileMenu'
127
+ }, error);
128
+ _bloom.toast.error(t('common.errors.signOutAllFailed') || 'Failed to sign out of all accounts');
129
+ } finally {
130
+ setSigningOutAll(false);
131
+ }
132
+ }, [signingOutAll, logoutAll, t, onClose, onBeforeSessionChange]);
133
+
134
+ // Escape-to-close (web only).
135
+ (0, _react.useEffect)(() => {
136
+ if (!open || !isWeb || typeof document === 'undefined') {
137
+ return undefined;
138
+ }
139
+ const onKey = event => {
140
+ if (event.key === 'Escape') {
141
+ event.stopPropagation();
142
+ onClose();
143
+ }
144
+ };
145
+ document.addEventListener('keydown', onKey, true);
146
+ return () => document.removeEventListener('keydown', onKey, true);
147
+ }, [open, onClose]);
148
+ if (!open) {
149
+ return null;
150
+ }
151
+
152
+ // Web: anchor the panel's bottom-left corner to the measured trigger, falling
153
+ // back to a bottom-left placement when no anchor was captured. Native ignores
154
+ // this (the panel docks to the bottom via the overlay's flex-end).
155
+ const panelAnchorStyle = isWeb ? {
156
+ position: 'absolute',
157
+ width: MENU_WIDTH,
158
+ left: anchor?.left ?? 8,
159
+ bottom: anchor?.bottom ?? 8
160
+ } : undefined;
161
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable
162
+ // Swallow taps inside the panel so they never reach the overlay's
163
+ // outside-tap-to-close handler.
164
+ , {
165
+ onPress: () => undefined,
166
+ className: isWeb ? 'overflow-hidden rounded-2xl border border-border bg-background' : 'overflow-hidden rounded-t-3xl bg-background pb-3',
167
+ style: [panelAnchorStyle, !isWeb ? {
168
+ maxHeight: '85%'
169
+ } : {
170
+ maxHeight: '85%'
171
+ }, styles.shadow],
172
+ accessibilityRole: "menu",
173
+ accessibilityLabel: t('accountMenu.label') || 'Account menu',
174
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
175
+ className: "grow-0",
176
+ contentContainerClassName: "py-1",
177
+ showsVerticalScrollIndicator: false,
178
+ children: [accounts.map(account => {
179
+ const isActive = account.isCurrent;
180
+ const isBusy = busySessionId === account.sessionId;
181
+ const isRemoving = removingSessionId === account.sessionId;
182
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
183
+ accessibilityRole: "menuitem",
184
+ accessibilityLabel: account.displayName,
185
+ accessibilityState: {
186
+ selected: isActive
187
+ },
188
+ onPress: () => handleSwitch(account.sessionId),
189
+ disabled: isActive || isBusy || isSwitching,
190
+ className: `flex-row items-center gap-3 px-4 py-2.5 ${isActive ? 'bg-secondary' : ''} ${isSwitching && !isActive ? 'opacity-40' : ''}`,
191
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_avatar.Avatar, {
192
+ source: account.user.avatar ?? undefined,
193
+ uri: account.avatarUrl,
194
+ variant: "thumb",
195
+ name: account.displayName,
196
+ size: isActive ? 40 : 32
197
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
198
+ className: "min-w-0 flex-1",
199
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.Text, {
200
+ className: `text-foreground ${isActive ? 'font-semibold' : 'font-medium'}`,
201
+ numberOfLines: 1,
202
+ children: account.displayName
203
+ }), account.email ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.Text, {
204
+ className: "text-xs text-muted-foreground",
205
+ numberOfLines: 1,
206
+ children: account.email
207
+ }) : null]
208
+ }), isBusy ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
209
+ color: colors.primary,
210
+ size: "small"
211
+ }) : isActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.MaterialCommunityIcons, {
212
+ name: "check",
213
+ size: 20,
214
+ color: colors.primary
215
+ }) : isRemoving ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
216
+ color: colors.textSecondary,
217
+ size: "small"
218
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
219
+ accessibilityRole: "button",
220
+ accessibilityLabel: t('accountMenu.signOutAccount', {
221
+ name: account.displayName
222
+ }) || `Sign out ${account.displayName}`,
223
+ onPress: () => handleRemove(account.sessionId),
224
+ disabled: actionDisabled,
225
+ hitSlop: {
226
+ top: 8,
227
+ bottom: 8,
228
+ left: 8,
229
+ right: 8
230
+ },
231
+ className: "h-7 w-7 items-center justify-center rounded-full opacity-60",
232
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.MaterialCommunityIcons, {
233
+ name: "logout",
234
+ size: 18,
235
+ color: colors.textSecondary
236
+ })
237
+ })]
238
+ }, `account-${account.sessionId}`);
239
+ }), isSwitching ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
240
+ className: "flex-row items-center justify-center gap-2 py-2",
241
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
242
+ color: colors.textSecondary,
243
+ size: "small"
244
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.Text, {
245
+ className: "text-xs font-medium text-muted-foreground",
246
+ children: t('accountMenu.switching') || 'Switching account…'
247
+ })]
248
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_divider.Divider, {
249
+ color: colors.border,
250
+ spacing: 4
251
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(ActionRow, {
252
+ icon: "account-plus-outline",
253
+ iconColor: colors.icon,
254
+ label: t('accountMenu.addAnother') || 'Add another account',
255
+ disabled: actionDisabled,
256
+ onPress: () => {
257
+ onClose();
258
+ onAddAccount();
259
+ }
260
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(ActionRow, {
261
+ icon: "cog-outline",
262
+ iconColor: colors.icon,
263
+ label: t('accountMenu.manage') || 'Manage your Oxy Account',
264
+ disabled: actionDisabled,
265
+ onPress: () => {
266
+ onClose();
267
+ onNavigateManage();
268
+ }
269
+ }), onNavigateProfile ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ActionRow, {
270
+ icon: "account-outline",
271
+ iconColor: colors.icon,
272
+ label: t('accountMenu.viewProfile') || 'View profile',
273
+ disabled: actionDisabled,
274
+ onPress: () => {
275
+ onClose();
276
+ onNavigateProfile();
277
+ }
278
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_divider.Divider, {
279
+ color: colors.border,
280
+ spacing: 4
281
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
282
+ accessibilityRole: "menuitem",
283
+ accessibilityLabel: t('accountMenu.signOutAll') || 'Sign out of all accounts',
284
+ onPress: () => signOutAllDialog.open(),
285
+ disabled: actionDisabled,
286
+ className: `flex-row items-center gap-3 px-4 py-3 ${actionDisabled ? 'opacity-40' : ''}`,
287
+ children: [signingOutAll ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
288
+ color: colors.error,
289
+ size: "small"
290
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.MaterialCommunityIcons, {
291
+ name: "logout",
292
+ size: 18,
293
+ color: colors.error
294
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.Text, {
295
+ className: "font-medium",
296
+ style: {
297
+ color: colors.error
298
+ },
299
+ children: t('accountMenu.signOutAll') || 'Sign out of all accounts'
300
+ })]
301
+ })]
302
+ })
303
+ });
304
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Modal, {
305
+ visible: open,
306
+ transparent: true,
307
+ animationType: isWeb ? 'fade' : 'slide',
308
+ onRequestClose: onClose,
309
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
310
+ accessibilityRole: "button",
311
+ accessibilityLabel: t('common.actions.close') || 'Close',
312
+ onPress: onClose,
313
+ className: isWeb ? 'flex-1 relative' : 'flex-1 justify-end',
314
+ style: !isWeb ? styles.nativeScrim : undefined,
315
+ children: content
316
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_bloom.Dialog, {
317
+ control: signOutAllDialog,
318
+ title: t('accountMenu.signOutAll') || 'Sign out of all accounts',
319
+ description: t('common.confirms.signOutAll') || 'Are you sure you want to sign out of all accounts?',
320
+ actions: [{
321
+ label: t('accountMenu.signOutAll') || 'Sign out of all accounts',
322
+ color: 'destructive',
323
+ onPress: performSignOutAll
324
+ }, {
325
+ label: t('common.cancel') || 'Cancel',
326
+ color: 'cancel'
327
+ }]
328
+ })]
329
+ });
330
+ };
331
+
332
+ /** Bottom-section action row (Add account / Manage / View profile). */
333
+ const ActionRow = ({
334
+ icon,
335
+ iconColor,
336
+ label,
337
+ disabled,
338
+ onPress
339
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
340
+ accessibilityRole: "menuitem",
341
+ accessibilityLabel: label,
342
+ onPress: onPress,
343
+ disabled: disabled,
344
+ className: `flex-row items-center gap-3 px-4 py-3 ${disabled ? 'opacity-40' : ''}`,
345
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.MaterialCommunityIcons, {
346
+ name: icon,
347
+ size: 20,
348
+ color: iconColor
349
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.Text, {
350
+ className: "font-medium text-foreground",
351
+ children: label
352
+ })]
353
+ });
354
+
355
+ // The panel's drop shadow and the native scrim are the only values with no
356
+ // NativeWind class equivalent in this package (dynamic elevation + rgba scrim),
357
+ // so they stay as small inline objects rather than raw class-replaceable styles.
358
+ const styles = {
359
+ shadow: {
360
+ shadowColor: '#000',
361
+ shadowOpacity: 0.18,
362
+ shadowRadius: 24,
363
+ shadowOffset: {
364
+ width: 0,
365
+ height: 8
366
+ },
367
+ elevation: 12
368
+ },
369
+ nativeScrim: {
370
+ backgroundColor: 'rgba(0,0,0,0.32)'
371
+ }
372
+ };
373
+ var _default = exports.default = ProfileMenu;
374
+ //# sourceMappingURL=ProfileMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","require","_reactNative","_vectorIcons","_avatar","_typography","_theme","_bloom","_divider","_core","_OxyContext","_useI18n","_useDeviceAccounts","_jsxRuntime","isWeb","Platform","OS","MENU_WIDTH","ProfileMenu","open","onClose","anchor","onNavigateManage","onAddAccount","onNavigateProfile","onBeforeSessionChange","activeSessionId","switchSession","logoutAll","removeSession","useOxy","t","useI18n","colors","useTheme","accounts","useDeviceAccounts","busySessionId","setBusySessionId","useState","removingSessionId","setRemovingSessionId","signingOutAll","setSigningOutAll","signOutAllDialog","useDialogControl","isSwitching","actionDisabled","handleSwitch","useCallback","sessionId","toast","success","error","isDev","loggerUtil","warn","component","handleRemove","performSignOutAll","useEffect","document","undefined","onKey","event","key","stopPropagation","addEventListener","removeEventListener","panelAnchorStyle","position","width","left","bottom","content","jsx","Pressable","onPress","className","style","maxHeight","styles","shadow","accessibilityRole","accessibilityLabel","children","jsxs","ScrollView","contentContainerClassName","showsVerticalScrollIndicator","map","account","isActive","isCurrent","isBusy","isRemoving","displayName","accessibilityState","selected","disabled","Avatar","source","user","avatar","uri","avatarUrl","variant","name","size","View","Text","numberOfLines","email","ActivityIndicator","color","primary","MaterialCommunityIcons","textSecondary","hitSlop","top","right","Divider","border","spacing","ActionRow","icon","iconColor","label","Modal","visible","transparent","animationType","onRequestClose","nativeScrim","Dialog","control","title","description","actions","shadowColor","shadowOpacity","shadowRadius","shadowOffset","height","elevation","backgroundColor","_default","exports","default"],"sourceRoot":"../../../../src","sources":["ui/components/ProfileMenu.tsx"],"mappings":";;;;;;AACA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AASA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,OAAA,GAAAH,OAAA;AACA,IAAAI,WAAA,GAAAJ,OAAA;AACA,IAAAK,MAAA,GAAAL,OAAA;AACA,IAAAM,MAAA,GAAAN,OAAA;AACA,IAAAO,QAAA,GAAAP,OAAA;AACA,IAAAQ,KAAA,GAAAR,OAAA;AACA,IAAAS,WAAA,GAAAT,OAAA;AACA,IAAAU,QAAA,GAAAV,OAAA;AACA,IAAAW,kBAAA,GAAAX,OAAA;AAA+D,IAAAY,WAAA,GAAAZ,OAAA;AAE/D,MAAMa,KAAK,GAAGC,qBAAQ,CAACC,EAAE,KAAK,KAAK;;AAEnC;AACA,MAAMC,UAAU,GAAG,GAAG;;AAEtB;AACA;AACA;AACA;AACA;;AAuBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,WAAuC,GAAGA,CAAC;EAC7CC,IAAI;EACJC,OAAO;EACPC,MAAM;EACNC,gBAAgB;EAChBC,YAAY;EACZC,iBAAiB;EACjBC;AACJ,CAAC,KAAK;EACF,MAAM;IACFC,eAAe;IACfC,aAAa;IACbC,SAAS;IACTC;EACJ,CAAC,GAAG,IAAAC,kBAAM,EAAC,CAAC;EACZ,MAAM;IAAEC;EAAE,CAAC,GAAG,IAAAC,gBAAO,EAAC,CAAC;EACvB,MAAM;IAAEC;EAAO,CAAC,GAAG,IAAAC,eAAQ,EAAC,CAAC;EAE7B,MAAM;IAAEC;EAAS,CAAC,GAAG,IAAAC,oCAAiB,EAAC,CAAC;EAExC,MAAM,CAACC,aAAa,EAAEC,gBAAgB,CAAC,GAAG,IAAAC,eAAQ,EAAgB,IAAI,CAAC;EACvE,MAAM,CAACC,iBAAiB,EAAEC,oBAAoB,CAAC,GAAG,IAAAF,eAAQ,EAAgB,IAAI,CAAC;EAC/E,MAAM,CAACG,aAAa,EAAEC,gBAAgB,CAAC,GAAG,IAAAJ,eAAQ,EAAC,KAAK,CAAC;EAEzD,MAAMK,gBAAgB,GAAG,IAAAC,uBAAgB,EAAC,CAAC;EAE3C,MAAMC,WAAW,GAAGT,aAAa,KAAK,IAAI;EAC1C,MAAMU,cAAc,GAAGD,WAAW,IAAIN,iBAAiB,KAAK,IAAI,IAAIE,aAAa;;EAEjF;EACA,MAAMM,YAAY,GAAG,IAAAC,kBAAW,EAAC,MAAOC,SAAiB,IAAK;IAC1D,IAAIA,SAAS,KAAKxB,eAAe,IAAIW,aAAa,EAAE;MAChD;IACJ;IACAC,gBAAgB,CAACY,SAAS,CAAC;IAC3B,IAAI;MACA,MAAMzB,qBAAqB,GAAG,CAAC;MAC/B,MAAME,aAAa,CAACuB,SAAS,CAAC;MAC9BC,YAAK,CAACC,OAAO,CAACrB,CAAC,CAAC,sCAAsC,CAAC,IAAI,kBAAkB,CAAC;MAC9EX,OAAO,CAAC,CAAC;IACb,CAAC,CAAC,OAAOiC,KAAK,EAAE;MACZ,IAAI,CAAC,IAAAC,WAAK,EAAC,CAAC,EAAE;QACVC,YAAU,CAACC,IAAI,CAAC,uBAAuB,EAAE;UAAEC,SAAS,EAAE;QAAc,CAAC,EAAEJ,KAAgB,CAAC;MAC5F;MACAF,YAAK,CAACE,KAAK,CAACtB,CAAC,CAAC,qCAAqC,CAAC,IAAI,0BAA0B,CAAC;IACvF,CAAC,SAAS;MACNO,gBAAgB,CAAC,IAAI,CAAC;IAC1B;EACJ,CAAC,EAAE,CAACZ,eAAe,EAAEW,aAAa,EAAEV,aAAa,EAAEI,CAAC,EAAEX,OAAO,EAAEK,qBAAqB,CAAC,CAAC;;EAEtF;EACA;EACA,MAAMiC,YAAY,GAAG,IAAAT,kBAAW,EAAC,MAAOC,SAAiB,IAAK;IAC1D,IAAIA,SAAS,KAAKxB,eAAe,IAAIc,iBAAiB,EAAE;MACpD;IACJ;IACAC,oBAAoB,CAACS,SAAS,CAAC;IAC/B,IAAI;MACA,MAAMrB,aAAa,CAACqB,SAAS,CAAC;MAC9BC,YAAK,CAACC,OAAO,CAACrB,CAAC,CAAC,0BAA0B,CAAC,IAAI,YAAY,CAAC;IAChE,CAAC,CAAC,OAAOsB,KAAK,EAAE;MACZE,YAAU,CAACC,IAAI,CAAC,uBAAuB,EAAE;QAAEC,SAAS,EAAE;MAAc,CAAC,EAAEJ,KAAgB,CAAC;MACxFF,YAAK,CAACE,KAAK,CAACtB,CAAC,CAAC,6BAA6B,CAAC,IAAI,oBAAoB,CAAC;IACzE,CAAC,SAAS;MACNU,oBAAoB,CAAC,IAAI,CAAC;IAC9B;EACJ,CAAC,EAAE,CAACf,eAAe,EAAEc,iBAAiB,EAAEX,aAAa,EAAEE,CAAC,CAAC,CAAC;EAE1D,MAAM4B,iBAAiB,GAAG,IAAAV,kBAAW,EAAC,YAAY;IAC9C,IAAIP,aAAa,EAAE;MACf;IACJ;IACAC,gBAAgB,CAAC,IAAI,CAAC;IACtB,IAAI;MACA,MAAMlB,qBAAqB,GAAG,CAAC;MAC/B,MAAMG,SAAS,CAAC,CAAC;MACjBuB,YAAK,CAACC,OAAO,CAACrB,CAAC,CAAC,0CAA0C,CAAC,IAAI,4BAA4B,CAAC;MAC5FX,OAAO,CAAC,CAAC;IACb,CAAC,CAAC,OAAOiC,KAAK,EAAE;MACZE,YAAU,CAACC,IAAI,CAAC,qBAAqB,EAAE;QAAEC,SAAS,EAAE;MAAc,CAAC,EAAEJ,KAAgB,CAAC;MACtFF,YAAK,CAACE,KAAK,CAACtB,CAAC,CAAC,gCAAgC,CAAC,IAAI,oCAAoC,CAAC;IAC5F,CAAC,SAAS;MACNY,gBAAgB,CAAC,KAAK,CAAC;IAC3B;EACJ,CAAC,EAAE,CAACD,aAAa,EAAEd,SAAS,EAAEG,CAAC,EAAEX,OAAO,EAAEK,qBAAqB,CAAC,CAAC;;EAEjE;EACA,IAAAmC,gBAAS,EAAC,MAAM;IACZ,IAAI,CAACzC,IAAI,IAAI,CAACL,KAAK,IAAI,OAAO+C,QAAQ,KAAK,WAAW,EAAE;MACpD,OAAOC,SAAS;IACpB;IACA,MAAMC,KAAK,GAAIC,KAAoB,IAAK;MACpC,IAAIA,KAAK,CAACC,GAAG,KAAK,QAAQ,EAAE;QACxBD,KAAK,CAACE,eAAe,CAAC,CAAC;QACvB9C,OAAO,CAAC,CAAC;MACb;IACJ,CAAC;IACDyC,QAAQ,CAACM,gBAAgB,CAAC,SAAS,EAAEJ,KAAK,EAAE,IAAI,CAAC;IACjD,OAAO,MAAMF,QAAQ,CAACO,mBAAmB,CAAC,SAAS,EAAEL,KAAK,EAAE,IAAI,CAAC;EACrE,CAAC,EAAE,CAAC5C,IAAI,EAAEC,OAAO,CAAC,CAAC;EAEnB,IAAI,CAACD,IAAI,EAAE;IACP,OAAO,IAAI;EACf;;EAEA;EACA;EACA;EACA,MAAMkD,gBAAuC,GAAGvD,KAAK,GAC/C;IACEwD,QAAQ,EAAE,UAAU;IACpBC,KAAK,EAAEtD,UAAU;IACjBuD,IAAI,EAAEnD,MAAM,EAAEmD,IAAI,IAAI,CAAC;IACvBC,MAAM,EAAEpD,MAAM,EAAEoD,MAAM,IAAI;EAC9B,CAAC,GACCX,SAAS;EAEf,MAAMY,OAAO,gBACT,IAAA7D,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA0E;EACG;EACA;EAAA;IACAC,OAAO,EAAEA,CAAA,KAAMf,SAAU;IACzBgB,SAAS,EACLhE,KAAK,GACC,gEAAgE,GAChE,kDACT;IACDiE,KAAK,EAAE,CACHV,gBAAgB,EAChB,CAACvD,KAAK,GAAG;MAAEkE,SAAS,EAAE;IAAM,CAAC,GAAG;MAAEA,SAAS,EAAE;IAAM,CAAC,EACpDC,MAAM,CAACC,MAAM,CACf;IACFC,iBAAiB,EAAC,MAAM;IACxBC,kBAAkB,EAAErD,CAAC,CAAC,mBAAmB,CAAC,IAAI,cAAe;IAAAsD,QAAA,eAE7D,IAAAxE,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAAqF,UAAU;MACPT,SAAS,EAAC,QAAQ;MAClBU,yBAAyB,EAAC,MAAM;MAChCC,4BAA4B,EAAE,KAAM;MAAAJ,QAAA,GAGnClD,QAAQ,CAACuD,GAAG,CAAEC,OAAO,IAAK;QACvB,MAAMC,QAAQ,GAAGD,OAAO,CAACE,SAAS;QAClC,MAAMC,MAAM,GAAGzD,aAAa,KAAKsD,OAAO,CAACzC,SAAS;QAClD,MAAM6C,UAAU,GAAGvD,iBAAiB,KAAKmD,OAAO,CAACzC,SAAS;QAC1D,oBACI,IAAArC,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAA0E,SAAS;UAENO,iBAAiB,EAAC,UAAU;UAC5BC,kBAAkB,EAAEO,OAAO,CAACK,WAAY;UACxCC,kBAAkB,EAAE;YAAEC,QAAQ,EAAEN;UAAS,CAAE;UAC3Cf,OAAO,EAAEA,CAAA,KAAM7B,YAAY,CAAC2C,OAAO,CAACzC,SAAS,CAAE;UAC/CiD,QAAQ,EAAEP,QAAQ,IAAIE,MAAM,IAAIhD,WAAY;UAC5CgC,SAAS,EAAE,2CACPc,QAAQ,GAAG,cAAc,GAAG,EAAE,IAC9B9C,WAAW,IAAI,CAAC8C,QAAQ,GAAG,YAAY,GAAG,EAAE,EAAG;UAAAP,QAAA,gBAEnD,IAAAxE,WAAA,CAAA8D,GAAA,EAACvE,OAAA,CAAAgG,MAAM;YACHC,MAAM,EAAEV,OAAO,CAACW,IAAI,CAACC,MAAM,IAAIzC,SAAU;YACzC0C,GAAG,EAAEb,OAAO,CAACc,SAAU;YACvBC,OAAO,EAAC,OAAO;YACfC,IAAI,EAAEhB,OAAO,CAACK,WAAY;YAC1BY,IAAI,EAAEhB,QAAQ,GAAG,EAAE,GAAG;UAAG,CAC5B,CAAC,eACF,IAAA/E,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAA2G,IAAI;YAAC/B,SAAS,EAAC,gBAAgB;YAAAO,QAAA,gBAC5B,IAAAxE,WAAA,CAAA8D,GAAA,EAACtE,WAAA,CAAAyG,IAAI;cACDhC,SAAS,EAAE,mBAAmBc,QAAQ,GAAG,eAAe,GAAG,aAAa,EAAG;cAC3EmB,aAAa,EAAE,CAAE;cAAA1B,QAAA,EAEhBM,OAAO,CAACK;YAAW,CAClB,CAAC,EACNL,OAAO,CAACqB,KAAK,gBACV,IAAAnG,WAAA,CAAA8D,GAAA,EAACtE,WAAA,CAAAyG,IAAI;cACDhC,SAAS,EAAC,+BAA+B;cACzCiC,aAAa,EAAE,CAAE;cAAA1B,QAAA,EAEhBM,OAAO,CAACqB;YAAK,CACZ,CAAC,GACP,IAAI;UAAA,CACN,CAAC,EACNlB,MAAM,gBACH,IAAAjF,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA+G,iBAAiB;YAACC,KAAK,EAAEjF,MAAM,CAACkF,OAAQ;YAACP,IAAI,EAAC;UAAO,CAAE,CAAC,GACzDhB,QAAQ,gBACR,IAAA/E,WAAA,CAAA8D,GAAA,EAACxE,YAAA,CAAAiH,sBAAsB;YAACT,IAAI,EAAC,OAAO;YAACC,IAAI,EAAE,EAAG;YAACM,KAAK,EAAEjF,MAAM,CAACkF;UAAQ,CAAE,CAAC,GACxEpB,UAAU,gBACV,IAAAlF,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA+G,iBAAiB;YAACC,KAAK,EAAEjF,MAAM,CAACoF,aAAc;YAACT,IAAI,EAAC;UAAO,CAAE,CAAC,gBAE/D,IAAA/F,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA0E,SAAS;YACNO,iBAAiB,EAAC,QAAQ;YAC1BC,kBAAkB,EACdrD,CAAC,CAAC,4BAA4B,EAAE;cAAE4E,IAAI,EAAEhB,OAAO,CAACK;YAAY,CAAC,CAAC,IAC3D,YAAYL,OAAO,CAACK,WAAW,EACrC;YACDnB,OAAO,EAAEA,CAAA,KAAMnB,YAAY,CAACiC,OAAO,CAACzC,SAAS,CAAE;YAC/CiD,QAAQ,EAAEpD,cAAe;YACzBuE,OAAO,EAAE;cAAEC,GAAG,EAAE,CAAC;cAAE9C,MAAM,EAAE,CAAC;cAAED,IAAI,EAAE,CAAC;cAAEgD,KAAK,EAAE;YAAE,CAAE;YAClD1C,SAAS,EAAC,6DAA6D;YAAAO,QAAA,eAEvE,IAAAxE,WAAA,CAAA8D,GAAA,EAACxE,YAAA,CAAAiH,sBAAsB;cACnBT,IAAI,EAAC,QAAQ;cACbC,IAAI,EAAE,EAAG;cACTM,KAAK,EAAEjF,MAAM,CAACoF;YAAc,CAC/B;UAAC,CACK,CACd;QAAA,GAzDI,WAAW1B,OAAO,CAACzC,SAAS,EA0D1B,CAAC;MAEpB,CAAC,CAAC,EAGDJ,WAAW,gBACR,IAAAjC,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAA2G,IAAI;QAAC/B,SAAS,EAAC,iDAAiD;QAAAO,QAAA,gBAC7D,IAAAxE,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA+G,iBAAiB;UAACC,KAAK,EAAEjF,MAAM,CAACoF,aAAc;UAACT,IAAI,EAAC;QAAO,CAAE,CAAC,eAC/D,IAAA/F,WAAA,CAAA8D,GAAA,EAACtE,WAAA,CAAAyG,IAAI;UAAChC,SAAS,EAAC,2CAA2C;UAAAO,QAAA,EACtDtD,CAAC,CAAC,uBAAuB,CAAC,IAAI;QAAoB,CACjD,CAAC;MAAA,CACL,CAAC,GACP,IAAI,eAER,IAAAlB,WAAA,CAAA8D,GAAA,EAACnE,QAAA,CAAAiH,OAAO;QAACP,KAAK,EAAEjF,MAAM,CAACyF,MAAO;QAACC,OAAO,EAAE;MAAE,CAAE,CAAC,eAG7C,IAAA9G,WAAA,CAAA8D,GAAA,EAACiD,SAAS;QACNC,IAAI,EAAC,sBAAsB;QAC3BC,SAAS,EAAE7F,MAAM,CAAC4F,IAAK;QACvBE,KAAK,EAAEhG,CAAC,CAAC,wBAAwB,CAAC,IAAI,qBAAsB;QAC5DoE,QAAQ,EAAEpD,cAAe;QACzB8B,OAAO,EAAEA,CAAA,KAAM;UACXzD,OAAO,CAAC,CAAC;UACTG,YAAY,CAAC,CAAC;QAClB;MAAE,CACL,CAAC,eAGF,IAAAV,WAAA,CAAA8D,GAAA,EAACiD,SAAS;QACNC,IAAI,EAAC,aAAa;QAClBC,SAAS,EAAE7F,MAAM,CAAC4F,IAAK;QACvBE,KAAK,EAAEhG,CAAC,CAAC,oBAAoB,CAAC,IAAI,yBAA0B;QAC5DoE,QAAQ,EAAEpD,cAAe;QACzB8B,OAAO,EAAEA,CAAA,KAAM;UACXzD,OAAO,CAAC,CAAC;UACTE,gBAAgB,CAAC,CAAC;QACtB;MAAE,CACL,CAAC,EAGDE,iBAAiB,gBACd,IAAAX,WAAA,CAAA8D,GAAA,EAACiD,SAAS;QACNC,IAAI,EAAC,iBAAiB;QACtBC,SAAS,EAAE7F,MAAM,CAAC4F,IAAK;QACvBE,KAAK,EAAEhG,CAAC,CAAC,yBAAyB,CAAC,IAAI,cAAe;QACtDoE,QAAQ,EAAEpD,cAAe;QACzB8B,OAAO,EAAEA,CAAA,KAAM;UACXzD,OAAO,CAAC,CAAC;UACTI,iBAAiB,CAAC,CAAC;QACvB;MAAE,CACL,CAAC,GACF,IAAI,eAGR,IAAAX,WAAA,CAAA8D,GAAA,EAACnE,QAAA,CAAAiH,OAAO;QAACP,KAAK,EAAEjF,MAAM,CAACyF,MAAO;QAACC,OAAO,EAAE;MAAE,CAAE,CAAC,eAC7C,IAAA9G,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAA0E,SAAS;QACNO,iBAAiB,EAAC,UAAU;QAC5BC,kBAAkB,EAAErD,CAAC,CAAC,wBAAwB,CAAC,IAAI,0BAA2B;QAC9E8C,OAAO,EAAEA,CAAA,KAAMjC,gBAAgB,CAACzB,IAAI,CAAC,CAAE;QACvCgF,QAAQ,EAAEpD,cAAe;QACzB+B,SAAS,EAAE,yCAAyC/B,cAAc,GAAG,YAAY,GAAG,EAAE,EAAG;QAAAsC,QAAA,GAExF3C,aAAa,gBACV,IAAA7B,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA+G,iBAAiB;UAACC,KAAK,EAAEjF,MAAM,CAACoB,KAAM;UAACuD,IAAI,EAAC;QAAO,CAAE,CAAC,gBAEvD,IAAA/F,WAAA,CAAA8D,GAAA,EAACxE,YAAA,CAAAiH,sBAAsB;UAACT,IAAI,EAAC,QAAQ;UAACC,IAAI,EAAE,EAAG;UAACM,KAAK,EAAEjF,MAAM,CAACoB;QAAM,CAAE,CACzE,eACD,IAAAxC,WAAA,CAAA8D,GAAA,EAACtE,WAAA,CAAAyG,IAAI;UAAChC,SAAS,EAAC,aAAa;UAACC,KAAK,EAAE;YAAEmC,KAAK,EAAEjF,MAAM,CAACoB;UAAM,CAAE;UAAAgC,QAAA,EACxDtD,CAAC,CAAC,wBAAwB,CAAC,IAAI;QAA0B,CACxD,CAAC;MAAA,CACA,CAAC;IAAA,CACJ;EAAC,CACN,CACd;EAED,oBACI,IAAAlB,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAA8H,KAAK;IACFC,OAAO,EAAE9G,IAAK;IACd+G,WAAW;IACXC,aAAa,EAAErH,KAAK,GAAG,MAAM,GAAG,OAAQ;IACxCsH,cAAc,EAAEhH,OAAQ;IAAAiE,QAAA,gBAExB,IAAAxE,WAAA,CAAA8D,GAAA,EAACzE,YAAA,CAAA0E,SAAS;MACNO,iBAAiB,EAAC,QAAQ;MAC1BC,kBAAkB,EAAErD,CAAC,CAAC,sBAAsB,CAAC,IAAI,OAAQ;MACzD8C,OAAO,EAAEzD,OAAQ;MACjB0D,SAAS,EAAEhE,KAAK,GAAG,iBAAiB,GAAG,oBAAqB;MAC5DiE,KAAK,EAAE,CAACjE,KAAK,GAAGmE,MAAM,CAACoD,WAAW,GAAGvE,SAAU;MAAAuB,QAAA,EAE9CX;IAAO,CACD,CAAC,eAEZ,IAAA7D,WAAA,CAAA8D,GAAA,EAACpE,MAAA,CAAA+H,MAAM;MACHC,OAAO,EAAE3F,gBAAiB;MAC1B4F,KAAK,EAAEzG,CAAC,CAAC,wBAAwB,CAAC,IAAI,0BAA2B;MACjE0G,WAAW,EAAE1G,CAAC,CAAC,4BAA4B,CAAC,IAAI,oDAAqD;MACrG2G,OAAO,EAAE,CACL;QACIX,KAAK,EAAEhG,CAAC,CAAC,wBAAwB,CAAC,IAAI,0BAA0B;QAChEmF,KAAK,EAAE,aAAa;QACpBrC,OAAO,EAAElB;MACb,CAAC,EACD;QAAEoE,KAAK,EAAEhG,CAAC,CAAC,eAAe,CAAC,IAAI,QAAQ;QAAEmF,KAAK,EAAE;MAAS,CAAC;IAC5D,CACL,CAAC;EAAA,CACC,CAAC;AAEhB,CAAC;;AAED;AACA,MAAMU,SAMJ,GAAGA,CAAC;EAAEC,IAAI;EAAEC,SAAS;EAAEC,KAAK;EAAE5B,QAAQ;EAAEtB;AAAQ,CAAC,kBAC/C,IAAAhE,WAAA,CAAAyE,IAAA,EAACpF,YAAA,CAAA0E,SAAS;EACNO,iBAAiB,EAAC,UAAU;EAC5BC,kBAAkB,EAAE2C,KAAM;EAC1BlD,OAAO,EAAEA,OAAQ;EACjBsB,QAAQ,EAAEA,QAAS;EACnBrB,SAAS,EAAE,yCAAyCqB,QAAQ,GAAG,YAAY,GAAG,EAAE,EAAG;EAAAd,QAAA,gBAEnF,IAAAxE,WAAA,CAAA8D,GAAA,EAACxE,YAAA,CAAAiH,sBAAsB;IAACT,IAAI,EAAEkB,IAAK;IAACjB,IAAI,EAAE,EAAG;IAACM,KAAK,EAAEY;EAAU,CAAE,CAAC,eAClE,IAAAjH,WAAA,CAAA8D,GAAA,EAACtE,WAAA,CAAAyG,IAAI;IAAChC,SAAS,EAAC,6BAA6B;IAAAO,QAAA,EAAE0C;EAAK,CAAO,CAAC;AAAA,CACrD,CACd;;AAED;AACA;AACA;AACA,MAAM9C,MAAM,GAAG;EACXC,MAAM,EAAE;IACJyD,WAAW,EAAE,MAAM;IACnBC,aAAa,EAAE,IAAI;IACnBC,YAAY,EAAE,EAAE;IAChBC,YAAY,EAAE;MAAEvE,KAAK,EAAE,CAAC;MAAEwE,MAAM,EAAE;IAAE,CAAC;IACrCC,SAAS,EAAE;EACf,CAAqB;EACrBX,WAAW,EAAE;IACTY,eAAe,EAAE;EACrB;AACJ,CAAC;AAAC,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAEalI,WAAW","ignoreList":[]}
@@ -1106,15 +1106,40 @@ const OxyProvider = ({
1106
1106
  // run cookie-restore BEFORE those probes (and disable the later duplicate).
1107
1107
  //
1108
1108
  // Read ONCE here (synchronously usable by the step `enabled` gates below).
1109
- // It is non-null ONLY on first-party `*.oxy.so` web apps that persist the
1110
- // slot — a cross-apex RP never writes it (its restore funnels through
1111
- // `handleWebSSOSession`, which does not touch the authuser), and native has
1112
- // no localStorage, so both keep their existing order untouched. The
1113
- // earlier `stored-session` step still runs first (FIX-A latency), and when
1114
- // a slot exists but its cookies have all lapsed, cookie-restore simply
1115
- // returns no accounts and the chain falls through to the cross-domain
1116
- // fallbacks exactly as before.
1109
+ // It is non-null ONLY on first-party web apps that persist the slot. Both the
1110
+ // device sign-in/switch paths AND `handleWebSSOSession` (FedCM/SSO/credentials
1111
+ // commit funnel) now persist it — but only when the session genuinely joined
1112
+ // the device set: `establishDeviceRefreshSlot` returns an `authuser` ONLY on
1113
+ // first-party web (same registrable apex as the API), so a cross-apex RP never
1114
+ // writes a phantom slot and native has no localStorage. Both therefore keep
1115
+ // their existing order untouched. The earlier `stored-session` step still runs
1116
+ // first (FIX-A latency), and when a slot exists but its cookies have all
1117
+ // lapsed, cookie-restore simply returns no accounts and the chain falls through
1118
+ // to the cross-domain fallbacks exactly as before.
1117
1119
  const prioritizeMultiAccount = (0, _useWebSSO.isWebBrowser)() && (0, _activeAuthuser.readActiveAuthuser)() !== null;
1120
+
1121
+ // DELIBERATELY-SIGNED-OUT gate (web): when the user pressed "Sign out", any
1122
+ // credential that can silently re-mint a session may still be live on the
1123
+ // next reload — the central IdP session (FedCM credential association /
1124
+ // per-apex `fedcm_session` cookie) AND the device refresh cookies. Since
1125
+ // PR #455 the PRIMARY web session also joins the `oxy_rt_<authuser>` device
1126
+ // set, so the un-gated cookie-restore steps would `refresh-all` that still-
1127
+ // present cookie and sign the user back in without intent — exactly the
1128
+ // "sign-out is silently undone" regression. So this flag gates EVERY
1129
+ // AUTOMATIC silent-restore cold-boot step: `stored-session`,
1130
+ // `cookie-restore-active`, `fedcm-silent`, `silent-iframe`, and
1131
+ // `cookie-restore`. The gate — not a cookie wipe — is the authority: the
1132
+ // account may stay "known" for a fast deliberate re-sign-in, but no step
1133
+ // restores it silently while the flag is set. Read the durable flag ONCE here
1134
+ // (synchronously usable by every step `enabled` gate). Any deliberate sign-in
1135
+ // (password, FedCM, account switch, device claim) clears it, so there is no
1136
+ // "stuck signed out" state. The `sso-bounce` step needs no extra gate: it is
1137
+ // already self-suppressed after sign-out (its `hasPriorSession` hint is
1138
+ // cleared). `sso-return` is NOT gated — it commits the result of a deliberate
1139
+ // top-level `/sso` bounce the user just initiated. `shared-key-signin` is
1140
+ // native-only and the flag never sets on native (`markSignedOut` no-ops
1141
+ // off-web), so its gate would be moot; it is left untouched.
1142
+ const silentRestoreBlocked = (0, _activeAuthuser.isSilentRestoreSuppressed)();
1118
1143
  try {
1119
1144
  const outcome = await (0, _core.runColdBoot)({
1120
1145
  steps: [{
@@ -1135,12 +1160,17 @@ const OxyProvider = ({
1135
1160
  };
1136
1161
  }
1137
1162
  }, {
1138
- // 2) Stored-session bearer restore. NO `enabled` gate runs on ALL
1139
- // platforms. This is native's ONLY restore path (every web-only step
1140
- // is disabled off-browser, so native reaches exactly this) AND the
1141
- // common WEB reload winner.
1163
+ // 2) Stored-session bearer restore. Runs on ALL platforms EXCEPT when
1164
+ // the deliberately-signed-out flag is set (web only it never sets on
1165
+ // native, so native still always reaches exactly this step, its ONLY
1166
+ // restore path). This is also the common WEB reload winner.
1167
+ //
1168
+ // SIGNED-OUT GATE: after a deliberate full sign-out the stored session
1169
+ // state is cleared, so this would normally skip anyway — but the gate
1170
+ // makes that authoritative rather than incidental, so no residual
1171
+ // stored token can silently restore while the user is signed out.
1142
1172
  //
1143
- // ORDERING (FIX A): this step now runs BEFORE the slow web-only
1173
+ // ORDERING (FIX A): this step runs BEFORE the slow web-only
1144
1174
  // probes (`fedcm-silent`, `silent-iframe`, `cookie-restore`). On a
1145
1175
  // normal reload the local bearer validates in one round-trip and
1146
1176
  // wins; `runColdBoot` then short-circuits and never even evaluates
@@ -1151,6 +1181,7 @@ const OxyProvider = ({
1151
1181
  // local session this step skips and the cross-domain fallback chain
1152
1182
  // (fedcm → iframe → cookie → sso-bounce) runs exactly as before.
1153
1183
  id: 'stored-session',
1184
+ enabled: () => !silentRestoreBlocked,
1154
1185
  run: async () => {
1155
1186
  const restored = await restoreStoredSession();
1156
1187
  if (restored) {
@@ -1234,8 +1265,14 @@ const OxyProvider = ({
1234
1265
  // When no slot is persisted this is disabled and the original order is
1235
1266
  // unchanged; when the slot's cookies have lapsed it returns no accounts
1236
1267
  // and the chain falls through to the cross-domain fallbacks below.
1268
+ //
1269
+ // SIGNED-OUT GATE: since PR #455 the primary's `oxy_rt` slot survives a
1270
+ // deliberate sign-out, so without this gate `refresh-all` would re-mint
1271
+ // and silently re-log-in the user on reload. The flag is cleared by any
1272
+ // deliberate sign-in (including an account SWITCH, which also writes the
1273
+ // new active slot), so the switch-survives-reload path is unaffected.
1237
1274
  id: 'cookie-restore-active',
1238
- enabled: () => prioritizeMultiAccount,
1275
+ enabled: () => prioritizeMultiAccount && !silentRestoreBlocked,
1239
1276
  run: async () => {
1240
1277
  const restored = await restoreViaRefreshCookie();
1241
1278
  return restored ? {
@@ -1257,7 +1294,7 @@ const OxyProvider = ({
1257
1294
  // already recovered a local session — the probe cannot improve on a
1258
1295
  // valid local bearer, and skipping it avoids the silent round-trip.
1259
1296
  id: 'fedcm-silent',
1260
- enabled: () => !storedSessionRestored && fedcmSupported && !servicesSilentAttempted.has(silentKey),
1297
+ enabled: () => !storedSessionRestored && !silentRestoreBlocked && fedcmSupported && !servicesSilentAttempted.has(silentKey),
1261
1298
  run: async () => {
1262
1299
  servicesSilentAttempted.add(silentKey);
1263
1300
  const session = await oxyServices.silentSignInWithFedCM?.();
@@ -1296,7 +1333,7 @@ const OxyProvider = ({
1296
1333
  // FIX-D: bounded by `SILENT_IFRAME_TIMEOUT` (plus `iframe.onerror`
1297
1334
  // fail-fast in core) so a no-message iframe cannot stall cold boot.
1298
1335
  id: 'silent-iframe',
1299
- enabled: () => !storedSessionRestored && (0, _useWebSSO.isWebBrowser)(),
1336
+ enabled: () => !storedSessionRestored && !silentRestoreBlocked && (0, _useWebSSO.isWebBrowser)(),
1300
1337
  run: async () => {
1301
1338
  if (!commitWebSession) {
1302
1339
  return {
@@ -1335,8 +1372,13 @@ const OxyProvider = ({
1335
1372
  // would be a redundant second `refreshAllSessions`. It still runs in the
1336
1373
  // common no-persisted-slot case (e.g. first visit to a first-party app
1337
1374
  // whose central refresh cookies already exist).
1375
+ //
1376
+ // SIGNED-OUT GATE (same rationale as `cookie-restore-active`): the
1377
+ // primary's `oxy_rt` slot survives a deliberate sign-out (PR #455), so
1378
+ // this must be skipped while the signed-out flag is set or it would
1379
+ // silently re-restore the primary on reload.
1338
1380
  id: 'cookie-restore',
1339
- enabled: () => (0, _useWebSSO.isWebBrowser)() && !prioritizeMultiAccount,
1381
+ enabled: () => (0, _useWebSSO.isWebBrowser)() && !prioritizeMultiAccount && !silentRestoreBlocked,
1340
1382
  run: async () => {
1341
1383
  const restored = await restoreViaRefreshCookie();
1342
1384
  return restored ? {
@@ -1576,13 +1618,48 @@ const OxyProvider = ({
1576
1618
  throw new Error('Session response did not include an access token');
1577
1619
  }
1578
1620
  oxyServices.httpService.setTokens(session.accessToken);
1621
+
1622
+ // A committed web session re-enables automatic silent restore: clear the
1623
+ // durable "deliberately signed out" flag. This funnel is reached by deliberate
1624
+ // sign-ins (password, interactive FedCM, `/sso` return) AND by the silent
1625
+ // cold-boot steps — but those are GATED on the flag, so when it is set they
1626
+ // never run and never reach here; clearing is therefore only hit on a genuine
1627
+ // (re-)sign-in or when restore was already permitted, both correct.
1628
+ (0, _activeAuthuser.clearSignedOut)();
1629
+
1630
+ // Register this primary session in the device's first-party multi-account
1631
+ // refresh-cookie set (web only). Every web primary-session restore funnels
1632
+ // through here — FedCM silent (`/fedcm/exchange`), per-apex `/auth/silent`
1633
+ // iframe, central `/sso` return, and keyless password sign-in. Of those, only
1634
+ // a same-apex `/fedcm/exchange` plants an `oxy_rt_<authuser>` slot as a side
1635
+ // effect; the cross-origin/credential-less restores (`/sso/exchange`,
1636
+ // `/auth/silent` postMessage) cannot set an `api.oxy.so` cookie at all. So
1637
+ // WITHOUT this call a web primary never joins the device set: `refresh-all`
1638
+ // returns zero accounts, and account-switch persistence + the
1639
+ // `cookie-restore-active` cold-boot step have no foundation. Calling the shared
1640
+ // `POST /auth/session` primitive here makes EVERY primary participate in the
1641
+ // set, re-plants the rotated token, and records the active `authuser` so the
1642
+ // next cold boot's `cookie-restore-active` reconciles the persisted active
1643
+ // (possibly switched) account instead of `fedcm-silent` clobbering it back to
1644
+ // the primary. Best-effort: a `null` result (native / transient failure)
1645
+ // leaves the in-session token untouched.
1646
+ const primaryAuthuser = await oxyServices.establishDeviceRefreshSlot();
1647
+ // A non-null slot is returned ONLY on first-party web (the helper gates on
1648
+ // platform + same registrable apex), so recording the active slot here is safe
1649
+ // and never writes a phantom authuser for a cross-apex RP or native.
1650
+ if (typeof primaryAuthuser === 'number') {
1651
+ (0, _activeAuthuser.writeActiveAuthuser)(primaryAuthuser);
1652
+ }
1579
1653
  const clientSession = {
1580
1654
  sessionId: session.sessionId,
1581
1655
  deviceId: session.deviceId || '',
1582
1656
  expiresAt: session.expiresAt || new Date(Date.now() + DEFAULT_SESSION_VALIDITY_MS).toISOString(),
1583
1657
  lastActive: new Date().toISOString(),
1584
1658
  userId: session.user.id?.toString() ?? '',
1585
- isCurrent: true
1659
+ isCurrent: true,
1660
+ ...(typeof primaryAuthuser === 'number' ? {
1661
+ authuser: primaryAuthuser
1662
+ } : null)
1586
1663
  };
1587
1664
  updateSessions([clientSession], {
1588
1665
  merge: true
@@ -1862,6 +1939,10 @@ const OxyProvider = ({
1862
1939
  throw new Error('Account switch did not return a valid session');
1863
1940
  }
1864
1941
 
1942
+ // A switch is a deliberate sign-in into an account: re-enable automatic silent
1943
+ // restore by clearing any prior "deliberately signed out" flag.
1944
+ (0, _activeAuthuser.clearSignedOut)();
1945
+
1865
1946
  // `oxyServices.switchToAccount` already planted `result.accessToken` as the
1866
1947
  // active token; mirror the minted session into the multi-account store and
1867
1948
  // mark it current, recording the device `authuser` slot so web silent-switch