@donotdev/ui 0.0.2 → 0.0.3
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/dist/components/auth/AuthMenu.d.ts.map +1 -1
- package/dist/components/auth/AuthMenu.js +15 -28
- package/dist/components/common/FeatureCard.js +1 -1
- package/dist/components/cookie-consent/CookieConsent.d.ts.map +1 -1
- package/dist/components/cookie-consent/CookieConsent.js +2 -41
- package/dist/components/cookie-consent/index.d.ts +0 -1
- package/dist/components/cookie-consent/index.d.ts.map +1 -1
- package/dist/components/cookie-consent/index.js +1 -1
- package/dist/components/layout/components/DropdownNavigation.d.ts.map +1 -1
- package/dist/components/layout/components/header/ThemeToggle.d.ts +1 -1
- package/dist/components/layout/components/header/ThemeToggle.d.ts.map +1 -1
- package/dist/components/layout/components/header/ThemeToggle.js +5 -4
- package/dist/dndev.css +137 -120
- package/dist/index.js +4 -4
- package/dist/internal/devtools/DebugTools.d.ts.map +1 -1
- package/dist/internal/devtools/DebugTools.js +8 -4
- package/dist/internal/devtools/components/ConfigTab.d.ts.map +1 -1
- package/dist/internal/devtools/components/ConfigTab.js +31 -133
- package/dist/internal/devtools/components/DebugDialog.d.ts.map +1 -1
- package/dist/internal/devtools/components/DebugDialog.js +11 -520
- package/dist/internal/devtools/components/DesignTab.d.ts +2 -0
- package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -0
- package/dist/internal/devtools/components/DesignTab.js +220 -0
- package/dist/internal/devtools/components/StoresTab.d.ts.map +1 -1
- package/dist/internal/devtools/components/StoresTab.js +54 -102
- package/dist/internal/devtools/components/index.d.ts +1 -6
- package/dist/internal/devtools/components/index.d.ts.map +1 -1
- package/dist/internal/devtools/components/index.js +1 -6
- package/dist/internal/devtools/utils/index.d.ts +0 -1
- package/dist/internal/devtools/utils/index.d.ts.map +1 -1
- package/dist/internal/devtools/utils/index.js +0 -1
- package/dist/internal/initializers/BaseStoresInitializer.d.ts.map +1 -1
- package/dist/internal/initializers/BaseStoresInitializer.js +25 -58
- package/dist/internal/layout/DnDevLayout.js +3 -3
- package/dist/internal/layout/components/footer/FooterBranding.d.ts.map +1 -1
- package/dist/internal/layout/components/footer/FooterBranding.js +3 -1
- package/dist/routing/AuthGuard.d.ts +14 -10
- package/dist/routing/AuthGuard.d.ts.map +1 -1
- package/dist/routing/AuthGuard.js +25 -22
- package/dist/routing/Link.d.ts +2 -2
- package/dist/routing/Link.js +2 -2
- package/dist/routing/hooks/hooks.next.js +1 -1
- package/dist/routing/hooks/hooks.vite.js +1 -1
- package/dist/routing/hooks/useRedirectGuard.next.d.ts +2 -36
- package/dist/routing/hooks/useRedirectGuard.next.d.ts.map +1 -1
- package/dist/routing/hooks/useRedirectGuard.next.js +14 -55
- package/dist/routing/hooks/useRedirectGuard.vite.d.ts +2 -36
- package/dist/routing/hooks/useRedirectGuard.vite.d.ts.map +1 -1
- package/dist/routing/hooks/useRedirectGuard.vite.js +14 -55
- package/dist/routing/index.d.ts +0 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/styles/index.css +137 -120
- package/dist/utils/assetResolver.d.ts +5 -5
- package/dist/utils/assetResolver.js +4 -4
- package/dist/utils/useAuthSafe.d.ts +25 -12
- package/dist/utils/useAuthSafe.d.ts.map +1 -1
- package/dist/utils/useAuthSafe.js +3 -1
- package/dist/utils/useAuthVisibility.d.ts +3 -3
- package/dist/utils/useAuthVisibility.d.ts.map +1 -1
- package/dist/utils/useAuthVisibility.js +25 -21
- package/dist/utils/useBillingVisibility.d.ts +2 -2
- package/dist/utils/useBillingVisibility.d.ts.map +1 -1
- package/dist/utils/useBillingVisibility.js +12 -13
- package/dist/utils/useCrudSafe.d.ts +1 -1
- package/dist/utils/useCrudSafe.d.ts.map +1 -1
- package/dist/utils/useCrudSafe.js +26 -13
- package/dist/utils/useOAuthSafe.d.ts +25 -12
- package/dist/utils/useOAuthSafe.d.ts.map +1 -1
- package/dist/utils/useStripeBillingSafe.d.ts +30 -18
- package/dist/utils/useStripeBillingSafe.d.ts.map +1 -1
- package/dist/utils/useStripeBillingSafe.js +5 -6
- package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
- package/dist/vite-routing/AppRoutes.js +5 -5
- package/dist/vite-routing/RootLayout.d.ts.map +1 -1
- package/dist/vite-routing/RootLayout.js +34 -7
- package/package.json +9 -9
- package/dist/internal/devtools/components/AuthTab.d.ts +0 -2
- package/dist/internal/devtools/components/AuthTab.d.ts.map +0 -1
- package/dist/internal/devtools/components/AuthTab.js +0 -98
- package/dist/internal/devtools/components/ColorRatioTab.d.ts +0 -2
- package/dist/internal/devtools/components/ColorRatioTab.d.ts.map +0 -1
- package/dist/internal/devtools/components/ColorRatioTab.js +0 -322
- package/dist/internal/devtools/components/DebugToggle.d.ts +0 -2
- package/dist/internal/devtools/components/DebugToggle.d.ts.map +0 -1
- package/dist/internal/devtools/components/DebugToggle.js +0 -57
- package/dist/internal/devtools/components/EnvironmentTab.d.ts +0 -2
- package/dist/internal/devtools/components/EnvironmentTab.d.ts.map +0 -1
- package/dist/internal/devtools/components/EnvironmentTab.js +0 -26
- package/dist/internal/devtools/components/I18nTab.d.ts +0 -2
- package/dist/internal/devtools/components/I18nTab.d.ts.map +0 -1
- package/dist/internal/devtools/components/I18nTab.js +0 -76
- package/dist/internal/devtools/components/OAuthGuideButton.d.ts +0 -10
- package/dist/internal/devtools/components/OAuthGuideButton.d.ts.map +0 -1
- package/dist/internal/devtools/components/OAuthGuideButton.js +0 -71
- package/dist/internal/devtools/components/StripeDebugTab.d.ts +0 -2
- package/dist/internal/devtools/components/StripeDebugTab.d.ts.map +0 -1
- package/dist/internal/devtools/components/StripeDebugTab.js +0 -175
- package/dist/internal/devtools/components/ThemesTab.d.ts +0 -2
- package/dist/internal/devtools/components/ThemesTab.d.ts.map +0 -1
- package/dist/internal/devtools/components/ThemesTab.js +0 -77
- package/dist/internal/devtools/utils/spacingAnalyzer.d.ts +0 -15
- package/dist/internal/devtools/utils/spacingAnalyzer.d.ts.map +0 -1
- package/dist/internal/devtools/utils/spacingAnalyzer.js +0 -88
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview AuthGuard component
|
|
3
3
|
* @description Protects routes based on authentication configuration
|
|
4
4
|
*
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.3
|
|
6
6
|
* @since 0.0.1
|
|
7
7
|
* @author AMBROISE PARK Consulting
|
|
8
8
|
*/
|
|
@@ -34,24 +34,28 @@ interface AuthGuardProps {
|
|
|
34
34
|
* - 'pro': Professional features
|
|
35
35
|
* - 'premium': Premium features
|
|
36
36
|
*
|
|
37
|
-
* @version 0.0.
|
|
37
|
+
* @version 0.0.3
|
|
38
38
|
* @since 0.0.1
|
|
39
39
|
* @author AMBROISE PARK Consulting
|
|
40
40
|
*/
|
|
41
41
|
export declare function AuthGuard({ auth, children, fallback: Fallback, }: AuthGuardProps): import("react/jsx-runtime").JSX.Element;
|
|
42
42
|
/**
|
|
43
|
-
* Hook to check if current user can
|
|
43
|
+
* Hook to check if current user can navigate to a route with given auth config
|
|
44
44
|
* ONLY uses store - single source of truth!
|
|
45
45
|
*
|
|
46
|
-
* @version 0.0.
|
|
46
|
+
* @version 0.0.3
|
|
47
47
|
* @since 0.0.1
|
|
48
48
|
* @author AMBROISE PARK Consulting
|
|
49
49
|
*/
|
|
50
|
-
export declare function
|
|
50
|
+
export declare function useCanNavigate(auth: PageAuth | false): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated Use useCanNavigate instead
|
|
53
|
+
*/
|
|
54
|
+
export declare const useCanAccess: typeof useCanNavigate;
|
|
51
55
|
/**
|
|
52
56
|
* Hook to get current user's role - directly from store
|
|
53
57
|
*
|
|
54
|
-
* @version 0.0.
|
|
58
|
+
* @version 0.0.3
|
|
55
59
|
* @since 0.0.1
|
|
56
60
|
* @author AMBROISE PARK Consulting
|
|
57
61
|
*/
|
|
@@ -59,7 +63,7 @@ export declare function useUserRole(): typeof USER_ROLES.GUEST | typeof USER_ROL
|
|
|
59
63
|
/**
|
|
60
64
|
* Hook to check specific role - directly from store
|
|
61
65
|
*
|
|
62
|
-
* @version 0.0.
|
|
66
|
+
* @version 0.0.3
|
|
63
67
|
* @since 0.0.1
|
|
64
68
|
* @author AMBROISE PARK Consulting
|
|
65
69
|
*/
|
|
@@ -67,7 +71,7 @@ export declare function useHasRole(role: typeof USER_ROLES.GUEST | typeof USER_R
|
|
|
67
71
|
/**
|
|
68
72
|
* Hook to get all auth state for debugging
|
|
69
73
|
*
|
|
70
|
-
* @version 0.0.
|
|
74
|
+
* @version 0.0.3
|
|
71
75
|
* @since 0.0.1
|
|
72
76
|
* @author AMBROISE PARK Consulting
|
|
73
77
|
*/
|
|
@@ -81,7 +85,7 @@ export declare function useAuthState(): {
|
|
|
81
85
|
/**
|
|
82
86
|
* HOC to wrap components with auth protection
|
|
83
87
|
*
|
|
84
|
-
* @version 0.0.
|
|
88
|
+
* @version 0.0.3
|
|
85
89
|
* @since 0.0.1
|
|
86
90
|
* @author AMBROISE PARK Consulting
|
|
87
91
|
*/
|
|
@@ -89,7 +93,7 @@ export declare function withAuth<P extends object>(Component: ComponentType<P>,
|
|
|
89
93
|
/**
|
|
90
94
|
* Utility to create auth configs
|
|
91
95
|
*
|
|
92
|
-
* @version 0.0.
|
|
96
|
+
* @version 0.0.3
|
|
93
97
|
* @since 0.0.1
|
|
94
98
|
* @author AMBROISE PARK Consulting
|
|
95
99
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthGuard.d.ts","sourceRoot":"","sources":["../../src/routing/AuthGuard.tsx"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"AuthGuard.d.ts","sourceRoot":"","sources":["../../src/routing/AuthGuard.tsx"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAGf,OAAO,EAGL,UAAU,EACV,kBAAkB,EAClB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAYxB;;GAEG;AACH,UAAU,cAAc;IACtB,wCAAwC;IACxC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IACvB,wCAAwC;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,QAAQ,EAAE,QAAiB,GAC5B,EAAE,cAAc,2CA2HhB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAG9D;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,uBAAiB,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,WAAW,IACvB,OAAO,UAAU,CAAC,KAAK,GACvB,OAAO,UAAU,CAAC,IAAI,GACtB,OAAO,UAAU,CAAC,KAAK,CAS1B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EACA,OAAO,UAAU,CAAC,KAAK,GACvB,OAAO,UAAU,CAAC,IAAI,GACtB,OAAO,UAAU,CAAC,KAAK,GAC1B,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY;;;;;;EAW3B;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACvC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,EAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,WAEW,CAAC,6CAOnC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;IAC3B,iCAAiC;kBACrB,KAAK;IAEjB,oCAAoC;oBACtB,QAAQ;IAEtB,yCAAyC;gBAC/B,QAAQ;IAKlB,uDAAuD;iBAC5C,QAAQ;IAKnB,gCAAgC;iBAExB,CAAC,OAAO,kBAAkB,EAAE,MAAM,OAAO,kBAAkB,CAAC,KACjE,QAAQ;IAKX,eAAe;eACN,QAAQ;IAKjB,mBAAmB;mBACN,QAAQ;IAKrB,sCAAsC;oBACxB,QAAQ;IAMtB,wBAAwB;uBACL,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,KAAG,QAAQ;CAItE,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -5,14 +5,13 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
5
5
|
* @fileoverview AuthGuard component
|
|
6
6
|
* @description Protects routes based on authentication configuration
|
|
7
7
|
*
|
|
8
|
-
* @version 0.0.
|
|
8
|
+
* @version 0.0.3
|
|
9
9
|
* @since 0.0.1
|
|
10
10
|
* @author AMBROISE PARK Consulting
|
|
11
11
|
*/
|
|
12
12
|
import { useEffect, useState, lazy, Suspense, } from 'react';
|
|
13
13
|
import { Stack } from '@donotdev/components';
|
|
14
|
-
import { useAuthConfig } from '@donotdev/core';
|
|
15
|
-
import { USER_ROLES, SUBSCRIPTION_TIERS } from '@donotdev/core';
|
|
14
|
+
import { useAuthConfig, FEATURE_STATUS, USER_ROLES, SUBSCRIPTION_TIERS, } from '@donotdev/core';
|
|
16
15
|
// Platform-specific hooks via conditional exports
|
|
17
16
|
import { useRedirectGuard, useNavigate } from '@donotdev/ui/routing/hooks';
|
|
18
17
|
import Loader from '../components/common/Loader';
|
|
@@ -34,15 +33,15 @@ const CookieConsent = lazy(() => import('../components/cookie-consent/CookieCons
|
|
|
34
33
|
* - 'pro': Professional features
|
|
35
34
|
* - 'premium': Premium features
|
|
36
35
|
*
|
|
37
|
-
* @version 0.0.
|
|
36
|
+
* @version 0.0.3
|
|
38
37
|
* @since 0.0.1
|
|
39
38
|
* @author AMBROISE PARK Consulting
|
|
40
39
|
*/
|
|
41
40
|
export function AuthGuard({ auth, children, fallback: Fallback = Loader, }) {
|
|
42
41
|
const navigate = useNavigate();
|
|
43
42
|
const user = useAuthSafe('user');
|
|
44
|
-
const
|
|
45
|
-
const
|
|
43
|
+
const can = useAuthSafe('can');
|
|
44
|
+
const status = useAuthSafe('status');
|
|
46
45
|
const [slowWarning, setSlowWarning] = useState(false);
|
|
47
46
|
// Check if redirect should happen BEFORE rendering fallback
|
|
48
47
|
const { shouldRedirect, redirectTo, isChecking } = useRedirectGuard({
|
|
@@ -52,13 +51,13 @@ export function AuthGuard({ auth, children, fallback: Fallback = Loader, }) {
|
|
|
52
51
|
// Soft timeout at 5 seconds - show warning, don't force redirect
|
|
53
52
|
// Firebase auth typically resolves in 200ms-800ms (broadband), 1-3s (cold start)
|
|
54
53
|
const timer = setTimeout(() => {
|
|
55
|
-
if (
|
|
54
|
+
if (status === FEATURE_STATUS.INITIALIZING) {
|
|
56
55
|
setSlowWarning(true);
|
|
57
56
|
console.warn('[AuthGuard] Auth taking longer than usual (>5s)');
|
|
58
57
|
}
|
|
59
58
|
}, 5000);
|
|
60
59
|
return () => clearTimeout(timer);
|
|
61
|
-
}, [
|
|
60
|
+
}, [status]);
|
|
62
61
|
// Redirect if needed
|
|
63
62
|
useEffect(() => {
|
|
64
63
|
if (shouldRedirect && redirectTo) {
|
|
@@ -75,7 +74,7 @@ export function AuthGuard({ auth, children, fallback: Fallback = Loader, }) {
|
|
|
75
74
|
return _jsx(Loader, {});
|
|
76
75
|
}
|
|
77
76
|
// Show slow auth warning after 5s timeout (only if not redirecting)
|
|
78
|
-
if (
|
|
77
|
+
if (status === FEATURE_STATUS.INITIALIZING && slowWarning) {
|
|
79
78
|
return (_jsx(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-md)', minHeight: '100vh' }, children: _jsxs("div", { className: "dndev-w-full", style: { maxWidth: '28rem', textAlign: 'center' }, children: [_jsx("h2", { style: { marginBottom: 'var(--gap-md)' }, children: "Loading is taking longer than usual" }), _jsx("p", { style: {
|
|
80
79
|
marginBottom: 'var(--gap-md)',
|
|
81
80
|
color: 'var(--muted-foreground)',
|
|
@@ -89,7 +88,7 @@ export function AuthGuard({ auth, children, fallback: Fallback = Loader, }) {
|
|
|
89
88
|
}, children: "Refresh Page" })] }) }));
|
|
90
89
|
}
|
|
91
90
|
// Still checking auth state (but not redirecting) - show fallback
|
|
92
|
-
if (
|
|
91
|
+
if (status === FEATURE_STATUS.INITIALIZING) {
|
|
93
92
|
return _jsx(Fallback, {});
|
|
94
93
|
}
|
|
95
94
|
// Check if it's a consent issue (no functional cookies for auth)
|
|
@@ -98,29 +97,33 @@ export function AuthGuard({ auth, children, fallback: Fallback = Loader, }) {
|
|
|
98
97
|
typeof auth === 'object' &&
|
|
99
98
|
auth.required &&
|
|
100
99
|
!user &&
|
|
101
|
-
|
|
102
|
-
!
|
|
100
|
+
can &&
|
|
101
|
+
!can.navigate(auth)) {
|
|
103
102
|
return (_jsx(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-md)', minHeight: '100vh' }, children: _jsxs("div", { className: "dndev-w-full", style: { maxWidth: '28rem' }, children: [_jsx("h2", { style: { marginBottom: 'var(--gap-md)' }, children: "Authentication Required" }), _jsx("p", { style: { marginBottom: 'var(--gap-md)' }, children: "This page requires authentication. Please accept functional cookies to continue." }), _jsx(Suspense, { fallback: _jsx("div", { children: "Loading consent..." }), children: _jsx(CookieConsent, {}) })] }) }));
|
|
104
103
|
}
|
|
105
104
|
// All checks passed, render children
|
|
106
105
|
return _jsx(_Fragment, { children: children });
|
|
107
106
|
}
|
|
108
107
|
/**
|
|
109
|
-
* Hook to check if current user can
|
|
108
|
+
* Hook to check if current user can navigate to a route with given auth config
|
|
110
109
|
* ONLY uses store - single source of truth!
|
|
111
110
|
*
|
|
112
|
-
* @version 0.0.
|
|
111
|
+
* @version 0.0.3
|
|
113
112
|
* @since 0.0.1
|
|
114
113
|
* @author AMBROISE PARK Consulting
|
|
115
114
|
*/
|
|
116
|
-
export function
|
|
117
|
-
const
|
|
118
|
-
return
|
|
115
|
+
export function useCanNavigate(auth) {
|
|
116
|
+
const can = useAuthSafe('can');
|
|
117
|
+
return can?.navigate(auth) ?? false;
|
|
119
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* @deprecated Use useCanNavigate instead
|
|
121
|
+
*/
|
|
122
|
+
export const useCanAccess = useCanNavigate;
|
|
120
123
|
/**
|
|
121
124
|
* Hook to get current user's role - directly from store
|
|
122
125
|
*
|
|
123
|
-
* @version 0.0.
|
|
126
|
+
* @version 0.0.3
|
|
124
127
|
* @since 0.0.1
|
|
125
128
|
* @author AMBROISE PARK Consulting
|
|
126
129
|
*/
|
|
@@ -132,7 +135,7 @@ export function useUserRole() {
|
|
|
132
135
|
/**
|
|
133
136
|
* Hook to check specific role - directly from store
|
|
134
137
|
*
|
|
135
|
-
* @version 0.0.
|
|
138
|
+
* @version 0.0.3
|
|
136
139
|
* @since 0.0.1
|
|
137
140
|
* @author AMBROISE PARK Consulting
|
|
138
141
|
*/
|
|
@@ -144,7 +147,7 @@ export function useHasRole(role) {
|
|
|
144
147
|
/**
|
|
145
148
|
* Hook to get all auth state for debugging
|
|
146
149
|
*
|
|
147
|
-
* @version 0.0.
|
|
150
|
+
* @version 0.0.3
|
|
148
151
|
* @since 0.0.1
|
|
149
152
|
* @author AMBROISE PARK Consulting
|
|
150
153
|
*/
|
|
@@ -163,7 +166,7 @@ export function useAuthState() {
|
|
|
163
166
|
/**
|
|
164
167
|
* HOC to wrap components with auth protection
|
|
165
168
|
*
|
|
166
|
-
* @version 0.0.
|
|
169
|
+
* @version 0.0.3
|
|
167
170
|
* @since 0.0.1
|
|
168
171
|
* @author AMBROISE PARK Consulting
|
|
169
172
|
*/
|
|
@@ -174,7 +177,7 @@ export function withAuth(Component, auth) {
|
|
|
174
177
|
/**
|
|
175
178
|
* Utility to create auth configs
|
|
176
179
|
*
|
|
177
|
-
* @version 0.0.
|
|
180
|
+
* @version 0.0.3
|
|
178
181
|
* @since 0.0.1
|
|
179
182
|
* @author AMBROISE PARK Consulting
|
|
180
183
|
*/
|
package/dist/routing/Link.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type ReactNode, type ComponentType, type AnchorHTMLAttributes } from 'r
|
|
|
2
2
|
/**
|
|
3
3
|
* Link component props interface
|
|
4
4
|
*
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.3
|
|
6
6
|
* @since 0.0.1
|
|
7
7
|
* @author AMBROISE PARK Consulting
|
|
8
8
|
*/
|
|
@@ -21,7 +21,7 @@ export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
|
21
21
|
/**
|
|
22
22
|
* Link component
|
|
23
23
|
*
|
|
24
|
-
* @version 0.0.
|
|
24
|
+
* @version 0.0.3
|
|
25
25
|
* @since 0.0.1
|
|
26
26
|
* @author AMBROISE PARK Consulting
|
|
27
27
|
*/
|
package/dist/routing/Link.js
CHANGED
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
* @fileoverview Link component
|
|
6
6
|
* @description Platform-agnostic link component for navigation
|
|
7
7
|
*
|
|
8
|
-
* @version 0.0.
|
|
8
|
+
* @version 0.0.3
|
|
9
9
|
* @since 0.0.1
|
|
10
10
|
* @author AMBROISE PARK Consulting
|
|
11
11
|
*/
|
|
@@ -19,7 +19,7 @@ import { Icon } from '../components/common/icon';
|
|
|
19
19
|
/**
|
|
20
20
|
* Link component
|
|
21
21
|
*
|
|
22
|
-
* @version 0.0.
|
|
22
|
+
* @version 0.0.3
|
|
23
23
|
* @since 0.0.1
|
|
24
24
|
* @author AMBROISE PARK Consulting
|
|
25
25
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{useCallback as
|
|
1
|
+
"use client";import{useCallback as f}from"react";import{useRouter as h}from"next/navigation";import{isClient as x,useOverlayStore as S}from"@donotdev/core";function d(){let e=h(),t=S(r=>r.closeAll);return f((r,i)=>{if(r==="back")return t(),e.back();if(t(),i?.preserveScroll&&x()){let o=window.scrollY;i?.replace?e.replace(r):e.push(r),requestAnimationFrame(()=>{window.scrollTo({top:o,behavior:"auto"})});return}return i?.replace?e.replace(r):e.push(r)},[e,t])}function y(){let e=h();return f(()=>e.back(),[e])}function k(){let e=h();return f(()=>e.refresh(),[e])}function T(){let e=h();return f(t=>e.prefetch(t),[e])}import{usePathname as v,useSearchParams as b}from"next/navigation";function l(){let e=v(),t=b(),r=t.toString()?`?${t.toString()}`:"";return{pathname:e||"/",search:r,hash:"",state:null}}import{useParams as w}from"next/navigation";function C(){return w()}import{useSearchParams as I}from"next/navigation";function g(){return I()}import{usePathname as N}from"next/navigation";function G(e){let t=N(),r=e.replace(/:[^/]+/g,"([^/]+)").replace(/\*/g,".*"),i=new RegExp(`^${r}$`),o=t.match(i);if(!o)return null;let s=e.match(/:[^/]+/g)?.map(a=>a.slice(1))||[],n={};return s.forEach((a,c)=>{n[a]=o[c+1]||""}),{params:n,pathname:t,pattern:e}}import{useCallback as R}from"react";function $(){let e=g(),t=d(),r=l(),i=R((n,a)=>{let c=new URLSearchParams(e.toString());c.set(n,a);let m=c.toString(),P=`${r.pathname||"/"}${m?`?${m}`:""}`;t(P)},[e,t,r.pathname]),o=R(n=>{let a=new URLSearchParams(e.toString());a.delete(n);let c=a.toString(),u=`${r.pathname||"/"}${c?`?${c}`:""}`;t(u)},[e,t,r.pathname]),s=R(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:o,clearQueries:s}}import{useMemo as L}from"react";import{isClient as E,FEATURE_STATUS as Q}from"@donotdev/core";import{useAuthConfig as F}from"@donotdev/core";import{DEGRADED_AUTH_API as K}from"@donotdev/core";import*as O from"@donotdev/auth";var A=O?.useAuth;function U(e){return K[e]}function p(e){return A?A(e):U(e)}function M(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!E())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let o=l(),s=F(),n=p("user"),a=p("can"),c=p("status");return L(()=>{if(c===Q.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let u=i(n,c);return{shouldRedirect:u,redirectTo:u&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!a)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!a.navigate(t)){let u=null;return typeof t=="object"&&t.required&&!n?o.search.includes("code=")||o.search.includes("state=")||o.search.includes("error=")?u=`${s.authRoute}${o.search}`:u=s.authRoute:typeof t=="object"&&t.role?u=s.roleRoute:typeof t=="object"&&t.tier?u=s.tierRoute:u=s.roleRoute,{shouldRedirect:!0,redirectTo:r||u,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,c,n,a,i,r,o.search,s.authRoute,s.roleRoute,s.tierRoute])}export{y as useBack,l as useLocation,G as useMatch,d as useNavigate,C as useParams,T as usePrefetch,$ as useQueryParams,M as useRedirectGuard,k as useRefresh,g as useSearchParams};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{useCallback as m}from"react";import{useNavigate as A}from"react-router-dom";import{isClient as x,useOverlayStore as S}from"@donotdev/core";function p(){let e=A(),t=S(r=>r.closeAll);return m((r,i)=>r==="back"?(t(),e(-1)):(t(),i?.replace?e(r,{replace:!0}):e(r)),[e,t])}function y(){let e=A();return m(()=>e(-1),[e])}function
|
|
1
|
+
"use client";import{useCallback as m}from"react";import{useNavigate as A}from"react-router-dom";import{isClient as x,useOverlayStore as S}from"@donotdev/core";function p(){let e=A(),t=S(r=>r.closeAll);return m((r,i)=>r==="back"?(t(),e(-1)):(t(),i?.replace?e(r,{replace:!0}):e(r)),[e,t])}function y(){let e=A();return m(()=>e(-1),[e])}function v(){return m(()=>{x()&&window.location.reload()},[])}function k(){return m(e=>{},[])}import{useLocation as T}from"react-router-dom";function l(){return T()}import{useParams as C}from"react-router-dom";function I(){return C()}import{useSearchParams as b}from"react-router-dom";function d(){return b()[0]}import{useMatch as G}from"react-router-dom";function w(e){return G(e)}import{useCallback as R}from"react";function N(){let e=d(),t=p(),r=l(),i=R((n,u)=>{let a=new URLSearchParams(e.toString());a.set(n,u);let f=a.toString(),g=`${r.pathname||"/"}${f?`?${f}`:""}`;t(g)},[e,t,r.pathname]),c=R(n=>{let u=new URLSearchParams(e.toString());u.delete(n);let a=u.toString(),o=`${r.pathname||"/"}${a?`?${a}`:""}`;t(o)},[e,t,r.pathname]),s=R(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:c,clearQueries:s}}import{useMemo as U}from"react";import{isClient as $,FEATURE_STATUS as M}from"@donotdev/core";import{useAuthConfig as Q}from"@donotdev/core";import{DEGRADED_AUTH_API as K}from"@donotdev/core";import*as L from"@donotdev/auth";var P=L?.useAuth;function O(e){return K[e]}function h(e){return P?P(e):O(e)}function E(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!$())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let c=l(),s=Q(),n=h("user"),u=h("can"),a=h("status");return U(()=>{if(a===M.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let o=i(n,a);return{shouldRedirect:o,redirectTo:o&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!u)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!u.navigate(t)){let o=null;return typeof t=="object"&&t.required&&!n?c.search.includes("code=")||c.search.includes("state=")||c.search.includes("error=")?o=`${s.authRoute}${c.search}`:o=s.authRoute:typeof t=="object"&&t.role?o=s.roleRoute:typeof t=="object"&&t.tier?o=s.tierRoute:o=s.roleRoute,{shouldRedirect:!0,redirectTo:r||o,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,a,n,u,i,r,c.search,s.authRoute,s.roleRoute,s.tierRoute])}export{y as useBack,l as useLocation,w as useMatch,p as useNavigate,I as useParams,k as usePrefetch,N as useQueryParams,E as useRedirectGuard,v as useRefresh,d as useSearchParams};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { PageAuth } from '@donotdev/core';
|
|
1
|
+
import type { PageAuth, FeatureStatus } from '@donotdev/core';
|
|
2
2
|
export interface RedirectGuardOptions {
|
|
3
3
|
/** Auth configuration for this route */
|
|
4
4
|
auth?: PageAuth | false;
|
|
5
5
|
/** Custom redirect target (overrides auth config defaults) */
|
|
6
6
|
redirectTo?: string | null;
|
|
7
7
|
/** Custom condition function to check if redirect should happen */
|
|
8
|
-
condition?: (user: any,
|
|
8
|
+
condition?: (user: any, status: FeatureStatus) => boolean;
|
|
9
9
|
}
|
|
10
10
|
export interface RedirectGuardResult {
|
|
11
11
|
/** Whether redirect should happen */
|
|
@@ -16,47 +16,13 @@ export interface RedirectGuardResult {
|
|
|
16
16
|
isChecking: boolean;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
|
|
20
19
|
* Hook that checks if redirect should happen before render
|
|
21
|
-
|
|
22
20
|
*
|
|
23
|
-
|
|
24
21
|
* Prevents content flash by determining redirect state synchronously.
|
|
25
|
-
|
|
26
22
|
* Returns safe defaults on server (SSR-safe).
|
|
27
|
-
|
|
28
23
|
*
|
|
29
|
-
|
|
30
24
|
* @param options - Redirect guard configuration
|
|
31
|
-
|
|
32
25
|
* @returns Redirect guard state
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
* @example
|
|
37
|
-
|
|
38
|
-
* ```tsx
|
|
39
|
-
|
|
40
|
-
* // PricingPage: redirect authenticated users to /purchase
|
|
41
|
-
|
|
42
|
-
* const { shouldRedirect, redirectTo, isChecking } = useRedirectGuard({
|
|
43
|
-
|
|
44
|
-
* condition: (user) => !!user,
|
|
45
|
-
|
|
46
|
-
* redirectTo: '/purchase'
|
|
47
|
-
|
|
48
|
-
* });
|
|
49
|
-
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
* if (shouldRedirect || isChecking) {
|
|
53
|
-
|
|
54
|
-
* return <Loader />;
|
|
55
|
-
|
|
56
|
-
* }
|
|
57
|
-
|
|
58
|
-
* ```
|
|
59
|
-
|
|
60
26
|
*/
|
|
61
27
|
export declare function useRedirectGuard(options?: RedirectGuardOptions): RedirectGuardResult;
|
|
62
28
|
//# sourceMappingURL=useRedirectGuard.next.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRedirectGuard.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.next.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useRedirectGuard.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.next.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA4GrB"}
|
|
@@ -1,67 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
// packages/ui/src/routing/hooks/useRedirectGuard.next.ts
|
|
3
3
|
/**
|
|
4
|
-
|
|
5
|
-
* @
|
|
6
|
-
|
|
7
|
-
* @description Checks if redirect should happen before render, preventing content flash
|
|
8
|
-
|
|
4
|
+
* @fileoverview Next.js Redirect Guard Hook
|
|
5
|
+
* @description Determines redirect state before render. Prevents content flash.
|
|
9
6
|
*
|
|
10
|
-
|
|
11
|
-
* @version 0.0.1
|
|
12
|
-
|
|
7
|
+
* @version 0.0.3
|
|
13
8
|
* @since 0.0.1
|
|
14
|
-
|
|
15
9
|
* @author AMBROISE PARK Consulting
|
|
16
|
-
|
|
17
10
|
*/
|
|
18
11
|
import { useMemo } from 'react';
|
|
19
|
-
import { isClient } from '@donotdev/core';
|
|
12
|
+
import { isClient, FEATURE_STATUS } from '@donotdev/core';
|
|
20
13
|
import { useAuthConfig } from '@donotdev/core';
|
|
21
14
|
import { useLocation } from './useLocation.next';
|
|
22
15
|
import { useAuthSafe } from '../../utils/useAuthSafe';
|
|
23
16
|
/**
|
|
24
|
-
|
|
25
17
|
* Hook that checks if redirect should happen before render
|
|
26
|
-
|
|
27
18
|
*
|
|
28
|
-
|
|
29
19
|
* Prevents content flash by determining redirect state synchronously.
|
|
30
|
-
|
|
31
20
|
* Returns safe defaults on server (SSR-safe).
|
|
32
|
-
|
|
33
21
|
*
|
|
34
|
-
|
|
35
22
|
* @param options - Redirect guard configuration
|
|
36
|
-
|
|
37
23
|
* @returns Redirect guard state
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
|
|
41
|
-
* @example
|
|
42
|
-
|
|
43
|
-
* ```tsx
|
|
44
|
-
|
|
45
|
-
* // PricingPage: redirect authenticated users to /purchase
|
|
46
|
-
|
|
47
|
-
* const { shouldRedirect, redirectTo, isChecking } = useRedirectGuard({
|
|
48
|
-
|
|
49
|
-
* condition: (user) => !!user,
|
|
50
|
-
|
|
51
|
-
* redirectTo: '/purchase'
|
|
52
|
-
|
|
53
|
-
* });
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
|
|
57
|
-
* if (shouldRedirect || isChecking) {
|
|
58
|
-
|
|
59
|
-
* return <Loader />;
|
|
60
|
-
|
|
61
|
-
* }
|
|
62
|
-
|
|
63
|
-
* ```
|
|
64
|
-
|
|
65
24
|
*/
|
|
66
25
|
export function useRedirectGuard(options = {}) {
|
|
67
26
|
const { auth, redirectTo: customRedirectTo, condition } = options;
|
|
@@ -76,12 +35,12 @@ export function useRedirectGuard(options = {}) {
|
|
|
76
35
|
const location = useLocation();
|
|
77
36
|
const authConfig = useAuthConfig();
|
|
78
37
|
const user = useAuthSafe('user');
|
|
79
|
-
const
|
|
80
|
-
const
|
|
38
|
+
const can = useAuthSafe('can');
|
|
39
|
+
const status = useAuthSafe('status');
|
|
81
40
|
// Determine redirect state
|
|
82
41
|
const redirectState = useMemo(() => {
|
|
83
|
-
//
|
|
84
|
-
if (
|
|
42
|
+
// Only INITIALIZING = still checking. DEGRADED/ERROR/READY = auth resolved (proceed with current user)
|
|
43
|
+
if (status === FEATURE_STATUS.INITIALIZING) {
|
|
85
44
|
return {
|
|
86
45
|
shouldRedirect: false,
|
|
87
46
|
redirectTo: null,
|
|
@@ -90,7 +49,7 @@ export function useRedirectGuard(options = {}) {
|
|
|
90
49
|
}
|
|
91
50
|
// Custom condition provided
|
|
92
51
|
if (condition) {
|
|
93
|
-
const shouldRedirect = condition(user,
|
|
52
|
+
const shouldRedirect = condition(user, status);
|
|
94
53
|
return {
|
|
95
54
|
shouldRedirect,
|
|
96
55
|
redirectTo: shouldRedirect ? customRedirectTo || null : null,
|
|
@@ -99,15 +58,15 @@ export function useRedirectGuard(options = {}) {
|
|
|
99
58
|
}
|
|
100
59
|
// Use auth config to determine redirect
|
|
101
60
|
if (auth !== false && auth !== undefined) {
|
|
102
|
-
if (!
|
|
61
|
+
if (!can) {
|
|
103
62
|
return {
|
|
104
63
|
shouldRedirect: false,
|
|
105
64
|
redirectTo: null,
|
|
106
65
|
isChecking: false,
|
|
107
66
|
};
|
|
108
67
|
}
|
|
109
|
-
// Check if user can
|
|
110
|
-
if (!
|
|
68
|
+
// Check if user can navigate to this route
|
|
69
|
+
if (!can.navigate(auth)) {
|
|
111
70
|
let targetRoute = null;
|
|
112
71
|
// Authentication failure (not logged in)
|
|
113
72
|
if (typeof auth === 'object' && auth.required && !user) {
|
|
@@ -149,9 +108,9 @@ export function useRedirectGuard(options = {}) {
|
|
|
149
108
|
};
|
|
150
109
|
}, [
|
|
151
110
|
auth,
|
|
152
|
-
|
|
111
|
+
status,
|
|
153
112
|
user,
|
|
154
|
-
|
|
113
|
+
can,
|
|
155
114
|
condition,
|
|
156
115
|
customRedirectTo,
|
|
157
116
|
location.search,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { PageAuth } from '@donotdev/core';
|
|
1
|
+
import type { PageAuth, FeatureStatus } from '@donotdev/core';
|
|
2
2
|
export interface RedirectGuardOptions {
|
|
3
3
|
/** Auth configuration for this route */
|
|
4
4
|
auth?: PageAuth | false;
|
|
5
5
|
/** Custom redirect target (overrides auth config defaults) */
|
|
6
6
|
redirectTo?: string | null;
|
|
7
7
|
/** Custom condition function to check if redirect should happen */
|
|
8
|
-
condition?: (user: any,
|
|
8
|
+
condition?: (user: any, status: FeatureStatus) => boolean;
|
|
9
9
|
}
|
|
10
10
|
export interface RedirectGuardResult {
|
|
11
11
|
/** Whether redirect should happen */
|
|
@@ -16,47 +16,13 @@ export interface RedirectGuardResult {
|
|
|
16
16
|
isChecking: boolean;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
|
|
20
19
|
* Hook that checks if redirect should happen before render
|
|
21
|
-
|
|
22
20
|
*
|
|
23
|
-
|
|
24
21
|
* Prevents content flash by determining redirect state synchronously.
|
|
25
|
-
|
|
26
22
|
* Returns safe defaults on server (SSR-safe).
|
|
27
|
-
|
|
28
23
|
*
|
|
29
|
-
|
|
30
24
|
* @param options - Redirect guard configuration
|
|
31
|
-
|
|
32
25
|
* @returns Redirect guard state
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
* @example
|
|
37
|
-
|
|
38
|
-
* ```tsx
|
|
39
|
-
|
|
40
|
-
* // PricingPage: redirect authenticated users to /purchase
|
|
41
|
-
|
|
42
|
-
* const { shouldRedirect, redirectTo, isChecking } = useRedirectGuard({
|
|
43
|
-
|
|
44
|
-
* condition: (user) => !!user,
|
|
45
|
-
|
|
46
|
-
* redirectTo: '/purchase'
|
|
47
|
-
|
|
48
|
-
* });
|
|
49
|
-
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
* if (shouldRedirect || isChecking) {
|
|
53
|
-
|
|
54
|
-
* return <Loader />;
|
|
55
|
-
|
|
56
|
-
* }
|
|
57
|
-
|
|
58
|
-
* ```
|
|
59
|
-
|
|
60
26
|
*/
|
|
61
27
|
export declare function useRedirectGuard(options?: RedirectGuardOptions): RedirectGuardResult;
|
|
62
28
|
//# sourceMappingURL=useRedirectGuard.vite.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRedirectGuard.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.vite.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useRedirectGuard.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.vite.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA4GrB"}
|