lynx-console 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/components/BottomSheet.tsx","../src/hooks/useConsole.ts","../src/hooks/useNetwork.ts","../src/hooks/usePerformance.ts","../src/components/FadeList.tsx","../src/components/LogPanel.tsx","../src/components/NetworkDetailSection.tsx","../src/components/NetworkPanel.tsx","../src/components/PerformancePanel.tsx","../src/components/Tabs.tsx","../src/components/ConsolePanel.tsx","../src/hooks/useLongPressDrag.ts","../src/components/FloatingButton.tsx","../src/index.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\nimport \"./BottomSheet.css\";\n\ninterface BottomSheetProps {\n children: ReactNode;\n title?: string;\n footer?: ReactNode;\n onClose: () => void;\n isOpen: boolean;\n shouldClose?: boolean;\n safeAreaInsetBottom?: string;\n}\n\nconst MIN_HEIGHT = 200;\nconst MAX_HEIGHT = 700;\nconst DEFAULT_HEIGHT = 500;\nconst CLOSE_DRAG_THRESHOLD = 30; // 30px 이상 아래로 드래그하면 닫힘\n\n// 마지막 높이 저장\nlet savedHeight: number | null = null;\n\nexport default function BottomSheet({\n children,\n title,\n footer,\n onClose,\n isOpen,\n shouldClose = false,\n safeAreaInsetBottom = \"25px\",\n}: BottomSheetProps) {\n const [sheetHeight, setSheetHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [tempHeight, setTempHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [isDragging, setIsDragging] = useState(false);\n const [dragStartY, setDragStartY] = useState(0);\n const [dragStartHeight, setDragStartHeight] = useState(\n savedHeight ?? DEFAULT_HEIGHT,\n );\n const [isOpening, setIsOpening] = useState(true);\n const [isClosing, setIsClosing] = useState(false);\n\n // 닫기 애니메이션 처리\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => {\n onClose();\n }, 300);\n };\n\n // 아래에서 올라오는 애니메이션\n useEffect(() => {\n requestAnimationFrame(() => {\n setIsOpening(false);\n });\n }, []);\n\n // 외부에서 닫기 요청 시 애니메이션 처리\n useEffect(() => {\n if (shouldClose && !isClosing) {\n handleClose();\n }\n }, [shouldClose, isClosing]);\n\n // 높이 변경 시 저장\n useEffect(() => {\n savedHeight = sheetHeight;\n }, [sheetHeight]);\n\n if (!isOpen) return null;\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n setIsDragging(true);\n setDragStartY(e.detail.y);\n setDragStartHeight(sheetHeight);\n setTempHeight(sheetHeight);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n if (!isDragging) return;\n const deltaY = dragStartY - e.detail.y;\n const newHeight = Math.min(\n Math.max(dragStartHeight + deltaY, MIN_HEIGHT),\n MAX_HEIGHT,\n );\n setTempHeight(newHeight);\n };\n\n const handleTouchEnd = () => {\n setIsDragging(false);\n\n // 아래로 일정 30px 이상 드래그하면 닫기\n const dragDistance = dragStartHeight - tempHeight;\n setSheetHeight(tempHeight);\n if (dragDistance > CLOSE_DRAG_THRESHOLD) {\n handleClose();\n }\n };\n\n return (\n <scroll-view\n className=\"bs-backdrop\"\n style={{\n opacity: isOpening || isClosing ? 0 : 1,\n }}\n >\n <view className=\"bs-overlay\" bindtap={handleClose}>\n <view\n className=\"bs-content\"\n catchtap={() => {}}\n style={{\n height: `${isDragging ? tempHeight : sheetHeight}px`,\n transform:\n isOpening || isClosing ? \"translateY(100%)\" : \"translateY(0)\",\n transition: isDragging ? \"none\" : undefined,\n }}\n >\n {/* catchtap: 이벤트 버블링 차단 */}\n <view\n className=\"bs-handleContainer\"\n bindtouchstart={handleTouchStart}\n bindtouchmove={handleTouchMove}\n bindtouchend={handleTouchEnd}\n >\n <view className=\"bs-handle\" />\n </view>\n <view className=\"bs-header\">\n {title && <text className=\"bs-title\">{title}</text>}\n </view>\n <view\n className=\"bs-body\"\n style={{\n paddingBottom: safeAreaInsetBottom,\n }}\n >\n {children}\n </view>\n {footer && <view className=\"bs-footer\">{footer}</view>}\n </view>\n </view>\n </scroll-view>\n );\n}\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { LogEntry } from \"../types\";\n\nexport const useConsole = () => {\n const [logs, setLogs] = useState<LogEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs === \"undefined\") {\n console.warn(\"[LynxConsole] Log monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setLogs([...(state.logs ?? [])]);\n\n const updateLogs = (_entry: LogEntry) => {\n setLogs([...(state.logs ?? [])]);\n };\n\n const unsubscribe = state.logSubscribe?.(updateLogs);\n\n return unsubscribe;\n }, []);\n\n const clearLogs = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.logs = [];\n setLogs([]);\n }\n };\n\n return { logs, clearLogs };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { NetworkEntry } from \"../types\";\n\nexport const useNetwork = () => {\n const [networks, setNetworks] = useState<NetworkEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks === \"undefined\") {\n console.warn(\"[LynxConsole] Network monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setNetworks([...(state.networks ?? [])]);\n\n const updateNetworks = (_entry: NetworkEntry) => {\n setNetworks([...(state.networks ?? [])]);\n };\n\n const unsubscribe = state.subscribeNetwork?.(updateNetworks);\n\n return unsubscribe;\n }, []);\n\n const clearNetworks = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.networks = [];\n state.networksMap?.clear();\n setNetworks([]);\n }\n };\n\n return { networks, clearNetworks };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { PerformanceEntryData } from \"../types\";\n\nexport const usePerformance = () => {\n const [performances, setPerformances] = useState<PerformanceEntryData[]>([]);\n\n useEffect(() => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances === \"undefined\"\n ) {\n console.warn(\"[LynxConsole] Performance monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setPerformances([...(state.performances ?? [])]);\n\n const updatePerformances = (_entry: PerformanceEntryData) => {\n setPerformances([...(state.performances ?? [])]);\n };\n\n const unsubscribe = state.subscribePerformance?.(updatePerformances);\n\n return unsubscribe;\n }, []);\n\n const clearPerformances = () => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances !== \"undefined\"\n ) {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.performances = [];\n setPerformances([]);\n }\n };\n\n return { performances, clearPerformances };\n};\n","import { useRef } from \"@lynx-js/react\";\nimport type { NodesRef } from \"@lynx-js/types\";\n\ninterface FadeListProps {\n className?: string;\n listRef?: React.RefObject<NodesRef>;\n children: React.ReactNode;\n \"preload-buffer-count\"?: number;\n \"initial-scroll-index\"?: number;\n}\n\nexport const FadeList = ({\n className,\n listRef: externalListRef,\n children,\n ...listProps\n}: FadeListProps) => {\n const internalListRef = useRef<NodesRef>(null);\n const listRef = externalListRef ?? internalListRef;\n\n return (\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\n className={className}\n {...listProps}\n >\n {children}\n </list>\n );\n};\n","import { useEffect, useMemo, useRef, useState } from \"@lynx-js/react\";\nimport type { BaseEvent, InputInputEvent, NodesRef } from \"@lynx-js/types\";\nimport { stringify } from \"javascript-stringify\";\nimport type { LogEntry, LogLevel } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { FadeList } from \"./FadeList\";\n\nconst LOG_LEVELS: LogLevel[] = [\"log\", \"info\", \"warn\", \"error\"];\n\nlet savedEnabledLevels: Set<LogLevel> | null = null;\nlet savedSearchQuery = \"\";\nlet closeFilterDropdown: (() => void) | null = null;\n\nexport const dismissFilterDropdown = () => closeFilterDropdown?.();\n\ninterface LogPanelProps {\n logs: LogEntry[];\n clearLogs: () => void;\n}\n\nconst runCode = (code: string) => {\n try {\n // biome-ignore lint: intentional REPL tool\n const result = eval(code);\n if (result instanceof Promise) {\n result.then((r) => console.log(r)).catch((e) => console.error(e));\n } else {\n console.log(result);\n }\n } catch (e) {\n console.error(e);\n }\n};\n\nexport const LogPanel = ({ logs, clearLogs }: LogPanelProps) => {\n const [expandedArgs, setExpandedArgs] = useState(new Set());\n const [code, setCode] = useState(\"\");\n const [enabledLevels, setEnabledLevels] = useState<Set<LogLevel>>(\n () => savedEnabledLevels ?? new Set(LOG_LEVELS),\n );\n const [filterOpen, setFilterOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState(savedSearchQuery);\n const inputRef = useRef<NodesRef>(null);\n const searchInputRef = useRef<NodesRef>(null);\n const listRef = useRef<NodesRef>(null);\n\n useEffect(() => {\n savedEnabledLevels = enabledLevels;\n }, [enabledLevels]);\n\n useEffect(() => {\n savedSearchQuery = searchQuery;\n }, [searchQuery]);\n\n useEffect(() => {\n if (savedSearchQuery) {\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: savedSearchQuery } })\n .exec();\n }\n }, []);\n\n useEffect(() => {\n closeFilterDropdown = () => setFilterOpen(false);\n return () => { closeFilterDropdown = null; };\n }, []);\n\n const filteredLogs = useMemo(\n () =>\n logs.filter((log) => {\n if (!enabledLevels.has(log.level)) return false;\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return log.args.some((arg) => String(arg).toLowerCase().includes(query));\n }\n return true;\n }),\n [logs, enabledLevels, searchQuery],\n );\n const logsRef = useRef(filteredLogs);\n logsRef.current = filteredLogs;\n\n const toggleLevel = (level: LogLevel) => {\n setEnabledLevels((prev) => {\n const next = new Set(prev);\n if (next.has(level)) {\n next.delete(level);\n } else {\n next.add(level);\n }\n return next;\n });\n };\n\n const scrollToBottom = (smooth: boolean) => {\n if (logsRef.current.length === 0) return;\n listRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: { position: logsRef.current.length - 1, smooth },\n })\n .exec();\n };\n\n useEffect(() => {\n scrollToBottom(true);\n }, [filteredLogs]);\n\n const toggleArg = (key: string) => {\n setExpandedArgs((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n };\n\n const handleRun = () => {\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCode(\"\");\n inputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n runCode(trimmed);\n setTimeout(() => scrollToBottom(false), 100);\n };\n\n const renderArg = (\n arg: unknown,\n parentKey: string,\n level: \"log\" | \"info\" | \"warn\" | \"error\",\n ): React.ReactNode => {\n const key = parentKey;\n const isExpanded = expandedArgs.has(key);\n\n if (arg === null) {\n return <text className={\"cp-argNull\"}>null</text>;\n }\n\n if (arg === undefined) {\n return <text className={\"cp-argUndefined\"}>undefined</text>;\n }\n\n if (typeof arg === \"string\") {\n const MAX_LENGTH = 80;\n const shouldTruncate = arg.length > MAX_LENGTH;\n\n if (!shouldTruncate) {\n return <text className={`cp-argString cp-argString--${level}`}>{arg}</text>;\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text className={\"cp-toggleIndicator\"}>\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text className={`cp-argString cp-argString--${level}`}>\n {isExpanded ? arg : `${arg.slice(0, MAX_LENGTH)}...`}\n </text>\n </view>\n </view>\n );\n }\n\n if (typeof arg === \"number\" || typeof arg === \"boolean\") {\n return <text className={`cp-argPrimitive cp-argPrimitive--${level}`}>{String(arg)}</text>;\n }\n\n if (typeof arg === \"object\") {\n let preview = \"Object\";\n if (Array.isArray(arg)) {\n preview = `Array(${arg.length})`;\n } else if (arg instanceof Map) {\n preview = `Map(${arg.size})`;\n } else if (arg instanceof Set) {\n preview = `Set(${arg.size})`;\n } else if (arg instanceof Date) {\n preview = `Date`;\n } else if (arg instanceof RegExp) {\n preview = `RegExp`;\n } else if (arg instanceof Error) {\n preview = `${arg.constructor.name}`;\n } else if (arg?.constructor?.name && arg.constructor.name !== \"Object\") {\n preview = arg.constructor.name;\n }\n\n let jsonString: string;\n if (arg instanceof Map) {\n const entries = Array.from(arg.entries()).map(\n ([k, v]) => ` [${stringify(k)}, ${stringify(v)}]`,\n );\n jsonString = `{\\n${entries.join(\",\\n\")}\\n}`;\n } else if (arg instanceof Set) {\n const values = Array.from(arg.values()).map((v) => stringify(v));\n jsonString = `{\\n${values.join(\", \")}\\n}`;\n } else {\n jsonString =\n stringify(arg, null, 2, { references: true }) ?? String(arg);\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text className={\"cp-toggleIndicator\"}>\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text className={\"cp-argObjectPreview\"}>{preview}</text>\n </view>\n {isExpanded && (\n <view className={\"cp-argObjectContent\"}>\n <text className={\"cp-argObjectJson\"}>{jsonString}</text>\n </view>\n )}\n </view>\n );\n }\n\n return <text className={`cp-argPrimitive cp-argPrimitive--${level}`}>{String(arg)}</text>;\n };\n\n return (\n <view\n className={\"cp-logContainer\"}\n bindtap={() => { if (filterOpen) setFilterOpen(false); }}\n >\n <view className={\"cp-logHeader\"}>\n <view className={\"cp-filterWrapper\"}>\n <view\n className={\"cp-filterButton\"}\n catchtap={() => setFilterOpen((v) => !v)}\n >\n <text className={\"cp-filterButtonText\"}>Filter ▼</text>\n </view>\n {filterOpen && (\n <view className={\"cp-filterDropdown\"} catchtap={() => {}}>\n {LOG_LEVELS.map((level) => (\n <view\n key={level}\n className={\"cp-filterOption\"}\n bindtap={() => toggleLevel(level)}\n >\n <text className={`cp-filterCheckbox cp-filterCheckbox--${level}`}>\n {enabledLevels.has(level) ? \"✅\" : \"⬜\"}\n </text>\n <text className={`cp-filterLabel cp-filterLabel--${level}`}>\n {level.toUpperCase()}\n </text>\n </view>\n ))}\n </view>\n )}\n </view>\n <view className={\"cp-searchWrapper\"}>\n <text className={\"cp-searchPrompt\"}>{\"›\"}</text>\n <input\n ref={searchInputRef}\n className={\"cp-searchInput\"}\n placeholder=\"Search logs...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setSearchQuery(e.detail.value)\n }\n />\n {searchQuery.length > 0 && (\n <view\n className={\"cp-searchClear\"}\n bindtap={() => {\n setSearchQuery(\"\");\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n }}\n >\n <text className={\"cp-searchClearText\"}>✕</text>\n </view>\n )}\n </view>\n <view style={{ display: \"flex\", flexDirection: \"row\", gap: 8 }}>\n <view className={\"cp-clearButton\"} bindtap={clearLogs}>\n <text className={\"cp-clearButtonText\"}>🗑</text>\n </view>\n </view>\n </view>\n <FadeList\n listRef={listRef}\n className={\"cp-logList\"}\n preload-buffer-count={10}\n initial-scroll-index={Math.max(0, filteredLogs.length - 1)}\n >\n {filteredLogs.length === 0 ? (\n <list-item item-key=\"empty-state\">\n <view className={\"cp-placeholder\"}>\n <text className={\"cp-placeholderText\"}>\n No logs yet. Try console.log(\"Hello!\")\n </text>\n </view>\n </list-item>\n ) : (\n filteredLogs.map((log) => {\n return (\n <list-item key={log.id} item-key={log.id}>\n <view className={`cp-logItem cp-logItem--${log.level}`}>\n <view className={\"cp-logItemHeader\"}>\n <text className={`cp-logLevel cp-logLevel--${log.level}`}>\n {log.level.toUpperCase()}\n </text>\n <text className={\"cp-logTime\"}>\n {new Date(log.timestamp).toISOString()}\n </text>\n </view>\n <view className={\"cp-logArgsContainer\"}>\n {log.args.map((arg, index) => (\n <view\n key={`${log.id}-${index.toString()}`}\n className={\"cp-logArgItem\"}\n >\n {renderArg(\n arg,\n `${log.id}-${index.toString()}`,\n log.level,\n )}\n </view>\n ))}\n </view>\n </view>\n </list-item>\n );\n })\n )}\n </FadeList>\n <view className={\"cp-replInputRow\"}>\n <text className={\"cp-replPrompt\"}>{\"›\"}</text>\n <input\n ref={inputRef}\n className={\"cp-replInput\"}\n placeholder=\"enter code...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setCode(e.detail.value)\n }\n bindconfirm={handleRun}\n />\n <view className={\"cp-replRunButton\"} bindtap={handleRun}>\n <text className={\"cp-replRunButtonText\"}>Run</text>\n </view>\n </view>\n </view>\n );\n};\n","import \"./NetworkPanel.css\";\n\ninterface NetworkDetailSectionProps {\n headers?: Record<string, string> | undefined;\n body?: string | undefined;\n error?: string | undefined;\n}\n\nexport const NetworkDetailSection = ({\n headers = {},\n body = \"\",\n error = \"\",\n}: NetworkDetailSectionProps) => {\n return (\n <>\n {/* Headers */}\n <view className={\"np-detailSection\"}>\n <text className={\"np-detailSectionTitle\"}>Headers</text>\n {headers && Object.keys(headers).length > 0 ? (\n <view className={\"np-table\"}>\n {Object.entries(headers).map(([key, value]) => (\n <view key={key} className={\"np-tableRow\"}>\n <text className={\"np-tableKey\"}>{key}</text>\n <text className={\"np-tableValue\"}>{value}</text>\n </view>\n ))}\n </view>\n ) : (\n <text className={\"np-emptyText\"}>No headers</text>\n )}\n </view>\n\n {/* Body */}\n <view className={\"np-detailSection\"}>\n <text className={\"np-detailSectionTitle\"}>Body</text>\n {error && <text className={\"np-errorText\"}>{error}</text>}\n {body && <text className={\"np-bodyText\"}>{body}</text>}\n {!error && !body && <text className={\"np-emptyText\"}>No body</text>}\n </view>\n </>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport type { NetworkEntry } from \"../types\";\nimport { FadeList } from \"./FadeList\";\nimport { NetworkDetailSection } from \"./NetworkDetailSection\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkPanelProps {\n networks: NetworkEntry[];\n clearNetworks: () => void;\n}\n\ntype TabType = \"general\" | \"request\" | \"response\";\n\nexport const NetworkPanel = ({\n networks,\n clearNetworks,\n}: NetworkPanelProps) => {\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<TabType>(\"general\");\n const formatDuration = (duration?: number): string => {\n if (!duration) return \"-\";\n if (duration < 1000) return `${duration}ms`;\n return `${(duration / 1000).toFixed(2)}s`;\n };\n\n const extractPath = (url: string): string => {\n const pathMatch = url.match(/^https?:\\/\\/[^/]+(.*)$/);\n if (pathMatch?.[1]) {\n return pathMatch[1].startsWith(\"/\")\n ? pathMatch[1].slice(1)\n : pathMatch[1];\n }\n return url;\n };\n\n const getGeneralInfo = (network: NetworkEntry) => {\n return [\n { key: \"URL\", value: network.url },\n { key: \"Method\", value: network.method },\n network.statusCode\n ? { key: \"Status\", value: String(network.statusCode) }\n : null,\n {\n key: \"Request Time\",\n value: new Date(network.startTime).toISOString(),\n },\n network.endTime\n ? {\n key: \"Response Time\",\n value: new Date(network.endTime).toISOString(),\n }\n : null,\n network.duration\n ? { key: \"Duration\", value: formatDuration(network.duration) }\n : null,\n ].filter((item) => item !== null);\n };\n\n const getStatusCodeVariant = (\n status: string,\n statusCode?: number,\n ): \"success\" | \"error\" | \"pending\" => {\n if (status === \"pending\") return \"pending\";\n if (status === \"error\") return \"error\";\n if (statusCode && statusCode >= 200 && statusCode < 300) return \"success\";\n return \"error\";\n };\n\n return (\n <view className={\"np-container\"}>\n <view className={\"np-header\"}>\n <text className={\"np-count\"}>Total: {networks.length} requests</text>\n <view className={\"np-clearButton\"} bindtap={clearNetworks}>\n <text className={\"np-clearButtonText\"}>🗑</text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={\"np-placeholder\"}>\n <text className={\"np-placeholderText\"}>No network requests yet</text>\n </view>\n ) : (\n <FadeList className={\"np-list\"}>\n {networks.map((network) => (\n <list-item key={network.id} item-key={network.id}>\n <view className={`np-item np-item--${network.status}`}>\n <view\n className={\"np-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n <text\n className={`np-method np-method--${network.method}`}\n >\n {network.method}\n </text>\n {network.statusCode && (\n <text\n className={`np-statusCode np-statusCode--${getStatusCodeVariant(network.status, network.statusCode)}`}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text className={\"np-statusCode np-statusCode--pending\"}>\n Pending...\n </text>\n )}\n <text className={\"np-time\"}>\n {formatDuration(network.duration)}\n </text>\n <text className={\"np-time\"}>\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={\"np-path\"}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n {extractPath(network.url)}\n </text>\n\n {selectedId === network.id && (\n <view className={\"np-detailsContainer\"}>\n {/* Tabs */}\n <view className={\"np-tabs\"}>\n <view\n className={`np-tab${activeTab === \"general\" ? \" np-tab--active\" : \"\"}`}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={`np-tabText${activeTab === \"general\" ? \" np-tabText--active\" : \"\"}`}\n >\n General\n </text>\n </view>\n <view\n className={`np-tab${activeTab === \"request\" ? \" np-tab--active\" : \"\"}`}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={`np-tabText${activeTab === \"request\" ? \" np-tabText--active\" : \"\"}`}\n >\n Request\n </text>\n </view>\n <view\n className={`np-tab${activeTab === \"response\" ? \" np-tab--active\" : \"\"}`}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={`np-tabText${activeTab === \"response\" ? \" np-tabText--active\" : \"\"}`}\n >\n Response\n </text>\n </view>\n </view>\n\n {/* Tab Content */}\n <view className={\"np-tabContent\"}>\n {activeTab === \"general\" && (\n <view className={\"np-table\"}>\n {getGeneralInfo(network).map((item) => (\n <view key={item.key} className={\"np-tableRow\"}>\n <text className={\"np-tableKey\"}>{item.key}</text>\n <text className={\"np-tableValue\"}>\n {item.value}\n </text>\n </view>\n ))}\n </view>\n )}\n\n {activeTab === \"request\" && (\n <NetworkDetailSection\n headers={network.requestHeaders}\n body={network.requestBody}\n />\n )}\n\n {activeTab === \"response\" && (\n <NetworkDetailSection\n headers={network.responseHeaders}\n body={network.responseBody}\n error={network.error}\n />\n )}\n </view>\n </view>\n )}\n </view>\n </list-item>\n ))}\n </FadeList>\n )}\n </view>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport type { PerformanceEntryData } from \"../types\";\nimport { FadeList } from \"./FadeList\";\nimport \"./PerformancePanel.css\";\n\ninterface PerformancePanelProps {\n performances: PerformanceEntryData[];\n clearPerformances: () => void;\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst isMetricFcpEntry = (entry: PerformanceEntryData): boolean => {\n return entry.entryType === \"metric\" && entry.name === \"fcp\";\n};\n\nconst extractFcpMetrics = (entry: PerformanceEntryData) => {\n if (!isMetricFcpEntry(entry) || !entry.rawEntry) {\n return null;\n }\n\n const metricEntry = entry.rawEntry as MetricFcpEntry;\n\n return {\n totalFcp: metricEntry.totalFcp ?? undefined,\n lynxFcp: metricEntry.lynxFcp ?? undefined,\n fcp: metricEntry.fcp ?? undefined,\n };\n};\n\nconst formatDuration = (ms?: number): string => {\n if (ms === undefined) return \"-\";\n return `${ms.toFixed(2)}ms`;\n};\n\nconst getPrimaryFcpLabel = (entry: PerformanceEntryData): string => {\n const fcpMetrics = extractFcpMetrics(entry);\n if (!fcpMetrics) return \"\";\n\n const { totalFcp, lynxFcp, fcp } = fcpMetrics;\n\n if (totalFcp?.duration !== undefined) {\n return `totalFcp: ${formatDuration(totalFcp.duration)}`;\n }\n if (lynxFcp?.duration !== undefined) {\n return `lynxFcp: ${formatDuration(lynxFcp.duration)}`;\n }\n if (fcp?.duration !== undefined) {\n return `fcp: ${formatDuration(fcp.duration)}`;\n }\n return \"\";\n};\n\nexport const PerformancePanel = ({\n performances,\n clearPerformances,\n}: PerformancePanelProps) => {\n const [selectedId, setSelectedId] = useState<string | null>(null);\n if (performances.length === 0) {\n return (\n <view className={\"pp-container\"}>\n <view className={\"pp-header\"}>\n <text className={\"pp-count\"}>0 entries</text>\n <view\n bindtap={() => {\n console.log(\"[PerformancePanel] performances\", performances);\n }}\n style={{ padding: \"10px\", backgroundColor: \"red\" }}\n >\n <text>Log</text>\n </view>\n <view bindtap={clearPerformances} className={\"pp-clearButton\"}>\n <text className={\"pp-clearButtonText\"}>🗑</text>\n </view>\n </view>\n <view className={\"pp-placeholder\"}>\n <text className={\"pp-placeholderText\"}>\n No performance data yet...\n </text>\n </view>\n </view>\n );\n }\n\n return (\n <view className={\"pp-container\"}>\n <view className={\"pp-header\"}>\n <text className={\"pp-count\"}>{performances.length} entries</text>\n <view bindtap={clearPerformances} className={\"pp-clearButton\"}>\n <text className={\"pp-clearButtonText\"}>🗑</text>\n </view>\n </view>\n\n <FadeList className={\"pp-list\"}>\n {performances.map((perf) => {\n const isMetricFcp = isMetricFcpEntry(perf);\n const fcpMetrics = extractFcpMetrics(perf);\n const primaryFcp = getPrimaryFcpLabel(perf);\n const { totalFcp, lynxFcp, fcp } = fcpMetrics ?? {};\n\n return (\n <list-item key={perf.id} item-key={perf.id}>\n <view className={\"pp-item\"}>\n <view\n className={\"pp-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n <text className={`pp-entryType pp-entryType--${perf.entryType}`}>\n {perf.entryType}\n </text>\n <text className={\"pp-entryName\"}>{perf.name}</text>\n <text className={\"pp-timestamp\"}>\n {new Date(perf.timestamp).toISOString()}\n </text>\n </view>\n\n <view\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n {isMetricFcp && primaryFcp && (\n <text className={\"pp-fcpHighlight\"}>{primaryFcp}</text>\n )}\n </view>\n\n {selectedId === perf.id && (\n <view className={\"pp-detailsContainer\"}>\n {isMetricFcp && fcpMetrics && (\n <view className={\"pp-fcpSection\"}>\n {totalFcp !== undefined && (\n <view className={\"pp-fcpMetric\"}>\n <view className={\"pp-fcpMetricHeader\"}>\n <text className={\"pp-fcpMetricName\"}>\n 전체 FCP\n </text>\n <text className={\"pp-fcpMetricValue\"}>\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text className={\"pp-fcpMetricDescription\"}>\n PrepareTemplate Start부터 Paint End 까지 걸리는\n 시간\n </text>\n </view>\n )}\n\n {lynxFcp !== undefined && (\n <view className={\"pp-fcpMetric\"}>\n <view className={\"pp-fcpMetricHeader\"}>\n <text className={\"pp-fcpMetricName\"}>LynxFCP</text>\n <text className={\"pp-fcpMetricValue\"}>\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text className={\"pp-fcpMetricDescription\"}>\n Bundle Load 시작부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n\n {fcp !== undefined && (\n <view className={\"pp-fcpMetric\"}>\n <view className={\"pp-fcpMetricHeader\"}>\n <text className={\"pp-fcpMetricName\"}>\n 렌더링 FCP\n </text>\n <text className={\"pp-fcpMetricValue\"}>\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text className={\"pp-fcpMetricDescription\"}>\n TemplateBundle 준비부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n </view>\n )}\n\n {!!perf.rawEntry && (\n <view className={\"pp-rawEntrySection\"}>\n <text className={\"pp-detailTitle\"}>Raw Entry</text>\n <text className={\"pp-rawEntry\"}>\n {String(stringify(perf.rawEntry, null, 2, { references: true }))}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </FadeList>\n </view>\n );\n};\n","import { type ReactNode, useRef, useState } from \"@lynx-js/react\";\nimport type { ListSnapEvent, NodesRef } from \"@lynx-js/types\";\nimport \"./Tabs.css\";\n\ntype TabsProps = {\n items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }>;\n onTabChange?: () => void;\n};\n\nexport default function Tabs(props: TabsProps) {\n const tabContentsRef = useRef<NodesRef>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const tabSize =\n props.items.length < 4\n ? undefined\n : (`t${Math.max(1, 5 - (props.items.length - 3))}`);\n\n return (\n <view className={\"tabs-root\"}>\n <view className={\"tabs-header\"}>\n {props.items.map((item, i) => (\n <view\n key={item.key}\n className={\"tabs-triggerButton\"}\n bindtap={() => {\n setActiveIndex(i);\n props.onTabChange?.();\n\n tabContentsRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: {\n position: i,\n smooth: true,\n },\n })\n .exec();\n }}\n >\n <text\n className={`tabs-triggerButtonText${i === activeIndex ? \" tabs-triggerButtonText--active\" : \"\"}${tabSize ? ` tabs-triggerButtonText--${tabSize}` : \"\"}`}\n >\n {item.label}\n </text>\n {i === 0 && (\n <view\n className={\"tabs-triggerIndicator\"}\n style={{ transform: `translateX(${activeIndex * 100}%)` }}\n >\n <view className={\"tabs-triggerIndicatorLine\"} />\n </view>\n )}\n </view>\n ))}\n </view>\n\n <list\n ref={tabContentsRef}\n className={\"tabs-contents\"}\n scroll-orientation=\"horizontal\"\n item-snap={{ factor: 0, offset: 0 }}\n bindscroll={() => props.onTabChange?.()}\n bindsnap={(e: ListSnapEvent) => {\n setActiveIndex(e.detail.position);\n }}\n bounces={false}\n preload-buffer-count={props.items.length}\n >\n {props.items.map((item) => (\n <list-item\n key={item.key}\n item-key={item.key}\n recyclable={false}\n className={\"tabs-content\"}\n >\n {item.renderContent()}\n </list-item>\n ))}\n </list>\n </view>\n );\n}\n","import { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport type { CustomTab } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { LogPanel, dismissFilterDropdown } from \"./LogPanel\";\nimport { NetworkPanel } from \"./NetworkPanel\";\nimport { PerformancePanel } from \"./PerformancePanel\";\nimport Tabs from \"./Tabs\";\n\ninterface ConsolePanelProps {\n customTabs?: CustomTab[];\n}\n\nexport const ConsolePanel = ({ customTabs }: ConsolePanelProps) => {\n const { logs, clearLogs } = useConsole();\n const { networks, clearNetworks } = useNetwork();\n const { performances, clearPerformances } = usePerformance();\n\n const state = globalThis.__LYNX_CONSOLE__?.state;\n\n const items: Array<{\n key: string;\n label: string;\n renderContent: () => ReturnType<typeof LogPanel>;\n }> = [];\n\n if (state?.logs) {\n items.push({\n key: \"log\",\n label: \"Log\",\n renderContent: () => <LogPanel logs={logs} clearLogs={clearLogs} />,\n });\n }\n\n if (state?.networks) {\n items.push({\n key: \"network\",\n label: \"Network\",\n renderContent: () => (\n <NetworkPanel networks={networks} clearNetworks={clearNetworks} />\n ),\n });\n }\n\n if (state?.performances) {\n items.push({\n key: \"performance\",\n label: \"Perf\",\n renderContent: () => (\n <PerformancePanel\n performances={performances}\n clearPerformances={clearPerformances}\n />\n ),\n });\n }\n\n if (customTabs) {\n for (const tab of customTabs) {\n items.push({\n key: tab.key,\n label: tab.label,\n renderContent: tab.renderContent,\n });\n }\n }\n\n if (items.length === 0) {\n return null;\n }\n\n return (\n <view className=\"cp-container\">\n <Tabs onTabChange={dismissFilterDropdown} items={items} />\n </view>\n );\n};\n","import { useRef, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\n\nconst LONG_PRESS_DURATION = 400;\nconst MOVE_THRESHOLD = 5;\n\nconst DEFAULT_RIGHT = 16;\nconst DEFAULT_BOTTOM = 84;\n\nlet savedRight = DEFAULT_RIGHT;\nlet savedBottom = DEFAULT_BOTTOM;\n\nexport function useLongPressDrag(onTap: () => void) {\n const [right, setRight] = useState(savedRight);\n const [bottom, setBottom] = useState(savedBottom);\n const [phase, setPhase] = useState<\"idle\" | \"dragging\" | \"releasing\">(\"idle\");\n const [tempRight, setTempRight] = useState(savedRight);\n const [tempBottom, setTempBottom] = useState(savedBottom);\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const draggingRef = useRef(false);\n const startRef = useRef({ x: 0, y: 0, r: 0, b: 0 });\n\n const clearTimer = () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n startRef.current = {\n x: e.detail.x,\n y: e.detail.y,\n r: right,\n b: bottom,\n };\n draggingRef.current = false;\n\n timerRef.current = setTimeout(() => {\n draggingRef.current = true;\n setPhase(\"dragging\");\n setTempRight(right);\n setTempBottom(bottom);\n }, LONG_PRESS_DURATION);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n const dx = e.detail.x - startRef.current.x;\n const dy = e.detail.y - startRef.current.y;\n\n if (\n !draggingRef.current &&\n (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)\n ) {\n clearTimer();\n }\n\n if (!draggingRef.current) return;\n\n // right/bottom 기준이므로 방향 반전\n setTempRight(startRef.current.r - dx);\n setTempBottom(startRef.current.b - dy);\n };\n\n const handleTouchEnd = () => {\n clearTimer();\n\n if (draggingRef.current) {\n setRight(tempRight);\n setBottom(tempBottom);\n savedRight = tempRight;\n savedBottom = tempBottom;\n setPhase(\"releasing\");\n draggingRef.current = false;\n setTimeout(() => setPhase(\"idle\"), 300);\n } else {\n onTap();\n }\n };\n\n const isDragging = phase === \"dragging\";\n\n return {\n phase,\n right: isDragging ? tempRight : right,\n bottom: isDragging ? tempBottom : bottom,\n clearTimer,\n handlers: {\n catchtouchstart: handleTouchStart,\n catchtouchmove: handleTouchMove,\n catchtouchend: handleTouchEnd,\n },\n };\n}\n","import type { ReactNode } from \"@lynx-js/react\";\nimport { useLongPressDrag } from \"../hooks/useLongPressDrag\";\nimport \"./FloatingButton.css\";\n\ninterface FloatingButtonProps {\n bindtap: () => void;\n children: ReactNode;\n}\n\nconst SHINE_STYLES = {\n idle: {\n transform: \"scale(0)\",\n opacity: 0,\n },\n dragging: {\n transform: \"scale(1)\",\n opacity: 1,\n transition: \"transform 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n releasing: {\n transform: \"scale(1)\",\n opacity: 0,\n transition: \"opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n} as const;\n\nexport const FloatingButton = ({\n bindtap,\n children,\n}: FloatingButtonProps) => {\n const { phase, right, bottom, clearTimer, handlers } =\n useLongPressDrag(bindtap);\n\n\n const handleReload = () => {\n try {\n lynx.reload({}, () => {\n console.log(\"reloaded!\");\n });\n } catch (e) {\n console.error(\"[LynxConsole] reload failed:\", e);\n }\n };\n\n const isDragging = phase === \"dragging\";\n\n return (\n <>\n <view\n className={\"fb-wrapper\"}\n consume-slide-event={[[-180, 180]]}\n style={{\n right: `${right}px`,\n bottom: `${bottom}px`,\n transform: isDragging ? \"scale(1.05)\" : \"scale(1)\",\n }}\n {...handlers}\n >\n <view className={\"fb-button\"}>\n {children}\n <view className={\"fb-shineOverlay\"} style={SHINE_STYLES[phase]} />\n </view>\n <view\n className={\"fb-reloadButton\"}\n catchtouchstart={() => clearTimer()}\n bindtap={handleReload}\n >\n <text className={\"fb-reloadIcon\"}>{\"\\u21BB\"}</text>\n </view>\n </view>\n </>\n );\n};\n","import \"./styles/vars/index.css\";\nimport \"./styles/global.css\";\nimport {\n type ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useState,\n} from \"@lynx-js/react\";\nimport BottomSheet from \"./components/BottomSheet.jsx\";\nimport { ConsolePanel } from \"./components/ConsolePanel.jsx\";\nimport \"./components/FloatingButton.css\";\nimport { FloatingButton } from \"./components/FloatingButton.jsx\";\nimport { usePerformance } from \"./hooks/usePerformance\";\nimport type { CustomTab } from \"./types\";\n\nexport interface LynxConsoleHandle {\n open: () => void;\n close: () => void;\n isOpen: () => boolean;\n}\n\nexport interface LynxConsoleProps {\n theme?: \"light\" | \"dark\";\n safeAreaInsetBottom?: string;\n customTabs?: CustomTab[];\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst LynxConsole = forwardRef<LynxConsoleHandle, LynxConsoleProps>(\n (\n { theme = \"light\", safeAreaInsetBottom = \"50px\", customTabs },\n ref: ForwardedRef<LynxConsoleHandle>,\n ) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shouldClose, setShouldClose] = useState(false);\n const { performances } = usePerformance();\n\n const latestFcp = useMemo(() => {\n for (let i = performances.length - 1; i >= 0; i--) {\n const perf = performances[i];\n if (perf && perf.entryType === \"metric\" && perf.name === \"fcp\") {\n const metricEntry = perf.rawEntry as MetricFcpEntry | undefined;\n // totalFcp를 먼저 시도하고, 없으면 lynxFcp 반환\n if (metricEntry?.totalFcp?.duration !== undefined) {\n return metricEntry.totalFcp;\n }\n if (metricEntry?.lynxFcp?.duration !== undefined) {\n return metricEntry.lynxFcp;\n }\n }\n }\n return undefined;\n }, [performances]);\n\n useImperativeHandle(ref, () => ({\n open: () => {\n setIsOpen(true);\n setShouldClose(false);\n },\n close: () => {\n setShouldClose(true);\n },\n isOpen: () => isOpen,\n }));\n\n const handleOpenBottomSheet = () => {\n setIsOpen(true);\n setShouldClose(false);\n };\n\n const handleCloseBottomSheet = () => {\n setIsOpen(false);\n setShouldClose(false);\n };\n\n const themeClass = `data-lynx-console-color-mode__${theme}-only`;\n\n return (\n <view className={themeClass}>\n <FloatingButton bindtap={handleOpenBottomSheet}>\n <text className=\"fb-title\">LynxConsole</text>\n <text className=\"fb-subtitle\">\n {`${latestFcp?.name ?? \"FCP\"}: ${latestFcp?.duration ? latestFcp.duration.toFixed(2) : \"--\"}ms`}\n </text>\n </FloatingButton>\n {isOpen && (\n <BottomSheet\n isOpen={isOpen}\n shouldClose={shouldClose}\n onClose={handleCloseBottomSheet}\n title=\"Lynx Console\"\n safeAreaInsetBottom={safeAreaInsetBottom}\n >\n <ConsolePanel customTabs={customTabs} />\n </BottomSheet>\n )}\n </view>\n );\n },\n);\n\nexport type { CustomTab } from \"./types\";\nexport default LynxConsole;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/styles/theme.ts","../src/styles/ThemeContext.ts","../src/components/BottomSheet.tsx","../src/hooks/useConsole.ts","../src/hooks/useNetwork.ts","../src/hooks/usePerformance.ts","../src/components/FadeList.tsx","../src/components/LogPanel.tsx","../src/components/NetworkDetailSection.tsx","../src/components/NetworkPanel.tsx","../src/components/PerformancePanel.tsx","../src/components/Tabs.tsx","../src/components/ConsolePanel.tsx","../src/hooks/useLongPressDrag.ts","../src/components/FloatingButton.tsx","../src/index.tsx"],"sourcesContent":["export type Theme = \"light\" | \"dark\";\n\nconst lightColors = {\n palette: {\n blue100: \"#eff6ff\",\n blue600: \"#5e98fe\",\n gray100: \"#f7f8f9\",\n gray400: \"#dcdee3\",\n green100: \"#edfaf6\",\n green600: \"#10ab7d\",\n purple100: \"#f5f3fe\",\n purple600: \"#9f84fb\",\n red100: \"#fdf0f0\",\n red600: \"#fc6a66\",\n red900: \"#921708\",\n staticWhite: \"#ffffff\",\n yellow100: \"#fff7de\",\n yellow600: \"#c49725\",\n yellow900: \"#4f3e1f\",\n },\n fg: {\n neutral: \"#1a1c20\",\n placeholder: \"#b0b3ba\",\n disabled: \"#d1d3d8\",\n neutralMuted: \"#555d6d\",\n neutralSubtle: \"#868b94\",\n },\n bg: {\n overlay: \"#00000074\",\n layerDefault: \"#ffffff\",\n layerFloating: \"#ffffff\",\n neutralWeak: \"#f3f4f5\",\n },\n stroke: {\n neutralSubtle: \"#0000000c\",\n neutralWeak: \"#dcdee3\",\n },\n} as const;\n\nconst darkColors = {\n palette: {\n blue100: \"#202742\",\n blue600: \"#1e82eb\",\n gray100: \"#16171b\",\n gray400: \"#393d46\",\n green100: \"#202926\",\n green600: \"#1b946d\",\n purple100: \"#28213b\",\n purple600: \"#8e6bee\",\n red100: \"#322323\",\n red600: \"#f73526\",\n red900: \"#f8c5c3\",\n staticWhite: \"#ffffff\",\n yellow100: \"#302819\",\n yellow600: \"#b6720d\",\n yellow900: \"#e5d49b\",\n },\n fg: {\n neutral: \"#f3f4f5\",\n placeholder: \"#868b94\",\n disabled: \"#5b606a\",\n neutralMuted: \"#dcdee3\",\n neutralSubtle: \"#b0b3ba\",\n },\n bg: {\n overlay: \"#00000074\",\n layerDefault: \"#16171b\",\n layerFloating: \"#1d2025\",\n neutralWeak: \"#2b2e35\",\n },\n stroke: {\n neutralSubtle: \"#ffffff0d\",\n neutralWeak: \"#393d46\",\n },\n} as const;\n\nconst colorMap = {\n light: lightColors,\n dark: darkColors,\n} as const;\n\nexport const fontWeight = {\n regular: \"400\",\n medium: \"500\",\n bold: \"700\",\n} as const;\n\nexport const duration = {\n d4: \"200ms\",\n d6: \"300ms\",\n} as const;\n\nexport const dimension = {\n x2: \"8px\",\n x3: \"12px\",\n x4: \"16px\",\n x6: \"24px\",\n spacingX: {\n globalGutter: \"16px\",\n },\n} as const;\n\nexport const radius = {\n r6: \"24px\",\n} as const;\n\nexport function getColors(theme: Theme) {\n return colorMap[theme];\n}\n\nexport type ThemeColors = ReturnType<typeof getColors>;\n","import { createContext, useContext } from \"@lynx-js/react\";\nimport { type ThemeColors, getColors } from \"./theme\";\n\nconst ThemeContext = createContext<ThemeColors>(getColors(\"light\"));\n\nexport const ThemeProvider = ThemeContext.Provider;\n\nexport function useThemeColors(): ThemeColors {\n return useContext(ThemeContext);\n}\n","import { type ReactNode, useEffect, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { duration, fontWeight } from \"../styles/theme\";\nimport \"./BottomSheet.css\";\n\ninterface BottomSheetProps {\n children: ReactNode;\n title?: string;\n footer?: ReactNode;\n onClose: () => void;\n isOpen: boolean;\n shouldClose?: boolean;\n safeAreaInsetBottom?: string;\n}\n\nconst MIN_HEIGHT = 200;\nconst MAX_HEIGHT = 700;\nconst DEFAULT_HEIGHT = 500;\nconst CLOSE_DRAG_THRESHOLD = 30; // 30px 이상 아래로 드래그하면 닫힘\n\n// 마지막 높이 저장\nlet savedHeight: number | null = null;\n\nexport default function BottomSheet({\n children,\n title,\n footer,\n onClose,\n isOpen,\n shouldClose = false,\n safeAreaInsetBottom = \"25px\",\n}: BottomSheetProps) {\n const colors = useThemeColors();\n const [sheetHeight, setSheetHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [tempHeight, setTempHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [isDragging, setIsDragging] = useState(false);\n const [dragStartY, setDragStartY] = useState(0);\n const [dragStartHeight, setDragStartHeight] = useState(\n savedHeight ?? DEFAULT_HEIGHT,\n );\n const [isOpening, setIsOpening] = useState(true);\n const [isClosing, setIsClosing] = useState(false);\n\n // 닫기 애니메이션 처리\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => {\n onClose();\n }, 300);\n };\n\n // 아래에서 올라오는 애니메이션\n useEffect(() => {\n requestAnimationFrame(() => {\n setIsOpening(false);\n });\n }, []);\n\n // 외부에서 닫기 요청 시 애니메이션 처리\n useEffect(() => {\n if (shouldClose && !isClosing) {\n handleClose();\n }\n }, [shouldClose, isClosing]);\n\n // 높이 변경 시 저장\n useEffect(() => {\n savedHeight = sheetHeight;\n }, [sheetHeight]);\n\n if (!isOpen) return null;\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n setIsDragging(true);\n setDragStartY(e.detail.y);\n setDragStartHeight(sheetHeight);\n setTempHeight(sheetHeight);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n if (!isDragging) return;\n const deltaY = dragStartY - e.detail.y;\n const newHeight = Math.min(\n Math.max(dragStartHeight + deltaY, MIN_HEIGHT),\n MAX_HEIGHT,\n );\n setTempHeight(newHeight);\n };\n\n const handleTouchEnd = () => {\n setIsDragging(false);\n\n // 아래로 일정 30px 이상 드래그하면 닫기\n const dragDistance = dragStartHeight - tempHeight;\n setSheetHeight(tempHeight);\n if (dragDistance > CLOSE_DRAG_THRESHOLD) {\n handleClose();\n }\n };\n\n return (\n <scroll-view\n className=\"bs-backdrop\"\n style={{\n background: colors.bg.overlay,\n opacity: isOpening || isClosing ? 0 : 1,\n transition: `opacity ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n >\n <view className=\"bs-overlay\" bindtap={handleClose}>\n <view\n className=\"bs-content\"\n catchtap={() => {}}\n style={{\n background: colors.bg.layerFloating,\n height: `${isDragging ? tempHeight : sheetHeight}px`,\n transform:\n isOpening || isClosing ? \"translateY(100%)\" : \"translateY(0)\",\n transition: isDragging\n ? \"none\"\n : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n >\n {/* catchtap: 이벤트 버블링 차단 */}\n <view\n className=\"bs-handleContainer\"\n bindtouchstart={handleTouchStart}\n bindtouchmove={handleTouchMove}\n bindtouchend={handleTouchEnd}\n >\n <view\n className=\"bs-handle\"\n style={{ backgroundColor: colors.palette.gray400 }}\n />\n </view>\n <view className=\"bs-header\">\n {title && (\n <text\n className=\"bs-title\"\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n {title}\n </text>\n )}\n </view>\n <view\n className=\"bs-body\"\n style={{\n paddingBottom: safeAreaInsetBottom,\n }}\n >\n {children}\n </view>\n {footer && <view className=\"bs-footer\">{footer}</view>}\n </view>\n </view>\n </scroll-view>\n );\n}\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { LogEntry } from \"../types\";\n\nexport const useConsole = () => {\n const [logs, setLogs] = useState<LogEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs === \"undefined\") {\n console.warn(\"[LynxConsole] Log monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setLogs([...(state.logs ?? [])]);\n\n const updateLogs = (_entry: LogEntry) => {\n setLogs([...(state.logs ?? [])]);\n };\n\n const unsubscribe = state.logSubscribe?.(updateLogs);\n\n return unsubscribe;\n }, []);\n\n const clearLogs = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.logs = [];\n setLogs([]);\n }\n };\n\n return { logs, clearLogs };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { NetworkEntry } from \"../types\";\n\nexport const useNetwork = () => {\n const [networks, setNetworks] = useState<NetworkEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks === \"undefined\") {\n console.warn(\"[LynxConsole] Network monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setNetworks([...(state.networks ?? [])]);\n\n const updateNetworks = (_entry: NetworkEntry) => {\n setNetworks([...(state.networks ?? [])]);\n };\n\n const unsubscribe = state.subscribeNetwork?.(updateNetworks);\n\n return unsubscribe;\n }, []);\n\n const clearNetworks = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.networks = [];\n state.networksMap?.clear();\n setNetworks([]);\n }\n };\n\n return { networks, clearNetworks };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { PerformanceEntryData } from \"../types\";\n\nexport const usePerformance = () => {\n const [performances, setPerformances] = useState<PerformanceEntryData[]>([]);\n\n useEffect(() => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances === \"undefined\"\n ) {\n console.warn(\"[LynxConsole] Performance monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setPerformances([...(state.performances ?? [])]);\n\n const updatePerformances = (_entry: PerformanceEntryData) => {\n setPerformances([...(state.performances ?? [])]);\n };\n\n const unsubscribe = state.subscribePerformance?.(updatePerformances);\n\n return unsubscribe;\n }, []);\n\n const clearPerformances = () => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances !== \"undefined\"\n ) {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.performances = [];\n setPerformances([]);\n }\n };\n\n return { performances, clearPerformances };\n};\n","import { useRef } from \"@lynx-js/react\";\nimport type { NodesRef } from \"@lynx-js/types\";\n\ninterface FadeListProps {\n className?: string;\n listRef?: React.RefObject<NodesRef>;\n children: React.ReactNode;\n \"preload-buffer-count\"?: number;\n \"initial-scroll-index\"?: number;\n}\n\nexport const FadeList = ({\n className,\n listRef: externalListRef,\n children,\n ...listProps\n}: FadeListProps) => {\n const internalListRef = useRef<NodesRef>(null);\n const listRef = externalListRef ?? internalListRef;\n\n return (\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\n className={className}\n {...listProps}\n >\n {children}\n </list>\n );\n};\n","import { useEffect, useMemo, useRef, useState } from \"@lynx-js/react\";\nimport type { BaseEvent, InputInputEvent, NodesRef } from \"@lynx-js/types\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { type ThemeColors, fontWeight } from \"../styles/theme\";\nimport type { LogEntry, LogLevel } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { FadeList } from \"./FadeList\";\n\nconst LOG_LEVELS: LogLevel[] = [\"log\", \"info\", \"warn\", \"error\"];\n\nlet savedEnabledLevels: Set<LogLevel> | null = null;\nlet savedSearchQuery = \"\";\nlet closeFilterDropdown: (() => void) | null = null;\n\nexport const dismissFilterDropdown = () => closeFilterDropdown?.();\n\ninterface LogPanelProps {\n logs: LogEntry[];\n clearLogs: () => void;\n}\n\nconst runCode = (code: string) => {\n try {\n // biome-ignore lint: intentional REPL tool\n const result = eval(code);\n if (result instanceof Promise) {\n result.then((r) => console.log(r)).catch((e) => console.error(e));\n } else {\n console.log(result);\n }\n } catch (e) {\n console.error(e);\n }\n};\n\nfunction getLevelColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"log\":\n return colors.palette.green600;\n case \"info\":\n return colors.palette.blue600;\n case \"warn\":\n return colors.palette.yellow600;\n case \"error\":\n return colors.palette.red600;\n }\n}\n\nfunction getLogItemBg(\n colors: ThemeColors,\n level: LogLevel,\n): string | undefined {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow100;\n case \"error\":\n return colors.palette.red100;\n default:\n return undefined;\n }\n}\n\nfunction getStringColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow900;\n case \"error\":\n return colors.palette.red900;\n default:\n return colors.fg.neutral;\n }\n}\n\nfunction getPrimitiveColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow900;\n case \"error\":\n return colors.palette.red900;\n default:\n return colors.palette.blue600;\n }\n}\n\nexport const LogPanel = ({ logs, clearLogs }: LogPanelProps) => {\n const colors = useThemeColors();\n const [expandedArgs, setExpandedArgs] = useState(new Set());\n const [code, setCode] = useState(\"\");\n const [enabledLevels, setEnabledLevels] = useState<Set<LogLevel>>(\n () => savedEnabledLevels ?? new Set(LOG_LEVELS),\n );\n const [filterOpen, setFilterOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState(savedSearchQuery);\n const inputRef = useRef<NodesRef>(null);\n const searchInputRef = useRef<NodesRef>(null);\n const listRef = useRef<NodesRef>(null);\n\n useEffect(() => {\n savedEnabledLevels = enabledLevels;\n }, [enabledLevels]);\n\n useEffect(() => {\n savedSearchQuery = searchQuery;\n }, [searchQuery]);\n\n useEffect(() => {\n if (savedSearchQuery) {\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: savedSearchQuery } })\n .exec();\n }\n }, []);\n\n useEffect(() => {\n closeFilterDropdown = () => setFilterOpen(false);\n return () => { closeFilterDropdown = null; };\n }, []);\n\n const filteredLogs = useMemo(\n () =>\n logs.filter((log) => {\n if (!enabledLevels.has(log.level)) return false;\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return log.args.some((arg) => String(arg).toLowerCase().includes(query));\n }\n return true;\n }),\n [logs, enabledLevels, searchQuery],\n );\n const logsRef = useRef(filteredLogs);\n logsRef.current = filteredLogs;\n\n const toggleLevel = (level: LogLevel) => {\n setEnabledLevels((prev) => {\n const next = new Set(prev);\n if (next.has(level)) {\n next.delete(level);\n } else {\n next.add(level);\n }\n return next;\n });\n };\n\n const scrollToBottom = (smooth: boolean) => {\n if (logsRef.current.length === 0) return;\n listRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: { position: logsRef.current.length - 1, smooth },\n })\n .exec();\n };\n\n useEffect(() => {\n scrollToBottom(true);\n }, [filteredLogs]);\n\n const toggleArg = (key: string) => {\n setExpandedArgs((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n };\n\n const handleRun = () => {\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCode(\"\");\n inputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n runCode(trimmed);\n setTimeout(() => scrollToBottom(false), 100);\n };\n\n const renderArg = (\n arg: unknown,\n parentKey: string,\n level: \"log\" | \"info\" | \"warn\" | \"error\",\n ): React.ReactNode => {\n const key = parentKey;\n const isExpanded = expandedArgs.has(key);\n\n if (arg === null) {\n return (\n <text style={{ color: colors.fg.neutralSubtle, fontWeight: fontWeight.regular }}>\n null\n </text>\n );\n }\n\n if (arg === undefined) {\n return (\n <text style={{ color: colors.fg.neutralSubtle, fontWeight: fontWeight.regular }}>\n undefined\n </text>\n );\n }\n\n if (typeof arg === \"string\") {\n const MAX_LENGTH = 80;\n const shouldTruncate = arg.length > MAX_LENGTH;\n const strColor = getStringColor(colors, level);\n\n if (!shouldTruncate) {\n return (\n <text\n className={\"cp-argString\"}\n style={{ color: strColor, fontWeight: fontWeight.regular }}\n >\n {arg}\n </text>\n );\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text\n className={\"cp-toggleIndicator\"}\n style={{ color: colors.fg.neutralSubtle, fontWeight: fontWeight.regular }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argString\"}\n style={{ color: strColor, fontWeight: fontWeight.regular }}\n >\n {isExpanded ? arg : `${arg.slice(0, MAX_LENGTH)}...`}\n </text>\n </view>\n </view>\n );\n }\n\n if (typeof arg === \"number\" || typeof arg === \"boolean\") {\n return (\n <text\n className={\"cp-argPrimitive\"}\n style={{ color: getPrimitiveColor(colors, level), fontWeight: fontWeight.regular }}\n >\n {String(arg)}\n </text>\n );\n }\n\n if (typeof arg === \"object\") {\n let preview = \"Object\";\n if (Array.isArray(arg)) {\n preview = `Array(${arg.length})`;\n } else if (arg instanceof Map) {\n preview = `Map(${arg.size})`;\n } else if (arg instanceof Set) {\n preview = `Set(${arg.size})`;\n } else if (arg instanceof Date) {\n preview = `Date`;\n } else if (arg instanceof RegExp) {\n preview = `RegExp`;\n } else if (arg instanceof Error) {\n preview = `${arg.constructor.name}`;\n } else if (arg?.constructor?.name && arg.constructor.name !== \"Object\") {\n preview = arg.constructor.name;\n }\n\n let jsonString: string;\n if (arg instanceof Map) {\n const entries = Array.from(arg.entries()).map(\n ([k, v]) => ` [${stringify(k)}, ${stringify(v)}]`,\n );\n jsonString = `{\\n${entries.join(\",\\n\")}\\n}`;\n } else if (arg instanceof Set) {\n const values = Array.from(arg.values()).map((v) => stringify(v));\n jsonString = `{\\n${values.join(\", \")}\\n}`;\n } else {\n jsonString =\n stringify(arg, null, 2, { references: true }) ?? String(arg);\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text\n className={\"cp-toggleIndicator\"}\n style={{ color: colors.fg.neutralSubtle, fontWeight: fontWeight.regular }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argObjectPreview\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutral }}\n >\n {preview}\n </text>\n </view>\n {isExpanded && (\n <view className={\"cp-argObjectContent\"}>\n <text\n className={\"cp-argObjectJson\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutral }}\n >\n {jsonString}\n </text>\n </view>\n )}\n </view>\n );\n }\n\n return (\n <text\n className={\"cp-argPrimitive\"}\n style={{ color: getPrimitiveColor(colors, level), fontWeight: fontWeight.regular }}\n >\n {String(arg)}\n </text>\n );\n };\n\n return (\n <view\n className={\"cp-logContainer\"}\n bindtap={() => { if (filterOpen) setFilterOpen(false); }}\n >\n <view className={\"cp-logHeader\"}>\n <view className={\"cp-filterWrapper\"}>\n <view\n className={\"cp-filterButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n catchtap={() => setFilterOpen((v) => !v)}\n >\n <text\n className={\"cp-filterButtonText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutralMuted }}\n >\n Filter ▼\n </text>\n </view>\n {filterOpen && (\n <view\n className={\"cp-filterDropdown\"}\n style={{\n backgroundColor: colors.bg.layerFloating,\n borderColor: colors.stroke.neutralSubtle,\n }}\n catchtap={() => {}}\n >\n {LOG_LEVELS.map((level) => (\n <view\n key={level}\n className={\"cp-filterOption\"}\n bindtap={() => toggleLevel(level)}\n >\n <text\n className={\"cp-filterCheckbox\"}\n style={{ fontWeight: fontWeight.medium, color: getLevelColor(colors, level) }}\n >\n {enabledLevels.has(level) ? \"✅\" : \"⬜\"}\n </text>\n <text\n className={\"cp-filterLabel\"}\n style={{ fontWeight: fontWeight.medium, color: getLevelColor(colors, level) }}\n >\n {level.toUpperCase()}\n </text>\n </view>\n ))}\n </view>\n )}\n </view>\n <view\n className={\"cp-searchWrapper\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"cp-searchPrompt\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.placeholder }}\n >\n {\"›\"}\n </text>\n <input\n ref={searchInputRef}\n className={\"cp-searchInput\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n caretColor: colors.palette.green600,\n }}\n placeholder=\"Search logs...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setSearchQuery(e.detail.value)\n }\n />\n {searchQuery.length > 0 && (\n <view\n className={\"cp-searchClear\"}\n bindtap={() => {\n setSearchQuery(\"\");\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n }}\n >\n <text\n className={\"cp-searchClearText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.placeholder }}\n >\n ✕\n </text>\n </view>\n )}\n </view>\n <view style={{ display: \"flex\", flexDirection: \"row\", gap: 8 }}>\n <view\n className={\"cp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n bindtap={clearLogs}\n >\n <text\n className={\"cp-clearButtonText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutralMuted }}\n >\n 🗑\n </text>\n </view>\n </view>\n </view>\n <FadeList\n listRef={listRef}\n className={\"cp-logList\"}\n preload-buffer-count={10}\n initial-scroll-index={Math.max(0, filteredLogs.length - 1)}\n >\n {filteredLogs.length === 0 ? (\n <list-item item-key=\"empty-state\">\n <view className={\"cp-placeholder\"}>\n <text\n className={\"cp-placeholderText\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.disabled }}\n >\n No logs yet. Try console.log(\"Hello!\")\n </text>\n </view>\n </list-item>\n ) : (\n filteredLogs.map((log) => {\n return (\n <list-item key={log.id} item-key={log.id}>\n <view\n className={\"cp-logItem\"}\n style={{\n backgroundColor: getLogItemBg(colors, log.level),\n borderBottomColor: colors.stroke.neutralWeak,\n }}\n >\n <view className={\"cp-logItemHeader\"}>\n <text\n className={\"cp-logLevel\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getLevelColor(colors, log.level),\n }}\n >\n {log.level.toUpperCase()}\n </text>\n <text\n className={\"cp-logTime\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(log.timestamp).toISOString()}\n </text>\n </view>\n <view className={\"cp-logArgsContainer\"}>\n {log.args.map((arg, index) => (\n <view\n key={`${log.id}-${index.toString()}`}\n className={\"cp-logArgItem\"}\n style={{ fontWeight: fontWeight.regular }}\n >\n {renderArg(\n arg,\n `${log.id}-${index.toString()}`,\n log.level,\n )}\n </view>\n ))}\n </view>\n </view>\n </list-item>\n );\n })\n )}\n </FadeList>\n <view className={\"cp-replInputRow\"}>\n <text\n className={\"cp-replPrompt\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.placeholder }}\n >\n {\"›\"}\n </text>\n <input\n ref={inputRef}\n className={\"cp-replInput\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n caretColor: colors.palette.green600,\n }}\n placeholder=\"enter code...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setCode(e.detail.value)\n }\n bindconfirm={handleRun}\n />\n <view\n className={\"cp-replRunButton\"}\n style={{ backgroundColor: colors.palette.green100 }}\n bindtap={handleRun}\n >\n <text\n className={\"cp-replRunButtonText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.palette.green600 }}\n >\n Run\n </text>\n </view>\n </view>\n </view>\n );\n};\n","import { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight } from \"../styles/theme\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkDetailSectionProps {\n headers?: Record<string, string> | undefined;\n body?: string | undefined;\n error?: string | undefined;\n}\n\nexport const NetworkDetailSection = ({\n headers = {},\n body = \"\",\n error = \"\",\n}: NetworkDetailSectionProps) => {\n const colors = useThemeColors();\n\n return (\n <>\n {/* Headers */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Headers\n </text>\n {headers && Object.keys(headers).length > 0 ? (\n <view className={\"np-table\"}>\n {Object.entries(headers).map(([key, value]) => (\n <view\n key={key}\n className={\"np-tableRow\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"np-tableKey\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutralSubtle }}\n >\n {key}\n </text>\n <text\n className={\"np-tableValue\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutral }}\n >\n {value}\n </text>\n </view>\n ))}\n </view>\n ) : (\n <text\n className={\"np-emptyText\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.disabled }}\n >\n No headers\n </text>\n )}\n </view>\n\n {/* Body */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Body\n </text>\n {error && (\n <text\n className={\"np-errorText\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n }}\n >\n {error}\n </text>\n )}\n {body && (\n <text\n className={\"np-bodyText\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n }}\n >\n {body}\n </text>\n )}\n {!error && !body && (\n <text\n className={\"np-emptyText\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.disabled }}\n >\n No body\n </text>\n )}\n </view>\n </>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { type ThemeColors, fontWeight } from \"../styles/theme\";\nimport type { NetworkEntry } from \"../types\";\nimport { FadeList } from \"./FadeList\";\nimport { NetworkDetailSection } from \"./NetworkDetailSection\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkPanelProps {\n networks: NetworkEntry[];\n clearNetworks: () => void;\n}\n\ntype TabType = \"general\" | \"request\" | \"response\";\n\nfunction getMethodColors(colors: ThemeColors, method: string) {\n switch (method) {\n case \"GET\":\n return { color: colors.palette.blue600, backgroundColor: colors.palette.blue100 };\n case \"POST\":\n return { color: colors.palette.green600, backgroundColor: colors.palette.green100 };\n case \"PUT\":\n return { color: colors.palette.yellow600, backgroundColor: colors.palette.yellow100 };\n case \"PATCH\":\n return { color: colors.palette.purple600, backgroundColor: colors.palette.purple100 };\n case \"DELETE\":\n return { color: colors.palette.red600, backgroundColor: colors.palette.red100 };\n default:\n return { color: colors.fg.neutral, backgroundColor: colors.bg.neutralWeak };\n }\n}\n\nfunction getStatusCodeColor(\n colors: ThemeColors,\n variant: \"success\" | \"error\" | \"pending\",\n): string {\n switch (variant) {\n case \"success\":\n return colors.palette.green600;\n case \"error\":\n return colors.palette.red600;\n case \"pending\":\n return colors.fg.neutralSubtle;\n }\n}\n\nfunction getItemBg(colors: ThemeColors, status: string): string | undefined {\n switch (status) {\n case \"pending\":\n return colors.palette.gray100;\n case \"error\":\n return colors.palette.red100;\n default:\n return undefined;\n }\n}\n\nexport const NetworkPanel = ({\n networks,\n clearNetworks,\n}: NetworkPanelProps) => {\n const colors = useThemeColors();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<TabType>(\"general\");\n const formatDuration = (duration?: number): string => {\n if (!duration) return \"-\";\n if (duration < 1000) return `${duration}ms`;\n return `${(duration / 1000).toFixed(2)}s`;\n };\n\n const extractPath = (url: string): string => {\n const pathMatch = url.match(/^https?:\\/\\/[^/]+(.*)$/);\n if (pathMatch?.[1]) {\n return pathMatch[1].startsWith(\"/\")\n ? pathMatch[1].slice(1)\n : pathMatch[1];\n }\n return url;\n };\n\n const getGeneralInfo = (network: NetworkEntry) => {\n return [\n { key: \"URL\", value: network.url },\n { key: \"Method\", value: network.method },\n network.statusCode\n ? { key: \"Status\", value: String(network.statusCode) }\n : null,\n {\n key: \"Request Time\",\n value: new Date(network.startTime).toISOString(),\n },\n network.endTime\n ? {\n key: \"Response Time\",\n value: new Date(network.endTime).toISOString(),\n }\n : null,\n network.duration\n ? { key: \"Duration\", value: formatDuration(network.duration) }\n : null,\n ].filter((item) => item !== null);\n };\n\n const getStatusCodeVariant = (\n status: string,\n statusCode?: number,\n ): \"success\" | \"error\" | \"pending\" => {\n if (status === \"pending\") return \"pending\";\n if (status === \"error\") return \"error\";\n if (statusCode && statusCode >= 200 && statusCode < 300) return \"success\";\n return \"error\";\n };\n\n return (\n <view className={\"np-container\"}>\n <view className={\"np-header\"}>\n <text\n className={\"np-count\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n Total: {networks.length} requests\n </text>\n <view\n className={\"np-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n bindtap={clearNetworks}\n >\n <text\n className={\"np-clearButtonText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutralMuted }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={\"np-placeholder\"}>\n <text\n className={\"np-placeholderText\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.disabled }}\n >\n No network requests yet\n </text>\n </view>\n ) : (\n <FadeList className={\"np-list\"}>\n {networks.map((network) => (\n <list-item key={network.id} item-key={network.id}>\n <view\n className={\"np-item\"}\n style={{\n backgroundColor: getItemBg(colors, network.status),\n borderBottomColor: colors.stroke.neutralWeak,\n }}\n >\n <view\n className={\"np-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n <text\n className={\"np-method\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getMethodColors(colors, network.method),\n }}\n >\n {network.method}\n </text>\n {network.statusCode && (\n <text\n className={\"np-statusCode\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getStatusCodeColor(\n colors,\n getStatusCodeVariant(network.status, network.statusCode),\n ),\n }}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text\n className={\"np-statusCode\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n Pending...\n </text>\n )}\n <text\n className={\"np-time\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n {formatDuration(network.duration)}\n </text>\n <text\n className={\"np-time\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={\"np-path\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutral }}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n {extractPath(network.url)}\n </text>\n\n {selectedId === network.id && (\n <view\n className={\"np-detailsContainer\"}\n style={{ borderTopColor: colors.stroke.neutralSubtle }}\n >\n {/* Tabs */}\n <view className={\"np-tabs\"}>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"general\" ? colors.bg.neutralWeak : undefined,\n }}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={\"np-tabText\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"general\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n General\n </text>\n </view>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"request\" ? colors.bg.neutralWeak : undefined,\n }}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={\"np-tabText\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"request\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n Request\n </text>\n </view>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"response\" ? colors.bg.neutralWeak : undefined,\n }}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={\"np-tabText\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"response\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n Response\n </text>\n </view>\n </view>\n\n {/* Tab Content */}\n <view className={\"np-tabContent\"}>\n {activeTab === \"general\" && (\n <view className={\"np-table\"}>\n {getGeneralInfo(network).map((item) => (\n <view\n key={item.key}\n className={\"np-tableRow\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"np-tableKey\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {item.key}\n </text>\n <text\n className={\"np-tableValue\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {item.value}\n </text>\n </view>\n ))}\n </view>\n )}\n\n {activeTab === \"request\" && (\n <NetworkDetailSection\n headers={network.requestHeaders}\n body={network.requestBody}\n />\n )}\n\n {activeTab === \"response\" && (\n <NetworkDetailSection\n headers={network.responseHeaders}\n body={network.responseBody}\n error={network.error}\n />\n )}\n </view>\n </view>\n )}\n </view>\n </list-item>\n ))}\n </FadeList>\n )}\n </view>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { type ThemeColors, fontWeight } from \"../styles/theme\";\nimport type { PerformanceEntryData } from \"../types\";\nimport { FadeList } from \"./FadeList\";\nimport \"./PerformancePanel.css\";\n\ninterface PerformancePanelProps {\n performances: PerformanceEntryData[];\n clearPerformances: () => void;\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst isMetricFcpEntry = (entry: PerformanceEntryData): boolean => {\n return entry.entryType === \"metric\" && entry.name === \"fcp\";\n};\n\nconst extractFcpMetrics = (entry: PerformanceEntryData) => {\n if (!isMetricFcpEntry(entry) || !entry.rawEntry) {\n return null;\n }\n\n const metricEntry = entry.rawEntry as MetricFcpEntry;\n\n return {\n totalFcp: metricEntry.totalFcp ?? undefined,\n lynxFcp: metricEntry.lynxFcp ?? undefined,\n fcp: metricEntry.fcp ?? undefined,\n };\n};\n\nconst formatDuration = (ms?: number): string => {\n if (ms === undefined) return \"-\";\n return `${ms.toFixed(2)}ms`;\n};\n\nconst getPrimaryFcpLabel = (entry: PerformanceEntryData): string => {\n const fcpMetrics = extractFcpMetrics(entry);\n if (!fcpMetrics) return \"\";\n\n const { totalFcp, lynxFcp, fcp } = fcpMetrics;\n\n if (totalFcp?.duration !== undefined) {\n return `totalFcp: ${formatDuration(totalFcp.duration)}`;\n }\n if (lynxFcp?.duration !== undefined) {\n return `lynxFcp: ${formatDuration(lynxFcp.duration)}`;\n }\n if (fcp?.duration !== undefined) {\n return `fcp: ${formatDuration(fcp.duration)}`;\n }\n return \"\";\n};\n\nfunction getEntryTypeColors(colors: ThemeColors, entryType: string) {\n switch (entryType) {\n case \"init\":\n return { color: colors.palette.blue600, backgroundColor: colors.palette.blue100 };\n case \"metric\":\n return { color: colors.palette.green600, backgroundColor: colors.palette.green100 };\n case \"pipeline\":\n return { color: colors.palette.purple600, backgroundColor: colors.palette.purple100 };\n case \"resource\":\n return { color: colors.palette.yellow600, backgroundColor: colors.palette.yellow100 };\n default:\n return { color: colors.fg.neutral, backgroundColor: colors.bg.neutralWeak };\n }\n}\n\nexport const PerformancePanel = ({\n performances,\n clearPerformances,\n}: PerformancePanelProps) => {\n const colors = useThemeColors();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n if (performances.length === 0) {\n return (\n <view className={\"pp-container\"}>\n <view\n className={\"pp-header\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"pp-count\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n 0 entries\n </text>\n <view\n bindtap={clearPerformances}\n className={\"pp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-clearButtonText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutralMuted }}\n >\n 🗑\n </text>\n </view>\n </view>\n <view className={\"pp-placeholder\"}>\n <text\n className={\"pp-placeholderText\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.disabled }}\n >\n No performance data yet...\n </text>\n </view>\n </view>\n );\n }\n\n return (\n <view className={\"pp-container\"}>\n <view\n className={\"pp-header\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"pp-count\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n {performances.length} entries\n </text>\n <view\n bindtap={clearPerformances}\n className={\"pp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-clearButtonText\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutralMuted }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n <FadeList className={\"pp-list\"}>\n {performances.map((perf) => {\n const isMetricFcp = isMetricFcpEntry(perf);\n const fcpMetrics = extractFcpMetrics(perf);\n const primaryFcp = getPrimaryFcpLabel(perf);\n const { totalFcp, lynxFcp, fcp } = fcpMetrics ?? {};\n\n return (\n <list-item key={perf.id} item-key={perf.id}>\n <view\n className={\"pp-item\"}\n style={{ borderBottomColor: colors.stroke.neutralWeak }}\n >\n <view\n className={\"pp-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n <text\n className={\"pp-entryType\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getEntryTypeColors(colors, perf.entryType),\n }}\n >\n {perf.entryType}\n </text>\n <text\n className={\"pp-entryName\"}\n style={{ fontWeight: fontWeight.medium, color: colors.fg.neutral }}\n >\n {perf.name}\n </text>\n <text\n className={\"pp-timestamp\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n {new Date(perf.timestamp).toISOString()}\n </text>\n </view>\n\n <view\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n {isMetricFcp && primaryFcp && (\n <text\n className={\"pp-fcpHighlight\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n }}\n >\n {primaryFcp}\n </text>\n )}\n </view>\n\n {selectedId === perf.id && (\n <view className={\"pp-detailsContainer\"}>\n {isMetricFcp && fcpMetrics && (\n <view className={\"pp-fcpSection\"}>\n {totalFcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n 전체 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue\"}\n style={{ fontWeight: fontWeight.bold, color: colors.palette.blue600 }}\n >\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n PrepareTemplate Start부터 Paint End 까지 걸리는\n 시간\n </text>\n </view>\n )}\n\n {lynxFcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n LynxFCP\n </text>\n <text\n className={\"pp-fcpMetricValue\"}\n style={{ fontWeight: fontWeight.bold, color: colors.palette.blue600 }}\n >\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n Bundle Load 시작부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n\n {fcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n 렌더링 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue\"}\n style={{ fontWeight: fontWeight.bold, color: colors.palette.blue600 }}\n >\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n TemplateBundle 준비부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n </view>\n )}\n\n {!!perf.rawEntry && (\n <view\n className={\"pp-rawEntrySection\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-detailTitle\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Raw Entry\n </text>\n <text\n className={\"pp-rawEntry\"}\n style={{ fontWeight: fontWeight.regular, color: colors.fg.neutralSubtle }}\n >\n {String(stringify(perf.rawEntry, null, 2, { references: true }))}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </FadeList>\n </view>\n );\n};\n","import { type ReactNode, useRef, useState } from \"@lynx-js/react\";\nimport type { ListSnapEvent, NodesRef } from \"@lynx-js/types\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight } from \"../styles/theme\";\nimport \"./Tabs.css\";\n\ntype TabsProps = {\n items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }>;\n onTabChange?: () => void;\n};\n\nexport default function Tabs(props: TabsProps) {\n const colors = useThemeColors();\n const tabContentsRef = useRef<NodesRef>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const tabSize =\n props.items.length < 4\n ? undefined\n : (`t${Math.max(1, 5 - (props.items.length - 3))}`);\n\n return (\n <view className={\"tabs-root\"}>\n <view\n className={\"tabs-header\"}\n style={{\n boxShadow: `inset 0 -1px 0 0 ${colors.stroke.neutralSubtle}`,\n }}\n >\n {props.items.map((item, i) => (\n <view\n key={item.key}\n className={\"tabs-triggerButton\"}\n bindtap={() => {\n setActiveIndex(i);\n props.onTabChange?.();\n\n tabContentsRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: {\n position: i,\n smooth: true,\n },\n })\n .exec();\n }}\n >\n <text\n className={`tabs-triggerButtonText${tabSize ? ` tabs-triggerButtonText--${tabSize}` : \"\"}`}\n style={{\n fontWeight: fontWeight.bold,\n color:\n i === activeIndex\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n {item.label}\n </text>\n {i === 0 && (\n <view\n className={\"tabs-triggerIndicator\"}\n style={{ transform: `translateX(${activeIndex * 100}%)` }}\n >\n <view\n className={\"tabs-triggerIndicatorLine\"}\n style={{ backgroundColor: colors.fg.neutral }}\n />\n </view>\n )}\n </view>\n ))}\n </view>\n\n <list\n ref={tabContentsRef}\n className={\"tabs-contents\"}\n scroll-orientation=\"horizontal\"\n item-snap={{ factor: 0, offset: 0 }}\n bindscroll={() => props.onTabChange?.()}\n bindsnap={(e: ListSnapEvent) => {\n setActiveIndex(e.detail.position);\n }}\n bounces={false}\n preload-buffer-count={props.items.length}\n >\n {props.items.map((item) => (\n <list-item\n key={item.key}\n item-key={item.key}\n recyclable={false}\n className={\"tabs-content\"}\n >\n {item.renderContent()}\n </list-item>\n ))}\n </list>\n </view>\n );\n}\n","import { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport type { CustomTab } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { LogPanel, dismissFilterDropdown } from \"./LogPanel\";\nimport { NetworkPanel } from \"./NetworkPanel\";\nimport { PerformancePanel } from \"./PerformancePanel\";\nimport Tabs from \"./Tabs\";\n\ninterface ConsolePanelProps {\n customTabs?: CustomTab[];\n}\n\nexport const ConsolePanel = ({ customTabs }: ConsolePanelProps) => {\n const { logs, clearLogs } = useConsole();\n const { networks, clearNetworks } = useNetwork();\n const { performances, clearPerformances } = usePerformance();\n\n const state = globalThis.__LYNX_CONSOLE__?.state;\n\n const items: Array<{\n key: string;\n label: string;\n renderContent: () => ReturnType<typeof LogPanel>;\n }> = [];\n\n if (state?.logs) {\n items.push({\n key: \"log\",\n label: \"Log\",\n renderContent: () => <LogPanel logs={logs} clearLogs={clearLogs} />,\n });\n }\n\n if (state?.networks) {\n items.push({\n key: \"network\",\n label: \"Network\",\n renderContent: () => (\n <NetworkPanel networks={networks} clearNetworks={clearNetworks} />\n ),\n });\n }\n\n if (state?.performances) {\n items.push({\n key: \"performance\",\n label: \"Perf\",\n renderContent: () => (\n <PerformancePanel\n performances={performances}\n clearPerformances={clearPerformances}\n />\n ),\n });\n }\n\n if (customTabs) {\n for (const tab of customTabs) {\n items.push({\n key: tab.key,\n label: tab.label,\n renderContent: tab.renderContent,\n });\n }\n }\n\n if (items.length === 0) {\n return null;\n }\n\n return (\n <view className=\"cp-container\">\n <Tabs onTabChange={dismissFilterDropdown} items={items} />\n </view>\n );\n};\n","import { useRef, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\n\nconst LONG_PRESS_DURATION = 400;\nconst MOVE_THRESHOLD = 5;\n\nconst DEFAULT_RIGHT = 16;\nconst DEFAULT_BOTTOM = 84;\n\nlet savedRight = DEFAULT_RIGHT;\nlet savedBottom = DEFAULT_BOTTOM;\n\nexport function useLongPressDrag(onTap: () => void) {\n const [right, setRight] = useState(savedRight);\n const [bottom, setBottom] = useState(savedBottom);\n const [phase, setPhase] = useState<\"idle\" | \"dragging\" | \"releasing\">(\"idle\");\n const [tempRight, setTempRight] = useState(savedRight);\n const [tempBottom, setTempBottom] = useState(savedBottom);\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const draggingRef = useRef(false);\n const startRef = useRef({ x: 0, y: 0, r: 0, b: 0 });\n\n const clearTimer = () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n startRef.current = {\n x: e.detail.x,\n y: e.detail.y,\n r: right,\n b: bottom,\n };\n draggingRef.current = false;\n\n timerRef.current = setTimeout(() => {\n draggingRef.current = true;\n setPhase(\"dragging\");\n setTempRight(right);\n setTempBottom(bottom);\n }, LONG_PRESS_DURATION);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n const dx = e.detail.x - startRef.current.x;\n const dy = e.detail.y - startRef.current.y;\n\n if (\n !draggingRef.current &&\n (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)\n ) {\n clearTimer();\n }\n\n if (!draggingRef.current) return;\n\n // right/bottom 기준이므로 방향 반전\n setTempRight(startRef.current.r - dx);\n setTempBottom(startRef.current.b - dy);\n };\n\n const handleTouchEnd = () => {\n clearTimer();\n\n if (draggingRef.current) {\n setRight(tempRight);\n setBottom(tempBottom);\n savedRight = tempRight;\n savedBottom = tempBottom;\n setPhase(\"releasing\");\n draggingRef.current = false;\n setTimeout(() => setPhase(\"idle\"), 300);\n } else {\n onTap();\n }\n };\n\n const isDragging = phase === \"dragging\";\n\n return {\n phase,\n right: isDragging ? tempRight : right,\n bottom: isDragging ? tempBottom : bottom,\n clearTimer,\n handlers: {\n catchtouchstart: handleTouchStart,\n catchtouchmove: handleTouchMove,\n catchtouchend: handleTouchEnd,\n },\n };\n}\n","import type { ReactNode } from \"@lynx-js/react\";\nimport { useLongPressDrag } from \"../hooks/useLongPressDrag\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { duration } from \"../styles/theme\";\nimport \"./FloatingButton.css\";\n\ninterface FloatingButtonProps {\n bindtap: () => void;\n children: ReactNode;\n}\n\nconst SHINE_STYLES = {\n idle: {\n transform: \"scale(0)\",\n opacity: 0,\n },\n dragging: {\n transform: \"scale(1)\",\n opacity: 1,\n transition: \"transform 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n releasing: {\n transform: \"scale(1)\",\n opacity: 0,\n transition: \"opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n} as const;\n\nexport const FloatingButton = ({\n bindtap,\n children,\n}: FloatingButtonProps) => {\n const colors = useThemeColors();\n const { phase, right, bottom, clearTimer, handlers } =\n useLongPressDrag(bindtap);\n\n\n const handleReload = () => {\n try {\n lynx.reload({}, () => {\n console.log(\"reloaded!\");\n });\n } catch (e) {\n console.error(\"[LynxConsole] reload failed:\", e);\n }\n };\n\n const isDragging = phase === \"dragging\";\n\n return (\n <>\n <view\n className={\"fb-wrapper\"}\n consume-slide-event={[[-180, 180]]}\n style={{\n right: `${right}px`,\n bottom: `${bottom}px`,\n transform: isDragging ? \"scale(1.05)\" : \"scale(1)\",\n transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n {...handlers}\n >\n <view\n className={\"fb-button\"}\n style={{ backgroundColor: colors.palette.green600 }}\n >\n {children}\n <view className={\"fb-shineOverlay\"} style={SHINE_STYLES[phase]} />\n </view>\n <view\n className={\"fb-reloadButton\"}\n style={{ backgroundColor: colors.palette.green600 }}\n catchtouchstart={() => clearTimer()}\n bindtap={handleReload}\n >\n <text\n className={\"fb-reloadIcon\"}\n style={{ color: colors.palette.staticWhite }}\n >\n {\"\\u21BB\"}\n </text>\n </view>\n </view>\n </>\n );\n};\n","import {\n type ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useState,\n} from \"@lynx-js/react\";\nimport BottomSheet from \"./components/BottomSheet.jsx\";\nimport { ConsolePanel } from \"./components/ConsolePanel.jsx\";\nimport \"./components/FloatingButton.css\";\nimport { FloatingButton } from \"./components/FloatingButton.jsx\";\nimport { usePerformance } from \"./hooks/usePerformance\";\nimport { ThemeProvider } from \"./styles/ThemeContext\";\nimport { getColors } from \"./styles/theme\";\nimport type { CustomTab } from \"./types\";\n\nexport interface LynxConsoleHandle {\n open: () => void;\n close: () => void;\n isOpen: () => boolean;\n}\n\nexport interface LynxConsoleProps {\n theme?: \"light\" | \"dark\";\n safeAreaInsetBottom?: string;\n customTabs?: CustomTab[];\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst LynxConsole = forwardRef<LynxConsoleHandle, LynxConsoleProps>(\n (\n { theme = \"light\", safeAreaInsetBottom = \"50px\", customTabs },\n ref: ForwardedRef<LynxConsoleHandle>,\n ) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shouldClose, setShouldClose] = useState(false);\n const { performances } = usePerformance();\n const colors = useMemo(() => getColors(theme), [theme]);\n\n const latestFcp = useMemo(() => {\n for (let i = performances.length - 1; i >= 0; i--) {\n const perf = performances[i];\n if (perf && perf.entryType === \"metric\" && perf.name === \"fcp\") {\n const metricEntry = perf.rawEntry as MetricFcpEntry | undefined;\n // totalFcp를 먼저 시도하고, 없으면 lynxFcp 반환\n if (metricEntry?.totalFcp?.duration !== undefined) {\n return metricEntry.totalFcp;\n }\n if (metricEntry?.lynxFcp?.duration !== undefined) {\n return metricEntry.lynxFcp;\n }\n }\n }\n return undefined;\n }, [performances]);\n\n useImperativeHandle(ref, () => ({\n open: () => {\n setIsOpen(true);\n setShouldClose(false);\n },\n close: () => {\n setShouldClose(true);\n },\n isOpen: () => isOpen,\n }));\n\n const handleOpenBottomSheet = () => {\n setIsOpen(true);\n setShouldClose(false);\n };\n\n const handleCloseBottomSheet = () => {\n setIsOpen(false);\n setShouldClose(false);\n };\n\n return (\n <ThemeProvider value={colors}>\n <view\n style={{\n backgroundColor: colors.bg.layerDefault,\n color: colors.fg.neutral,\n }}\n >\n <FloatingButton bindtap={handleOpenBottomSheet}>\n <text className=\"fb-title\" style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}>LynxConsole</text>\n <text className=\"fb-subtitle\" style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}>\n {`${latestFcp?.name ?? \"FCP\"}: ${latestFcp?.duration ? latestFcp.duration.toFixed(2) : \"--\"}ms`}\n </text>\n </FloatingButton>\n {isOpen && (\n <BottomSheet\n isOpen={isOpen}\n shouldClose={shouldClose}\n onClose={handleCloseBottomSheet}\n title=\"Lynx Console\"\n safeAreaInsetBottom={safeAreaInsetBottom}\n >\n <ConsolePanel customTabs={customTabs} />\n </BottomSheet>\n )}\n </view>\n </ThemeProvider>\n );\n },\n);\n\nexport type { CustomTab } from \"./types\";\nexport default LynxConsole;\n"],"mappings":";;;;;AA4EA,MAAM,WAAW;CACf,OA3EkB;EAClB,SAAS;GACP,SAAS;GACT,SAAS;GACT,SAAS;GACT,SAAS;GACT,UAAU;GACV,UAAU;GACV,WAAW;GACX,WAAW;GACX,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,WAAW;GACX,WAAW;GACX,WAAW;GACZ;EACD,IAAI;GACF,SAAS;GACT,aAAa;GACb,UAAU;GACV,cAAc;GACd,eAAe;GAChB;EACD,IAAI;GACF,SAAS;GACT,cAAc;GACd,eAAe;GACf,aAAa;GACd;EACD,QAAQ;GACN,eAAe;GACf,aAAa;GACd;EACF;CAyCC,MAvCiB;EACjB,SAAS;GACP,SAAS;GACT,SAAS;GACT,SAAS;GACT,SAAS;GACT,UAAU;GACV,UAAU;GACV,WAAW;GACX,WAAW;GACX,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,WAAW;GACX,WAAW;GACX,WAAW;GACZ;EACD,IAAI;GACF,SAAS;GACT,aAAa;GACb,UAAU;GACV,cAAc;GACd,eAAe;GAChB;EACD,IAAI;GACF,SAAS;GACT,cAAc;GACd,eAAe;GACf,aAAa;GACd;EACD,QAAQ;GACN,eAAe;GACf,aAAa;GACd;EACF;CAKA;AAED,MAAa,aAAa;CACxB,SAAS;CACT,QAAQ;CACR,MAAM;CACP;AAED,MAAa,WAAW;CACtB,IAAI;CACJ,IAAI;CACL;AAgBD,SAAgB,UAAU,OAAc;AACtC,QAAO,SAAS;;;;;ACxGlB,MAAM,eAAe,cAA2B,UAAU,QAAQ,CAAC;AAEnE,MAAa,gBAAgB,aAAa;AAE1C,SAAgB,iBAA8B;AAC5C,QAAO,WAAW,aAAa;;;;;ACQjC,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,iBAAiB;AACvB,MAAM,uBAAuB;AAG7B,IAAI,cAA6B;AAEjC,SAAwB,YAAY,EAClC,UACA,OACA,QACA,SACA,QACA,cAAc,OACd,sBAAsB,UACH;CACnB,MAAM,SAAS,gBAAgB;CAC/B,MAAM,CAAC,aAAa,kBAAkB,SAAS,eAAe,eAAe;CAC7E,MAAM,CAAC,YAAY,iBAAiB,SAAS,eAAe,eAAe;CAC3E,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM;CACnD,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAC/C,MAAM,CAAC,iBAAiB,sBAAsB,SAC5C,eAAe,eAChB;CACD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CAGjD,MAAM,oBAAoB;AACxB,eAAa,KAAK;AAClB,mBAAiB;AACf,YAAS;KACR,IAAI;;AAIT,iBAAgB;AACd,8BAA4B;AAC1B,gBAAa,MAAM;IACnB;IACD,EAAE,CAAC;AAGN,iBAAgB;AACd,MAAI,eAAe,CAAC,UAClB,cAAa;IAEd,CAAC,aAAa,UAAU,CAAC;AAG5B,iBAAgB;AACd,gBAAc;IACb,CAAC,YAAY,CAAC;AAEjB,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,oBAAoB,MAA8B;AACtD,gBAAc,KAAK;AACnB,gBAAc,EAAE,OAAO,EAAE;AACzB,qBAAmB,YAAY;AAC/B,gBAAc,YAAY;;CAG5B,MAAM,mBAAmB,MAA8B;AACrD,MAAI,CAAC,WAAY;EACjB,MAAM,SAAS,aAAa,EAAE,OAAO;AAKrC,gBAJkB,KAAK,IACrB,KAAK,IAAI,kBAAkB,QAAQ,WAAW,EAC9C,WACD,CACuB;;CAG1B,MAAM,uBAAuB;AAC3B,gBAAc,MAAM;EAGpB,MAAM,eAAe,kBAAkB;AACvC,iBAAe,WAAW;AAC1B,MAAI,eAAe,qBACjB,cAAa;;AAIjB,QACE,CAAC,YACC,wBACA,OAAO;EACL,YAAY,OAAO,GAAG;EACtB,SAAS,aAAa,YAAY,IAAI;EACtC,YAAY,WAAW,SAAS,GAAG;EACpC,EACF;MACC,CAAC,KAAK,uBAAuB,SAAS,aAAa;QACjD,CAAC,KACC,uBACA,gBAAgB,IAChB,OAAO;EACL,YAAY,OAAO,GAAG;EACtB,QAAQ,GAAG,aAAa,aAAa,YAAY;EACjD,WACE,aAAa,YAAY,qBAAqB;EAChD,YAAY,aACR,SACA,aAAa,SAAS,GAAG;EAC9B,EACF;YAC6B;UAC5B,CAAC,KACC,+BACA,gBAAgB,kBAChB,eAAe,iBACf,cAAc,gBACf;YACC,CAAC,KACC,sBACA,OAAO,EAAE,iBAAiB,OAAO,QAAQ,SAAS,IAClD;UACJ,EAAE,KAAK;UACP,CAAC,KAAK,sBAAsB;aACzB,SACC,CAAC,KACC,qBACA,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EAClB,EACF;iBACE,MAAM;cACT,EAAE,MACF;UACJ,EAAE,KAAK;UACP,CAAC,KACC,oBACA,OAAO,EACL,eAAe,qBAChB,EACF;aACE,SAAS;UACZ,EAAE,KAAK;WACN,UAAU,CAAC,KAAK,uBAAuB,OAAO,EAAE,MAAM;QACzD,EAAE,KAAK;MACT,EAAE,KAAK;IACT,EAAE;;;;;AC7JN,MAAa,mBAAmB;CAC9B,MAAM,CAAC,MAAM,WAAW,SAAqB,EAAE,CAAC;AAEhD,iBAAgB;AACd,MAAI,OAAO,WAAW,kBAAkB,OAAO,SAAS,aAAa;AACnE,WAAQ,KAAK,+CAA+C;AAC5D;;EAGF,MAAM,QAAQ,WAAW,iBAAiB;AAE1C,UAAQ,CAAC,GAAI,MAAM,QAAQ,EAAE,CAAE,CAAC;EAEhC,MAAM,cAAc,WAAqB;AACvC,WAAQ,CAAC,GAAI,MAAM,QAAQ,EAAE,CAAE,CAAC;;AAKlC,SAFoB,MAAM,eAAe,WAAW;IAGnD,EAAE,CAAC;CAEN,MAAM,kBAAkB;AACtB,MAAI,OAAO,WAAW,kBAAkB,OAAO,SAAS,aAAa;GACnE,MAAM,QAAQ,WAAW,iBAAiB;AAC1C,SAAM,OAAO,EAAE;AACf,WAAQ,EAAE,CAAC;;;AAIf,QAAO;EAAE;EAAM;EAAW;;;;;AC9B5B,MAAa,mBAAmB;CAC9B,MAAM,CAAC,UAAU,eAAe,SAAyB,EAAE,CAAC;AAE5D,iBAAgB;AACd,MAAI,OAAO,WAAW,kBAAkB,OAAO,aAAa,aAAa;AACvE,WAAQ,KAAK,mDAAmD;AAChE;;EAGF,MAAM,QAAQ,WAAW,iBAAiB;AAE1C,cAAY,CAAC,GAAI,MAAM,YAAY,EAAE,CAAE,CAAC;EAExC,MAAM,kBAAkB,WAAyB;AAC/C,eAAY,CAAC,GAAI,MAAM,YAAY,EAAE,CAAE,CAAC;;AAK1C,SAFoB,MAAM,mBAAmB,eAAe;IAG3D,EAAE,CAAC;CAEN,MAAM,sBAAsB;AAC1B,MAAI,OAAO,WAAW,kBAAkB,OAAO,aAAa,aAAa;GACvE,MAAM,QAAQ,WAAW,iBAAiB;AAC1C,SAAM,WAAW,EAAE;AACnB,SAAM,aAAa,OAAO;AAC1B,eAAY,EAAE,CAAC;;;AAInB,QAAO;EAAE;EAAU;EAAe;;;;;AC/BpC,MAAa,uBAAuB;CAClC,MAAM,CAAC,cAAc,mBAAmB,SAAiC,EAAE,CAAC;AAE5E,iBAAgB;AACd,MACE,OAAO,WAAW,kBAAkB,OAAO,iBAAiB,aAC5D;AACA,WAAQ,KAAK,uDAAuD;AACpE;;EAGF,MAAM,QAAQ,WAAW,iBAAiB;AAE1C,kBAAgB,CAAC,GAAI,MAAM,gBAAgB,EAAE,CAAE,CAAC;EAEhD,MAAM,sBAAsB,WAAiC;AAC3D,mBAAgB,CAAC,GAAI,MAAM,gBAAgB,EAAE,CAAE,CAAC;;AAKlD,SAFoB,MAAM,uBAAuB,mBAAmB;IAGnE,EAAE,CAAC;CAEN,MAAM,0BAA0B;AAC9B,MACE,OAAO,WAAW,kBAAkB,OAAO,iBAAiB,aAC5D;GACA,MAAM,QAAQ,WAAW,iBAAiB;AAC1C,SAAM,eAAe,EAAE;AACvB,mBAAgB,EAAE,CAAC;;;AAIvB,QAAO;EAAE;EAAc;EAAmB;;;;;AC1B5C,MAAa,YAAY,EACvB,WACA,SAAS,iBACT,UACA,GAAG,gBACgB;CACnB,MAAM,kBAAkB,OAAiB,KAAK;CAC9C,MAAM,UAAU,mBAAmB;AAEnC,QACE,CAAC,KACC,KAAK,SACL,8BACA,WAAW,eACP,WACL;OACE,SAAS;IACZ,EAAE;;;;;ACnBN,MAAM,aAAyB;CAAC;CAAO;CAAQ;CAAQ;CAAQ;AAE/D,IAAI,qBAA2C;AAC/C,IAAI,mBAAmB;AACvB,IAAI,sBAA2C;AAE/C,MAAa,8BAA8B,uBAAuB;AAOlE,MAAM,WAAW,SAAiB;AAChC,KAAI;EAEF,MAAM,SAAS,KAAK,KAAK;AACzB,MAAI,kBAAkB,QACpB,QAAO,MAAM,MAAM,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,MAAM,QAAQ,MAAM,EAAE,CAAC;MAEjE,SAAQ,IAAI,OAAO;UAEd,GAAG;AACV,UAAQ,MAAM,EAAE;;;AAIpB,SAAS,cAAc,QAAqB,OAAyB;AACnE,SAAQ,OAAR;EACE,KAAK,MACH,QAAO,OAAO,QAAQ;EACxB,KAAK,OACH,QAAO,OAAO,QAAQ;EACxB,KAAK,OACH,QAAO,OAAO,QAAQ;EACxB,KAAK,QACH,QAAO,OAAO,QAAQ;;;AAI5B,SAAS,aACP,QACA,OACoB;AACpB,SAAQ,OAAR;EACE,KAAK,OACH,QAAO,OAAO,QAAQ;EACxB,KAAK,QACH,QAAO,OAAO,QAAQ;EACxB,QACE;;;AAIN,SAAS,eAAe,QAAqB,OAAyB;AACpE,SAAQ,OAAR;EACE,KAAK,OACH,QAAO,OAAO,QAAQ;EACxB,KAAK,QACH,QAAO,OAAO,QAAQ;EACxB,QACE,QAAO,OAAO,GAAG;;;AAIvB,SAAS,kBAAkB,QAAqB,OAAyB;AACvE,SAAQ,OAAR;EACE,KAAK,OACH,QAAO,OAAO,QAAQ;EACxB,KAAK,QACH,QAAO,OAAO,QAAQ;EACxB,QACE,QAAO,OAAO,QAAQ;;;AAI5B,MAAa,YAAY,EAAE,MAAM,gBAA+B;CAC9D,MAAM,SAAS,gBAAgB;CAC/B,MAAM,CAAC,cAAc,mBAAmB,yBAAS,IAAI,KAAK,CAAC;CAC3D,MAAM,CAAC,MAAM,WAAW,SAAS,GAAG;CACpC,MAAM,CAAC,eAAe,oBAAoB,eAClC,sBAAsB,IAAI,IAAI,WAAW,CAChD;CACD,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM;CACnD,MAAM,CAAC,aAAa,kBAAkB,SAAS,iBAAiB;CAChE,MAAM,WAAW,OAAiB,KAAK;CACvC,MAAM,iBAAiB,OAAiB,KAAK;CAC7C,MAAM,UAAU,OAAiB,KAAK;AAEtC,iBAAgB;AACd,uBAAqB;IACpB,CAAC,cAAc,CAAC;AAEnB,iBAAgB;AACd,qBAAmB;IAClB,CAAC,YAAY,CAAC;AAEjB,iBAAgB;AACd,MAAI,iBACF,gBAAe,SACX,OAAO;GAAE,QAAQ;GAAY,QAAQ,EAAE,OAAO,kBAAkB;GAAE,CAAC,CACpE,MAAM;IAEV,EAAE,CAAC;AAEN,iBAAgB;AACd,8BAA4B,cAAc,MAAM;AAChD,eAAa;AAAE,yBAAsB;;IACpC,EAAE,CAAC;CAEN,MAAM,eAAe,cAEjB,KAAK,QAAQ,QAAQ;AACnB,MAAI,CAAC,cAAc,IAAI,IAAI,MAAM,CAAE,QAAO;AAC1C,MAAI,aAAa;GACf,MAAM,QAAQ,YAAY,aAAa;AACvC,UAAO,IAAI,KAAK,MAAM,QAAQ,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,MAAM,CAAC;;AAE1E,SAAO;GACP,EACJ;EAAC;EAAM;EAAe;EAAY,CACnC;CACD,MAAM,UAAU,OAAO,aAAa;AACpC,SAAQ,UAAU;CAElB,MAAM,eAAe,UAAoB;AACvC,oBAAkB,SAAS;GACzB,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,OAAI,KAAK,IAAI,MAAM,CACjB,MAAK,OAAO,MAAM;OAElB,MAAK,IAAI,MAAM;AAEjB,UAAO;IACP;;CAGJ,MAAM,kBAAkB,WAAoB;AAC1C,MAAI,QAAQ,QAAQ,WAAW,EAAG;AAClC,UAAQ,SACJ,OAAO;GACP,QAAQ;GACR,QAAQ;IAAE,UAAU,QAAQ,QAAQ,SAAS;IAAG;IAAQ;GACzD,CAAC,CACD,MAAM;;AAGX,iBAAgB;AACd,iBAAe,KAAK;IACnB,CAAC,aAAa,CAAC;CAElB,MAAM,aAAa,QAAgB;AACjC,mBAAiB,SAAS;GACxB,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,OAAI,KAAK,IAAI,IAAI,CACf,MAAK,OAAO,IAAI;OAEhB,MAAK,IAAI,IAAI;AAEf,UAAO;IACP;;CAGJ,MAAM,kBAAkB;EACtB,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,CAAC,QAAS;AAEd,UAAQ,GAAG;AACX,WAAS,SACL,OAAO;GAAE,QAAQ;GAAY,QAAQ,EAAE,OAAO,IAAI;GAAE,CAAC,CACtD,MAAM;AACT,UAAQ,QAAQ;AAChB,mBAAiB,eAAe,MAAM,EAAE,IAAI;;CAG9C,MAAM,aACJ,KACA,WACA,UACoB;EACpB,MAAM,MAAM;EACZ,MAAM,aAAa,aAAa,IAAI,IAAI;AAExC,MAAI,QAAQ,KACV,QACE,CAAC,KAAK,OAAO;GAAE,OAAO,OAAO,GAAG;GAAe,YAAY,WAAW;GAAS,EAAE;;QAEjF,EAAE;AAIN,MAAI,QAAQ,OACV,QACE,CAAC,KAAK,OAAO;GAAE,OAAO,OAAO,GAAG;GAAe,YAAY,WAAW;GAAS,EAAE;;QAEjF,EAAE;AAIN,MAAI,OAAO,QAAQ,UAAU;GAC3B,MAAM,aAAa;GACnB,MAAM,iBAAiB,IAAI,SAAS;GACpC,MAAM,WAAW,eAAe,QAAQ,MAAM;AAE9C,OAAI,CAAC,eACH,QACE,CAAC,KACC,WAAW,gBACX,OAAO;IAAE,OAAO;IAAU,YAAY,WAAW;IAAS,EAC3D;aACE,IAAI;UACP,EAAE;AAIN,UACE,CAAC,KAAK,WAAW,gBAAgB;UAC/B,CAAC,KAAK,WAAW,sBAAsB,eAAe,UAAU,IAAI,EAAE;YACpE,CAAC,KACC,WAAW,sBACX,OAAO;IAAE,OAAO,OAAO,GAAG;IAAe,YAAY,WAAW;IAAS,EAC1E;eACE,aAAa,MAAM,IAAI;YAC1B,EAAE,KAAK;YACP,CAAC,KACC,WAAW,gBACX,OAAO;IAAE,OAAO;IAAU,YAAY,WAAW;IAAS,EAC3D;eACE,aAAa,MAAM,GAAG,IAAI,MAAM,GAAG,WAAW,CAAC,KAAK;YACvD,EAAE,KAAK;UACT,EAAE,KAAK;QACT,EAAE;;AAIN,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAC5C,QACE,CAAC,KACC,WAAW,mBACX,OAAO;GAAE,OAAO,kBAAkB,QAAQ,MAAM;GAAE,YAAY,WAAW;GAAS,EACnF;WACE,OAAO,IAAI,CAAC;QACf,EAAE;AAIN,MAAI,OAAO,QAAQ,UAAU;GAC3B,IAAI,UAAU;AACd,OAAI,MAAM,QAAQ,IAAI,CACpB,WAAU,SAAS,IAAI,OAAO;YACrB,eAAe,IACxB,WAAU,OAAO,IAAI,KAAK;YACjB,eAAe,IACxB,WAAU,OAAO,IAAI,KAAK;YACjB,eAAe,KACxB,WAAU;YACD,eAAe,OACxB,WAAU;YACD,eAAe,MACxB,WAAU,GAAG,IAAI,YAAY;YACpB,KAAK,aAAa,QAAQ,IAAI,YAAY,SAAS,SAC5D,WAAU,IAAI,YAAY;GAG5B,IAAI;AACJ,OAAI,eAAe,IAIjB,cAAa,MAHG,MAAM,KAAK,IAAI,SAAS,CAAC,CAAC,KACvC,CAAC,GAAG,OAAO,MAAM,UAAU,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,GACjD,CAC0B,KAAK,MAAM,CAAC;YAC9B,eAAe,IAExB,cAAa,MADE,MAAM,KAAK,IAAI,QAAQ,CAAC,CAAC,KAAK,MAAM,UAAU,EAAE,CAAC,CACtC,KAAK,KAAK,CAAC;OAErC,cACE,UAAU,KAAK,MAAM,GAAG,EAAE,YAAY,MAAM,CAAC,IAAI,OAAO,IAAI;AAGhE,UACE,CAAC,KAAK,WAAW,gBAAgB;UAC/B,CAAC,KAAK,WAAW,sBAAsB,eAAe,UAAU,IAAI,EAAE;YACpE,CAAC,KACC,WAAW,sBACX,OAAO;IAAE,OAAO,OAAO,GAAG;IAAe,YAAY,WAAW;IAAS,EAC1E;eACE,aAAa,MAAM,IAAI;YAC1B,EAAE,KAAK;YACP,CAAC,KACC,WAAW,uBACX,OAAO;IAAE,YAAY,WAAW;IAAQ,OAAO,OAAO,GAAG;IAAS,EACnE;eACE,QAAQ;YACX,EAAE,KAAK;UACT,EAAE,KAAK;WACN,cACC,CAAC,KAAK,WAAW,uBAAuB;cACtC,CAAC,KACC,WAAW,oBACX,OAAO;IAAE,YAAY,WAAW;IAAS,OAAO,OAAO,GAAG;IAAS,EACpE;iBACE,WAAW;cACd,EAAE,KAAK;YACT,EAAE,MACF;QACJ,EAAE;;AAIN,SACE,CAAC,KACC,WAAW,mBACX,OAAO;GAAE,OAAO,kBAAkB,QAAQ,MAAM;GAAE,YAAY,WAAW;GAAS,EACnF;SACE,OAAO,IAAI,CAAC;MACf,EAAE;;AAIN,QACE,CAAC,KACC,WAAW,mBACX,eAAe;AAAE,MAAI,WAAY,eAAc,MAAM;IACtD;MACC,CAAC,KAAK,WAAW,gBAAgB;QAC/B,CAAC,KAAK,WAAW,oBAAoB;UACnC,CAAC,KACC,WAAW,mBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EACjD,gBAAgB,eAAe,MAAM,CAAC,EAAE,EACzC;YACC,CAAC,KACC,WAAW,uBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAc,EACxE;;YAED,EAAE,KAAK;UACT,EAAE,KAAK;WACN,cACC,CAAC,KACC,WAAW,qBACX,OAAO;EACL,iBAAiB,OAAO,GAAG;EAC3B,aAAa,OAAO,OAAO;EAC5B,EACD,gBAAgB,IACjB;eACE,WAAW,KAAK,UACf,CAAC,KACC,KAAK,OACL,WAAW,mBACX,eAAe,YAAY,MAAM,EAClC;kBACC,CAAC,KACC,WAAW,qBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,cAAc,QAAQ,MAAM;EAAE,EAC9E;qBACE,cAAc,IAAI,MAAM,GAAG,MAAM,IAAI;kBACxC,EAAE,KAAK;kBACP,CAAC,KACC,WAAW,kBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,cAAc,QAAQ,MAAM;EAAE,EAC9E;qBACE,MAAM,aAAa,CAAC;kBACvB,EAAE,KAAK;gBACT,EAAE,MACF,CAAC;YACL,EAAE,MACF;QACJ,EAAE,KAAK;QACP,CAAC,KACC,WAAW,oBACX,OAAO,EAAE,mBAAmB,OAAO,OAAO,eAAe,EAC1D;UACC,CAAC,KACC,WAAW,mBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAa,EACvE;aACE,IAAI;UACP,EAAE,KAAK;UACP,CAAC,MACC,KAAK,gBACL,WAAW,kBACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EACjB,YAAY,OAAO,QAAQ;EAC5B,EACD,6BACA,YAAY,MACV,eAAe,EAAE,OAAO,MAAM,IAEhC;WACD,YAAY,SAAS,KACpB,CAAC,KACC,WAAW,kBACX,eAAe;AACb,iBAAe,GAAG;AAClB,iBAAe,SACX,OAAO;GAAE,QAAQ;GAAY,QAAQ,EAAE,OAAO,IAAI;GAAE,CAAC,CACtD,MAAM;IAEZ;cACC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAa,EACvE;;cAED,EAAE,KAAK;YACT,EAAE,MACF;QACJ,EAAE,KAAK;QACP,CAAC,KAAK,OAAO;EAAE,SAAS;EAAQ,eAAe;EAAO,KAAK;EAAG,EAAE;UAC9D,CAAC,KACC,WAAW,kBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EACjD,SAAS,WACV;YACC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAc,EACxE;;YAED,EAAE,KAAK;UACT,EAAE,KAAK;QACT,EAAE,KAAK;MACT,EAAE,KAAK;MACP,CAAC,SACC,SAAS,SACT,WAAW,cACX,sBAAsB,IACtB,sBAAsB,KAAK,IAAI,GAAG,aAAa,SAAS,EAAE,EAC3D;SACE,aAAa,WAAW,IACvB,CAAC,UAAU,uBAAuB;YAChC,CAAC,KAAK,WAAW,kBAAkB;cACjC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAU,EACrE;;cAED,EAAE,KAAK;YACT,EAAE,KAAK;UACT,EAAE,aAEF,aAAa,KAAK,QAAQ;AACxB,SACE,CAAC,UAAU,KAAK,IAAI,IAAI,UAAU,IAAI,IAAI;gBACxC,CAAC,KACC,WAAW,cACX,OAAO;GACL,iBAAiB,aAAa,QAAQ,IAAI,MAAM;GAChD,mBAAmB,OAAO,OAAO;GAClC,EACF;kBACC,CAAC,KAAK,WAAW,oBAAoB;oBACnC,CAAC,KACC,WAAW,eACX,OAAO;GACL,YAAY,WAAW;GACvB,OAAO,cAAc,QAAQ,IAAI,MAAM;GACxC,EACF;uBACE,IAAI,MAAM,aAAa,CAAC;oBAC3B,EAAE,KAAK;oBACP,CAAC,KACC,WAAW,cACX,OAAO;GACL,YAAY,WAAW;GACvB,OAAO,OAAO,GAAG;GAClB,EACF;uBACE,IAAI,KAAK,IAAI,UAAU,CAAC,aAAa,CAAC;oBACzC,EAAE,KAAK;kBACT,EAAE,KAAK;kBACP,CAAC,KAAK,WAAW,uBAAuB;qBACrC,IAAI,KAAK,KAAK,KAAK,UAClB,CAAC,KACC,KAAK,GAAG,IAAI,GAAG,GAAG,MAAM,UAAU,IAClC,WAAW,iBACX,OAAO,EAAE,YAAY,WAAW,SAAS,EAC1C;yBACE,UACC,KACA,GAAG,IAAI,GAAG,GAAG,MAAM,UAAU,IAC7B,IAAI,MACL,CAAC;sBACJ,EAAE,MACF,CAAC;kBACL,EAAE,KAAK;gBACT,EAAE,KAAK;cACT,EAAE;GAEJ,CACF;MACJ,EAAE,SAAS;MACX,CAAC,KAAK,WAAW,mBAAmB;QAClC,CAAC,KACC,WAAW,iBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAa,EACvE;WACE,IAAI;QACP,EAAE,KAAK;QACP,CAAC,MACC,KAAK,UACL,WAAW,gBACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EACjB,YAAY,OAAO,QAAQ;EAC5B,EACD,4BACA,YAAY,MACV,QAAQ,EAAE,OAAO,MAAM,EAEzB,aAAa,aACb;QACF,CAAC,KACC,WAAW,oBACX,OAAO,EAAE,iBAAiB,OAAO,QAAQ,UAAU,EACnD,SAAS,WACV;UACC,CAAC,KACC,WAAW,wBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,QAAQ;EAAU,EACzE;;UAED,EAAE,KAAK;QACT,EAAE,KAAK;MACT,EAAE,KAAK;IACT,EAAE;;;;;AChhBN,MAAa,wBAAwB,EACnC,UAAU,EAAE,EACZ,OAAO,IACP,QAAQ,SACuB;CAC/B,MAAM,SAAS,gBAAgB;AAE/B,QACE,EAAE;QACe;MACf,CAAC,KAAK,WAAW,oBAAoB;QACnC,CAAC,KACC,WAAW,yBACX,OAAO;EAAE,YAAY,WAAW;EAAM,OAAO,OAAO,GAAG;EAAS,EACjE;;QAED,EAAE,KAAK;SACN,WAAW,OAAO,KAAK,QAAQ,CAAC,SAAS,IACxC,CAAC,KAAK,WAAW,YAAY;aAC1B,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,KAAK,WAClC,CAAC,KACC,KAAK,KACL,WAAW,eACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EAClD;gBACC,CAAC,KACC,WAAW,eACX,OAAO;EAAE,YAAY,WAAW;EAAM,OAAO,OAAO,GAAG;EAAe,EACvE;mBACE,IAAI;gBACP,EAAE,KAAK;gBACP,CAAC,KACC,WAAW,iBACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAS,EACpE;mBACE,MAAM;gBACT,EAAE,KAAK;cACT,EAAE,MACF,CAAC;UACL,EAAE,QAEF,CAAC,KACC,WAAW,gBACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAU,EACrE;;UAED,EAAE,MACF;MACJ,EAAE,KAAK;;QAEK;MACZ,CAAC,KAAK,WAAW,oBAAoB;QACnC,CAAC,KACC,WAAW,yBACX,OAAO;EAAE,YAAY,WAAW;EAAM,OAAO,OAAO,GAAG;EAAS,EACjE;;QAED,EAAE,KAAK;SACN,SACC,CAAC,KACC,WAAW,gBACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,QAAQ;EACtB,iBAAiB,OAAO,QAAQ;EACjC,EACF;aACE,MAAM;UACT,EAAE,MACF;SACD,QACC,CAAC,KACC,WAAW,eACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EACjB,iBAAiB,OAAO,GAAG;EAC5B,EACF;aACE,KAAK;UACR,EAAE,MACF;SACD,CAAC,SAAS,CAAC,QACV,CAAC,KACC,WAAW,gBACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAU,EACrE;;UAED,EAAE,MACF;MACJ,EAAE,KAAK;IACT;;;;;ACtFJ,SAAS,gBAAgB,QAAqB,QAAgB;AAC5D,SAAQ,QAAR;EACE,KAAK,MACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAS,iBAAiB,OAAO,QAAQ;GAAS;EACnF,KAAK,OACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAU,iBAAiB,OAAO,QAAQ;GAAU;EACrF,KAAK,MACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAW,iBAAiB,OAAO,QAAQ;GAAW;EACvF,KAAK,QACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAW,iBAAiB,OAAO,QAAQ;GAAW;EACvF,KAAK,SACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAQ,iBAAiB,OAAO,QAAQ;GAAQ;EACjF,QACE,QAAO;GAAE,OAAO,OAAO,GAAG;GAAS,iBAAiB,OAAO,GAAG;GAAa;;;AAIjF,SAAS,mBACP,QACA,SACQ;AACR,SAAQ,SAAR;EACE,KAAK,UACH,QAAO,OAAO,QAAQ;EACxB,KAAK,QACH,QAAO,OAAO,QAAQ;EACxB,KAAK,UACH,QAAO,OAAO,GAAG;;;AAIvB,SAAS,UAAU,QAAqB,QAAoC;AAC1E,SAAQ,QAAR;EACE,KAAK,UACH,QAAO,OAAO,QAAQ;EACxB,KAAK,QACH,QAAO,OAAO,QAAQ;EACxB,QACE;;;AAIN,MAAa,gBAAgB,EAC3B,UACA,oBACuB;CACvB,MAAM,SAAS,gBAAgB;CAC/B,MAAM,CAAC,YAAY,iBAAiB,SAAwB,KAAK;CACjE,MAAM,CAAC,WAAW,gBAAgB,SAAkB,UAAU;CAC9D,MAAM,kBAAkB,aAA8B;AACpD,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,WAAW,IAAM,QAAO,GAAG,SAAS;AACxC,SAAO,IAAI,WAAW,KAAM,QAAQ,EAAE,CAAC;;CAGzC,MAAM,eAAe,QAAwB;EAC3C,MAAM,YAAY,IAAI,MAAM,yBAAyB;AACrD,MAAI,YAAY,GACd,QAAO,UAAU,GAAG,WAAW,IAAI,GAC/B,UAAU,GAAG,MAAM,EAAE,GACrB,UAAU;AAEhB,SAAO;;CAGT,MAAM,kBAAkB,YAA0B;AAChD,SAAO;GACL;IAAE,KAAK;IAAO,OAAO,QAAQ;IAAK;GAClC;IAAE,KAAK;IAAU,OAAO,QAAQ;IAAQ;GACxC,QAAQ,aACJ;IAAE,KAAK;IAAU,OAAO,OAAO,QAAQ,WAAW;IAAE,GACpD;GACJ;IACE,KAAK;IACL,OAAO,IAAI,KAAK,QAAQ,UAAU,CAAC,aAAa;IACjD;GACD,QAAQ,UACJ;IACE,KAAK;IACL,OAAO,IAAI,KAAK,QAAQ,QAAQ,CAAC,aAAa;IAC/C,GACD;GACJ,QAAQ,WACJ;IAAE,KAAK;IAAY,OAAO,eAAe,QAAQ,SAAS;IAAE,GAC5D;GACL,CAAC,QAAQ,SAAS,SAAS,KAAK;;CAGnC,MAAM,wBACJ,QACA,eACoC;AACpC,MAAI,WAAW,UAAW,QAAO;AACjC,MAAI,WAAW,QAAS,QAAO;AAC/B,MAAI,cAAc,cAAc,OAAO,aAAa,IAAK,QAAO;AAChE,SAAO;;AAGT,QACE,CAAC,KAAK,WAAW,gBAAgB;MAC/B,CAAC,KAAK,WAAW,aAAa;QAC5B,CAAC,KACC,WAAW,YACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAe,EAC1E;kBACS,SAAS,OAAO;QAC1B,EAAE,KAAK;QACP,CAAC,KACC,WAAW,kBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EACjD,SAAS,eACV;UACC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAc,EACxE;;UAED,EAAE,KAAK;QACT,EAAE,KAAK;MACT,EAAE,KAAK;;OAEN,SAAS,WAAW,IACnB,CAAC,KAAK,WAAW,kBAAkB;UACjC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAU,EACrE;;UAED,EAAE,KAAK;QACT,EAAE,QAEF,CAAC,SAAS,WAAW,WAAW;WAC7B,SAAS,KAAK,YACb,CAAC,UAAU,KAAK,QAAQ,IAAI,UAAU,QAAQ,IAAI;cAChD,CAAC,KACC,WAAW,WACX,OAAO;EACL,iBAAiB,UAAU,QAAQ,QAAQ,OAAO;EAClD,mBAAmB,OAAO,OAAO;EAClC,EACF;gBACC,CAAC,KACC,WAAW,iBACX,eACE,cAAc,eAAe,QAAQ,KAAK,OAAO,QAAQ,GAAG,EAE/D;kBACC,CAAC,KACC,WAAW,aACX,OAAO;EACL,YAAY,WAAW;EACvB,GAAG,gBAAgB,QAAQ,QAAQ,OAAO;EAC3C,EACF;qBACE,QAAQ,OAAO;kBAClB,EAAE,KAAK;mBACN,QAAQ,cACP,CAAC,KACC,WAAW,iBACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,mBACL,QACA,qBAAqB,QAAQ,QAAQ,QAAQ,WAAW,CACzD;EACF,EACF;uBACE,QAAQ,WAAW;oBACtB,EAAE,MACF;mBACD,QAAQ,WAAW,aAClB,CAAC,KACC,WAAW,iBACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EAClB,EACF;;oBAED,EAAE,MACF;kBACF,CAAC,KACC,WAAW,WACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAe,EAC1E;qBACE,eAAe,QAAQ,SAAS,CAAC;kBACpC,EAAE,KAAK;kBACP,CAAC,KACC,WAAW,WACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAe,EAC1E;qBACE,IAAI,KAAK,QAAQ,UAAU,CAAC,aAAa,CAAC;kBAC7C,EAAE,KAAK;gBACT,EAAE,KAAK;;gBAEP,CAAC,KACC,WAAW,WACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAS,EACnE,eACE,cAAc,eAAe,QAAQ,KAAK,OAAO,QAAQ,GAAG,EAE/D;mBACE,YAAY,QAAQ,IAAI,CAAC;gBAC5B,EAAE,KAAK;;iBAEN,eAAe,QAAQ,MACtB,CAAC,KACC,WAAW,uBACX,OAAO,EAAE,gBAAgB,OAAO,OAAO,eAAe,EACvD;sBACa;oBACZ,CAAC,KAAK,WAAW,WAAW;sBAC1B,CAAC,KACC,WAAW,UACX,OAAO,EACL,iBACE,cAAc,YAAY,OAAO,GAAG,cAAc,QACrD,EACD,eAAe,aAAa,UAAU,EACvC;wBACC,CAAC,KACC,WAAW,cACX,OAAO;EACL,YAAY,WAAW;EACvB,OACE,cAAc,YACV,OAAO,GAAG,UACV,OAAO,GAAG;EACjB,EACF;;wBAED,EAAE,KAAK;sBACT,EAAE,KAAK;sBACP,CAAC,KACC,WAAW,UACX,OAAO,EACL,iBACE,cAAc,YAAY,OAAO,GAAG,cAAc,QACrD,EACD,eAAe,aAAa,UAAU,EACvC;wBACC,CAAC,KACC,WAAW,cACX,OAAO;EACL,YAAY,WAAW;EACvB,OACE,cAAc,YACV,OAAO,GAAG,UACV,OAAO,GAAG;EACjB,EACF;;wBAED,EAAE,KAAK;sBACT,EAAE,KAAK;sBACP,CAAC,KACC,WAAW,UACX,OAAO,EACL,iBACE,cAAc,aAAa,OAAO,GAAG,cAAc,QACtD,EACD,eAAe,aAAa,WAAW,EACxC;wBACC,CAAC,KACC,WAAW,cACX,OAAO;EACL,YAAY,WAAW;EACvB,OACE,cAAc,aACV,OAAO,GAAG,UACV,OAAO,GAAG;EACjB,EACF;;wBAED,EAAE,KAAK;sBACT,EAAE,KAAK;oBACT,EAAE,KAAK;;sBAEY;oBACnB,CAAC,KAAK,WAAW,iBAAiB;uBAC/B,cAAc,aACb,CAAC,KAAK,WAAW,YAAY;2BAC1B,eAAe,QAAQ,CAAC,KAAK,SAC5B,CAAC,KACC,KAAK,KAAK,KACV,WAAW,eACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EAClD;8BACC,CAAC,KACC,WAAW,eACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EAClB,EACF;iCACE,KAAK,IAAI;8BACZ,EAAE,KAAK;8BACP,CAAC,KACC,WAAW,iBACX,OAAO;EACL,YAAY,WAAW;EACvB,OAAO,OAAO,GAAG;EAClB,EACF;iCACE,KAAK,MAAM;8BACd,EAAE,KAAK;4BACT,EAAE,MACF,CAAC;wBACL,EAAE,MACF;;uBAED,cAAc,aACb,CAAC,qBACC,SAAS,QAAQ,gBACjB,MAAM,QAAQ,gBAEhB;;uBAED,cAAc,cACb,CAAC,qBACC,SAAS,QAAQ,iBACjB,MAAM,QAAQ,cACd,OAAO,QAAQ,UAEjB;oBACJ,EAAE,KAAK;kBACT,EAAE,MACF;cACJ,EAAE,KAAK;YACT,EAAE,WACF,CAAC;QACL,EAAE,UACF;IACJ,EAAE;;;;;ACnUN,MAAM,oBAAoB,UAAyC;AACjE,QAAO,MAAM,cAAc,YAAY,MAAM,SAAS;;AAGxD,MAAM,qBAAqB,UAAgC;AACzD,KAAI,CAAC,iBAAiB,MAAM,IAAI,CAAC,MAAM,SACrC,QAAO;CAGT,MAAM,cAAc,MAAM;AAE1B,QAAO;EACL,UAAU,YAAY,YAAY;EAClC,SAAS,YAAY,WAAW;EAChC,KAAK,YAAY,OAAO;EACzB;;AAGH,MAAM,kBAAkB,OAAwB;AAC9C,KAAI,OAAO,OAAW,QAAO;AAC7B,QAAO,GAAG,GAAG,QAAQ,EAAE,CAAC;;AAG1B,MAAM,sBAAsB,UAAwC;CAClE,MAAM,aAAa,kBAAkB,MAAM;AAC3C,KAAI,CAAC,WAAY,QAAO;CAExB,MAAM,EAAE,UAAU,SAAS,QAAQ;AAEnC,KAAI,UAAU,aAAa,OACzB,QAAO,aAAa,eAAe,SAAS,SAAS;AAEvD,KAAI,SAAS,aAAa,OACxB,QAAO,YAAY,eAAe,QAAQ,SAAS;AAErD,KAAI,KAAK,aAAa,OACpB,QAAO,QAAQ,eAAe,IAAI,SAAS;AAE7C,QAAO;;AAGT,SAAS,mBAAmB,QAAqB,WAAmB;AAClE,SAAQ,WAAR;EACE,KAAK,OACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAS,iBAAiB,OAAO,QAAQ;GAAS;EACnF,KAAK,SACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAU,iBAAiB,OAAO,QAAQ;GAAU;EACrF,KAAK,WACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAW,iBAAiB,OAAO,QAAQ;GAAW;EACvF,KAAK,WACH,QAAO;GAAE,OAAO,OAAO,QAAQ;GAAW,iBAAiB,OAAO,QAAQ;GAAW;EACvF,QACE,QAAO;GAAE,OAAO,OAAO,GAAG;GAAS,iBAAiB,OAAO,GAAG;GAAa;;;AAIjF,MAAa,oBAAoB,EAC/B,cACA,wBAC2B;CAC3B,MAAM,SAAS,gBAAgB;CAC/B,MAAM,CAAC,YAAY,iBAAiB,SAAwB,KAAK;AACjE,KAAI,aAAa,WAAW,EAC1B,QACE,CAAC,KAAK,WAAW,gBAAgB;QAC/B,CAAC,KACC,WAAW,aACX,OAAO,EAAE,mBAAmB,OAAO,OAAO,eAAe,EAC1D;UACC,CAAC,KACC,WAAW,YACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAe,EAC1E;;UAED,EAAE,KAAK;UACP,CAAC,KACC,SAAS,mBACT,WAAW,kBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EAClD;YACC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAc,EACxE;;YAED,EAAE,KAAK;UACT,EAAE,KAAK;QACT,EAAE,KAAK;QACP,CAAC,KAAK,WAAW,kBAAkB;UACjC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAU,EACrE;;UAED,EAAE,KAAK;QACT,EAAE,KAAK;MACT,EAAE;AAIN,QACE,CAAC,KAAK,WAAW,gBAAgB;MAC/B,CAAC,KACC,WAAW,aACX,OAAO,EAAE,mBAAmB,OAAO,OAAO,eAAe,EAC1D;QACC,CAAC,KACC,WAAW,YACX,OAAO;EAAE,YAAY,WAAW;EAAS,OAAO,OAAO,GAAG;EAAe,EAC1E;WACE,aAAa,OAAO;QACvB,EAAE,KAAK;QACP,CAAC,KACC,SAAS,mBACT,WAAW,kBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EAClD;UACC,CAAC,KACC,WAAW,sBACX,OAAO;EAAE,YAAY,WAAW;EAAQ,OAAO,OAAO,GAAG;EAAc,EACxE;;UAED,EAAE,KAAK;QACT,EAAE,KAAK;MACT,EAAE,KAAK;;MAEP,CAAC,SAAS,WAAW,WAAW;SAC7B,aAAa,KAAK,SAAS;EAC1B,MAAM,cAAc,iBAAiB,KAAK;EAC1C,MAAM,aAAa,kBAAkB,KAAK;EAC1C,MAAM,aAAa,mBAAmB,KAAK;EAC3C,MAAM,EAAE,UAAU,SAAS,QAAQ,cAAc,EAAE;AAEnD,SACE,CAAC,UAAU,KAAK,KAAK,IAAI,UAAU,KAAK,IAAI;cAC1C,CAAC,KACC,WAAW,WACX,OAAO,EAAE,mBAAmB,OAAO,OAAO,aAAa,EACxD;gBACC,CAAC,KACC,WAAW,iBACX,eACE,cAAc,eAAe,KAAK,KAAK,OAAO,KAAK,GAAG,EAEzD;kBACC,CAAC,KACC,WAAW,gBACX,OAAO;GACL,YAAY,WAAW;GACvB,GAAG,mBAAmB,QAAQ,KAAK,UAAU;GAC9C,EACF;qBACE,KAAK,UAAU;kBAClB,EAAE,KAAK;kBACP,CAAC,KACC,WAAW,gBACX,OAAO;GAAE,YAAY,WAAW;GAAQ,OAAO,OAAO,GAAG;GAAS,EACnE;qBACE,KAAK,KAAK;kBACb,EAAE,KAAK;kBACP,CAAC,KACC,WAAW,gBACX,OAAO;GAAE,YAAY,WAAW;GAAS,OAAO,OAAO,GAAG;GAAe,EAC1E;qBACE,IAAI,KAAK,KAAK,UAAU,CAAC,aAAa,CAAC;kBAC1C,EAAE,KAAK;gBACT,EAAE,KAAK;;gBAEP,CAAC,KACC,eACE,cAAc,eAAe,KAAK,KAAK,OAAO,KAAK,GAAG,EAEzD;mBACE,eAAe,cACd,CAAC,KACC,WAAW,mBACX,OAAO;GACL,YAAY,WAAW;GACvB,OAAO,OAAO,QAAQ;GACtB,iBAAiB,OAAO,QAAQ;GACjC,EACF;uBACE,WAAW;oBACd,EAAE,MACF;gBACJ,EAAE,KAAK;;iBAEN,eAAe,KAAK,MACnB,CAAC,KAAK,WAAW,uBAAuB;qBACrC,eAAe,cACd,CAAC,KAAK,WAAW,iBAAiB;yBAC/B,aAAa,UACZ,CAAC,KACC,WAAW,gBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,cAAc,EACnD;4BACC,CAAC,KAAK,WAAW,sBAAsB;8BACrC,CAAC,KACC,WAAW,oBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,GAAG;GAAS,EACjE;;8BAED,EAAE,KAAK;8BACP,CAAC,KACC,WAAW,qBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,QAAQ;GAAS,EACtE;iCACE,eAAe,SAAS,SAAS,CAAC;8BACrC,EAAE,KAAK;4BACT,EAAE,KAAK;4BACP,CAAC,KACC,WAAW,2BACX,OAAO;GAAE,YAAY,WAAW;GAAS,OAAO,OAAO,GAAG;GAAe,EAC1E;;;4BAGD,EAAE,KAAK;0BACT,EAAE,MACF;;yBAED,YAAY,UACX,CAAC,KACC,WAAW,gBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,cAAc,EACnD;4BACC,CAAC,KAAK,WAAW,sBAAsB;8BACrC,CAAC,KACC,WAAW,oBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,GAAG;GAAS,EACjE;;8BAED,EAAE,KAAK;8BACP,CAAC,KACC,WAAW,qBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,QAAQ;GAAS,EACtE;iCACE,eAAe,QAAQ,SAAS,CAAC;8BACpC,EAAE,KAAK;4BACT,EAAE,KAAK;4BACP,CAAC,KACC,WAAW,2BACX,OAAO;GAAE,YAAY,WAAW;GAAS,OAAO,OAAO,GAAG;GAAe,EAC1E;;4BAED,EAAE,KAAK;0BACT,EAAE,MACF;;yBAED,QAAQ,UACP,CAAC,KACC,WAAW,gBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,cAAc,EACnD;4BACC,CAAC,KAAK,WAAW,sBAAsB;8BACrC,CAAC,KACC,WAAW,oBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,GAAG;GAAS,EACjE;;8BAED,EAAE,KAAK;8BACP,CAAC,KACC,WAAW,qBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,QAAQ;GAAS,EACtE;iCACE,eAAe,IAAI,SAAS,CAAC;8BAChC,EAAE,KAAK;4BACT,EAAE,KAAK;4BACP,CAAC,KACC,WAAW,2BACX,OAAO;GAAE,YAAY,WAAW;GAAS,OAAO,OAAO,GAAG;GAAe,EAC1E;;4BAED,EAAE,KAAK;0BACT,EAAE,MACF;sBACJ,EAAE,MACF;;qBAED,CAAC,CAAC,KAAK,YACN,CAAC,KACC,WAAW,sBACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,aAAa,EAClD;wBACC,CAAC,KACC,WAAW,kBACX,OAAO;GAAE,YAAY,WAAW;GAAM,OAAO,OAAO,GAAG;GAAS,EACjE;;wBAED,EAAE,KAAK;wBACP,CAAC,KACC,WAAW,eACX,OAAO;GAAE,YAAY,WAAW;GAAS,OAAO,OAAO,GAAG;GAAe,EAC1E;2BACE,OAAO,UAAU,KAAK,UAAU,MAAM,GAAG,EAAE,YAAY,MAAM,CAAC,CAAC,CAAC;wBACnE,EAAE,KAAK;sBACT,EAAE,MACF;kBACJ,EAAE,MACF;cACJ,EAAE,KAAK;YACT,EAAE;GAEJ,CAAC;MACL,EAAE,SAAS;IACb,EAAE;;;;;ACzTN,SAAwB,KAAK,OAAkB;CAC7C,MAAM,SAAS,gBAAgB;CAC/B,MAAM,iBAAiB,OAAiB,KAAK;CAC7C,MAAM,CAAC,aAAa,kBAAkB,SAAS,EAAE;CACjD,MAAM,UACJ,MAAM,MAAM,SAAS,IACjB,SACC,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,SAAS,GAAG;AAEpD,QACE,CAAC,KAAK,WAAW,aAAa;MAC5B,CAAC,KACC,WAAW,eACX,OAAO,EACL,WAAW,oBAAoB,OAAO,OAAO,iBAC9C,EACF;SACE,MAAM,MAAM,KAAK,MAAM,MACtB,CAAC,KACC,KAAK,KAAK,KACV,WAAW,sBACX,eAAe;AACb,iBAAe,EAAE;AACjB,QAAM,eAAe;AAErB,iBAAe,SACX,OAAO;GACP,QAAQ;GACR,QAAQ;IACN,UAAU;IACV,QAAQ;IACT;GACF,CAAC,CACD,MAAM;IAEZ;YACC,CAAC,KACC,WAAW,yBAAyB,UAAU,4BAA4B,YAAY,MACtF,OAAO;EACL,YAAY,WAAW;EACvB,OACE,MAAM,cACF,OAAO,GAAG,UACV,OAAO,GAAG;EACjB,EACF;eACE,KAAK,MAAM;YACd,EAAE,KAAK;aACN,MAAM,KACL,CAAC,KACC,WAAW,yBACX,OAAO,EAAE,WAAW,cAAc,cAAc,IAAI,KAAK,EAC1D;gBACC,CAAC,KACC,WAAW,6BACX,OAAO,EAAE,iBAAiB,OAAO,GAAG,SAAS,IAC7C;cACJ,EAAE,MACF;UACJ,EAAE,MACF,CAAC;MACL,EAAE,KAAK;;MAEP,CAAC,KACC,KAAK,gBACL,WAAW,iBACX,gCACA,WAAW;EAAE,QAAQ;EAAG,QAAQ;EAAG,EACnC,kBAAkB,MAAM,eAAe,EACvC,WAAW,MAAqB;AAC9B,iBAAe,EAAE,OAAO,SAAS;IAEnC,SAAS,OACT,sBAAsB,MAAM,MAAM,QACnC;SACE,MAAM,MAAM,KAAK,SAChB,CAAC,UACC,KAAK,KAAK,KACV,UAAU,KAAK,KACf,YAAY,OACZ,WAAW,gBACZ;aACE,KAAK,eAAe,CAAC;UACxB,EAAE,WACF,CAAC;MACL,EAAE,KAAK;IACT,EAAE;;;;;ACzFN,MAAa,gBAAgB,EAAE,iBAAoC;CACjE,MAAM,EAAE,MAAM,cAAc,YAAY;CACxC,MAAM,EAAE,UAAU,kBAAkB,YAAY;CAChD,MAAM,EAAE,cAAc,sBAAsB,gBAAgB;CAE5D,MAAM,QAAQ,WAAW,kBAAkB;CAE3C,MAAM,QAID,EAAE;AAEP,KAAI,OAAO,KACT,OAAM,KAAK;EACT,KAAK;EACL,OAAO;EACP,qBAAqB,CAAC,SAAS,MAAM,MAAM,WAAW;EACvD,CAAC;AAGJ,KAAI,OAAO,SACT,OAAM,KAAK;EACT,KAAK;EACL,OAAO;EACP,qBACE,CAAC,aAAa,UAAU,UAAU,eAAe;EAEpD,CAAC;AAGJ,KAAI,OAAO,aACT,OAAM,KAAK;EACT,KAAK;EACL,OAAO;EACP,qBACE,CAAC,iBACC,cAAc,cACd,mBAAmB;EAGxB,CAAC;AAGJ,KAAI,WACF,MAAK,MAAM,OAAO,WAChB,OAAM,KAAK;EACT,KAAK,IAAI;EACT,OAAO,IAAI;EACX,eAAe,IAAI;EACpB,CAAC;AAIN,KAAI,MAAM,WAAW,EACnB,QAAO;AAGT,QACE,CAAC,KAAK,yBAAyB;MAC7B,CAAC,KAAK,aAAa,uBAAuB,OAAO,SAAS;IAC5D,EAAE;;;;;ACtEN,MAAM,sBAAsB;AAC5B,MAAM,iBAAiB;AAEvB,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AAEvB,IAAI,aAAa;AACjB,IAAI,cAAc;AAElB,SAAgB,iBAAiB,OAAmB;CAClD,MAAM,CAAC,OAAO,YAAY,SAAS,WAAW;CAC9C,MAAM,CAAC,QAAQ,aAAa,SAAS,YAAY;CACjD,MAAM,CAAC,OAAO,YAAY,SAA4C,OAAO;CAC7E,MAAM,CAAC,WAAW,gBAAgB,SAAS,WAAW;CACtD,MAAM,CAAC,YAAY,iBAAiB,SAAS,YAAY;CAEzD,MAAM,WAAW,OAA6C,KAAK;CACnE,MAAM,cAAc,OAAO,MAAM;CACjC,MAAM,WAAW,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;EAAG,GAAG;EAAG,CAAC;CAEnD,MAAM,mBAAmB;AACvB,MAAI,SAAS,SAAS;AACpB,gBAAa,SAAS,QAAQ;AAC9B,YAAS,UAAU;;;CAIvB,MAAM,oBAAoB,MAA8B;AACtD,WAAS,UAAU;GACjB,GAAG,EAAE,OAAO;GACZ,GAAG,EAAE,OAAO;GACZ,GAAG;GACH,GAAG;GACJ;AACD,cAAY,UAAU;AAEtB,WAAS,UAAU,iBAAiB;AAClC,eAAY,UAAU;AACtB,YAAS,WAAW;AACpB,gBAAa,MAAM;AACnB,iBAAc,OAAO;KACpB,oBAAoB;;CAGzB,MAAM,mBAAmB,MAA8B;EACrD,MAAM,KAAK,EAAE,OAAO,IAAI,SAAS,QAAQ;EACzC,MAAM,KAAK,EAAE,OAAO,IAAI,SAAS,QAAQ;AAEzC,MACE,CAAC,YAAY,YACZ,KAAK,IAAI,GAAG,GAAG,kBAAkB,KAAK,IAAI,GAAG,GAAG,gBAEjD,aAAY;AAGd,MAAI,CAAC,YAAY,QAAS;AAG1B,eAAa,SAAS,QAAQ,IAAI,GAAG;AACrC,gBAAc,SAAS,QAAQ,IAAI,GAAG;;CAGxC,MAAM,uBAAuB;AAC3B,cAAY;AAEZ,MAAI,YAAY,SAAS;AACvB,YAAS,UAAU;AACnB,aAAU,WAAW;AACrB,gBAAa;AACb,iBAAc;AACd,YAAS,YAAY;AACrB,eAAY,UAAU;AACtB,oBAAiB,SAAS,OAAO,EAAE,IAAI;QAEvC,QAAO;;CAIX,MAAM,aAAa,UAAU;AAE7B,QAAO;EACL;EACA,OAAO,aAAa,YAAY;EAChC,QAAQ,aAAa,aAAa;EAClC;EACA,UAAU;GACR,iBAAiB;GACjB,gBAAgB;GAChB,eAAe;GAChB;EACF;;;;;AClFH,MAAM,eAAe;CACnB,MAAM;EACJ,WAAW;EACX,SAAS;EACV;CACD,UAAU;EACR,WAAW;EACX,SAAS;EACT,YAAY;EACb;CACD,WAAW;EACT,WAAW;EACX,SAAS;EACT,YAAY;EACb;CACF;AAED,MAAa,kBAAkB,EAC7B,SACA,eACyB;CACzB,MAAM,SAAS,gBAAgB;CAC/B,MAAM,EAAE,OAAO,OAAO,QAAQ,YAAY,aACxC,iBAAiB,QAAQ;CAG3B,MAAM,qBAAqB;AACzB,MAAI;AACF,QAAK,OAAO,EAAE,QAAQ;AACpB,YAAQ,IAAI,YAAY;KACxB;WACK,GAAG;AACV,WAAQ,MAAM,gCAAgC,EAAE;;;CAIpD,MAAM,aAAa,UAAU;AAE7B,QACE,EAAE;MACA,CAAC,KACC,WAAW,cACX,qBAAqB,CAAC,CAAC,MAAM,IAAI,CAAC,EAClC,OAAO;EACL,OAAO,GAAG,MAAM;EAChB,QAAQ,GAAG,OAAO;EAClB,WAAW,aAAa,gBAAgB;EACxC,YAAY,aAAa,SAAS,GAAG;EACtC,MACG,UACL;QACC,CAAC,KACC,WAAW,aACX,OAAO,EAAE,iBAAiB,OAAO,QAAQ,UAAU,EACpD;WACE,SAAS;UACV,CAAC,KAAK,WAAW,mBAAmB,OAAO,aAAa,UAAU;QACpE,EAAE,KAAK;QACP,CAAC,KACC,WAAW,mBACX,OAAO,EAAE,iBAAiB,OAAO,QAAQ,UAAU,EACnD,uBAAuB,YAAY,EACnC,SAAS,cACV;UACC,CAAC,KACC,WAAW,iBACX,OAAO,EAAE,OAAO,OAAO,QAAQ,aAAa,EAC7C;aACE,IAAS;UACZ,EAAE,KAAK;QACT,EAAE,KAAK;MACT,EAAE,KAAK;IACT;;;;;AC5CJ,MAAM,cAAc,YAEhB,EAAE,QAAQ,SAAS,sBAAsB,QAAQ,cACjD,QACG;CACH,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,EAAE,iBAAiB,gBAAgB;CACzC,MAAM,SAAS,cAAc,UAAU,MAAM,EAAE,CAAC,MAAM,CAAC;CAEvD,MAAM,YAAY,cAAc;AAC9B,OAAK,IAAI,IAAI,aAAa,SAAS,GAAG,KAAK,GAAG,KAAK;GACjD,MAAM,OAAO,aAAa;AAC1B,OAAI,QAAQ,KAAK,cAAc,YAAY,KAAK,SAAS,OAAO;IAC9D,MAAM,cAAc,KAAK;AAEzB,QAAI,aAAa,UAAU,aAAa,OACtC,QAAO,YAAY;AAErB,QAAI,aAAa,SAAS,aAAa,OACrC,QAAO,YAAY;;;IAKxB,CAAC,aAAa,CAAC;AAElB,qBAAoB,YAAY;EAC9B,YAAY;AACV,aAAU,KAAK;AACf,kBAAe,MAAM;;EAEvB,aAAa;AACX,kBAAe,KAAK;;EAEtB,cAAc;EACf,EAAE;CAEH,MAAM,8BAA8B;AAClC,YAAU,KAAK;AACf,iBAAe,MAAM;;CAGvB,MAAM,+BAA+B;AACnC,YAAU,MAAM;AAChB,iBAAe,MAAM;;AAGvB,QACE,CAAC,cAAc,OAAO,QAAQ;QAC5B,CAAC,KACC,OAAO;EACL,iBAAiB,OAAO,GAAG;EAC3B,OAAO,OAAO,GAAG;EAClB,EACF;UACC,CAAC,eAAe,SAAS,uBAAuB;YAC9C,CAAC,KAAK,qBAAqB,OAAO;EAAE,YAAY;EAAO,OAAO,OAAO,QAAQ;EAAa,EAAE,WAAW,EAAE,KAAK;YAC9G,CAAC,KAAK,wBAAwB,OAAO;EAAE,YAAY;EAAO,OAAO,OAAO,QAAQ;EAAa,EAAE;eAC5F,GAAG,WAAW,QAAQ,MAAM,IAAI,WAAW,WAAW,UAAU,SAAS,QAAQ,EAAE,GAAG,KAAK,IAAI;YAClG,EAAE,KAAK;UACT,EAAE,eAAe;WAChB,UACC,CAAC,YACC,QAAQ,QACR,aAAa,aACb,SAAS,wBACT,qBACA,qBAAqB,qBACtB;cACC,CAAC,aAAa,YAAY,cAAc;YAC1C,EAAE,aACF;QACJ,EAAE,KAAK;MACT,EAAE;EAGP"}
package/dist/setup.cjs CHANGED
@@ -1,4 +1,3 @@
1
- import "./index.css";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
2
  let _lynx_js_react = require("@lynx-js/react");
4
3
  let javascript_stringify = require("javascript-stringify");
package/dist/setup.d.cts CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  //#region src/setup/setupLogMonitor.d.ts
3
2
  declare const initLogMonitor: () => void;
4
3
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.cts","names":[],"sources":["../src/setup/setupLogMonitor.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"mappings":";;cAsCa,cAAA;;;cC7BA,qBAAA,QAAkC,OAAA;;;cCiHlC,kBAAA;;;cClGA,sBAAA"}
1
+ {"version":3,"file":"setup.d.cts","names":[],"sources":["../src/setup/setupLogMonitor.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"mappings":";cAsCa,cAAA;;;cC7BA,qBAAA,QAAkC,OAAA;;;cCiHlC,kBAAA;;;cClGA,sBAAA"}
package/dist/setup.d.mts CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  //#region src/setup/setupLogMonitor.d.ts
3
2
  declare const initLogMonitor: () => void;
4
3
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.mts","names":[],"sources":["../src/setup/setupLogMonitor.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"mappings":";;cAsCa,cAAA;;;cC7BA,qBAAA,QAAkC,OAAA;;;cCiHlC,kBAAA;;;cClGA,sBAAA"}
1
+ {"version":3,"file":"setup.d.mts","names":[],"sources":["../src/setup/setupLogMonitor.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"mappings":";cAsCa,cAAA;;;cC7BA,qBAAA,QAAkC,OAAA;;;cCiHlC,kBAAA;;;cClGA,sBAAA"}
package/dist/setup.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import "./index.css";
2
1
  import { runOnBackground, runOnMainThread } from "@lynx-js/react";
3
2
  import { stringify } from "javascript-stringify";
4
3
 
@@ -1 +1 @@
1
- {"version":3,"file":"setup.mjs","names":[],"sources":["../src/shared/ensureConsoleStructure.ts","../src/setup/setupLogMonitor.ts","../src/setup/_setupMainThreadConsole.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"sourcesContent":["type LynxConsole = NonNullable<typeof globalThis.__LYNX_CONSOLE__>;\ntype ConsoleState = NonNullable<LynxConsole[\"state\"]>;\n\nexport const ensureConsoleStructure = (): {\n lynxConsole: LynxConsole;\n state: ConsoleState;\n} => {\n if (!globalThis.__LYNX_CONSOLE__) {\n globalThis.__LYNX_CONSOLE__ = {};\n }\n\n if (!globalThis.__LYNX_CONSOLE__.state) {\n globalThis.__LYNX_CONSOLE__.state = {};\n }\n\n return {\n lynxConsole: globalThis.__LYNX_CONSOLE__,\n state: globalThis.__LYNX_CONSOLE__.state,\n };\n};\n","import { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport type { LogEntry, LogLevel } from \"../types\";\n\ntype LogListener = (entry: LogEntry) => void;\n\nconst LOG_METHODS: LogLevel[] = [\"log\", \"warn\", \"error\", \"info\"];\nconst LOG_ID_PREFIX = \"background-thread\";\n\nconst generateLogId = (): string => {\n return `${LOG_ID_PREFIX}-${Date.now()}-${Math.random()}`;\n};\n\nconst createLogEntry = (method: LogLevel, args: unknown[]): LogEntry => {\n return {\n id: generateLogId(),\n level: method,\n message: \"\",\n timestamp: Date.now(),\n args,\n };\n};\n\nconst addLogEntry = (entry: LogEntry): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.logs || !state?.logListeners) {\n console.error(\n \"[LynxConsole] Cannot add log entry: Log monitor not initialized. Call initLogMonitor() first.\",\n );\n return;\n }\n\n state.logs.push(entry);\n state.logListeners.forEach((listener) => {\n listener(entry);\n });\n};\n\n// Background Thread: Log monitoring 초기화\nexport const initLogMonitor = () => {\n \"background only\";\n\n const { lynxConsole, state } = ensureConsoleStructure();\n\n if (lynxConsole.originalConsole) {\n console.warn(\"[LynxConsole] Log monitor already initialized\");\n return;\n }\n\n const originalConsole = globalThis.console;\n lynxConsole.originalConsole = {\n log: originalConsole.log.bind(originalConsole),\n warn: originalConsole.warn.bind(originalConsole),\n error: originalConsole.error.bind(originalConsole),\n info: originalConsole.info.bind(originalConsole),\n };\n\n state.logs = [];\n state.logListeners = new Set();\n state.logSubscribe = (listener: LogListener) => {\n state.logListeners?.add(listener);\n return () => {\n state.logListeners?.delete(listener);\n };\n };\n\n // Background Thread console 오버라이드\n LOG_METHODS.forEach((method) => {\n globalThis.console[method] = ((...args: unknown[]) => {\n lynxConsole.originalConsole?.[method](...args);\n const entry = createLogEntry(method, args);\n addLogEntry(entry);\n }).bind(globalThis.console);\n });\n\n lynxConsole.originalConsole?.log(\n \"[LynxConsole] ✅ Log monitoring initialized\",\n );\n};\n","import { runOnBackground } from \"@lynx-js/react\";\nimport type { LogEntry, LogLevel } from \"../types\";\n\nconst _setupMainThreadConsole = (): void => {\n \"main thread\";\n\n //IMPORTANT: do not use external functions in main thread\n if (!globalThis.__LYNX_CONSOLE__) globalThis.__LYNX_CONSOLE__ = {};\n const lynxConsole = globalThis.__LYNX_CONSOLE__;\n\n if (lynxConsole.mainThreadInitialized) {\n console.warn(\"[LynxConsole] Main thread console already initialized\");\n return;\n }\n\n const LOG_METHODS: LogLevel[] = [\"log\", \"warn\", \"error\", \"info\"];\n const LOG_ID_PREFIX = \"main-thread\";\n\n const serializeArgs = (args: unknown[]): unknown[] => {\n return args.map((arg) => {\n try {\n JSON.stringify(arg);\n return arg;\n } catch {\n return String(arg);\n }\n });\n };\n\n const generateLogId = (): string => {\n return `${LOG_ID_PREFIX}-${Date.now()}-${Math.random()}`;\n };\n\n // Main Thread에서 Background Thread로 로그 전송하는 함수\n const sendLogToBackground = runOnBackground((entry: LogEntry): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state) return;\n\n state.logs?.push(entry);\n state.logListeners?.forEach((listener) => {\n listener(entry);\n });\n });\n\n const originalConsole = globalThis.console;\n\n const originalMethods = {\n log: originalConsole.log.bind(originalConsole),\n warn: originalConsole.warn.bind(originalConsole),\n error: originalConsole.error.bind(originalConsole),\n info: originalConsole.info.bind(originalConsole),\n };\n\n // Main Thread console 오버라이드\n LOG_METHODS.forEach((method) => {\n const original = originalMethods[method];\n originalConsole[method] = ((...args: unknown[]) => {\n // 원본 console 호출\n original(...args);\n\n const serializedArgs = serializeArgs(args);\n const timestamp = Date.now();\n const id = generateLogId();\n\n sendLogToBackground({\n id,\n level: method,\n message: \"\",\n timestamp,\n args: serializedArgs,\n });\n }).bind(originalConsole);\n });\n\n lynxConsole.mainThreadInitialized = true;\n\n originalConsole.log(\"[LynxConsole] ✅ Main thread console initialized\");\n};\n\nexport default _setupMainThreadConsole;\n","// both thread;\nimport \"./_setupMainThreadConsole\";\n\nimport { runOnMainThread } from \"@lynx-js/react\";\nimport { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport _setupMainThreadConsole from \"./_setupMainThreadConsole\";\n\n// Main Thread: Console 초기화\n\nexport const initMainThreadConsole = async (): Promise<void> => {\n \"background only\";\n\n const { lynxConsole, state } = ensureConsoleStructure();\n\n if (lynxConsole.mainThreadInitialized) {\n console.error(\"[LynxConsole] Main thread console already initialized\");\n return;\n }\n\n if (!state.logs) {\n console.error(\"[LynxConsole] Background thread console not initialized\");\n return;\n }\n\n try {\n const setupOnMainThread = runOnMainThread(_setupMainThreadConsole);\n await setupOnMainThread();\n } catch (error) {\n console.error(\n \"[LynxConsole] Failed to initialize main thread console:\",\n error,\n );\n }\n};\n","import { stringify } from \"javascript-stringify\";\nimport { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport type { NetworkEntry } from \"../types\";\n\nconst generateNetworkId = (): string => {\n return `network-${Date.now()}-${Math.random()}`;\n};\n\nconst extractUrl = (input: RequestInfo | URL): string => {\n if (typeof input === \"string\") return input;\n if (input instanceof URL) return input.href;\n return (input as Request).url;\n};\n\nconst extractMethod = (\n input: RequestInfo | URL,\n init?: RequestInit,\n): string | undefined => {\n if (init?.method) return init.method;\n if (typeof input === \"object\" && \"method\" in input) {\n return (input as Request).method;\n }\n return \"GET\";\n};\n\nconst extractHeaders = (\n headers: HeadersInit | undefined,\n): Record<string, string> => {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n try {\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n result[key] = value;\n });\n } else if (Array.isArray(headers)) {\n headers.forEach(([key, value]) => {\n result[key] = value;\n });\n } else {\n Object.entries(headers).forEach(([key, value]) => {\n result[key] = value;\n });\n }\n } catch (error) {\n console.error(\"[LynxConsole] Failed to extract headers:\", error);\n }\n\n return result;\n};\n\nconst mergeRequestHeaders = (\n input: RequestInfo | URL,\n init?: RequestInit,\n): Record<string, string> => {\n const merged: Record<string, string> = {};\n\n // Request 객체나 URL 객체에서 헤더 추출\n if (typeof input === \"object\" && \"headers\" in input) {\n Object.assign(merged, extractHeaders(input.headers as HeadersInit));\n }\n\n // RequestInit에서 헤더 추출 (나중 값이 우선)\n if (init?.headers) {\n Object.assign(merged, extractHeaders(init.headers));\n }\n\n return merged;\n};\n\nconst addNetworkEntry = (entry: NetworkEntry): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.networks || !state?.networksMap || !state?.networkListeners) {\n console.error(\n \"[LynxConsole] Cannot add network entry: Network monitor not initialized. Call initNetworkMonitor() first.\",\n );\n return;\n }\n\n state.networks.push(entry);\n state.networksMap.set(entry.id, entry);\n\n state.networkListeners.forEach((listener) => {\n listener(entry);\n });\n};\n\nconst updateNetworkEntry = (\n id: string,\n updates: Partial<NetworkEntry>,\n): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.networks || !state?.networksMap || !state?.networkListeners) {\n console.error(\n \"[LynxConsole] Cannot update network entry: Network monitor not initialized. Call initNetworkMonitor() first.\",\n );\n return;\n }\n\n const existingEntry = state.networksMap.get(id);\n if (!existingEntry) {\n console.error(\n `[LynxConsole] Cannot update network entry: Entry with id '${id}' not found.`,\n );\n return;\n }\n\n const updatedEntry = { ...existingEntry, ...updates };\n\n const index = state.networks.findIndex((entry) => entry.id === id);\n if (index !== -1) {\n state.networks[index] = updatedEntry;\n }\n\n state.networksMap.set(id, updatedEntry);\n\n state.networkListeners.forEach((listener) => {\n listener(updatedEntry);\n });\n};\n\nexport const initNetworkMonitor = () => {\n if (!lynx.fetch) {\n console.warn(\n \"[LynxConsole] lynx.fetch not available, skipping network monitor\",\n );\n return;\n }\n\n const { state } = ensureConsoleStructure();\n\n if (state.networks !== undefined) {\n console.warn(\"[LynxConsole] Network monitor already initialized\");\n return;\n }\n\n type NetworkListener = (entry: NetworkEntry) => void;\n state.networks = [];\n state.networksMap = new Map();\n state.networkListeners = new Set();\n state.subscribeNetwork = (listener: NetworkListener) => {\n state.networkListeners?.add(listener);\n return () => {\n state.networkListeners?.delete(listener);\n };\n };\n\n const originalFetch = fetch.bind(lynx);\n\n const monitoredFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const id = generateNetworkId();\n const startTime = Date.now();\n const url = extractUrl(input);\n const method = extractMethod(input, init);\n\n const requestHeaders = mergeRequestHeaders(input, init);\n\n // Request body 처리\n let requestBody: string | undefined;\n if (init?.body) {\n if (typeof init.body === \"string\") {\n requestBody = init.body;\n } else if (init.body instanceof URLSearchParams) {\n requestBody = init.body.toString();\n } else {\n // Lynx가 지원하지 않는 타입이거나 알 수 없는 타입\n requestBody = String(init.body);\n }\n }\n\n addNetworkEntry({\n id,\n url,\n method: method || \"default\",\n status: \"pending\",\n startTime,\n requestHeaders,\n requestBody: requestBody ?? \"\",\n });\n\n try {\n const response = await originalFetch(input, init);\n const endTime = Date.now();\n\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n const clonedResponse = response.clone();\n let responseBody: string | undefined;\n\n try {\n const headerMap: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headerMap[key.toLowerCase()] = value;\n });\n\n const contentType = headerMap[\"content-type\"];\n if (contentType?.includes(\"application/json\")) {\n const json = await clonedResponse.json();\n responseBody = stringify(json, null, 2, { references: true }) ?? \"\";\n } else if (contentType?.includes(\"text\")) {\n responseBody = await clonedResponse.text();\n }\n } catch (error) {\n responseBody = `[Unable to read response body] ${error}`;\n console.error(\"[LynxConsole] Error reading response body:\", error);\n }\n\n updateNetworkEntry(id, {\n status: \"success\",\n statusCode: response.status,\n statusText: response.statusText,\n endTime,\n duration: endTime - startTime,\n responseHeaders,\n responseBody: responseBody ?? \"\",\n });\n\n return response;\n } catch (error) {\n const endTime = Date.now();\n updateNetworkEntry(id, {\n status: \"error\",\n endTime,\n duration: endTime - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n };\n\n // biome-ignore lint/suspicious/noTsIgnore: to assign fetch to global functionfetch\n // @ts-ignore\n // biome-ignore lint/suspicious/noGlobalAssign: to assign fetch to global functionfetch fetch\n fetch = monitoredFetch as typeof fetch;\n\n //fetch 대신 lynx.fetch를 사용하는 경우에도 모니터링 되도록 설정\n lynx.fetch = monitoredFetch as typeof lynx.fetch;\n\n console.log(\"[LynxConsole] ✅ Network monitoring initialized\");\n};\n","import { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport type { PerformanceEntryData, PerformanceEntryType } from \"../types\";\n\ntype PerformanceListener = (entry: PerformanceEntryData) => void;\n\nconst generatePerformanceId = (): string => {\n return `performance-${Date.now()}-${Math.random()}`;\n};\n\nconst addPerformanceEntry = (entry: PerformanceEntryData): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.performances || !state?.performanceListeners) {\n console.error(\n \"[LynxConsole] Cannot add performance entry: Performance monitor not initialized. Call initPerformanceMonitor() first.\",\n );\n return;\n }\n\n state.performances.push(entry);\n state.performanceListeners.forEach((listener) => {\n listener(entry);\n });\n};\n\nexport const initPerformanceMonitor = () => {\n \"background only\";\n\n if (!lynx.performance) {\n console.warn(\n \"[LynxConsole] lynx.performance not available, skipping performance monitor\",\n );\n return;\n }\n\n const { state } = ensureConsoleStructure();\n\n if (state.performances !== undefined) {\n console.warn(\"[LynxConsole] Performance monitor already initialized\");\n return;\n }\n\n state.performances = [];\n state.performanceListeners = new Set();\n state.subscribePerformance = (listener: PerformanceListener) => {\n state.performanceListeners?.add(listener);\n return () => {\n state.performanceListeners?.delete(listener);\n };\n };\n\n const observer = lynx.performance.createObserver((entry) => {\n const performanceEntry: PerformanceEntryData = {\n id: generatePerformanceId(),\n entryType: entry.entryType as PerformanceEntryType,\n name: entry.name,\n timestamp: Date.now(),\n rawEntry: entry,\n };\n\n addPerformanceEntry(performanceEntry);\n });\n\n observer.observe([\n \"pipeline\", // LoadBundleEntry\n \"init\", // InitLynxviewEntry\n \"metric\", // MetricEntry\n ]);\n\n console.log(\"[LynxConsole] ✅ Performance monitoring initialized\");\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"setup.mjs","names":[],"sources":["../src/shared/ensureConsoleStructure.ts","../src/setup/setupLogMonitor.ts","../src/setup/_setupMainThreadConsole.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"sourcesContent":["type LynxConsole = NonNullable<typeof globalThis.__LYNX_CONSOLE__>;\ntype ConsoleState = NonNullable<LynxConsole[\"state\"]>;\n\nexport const ensureConsoleStructure = (): {\n lynxConsole: LynxConsole;\n state: ConsoleState;\n} => {\n if (!globalThis.__LYNX_CONSOLE__) {\n globalThis.__LYNX_CONSOLE__ = {};\n }\n\n if (!globalThis.__LYNX_CONSOLE__.state) {\n globalThis.__LYNX_CONSOLE__.state = {};\n }\n\n return {\n lynxConsole: globalThis.__LYNX_CONSOLE__,\n state: globalThis.__LYNX_CONSOLE__.state,\n };\n};\n","import { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport type { LogEntry, LogLevel } from \"../types\";\n\ntype LogListener = (entry: LogEntry) => void;\n\nconst LOG_METHODS: LogLevel[] = [\"log\", \"warn\", \"error\", \"info\"];\nconst LOG_ID_PREFIX = \"background-thread\";\n\nconst generateLogId = (): string => {\n return `${LOG_ID_PREFIX}-${Date.now()}-${Math.random()}`;\n};\n\nconst createLogEntry = (method: LogLevel, args: unknown[]): LogEntry => {\n return {\n id: generateLogId(),\n level: method,\n message: \"\",\n timestamp: Date.now(),\n args,\n };\n};\n\nconst addLogEntry = (entry: LogEntry): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.logs || !state?.logListeners) {\n console.error(\n \"[LynxConsole] Cannot add log entry: Log monitor not initialized. Call initLogMonitor() first.\",\n );\n return;\n }\n\n state.logs.push(entry);\n state.logListeners.forEach((listener) => {\n listener(entry);\n });\n};\n\n// Background Thread: Log monitoring 초기화\nexport const initLogMonitor = () => {\n \"background only\";\n\n const { lynxConsole, state } = ensureConsoleStructure();\n\n if (lynxConsole.originalConsole) {\n console.warn(\"[LynxConsole] Log monitor already initialized\");\n return;\n }\n\n const originalConsole = globalThis.console;\n lynxConsole.originalConsole = {\n log: originalConsole.log.bind(originalConsole),\n warn: originalConsole.warn.bind(originalConsole),\n error: originalConsole.error.bind(originalConsole),\n info: originalConsole.info.bind(originalConsole),\n };\n\n state.logs = [];\n state.logListeners = new Set();\n state.logSubscribe = (listener: LogListener) => {\n state.logListeners?.add(listener);\n return () => {\n state.logListeners?.delete(listener);\n };\n };\n\n // Background Thread console 오버라이드\n LOG_METHODS.forEach((method) => {\n globalThis.console[method] = ((...args: unknown[]) => {\n lynxConsole.originalConsole?.[method](...args);\n const entry = createLogEntry(method, args);\n addLogEntry(entry);\n }).bind(globalThis.console);\n });\n\n lynxConsole.originalConsole?.log(\n \"[LynxConsole] ✅ Log monitoring initialized\",\n );\n};\n","import { runOnBackground } from \"@lynx-js/react\";\nimport type { LogEntry, LogLevel } from \"../types\";\n\nconst _setupMainThreadConsole = (): void => {\n \"main thread\";\n\n //IMPORTANT: do not use external functions in main thread\n if (!globalThis.__LYNX_CONSOLE__) globalThis.__LYNX_CONSOLE__ = {};\n const lynxConsole = globalThis.__LYNX_CONSOLE__;\n\n if (lynxConsole.mainThreadInitialized) {\n console.warn(\"[LynxConsole] Main thread console already initialized\");\n return;\n }\n\n const LOG_METHODS: LogLevel[] = [\"log\", \"warn\", \"error\", \"info\"];\n const LOG_ID_PREFIX = \"main-thread\";\n\n const serializeArgs = (args: unknown[]): unknown[] => {\n return args.map((arg) => {\n try {\n JSON.stringify(arg);\n return arg;\n } catch {\n return String(arg);\n }\n });\n };\n\n const generateLogId = (): string => {\n return `${LOG_ID_PREFIX}-${Date.now()}-${Math.random()}`;\n };\n\n // Main Thread에서 Background Thread로 로그 전송하는 함수\n const sendLogToBackground = runOnBackground((entry: LogEntry): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state) return;\n\n state.logs?.push(entry);\n state.logListeners?.forEach((listener) => {\n listener(entry);\n });\n });\n\n const originalConsole = globalThis.console;\n\n const originalMethods = {\n log: originalConsole.log.bind(originalConsole),\n warn: originalConsole.warn.bind(originalConsole),\n error: originalConsole.error.bind(originalConsole),\n info: originalConsole.info.bind(originalConsole),\n };\n\n // Main Thread console 오버라이드\n LOG_METHODS.forEach((method) => {\n const original = originalMethods[method];\n originalConsole[method] = ((...args: unknown[]) => {\n // 원본 console 호출\n original(...args);\n\n const serializedArgs = serializeArgs(args);\n const timestamp = Date.now();\n const id = generateLogId();\n\n sendLogToBackground({\n id,\n level: method,\n message: \"\",\n timestamp,\n args: serializedArgs,\n });\n }).bind(originalConsole);\n });\n\n lynxConsole.mainThreadInitialized = true;\n\n originalConsole.log(\"[LynxConsole] ✅ Main thread console initialized\");\n};\n\nexport default _setupMainThreadConsole;\n","// both thread;\nimport \"./_setupMainThreadConsole\";\n\nimport { runOnMainThread } from \"@lynx-js/react\";\nimport { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport _setupMainThreadConsole from \"./_setupMainThreadConsole\";\n\n// Main Thread: Console 초기화\n\nexport const initMainThreadConsole = async (): Promise<void> => {\n \"background only\";\n\n const { lynxConsole, state } = ensureConsoleStructure();\n\n if (lynxConsole.mainThreadInitialized) {\n console.error(\"[LynxConsole] Main thread console already initialized\");\n return;\n }\n\n if (!state.logs) {\n console.error(\"[LynxConsole] Background thread console not initialized\");\n return;\n }\n\n try {\n const setupOnMainThread = runOnMainThread(_setupMainThreadConsole);\n await setupOnMainThread();\n } catch (error) {\n console.error(\n \"[LynxConsole] Failed to initialize main thread console:\",\n error,\n );\n }\n};\n","import { stringify } from \"javascript-stringify\";\nimport { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport type { NetworkEntry } from \"../types\";\n\nconst generateNetworkId = (): string => {\n return `network-${Date.now()}-${Math.random()}`;\n};\n\nconst extractUrl = (input: RequestInfo | URL): string => {\n if (typeof input === \"string\") return input;\n if (input instanceof URL) return input.href;\n return (input as Request).url;\n};\n\nconst extractMethod = (\n input: RequestInfo | URL,\n init?: RequestInit,\n): string | undefined => {\n if (init?.method) return init.method;\n if (typeof input === \"object\" && \"method\" in input) {\n return (input as Request).method;\n }\n return \"GET\";\n};\n\nconst extractHeaders = (\n headers: HeadersInit | undefined,\n): Record<string, string> => {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n try {\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n result[key] = value;\n });\n } else if (Array.isArray(headers)) {\n headers.forEach(([key, value]) => {\n result[key] = value;\n });\n } else {\n Object.entries(headers).forEach(([key, value]) => {\n result[key] = value;\n });\n }\n } catch (error) {\n console.error(\"[LynxConsole] Failed to extract headers:\", error);\n }\n\n return result;\n};\n\nconst mergeRequestHeaders = (\n input: RequestInfo | URL,\n init?: RequestInit,\n): Record<string, string> => {\n const merged: Record<string, string> = {};\n\n // Request 객체나 URL 객체에서 헤더 추출\n if (typeof input === \"object\" && \"headers\" in input) {\n Object.assign(merged, extractHeaders(input.headers as HeadersInit));\n }\n\n // RequestInit에서 헤더 추출 (나중 값이 우선)\n if (init?.headers) {\n Object.assign(merged, extractHeaders(init.headers));\n }\n\n return merged;\n};\n\nconst addNetworkEntry = (entry: NetworkEntry): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.networks || !state?.networksMap || !state?.networkListeners) {\n console.error(\n \"[LynxConsole] Cannot add network entry: Network monitor not initialized. Call initNetworkMonitor() first.\",\n );\n return;\n }\n\n state.networks.push(entry);\n state.networksMap.set(entry.id, entry);\n\n state.networkListeners.forEach((listener) => {\n listener(entry);\n });\n};\n\nconst updateNetworkEntry = (\n id: string,\n updates: Partial<NetworkEntry>,\n): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.networks || !state?.networksMap || !state?.networkListeners) {\n console.error(\n \"[LynxConsole] Cannot update network entry: Network monitor not initialized. Call initNetworkMonitor() first.\",\n );\n return;\n }\n\n const existingEntry = state.networksMap.get(id);\n if (!existingEntry) {\n console.error(\n `[LynxConsole] Cannot update network entry: Entry with id '${id}' not found.`,\n );\n return;\n }\n\n const updatedEntry = { ...existingEntry, ...updates };\n\n const index = state.networks.findIndex((entry) => entry.id === id);\n if (index !== -1) {\n state.networks[index] = updatedEntry;\n }\n\n state.networksMap.set(id, updatedEntry);\n\n state.networkListeners.forEach((listener) => {\n listener(updatedEntry);\n });\n};\n\nexport const initNetworkMonitor = () => {\n if (!lynx.fetch) {\n console.warn(\n \"[LynxConsole] lynx.fetch not available, skipping network monitor\",\n );\n return;\n }\n\n const { state } = ensureConsoleStructure();\n\n if (state.networks !== undefined) {\n console.warn(\"[LynxConsole] Network monitor already initialized\");\n return;\n }\n\n type NetworkListener = (entry: NetworkEntry) => void;\n state.networks = [];\n state.networksMap = new Map();\n state.networkListeners = new Set();\n state.subscribeNetwork = (listener: NetworkListener) => {\n state.networkListeners?.add(listener);\n return () => {\n state.networkListeners?.delete(listener);\n };\n };\n\n const originalFetch = fetch.bind(lynx);\n\n const monitoredFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const id = generateNetworkId();\n const startTime = Date.now();\n const url = extractUrl(input);\n const method = extractMethod(input, init);\n\n const requestHeaders = mergeRequestHeaders(input, init);\n\n // Request body 처리\n let requestBody: string | undefined;\n if (init?.body) {\n if (typeof init.body === \"string\") {\n requestBody = init.body;\n } else if (init.body instanceof URLSearchParams) {\n requestBody = init.body.toString();\n } else {\n // Lynx가 지원하지 않는 타입이거나 알 수 없는 타입\n requestBody = String(init.body);\n }\n }\n\n addNetworkEntry({\n id,\n url,\n method: method || \"default\",\n status: \"pending\",\n startTime,\n requestHeaders,\n requestBody: requestBody ?? \"\",\n });\n\n try {\n const response = await originalFetch(input, init);\n const endTime = Date.now();\n\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n const clonedResponse = response.clone();\n let responseBody: string | undefined;\n\n try {\n const headerMap: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headerMap[key.toLowerCase()] = value;\n });\n\n const contentType = headerMap[\"content-type\"];\n if (contentType?.includes(\"application/json\")) {\n const json = await clonedResponse.json();\n responseBody = stringify(json, null, 2, { references: true }) ?? \"\";\n } else if (contentType?.includes(\"text\")) {\n responseBody = await clonedResponse.text();\n }\n } catch (error) {\n responseBody = `[Unable to read response body] ${error}`;\n console.error(\"[LynxConsole] Error reading response body:\", error);\n }\n\n updateNetworkEntry(id, {\n status: \"success\",\n statusCode: response.status,\n statusText: response.statusText,\n endTime,\n duration: endTime - startTime,\n responseHeaders,\n responseBody: responseBody ?? \"\",\n });\n\n return response;\n } catch (error) {\n const endTime = Date.now();\n updateNetworkEntry(id, {\n status: \"error\",\n endTime,\n duration: endTime - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n };\n\n // biome-ignore lint/suspicious/noTsIgnore: to assign fetch to global functionfetch\n // @ts-ignore\n // biome-ignore lint/suspicious/noGlobalAssign: to assign fetch to global functionfetch fetch\n fetch = monitoredFetch as typeof fetch;\n\n //fetch 대신 lynx.fetch를 사용하는 경우에도 모니터링 되도록 설정\n lynx.fetch = monitoredFetch as typeof lynx.fetch;\n\n console.log(\"[LynxConsole] ✅ Network monitoring initialized\");\n};\n","import { ensureConsoleStructure } from \"../shared/ensureConsoleStructure\";\nimport type { PerformanceEntryData, PerformanceEntryType } from \"../types\";\n\ntype PerformanceListener = (entry: PerformanceEntryData) => void;\n\nconst generatePerformanceId = (): string => {\n return `performance-${Date.now()}-${Math.random()}`;\n};\n\nconst addPerformanceEntry = (entry: PerformanceEntryData): void => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.performances || !state?.performanceListeners) {\n console.error(\n \"[LynxConsole] Cannot add performance entry: Performance monitor not initialized. Call initPerformanceMonitor() first.\",\n );\n return;\n }\n\n state.performances.push(entry);\n state.performanceListeners.forEach((listener) => {\n listener(entry);\n });\n};\n\nexport const initPerformanceMonitor = () => {\n \"background only\";\n\n if (!lynx.performance) {\n console.warn(\n \"[LynxConsole] lynx.performance not available, skipping performance monitor\",\n );\n return;\n }\n\n const { state } = ensureConsoleStructure();\n\n if (state.performances !== undefined) {\n console.warn(\"[LynxConsole] Performance monitor already initialized\");\n return;\n }\n\n state.performances = [];\n state.performanceListeners = new Set();\n state.subscribePerformance = (listener: PerformanceListener) => {\n state.performanceListeners?.add(listener);\n return () => {\n state.performanceListeners?.delete(listener);\n };\n };\n\n const observer = lynx.performance.createObserver((entry) => {\n const performanceEntry: PerformanceEntryData = {\n id: generatePerformanceId(),\n entryType: entry.entryType as PerformanceEntryType,\n name: entry.name,\n timestamp: Date.now(),\n rawEntry: entry,\n };\n\n addPerformanceEntry(performanceEntry);\n });\n\n observer.observe([\n \"pipeline\", // LoadBundleEntry\n \"init\", // InitLynxviewEntry\n \"metric\", // MetricEntry\n ]);\n\n console.log(\"[LynxConsole] ✅ Performance monitoring initialized\");\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lynx-console",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",