@semiont/frontend 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/assets/AuthContext-xM132UqD.js +2 -0
  2. package/dist/assets/AuthContext-xM132UqD.js.map +1 -0
  3. package/dist/assets/{CookiePreferences-C35ds4bQ.js → CookiePreferences-L69Zja-8.js} +2 -2
  4. package/dist/assets/{CookiePreferences-C35ds4bQ.js.map → CookiePreferences-L69Zja-8.js.map} +1 -1
  5. package/dist/assets/{PdfAnnotationCanvas.client-LF6DDTCV-B4G1hSau.js → PdfAnnotationCanvas.client-LF6DDTCV-DjnFutDo.js} +2 -2
  6. package/dist/assets/{PdfAnnotationCanvas.client-LF6DDTCV-B4G1hSau.js.map → PdfAnnotationCanvas.client-LF6DDTCV-DjnFutDo.js.map} +1 -1
  7. package/dist/assets/{ToolbarPanels-zXxZM4bL.js → ToolbarPanels-Dq0eXjjR.js} +2 -2
  8. package/dist/assets/{ToolbarPanels-zXxZM4bL.js.map → ToolbarPanels-Dq0eXjjR.js.map} +1 -1
  9. package/dist/assets/{client-CgVU9eN0.js → client-CmvSjN3K.js} +2 -2
  10. package/dist/assets/{client-CgVU9eN0.js.map → client-CmvSjN3K.js.map} +1 -1
  11. package/dist/assets/{client-BFN4OqK0.js → client-Cxt1NUWp.js} +2 -2
  12. package/dist/assets/{client-BFN4OqK0.js.map → client-Cxt1NUWp.js.map} +1 -1
  13. package/dist/assets/{client-CF_pv0rC.js → client-D1NYe5bc.js} +2 -2
  14. package/dist/assets/{client-CF_pv0rC.js.map → client-D1NYe5bc.js.map} +1 -1
  15. package/dist/assets/{client-Di531MRg.js → client-D5mudL5R.js} +2 -2
  16. package/dist/assets/{client-Di531MRg.js.map → client-D5mudL5R.js.map} +1 -1
  17. package/dist/assets/{en-LNW2A3RA-BUa1vcQc.js → en-LNW2A3RA-CQBvSBCl.js} +5 -5
  18. package/dist/assets/{en-LNW2A3RA-BUa1vcQc.js.map → en-LNW2A3RA-CQBvSBCl.js.map} +1 -1
  19. package/dist/assets/{index-DsKSr5Q5.js → index-IyxbPWuo.js} +3 -3
  20. package/dist/assets/{index-DsKSr5Q5.js.map → index-IyxbPWuo.js.map} +1 -1
  21. package/dist/assets/{layout-CdHgzhHf.js → layout-5_En-vLB.js} +2 -2
  22. package/dist/assets/{layout-CdHgzhHf.js.map → layout-5_En-vLB.js.map} +1 -1
  23. package/dist/assets/{layout-CYimsq_V.js → layout-DF8lLIQx.js} +2 -2
  24. package/dist/assets/{layout-CYimsq_V.js.map → layout-DF8lLIQx.js.map} +1 -1
  25. package/dist/assets/{layout-BRiOZEGL.js → layout-DYaEHeqB.js} +2 -2
  26. package/dist/assets/{layout-BRiOZEGL.js.map → layout-DYaEHeqB.js.map} +1 -1
  27. package/dist/assets/{layout-C-7nzim0.js → layout-QdxLp1Jq.js} +2 -2
  28. package/dist/assets/{layout-C-7nzim0.js.map → layout-QdxLp1Jq.js.map} +1 -1
  29. package/dist/assets/{not-found-D_yWa0eC.js → not-found-BjlzlRT_.js} +2 -2
  30. package/dist/assets/{not-found-D_yWa0eC.js.map → not-found-BjlzlRT_.js.map} +1 -1
  31. package/dist/assets/{page-Dnixz6NY.js → page-4vdCvEL0.js} +2 -2
  32. package/dist/assets/{page-Dnixz6NY.js.map → page-4vdCvEL0.js.map} +1 -1
  33. package/dist/assets/{page-BItZqEKs.js → page-6Y-lDxnu.js} +2 -2
  34. package/dist/assets/{page-BItZqEKs.js.map → page-6Y-lDxnu.js.map} +1 -1
  35. package/dist/assets/{page-BKC4knAP.js → page-B8hAUDzt.js} +2 -2
  36. package/dist/assets/{page-BKC4knAP.js.map → page-B8hAUDzt.js.map} +1 -1
  37. package/dist/assets/{page-aXQvfZxG.js → page-BUPqapmo.js} +2 -2
  38. package/dist/assets/{page-aXQvfZxG.js.map → page-BUPqapmo.js.map} +1 -1
  39. package/dist/assets/{page-KzkTaHkN.js → page-Bb2aSxYZ.js} +2 -2
  40. package/dist/assets/{page-KzkTaHkN.js.map → page-Bb2aSxYZ.js.map} +1 -1
  41. package/dist/assets/{page-Nxgrl4fs.js → page-CG2brhZf.js} +2 -2
  42. package/dist/assets/{page-Nxgrl4fs.js.map → page-CG2brhZf.js.map} +1 -1
  43. package/dist/assets/{page-aAjfohhi.js → page-CPxgvPSe.js} +2 -2
  44. package/dist/assets/{page-aAjfohhi.js.map → page-CPxgvPSe.js.map} +1 -1
  45. package/dist/assets/{page-OQxske5w.js → page-CTn7lGDa.js} +2 -2
  46. package/dist/assets/{page-OQxske5w.js.map → page-CTn7lGDa.js.map} +1 -1
  47. package/dist/assets/page-CkeyIRf4.js +2 -0
  48. package/dist/assets/{page-amCJRFD1.js.map → page-CkeyIRf4.js.map} +1 -1
  49. package/dist/assets/{page-CRyuR46S.js → page-D77AjrZW.js} +2 -2
  50. package/dist/assets/{page-CRyuR46S.js.map → page-D77AjrZW.js.map} +1 -1
  51. package/dist/assets/{page-DayDCUEn.js → page-D7qEC0QY.js} +2 -2
  52. package/dist/assets/{page-DayDCUEn.js.map → page-D7qEC0QY.js.map} +1 -1
  53. package/dist/assets/{page-DnbS5nGR.js → page-DA0znMx6.js} +2 -2
  54. package/dist/assets/{page-DnbS5nGR.js.map → page-DA0znMx6.js.map} +1 -1
  55. package/dist/assets/{page-ciRM605J.js → page-DwQP9ZTM.js} +2 -2
  56. package/dist/assets/{page-ciRM605J.js.map → page-DwQP9ZTM.js.map} +1 -1
  57. package/dist/assets/{page-BBlT4pdR.js → page-MyIklHT7.js} +2 -2
  58. package/dist/assets/{page-BBlT4pdR.js.map → page-MyIklHT7.js.map} +1 -1
  59. package/dist/assets/{page-B209dGEN.js → page-VpcpXQSK.js} +2 -2
  60. package/dist/assets/{page-B209dGEN.js.map → page-VpcpXQSK.js.map} +1 -1
  61. package/dist/assets/{page-BZ2PDkOm.js → page-bnSUmwNQ.js} +2 -2
  62. package/dist/assets/{page-BZ2PDkOm.js.map → page-bnSUmwNQ.js.map} +1 -1
  63. package/dist/assets/{page-C8k0U1_B.js → page-kZNdnhdh.js} +2 -2
  64. package/dist/assets/{page-C8k0U1_B.js.map → page-kZNdnhdh.js.map} +1 -1
  65. package/dist/assets/{page-QmDs_FHZ.js → page-n2Dj9C-v.js} +2 -2
  66. package/dist/assets/{page-QmDs_FHZ.js.map → page-n2Dj9C-v.js.map} +1 -1
  67. package/dist/assets/{privacy-B1CWCygr.js → privacy-D5H-YTl9.js} +2 -2
  68. package/dist/assets/{privacy-B1CWCygr.js.map → privacy-D5H-YTl9.js.map} +1 -1
  69. package/dist/assets/{routing-BhiBwewL.js → routing-CBiIPmyX.js} +2 -2
  70. package/dist/assets/{routing-BhiBwewL.js.map → routing-CBiIPmyX.js.map} +1 -1
  71. package/dist/assets/{routing-QElszVRP.js → routing-tt0MahYa.js} +2 -2
  72. package/dist/assets/{routing-QElszVRP.js.map → routing-tt0MahYa.js.map} +1 -1
  73. package/dist/assets/{useAuth-ByOA13lp.js → useAuth-Bw_w8L0H.js} +2 -2
  74. package/dist/assets/{useAuth-ByOA13lp.js.map → useAuth-Bw_w8L0H.js.map} +1 -1
  75. package/dist/index.html +1 -1
  76. package/package.json +1 -1
  77. package/server.js +18 -2
  78. package/dist/assets/AuthContext-BVzUcaCU.js +0 -2
  79. package/dist/assets/AuthContext-BVzUcaCU.js.map +0 -1
  80. package/dist/assets/page-amCJRFD1.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"privacy-B1CWCygr.js","sources":["../../src/components/modals/GlobalSearchModal.tsx","../../src/contexts/KeyboardShortcutsContext.tsx","../../src/lib/cookies/constants.ts","../../src/lib/cookies/cleanup.ts","../../src/lib/cookies/consent.ts","../../src/lib/cookies/privacy.ts"],"sourcesContent":["import React from 'react';\nimport { useRouter } from '@/i18n/routing';\nimport { SearchModal } from '@semiont/react-ui';\nimport { useTranslation } from 'react-i18next';\n\ninterface GlobalSearchModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function GlobalSearchModal({ isOpen, onClose }: GlobalSearchModalProps) {\n const router = useRouter();\n const { t: _t } = useTranslation();\n const t = (k: string, p?: Record<string, unknown>) => _t(`Search.${k}`, p as any) as string;\n\n const handleNavigate = (type: 'resource' | 'entity', id: string) => {\n if (type === 'resource') {\n router.push(`/know/resource/${encodeURIComponent(id)}`);\n } else {\n router.push(`/know/entity/${id}`);\n }\n };\n\n return (\n <SearchModal\n isOpen={isOpen}\n onClose={onClose}\n onNavigate={handleNavigate}\n translations={{\n placeholder: t('placeholder'),\n searching: t('searching'),\n noResults: t('noResults'),\n startTyping: t('startTyping'),\n navigate: t('navigate'),\n select: t('select'),\n close: t('close'),\n enter: t('enter'),\n esc: t('esc'),\n }}\n />\n );\n}","import React, { createContext, useContext, useState, useCallback } from 'react';\nimport { useRouter } from '@/i18n/routing';\nimport { useKeyboardShortcuts, useDoubleKeyPress, KeyboardShortcutsHelpModal } from '@semiont/react-ui';\nimport { GlobalSearchModal } from '../components/modals/GlobalSearchModal';\n\ninterface KeyboardShortcutsContextType {\n openGlobalSearch: () => void;\n openKeyboardHelp: () => void;\n closeAllOverlays: () => void;\n}\n\nexport const KeyboardShortcutsContext = createContext<KeyboardShortcutsContextType | null>(null);\n\nexport function useKeyboardShortcutsContext() {\n const context = useContext(KeyboardShortcutsContext);\n if (!context) {\n throw new Error('useKeyboardShortcutsContext must be used within KeyboardShortcutsProvider');\n }\n return context;\n}\n\ninterface KeyboardShortcutsProviderProps {\n children: React.ReactNode;\n}\n\nexport function KeyboardShortcutsProvider({ children }: KeyboardShortcutsProviderProps) {\n const router = useRouter();\n const [isSearchOpen, setIsSearchOpen] = useState(false);\n const [isHelpOpen, setIsHelpOpen] = useState(false);\n const [overlayCloseCallbacks, setOverlayCloseCallbacks] = useState<(() => void)[]>([]);\n\n // Open global search\n const openGlobalSearch = useCallback(() => {\n setIsSearchOpen(true);\n }, []);\n\n // Open keyboard help\n const openKeyboardHelp = useCallback(() => {\n setIsHelpOpen(true);\n }, []);\n\n // Close all overlays\n const closeAllOverlays = useCallback(() => {\n // Close all modals\n setIsSearchOpen(false);\n setIsHelpOpen(false);\n\n // Call all registered overlay close callbacks\n overlayCloseCallbacks.forEach(callback => callback());\n\n // Clear the callbacks\n setOverlayCloseCallbacks([]);\n }, [overlayCloseCallbacks]);\n\n // Register global keyboard shortcuts\n useKeyboardShortcuts([\n {\n key: 'k',\n ctrlOrCmd: true,\n handler: () => {\n openGlobalSearch();\n },\n description: 'Open global search'\n },\n {\n key: 'n',\n ctrlOrCmd: true,\n handler: () => {\n // Navigate to compose page to create new resource\n router.push('/know/compose');\n },\n description: 'Create new resource'\n },\n {\n key: '/',\n handler: () => {\n // Alternative search trigger (like GitHub)\n openGlobalSearch();\n },\n description: 'Open global search (alternative)'\n },\n {\n key: '?',\n shift: true,\n handler: () => {\n // Open keyboard shortcuts help\n openKeyboardHelp();\n },\n description: 'Show keyboard shortcuts help'\n }\n ]);\n\n // Double Escape to close all overlays\n useDoubleKeyPress('Escape', closeAllOverlays, 300);\n\n const contextValue: KeyboardShortcutsContextType = {\n openGlobalSearch,\n openKeyboardHelp,\n closeAllOverlays\n };\n\n return (\n <KeyboardShortcutsContext.Provider value={contextValue}>\n {children}\n {isSearchOpen && (\n <GlobalSearchModal\n isOpen={isSearchOpen}\n onClose={() => setIsSearchOpen(false)}\n />\n )}\n {isHelpOpen && (\n <KeyboardShortcutsHelpModal\n isOpen={isHelpOpen}\n onClose={() => setIsHelpOpen(false)}\n />\n )}\n </KeyboardShortcutsContext.Provider>\n );\n}","import type { CookieCategory, CookieConsent } from './types';\n\n// Cookie categories with descriptions\nexport const COOKIE_CATEGORIES: CookieCategory[] = [\n {\n id: 'necessary',\n name: 'Strictly Necessary',\n description: 'These cookies are essential for the website to function properly. They enable core functionality such as security, network management, and accessibility.',\n required: true,\n cookies: ['semiont-token', 'consent-preferences']\n },\n {\n id: 'analytics',\n name: 'Analytics',\n description: 'These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously.',\n required: false,\n cookies: ['_ga', '_ga_*', '_gid', '_gat', 'lighthouse-*']\n },\n {\n id: 'marketing',\n name: 'Marketing',\n description: 'These cookies are used to track visitors across websites to display relevant advertisements and measure campaign effectiveness.',\n required: false,\n cookies: ['_fbp', '_fbc', 'fr', 'ads-*']\n },\n {\n id: 'preferences',\n name: 'Preferences',\n description: 'These cookies remember your choices and preferences to provide a more personalized experience.',\n required: false,\n cookies: ['theme-preference', 'language-preference', 'ui-settings']\n }\n];\n\n// Current consent version (increment when privacy policy changes)\nexport const CONSENT_VERSION = '1.0';\n\n// Cookie names\nexport const CONSENT_COOKIE_NAME = 'semiont-cookie-consent';\nexport const PREFERENCES_COOKIE_NAME = 'semiont-cookie-preferences';\n\n// Default consent state\nexport const DEFAULT_CONSENT: CookieConsent = {\n necessary: true, // Always true, required for functionality\n analytics: false,\n marketing: false,\n preferences: false,\n timestamp: new Date().toISOString(),\n version: CONSENT_VERSION\n};\n","import type { CookieConsent } from './types';\nimport { COOKIE_CATEGORIES } from './constants';\n\n// Clean up cookies based on consent\nexport const cleanupCookies = (consent: CookieConsent): void => {\n if (typeof window === 'undefined') return;\n\n COOKIE_CATEGORIES.forEach(category => {\n if (category.required) return; // Never clean up required cookies\n\n const hasConsent = consent[category.id];\n if (!hasConsent) {\n // Remove cookies for this category\n category.cookies.forEach(cookieName => {\n if (cookieName.includes('*')) {\n // Handle wildcard cookies\n const prefix = cookieName.replace('*', '');\n document.cookie.split(';').forEach(cookie => {\n const name = cookie.split('=')[0]?.trim();\n if (name && name.startsWith(prefix)) {\n deleteCookie(name);\n }\n });\n } else {\n deleteCookie(cookieName);\n }\n });\n }\n });\n};\n\n// Delete a specific cookie\nexport const deleteCookie = (name: string): void => {\n // Delete for current domain\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n // Delete for parent domain\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${window.location.hostname}`;\n // Delete for root domain\n const rootDomain = window.location.hostname.split('.').slice(-2).join('.');\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${rootDomain}`;\n};\n","import type { CookieConsent } from './types';\nimport { CONSENT_COOKIE_NAME, CONSENT_VERSION, DEFAULT_CONSENT } from './constants';\nimport { cleanupCookies } from './cleanup';\n\nexport const getCookieConsent = (): CookieConsent | null => {\n if (typeof window === 'undefined') return null;\n\n try {\n const consent = localStorage.getItem(CONSENT_COOKIE_NAME);\n if (!consent) return null;\n\n const parsed = JSON.parse(consent) as CookieConsent;\n\n // Check if consent is for current version\n if (parsed.version !== CONSENT_VERSION) {\n return null; // Force re-consent for new version\n }\n\n return parsed;\n } catch (error) {\n console.warn('Failed to parse cookie consent:', error);\n return null;\n }\n};\n\nexport const setCookieConsent = (consent: Partial<CookieConsent>): void => {\n if (typeof window === 'undefined') return;\n\n const fullConsent: CookieConsent = {\n ...DEFAULT_CONSENT,\n ...consent,\n necessary: true, // Always true\n timestamp: new Date().toISOString(),\n version: CONSENT_VERSION\n };\n\n try {\n localStorage.setItem(CONSENT_COOKIE_NAME, JSON.stringify(fullConsent));\n\n // Clean up cookies based on consent\n cleanupCookies(fullConsent);\n\n // Dispatch custom event for components to react to consent changes\n window.dispatchEvent(new CustomEvent('cookieConsentChanged', {\n detail: fullConsent\n }));\n } catch (error) {\n console.error('Failed to save cookie consent:', error);\n }\n};\n\nexport const hasValidConsent = (): boolean => {\n const consent = getCookieConsent();\n if (!consent) return false;\n\n // Check if consent is less than 13 months old (GDPR requirement)\n const consentDate = new Date(consent.timestamp);\n const thirteenMonthsAgo = new Date();\n thirteenMonthsAgo.setMonth(thirteenMonthsAgo.getMonth() - 13);\n\n return consentDate > thirteenMonthsAgo;\n};\n\nexport const shouldShowBanner = (): boolean => {\n if (typeof window === 'undefined') return false;\n return !hasValidConsent();\n};\n","import { deleteCookie } from './cleanup';\n\n// Get user's location for CCPA vs GDPR detection (simplified)\nexport const getUserLocation = async (): Promise<'EU' | 'CA' | 'US' | 'OTHER'> => {\n try {\n // In a real implementation, you'd use a geolocation service\n // For now, we'll detect based on timezone as a rough approximation\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n if (timezone.includes('Europe/')) return 'EU';\n if (timezone.includes('America/Los_Angeles') || timezone.includes('America/Vancouver')) return 'CA';\n if (timezone.includes('America/')) return 'US';\n\n return 'OTHER';\n } catch {\n return 'OTHER';\n }\n};\n\n// Check if CCPA applies (California residents)\nexport const isCCPAApplicable = async (): Promise<boolean> => {\n const location = await getUserLocation();\n return location === 'CA';\n};\n\n// Check if GDPR applies (EU residents)\nexport const isGDPRApplicable = async (): Promise<boolean> => {\n const location = await getUserLocation();\n return location === 'EU';\n};\n\n// Export all cookies currently set\nexport const exportUserData = (): Record<string, string> => {\n if (typeof window === 'undefined') return {};\n\n const data: Record<string, string> = {};\n\n // Get all cookies\n document.cookie.split(';').forEach(cookie => {\n const [name, value] = cookie.trim().split('=');\n if (name && value) {\n data[`cookie_${name}`] = decodeURIComponent(value);\n }\n });\n\n // Get localStorage data\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key) {\n data[`localStorage_${key}`] = localStorage.getItem(key) || '';\n }\n }\n\n // Get sessionStorage data\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (key) {\n data[`sessionStorage_${key}`] = sessionStorage.getItem(key) || '';\n }\n }\n\n return data;\n};\n\n// Delete all user data (GDPR right to be forgotten)\nexport const deleteAllUserData = (): void => {\n if (typeof window === 'undefined') return;\n\n // Clear all localStorage\n localStorage.clear();\n\n // Clear all sessionStorage\n sessionStorage.clear();\n\n // Delete all cookies\n document.cookie.split(';').forEach(cookie => {\n const name = cookie.split('=')[0]?.trim();\n if (name) {\n deleteCookie(name);\n }\n });\n\n // Reload page to ensure clean state\n window.location.reload();\n};\n"],"names":["GlobalSearchModal","isOpen","onClose","router","useRouter","_t","useTranslation","t","k","p","handleNavigate","type","id","jsx","SearchModal","KeyboardShortcutsContext","createContext","KeyboardShortcutsProvider","children","isSearchOpen","setIsSearchOpen","useState","isHelpOpen","setIsHelpOpen","overlayCloseCallbacks","setOverlayCloseCallbacks","openGlobalSearch","useCallback","openKeyboardHelp","closeAllOverlays","callback","useKeyboardShortcuts","useDoubleKeyPress","contextValue","jsxs","KeyboardShortcutsHelpModal","COOKIE_CATEGORIES","CONSENT_VERSION","CONSENT_COOKIE_NAME","DEFAULT_CONSENT","cleanupCookies","consent","category","cookieName","prefix","cookie","name","_a","deleteCookie","rootDomain","getCookieConsent","parsed","error","setCookieConsent","fullConsent","hasValidConsent","consentDate","thirteenMonthsAgo","shouldShowBanner","getUserLocation","timezone","isCCPAApplicable","isGDPRApplicable","exportUserData","data","value","i","key","deleteAllUserData"],"mappings":"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"}
1
+ {"version":3,"file":"privacy-D5H-YTl9.js","sources":["../../src/components/modals/GlobalSearchModal.tsx","../../src/contexts/KeyboardShortcutsContext.tsx","../../src/lib/cookies/constants.ts","../../src/lib/cookies/cleanup.ts","../../src/lib/cookies/consent.ts","../../src/lib/cookies/privacy.ts"],"sourcesContent":["import React from 'react';\nimport { useRouter } from '@/i18n/routing';\nimport { SearchModal } from '@semiont/react-ui';\nimport { useTranslation } from 'react-i18next';\n\ninterface GlobalSearchModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function GlobalSearchModal({ isOpen, onClose }: GlobalSearchModalProps) {\n const router = useRouter();\n const { t: _t } = useTranslation();\n const t = (k: string, p?: Record<string, unknown>) => _t(`Search.${k}`, p as any) as string;\n\n const handleNavigate = (type: 'resource' | 'entity', id: string) => {\n if (type === 'resource') {\n router.push(`/know/resource/${encodeURIComponent(id)}`);\n } else {\n router.push(`/know/entity/${id}`);\n }\n };\n\n return (\n <SearchModal\n isOpen={isOpen}\n onClose={onClose}\n onNavigate={handleNavigate}\n translations={{\n placeholder: t('placeholder'),\n searching: t('searching'),\n noResults: t('noResults'),\n startTyping: t('startTyping'),\n navigate: t('navigate'),\n select: t('select'),\n close: t('close'),\n enter: t('enter'),\n esc: t('esc'),\n }}\n />\n );\n}","import React, { createContext, useContext, useState, useCallback } from 'react';\nimport { useRouter } from '@/i18n/routing';\nimport { useKeyboardShortcuts, useDoubleKeyPress, KeyboardShortcutsHelpModal } from '@semiont/react-ui';\nimport { GlobalSearchModal } from '../components/modals/GlobalSearchModal';\n\ninterface KeyboardShortcutsContextType {\n openGlobalSearch: () => void;\n openKeyboardHelp: () => void;\n closeAllOverlays: () => void;\n}\n\nexport const KeyboardShortcutsContext = createContext<KeyboardShortcutsContextType | null>(null);\n\nexport function useKeyboardShortcutsContext() {\n const context = useContext(KeyboardShortcutsContext);\n if (!context) {\n throw new Error('useKeyboardShortcutsContext must be used within KeyboardShortcutsProvider');\n }\n return context;\n}\n\ninterface KeyboardShortcutsProviderProps {\n children: React.ReactNode;\n}\n\nexport function KeyboardShortcutsProvider({ children }: KeyboardShortcutsProviderProps) {\n const router = useRouter();\n const [isSearchOpen, setIsSearchOpen] = useState(false);\n const [isHelpOpen, setIsHelpOpen] = useState(false);\n const [overlayCloseCallbacks, setOverlayCloseCallbacks] = useState<(() => void)[]>([]);\n\n // Open global search\n const openGlobalSearch = useCallback(() => {\n setIsSearchOpen(true);\n }, []);\n\n // Open keyboard help\n const openKeyboardHelp = useCallback(() => {\n setIsHelpOpen(true);\n }, []);\n\n // Close all overlays\n const closeAllOverlays = useCallback(() => {\n // Close all modals\n setIsSearchOpen(false);\n setIsHelpOpen(false);\n\n // Call all registered overlay close callbacks\n overlayCloseCallbacks.forEach(callback => callback());\n\n // Clear the callbacks\n setOverlayCloseCallbacks([]);\n }, [overlayCloseCallbacks]);\n\n // Register global keyboard shortcuts\n useKeyboardShortcuts([\n {\n key: 'k',\n ctrlOrCmd: true,\n handler: () => {\n openGlobalSearch();\n },\n description: 'Open global search'\n },\n {\n key: 'n',\n ctrlOrCmd: true,\n handler: () => {\n // Navigate to compose page to create new resource\n router.push('/know/compose');\n },\n description: 'Create new resource'\n },\n {\n key: '/',\n handler: () => {\n // Alternative search trigger (like GitHub)\n openGlobalSearch();\n },\n description: 'Open global search (alternative)'\n },\n {\n key: '?',\n shift: true,\n handler: () => {\n // Open keyboard shortcuts help\n openKeyboardHelp();\n },\n description: 'Show keyboard shortcuts help'\n }\n ]);\n\n // Double Escape to close all overlays\n useDoubleKeyPress('Escape', closeAllOverlays, 300);\n\n const contextValue: KeyboardShortcutsContextType = {\n openGlobalSearch,\n openKeyboardHelp,\n closeAllOverlays\n };\n\n return (\n <KeyboardShortcutsContext.Provider value={contextValue}>\n {children}\n {isSearchOpen && (\n <GlobalSearchModal\n isOpen={isSearchOpen}\n onClose={() => setIsSearchOpen(false)}\n />\n )}\n {isHelpOpen && (\n <KeyboardShortcutsHelpModal\n isOpen={isHelpOpen}\n onClose={() => setIsHelpOpen(false)}\n />\n )}\n </KeyboardShortcutsContext.Provider>\n );\n}","import type { CookieCategory, CookieConsent } from './types';\n\n// Cookie categories with descriptions\nexport const COOKIE_CATEGORIES: CookieCategory[] = [\n {\n id: 'necessary',\n name: 'Strictly Necessary',\n description: 'These cookies are essential for the website to function properly. They enable core functionality such as security, network management, and accessibility.',\n required: true,\n cookies: ['semiont-token', 'consent-preferences']\n },\n {\n id: 'analytics',\n name: 'Analytics',\n description: 'These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously.',\n required: false,\n cookies: ['_ga', '_ga_*', '_gid', '_gat', 'lighthouse-*']\n },\n {\n id: 'marketing',\n name: 'Marketing',\n description: 'These cookies are used to track visitors across websites to display relevant advertisements and measure campaign effectiveness.',\n required: false,\n cookies: ['_fbp', '_fbc', 'fr', 'ads-*']\n },\n {\n id: 'preferences',\n name: 'Preferences',\n description: 'These cookies remember your choices and preferences to provide a more personalized experience.',\n required: false,\n cookies: ['theme-preference', 'language-preference', 'ui-settings']\n }\n];\n\n// Current consent version (increment when privacy policy changes)\nexport const CONSENT_VERSION = '1.0';\n\n// Cookie names\nexport const CONSENT_COOKIE_NAME = 'semiont-cookie-consent';\nexport const PREFERENCES_COOKIE_NAME = 'semiont-cookie-preferences';\n\n// Default consent state\nexport const DEFAULT_CONSENT: CookieConsent = {\n necessary: true, // Always true, required for functionality\n analytics: false,\n marketing: false,\n preferences: false,\n timestamp: new Date().toISOString(),\n version: CONSENT_VERSION\n};\n","import type { CookieConsent } from './types';\nimport { COOKIE_CATEGORIES } from './constants';\n\n// Clean up cookies based on consent\nexport const cleanupCookies = (consent: CookieConsent): void => {\n if (typeof window === 'undefined') return;\n\n COOKIE_CATEGORIES.forEach(category => {\n if (category.required) return; // Never clean up required cookies\n\n const hasConsent = consent[category.id];\n if (!hasConsent) {\n // Remove cookies for this category\n category.cookies.forEach(cookieName => {\n if (cookieName.includes('*')) {\n // Handle wildcard cookies\n const prefix = cookieName.replace('*', '');\n document.cookie.split(';').forEach(cookie => {\n const name = cookie.split('=')[0]?.trim();\n if (name && name.startsWith(prefix)) {\n deleteCookie(name);\n }\n });\n } else {\n deleteCookie(cookieName);\n }\n });\n }\n });\n};\n\n// Delete a specific cookie\nexport const deleteCookie = (name: string): void => {\n // Delete for current domain\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n // Delete for parent domain\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${window.location.hostname}`;\n // Delete for root domain\n const rootDomain = window.location.hostname.split('.').slice(-2).join('.');\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${rootDomain}`;\n};\n","import type { CookieConsent } from './types';\nimport { CONSENT_COOKIE_NAME, CONSENT_VERSION, DEFAULT_CONSENT } from './constants';\nimport { cleanupCookies } from './cleanup';\n\nexport const getCookieConsent = (): CookieConsent | null => {\n if (typeof window === 'undefined') return null;\n\n try {\n const consent = localStorage.getItem(CONSENT_COOKIE_NAME);\n if (!consent) return null;\n\n const parsed = JSON.parse(consent) as CookieConsent;\n\n // Check if consent is for current version\n if (parsed.version !== CONSENT_VERSION) {\n return null; // Force re-consent for new version\n }\n\n return parsed;\n } catch (error) {\n console.warn('Failed to parse cookie consent:', error);\n return null;\n }\n};\n\nexport const setCookieConsent = (consent: Partial<CookieConsent>): void => {\n if (typeof window === 'undefined') return;\n\n const fullConsent: CookieConsent = {\n ...DEFAULT_CONSENT,\n ...consent,\n necessary: true, // Always true\n timestamp: new Date().toISOString(),\n version: CONSENT_VERSION\n };\n\n try {\n localStorage.setItem(CONSENT_COOKIE_NAME, JSON.stringify(fullConsent));\n\n // Clean up cookies based on consent\n cleanupCookies(fullConsent);\n\n // Dispatch custom event for components to react to consent changes\n window.dispatchEvent(new CustomEvent('cookieConsentChanged', {\n detail: fullConsent\n }));\n } catch (error) {\n console.error('Failed to save cookie consent:', error);\n }\n};\n\nexport const hasValidConsent = (): boolean => {\n const consent = getCookieConsent();\n if (!consent) return false;\n\n // Check if consent is less than 13 months old (GDPR requirement)\n const consentDate = new Date(consent.timestamp);\n const thirteenMonthsAgo = new Date();\n thirteenMonthsAgo.setMonth(thirteenMonthsAgo.getMonth() - 13);\n\n return consentDate > thirteenMonthsAgo;\n};\n\nexport const shouldShowBanner = (): boolean => {\n if (typeof window === 'undefined') return false;\n return !hasValidConsent();\n};\n","import { deleteCookie } from './cleanup';\n\n// Get user's location for CCPA vs GDPR detection (simplified)\nexport const getUserLocation = async (): Promise<'EU' | 'CA' | 'US' | 'OTHER'> => {\n try {\n // In a real implementation, you'd use a geolocation service\n // For now, we'll detect based on timezone as a rough approximation\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n if (timezone.includes('Europe/')) return 'EU';\n if (timezone.includes('America/Los_Angeles') || timezone.includes('America/Vancouver')) return 'CA';\n if (timezone.includes('America/')) return 'US';\n\n return 'OTHER';\n } catch {\n return 'OTHER';\n }\n};\n\n// Check if CCPA applies (California residents)\nexport const isCCPAApplicable = async (): Promise<boolean> => {\n const location = await getUserLocation();\n return location === 'CA';\n};\n\n// Check if GDPR applies (EU residents)\nexport const isGDPRApplicable = async (): Promise<boolean> => {\n const location = await getUserLocation();\n return location === 'EU';\n};\n\n// Export all cookies currently set\nexport const exportUserData = (): Record<string, string> => {\n if (typeof window === 'undefined') return {};\n\n const data: Record<string, string> = {};\n\n // Get all cookies\n document.cookie.split(';').forEach(cookie => {\n const [name, value] = cookie.trim().split('=');\n if (name && value) {\n data[`cookie_${name}`] = decodeURIComponent(value);\n }\n });\n\n // Get localStorage data\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key) {\n data[`localStorage_${key}`] = localStorage.getItem(key) || '';\n }\n }\n\n // Get sessionStorage data\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (key) {\n data[`sessionStorage_${key}`] = sessionStorage.getItem(key) || '';\n }\n }\n\n return data;\n};\n\n// Delete all user data (GDPR right to be forgotten)\nexport const deleteAllUserData = (): void => {\n if (typeof window === 'undefined') return;\n\n // Clear all localStorage\n localStorage.clear();\n\n // Clear all sessionStorage\n sessionStorage.clear();\n\n // Delete all cookies\n document.cookie.split(';').forEach(cookie => {\n const name = cookie.split('=')[0]?.trim();\n if (name) {\n deleteCookie(name);\n }\n });\n\n // Reload page to ensure clean state\n window.location.reload();\n};\n"],"names":["GlobalSearchModal","isOpen","onClose","router","useRouter","_t","useTranslation","t","k","p","handleNavigate","type","id","jsx","SearchModal","KeyboardShortcutsContext","createContext","KeyboardShortcutsProvider","children","isSearchOpen","setIsSearchOpen","useState","isHelpOpen","setIsHelpOpen","overlayCloseCallbacks","setOverlayCloseCallbacks","openGlobalSearch","useCallback","openKeyboardHelp","closeAllOverlays","callback","useKeyboardShortcuts","useDoubleKeyPress","contextValue","jsxs","KeyboardShortcutsHelpModal","COOKIE_CATEGORIES","CONSENT_VERSION","CONSENT_COOKIE_NAME","DEFAULT_CONSENT","cleanupCookies","consent","category","cookieName","prefix","cookie","name","_a","deleteCookie","rootDomain","getCookieConsent","parsed","error","setCookieConsent","fullConsent","hasValidConsent","consentDate","thirteenMonthsAgo","shouldShowBanner","getUserLocation","timezone","isCCPAApplicable","isGDPRApplicable","exportUserData","data","value","i","key","deleteAllUserData"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{L as o}from"./routing-QElszVRP.js";const s=o,a={resourceDetail:e=>`/know/resource/${e}`,userProfile:e=>`/users/${e}`,search:e=>`/search?q=${encodeURIComponent(e)}`,home:()=>"/",about:()=>"/about",privacy:()=>"/privacy",terms:()=>"/terms",knowledge:()=>"/know",moderate:()=>"/moderate",admin:()=>"/admin"};export{s as L,a as r};
2
- //# sourceMappingURL=routing-BhiBwewL.js.map
1
+ import{L as o}from"./routing-tt0MahYa.js";const s=o,a={resourceDetail:e=>`/know/resource/${e}`,userProfile:e=>`/users/${e}`,search:e=>`/search?q=${encodeURIComponent(e)}`,home:()=>"/",about:()=>"/about",privacy:()=>"/privacy",terms:()=>"/terms",knowledge:()=>"/know",moderate:()=>"/moderate",admin:()=>"/admin"};export{s as L,a as r};
2
+ //# sourceMappingURL=routing-CBiIPmyX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routing-BhiBwewL.js","sources":["../../src/lib/routing.ts"],"sourcesContent":["/**\n * Next.js routing configuration for Semiont frontend\n *\n * This module provides the concrete implementation of the RoutingContext\n * interface for the Next.js-based frontend application.\n */\n\nimport { Link as NextLink } from '@/i18n/routing';\nimport type { RouteBuilder, LinkComponentProps } from '@semiont/react-ui';\nimport type { ComponentType } from 'react';\n\n/**\n * Next.js Link component wrapper\n * Ensures compatibility with react-ui's LinkComponentProps interface\n */\nexport const Link: ComponentType<LinkComponentProps> = NextLink as any;\n\n/**\n * Route builder for Semiont frontend\n * Implements the RouteBuilder interface with Next.js App Router paths\n */\nexport const routes: RouteBuilder = {\n /**\n * Resource detail page\n * @param id - Resource ID\n * @returns Path to resource detail page\n */\n resourceDetail: (id: string) => `/know/resource/${id}`,\n\n /**\n * User profile page\n * @param id - User ID\n * @returns Path to user profile page\n */\n userProfile: (id: string) => `/users/${id}`,\n\n /**\n * Search page with query\n * @param query - Search query string\n * @returns Path to search page with encoded query parameter\n */\n search: (query: string) => `/search?q=${encodeURIComponent(query)}`,\n\n /**\n * Home/root page\n * @returns Path to home page\n */\n home: () => '/',\n\n /**\n * About page\n * @returns Path to about page\n */\n about: () => '/about',\n\n /**\n * Privacy policy page\n * @returns Path to privacy page\n */\n privacy: () => '/privacy',\n\n /**\n * Terms of service page\n * @returns Path to terms page\n */\n terms: () => '/terms',\n\n /**\n * Knowledge base page\n * @returns Path to knowledge page\n */\n knowledge: () => '/know',\n\n /**\n * Moderation dashboard\n * @returns Path to moderation page\n */\n moderate: () => '/moderate',\n\n /**\n * Admin dashboard\n * @returns Path to admin page\n */\n admin: () => '/admin',\n};\n"],"names":["Link","NextLink","routes","id","query"],"mappings":"0CAeO,MAAMA,EAA0CC,EAM1CC,EAAuB,CAMlC,eAAiBC,GAAe,kBAAkBA,CAAE,GAOpD,YAAcA,GAAe,UAAUA,CAAE,GAOzC,OAASC,GAAkB,aAAa,mBAAmBA,CAAK,CAAC,GAMjE,KAAM,IAAM,IAMZ,MAAO,IAAM,SAMb,QAAS,IAAM,WAMf,MAAO,IAAM,SAMb,UAAW,IAAM,QAMjB,SAAU,IAAM,YAMhB,MAAO,IAAM,QACf"}
1
+ {"version":3,"file":"routing-CBiIPmyX.js","sources":["../../src/lib/routing.ts"],"sourcesContent":["/**\n * Next.js routing configuration for Semiont frontend\n *\n * This module provides the concrete implementation of the RoutingContext\n * interface for the Next.js-based frontend application.\n */\n\nimport { Link as NextLink } from '@/i18n/routing';\nimport type { RouteBuilder, LinkComponentProps } from '@semiont/react-ui';\nimport type { ComponentType } from 'react';\n\n/**\n * Next.js Link component wrapper\n * Ensures compatibility with react-ui's LinkComponentProps interface\n */\nexport const Link: ComponentType<LinkComponentProps> = NextLink as any;\n\n/**\n * Route builder for Semiont frontend\n * Implements the RouteBuilder interface with Next.js App Router paths\n */\nexport const routes: RouteBuilder = {\n /**\n * Resource detail page\n * @param id - Resource ID\n * @returns Path to resource detail page\n */\n resourceDetail: (id: string) => `/know/resource/${id}`,\n\n /**\n * User profile page\n * @param id - User ID\n * @returns Path to user profile page\n */\n userProfile: (id: string) => `/users/${id}`,\n\n /**\n * Search page with query\n * @param query - Search query string\n * @returns Path to search page with encoded query parameter\n */\n search: (query: string) => `/search?q=${encodeURIComponent(query)}`,\n\n /**\n * Home/root page\n * @returns Path to home page\n */\n home: () => '/',\n\n /**\n * About page\n * @returns Path to about page\n */\n about: () => '/about',\n\n /**\n * Privacy policy page\n * @returns Path to privacy page\n */\n privacy: () => '/privacy',\n\n /**\n * Terms of service page\n * @returns Path to terms page\n */\n terms: () => '/terms',\n\n /**\n * Knowledge base page\n * @returns Path to knowledge page\n */\n knowledge: () => '/know',\n\n /**\n * Moderation dashboard\n * @returns Path to moderation page\n */\n moderate: () => '/moderate',\n\n /**\n * Admin dashboard\n * @returns Path to admin page\n */\n admin: () => '/admin',\n};\n"],"names":["Link","NextLink","routes","id","query"],"mappings":"0CAeO,MAAMA,EAA0CC,EAM1CC,EAAuB,CAMlC,eAAiBC,GAAe,kBAAkBA,CAAE,GAOpD,YAAcA,GAAe,UAAUA,CAAE,GAOzC,OAASC,GAAkB,aAAa,mBAAmBA,CAAK,CAAC,GAMjE,KAAM,IAAM,IAMZ,MAAO,IAAM,SAMb,QAAS,IAAM,WAMf,MAAO,IAAM,SAMb,UAAW,IAAM,QAMjB,SAAU,IAAM,YAMhB,MAAO,IAAM,QACf"}
@@ -1,2 +1,2 @@
1
- import{j as m}from"./query-ATBhtd3K.js";import{R as f,a as c,L as g,b as L,c as p}from"./vendor-EnoIVk-c.js";import{D as o,i as h}from"./index-DsKSr5Q5.js";import{u}from"./i18n-BYxb14hm.js";const k=f.forwardRef(function({to:a,...n},s){const{i18n:t}=u(),e=c(),l=t.language||e.locale||o,i=typeof a=="string"?`/${l}${a.startsWith("/")?a:`/${a}`}`:a;return m.jsx(g,{ref:s,to:i,...n})});function w(){const r=L(),{i18n:a}=u(),n=c();function s(t,e){return`/${e||a.language||n.locale||o}${t.startsWith("/")?t:`/${t}`}`}return{push(t,e){r(s(t,e==null?void 0:e.locale))},replace(t,e){r(s(t,e==null?void 0:e.locale),{replace:!0})},back(){r(-1)},forward(){r(1)},refresh(){window.location.reload()},prefetch(t){}}}function b(){const{pathname:r}=p(),a=r.match(/^\/[a-z]{2}(\/.*)?$/);return a?a[1]??"/":r}function j(){const r=c(),{i18n:a}=u(),n=r.locale;return n&&h(n)?n:a.language||o}export{k as L,w as a,b,j as u};
2
- //# sourceMappingURL=routing-QElszVRP.js.map
1
+ import{j as m}from"./query-ATBhtd3K.js";import{R as f,a as c,L as g,b as L,c as p}from"./vendor-EnoIVk-c.js";import{D as o,i as h}from"./index-IyxbPWuo.js";import{u}from"./i18n-BYxb14hm.js";const k=f.forwardRef(function({to:a,...n},s){const{i18n:t}=u(),e=c(),l=t.language||e.locale||o,i=typeof a=="string"?`/${l}${a.startsWith("/")?a:`/${a}`}`:a;return m.jsx(g,{ref:s,to:i,...n})});function w(){const r=L(),{i18n:a}=u(),n=c();function s(t,e){return`/${e||a.language||n.locale||o}${t.startsWith("/")?t:`/${t}`}`}return{push(t,e){r(s(t,e==null?void 0:e.locale))},replace(t,e){r(s(t,e==null?void 0:e.locale),{replace:!0})},back(){r(-1)},forward(){r(1)},refresh(){window.location.reload()},prefetch(t){}}}function b(){const{pathname:r}=p(),a=r.match(/^\/[a-z]{2}(\/.*)?$/);return a?a[1]??"/":r}function j(){const r=c(),{i18n:a}=u(),n=r.locale;return n&&h(n)?n:a.language||o}export{k as L,w as a,b,j as u};
2
+ //# sourceMappingURL=routing-tt0MahYa.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routing-QElszVRP.js","sources":["../../src/i18n/routing.tsx"],"sourcesContent":["/**\n * Routing abstraction layer — React Router implementation\n *\n * Replaces next-intl/navigation. All call sites import from @/i18n/routing\n * and do not need to change when the underlying router changes.\n *\n * Key behaviours:\n * - Link: locale-prefixed anchor rendered via react-router-dom\n * - useRouter: locale-aware push/replace/back\n * - usePathname: returns path WITHOUT locale prefix (matches next-intl behaviour)\n * - redirect: programmatic navigation without locale prefix\n */\n\nimport React from 'react';\nimport {\n Link as RouterLink,\n useNavigate,\n useLocation,\n useParams,\n Navigate,\n} from 'react-router-dom';\nimport { useTranslation } from 'react-i18next';\nimport { SUPPORTED_LOCALES, DEFAULT_LOCALE, isSupportedLocale } from './config';\n\nexport { SUPPORTED_LOCALES, DEFAULT_LOCALE };\n\n// ── Link ─────────────────────────────────────────────────────────────────────\n\ntype LinkProps = React.ComponentProps<typeof RouterLink>;\n\n/**\n * Locale-aware Link. Prepends the current locale to the href.\n */\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n function Link({ to, ...props }, ref) {\n const { i18n } = useTranslation();\n const params = useParams<{ locale?: string }>();\n const locale = i18n.language || params.locale || DEFAULT_LOCALE;\n const target = typeof to === 'string' ? `/${locale}${to.startsWith('/') ? to : `/${to}`}` : to;\n return <RouterLink ref={ref} to={target} {...props} />;\n },\n);\n\n// ── useRouter ─────────────────────────────────────────────────────────────────\n\ntype RouterOptions = { locale?: string };\n\nexport function useRouter() {\n const navigate = useNavigate();\n const { i18n } = useTranslation();\n const params = useParams<{ locale?: string }>();\n\n function prefixLocale(path: string, locale?: string): string {\n const lang = locale || i18n.language || params.locale || DEFAULT_LOCALE;\n return `/${lang}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n return {\n push(path: string, options?: RouterOptions) {\n navigate(prefixLocale(path, options?.locale));\n },\n replace(path: string, options?: RouterOptions) {\n navigate(prefixLocale(path, options?.locale), { replace: true });\n },\n back() {\n navigate(-1);\n },\n forward() {\n navigate(1);\n },\n refresh() {\n window.location.reload();\n },\n prefetch(_path: string) {\n // No-op: Vite/React Router handles prefetching differently\n },\n };\n}\n\n// ── usePathname ───────────────────────────────────────────────────────────────\n\n/**\n * Returns the path WITHOUT the locale prefix, matching next-intl behaviour.\n * e.g. /en/know/discover → /know/discover\n */\nexport function usePathname(): string {\n const { pathname } = useLocation();\n // Strip leading /{locale}\n const match = pathname.match(/^\\/[a-z]{2}(\\/.*)?$/);\n if (match) {\n return match[1] ?? '/';\n }\n return pathname;\n}\n\n// ── redirect ─────────────────────────────────────────────────────────────────\n\n/**\n * Render a redirect component. Pass { href, locale } to redirect with locale,\n * or just a string href to redirect to an absolute path.\n */\nexport function redirect(target: string | { href: string; locale?: string }): React.ReactElement {\n const { i18n } = useTranslation();\n const locale = typeof target === 'string' ? (i18n.language || DEFAULT_LOCALE) : (target.locale || i18n.language || DEFAULT_LOCALE);\n const href = typeof target === 'string' ? target : target.href;\n const to = `/${locale}${href.startsWith('/') ? href : `/${href}`}`;\n return <Navigate to={to} replace />;\n}\n\n// ── useParams with locale ────────────────────────────────────────────────────\n\nexport function useLocale(): string {\n const params = useParams<{ locale?: string }>();\n const { i18n } = useTranslation();\n const localeFromParams = params.locale;\n if (localeFromParams && isSupportedLocale(localeFromParams)) {\n return localeFromParams;\n }\n return i18n.language || DEFAULT_LOCALE;\n}\n"],"names":["Link","React","to","props","ref","i18n","useTranslation","params","useParams","locale","DEFAULT_LOCALE","target","RouterLink","useRouter","navigate","useNavigate","prefixLocale","path","options","_path","usePathname","pathname","useLocation","match","useLocale","localeFromParams","isSupportedLocale"],"mappings":"8LAiCO,MAAMA,EAAOC,EAAM,WACxB,SAAc,CAAE,GAAAC,EAAI,GAAGC,CAAA,EAASC,EAAK,CACnC,KAAM,CAAE,KAAAC,CAAA,EAASC,EAAA,EACXC,EAASC,EAAA,EACTC,EAASJ,EAAK,UAAYE,EAAO,QAAUG,EAC3CC,EAAS,OAAOT,GAAO,SAAW,IAAIO,CAAM,GAAGP,EAAG,WAAW,GAAG,EAAIA,EAAK,IAAIA,CAAE,EAAE,GAAKA,EAC5F,aAAQU,EAAA,CAAW,IAAAR,EAAU,GAAIO,EAAS,GAAGR,EAAO,CACtD,CACF,EAMO,SAASU,GAAY,CAC1B,MAAMC,EAAWC,EAAA,EACX,CAAE,KAAAV,CAAA,EAASC,EAAA,EACXC,EAASC,EAAA,EAEf,SAASQ,EAAaC,EAAcR,EAAyB,CAE3D,MAAO,IADMA,GAAUJ,EAAK,UAAYE,EAAO,QAAUG,CAC1C,GAAGO,EAAK,WAAW,GAAG,EAAIA,EAAO,IAAIA,CAAI,EAAE,EAC5D,CAEA,MAAO,CACL,KAAKA,EAAcC,EAAyB,CAC1CJ,EAASE,EAAaC,EAAMC,GAAA,YAAAA,EAAS,MAAM,CAAC,CAC9C,EACA,QAAQD,EAAcC,EAAyB,CAC7CJ,EAASE,EAAaC,EAAMC,GAAA,YAAAA,EAAS,MAAM,EAAG,CAAE,QAAS,GAAM,CACjE,EACA,MAAO,CACLJ,EAAS,EAAE,CACb,EACA,SAAU,CACRA,EAAS,CAAC,CACZ,EACA,SAAU,CACR,OAAO,SAAS,OAAA,CAClB,EACA,SAASK,EAAe,CAExB,CAAA,CAEJ,CAQO,SAASC,GAAsB,CACpC,KAAM,CAAE,SAAAC,CAAA,EAAaC,EAAA,EAEfC,EAAQF,EAAS,MAAM,qBAAqB,EAClD,OAAIE,EACKA,EAAM,CAAC,GAAK,IAEdF,CACT,CAkBO,SAASG,GAAoB,CAClC,MAAMjB,EAASC,EAAA,EACT,CAAE,KAAAH,CAAA,EAASC,EAAA,EACXmB,EAAmBlB,EAAO,OAChC,OAAIkB,GAAoBC,EAAkBD,CAAgB,EACjDA,EAEFpB,EAAK,UAAYK,CAC1B"}
1
+ {"version":3,"file":"routing-tt0MahYa.js","sources":["../../src/i18n/routing.tsx"],"sourcesContent":["/**\n * Routing abstraction layer — React Router implementation\n *\n * Replaces next-intl/navigation. All call sites import from @/i18n/routing\n * and do not need to change when the underlying router changes.\n *\n * Key behaviours:\n * - Link: locale-prefixed anchor rendered via react-router-dom\n * - useRouter: locale-aware push/replace/back\n * - usePathname: returns path WITHOUT locale prefix (matches next-intl behaviour)\n * - redirect: programmatic navigation without locale prefix\n */\n\nimport React from 'react';\nimport {\n Link as RouterLink,\n useNavigate,\n useLocation,\n useParams,\n Navigate,\n} from 'react-router-dom';\nimport { useTranslation } from 'react-i18next';\nimport { SUPPORTED_LOCALES, DEFAULT_LOCALE, isSupportedLocale } from './config';\n\nexport { SUPPORTED_LOCALES, DEFAULT_LOCALE };\n\n// ── Link ─────────────────────────────────────────────────────────────────────\n\ntype LinkProps = React.ComponentProps<typeof RouterLink>;\n\n/**\n * Locale-aware Link. Prepends the current locale to the href.\n */\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n function Link({ to, ...props }, ref) {\n const { i18n } = useTranslation();\n const params = useParams<{ locale?: string }>();\n const locale = i18n.language || params.locale || DEFAULT_LOCALE;\n const target = typeof to === 'string' ? `/${locale}${to.startsWith('/') ? to : `/${to}`}` : to;\n return <RouterLink ref={ref} to={target} {...props} />;\n },\n);\n\n// ── useRouter ─────────────────────────────────────────────────────────────────\n\ntype RouterOptions = { locale?: string };\n\nexport function useRouter() {\n const navigate = useNavigate();\n const { i18n } = useTranslation();\n const params = useParams<{ locale?: string }>();\n\n function prefixLocale(path: string, locale?: string): string {\n const lang = locale || i18n.language || params.locale || DEFAULT_LOCALE;\n return `/${lang}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n return {\n push(path: string, options?: RouterOptions) {\n navigate(prefixLocale(path, options?.locale));\n },\n replace(path: string, options?: RouterOptions) {\n navigate(prefixLocale(path, options?.locale), { replace: true });\n },\n back() {\n navigate(-1);\n },\n forward() {\n navigate(1);\n },\n refresh() {\n window.location.reload();\n },\n prefetch(_path: string) {\n // No-op: Vite/React Router handles prefetching differently\n },\n };\n}\n\n// ── usePathname ───────────────────────────────────────────────────────────────\n\n/**\n * Returns the path WITHOUT the locale prefix, matching next-intl behaviour.\n * e.g. /en/know/discover → /know/discover\n */\nexport function usePathname(): string {\n const { pathname } = useLocation();\n // Strip leading /{locale}\n const match = pathname.match(/^\\/[a-z]{2}(\\/.*)?$/);\n if (match) {\n return match[1] ?? '/';\n }\n return pathname;\n}\n\n// ── redirect ─────────────────────────────────────────────────────────────────\n\n/**\n * Render a redirect component. Pass { href, locale } to redirect with locale,\n * or just a string href to redirect to an absolute path.\n */\nexport function redirect(target: string | { href: string; locale?: string }): React.ReactElement {\n const { i18n } = useTranslation();\n const locale = typeof target === 'string' ? (i18n.language || DEFAULT_LOCALE) : (target.locale || i18n.language || DEFAULT_LOCALE);\n const href = typeof target === 'string' ? target : target.href;\n const to = `/${locale}${href.startsWith('/') ? href : `/${href}`}`;\n return <Navigate to={to} replace />;\n}\n\n// ── useParams with locale ────────────────────────────────────────────────────\n\nexport function useLocale(): string {\n const params = useParams<{ locale?: string }>();\n const { i18n } = useTranslation();\n const localeFromParams = params.locale;\n if (localeFromParams && isSupportedLocale(localeFromParams)) {\n return localeFromParams;\n }\n return i18n.language || DEFAULT_LOCALE;\n}\n"],"names":["Link","React","to","props","ref","i18n","useTranslation","params","useParams","locale","DEFAULT_LOCALE","target","RouterLink","useRouter","navigate","useNavigate","prefixLocale","path","options","_path","usePathname","pathname","useLocation","match","useLocale","localeFromParams","isSupportedLocale"],"mappings":"8LAiCO,MAAMA,EAAOC,EAAM,WACxB,SAAc,CAAE,GAAAC,EAAI,GAAGC,CAAA,EAASC,EAAK,CACnC,KAAM,CAAE,KAAAC,CAAA,EAASC,EAAA,EACXC,EAASC,EAAA,EACTC,EAASJ,EAAK,UAAYE,EAAO,QAAUG,EAC3CC,EAAS,OAAOT,GAAO,SAAW,IAAIO,CAAM,GAAGP,EAAG,WAAW,GAAG,EAAIA,EAAK,IAAIA,CAAE,EAAE,GAAKA,EAC5F,aAAQU,EAAA,CAAW,IAAAR,EAAU,GAAIO,EAAS,GAAGR,EAAO,CACtD,CACF,EAMO,SAASU,GAAY,CAC1B,MAAMC,EAAWC,EAAA,EACX,CAAE,KAAAV,CAAA,EAASC,EAAA,EACXC,EAASC,EAAA,EAEf,SAASQ,EAAaC,EAAcR,EAAyB,CAE3D,MAAO,IADMA,GAAUJ,EAAK,UAAYE,EAAO,QAAUG,CAC1C,GAAGO,EAAK,WAAW,GAAG,EAAIA,EAAO,IAAIA,CAAI,EAAE,EAC5D,CAEA,MAAO,CACL,KAAKA,EAAcC,EAAyB,CAC1CJ,EAASE,EAAaC,EAAMC,GAAA,YAAAA,EAAS,MAAM,CAAC,CAC9C,EACA,QAAQD,EAAcC,EAAyB,CAC7CJ,EAASE,EAAaC,EAAMC,GAAA,YAAAA,EAAS,MAAM,EAAG,CAAE,QAAS,GAAM,CACjE,EACA,MAAO,CACLJ,EAAS,EAAE,CACb,EACA,SAAU,CACRA,EAAS,CAAC,CACZ,EACA,SAAU,CACR,OAAO,SAAS,OAAA,CAClB,EACA,SAASK,EAAe,CAExB,CAAA,CAEJ,CAQO,SAASC,GAAsB,CACpC,KAAM,CAAE,SAAAC,CAAA,EAAaC,EAAA,EAEfC,EAAQF,EAAS,MAAM,qBAAqB,EAClD,OAAIE,EACKA,EAAM,CAAC,GAAK,IAEdF,CACT,CAkBO,SAASG,GAAoB,CAClC,MAAMjB,EAASC,EAAA,EACT,CAAE,KAAAH,CAAA,EAASC,EAAA,EACXmB,EAAmBlB,EAAO,OAChC,OAAIkB,GAAoBC,EAAkBD,CAAgB,EACjDA,EAEFpB,EAAK,UAAYK,CAC1B"}
@@ -1,2 +1,2 @@
1
- import{r as e}from"./vendor-EnoIVk-c.js";import{u as m}from"./AuthContext-BVzUcaCU.js";function r(){const{session:a,isLoading:n}=m();return e.useMemo(()=>{var l,o;const i=!!a,t=(a==null?void 0:a.user)??null;return{session:a,user:t,backendUser:t,token:(a==null?void 0:a.token)??null,isLoading:n,isAuthenticated:i,hasValidBackendToken:!!(a!=null&&a.token),isFullyAuthenticated:i,userDomain:(t==null?void 0:t.domain)||((l=t==null?void 0:t.email)==null?void 0:l.split("@")[1]),displayName:(t==null?void 0:t.name)??((o=t==null?void 0:t.email)==null?void 0:o.split("@")[0])??"User",avatarUrl:(t==null?void 0:t.image)??null,isAdmin:(t==null?void 0:t.isAdmin)??!1,isModerator:!1}},[a,n])}export{r as u};
2
- //# sourceMappingURL=useAuth-ByOA13lp.js.map
1
+ import{r as e}from"./vendor-EnoIVk-c.js";import{u as m}from"./AuthContext-xM132UqD.js";function r(){const{session:a,isLoading:n}=m();return e.useMemo(()=>{var l,o;const i=!!a,t=(a==null?void 0:a.user)??null;return{session:a,user:t,backendUser:t,token:(a==null?void 0:a.token)??null,isLoading:n,isAuthenticated:i,hasValidBackendToken:!!(a!=null&&a.token),isFullyAuthenticated:i,userDomain:(t==null?void 0:t.domain)||((l=t==null?void 0:t.email)==null?void 0:l.split("@")[1]),displayName:(t==null?void 0:t.name)??((o=t==null?void 0:t.email)==null?void 0:o.split("@")[0])??"User",avatarUrl:(t==null?void 0:t.image)??null,isAdmin:(t==null?void 0:t.isAdmin)??!1,isModerator:!1}},[a,n])}export{r as u};
2
+ //# sourceMappingURL=useAuth-Bw_w8L0H.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAuth-ByOA13lp.js","sources":["../../src/hooks/useAuth.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { useAuthContext } from '@/contexts/AuthContext';\n\n/**\n * Enhanced authentication hook\n */\nexport function useAuth() {\n const { session, isLoading } = useAuthContext();\n\n return useMemo(() => {\n const isAuthenticated = !!session;\n const user = session?.user ?? null;\n\n return {\n session,\n user,\n backendUser: user,\n token: session?.token ?? null,\n\n isLoading,\n isAuthenticated,\n hasValidBackendToken: !!session?.token,\n isFullyAuthenticated: isAuthenticated,\n\n userDomain: user?.domain || user?.email?.split('@')[1],\n displayName: user?.name ?? user?.email?.split('@')[0] ?? 'User',\n avatarUrl: user?.image ?? null,\n isAdmin: user?.isAdmin ?? false,\n isModerator: false,\n };\n }, [session, isLoading]);\n}\n\n/**\n * Hook for getting user preferences and settings\n */\nexport function useUserPreferences() {\n return useMemo(() => ({\n theme: 'system' as 'light' | 'dark' | 'system',\n language: 'en',\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n emailNotifications: true,\n }), []);\n}\n\n/**\n * Hook for checking user permissions\n */\nexport function usePermissions() {\n const { isFullyAuthenticated, backendUser } = useAuth();\n\n return useMemo(() => {\n if (!isFullyAuthenticated || !backendUser) {\n return { canRead: false, canWrite: false, canAdmin: false, canManageUsers: false };\n }\n return { canRead: true, canWrite: true, canAdmin: false, canManageUsers: false };\n }, [backendUser, isFullyAuthenticated]);\n}\n"],"names":["useAuth","session","isLoading","useAuthContext","useMemo","isAuthenticated","user","_a","_b"],"mappings":"uFAMO,SAASA,GAAU,CACxB,KAAM,CAAE,QAAAC,EAAS,UAAAC,CAAA,EAAcC,EAAA,EAE/B,OAAOC,EAAAA,QAAQ,IAAM,SACnB,MAAMC,EAAkB,CAAC,CAACJ,EACpBK,GAAOL,GAAA,YAAAA,EAAS,OAAQ,KAE9B,MAAO,CACL,QAAAA,EACA,KAAAK,EACA,YAAaA,EACb,OAAOL,GAAA,YAAAA,EAAS,QAAS,KAEzB,UAAAC,EACA,gBAAAG,EACA,qBAAsB,CAAC,EAACJ,GAAA,MAAAA,EAAS,OACjC,qBAAsBI,EAEtB,YAAYC,GAAA,YAAAA,EAAM,WAAUC,EAAAD,GAAA,YAAAA,EAAM,QAAN,YAAAC,EAAa,MAAM,KAAK,IACpD,aAAaD,GAAA,YAAAA,EAAM,SAAQE,EAAAF,GAAA,YAAAA,EAAM,QAAN,YAAAE,EAAa,MAAM,KAAK,KAAM,OACzD,WAAWF,GAAA,YAAAA,EAAM,QAAS,KAC1B,SAASA,GAAA,YAAAA,EAAM,UAAW,GAC1B,YAAa,EAAA,CAEjB,EAAG,CAACL,EAASC,CAAS,CAAC,CACzB"}
1
+ {"version":3,"file":"useAuth-Bw_w8L0H.js","sources":["../../src/hooks/useAuth.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { useAuthContext } from '@/contexts/AuthContext';\n\n/**\n * Enhanced authentication hook\n */\nexport function useAuth() {\n const { session, isLoading } = useAuthContext();\n\n return useMemo(() => {\n const isAuthenticated = !!session;\n const user = session?.user ?? null;\n\n return {\n session,\n user,\n backendUser: user,\n token: session?.token ?? null,\n\n isLoading,\n isAuthenticated,\n hasValidBackendToken: !!session?.token,\n isFullyAuthenticated: isAuthenticated,\n\n userDomain: user?.domain || user?.email?.split('@')[1],\n displayName: user?.name ?? user?.email?.split('@')[0] ?? 'User',\n avatarUrl: user?.image ?? null,\n isAdmin: user?.isAdmin ?? false,\n isModerator: false,\n };\n }, [session, isLoading]);\n}\n\n/**\n * Hook for getting user preferences and settings\n */\nexport function useUserPreferences() {\n return useMemo(() => ({\n theme: 'system' as 'light' | 'dark' | 'system',\n language: 'en',\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n emailNotifications: true,\n }), []);\n}\n\n/**\n * Hook for checking user permissions\n */\nexport function usePermissions() {\n const { isFullyAuthenticated, backendUser } = useAuth();\n\n return useMemo(() => {\n if (!isFullyAuthenticated || !backendUser) {\n return { canRead: false, canWrite: false, canAdmin: false, canManageUsers: false };\n }\n return { canRead: true, canWrite: true, canAdmin: false, canManageUsers: false };\n }, [backendUser, isFullyAuthenticated]);\n}\n"],"names":["useAuth","session","isLoading","useAuthContext","useMemo","isAuthenticated","user","_a","_b"],"mappings":"uFAMO,SAASA,GAAU,CACxB,KAAM,CAAE,QAAAC,EAAS,UAAAC,CAAA,EAAcC,EAAA,EAE/B,OAAOC,EAAAA,QAAQ,IAAM,SACnB,MAAMC,EAAkB,CAAC,CAACJ,EACpBK,GAAOL,GAAA,YAAAA,EAAS,OAAQ,KAE9B,MAAO,CACL,QAAAA,EACA,KAAAK,EACA,YAAaA,EACb,OAAOL,GAAA,YAAAA,EAAS,QAAS,KAEzB,UAAAC,EACA,gBAAAG,EACA,qBAAsB,CAAC,EAACJ,GAAA,MAAAA,EAAS,OACjC,qBAAsBI,EAEtB,YAAYC,GAAA,YAAAA,EAAM,WAAUC,EAAAD,GAAA,YAAAA,EAAM,QAAN,YAAAC,EAAa,MAAM,KAAK,IACpD,aAAaD,GAAA,YAAAA,EAAM,SAAQE,EAAAF,GAAA,YAAAA,EAAM,QAAN,YAAAE,EAAa,MAAM,KAAK,KAAM,OACzD,WAAWF,GAAA,YAAAA,EAAM,QAAS,KAC1B,SAASA,GAAA,YAAAA,EAAM,UAAW,GAC1B,YAAa,EAAA,CAEjB,EAAG,CAACL,EAASC,CAAS,CAAC,CACzB"}
package/dist/index.html CHANGED
@@ -11,7 +11,7 @@
11
11
  <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
12
12
  <link rel="manifest" href="/site.webmanifest" />
13
13
  <meta name="theme-color" content="#00FFFF" />
14
- <script type="module" crossorigin src="/assets/index-DsKSr5Q5.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-IyxbPWuo.js"></script>
15
15
  <link rel="modulepreload" crossorigin href="/assets/vendor-EnoIVk-c.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/query-ATBhtd3K.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/i18n-BYxb14hm.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semiont/frontend",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "Semiont frontend - pre-built Vite SPA with static file server",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -4,7 +4,11 @@
4
4
  * Serves the Vite-built dist/ directory with SPA fallback (all routes → index.html).
5
5
  *
6
6
  * Environment variables:
7
- * PORT - port to listen on (default: 3000)
7
+ * PORT - port to listen on (default: 3000)
8
+ * SEMIONT_BACKEND_URL - fallback backend URL if --bus is not passed
9
+ *
10
+ * Arguments:
11
+ * --bus <url> - backend URL injected into index.html as window.__SEMIONT_CONFIG__
8
12
  */
9
13
  'use strict';
10
14
 
@@ -14,6 +18,10 @@ const path = require('path');
14
18
 
15
19
  const PORT = parseInt(process.env.PORT || '3000', 10);
16
20
 
21
+ // --bus <url> sets the backend URL injected into the SPA at serve time
22
+ const busArgIndex = process.argv.indexOf('--bus');
23
+ const BUS_URL = busArgIndex !== -1 ? process.argv[busArgIndex + 1] : (process.env.SEMIONT_BACKEND_URL || '');
24
+
17
25
  // dist/ is a sibling of this file in the published package
18
26
  const DIST_DIR = path.join(__dirname, 'dist');
19
27
 
@@ -40,6 +48,14 @@ const MIME_TYPES = {
40
48
  };
41
49
 
42
50
  function serveFile(res, filePath, ext) {
51
+ if (ext === '.html') {
52
+ const html = fs.readFileSync(filePath, 'utf8');
53
+ const configScript = `<script>window.__SEMIONT_CONFIG__=${JSON.stringify({ backendURL: BUS_URL })};</script>`;
54
+ const injected = html.replace('</head>', `${configScript}</head>`);
55
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
56
+ res.end(injected);
57
+ return;
58
+ }
43
59
  const contentType = MIME_TYPES[ext] || 'application/octet-stream';
44
60
  res.writeHead(200, { 'Content-Type': contentType });
45
61
  fs.createReadStream(filePath).pipe(res);
@@ -61,7 +77,7 @@ const server = http.createServer((req, res) => {
61
77
  return;
62
78
  }
63
79
 
64
- // SPA fallback: all non-file routes serve index.html
80
+ // SPA fallback: all non-file routes serve index.html with runtime config injected
65
81
  const indexPath = path.join(DIST_DIR, 'index.html');
66
82
  if (!fs.existsSync(indexPath)) {
67
83
  res.writeHead(500, { 'Content-Type': 'text/plain' });
@@ -1,2 +0,0 @@
1
- import{j as f}from"./query-ATBhtd3K.js";import{r as t}from"./vendor-EnoIVk-c.js";import{a as C,c as S}from"./en-LNW2A3RA-BUa1vcQc.js";var c={};const x=c.SEMIONT_BACKEND_URL||"",I=c.SEMIONT_GOOGLE_CLIENT_ID,l=t.createContext(void 0);function d({children:e}){const[n,s]=t.useState(null),[o,E]=t.useState(!0);t.useEffect(()=>{new C({baseUrl:S(x)}).getMe().then(i=>{s({token:i.token,user:i})}).catch(()=>{s(null)}).finally(()=>{E(!1)})},[]);const r=t.useCallback(a=>{s(a)},[]),u=t.useCallback(()=>{s(null)},[]),_=t.useMemo(()=>({session:n,isLoading:o,setSession:r,clearSession:u}),[n,o,r,u]);return f.jsx(l.Provider,{value:_,children:e})}function p(){const e=t.useContext(l);if(!e)throw new Error("useAuthContext must be used within AuthProvider");return e}export{d as A,I as S,x as a,p as u};
2
- //# sourceMappingURL=AuthContext-BVzUcaCU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthContext-BVzUcaCU.js","sources":["../../src/lib/env.ts","../../src/contexts/AuthContext.tsx"],"sourcesContent":["// Environment configuration for Semiont Frontend\n// No validation at module load time - values are validated when actually used\n\n// SEMIONT_BACKEND_URL: Client-side backend URL used by the browser to call the API directly.\n// Defaults to '' (relative URLs) when running behind Envoy on the same origin.\nexport const SEMIONT_BACKEND_URL = process.env.SEMIONT_BACKEND_URL || '';\n\n// Site Configuration\nexport const SEMIONT_SITE_NAME = process.env.SEMIONT_SITE_NAME || 'Semiont';\nexport const SEMIONT_BASE_URL = process.env.SEMIONT_BASE_URL || 'http://localhost:3000';\n\n// OAuth Configuration\nexport const SEMIONT_GOOGLE_CLIENT_ID = process.env.SEMIONT_GOOGLE_CLIENT_ID;\n\n// OAuth allowed domains (comma-separated list)\nexport const SEMIONT_OAUTH_ALLOWED_DOMAINS = process.env.SEMIONT_OAUTH_ALLOWED_DOMAINS || '';\n\n// Environment helpers\nexport const isDevelopment = process.env.NODE_ENV === 'development';\nexport const isProduction = process.env.NODE_ENV === 'production';\n\n// Helper to parse allowed domains from comma-separated string\nexport function getAllowedDomains(): string[] {\n return SEMIONT_OAUTH_ALLOWED_DOMAINS\n .split(',')\n .map(d => d.trim())\n .filter(d => d.length > 0);\n}\n","import React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';\nimport { SemiontApiClient } from '@semiont/api-client';\nimport type { components } from '@semiont/core';\nimport { baseUrl } from '@semiont/core';\nimport { SEMIONT_BACKEND_URL } from '@/lib/env';\n\ntype UserInfo = components['schemas']['UserResponse'];\n\nexport interface AuthSession {\n token: string;\n user: UserInfo;\n}\n\ninterface AuthContextValue {\n session: AuthSession | null;\n isLoading: boolean;\n setSession: (session: AuthSession) => void;\n clearSession: () => void;\n}\n\nconst AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\nexport function AuthProvider({ children }: { children: React.ReactNode }) {\n const [session, setSessionState] = useState<AuthSession | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n const client = new SemiontApiClient({ baseUrl: baseUrl(SEMIONT_BACKEND_URL) });\n client.getMe()\n .then((data) => {\n setSessionState({ token: data.token, user: data });\n })\n .catch(() => {\n setSessionState(null);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, []);\n\n const setSession = useCallback((s: AuthSession) => {\n setSessionState(s);\n }, []);\n\n const clearSession = useCallback(() => {\n setSessionState(null);\n }, []);\n\n const value = useMemo(\n () => ({ session, isLoading, setSession, clearSession }),\n [session, isLoading, setSession, clearSession]\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuthContext(): AuthContextValue {\n const ctx = useContext(AuthContext);\n if (!ctx) throw new Error('useAuthContext must be used within AuthProvider');\n return ctx;\n}\n"],"names":["SEMIONT_BACKEND_URL","define_process_env_default","SEMIONT_GOOGLE_CLIENT_ID","AuthContext","createContext","AuthProvider","children","session","setSessionState","useState","isLoading","setIsLoading","useEffect","SemiontApiClient","baseUrl","data","setSession","useCallback","s","clearSession","value","useMemo","jsx","useAuthContext","ctx","useContext"],"mappings":"+IAKO,MAAMA,EAAsBC,EAAY,qBAAuB,GAOzDC,EAA2BD,EAAY,yBCQ9CE,EAAcC,EAAAA,cAA4C,MAAS,EAElE,SAASC,EAAa,CAAE,SAAAC,GAA2C,CACxE,KAAM,CAACC,EAASC,CAAe,EAAIC,EAAAA,SAA6B,IAAI,EAC9D,CAACC,EAAWC,CAAY,EAAIF,EAAAA,SAAS,EAAI,EAE/CG,EAAAA,UAAU,IAAM,CACC,IAAIC,EAAiB,CAAE,QAASC,EAAQd,CAAmB,EAAG,EACtE,MAAA,EACJ,KAAMe,GAAS,CACdP,EAAgB,CAAE,MAAOO,EAAK,MAAO,KAAMA,EAAM,CACnD,CAAC,EACA,MAAM,IAAM,CACXP,EAAgB,IAAI,CACtB,CAAC,EACA,QAAQ,IAAM,CACbG,EAAa,EAAK,CACpB,CAAC,CACL,EAAG,CAAA,CAAE,EAEL,MAAMK,EAAaC,cAAaC,GAAmB,CACjDV,EAAgBU,CAAC,CACnB,EAAG,CAAA,CAAE,EAECC,EAAeF,EAAAA,YAAY,IAAM,CACrCT,EAAgB,IAAI,CACtB,EAAG,CAAA,CAAE,EAECY,EAAQC,EAAAA,QACZ,KAAO,CAAE,QAAAd,EAAS,UAAAG,EAAW,WAAAM,EAAY,aAAAG,CAAA,GACzC,CAACZ,EAASG,EAAWM,EAAYG,CAAY,CAAA,EAG/C,OAAOG,EAAAA,IAACnB,EAAY,SAAZ,CAAqB,MAAAiB,EAAe,SAAAd,CAAA,CAAS,CACvD,CAEO,SAASiB,GAAmC,CACjD,MAAMC,EAAMC,EAAAA,WAAWtB,CAAW,EAClC,GAAI,CAACqB,EAAK,MAAM,IAAI,MAAM,iDAAiD,EAC3E,OAAOA,CACT"}
@@ -1,2 +0,0 @@
1
- import{j as r}from"./query-ATBhtd3K.js";import{u as t}from"./routing-QElszVRP.js";import{N as e}from"./vendor-EnoIVk-c.js";import"./index-DsKSr5Q5.js";import"./i18n-BYxb14hm.js";function u(){const o=t();return r.jsx(e,{to:`/${o}/admin/users`,replace:!0})}export{u as default};
2
- //# sourceMappingURL=page-amCJRFD1.js.map