@sudobility/building_blocks 0.0.136 → 0.0.138
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/__tests__/app-sitemap-page.test.d.ts +1 -0
- package/dist/__tests__/app-text-page.test.d.ts +1 -0
- package/dist/__tests__/appearance-settings.test.d.ts +1 -0
- package/dist/__tests__/global-settings-page.test.d.ts +1 -0
- package/dist/__tests__/login-page.test.d.ts +1 -0
- package/dist/components/breadcrumbs/app-breadcrumbs.d.ts +20 -0
- package/dist/components/footer/index.d.ts +1 -0
- package/dist/components/footer/shared.d.ts +15 -0
- package/dist/components/pages/index.d.ts +1 -1
- package/dist/components/pages/login-page.d.ts +66 -6
- package/dist/components/topbar/language-selector.d.ts +19 -0
- package/dist/firebase.js +6 -5
- package/dist/firebase.js.map +1 -1
- package/dist/index.js +287 -107
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -20,6 +20,26 @@ export interface AppBreadcrumbsProps extends VariantProps<typeof breadcrumbConta
|
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* AppBreadcrumbs - Self-contained breadcrumb navigation with share and "Talk to Founder" button.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <AppBreadcrumbs
|
|
27
|
+
* items={[
|
|
28
|
+
* { label: 'Home', href: '/' },
|
|
29
|
+
* { label: 'Products', href: '/products' },
|
|
30
|
+
* { label: 'Widget', current: true },
|
|
31
|
+
* ]}
|
|
32
|
+
* shareConfig={{
|
|
33
|
+
* title: 'Widget Page',
|
|
34
|
+
* description: 'Check out this widget',
|
|
35
|
+
* hashtags: ['widget'],
|
|
36
|
+
* }}
|
|
37
|
+
* talkToFounder={{
|
|
38
|
+
* meetingUrl: 'https://calendly.com/founder',
|
|
39
|
+
* }}
|
|
40
|
+
* variant="default"
|
|
41
|
+
* />
|
|
42
|
+
* ```
|
|
23
43
|
*/
|
|
24
44
|
export declare const AppBreadcrumbs: React.FC<AppBreadcrumbsProps>;
|
|
25
45
|
export default AppBreadcrumbs;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ComponentType } from 'react';
|
|
2
|
+
import type { LinkComponentProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Default link component that renders a plain anchor.
|
|
5
|
+
* Shared between AppFooter and AppFooterForHomePage.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DefaultLinkComponent: ComponentType<LinkComponentProps>;
|
|
8
|
+
/**
|
|
9
|
+
* Helper to get copyright year or range.
|
|
10
|
+
* Shared between AppFooter and AppFooterForHomePage.
|
|
11
|
+
*
|
|
12
|
+
* @param startYear - The starting year for the copyright range (default: 2025)
|
|
13
|
+
* @returns A string representing the year or year range
|
|
14
|
+
*/
|
|
15
|
+
export declare function getCopyrightYear(startYear?: number): string;
|
|
@@ -3,4 +3,4 @@ export type { AppSitemapPageProps, SitemapPageText, SitemapSection, SitemapLink,
|
|
|
3
3
|
export { AppTextPage } from './app-text-page';
|
|
4
4
|
export type { AppTextPageProps, TextPageContent, TextSection, TextSectionWithContent, TextSectionWithList, TextSectionWithSubsections, TextPageContact, TextPageContactInfo, GdprNotice, } from './app-text-page';
|
|
5
5
|
export { LoginPage } from './login-page';
|
|
6
|
-
export type { LoginPageProps, LoginPageText, AuthErrorInfo, } from './login-page';
|
|
6
|
+
export type { LoginPageProps, LoginPageText, LoginPageColorVariant, AuthErrorInfo, } from './login-page';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
import { type Auth } from 'firebase/auth';
|
|
3
2
|
/**
|
|
4
3
|
* Auth error info passed to onAuthError callback
|
|
5
4
|
*/
|
|
@@ -11,16 +10,40 @@ export interface AuthErrorInfo {
|
|
|
11
10
|
/** Whether this is a user-initiated action (like closing popup) vs actual error */
|
|
12
11
|
isUserAction: boolean;
|
|
13
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Color variant for the LoginPage.
|
|
15
|
+
* Each variant maps to a set of static, JIT-safe Tailwind classes.
|
|
16
|
+
*/
|
|
17
|
+
export type LoginPageColorVariant = 'primary' | 'blue' | 'indigo' | 'violet' | 'orange' | 'emerald' | 'rose';
|
|
14
18
|
/**
|
|
15
19
|
* Props for the LoginPage component
|
|
20
|
+
*
|
|
21
|
+
* LoginPage is a presentational component that accepts auth handler callbacks.
|
|
22
|
+
* The consumer must provide the actual auth logic (e.g., Firebase signIn).
|
|
16
23
|
*/
|
|
17
24
|
export interface LoginPageProps {
|
|
18
25
|
/** Application name displayed as the main title */
|
|
19
26
|
appName: string;
|
|
20
27
|
/** Optional logo element to display above the title */
|
|
21
28
|
logo?: ReactNode;
|
|
22
|
-
/**
|
|
23
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Handler for email/password sign-in.
|
|
31
|
+
* Called with email and password; should throw on error.
|
|
32
|
+
* The error object should have `code` and `message` properties for proper error display.
|
|
33
|
+
*/
|
|
34
|
+
onEmailSignIn: (email: string, password: string) => Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Handler for email/password sign-up (account creation).
|
|
37
|
+
* Called with email and password; should throw on error.
|
|
38
|
+
* Only used when `showSignUp` is true.
|
|
39
|
+
*/
|
|
40
|
+
onEmailSignUp?: (email: string, password: string) => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Handler for Google sign-in.
|
|
43
|
+
* Should perform the Google OAuth flow; should throw on error.
|
|
44
|
+
* Only used when `showGoogleSignIn` is true.
|
|
45
|
+
*/
|
|
46
|
+
onGoogleSignIn?: () => Promise<void>;
|
|
24
47
|
/** Callback fired on successful authentication */
|
|
25
48
|
onSuccess: () => void;
|
|
26
49
|
/** Callback fired on auth errors - if provided, errors won't be shown inline */
|
|
@@ -31,8 +54,11 @@ export interface LoginPageProps {
|
|
|
31
54
|
showSignUp?: boolean;
|
|
32
55
|
/** Custom className for the container */
|
|
33
56
|
className?: string;
|
|
34
|
-
/**
|
|
35
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Color variant for themed elements (default: 'primary').
|
|
59
|
+
* Uses static Tailwind classes to ensure JIT compatibility.
|
|
60
|
+
*/
|
|
61
|
+
colorVariant?: LoginPageColorVariant;
|
|
36
62
|
}
|
|
37
63
|
/**
|
|
38
64
|
* Text content for the LoginPage
|
|
@@ -51,4 +77,38 @@ export interface LoginPageText {
|
|
|
51
77
|
alreadyHaveAccount: string;
|
|
52
78
|
dontHaveAccount: string;
|
|
53
79
|
}
|
|
54
|
-
|
|
80
|
+
/**
|
|
81
|
+
* A reusable login page component with email/password and Google sign-in support.
|
|
82
|
+
*
|
|
83
|
+
* This component is fully decoupled from any auth provider. The consumer provides
|
|
84
|
+
* auth handler callbacks (`onEmailSignIn`, `onEmailSignUp`, `onGoogleSignIn`).
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```tsx
|
|
88
|
+
* import { LoginPage } from '@sudobility/building_blocks';
|
|
89
|
+
* import { signInWithEmailAndPassword, createUserWithEmailAndPassword, GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
|
|
90
|
+
* import { getFirebaseAuth } from '@sudobility/auth_lib';
|
|
91
|
+
*
|
|
92
|
+
* function MyLoginPage() {
|
|
93
|
+
* const navigate = useNavigate();
|
|
94
|
+
* const auth = getFirebaseAuth();
|
|
95
|
+
*
|
|
96
|
+
* return (
|
|
97
|
+
* <LoginPage
|
|
98
|
+
* appName="My App"
|
|
99
|
+
* onEmailSignIn={async (email, password) => {
|
|
100
|
+
* await signInWithEmailAndPassword(auth, email, password);
|
|
101
|
+
* }}
|
|
102
|
+
* onEmailSignUp={async (email, password) => {
|
|
103
|
+
* await createUserWithEmailAndPassword(auth, email, password);
|
|
104
|
+
* }}
|
|
105
|
+
* onGoogleSignIn={async () => {
|
|
106
|
+
* await signInWithPopup(auth, new GoogleAuthProvider());
|
|
107
|
+
* }}
|
|
108
|
+
* onSuccess={() => navigate('/')}
|
|
109
|
+
* />
|
|
110
|
+
* );
|
|
111
|
+
* }
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function LoginPage({ appName, logo, onEmailSignIn, onEmailSignUp, onGoogleSignIn, onSuccess, onAuthError, showGoogleSignIn, showSignUp, className, colorVariant, }: LoginPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -19,6 +19,25 @@ export interface LanguageSelectorProps {
|
|
|
19
19
|
/**
|
|
20
20
|
* LanguageSelector component with dropdown for switching languages.
|
|
21
21
|
* Uses default 16 languages if none provided.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* // Compact variant for topbar
|
|
26
|
+
* <LanguageSelector
|
|
27
|
+
* currentLanguage="en"
|
|
28
|
+
* onLanguageChange={(code) => i18n.changeLanguage(code)}
|
|
29
|
+
* variant="compact"
|
|
30
|
+
* />
|
|
31
|
+
*
|
|
32
|
+
* // Full variant for settings pages
|
|
33
|
+
* <LanguageSelector
|
|
34
|
+
* currentLanguage="en"
|
|
35
|
+
* onLanguageChange={(code) => i18n.changeLanguage(code)}
|
|
36
|
+
* variant="full"
|
|
37
|
+
* label="Language"
|
|
38
|
+
* helperText="Select your preferred language"
|
|
39
|
+
* />
|
|
40
|
+
* ```
|
|
22
41
|
*/
|
|
23
42
|
export declare const LanguageSelector: React.FC<LanguageSelectorProps>;
|
|
24
43
|
export default LanguageSelector;
|
package/dist/firebase.js
CHANGED
|
@@ -2,14 +2,13 @@ import { jsx, Fragment } from "react/jsx-runtime";
|
|
|
2
2
|
import { S as SudobilityApp, a as SafeSubscriptionContext, b as STUB_SUBSCRIPTION_VALUE } from "./SafeSubscriptionContext-CNuEKeqJ.js";
|
|
3
3
|
import { useAuthStatus, AuthProvider } from "@sudobility/auth-components";
|
|
4
4
|
import { getFirebaseAuth, FirebaseAuthNetworkService, initializeFirebaseAuth, getFirebaseErrorMessage } from "@sudobility/auth_lib";
|
|
5
|
-
import { createContext, useState, useEffect, useCallback, useRef, useMemo, useContext,
|
|
5
|
+
import { createContext, useState, useEffect, useCallback, useRef, useMemo, useContext, Suspense, lazy } from "react";
|
|
6
6
|
import { onIdTokenChanged } from "firebase/auth";
|
|
7
7
|
import { getInfoService } from "@sudobility/di/info";
|
|
8
8
|
import { InfoType } from "@sudobility/types";
|
|
9
9
|
import { EntityClient, CurrentEntityProvider, useCurrentEntity } from "@sudobility/entity_client";
|
|
10
10
|
import { SubscriptionProvider, useSubscriptionContext } from "@sudobility/subscription-components";
|
|
11
11
|
import { setRevenueCatUser, refreshSubscription, clearRevenueCatUser } from "@sudobility/subscription_lib";
|
|
12
|
-
import "@sudobility/components";
|
|
13
12
|
const ApiContext = createContext(null);
|
|
14
13
|
function useApi() {
|
|
15
14
|
const context = useContext(ApiContext);
|
|
@@ -358,9 +357,11 @@ function SudobilityAppWithFirebaseAuthAndEntities({
|
|
|
358
357
|
if (entityClient) {
|
|
359
358
|
return /* @__PURE__ */ jsx(DefaultAuthAwareEntityProvider, { entityClient, children: content });
|
|
360
359
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
360
|
+
if (process.env.NODE_ENV !== "production") {
|
|
361
|
+
console.warn(
|
|
362
|
+
"[SudobilityAppWithFirebaseAuthAndEntities] No entityApiUrl or AuthAwareEntityProvider provided. Entity features are disabled. Provide apiUrl or AuthAwareEntityProvider to enable them."
|
|
363
|
+
);
|
|
364
|
+
}
|
|
364
365
|
return /* @__PURE__ */ jsx(Fragment, { children: content });
|
|
365
366
|
};
|
|
366
367
|
return /* @__PURE__ */ jsx(
|
package/dist/firebase.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase.js","sources":["../src/components/api/ApiContext.tsx","../src/components/app/SudobilityAppWithFirebaseAuth.tsx","../src/components/subscription/LazySubscriptionProvider.tsx","../src/components/subscription/SubscriptionProviderWrapper.tsx","../src/components/app/SudobilityAppWithFirebaseAuthAndEntities.tsx"],"sourcesContent":["/**\n * API Context and Provider\n *\n * Provides network client, auth token, and API configuration to the app.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n useMemo,\n useCallback,\n useRef,\n type ReactNode,\n} from 'react';\nimport { onIdTokenChanged } from 'firebase/auth';\nimport { getInfoService } from '@sudobility/di/info';\nimport { InfoType } from '@sudobility/types';\nimport type { NetworkClient } from '@sudobility/types';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport {\n getFirebaseAuth,\n FirebaseAuthNetworkService,\n} from '@sudobility/auth_lib';\n\n/**\n * API context value provided to consumers\n */\nexport interface ApiContextValue {\n /** Network client for making API requests */\n networkClient: NetworkClient;\n /** Base URL for API requests */\n baseUrl: string;\n /** Current user ID (Firebase UID) */\n userId: string | null;\n /** Firebase ID token for authenticated requests */\n token: string | null;\n /** Whether API is ready (user authenticated and token available) */\n isReady: boolean;\n /** Whether auth/token is still loading */\n isLoading: boolean;\n /** Force refresh the ID token */\n refreshToken: () => Promise<string | null>;\n /** Whether running in test/sandbox mode */\n testMode: boolean;\n}\n\nconst ApiContext = createContext<ApiContextValue | null>(null);\n\n/**\n * Hook to access API context\n * @throws Error if used outside of ApiProvider\n */\nexport function useApi(): ApiContextValue {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within an ApiProvider');\n }\n return context;\n}\n\n/**\n * Hook to safely access API context (returns null if not available)\n */\nexport function useApiSafe(): ApiContextValue | null {\n return useContext(ApiContext);\n}\n\ninterface ApiProviderProps {\n children: ReactNode;\n /**\n * Base URL for API requests (optional).\n * Defaults to VITE_API_URL env var.\n */\n baseUrl?: string;\n /**\n * Whether running in test/sandbox mode (optional).\n * Defaults to false.\n */\n testMode?: boolean;\n}\n\n/**\n * API Provider\n *\n * Manages Firebase ID token and provides API configuration.\n * Uses VITE_API_URL env var for baseUrl by default.\n */\nexport function ApiProvider({\n children,\n baseUrl: baseUrlProp,\n testMode = false,\n}: ApiProviderProps) {\n const { user, loading: authLoading } = useAuthStatus();\n const [token, setToken] = useState<string | null>(null);\n const [tokenLoading, setTokenLoading] = useState(false);\n const auth = getFirebaseAuth();\n\n const baseUrl = baseUrlProp || import.meta.env.VITE_API_URL || '';\n const userId = user?.uid ?? null;\n\n // Listen for token changes - Firebase automatically refreshes tokens\n // onIdTokenChanged fires on: sign-in, sign-out, and token refresh\n useEffect(() => {\n if (!auth) {\n setToken(null);\n setTokenLoading(false);\n return;\n }\n\n setTokenLoading(true);\n\n const unsubscribe = onIdTokenChanged(auth, async firebaseUser => {\n if (!firebaseUser) {\n setToken(null);\n setTokenLoading(false);\n return;\n }\n\n try {\n const idToken = await firebaseUser.getIdToken();\n setToken(idToken);\n } catch {\n try {\n getInfoService().show(\n 'Authentication Error',\n 'Failed to get ID token',\n InfoType.ERROR,\n 5000\n );\n } catch {\n console.error('[ApiProvider] Failed to get ID token');\n }\n setToken(null);\n } finally {\n setTokenLoading(false);\n }\n });\n\n return () => {\n unsubscribe();\n };\n }, [auth]);\n\n // Refresh token function for when token expires\n const refreshToken = useCallback(async (): Promise<string | null> => {\n const currentUser = auth?.currentUser;\n if (!currentUser) return null;\n try {\n const newToken = await currentUser.getIdToken(true); // Force refresh\n setToken(newToken);\n return newToken;\n } catch {\n try {\n getInfoService().show(\n 'Authentication Error',\n 'Failed to refresh ID token',\n InfoType.ERROR,\n 5000\n );\n } catch {\n console.error('[ApiProvider] Failed to refresh ID token');\n }\n setToken(null);\n return null;\n }\n }, [auth]);\n\n // Create FirebaseAuthNetworkService instance once\n // This handles automatic token refresh on 401 responses\n // Note: FirebaseAuthNetworkService doesn't perfectly implement NetworkClient interface\n // (different request signature), but it's compatible at runtime for our use cases.\n // Using type assertion as a workaround for the interface mismatch between\n // @sudobility/auth_lib and @sudobility/types.\n const networkClientRef = useRef<NetworkClient | null>(null);\n if (!networkClientRef.current) {\n const firebaseNetworkService = new FirebaseAuthNetworkService({\n onTokenRefreshFailed: error => {\n console.error('[ApiProvider] Token refresh failed:', error);\n try {\n getInfoService().show(\n 'Authentication Error',\n 'Session expired. Please sign in again.',\n InfoType.ERROR,\n 5000\n );\n } catch {\n // InfoService not available\n }\n },\n });\n // Type assertion needed due to interface mismatch between FirebaseAuthNetworkService\n // and NetworkClient (auth_lib uses RequestInit/Response while types uses NetworkRequestOptions/NetworkResponse)\n networkClientRef.current =\n firebaseNetworkService as unknown as NetworkClient;\n }\n\n const value = useMemo<ApiContextValue>(\n () => ({\n networkClient: networkClientRef.current!,\n baseUrl,\n userId,\n token,\n isReady: !!userId && !!token,\n isLoading: authLoading || tokenLoading,\n refreshToken,\n testMode,\n }),\n [baseUrl, userId, token, authLoading, tokenLoading, refreshToken, testMode]\n );\n\n return <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;\n}\n\nexport { ApiContext };\n","/**\n * SudobilityAppWithFirebaseAuth - App wrapper with Firebase authentication\n *\n * Extends SudobilityApp with:\n * - Firebase AuthProviderWrapper for authentication (built-in default)\n * - ApiProvider for network/token management (built-in default)\n */\nimport { ComponentType, ReactNode } from 'react';\nimport { SudobilityApp, SudobilityAppProps } from './SudobilityApp';\nimport { AuthProvider } from '@sudobility/auth-components';\nimport {\n getFirebaseAuth,\n getFirebaseErrorMessage,\n initializeFirebaseAuth,\n} from '@sudobility/auth_lib';\nimport { ApiProvider } from '../api';\n\n/** Auth text labels for UI - all fields required for localization */\nexport interface AuthTexts {\n signInTitle: string;\n signInWithEmail: string;\n createAccount: string;\n resetPassword: string;\n signIn: string;\n signUp: string;\n logout: string;\n login: string;\n continueWithGoogle: string;\n continueWithApple: string;\n continueWithEmail: string;\n sendResetLink: string;\n backToSignIn: string;\n close: string;\n email: string;\n password: string;\n confirmPassword: string;\n displayName: string;\n emailPlaceholder: string;\n passwordPlaceholder: string;\n confirmPasswordPlaceholder: string;\n displayNamePlaceholder: string;\n forgotPassword: string;\n noAccount: string;\n haveAccount: string;\n or: string;\n resetEmailSent: string;\n resetEmailSentDesc: string;\n passwordMismatch: string;\n passwordTooShort: string;\n loading: string;\n}\n\n/** Auth error messages for Firebase error codes */\nexport interface AuthErrorTexts {\n 'auth/user-not-found': string;\n 'auth/wrong-password': string;\n 'auth/invalid-email': string;\n 'auth/invalid-credential': string;\n 'auth/email-already-in-use': string;\n 'auth/weak-password': string;\n 'auth/too-many-requests': string;\n 'auth/network-request-failed': string;\n 'auth/popup-closed-by-user': string;\n 'auth/popup-blocked': string;\n 'auth/account-exists-with-different-credential': string;\n 'auth/operation-not-allowed': string;\n default: string;\n}\n\nexport interface SudobilityAppWithFirebaseAuthProps extends Omit<\n SudobilityAppProps,\n 'AppProviders' | 'RouterWrapper'\n> {\n /**\n * Custom Firebase auth provider wrapper component (optional).\n * If provided, authTexts and authErrorTexts are ignored.\n */\n AuthProviderWrapper?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Localized auth UI texts (required if not using custom AuthProviderWrapper).\n */\n authTexts?: AuthTexts;\n\n /**\n * Localized auth error messages (required if not using custom AuthProviderWrapper).\n */\n authErrorTexts?: AuthErrorTexts;\n\n /**\n * Auth providers to enable (optional).\n * Defaults to [\"google\", \"email\"].\n */\n authProviders?: ('google' | 'email' | 'apple')[];\n\n /**\n * Whether to enable anonymous auth (optional).\n * Defaults to false.\n */\n enableAnonymousAuth?: boolean;\n\n /**\n * Custom ApiProvider component (optional).\n * Defaults to built-in ApiProvider that manages Firebase ID token.\n * Set to false to disable the built-in ApiProvider.\n */\n ApiProvider?: ComponentType<{ children: ReactNode }> | false;\n\n /**\n * Additional providers to wrap around the router content.\n * These are rendered inside ApiProvider but outside BrowserRouter.\n */\n AppProviders?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Custom router wrapper component (optional).\n * Defaults to BrowserRouter. Pass a fragment wrapper `({ children }) => <>{children}</>`\n * to skip the router entirely (useful when nesting inside an existing router).\n */\n RouterWrapper?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Whether running in test/sandbox mode (optional).\n * Passed to ApiProvider. Defaults to false.\n */\n testMode?: boolean;\n\n /**\n * Base URL for API requests (optional).\n * Passed to ApiProvider. Defaults to VITE_API_URL env var.\n */\n baseUrl?: string;\n}\n\n/**\n * Default AuthProviderWrapper using Firebase\n */\nfunction DefaultAuthProviderWrapper({\n children,\n providers,\n enableAnonymous,\n texts,\n errorTexts,\n}: {\n children: ReactNode;\n providers: ('google' | 'email' | 'apple')[];\n enableAnonymous: boolean;\n texts: AuthTexts;\n errorTexts: AuthErrorTexts;\n}) {\n // Initialize Firebase Auth (idempotent - safe to call multiple times)\n initializeFirebaseAuth();\n\n const auth = getFirebaseAuth();\n\n // If Firebase is not configured, render children without auth\n if (!auth) {\n console.warn(\n '[SudobilityAppWithFirebaseAuth] No auth instance - Firebase not configured'\n );\n return <>{children}</>;\n }\n\n return (\n <AuthProvider\n firebaseConfig={{ type: 'instance', auth: auth }}\n providerConfig={{\n providers,\n enableAnonymous,\n }}\n texts={texts}\n errorTexts={errorTexts}\n resolveErrorMessage={getFirebaseErrorMessage}\n >\n {children}\n </AuthProvider>\n );\n}\n\n/**\n * SudobilityAppWithFirebaseAuth - App wrapper with Firebase authentication\n *\n * @example\n * ```tsx\n * // With custom AuthProviderWrapper (recommended for i18n)\n * import { SudobilityAppWithFirebaseAuth } from '@sudobility/building_blocks';\n *\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuth\n * AuthProviderWrapper={MyAuthProviderWrapper}\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuth>\n * );\n * }\n *\n * // With localized texts\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuth\n * authTexts={localizedAuthTexts}\n * authErrorTexts={localizedAuthErrorTexts}\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuth>\n * );\n * }\n * ```\n */\nexport function SudobilityAppWithFirebaseAuth({\n AuthProviderWrapper: AuthProviderWrapperProp,\n authTexts,\n authErrorTexts,\n authProviders = ['google', 'email'],\n enableAnonymousAuth = false,\n ApiProvider: ApiProviderProp,\n AppProviders,\n RouterWrapper,\n testMode = false,\n baseUrl,\n ...baseProps\n}: SudobilityAppWithFirebaseAuthProps) {\n // Create a combined providers component that includes auth and api\n const CombinedProviders: ComponentType<{ children: ReactNode }> = ({\n children,\n }) => {\n let content = children;\n\n // Wrap with AppProviders if provided\n if (AppProviders) {\n content = <AppProviders>{content}</AppProviders>;\n }\n\n // Wrap with ApiProvider (custom, default, or disabled)\n if (ApiProviderProp === false) {\n // Explicitly disabled\n } else if (ApiProviderProp) {\n content = <ApiProviderProp>{content}</ApiProviderProp>;\n } else {\n // Default ApiProvider\n content = (\n <ApiProvider baseUrl={baseUrl} testMode={testMode}>\n {content}\n </ApiProvider>\n );\n }\n\n // Wrap with AuthProviderWrapper (custom or default)\n if (AuthProviderWrapperProp) {\n return <AuthProviderWrapperProp>{content}</AuthProviderWrapperProp>;\n }\n\n // Require texts when using default AuthProviderWrapper\n if (!authTexts || !authErrorTexts) {\n throw new Error(\n '[SudobilityAppWithFirebaseAuth] authTexts and authErrorTexts are required when not using a custom AuthProviderWrapper'\n );\n }\n\n return (\n <DefaultAuthProviderWrapper\n providers={authProviders}\n enableAnonymous={enableAnonymousAuth}\n texts={authTexts}\n errorTexts={authErrorTexts}\n >\n {content}\n </DefaultAuthProviderWrapper>\n );\n };\n\n return (\n <SudobilityApp\n {...baseProps}\n AppProviders={CombinedProviders}\n RouterWrapper={RouterWrapper}\n />\n );\n}\n\nexport default SudobilityAppWithFirebaseAuth;\n","/**\n * Lazy Subscription Provider\n *\n * Defers loading of RevenueCat SDK (~600KB) until user is authenticated.\n * For unauthenticated users, provides a stub context.\n */\n\nimport { type ReactNode, Suspense, lazy, useMemo } from 'react';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport {\n SafeSubscriptionContext,\n STUB_SUBSCRIPTION_VALUE,\n} from './SafeSubscriptionContext';\n\n// Lazy load the actual subscription provider\nconst SubscriptionProviderWrapper = lazy(\n () => import('./SubscriptionProviderWrapper')\n);\n\nfunction StubSubscriptionProvider({ children }: { children: ReactNode }) {\n return (\n <SafeSubscriptionContext.Provider value={STUB_SUBSCRIPTION_VALUE}>\n {children}\n </SafeSubscriptionContext.Provider>\n );\n}\n\ninterface LazySubscriptionProviderProps {\n children: ReactNode;\n /** Entity ID to use as RevenueCat subscriber */\n entityId?: string;\n /** RevenueCat API key */\n apiKey: string;\n}\n\n/**\n * Lazy wrapper for SubscriptionProvider that only loads RevenueCat SDK\n * when the user is authenticated. This saves ~600KB on initial load.\n * For unauthenticated users, provides a stub context so hooks don't throw.\n */\nexport function LazySubscriptionProvider({\n children,\n entityId,\n apiKey,\n}: LazySubscriptionProviderProps) {\n const { user } = useAuthStatus();\n\n const isAuthenticated = useMemo(() => {\n return !!user && !user.isAnonymous;\n }, [user]);\n\n if (!isAuthenticated) {\n return <StubSubscriptionProvider>{children}</StubSubscriptionProvider>;\n }\n\n return (\n <Suspense\n fallback={<StubSubscriptionProvider>{children}</StubSubscriptionProvider>}\n >\n <SubscriptionProviderWrapper entityId={entityId} apiKey={apiKey}>\n {children}\n </SubscriptionProviderWrapper>\n </Suspense>\n );\n}\n\nexport default LazySubscriptionProvider;\n","/**\n * Subscription Provider Wrapper\n *\n * Integrates subscription-components with auth and sets up RevenueCat user.\n */\n\nimport { type ReactNode, useEffect, useRef } from 'react';\nimport {\n SubscriptionProvider,\n useSubscriptionContext,\n} from '@sudobility/subscription-components';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport { getInfoService } from '@sudobility/di/info';\nimport { InfoType } from '@sudobility/types';\nimport {\n setRevenueCatUser,\n clearRevenueCatUser,\n refreshSubscription,\n} from '@sudobility/subscription_lib';\nimport { SafeSubscriptionContext } from './SafeSubscriptionContext';\n\ninterface SubscriptionProviderWrapperProps {\n children: ReactNode;\n entityId?: string;\n apiKey: string;\n}\n\nconst handleSubscriptionError = (error: Error) => {\n try {\n getInfoService().show(\n 'Subscription Error',\n error.message,\n InfoType.ERROR,\n 5000\n );\n } catch {\n // InfoService not available - log to console\n console.error('[Subscription]', error.message);\n }\n};\n\n/**\n * Bridge that provides context and configures RevenueCat user.\n */\nfunction SubscriptionBridge({\n children,\n entityId,\n}: {\n children: ReactNode;\n entityId?: string;\n}) {\n const { user } = useAuthStatus();\n const context = useSubscriptionContext();\n const entityIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n const shouldSetUser = user && !user.isAnonymous && entityId;\n\n if (shouldSetUser && entityId !== entityIdRef.current) {\n entityIdRef.current = entityId;\n // Set user for both subscription-components and subscription_lib\n context.initialize(entityId, user.email || undefined);\n setRevenueCatUser(entityId, user.email || undefined).then(() => {\n // Refresh subscription_lib data after user is set\n refreshSubscription();\n });\n } else if (!shouldSetUser && entityIdRef.current) {\n entityIdRef.current = null;\n clearRevenueCatUser();\n }\n }, [user, entityId, context]);\n\n return (\n <SafeSubscriptionContext.Provider value={context}>\n {children}\n </SafeSubscriptionContext.Provider>\n );\n}\n\nexport function SubscriptionProviderWrapper({\n children,\n entityId,\n apiKey,\n}: SubscriptionProviderWrapperProps) {\n const { user } = useAuthStatus();\n\n return (\n <SubscriptionProvider\n apiKey={apiKey}\n userEmail={user?.email || undefined}\n onError={handleSubscriptionError}\n >\n <SubscriptionBridge entityId={entityId}>{children}</SubscriptionBridge>\n </SubscriptionProvider>\n );\n}\n\nexport default SubscriptionProviderWrapper;\n","/**\n * SudobilityAppWithFirebaseAuthAndEntities - App wrapper with Firebase auth and entity support\n *\n * Extends SudobilityAppWithFirebaseAuth with:\n * - AuthAwareEntityProvider that connects entity context to auth state (built-in default)\n * - EntityAwareSubscriptionProvider that connects subscription to entity (built-in default)\n */\nimport { ComponentType, ReactNode, useMemo } from 'react';\nimport {\n SudobilityAppWithFirebaseAuth,\n SudobilityAppWithFirebaseAuthProps,\n} from './SudobilityAppWithFirebaseAuth';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport {\n CurrentEntityProvider,\n EntityClient,\n useCurrentEntity,\n} from '@sudobility/entity_client';\nimport { LazySubscriptionProvider } from '../subscription';\nimport { useApiSafe } from '../api';\n\nexport interface SudobilityAppWithFirebaseAuthAndEntitiesProps extends Omit<\n SudobilityAppWithFirebaseAuthProps,\n 'AppProviders' | 'RouterWrapper'\n> {\n /**\n * Base URL for the API (optional).\n * Defaults to VITE_API_URL env var.\n * Used for both ApiProvider and EntityClient.\n *\n * @example \"https://api.myapp.com\"\n */\n apiUrl?: string;\n\n /**\n * @deprecated Use apiUrl instead. Will be removed in future version.\n */\n entityApiUrl?: string;\n\n /**\n * RevenueCat API key for production subscriptions (optional).\n * If not provided, reads from VITE_REVENUECAT_API_KEY env var.\n * If neither is available, subscription features are disabled.\n */\n revenueCatApiKey?: string;\n\n /**\n * RevenueCat API key for sandbox/test subscriptions (optional).\n * Used when testMode is true.\n * If not provided, reads from VITE_REVENUECAT_API_KEY_SANDBOX env var.\n */\n revenueCatApiKeySandbox?: string;\n\n /**\n * Custom AuthAwareEntityProvider component (optional).\n * Defaults to built-in provider if entityApiUrl is provided.\n */\n AuthAwareEntityProvider?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Custom EntityAwareSubscriptionProvider component (optional).\n * Defaults to built-in provider that uses LazySubscriptionProvider.\n * Set to false to disable subscription features entirely.\n */\n EntityAwareSubscriptionProvider?:\n | ComponentType<{ children: ReactNode }>\n | false;\n\n /**\n * Additional providers to wrap around the router content.\n * These are rendered inside EntityAwareSubscriptionProvider but outside BrowserRouter.\n * Use this for app-specific providers like ApiProvider.\n */\n AppProviders?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Custom router wrapper component (optional).\n * Defaults to BrowserRouter. Pass a fragment wrapper `({ children }) => <>{children}</>`\n * to skip the router entirely (useful when nesting inside an existing router).\n */\n RouterWrapper?: ComponentType<{ children: ReactNode }>;\n}\n\n/**\n * Default AuthAwareEntityProvider using CurrentEntityProvider\n */\nfunction DefaultAuthAwareEntityProvider({\n children,\n entityClient,\n}: {\n children: ReactNode;\n entityClient: EntityClient;\n}) {\n const { user } = useAuthStatus();\n const authUser = useMemo(\n () => (user ? { uid: user.uid, email: user.email } : null),\n [user]\n );\n\n return (\n <CurrentEntityProvider client={entityClient} user={authUser}>\n {children}\n </CurrentEntityProvider>\n );\n}\n\n/**\n * Default EntityAwareSubscriptionProvider using LazySubscriptionProvider\n */\nfunction DefaultEntityAwareSubscriptionProvider({\n children,\n apiKey,\n}: {\n children: ReactNode;\n apiKey: string;\n}) {\n const { currentEntityId } = useCurrentEntity();\n return (\n <LazySubscriptionProvider\n entityId={currentEntityId ?? undefined}\n apiKey={apiKey}\n >\n {children}\n </LazySubscriptionProvider>\n );\n}\n\n/**\n * SudobilityAppWithFirebaseAuthAndEntities - Full-featured app wrapper\n *\n * @example\n * ```tsx\n * // Minimal usage with entityApiUrl - uses all defaults\n * import { SudobilityAppWithFirebaseAuthAndEntities } from '@sudobility/building_blocks';\n * import i18n from './i18n';\n *\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuthAndEntities\n * i18n={i18n}\n * entityApiUrl=\"https://api.myapp.com/api/v1\"\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuthAndEntities>\n * );\n * }\n *\n * // With custom providers\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuthAndEntities\n * i18n={i18n}\n * AuthAwareEntityProvider={MyEntityProvider}\n * EntityAwareSubscriptionProvider={MySubscriptionProvider}\n * AppProviders={ApiProvider}\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuthAndEntities>\n * );\n * }\n * ```\n */\nexport function SudobilityAppWithFirebaseAuthAndEntities({\n apiUrl,\n entityApiUrl, // deprecated, use apiUrl\n revenueCatApiKey,\n revenueCatApiKeySandbox,\n AuthAwareEntityProvider: AuthAwareEntityProviderProp,\n EntityAwareSubscriptionProvider: EntityAwareSubscriptionProviderProp,\n AppProviders,\n RouterWrapper,\n testMode = false,\n ...baseProps\n}: SudobilityAppWithFirebaseAuthAndEntitiesProps) {\n // Get API URL from prop or env var\n // Support deprecated entityApiUrl for backwards compatibility\n const baseApiUrl = apiUrl || import.meta.env.VITE_API_URL || '';\n const entityUrl = entityApiUrl || (baseApiUrl ? `${baseApiUrl}/api/v1` : '');\n\n // Get RevenueCat API key from prop or env var, selecting based on testMode\n const rcApiKeyProd =\n revenueCatApiKey || import.meta.env.VITE_REVENUECAT_API_KEY || '';\n const rcApiKeySandbox =\n revenueCatApiKeySandbox ||\n import.meta.env.VITE_REVENUECAT_API_KEY_SANDBOX ||\n '';\n const rcApiKey = testMode ? rcApiKeySandbox : rcApiKeyProd;\n\n // Create a combined providers component that includes entity support\n // This renders inside ApiProvider, so useApiSafe() is available\n const EntityProviders: ComponentType<{ children: ReactNode }> = ({\n children,\n }) => {\n const api = useApiSafe();\n const entityClient = useMemo(\n () =>\n entityUrl && api?.networkClient\n ? new EntityClient({\n baseUrl: entityUrl,\n networkClient: api.networkClient,\n })\n : null,\n [api?.networkClient]\n );\n\n let content = children;\n\n // Wrap with AppProviders if provided\n if (AppProviders) {\n content = <AppProviders>{content}</AppProviders>;\n }\n\n // Wrap with EntityAwareSubscriptionProvider (custom, default, or disabled)\n if (EntityAwareSubscriptionProviderProp === false) {\n // Explicitly disabled - skip subscription provider\n } else if (EntityAwareSubscriptionProviderProp) {\n // Custom provider\n content = (\n <EntityAwareSubscriptionProviderProp>\n {content}\n </EntityAwareSubscriptionProviderProp>\n );\n } else if (rcApiKey) {\n // Default provider with API key\n content = (\n <DefaultEntityAwareSubscriptionProvider apiKey={rcApiKey}>\n {content}\n </DefaultEntityAwareSubscriptionProvider>\n );\n }\n // If no API key and no custom provider, subscription features are silently disabled\n\n // Wrap with AuthAwareEntityProvider (custom or default)\n if (AuthAwareEntityProviderProp) {\n return (\n <AuthAwareEntityProviderProp>{content}</AuthAwareEntityProviderProp>\n );\n }\n\n // Use default if entityClient is available\n if (entityClient) {\n return (\n <DefaultAuthAwareEntityProvider entityClient={entityClient}>\n {content}\n </DefaultAuthAwareEntityProvider>\n );\n }\n\n // No entity support if no entityApiUrl or custom provider\n console.warn(\n '[SudobilityAppWithFirebaseAuthAndEntities] No entityApiUrl or AuthAwareEntityProvider provided - entity features disabled'\n );\n return <>{content}</>;\n };\n\n return (\n <SudobilityAppWithFirebaseAuth\n {...baseProps}\n baseUrl={baseApiUrl}\n testMode={testMode}\n AppProviders={EntityProviders}\n RouterWrapper={RouterWrapper}\n />\n );\n}\n\nexport default SudobilityAppWithFirebaseAuthAndEntities;\n"],"names":["SubscriptionProviderWrapper"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"firebase.js","sources":["../src/components/api/ApiContext.tsx","../src/components/app/SudobilityAppWithFirebaseAuth.tsx","../src/components/subscription/LazySubscriptionProvider.tsx","../src/components/subscription/SubscriptionProviderWrapper.tsx","../src/components/app/SudobilityAppWithFirebaseAuthAndEntities.tsx"],"sourcesContent":["/**\n * API Context and Provider\n *\n * Provides network client, auth token, and API configuration to the app.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n useMemo,\n useCallback,\n useRef,\n type ReactNode,\n} from 'react';\nimport { onIdTokenChanged } from 'firebase/auth';\nimport { getInfoService } from '@sudobility/di/info';\nimport { InfoType } from '@sudobility/types';\nimport type { NetworkClient } from '@sudobility/types';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport {\n getFirebaseAuth,\n FirebaseAuthNetworkService,\n} from '@sudobility/auth_lib';\n\n/**\n * API context value provided to consumers\n */\nexport interface ApiContextValue {\n /** Network client for making API requests */\n networkClient: NetworkClient;\n /** Base URL for API requests */\n baseUrl: string;\n /** Current user ID (Firebase UID) */\n userId: string | null;\n /** Firebase ID token for authenticated requests */\n token: string | null;\n /** Whether API is ready (user authenticated and token available) */\n isReady: boolean;\n /** Whether auth/token is still loading */\n isLoading: boolean;\n /** Force refresh the ID token */\n refreshToken: () => Promise<string | null>;\n /** Whether running in test/sandbox mode */\n testMode: boolean;\n}\n\nconst ApiContext = createContext<ApiContextValue | null>(null);\n\n/**\n * Hook to access API context\n * @throws Error if used outside of ApiProvider\n */\nexport function useApi(): ApiContextValue {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within an ApiProvider');\n }\n return context;\n}\n\n/**\n * Hook to safely access API context (returns null if not available)\n */\nexport function useApiSafe(): ApiContextValue | null {\n return useContext(ApiContext);\n}\n\ninterface ApiProviderProps {\n children: ReactNode;\n /**\n * Base URL for API requests (optional).\n * Defaults to VITE_API_URL env var.\n */\n baseUrl?: string;\n /**\n * Whether running in test/sandbox mode (optional).\n * Defaults to false.\n */\n testMode?: boolean;\n}\n\n/**\n * API Provider\n *\n * Manages Firebase ID token and provides API configuration.\n * Uses VITE_API_URL env var for baseUrl by default.\n */\nexport function ApiProvider({\n children,\n baseUrl: baseUrlProp,\n testMode = false,\n}: ApiProviderProps) {\n const { user, loading: authLoading } = useAuthStatus();\n const [token, setToken] = useState<string | null>(null);\n const [tokenLoading, setTokenLoading] = useState(false);\n const auth = getFirebaseAuth();\n\n const baseUrl = baseUrlProp || import.meta.env.VITE_API_URL || '';\n const userId = user?.uid ?? null;\n\n // Listen for token changes - Firebase automatically refreshes tokens\n // onIdTokenChanged fires on: sign-in, sign-out, and token refresh\n useEffect(() => {\n if (!auth) {\n setToken(null);\n setTokenLoading(false);\n return;\n }\n\n setTokenLoading(true);\n\n const unsubscribe = onIdTokenChanged(auth, async firebaseUser => {\n if (!firebaseUser) {\n setToken(null);\n setTokenLoading(false);\n return;\n }\n\n try {\n const idToken = await firebaseUser.getIdToken();\n setToken(idToken);\n } catch {\n try {\n getInfoService().show(\n 'Authentication Error',\n 'Failed to get ID token',\n InfoType.ERROR,\n 5000\n );\n } catch {\n console.error('[ApiProvider] Failed to get ID token');\n }\n setToken(null);\n } finally {\n setTokenLoading(false);\n }\n });\n\n return () => {\n unsubscribe();\n };\n }, [auth]);\n\n // Refresh token function for when token expires\n const refreshToken = useCallback(async (): Promise<string | null> => {\n const currentUser = auth?.currentUser;\n if (!currentUser) return null;\n try {\n const newToken = await currentUser.getIdToken(true); // Force refresh\n setToken(newToken);\n return newToken;\n } catch {\n try {\n getInfoService().show(\n 'Authentication Error',\n 'Failed to refresh ID token',\n InfoType.ERROR,\n 5000\n );\n } catch {\n console.error('[ApiProvider] Failed to refresh ID token');\n }\n setToken(null);\n return null;\n }\n }, [auth]);\n\n // Create FirebaseAuthNetworkService instance once\n // This handles automatic token refresh on 401 responses\n // Note: FirebaseAuthNetworkService doesn't perfectly implement NetworkClient interface\n // (different request signature), but it's compatible at runtime for our use cases.\n // Using type assertion as a workaround for the interface mismatch between\n // @sudobility/auth_lib and @sudobility/types.\n const networkClientRef = useRef<NetworkClient | null>(null);\n if (!networkClientRef.current) {\n const firebaseNetworkService = new FirebaseAuthNetworkService({\n onTokenRefreshFailed: error => {\n console.error('[ApiProvider] Token refresh failed:', error);\n try {\n getInfoService().show(\n 'Authentication Error',\n 'Session expired. Please sign in again.',\n InfoType.ERROR,\n 5000\n );\n } catch {\n // InfoService not available\n }\n },\n });\n // Type assertion needed due to interface mismatch between FirebaseAuthNetworkService\n // and NetworkClient (auth_lib uses RequestInit/Response while types uses NetworkRequestOptions/NetworkResponse)\n networkClientRef.current =\n firebaseNetworkService as unknown as NetworkClient;\n }\n\n const value = useMemo<ApiContextValue>(\n () => ({\n networkClient: networkClientRef.current!,\n baseUrl,\n userId,\n token,\n isReady: !!userId && !!token,\n isLoading: authLoading || tokenLoading,\n refreshToken,\n testMode,\n }),\n [baseUrl, userId, token, authLoading, tokenLoading, refreshToken, testMode]\n );\n\n return <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;\n}\n\nexport { ApiContext };\n","/**\n * SudobilityAppWithFirebaseAuth - App wrapper with Firebase authentication\n *\n * Extends SudobilityApp with:\n * - Firebase AuthProviderWrapper for authentication (built-in default)\n * - ApiProvider for network/token management (built-in default)\n */\nimport { ComponentType, ReactNode } from 'react';\nimport { SudobilityApp, SudobilityAppProps } from './SudobilityApp';\nimport { AuthProvider } from '@sudobility/auth-components';\nimport {\n getFirebaseAuth,\n getFirebaseErrorMessage,\n initializeFirebaseAuth,\n} from '@sudobility/auth_lib';\nimport { ApiProvider } from '../api';\n\n/** Auth text labels for UI - all fields required for localization */\nexport interface AuthTexts {\n signInTitle: string;\n signInWithEmail: string;\n createAccount: string;\n resetPassword: string;\n signIn: string;\n signUp: string;\n logout: string;\n login: string;\n continueWithGoogle: string;\n continueWithApple: string;\n continueWithEmail: string;\n sendResetLink: string;\n backToSignIn: string;\n close: string;\n email: string;\n password: string;\n confirmPassword: string;\n displayName: string;\n emailPlaceholder: string;\n passwordPlaceholder: string;\n confirmPasswordPlaceholder: string;\n displayNamePlaceholder: string;\n forgotPassword: string;\n noAccount: string;\n haveAccount: string;\n or: string;\n resetEmailSent: string;\n resetEmailSentDesc: string;\n passwordMismatch: string;\n passwordTooShort: string;\n loading: string;\n}\n\n/** Auth error messages for Firebase error codes */\nexport interface AuthErrorTexts {\n 'auth/user-not-found': string;\n 'auth/wrong-password': string;\n 'auth/invalid-email': string;\n 'auth/invalid-credential': string;\n 'auth/email-already-in-use': string;\n 'auth/weak-password': string;\n 'auth/too-many-requests': string;\n 'auth/network-request-failed': string;\n 'auth/popup-closed-by-user': string;\n 'auth/popup-blocked': string;\n 'auth/account-exists-with-different-credential': string;\n 'auth/operation-not-allowed': string;\n default: string;\n}\n\nexport interface SudobilityAppWithFirebaseAuthProps extends Omit<\n SudobilityAppProps,\n 'AppProviders' | 'RouterWrapper'\n> {\n /**\n * Custom Firebase auth provider wrapper component (optional).\n * If provided, authTexts and authErrorTexts are ignored.\n */\n AuthProviderWrapper?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Localized auth UI texts (required if not using custom AuthProviderWrapper).\n */\n authTexts?: AuthTexts;\n\n /**\n * Localized auth error messages (required if not using custom AuthProviderWrapper).\n */\n authErrorTexts?: AuthErrorTexts;\n\n /**\n * Auth providers to enable (optional).\n * Defaults to [\"google\", \"email\"].\n */\n authProviders?: ('google' | 'email' | 'apple')[];\n\n /**\n * Whether to enable anonymous auth (optional).\n * Defaults to false.\n */\n enableAnonymousAuth?: boolean;\n\n /**\n * Custom ApiProvider component (optional).\n * Defaults to built-in ApiProvider that manages Firebase ID token.\n * Set to false to disable the built-in ApiProvider.\n */\n ApiProvider?: ComponentType<{ children: ReactNode }> | false;\n\n /**\n * Additional providers to wrap around the router content.\n * These are rendered inside ApiProvider but outside BrowserRouter.\n */\n AppProviders?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Custom router wrapper component (optional).\n * Defaults to BrowserRouter. Pass a fragment wrapper `({ children }) => <>{children}</>`\n * to skip the router entirely (useful when nesting inside an existing router).\n */\n RouterWrapper?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Whether running in test/sandbox mode (optional).\n * Passed to ApiProvider. Defaults to false.\n */\n testMode?: boolean;\n\n /**\n * Base URL for API requests (optional).\n * Passed to ApiProvider. Defaults to VITE_API_URL env var.\n */\n baseUrl?: string;\n}\n\n/**\n * Default AuthProviderWrapper using Firebase\n */\nfunction DefaultAuthProviderWrapper({\n children,\n providers,\n enableAnonymous,\n texts,\n errorTexts,\n}: {\n children: ReactNode;\n providers: ('google' | 'email' | 'apple')[];\n enableAnonymous: boolean;\n texts: AuthTexts;\n errorTexts: AuthErrorTexts;\n}) {\n // Initialize Firebase Auth (idempotent - safe to call multiple times)\n initializeFirebaseAuth();\n\n const auth = getFirebaseAuth();\n\n // If Firebase is not configured, render children without auth\n if (!auth) {\n console.warn(\n '[SudobilityAppWithFirebaseAuth] No auth instance - Firebase not configured'\n );\n return <>{children}</>;\n }\n\n return (\n <AuthProvider\n firebaseConfig={{ type: 'instance', auth: auth }}\n providerConfig={{\n providers,\n enableAnonymous,\n }}\n texts={texts}\n errorTexts={errorTexts}\n resolveErrorMessage={getFirebaseErrorMessage}\n >\n {children}\n </AuthProvider>\n );\n}\n\n/**\n * SudobilityAppWithFirebaseAuth - App wrapper with Firebase authentication\n *\n * @example\n * ```tsx\n * // With custom AuthProviderWrapper (recommended for i18n)\n * import { SudobilityAppWithFirebaseAuth } from '@sudobility/building_blocks';\n *\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuth\n * AuthProviderWrapper={MyAuthProviderWrapper}\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuth>\n * );\n * }\n *\n * // With localized texts\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuth\n * authTexts={localizedAuthTexts}\n * authErrorTexts={localizedAuthErrorTexts}\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuth>\n * );\n * }\n * ```\n */\nexport function SudobilityAppWithFirebaseAuth({\n AuthProviderWrapper: AuthProviderWrapperProp,\n authTexts,\n authErrorTexts,\n authProviders = ['google', 'email'],\n enableAnonymousAuth = false,\n ApiProvider: ApiProviderProp,\n AppProviders,\n RouterWrapper,\n testMode = false,\n baseUrl,\n ...baseProps\n}: SudobilityAppWithFirebaseAuthProps) {\n // Create a combined providers component that includes auth and api\n const CombinedProviders: ComponentType<{ children: ReactNode }> = ({\n children,\n }) => {\n let content = children;\n\n // Wrap with AppProviders if provided\n if (AppProviders) {\n content = <AppProviders>{content}</AppProviders>;\n }\n\n // Wrap with ApiProvider (custom, default, or disabled)\n if (ApiProviderProp === false) {\n // Explicitly disabled\n } else if (ApiProviderProp) {\n content = <ApiProviderProp>{content}</ApiProviderProp>;\n } else {\n // Default ApiProvider\n content = (\n <ApiProvider baseUrl={baseUrl} testMode={testMode}>\n {content}\n </ApiProvider>\n );\n }\n\n // Wrap with AuthProviderWrapper (custom or default)\n if (AuthProviderWrapperProp) {\n return <AuthProviderWrapperProp>{content}</AuthProviderWrapperProp>;\n }\n\n // Require texts when using default AuthProviderWrapper\n if (!authTexts || !authErrorTexts) {\n throw new Error(\n '[SudobilityAppWithFirebaseAuth] authTexts and authErrorTexts are required when not using a custom AuthProviderWrapper'\n );\n }\n\n return (\n <DefaultAuthProviderWrapper\n providers={authProviders}\n enableAnonymous={enableAnonymousAuth}\n texts={authTexts}\n errorTexts={authErrorTexts}\n >\n {content}\n </DefaultAuthProviderWrapper>\n );\n };\n\n return (\n <SudobilityApp\n {...baseProps}\n AppProviders={CombinedProviders}\n RouterWrapper={RouterWrapper}\n />\n );\n}\n\nexport default SudobilityAppWithFirebaseAuth;\n","/**\n * Lazy Subscription Provider\n *\n * Defers loading of RevenueCat SDK (~600KB) until user is authenticated.\n * For unauthenticated users, provides a stub context.\n */\n\nimport { type ReactNode, Suspense, lazy, useMemo } from 'react';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport {\n SafeSubscriptionContext,\n STUB_SUBSCRIPTION_VALUE,\n} from './SafeSubscriptionContext';\n\n// Lazy load the actual subscription provider\nconst SubscriptionProviderWrapper = lazy(\n () => import('./SubscriptionProviderWrapper')\n);\n\nfunction StubSubscriptionProvider({ children }: { children: ReactNode }) {\n return (\n <SafeSubscriptionContext.Provider value={STUB_SUBSCRIPTION_VALUE}>\n {children}\n </SafeSubscriptionContext.Provider>\n );\n}\n\ninterface LazySubscriptionProviderProps {\n children: ReactNode;\n /** Entity ID to use as RevenueCat subscriber */\n entityId?: string;\n /** RevenueCat API key */\n apiKey: string;\n}\n\n/**\n * Lazy wrapper for SubscriptionProvider that only loads RevenueCat SDK\n * when the user is authenticated. This saves ~600KB on initial load.\n * For unauthenticated users, provides a stub context so hooks don't throw.\n */\nexport function LazySubscriptionProvider({\n children,\n entityId,\n apiKey,\n}: LazySubscriptionProviderProps) {\n const { user } = useAuthStatus();\n\n const isAuthenticated = useMemo(() => {\n return !!user && !user.isAnonymous;\n }, [user]);\n\n if (!isAuthenticated) {\n return <StubSubscriptionProvider>{children}</StubSubscriptionProvider>;\n }\n\n return (\n <Suspense\n fallback={<StubSubscriptionProvider>{children}</StubSubscriptionProvider>}\n >\n <SubscriptionProviderWrapper entityId={entityId} apiKey={apiKey}>\n {children}\n </SubscriptionProviderWrapper>\n </Suspense>\n );\n}\n\nexport default LazySubscriptionProvider;\n","/**\n * Subscription Provider Wrapper\n *\n * Integrates subscription-components with auth and sets up RevenueCat user.\n */\n\nimport { type ReactNode, useEffect, useRef } from 'react';\nimport {\n SubscriptionProvider,\n useSubscriptionContext,\n} from '@sudobility/subscription-components';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport { getInfoService } from '@sudobility/di/info';\nimport { InfoType } from '@sudobility/types';\nimport {\n setRevenueCatUser,\n clearRevenueCatUser,\n refreshSubscription,\n} from '@sudobility/subscription_lib';\nimport { SafeSubscriptionContext } from './SafeSubscriptionContext';\n\ninterface SubscriptionProviderWrapperProps {\n children: ReactNode;\n entityId?: string;\n apiKey: string;\n}\n\nconst handleSubscriptionError = (error: Error) => {\n try {\n getInfoService().show(\n 'Subscription Error',\n error.message,\n InfoType.ERROR,\n 5000\n );\n } catch {\n // InfoService not available - log to console\n console.error('[Subscription]', error.message);\n }\n};\n\n/**\n * Bridge that provides context and configures RevenueCat user.\n */\nfunction SubscriptionBridge({\n children,\n entityId,\n}: {\n children: ReactNode;\n entityId?: string;\n}) {\n const { user } = useAuthStatus();\n const context = useSubscriptionContext();\n const entityIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n const shouldSetUser = user && !user.isAnonymous && entityId;\n\n if (shouldSetUser && entityId !== entityIdRef.current) {\n entityIdRef.current = entityId;\n // Set user for both subscription-components and subscription_lib\n context.initialize(entityId, user.email || undefined);\n setRevenueCatUser(entityId, user.email || undefined).then(() => {\n // Refresh subscription_lib data after user is set\n refreshSubscription();\n });\n } else if (!shouldSetUser && entityIdRef.current) {\n entityIdRef.current = null;\n clearRevenueCatUser();\n }\n }, [user, entityId, context]);\n\n return (\n <SafeSubscriptionContext.Provider value={context}>\n {children}\n </SafeSubscriptionContext.Provider>\n );\n}\n\nexport function SubscriptionProviderWrapper({\n children,\n entityId,\n apiKey,\n}: SubscriptionProviderWrapperProps) {\n const { user } = useAuthStatus();\n\n return (\n <SubscriptionProvider\n apiKey={apiKey}\n userEmail={user?.email || undefined}\n onError={handleSubscriptionError}\n >\n <SubscriptionBridge entityId={entityId}>{children}</SubscriptionBridge>\n </SubscriptionProvider>\n );\n}\n\nexport default SubscriptionProviderWrapper;\n","/**\n * SudobilityAppWithFirebaseAuthAndEntities - App wrapper with Firebase auth and entity support\n *\n * Extends SudobilityAppWithFirebaseAuth with:\n * - AuthAwareEntityProvider that connects entity context to auth state (built-in default)\n * - EntityAwareSubscriptionProvider that connects subscription to entity (built-in default)\n */\nimport { ComponentType, ReactNode, useMemo } from 'react';\nimport {\n SudobilityAppWithFirebaseAuth,\n SudobilityAppWithFirebaseAuthProps,\n} from './SudobilityAppWithFirebaseAuth';\nimport { useAuthStatus } from '@sudobility/auth-components';\nimport {\n CurrentEntityProvider,\n EntityClient,\n useCurrentEntity,\n} from '@sudobility/entity_client';\nimport { LazySubscriptionProvider } from '../subscription';\nimport { useApiSafe } from '../api';\n\nexport interface SudobilityAppWithFirebaseAuthAndEntitiesProps extends Omit<\n SudobilityAppWithFirebaseAuthProps,\n 'AppProviders' | 'RouterWrapper'\n> {\n /**\n * Base URL for the API (optional).\n * Defaults to VITE_API_URL env var.\n * Used for both ApiProvider and EntityClient.\n *\n * @example \"https://api.myapp.com\"\n */\n apiUrl?: string;\n\n /**\n * @deprecated Use apiUrl instead. Will be removed in future version.\n */\n entityApiUrl?: string;\n\n /**\n * RevenueCat API key for production subscriptions (optional).\n * If not provided, reads from VITE_REVENUECAT_API_KEY env var.\n * If neither is available, subscription features are disabled.\n */\n revenueCatApiKey?: string;\n\n /**\n * RevenueCat API key for sandbox/test subscriptions (optional).\n * Used when testMode is true.\n * If not provided, reads from VITE_REVENUECAT_API_KEY_SANDBOX env var.\n */\n revenueCatApiKeySandbox?: string;\n\n /**\n * Custom AuthAwareEntityProvider component (optional).\n * Defaults to built-in provider if entityApiUrl is provided.\n */\n AuthAwareEntityProvider?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Custom EntityAwareSubscriptionProvider component (optional).\n * Defaults to built-in provider that uses LazySubscriptionProvider.\n * Set to false to disable subscription features entirely.\n */\n EntityAwareSubscriptionProvider?:\n | ComponentType<{ children: ReactNode }>\n | false;\n\n /**\n * Additional providers to wrap around the router content.\n * These are rendered inside EntityAwareSubscriptionProvider but outside BrowserRouter.\n * Use this for app-specific providers like ApiProvider.\n */\n AppProviders?: ComponentType<{ children: ReactNode }>;\n\n /**\n * Custom router wrapper component (optional).\n * Defaults to BrowserRouter. Pass a fragment wrapper `({ children }) => <>{children}</>`\n * to skip the router entirely (useful when nesting inside an existing router).\n */\n RouterWrapper?: ComponentType<{ children: ReactNode }>;\n}\n\n/**\n * Default AuthAwareEntityProvider using CurrentEntityProvider\n */\nfunction DefaultAuthAwareEntityProvider({\n children,\n entityClient,\n}: {\n children: ReactNode;\n entityClient: EntityClient;\n}) {\n const { user } = useAuthStatus();\n const authUser = useMemo(\n () => (user ? { uid: user.uid, email: user.email } : null),\n [user]\n );\n\n return (\n <CurrentEntityProvider client={entityClient} user={authUser}>\n {children}\n </CurrentEntityProvider>\n );\n}\n\n/**\n * Default EntityAwareSubscriptionProvider using LazySubscriptionProvider\n */\nfunction DefaultEntityAwareSubscriptionProvider({\n children,\n apiKey,\n}: {\n children: ReactNode;\n apiKey: string;\n}) {\n const { currentEntityId } = useCurrentEntity();\n return (\n <LazySubscriptionProvider\n entityId={currentEntityId ?? undefined}\n apiKey={apiKey}\n >\n {children}\n </LazySubscriptionProvider>\n );\n}\n\n/**\n * SudobilityAppWithFirebaseAuthAndEntities - Full-featured app wrapper\n *\n * @example\n * ```tsx\n * // Minimal usage with entityApiUrl - uses all defaults\n * import { SudobilityAppWithFirebaseAuthAndEntities } from '@sudobility/building_blocks';\n * import i18n from './i18n';\n *\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuthAndEntities\n * i18n={i18n}\n * entityApiUrl=\"https://api.myapp.com/api/v1\"\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuthAndEntities>\n * );\n * }\n *\n * // With custom providers\n * function App() {\n * return (\n * <SudobilityAppWithFirebaseAuthAndEntities\n * i18n={i18n}\n * AuthAwareEntityProvider={MyEntityProvider}\n * EntityAwareSubscriptionProvider={MySubscriptionProvider}\n * AppProviders={ApiProvider}\n * >\n * <Routes>\n * <Route path=\"/\" element={<HomePage />} />\n * </Routes>\n * </SudobilityAppWithFirebaseAuthAndEntities>\n * );\n * }\n * ```\n */\nexport function SudobilityAppWithFirebaseAuthAndEntities({\n apiUrl,\n entityApiUrl, // deprecated, use apiUrl\n revenueCatApiKey,\n revenueCatApiKeySandbox,\n AuthAwareEntityProvider: AuthAwareEntityProviderProp,\n EntityAwareSubscriptionProvider: EntityAwareSubscriptionProviderProp,\n AppProviders,\n RouterWrapper,\n testMode = false,\n ...baseProps\n}: SudobilityAppWithFirebaseAuthAndEntitiesProps) {\n // Get API URL from prop or env var\n // Support deprecated entityApiUrl for backwards compatibility\n const baseApiUrl = apiUrl || import.meta.env.VITE_API_URL || '';\n const entityUrl = entityApiUrl || (baseApiUrl ? `${baseApiUrl}/api/v1` : '');\n\n // Get RevenueCat API key from prop or env var, selecting based on testMode\n const rcApiKeyProd =\n revenueCatApiKey || import.meta.env.VITE_REVENUECAT_API_KEY || '';\n const rcApiKeySandbox =\n revenueCatApiKeySandbox ||\n import.meta.env.VITE_REVENUECAT_API_KEY_SANDBOX ||\n '';\n const rcApiKey = testMode ? rcApiKeySandbox : rcApiKeyProd;\n\n // Create a combined providers component that includes entity support\n // This renders inside ApiProvider, so useApiSafe() is available\n const EntityProviders: ComponentType<{ children: ReactNode }> = ({\n children,\n }) => {\n const api = useApiSafe();\n const entityClient = useMemo(\n () =>\n entityUrl && api?.networkClient\n ? new EntityClient({\n baseUrl: entityUrl,\n networkClient: api.networkClient,\n })\n : null,\n [api?.networkClient]\n );\n\n let content = children;\n\n // Wrap with AppProviders if provided\n if (AppProviders) {\n content = <AppProviders>{content}</AppProviders>;\n }\n\n // Wrap with EntityAwareSubscriptionProvider (custom, default, or disabled)\n if (EntityAwareSubscriptionProviderProp === false) {\n // Explicitly disabled - skip subscription provider\n } else if (EntityAwareSubscriptionProviderProp) {\n // Custom provider\n content = (\n <EntityAwareSubscriptionProviderProp>\n {content}\n </EntityAwareSubscriptionProviderProp>\n );\n } else if (rcApiKey) {\n // Default provider with API key\n content = (\n <DefaultEntityAwareSubscriptionProvider apiKey={rcApiKey}>\n {content}\n </DefaultEntityAwareSubscriptionProvider>\n );\n }\n // If no API key and no custom provider, subscription features are silently disabled\n\n // Wrap with AuthAwareEntityProvider (custom or default)\n if (AuthAwareEntityProviderProp) {\n return (\n <AuthAwareEntityProviderProp>{content}</AuthAwareEntityProviderProp>\n );\n }\n\n // Use default if entityClient is available\n if (entityClient) {\n return (\n <DefaultAuthAwareEntityProvider entityClient={entityClient}>\n {content}\n </DefaultAuthAwareEntityProvider>\n );\n }\n\n // No entity support if no entityApiUrl or custom provider\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[SudobilityAppWithFirebaseAuthAndEntities] No entityApiUrl or AuthAwareEntityProvider provided. ' +\n 'Entity features are disabled. Provide apiUrl or AuthAwareEntityProvider to enable them.'\n );\n }\n return <>{content}</>;\n };\n\n return (\n <SudobilityAppWithFirebaseAuth\n {...baseProps}\n baseUrl={baseApiUrl}\n testMode={testMode}\n AppProviders={EntityProviders}\n RouterWrapper={RouterWrapper}\n />\n );\n}\n\nexport default SudobilityAppWithFirebaseAuthAndEntities;\n"],"names":["SubscriptionProviderWrapper"],"mappings":";;;;;;;;;;;AAgDA,MAAM,aAAa,cAAsC,IAAI;AAMtD,SAAS,SAA0B;AACxC,QAAM,UAAU,WAAW,UAAU;AACrC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO;AACT;AAKO,SAAS,aAAqC;AACnD,SAAO,WAAW,UAAU;AAC9B;AAsBO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,SAAS;AAAA,EACT,WAAW;AACb,GAAqB;AACnB,QAAM,EAAE,MAAM,SAAS,YAAA,IAAgB,cAAA;AACvC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,OAAO,gBAAA;AAEb,QAAM,UAAU,eAAe,UAAgC;AAC/D,QAAM,UAAS,6BAAM,QAAO;AAI5B,YAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT,eAAS,IAAI;AACb,sBAAgB,KAAK;AACrB;AAAA,IACF;AAEA,oBAAgB,IAAI;AAEpB,UAAM,cAAc,iBAAiB,MAAM,OAAM,iBAAgB;AAC/D,UAAI,CAAC,cAAc;AACjB,iBAAS,IAAI;AACb,wBAAgB,KAAK;AACrB;AAAA,MACF;AAEA,UAAI;AACF,cAAM,UAAU,MAAM,aAAa,WAAA;AACnC,iBAAS,OAAO;AAAA,MAClB,QAAQ;AACN,YAAI;AACF,yBAAA,EAAiB;AAAA,YACf;AAAA,YACA;AAAA,YACA,SAAS;AAAA,YACT;AAAA,UAAA;AAAA,QAEJ,QAAQ;AACN,kBAAQ,MAAM,sCAAsC;AAAA,QACtD;AACA,iBAAS,IAAI;AAAA,MACf,UAAA;AACE,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAGT,QAAM,eAAe,YAAY,YAAoC;AACnE,UAAM,cAAc,6BAAM;AAC1B,QAAI,CAAC,YAAa,QAAO;AACzB,QAAI;AACF,YAAM,WAAW,MAAM,YAAY,WAAW,IAAI;AAClD,eAAS,QAAQ;AACjB,aAAO;AAAA,IACT,QAAQ;AACN,UAAI;AACF,uBAAA,EAAiB;AAAA,UACf;AAAA,UACA;AAAA,UACA,SAAS;AAAA,UACT;AAAA,QAAA;AAAA,MAEJ,QAAQ;AACN,gBAAQ,MAAM,0CAA0C;AAAA,MAC1D;AACA,eAAS,IAAI;AACb,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAQT,QAAM,mBAAmB,OAA6B,IAAI;AAC1D,MAAI,CAAC,iBAAiB,SAAS;AAC7B,UAAM,yBAAyB,IAAI,2BAA2B;AAAA,MAC5D,sBAAsB,CAAA,UAAS;AAC7B,gBAAQ,MAAM,uCAAuC,KAAK;AAC1D,YAAI;AACF,yBAAA,EAAiB;AAAA,YACf;AAAA,YACA;AAAA,YACA,SAAS;AAAA,YACT;AAAA,UAAA;AAAA,QAEJ,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IAAA,CACD;AAGD,qBAAiB,UACf;AAAA,EACJ;AAEA,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL,eAAe,iBAAiB;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC;AAAA,MACvB,WAAW,eAAe;AAAA,MAC1B;AAAA,MACA;AAAA,IAAA;AAAA,IAEF,CAAC,SAAS,QAAQ,OAAO,aAAa,cAAc,cAAc,QAAQ;AAAA,EAAA;AAG5E,6BAAQ,WAAW,UAAX,EAAoB,OAAe,UAAS;AACtD;AC5EA,SAAS,2BAA2B;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AAED,yBAAA;AAEA,QAAM,OAAO,gBAAA;AAGb,MAAI,CAAC,MAAM;AACT,YAAQ;AAAA,MACN;AAAA,IAAA;AAEF,2CAAU,UAAS;AAAA,EACrB;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,gBAAgB,EAAE,MAAM,YAAY,KAAA;AAAA,MACpC,gBAAgB;AAAA,QACd;AAAA,QACA;AAAA,MAAA;AAAA,MAEF;AAAA,MACA;AAAA,MACA,qBAAqB;AAAA,MAEpB;AAAA,IAAA;AAAA,EAAA;AAGP;AAqCO,SAAS,8BAA8B;AAAA,EAC5C,qBAAqB;AAAA,EACrB;AAAA,EACA;AAAA,EACA,gBAAgB,CAAC,UAAU,OAAO;AAAA,EAClC,sBAAsB;AAAA,EACtB,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,GAAG;AACL,GAAuC;AAErC,QAAM,oBAA4D,CAAC;AAAA,IACjE;AAAA,EAAA,MACI;AACJ,QAAI,UAAU;AAGd,QAAI,cAAc;AAChB,gBAAU,oBAAC,gBAAc,UAAA,QAAA,CAAQ;AAAA,IACnC;AAGA,QAAI,oBAAoB,MAAO;AAAA,aAEpB,iBAAiB;AAC1B,gBAAU,oBAAC,mBAAiB,UAAA,QAAA,CAAQ;AAAA,IACtC,OAAO;AAEL,gBACE,oBAAC,aAAA,EAAY,SAAkB,UAC5B,UAAA,SACH;AAAA,IAEJ;AAGA,QAAI,yBAAyB;AAC3B,aAAO,oBAAC,2BAAyB,UAAA,QAAA,CAAQ;AAAA,IAC3C;AAGA,QAAI,CAAC,aAAa,CAAC,gBAAgB;AACjC,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,QACX,iBAAiB;AAAA,QACjB,OAAO;AAAA,QACP,YAAY;AAAA,QAEX,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,cAAc;AAAA,MACd;AAAA,IAAA;AAAA,EAAA;AAGN;AC5QA,MAAMA,gCAA8B;AAAA,EAClC,MAAM,QAAA,QAAA,EAAA,KAAA,MAAA,6BAAA;AACR;AAEA,SAAS,yBAAyB,EAAE,YAAqC;AACvE,6BACG,wBAAwB,UAAxB,EAAiC,OAAO,yBACtC,UACH;AAEJ;AAeO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF,GAAkC;AAChC,QAAM,EAAE,KAAA,IAAS,cAAA;AAEjB,QAAM,kBAAkB,QAAQ,MAAM;AACpC,WAAO,CAAC,CAAC,QAAQ,CAAC,KAAK;AAAA,EACzB,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,iBAAiB;AACpB,WAAO,oBAAC,4BAA0B,UAAS;AAAA,EAC7C;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,UAAU,oBAAC,0BAAA,EAA0B,SAAA,CAAS;AAAA,MAE9C,UAAA,oBAACA,+BAAA,EAA4B,UAAoB,QAC9C,SAAA,CACH;AAAA,IAAA;AAAA,EAAA;AAGN;ACrCA,MAAM,0BAA0B,CAAC,UAAiB;AAChD,MAAI;AACF,mBAAA,EAAiB;AAAA,MACf;AAAA,MACA,MAAM;AAAA,MACN,SAAS;AAAA,MACT;AAAA,IAAA;AAAA,EAEJ,QAAQ;AAEN,YAAQ,MAAM,kBAAkB,MAAM,OAAO;AAAA,EAC/C;AACF;AAKA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AACF,GAGG;AACD,QAAM,EAAE,KAAA,IAAS,cAAA;AACjB,QAAM,UAAU,uBAAA;AAChB,QAAM,cAAc,OAAsB,IAAI;AAE9C,YAAU,MAAM;AACd,UAAM,gBAAgB,QAAQ,CAAC,KAAK,eAAe;AAEnD,QAAI,iBAAiB,aAAa,YAAY,SAAS;AACrD,kBAAY,UAAU;AAEtB,cAAQ,WAAW,UAAU,KAAK,SAAS,MAAS;AACpD,wBAAkB,UAAU,KAAK,SAAS,MAAS,EAAE,KAAK,MAAM;AAE9D,4BAAA;AAAA,MACF,CAAC;AAAA,IACH,WAAW,CAAC,iBAAiB,YAAY,SAAS;AAChD,kBAAY,UAAU;AACtB,0BAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,UAAU,OAAO,CAAC;AAE5B,6BACG,wBAAwB,UAAxB,EAAiC,OAAO,SACtC,UACH;AAEJ;AAEO,SAAS,4BAA4B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AACF,GAAqC;AACnC,QAAM,EAAE,KAAA,IAAS,cAAA;AAEjB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,YAAW,6BAAM,UAAS;AAAA,MAC1B,SAAS;AAAA,MAET,UAAA,oBAAC,oBAAA,EAAmB,UAAqB,SAAA,CAAS;AAAA,IAAA;AAAA,EAAA;AAGxD;;;;;;ACTA,SAAS,+BAA+B;AAAA,EACtC;AAAA,EACA;AACF,GAGG;AACD,QAAM,EAAE,KAAA,IAAS,cAAA;AACjB,QAAM,WAAW;AAAA,IACf,MAAO,OAAO,EAAE,KAAK,KAAK,KAAK,OAAO,KAAK,MAAA,IAAU;AAAA,IACrD,CAAC,IAAI;AAAA,EAAA;AAGP,6BACG,uBAAA,EAAsB,QAAQ,cAAc,MAAM,UAChD,UACH;AAEJ;AAKA,SAAS,uCAAuC;AAAA,EAC9C;AAAA,EACA;AACF,GAGG;AACD,QAAM,EAAE,gBAAA,IAAoB,iBAAA;AAC5B,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,UAAU,mBAAmB;AAAA,MAC7B;AAAA,MAEC;AAAA,IAAA;AAAA,EAAA;AAGP;AAyCO,SAAS,yCAAyC;AAAA,EACvD;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAAA,EACzB,iCAAiC;AAAA,EACjC;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,GAAG;AACL,GAAkD;AAGhD,QAAM,aAAa,UAAU,UAAgC;AAC7D,QAAM,YAAY,iBAAiB,aAAa,GAAG,UAAU,YAAY;AAGzE,QAAM,eACJ,oBAAoB,UAA2C;AACjE,QAAM,kBACJ,2BACA,UACA;AACF,QAAM,WAAW,WAAW,kBAAkB;AAI9C,QAAM,kBAA0D,CAAC;AAAA,IAC/D;AAAA,EAAA,MACI;AACJ,UAAM,MAAM,WAAA;AACZ,UAAM,eAAe;AAAA,MACnB,MACE,cAAa,2BAAK,iBACd,IAAI,aAAa;AAAA,QACf,SAAS;AAAA,QACT,eAAe,IAAI;AAAA,MAAA,CACpB,IACD;AAAA,MACN,CAAC,2BAAK,aAAa;AAAA,IAAA;AAGrB,QAAI,UAAU;AAGd,QAAI,cAAc;AAChB,gBAAU,oBAAC,gBAAc,UAAA,SAAQ;AAAA,IACnC;AAGA,QAAI,wCAAwC,MAAO;AAAA,aAExC,qCAAqC;AAE9C,gBACE,oBAAC,uCACE,UAAA,SACH;AAAA,IAEJ,WAAW,UAAU;AAEnB,oCACG,wCAAA,EAAuC,QAAQ,UAC7C,UAAA,SACH;AAAA,IAEJ;AAIA,QAAI,6BAA6B;AAC/B,aACE,oBAAC,+BAA6B,UAAA,SAAQ;AAAA,IAE1C;AAGA,QAAI,cAAc;AAChB,iCACG,gCAAA,EAA+B,cAC7B,UAAA,SACH;AAAA,IAEJ;AAGA,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,cAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAGJ;AACA,2CAAU,UAAA,SAAQ;AAAA,EACpB;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,SAAS;AAAA,MACT;AAAA,MACA,cAAc;AAAA,MACd;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|