lynx-console 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -22
- package/dist/index.cjs +0 -1
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/dist/setup.cjs +7 -3
- package/dist/setup.mjs +9 -5
- package/dist/setup.mjs.map +1 -1
- package/package.json +6 -7
- package/src/components/LogPanel.tsx +0 -1
- package/src/setup/_setupMainThreadConsole.ts +17 -4
- package/src/styles/tokens.json +0 -80
package/README.md
CHANGED
|
@@ -1,16 +1,37 @@
|
|
|
1
|
+
[한국어](https://github.com/daangn/lynx-console/blob/main/package/README_ko.md) | English
|
|
2
|
+
|
|
1
3
|
# lynx-console
|
|
2
4
|
|
|
3
5
|
An in-app developer console that can be embedded in Lynx apps. View console logs, network requests, and performance metrics in real time.
|
|
4
6
|
|
|
7
|
+
## Demo
|
|
8
|
+
|
|
9
|
+
https://github.com/user-attachments/assets/dcd874bf-ff2e-4a98-ae03-d83de5fae31c
|
|
10
|
+
|
|
11
|
+
<img width="450" height="450" alt="lynx_bundle_qrcode_fullscreen" src="https://github.com/user-attachments/assets/8bbb9bfe-df2b-436d-ad17-6e4eb4b672c9" />
|
|
12
|
+
|
|
13
|
+
Scan the QR code above with the [Lynx Explorer](https://lynxjs.org/guide/start/quick-start.html#via-lynx-explorer-app) app to try the demo.
|
|
14
|
+
|
|
5
15
|
## Features
|
|
6
16
|
|
|
7
|
-
- **Console Logs** — View output from `console.log`, `console.error`, and more in real time
|
|
8
|
-
- **Main Thread Console** — Capture logs from the main thread
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
17
|
+
- **Console Logs** — View output from `console.log`, `console.error`, and more in real time. Supports level filtering, keyword search, log clearing, and a built-in REPL
|
|
18
|
+
- **Main Thread Console** — Capture logs from the main thread alongside background thread logs
|
|
19
|
+
|
|
20
|
+
https://github.com/user-attachments/assets/539fe31a-aca4-468d-b673-3b070b21cd08
|
|
21
|
+
|
|
22
|
+
- **Network Monitor** — Inspect method, status, headers, request body, and response of `fetch` requests
|
|
23
|
+
|
|
24
|
+
https://github.com/user-attachments/assets/edda4778-ab8d-4cb9-a3c5-bd8c42c81bde
|
|
25
|
+
|
|
26
|
+
- **Performance Monitor** — Track FCP (First Contentful Paint) and other performance metrics with raw entry details
|
|
27
|
+
|
|
28
|
+
https://github.com/user-attachments/assets/d231bdf5-71bb-483f-9bdb-5843279c1308
|
|
29
|
+
|
|
30
|
+
- **Floating Button** — Displays the latest FCP value; tap to open the console, long-press and drag to reposition it
|
|
31
|
+
- **Resizable Panel** — Drag the handle to resize the console panel (200–700px); swipe down to dismiss
|
|
32
|
+
- **Tab Visibility** — Only tabs for initialized monitors are shown; uninitialized monitors are automatically hidden
|
|
33
|
+
- **Custom Tabs** — Add your own tabs to the console via the `customTabs` prop
|
|
12
34
|
- **Light/Dark Theme** support
|
|
13
|
-
- **Seed Design** based UI
|
|
14
35
|
|
|
15
36
|
## Installation
|
|
16
37
|
|
|
@@ -22,10 +43,29 @@ yarn add lynx-console
|
|
|
22
43
|
|
|
23
44
|
```bash
|
|
24
45
|
yarn add @lynx-js/react @lynx-js/types
|
|
46
|
+
yarn add -D @types/react
|
|
25
47
|
```
|
|
26
48
|
|
|
49
|
+
> **Note:** Each monitor requires the corresponding Lynx API to be available at runtime. If `lynx.fetch` is not present, `initNetworkMonitor()` will be skipped with a warning. Likewise, `initPerformanceMonitor()` requires `lynx.performance`.
|
|
50
|
+
|
|
27
51
|
## Usage
|
|
28
52
|
|
|
53
|
+
### 0. Configure Build (Required for iOS)
|
|
54
|
+
|
|
55
|
+
On iOS, the Lynx runtime (JSC) injects a separate `console` object that is different from `globalThis.console`. This means patches applied by `initLogMonitor()` won't take effect on iOS unless you explicitly replace the `console` identifier with `globalThis.console` at build time.
|
|
56
|
+
|
|
57
|
+
Add the following to your `lynx.config.ts`:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
export default defineConfig({
|
|
61
|
+
source: {
|
|
62
|
+
define: {
|
|
63
|
+
console: "globalThis.console",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
29
69
|
### 1. Initialize Monitors
|
|
30
70
|
|
|
31
71
|
Call the monitoring functions at your app's entry point. This setup must run **before** the `LynxConsole` component is rendered.
|
|
@@ -44,6 +84,8 @@ initNetworkMonitor();
|
|
|
44
84
|
initPerformanceMonitor();
|
|
45
85
|
```
|
|
46
86
|
|
|
87
|
+
> **Note:** `initLogMonitor()` must be called before `initMainThreadConsole()`, as the main thread console depends on the log monitor being initialized first.
|
|
88
|
+
|
|
47
89
|
### 2. Render the Component
|
|
48
90
|
|
|
49
91
|
```tsx
|
|
@@ -68,7 +110,31 @@ function App() {
|
|
|
68
110
|
{/* Your app content */}
|
|
69
111
|
<Suspense>
|
|
70
112
|
<LynxConsole theme="light" safeAreaInsetBottom="34px" />
|
|
71
|
-
|
|
113
|
+
</Suspense>
|
|
114
|
+
</view>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Adding Custom Tabs
|
|
120
|
+
|
|
121
|
+
You can add your own tabs to the console using the `customTabs` prop.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import LynxConsole, { type CustomTab } from "lynx-console";
|
|
125
|
+
|
|
126
|
+
const customTabs: CustomTab[] = [
|
|
127
|
+
{
|
|
128
|
+
key: "debug",
|
|
129
|
+
label: "Debug",
|
|
130
|
+
renderContent: () => <text>Custom debug content</text>,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
function App() {
|
|
135
|
+
return (
|
|
136
|
+
<view>
|
|
137
|
+
<LynxConsole customTabs={customTabs} />
|
|
72
138
|
</view>
|
|
73
139
|
);
|
|
74
140
|
}
|
|
@@ -99,34 +165,45 @@ function App() {
|
|
|
99
165
|
<view>
|
|
100
166
|
<Suspense>
|
|
101
167
|
<LynxConsole ref={consoleRef} />
|
|
102
|
-
|
|
168
|
+
</Suspense>
|
|
103
169
|
</view>
|
|
104
170
|
);
|
|
105
171
|
}
|
|
106
172
|
```
|
|
107
173
|
|
|
174
|
+
You can also integrate it with a back press handler so that the console closes when the back button is pressed.
|
|
175
|
+
|
|
108
176
|
## API
|
|
109
177
|
|
|
110
178
|
### `LynxConsole` Props
|
|
111
179
|
|
|
112
|
-
| Prop
|
|
113
|
-
|
|
114
|
-
| `theme`
|
|
115
|
-
| `safeAreaInsetBottom` | `string`
|
|
180
|
+
| Prop | Type | Default | Description |
|
|
181
|
+
| --------------------- | ------------------- | ----------- | ------------------------------------------------ |
|
|
182
|
+
| `theme` | `"light" \| "dark"` | `"light"` | Console UI theme |
|
|
183
|
+
| `safeAreaInsetBottom` | `string` | `"50px"` | Bottom safe area inset |
|
|
184
|
+
| `customTabs` | `CustomTab[]` | `undefined` | Additional custom tabs to display in the console |
|
|
185
|
+
|
|
186
|
+
### `CustomTab`
|
|
187
|
+
|
|
188
|
+
| Property | Type | Description |
|
|
189
|
+
| --------------- | ----------------- | ------------------------------------- |
|
|
190
|
+
| `key` | `string` | Unique identifier for the tab |
|
|
191
|
+
| `label` | `string` | Tab label text |
|
|
192
|
+
| `renderContent` | `() => ReactNode` | Function that renders the tab content |
|
|
116
193
|
|
|
117
194
|
### `LynxConsoleHandle`
|
|
118
195
|
|
|
119
|
-
| Method
|
|
120
|
-
|
|
121
|
-
| `open()`
|
|
122
|
-
| `close()`
|
|
196
|
+
| Method | Description |
|
|
197
|
+
| ---------- | ----------------------------------- |
|
|
198
|
+
| `open()` | Opens the console |
|
|
199
|
+
| `close()` | Closes the console |
|
|
123
200
|
| `isOpen()` | Returns whether the console is open |
|
|
124
201
|
|
|
125
202
|
### Monitor Initialization Functions
|
|
126
203
|
|
|
127
|
-
| Function
|
|
128
|
-
|
|
129
|
-
| `initLogMonitor()`
|
|
130
|
-
| `initMainThreadConsole()`
|
|
131
|
-
| `initNetworkMonitor()`
|
|
132
|
-
| `initPerformanceMonitor()` | Collects performance metrics
|
|
204
|
+
| Function | Description |
|
|
205
|
+
| -------------------------- | --------------------------------------------- |
|
|
206
|
+
| `initLogMonitor()` | Captures `console.log`, `console.error`, etc. |
|
|
207
|
+
| `initMainThreadConsole()` | Captures console output from the main thread |
|
|
208
|
+
| `initNetworkMonitor()` | Intercepts and records `fetch` requests |
|
|
209
|
+
| `initPerformanceMonitor()` | Collects performance metrics |
|
package/dist/index.cjs
CHANGED
package/dist/index.mjs
CHANGED
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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/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 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 { getColors, type ThemeColors } 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 t7\"\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 { 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 { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { LogEntry, LogLevel } from \"../types\";\nimport \"./ConsolePanel.css\";\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 () => {\n closeFilterDropdown = null;\n };\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) =>\n String(arg).toLowerCase().includes(query),\n );\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\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n null\n </text>\n );\n }\n\n if (arg === undefined) {\n return (\n <text\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\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 t3\"}\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 t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argString t3\"}\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 t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\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 t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argObjectPreview t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {preview}\n </text>\n </view>\n {isExpanded && (\n <view className={\"cp-argObjectContent\"}>\n <text\n className={\"cp-argObjectJson t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {jsonString}\n </text>\n </view>\n )}\n </view>\n );\n }\n\n return (\n <text\n className={\"cp-argPrimitive t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\n >\n {String(arg)}\n </text>\n );\n };\n\n return (\n <view\n className={\"cp-logContainer\"}\n bindtap={() => {\n if (filterOpen) setFilterOpen(false);\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\n >\n {enabledLevels.has(level) ? \"✅\" : \"⬜\"}\n </text>\n <text\n className={\"cp-filterLabel t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\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 t6\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={searchInputRef}\n className={\"cp-searchInput t3\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n </view>\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\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 t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\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 t2\"}\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 t2\"}\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 </list>\n <view className={\"cp-replInputRow\"}>\n <text\n className={\"cp-replPrompt t10\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={inputRef}\n className={\"cp-replInput t5\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.palette.green600,\n }}\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 t3\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {key}\n </text>\n <text\n className={\"np-tableValue t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {value}\n </text>\n </view>\n ))}\n </view>\n ) : (\n <text\n className={\"np-emptyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No headers\n </text>\n )}\n </view>\n\n {/* Body */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle t3\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Body\n </text>\n {error && (\n <text\n className={\"np-errorText t3\"}\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 t3\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\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 { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { NetworkEntry } from \"../types\";\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 {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"POST\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"PUT\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n case \"PATCH\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"DELETE\":\n return {\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={\"np-placeholder\"}>\n <text\n className={\"np-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No network requests yet\n </text>\n </view>\n ) : (\n <list scroll-orientation=\"vertical\" 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 t2\"}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getStatusCodeColor(\n colors,\n getStatusCodeVariant(\n network.status,\n network.statusCode,\n ),\n ),\n }}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text\n className={\"np-statusCode t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n Pending...\n </text>\n )}\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {formatDuration(network.duration)}\n </text>\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={\"np-path t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\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\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={\"np-tabText t4\"}\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\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={\"np-tabText t4\"}\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\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={\"np-tabText t4\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {item.key}\n </text>\n <text\n className={\"np-tableValue t3\"}\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 </list>\n )}\n </view>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { PerformanceEntryData } from \"../types\";\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 {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"metric\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"pipeline\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"resource\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n <view className={\"pp-placeholder\"}>\n <text\n className={\"pp-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n <list scroll-orientation=\"vertical\" 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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getEntryTypeColors(colors, perf.entryType),\n }}\n >\n {perf.entryType}\n </text>\n <text\n className={\"pp-entryName t2\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {perf.name}\n </text>\n <text\n className={\"pp-timestamp t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 전체 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n LynxFCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 렌더링 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n Raw Entry\n </text>\n <text\n className={\"pp-rawEntry t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {String(\n stringify(perf.rawEntry, null, 2, {\n references: true,\n }),\n )}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </list>\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 ? ` ${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 type { ReactNode } from \"@lynx-js/react\";\nimport { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport type { CustomTab } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { dismissFilterDropdown, LogPanel } 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: () => ReactNode;\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 = ({ bindtap, children }: FloatingButtonProps) => {\n const colors = useThemeColors();\n const { phase, right, bottom, clearTimer, handlers } =\n useLongPressDrag(bindtap);\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 <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","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 \"./styles/tokens.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\n className=\"fb-title t4\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\n LynxConsole\n </text>\n <text\n className=\"fb-subtitle t3\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\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":"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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/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 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 { getColors, type ThemeColors } 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 t7\"\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 { 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 { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { LogEntry, LogLevel } from \"../types\";\nimport \"./ConsolePanel.css\";\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 () => {\n closeFilterDropdown = null;\n };\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) =>\n String(arg).toLowerCase().includes(query),\n );\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 };\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\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n null\n </text>\n );\n }\n\n if (arg === undefined) {\n return (\n <text\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\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 t3\"}\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 t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argString t3\"}\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 t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\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 t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argObjectPreview t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {preview}\n </text>\n </view>\n {isExpanded && (\n <view className={\"cp-argObjectContent\"}>\n <text\n className={\"cp-argObjectJson t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {jsonString}\n </text>\n </view>\n )}\n </view>\n );\n }\n\n return (\n <text\n className={\"cp-argPrimitive t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\n >\n {String(arg)}\n </text>\n );\n };\n\n return (\n <view\n className={\"cp-logContainer\"}\n bindtap={() => {\n if (filterOpen) setFilterOpen(false);\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\n >\n {enabledLevels.has(level) ? \"✅\" : \"⬜\"}\n </text>\n <text\n className={\"cp-filterLabel t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\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 t6\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={searchInputRef}\n className={\"cp-searchInput t3\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n </view>\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\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 t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\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 t2\"}\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 t2\"}\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 </list>\n <view className={\"cp-replInputRow\"}>\n <text\n className={\"cp-replPrompt t10\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={inputRef}\n className={\"cp-replInput t5\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.palette.green600,\n }}\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 t3\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {key}\n </text>\n <text\n className={\"np-tableValue t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {value}\n </text>\n </view>\n ))}\n </view>\n ) : (\n <text\n className={\"np-emptyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No headers\n </text>\n )}\n </view>\n\n {/* Body */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle t3\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Body\n </text>\n {error && (\n <text\n className={\"np-errorText t3\"}\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 t3\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\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 { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { NetworkEntry } from \"../types\";\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 {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"POST\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"PUT\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n case \"PATCH\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"DELETE\":\n return {\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={\"np-placeholder\"}>\n <text\n className={\"np-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No network requests yet\n </text>\n </view>\n ) : (\n <list scroll-orientation=\"vertical\" 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 t2\"}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getStatusCodeColor(\n colors,\n getStatusCodeVariant(\n network.status,\n network.statusCode,\n ),\n ),\n }}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text\n className={\"np-statusCode t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n Pending...\n </text>\n )}\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {formatDuration(network.duration)}\n </text>\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={\"np-path t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\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\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={\"np-tabText t4\"}\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\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={\"np-tabText t4\"}\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\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={\"np-tabText t4\"}\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 t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {item.key}\n </text>\n <text\n className={\"np-tableValue t3\"}\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 </list>\n )}\n </view>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { PerformanceEntryData } from \"../types\";\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 {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"metric\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"pipeline\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"resource\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n <view className={\"pp-placeholder\"}>\n <text\n className={\"pp-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n <list scroll-orientation=\"vertical\" 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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getEntryTypeColors(colors, perf.entryType),\n }}\n >\n {perf.entryType}\n </text>\n <text\n className={\"pp-entryName t2\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {perf.name}\n </text>\n <text\n className={\"pp-timestamp t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 전체 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n LynxFCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 렌더링 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\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 t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n Raw Entry\n </text>\n <text\n className={\"pp-rawEntry t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {String(\n stringify(perf.rawEntry, null, 2, {\n references: true,\n }),\n )}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </list>\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 ? ` ${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 type { ReactNode } from \"@lynx-js/react\";\nimport { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport type { CustomTab } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { dismissFilterDropdown, LogPanel } 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: () => ReactNode;\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 = ({ bindtap, children }: FloatingButtonProps) => {\n const colors = useThemeColors();\n const { phase, right, bottom, clearTimer, handlers } =\n useLongPressDrag(bindtap);\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 <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","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 \"./styles/tokens.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\n className=\"fb-title t4\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\n LynxConsole\n </text>\n <text\n className=\"fb-subtitle t3\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\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":"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"}
|
package/dist/setup.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
let _lynx_js_react = require("@lynx-js/react");
|
|
3
|
+
let devalue = require("devalue");
|
|
3
4
|
let javascript_stringify = require("javascript-stringify");
|
|
4
5
|
|
|
5
6
|
//#region src/shared/ensureConsoleStructure.ts
|
|
@@ -95,10 +96,9 @@ const _setupMainThreadConsole = () => {
|
|
|
95
96
|
const serializeArgs = (args) => {
|
|
96
97
|
return args.map((arg) => {
|
|
97
98
|
try {
|
|
98
|
-
|
|
99
|
-
return arg;
|
|
99
|
+
return (0, devalue.stringify)(arg);
|
|
100
100
|
} catch {
|
|
101
|
-
return String(arg);
|
|
101
|
+
return (0, devalue.stringify)(String(arg));
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
};
|
|
@@ -108,6 +108,10 @@ const _setupMainThreadConsole = () => {
|
|
|
108
108
|
const sendLogToBackground = (0, _lynx_js_react.runOnBackground)((entry) => {
|
|
109
109
|
const state = globalThis.__LYNX_CONSOLE__?.state;
|
|
110
110
|
if (!state) return;
|
|
111
|
+
entry.args = entry.args.map((arg) => {
|
|
112
|
+
if (typeof arg !== "string") throw new Error(`[LynxConsole] Expected devalue string, got ${typeof arg}`);
|
|
113
|
+
return (0, devalue.parse)(arg);
|
|
114
|
+
});
|
|
111
115
|
state.logs?.push(entry);
|
|
112
116
|
state.logListeners?.forEach((listener) => {
|
|
113
117
|
listener(entry);
|
package/dist/setup.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { runOnBackground, runOnMainThread } from "@lynx-js/react";
|
|
2
|
-
import { stringify } from "
|
|
2
|
+
import { parse, stringify } from "devalue" with { runtime: "shared" };
|
|
3
|
+
import { stringify as stringify$1 } from "javascript-stringify";
|
|
3
4
|
|
|
4
5
|
//#region src/shared/ensureConsoleStructure.ts
|
|
5
6
|
const ensureConsoleStructure = () => {
|
|
@@ -94,10 +95,9 @@ const _setupMainThreadConsole = () => {
|
|
|
94
95
|
const serializeArgs = (args) => {
|
|
95
96
|
return args.map((arg) => {
|
|
96
97
|
try {
|
|
97
|
-
|
|
98
|
-
return arg;
|
|
98
|
+
return stringify(arg);
|
|
99
99
|
} catch {
|
|
100
|
-
return String(arg);
|
|
100
|
+
return stringify(String(arg));
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
103
|
};
|
|
@@ -107,6 +107,10 @@ const _setupMainThreadConsole = () => {
|
|
|
107
107
|
const sendLogToBackground = runOnBackground((entry) => {
|
|
108
108
|
const state = globalThis.__LYNX_CONSOLE__?.state;
|
|
109
109
|
if (!state) return;
|
|
110
|
+
entry.args = entry.args.map((arg) => {
|
|
111
|
+
if (typeof arg !== "string") throw new Error(`[LynxConsole] Expected devalue string, got ${typeof arg}`);
|
|
112
|
+
return parse(arg);
|
|
113
|
+
});
|
|
110
114
|
state.logs?.push(entry);
|
|
111
115
|
state.logListeners?.forEach((listener) => {
|
|
112
116
|
listener(entry);
|
|
@@ -285,7 +289,7 @@ const initNetworkMonitor = () => {
|
|
|
285
289
|
headerMap[key.toLowerCase()] = value;
|
|
286
290
|
});
|
|
287
291
|
const contentType = headerMap["content-type"];
|
|
288
|
-
if (contentType?.includes("application/json")) responseBody = stringify(await clonedResponse.json(), null, 2, { references: true }) ?? "";
|
|
292
|
+
if (contentType?.includes("application/json")) responseBody = stringify$1(await clonedResponse.json(), null, 2, { references: true }) ?? "";
|
|
289
293
|
else if (contentType?.includes("text")) responseBody = await clonedResponse.text();
|
|
290
294
|
} catch (error) {
|
|
291
295
|
responseBody = `[Unable to read response body] ${error}`;
|
package/dist/setup.mjs.map
CHANGED
|
@@ -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":["devalueStringify","devalueParse","stringify"],"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 { stringify as devalueStringify } from \"devalue\" with {\n runtime: \"shared\",\n};\nimport { parse as devalueParse } from \"devalue\";\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[]): string[] => {\n return args.map((arg) => {\n try {\n return devalueStringify(arg);\n } catch {\n return devalueStringify(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 // devalue 문자열을 원래 타입으로 복원\n entry.args = entry.args.map((arg) => {\n if (typeof arg !== \"string\") {\n throw new Error(\n `[LynxConsole] Expected devalue string, got ${typeof arg}`,\n );\n }\n return devalueParse(arg);\n });\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,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lynx-console",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
6
|
-
"**/*.css"
|
|
7
|
-
"dist/index.css"
|
|
6
|
+
"**/*.css"
|
|
8
7
|
],
|
|
9
8
|
"exports": {
|
|
10
9
|
".": {
|
|
@@ -16,8 +15,7 @@
|
|
|
16
15
|
"types": "./dist/setup.d.mts",
|
|
17
16
|
"import": "./dist/setup.mjs",
|
|
18
17
|
"require": "./dist/setup.cjs"
|
|
19
|
-
}
|
|
20
|
-
"./style.css": "./dist/index.css"
|
|
18
|
+
}
|
|
21
19
|
},
|
|
22
20
|
"main": "dist/index.mjs",
|
|
23
21
|
"types": "dist/index.d.mts",
|
|
@@ -38,11 +36,12 @@
|
|
|
38
36
|
"typescript": "^5.9.3"
|
|
39
37
|
},
|
|
40
38
|
"peerDependencies": {
|
|
41
|
-
"@lynx-js/react": "^0.
|
|
42
|
-
"@lynx-js/types": "^3.
|
|
39
|
+
"@lynx-js/react": "^0.110.0",
|
|
40
|
+
"@lynx-js/types": "^3.6.0",
|
|
43
41
|
"@types/react": "^18"
|
|
44
42
|
},
|
|
45
43
|
"dependencies": {
|
|
44
|
+
"devalue": "^5.6.4",
|
|
46
45
|
"javascript-stringify": "^2.1.0"
|
|
47
46
|
},
|
|
48
47
|
"repository": {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { runOnBackground } from "@lynx-js/react";
|
|
2
|
+
import { stringify as devalueStringify } from "devalue" with {
|
|
3
|
+
runtime: "shared",
|
|
4
|
+
};
|
|
5
|
+
import { parse as devalueParse } from "devalue";
|
|
2
6
|
import type { LogEntry, LogLevel } from "../types";
|
|
3
7
|
|
|
4
8
|
const _setupMainThreadConsole = (): void => {
|
|
@@ -16,13 +20,12 @@ const _setupMainThreadConsole = (): void => {
|
|
|
16
20
|
const LOG_METHODS: LogLevel[] = ["log", "warn", "error", "info"];
|
|
17
21
|
const LOG_ID_PREFIX = "main-thread";
|
|
18
22
|
|
|
19
|
-
const serializeArgs = (args: unknown[]):
|
|
23
|
+
const serializeArgs = (args: unknown[]): string[] => {
|
|
20
24
|
return args.map((arg) => {
|
|
21
25
|
try {
|
|
22
|
-
|
|
23
|
-
return arg;
|
|
26
|
+
return devalueStringify(arg);
|
|
24
27
|
} catch {
|
|
25
|
-
return String(arg);
|
|
28
|
+
return devalueStringify(String(arg));
|
|
26
29
|
}
|
|
27
30
|
});
|
|
28
31
|
};
|
|
@@ -36,6 +39,16 @@ const _setupMainThreadConsole = (): void => {
|
|
|
36
39
|
const state = globalThis.__LYNX_CONSOLE__?.state;
|
|
37
40
|
if (!state) return;
|
|
38
41
|
|
|
42
|
+
// devalue 문자열을 원래 타입으로 복원
|
|
43
|
+
entry.args = entry.args.map((arg) => {
|
|
44
|
+
if (typeof arg !== "string") {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`[LynxConsole] Expected devalue string, got ${typeof arg}`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return devalueParse(arg);
|
|
50
|
+
});
|
|
51
|
+
|
|
39
52
|
state.logs?.push(entry);
|
|
40
53
|
state.logListeners?.forEach((listener) => {
|
|
41
54
|
listener(entry);
|
package/src/styles/tokens.json
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"dimensions": {
|
|
3
|
-
"$dimension.x0_5": "2px",
|
|
4
|
-
"$dimension.x1": "4px",
|
|
5
|
-
"$dimension.x1_5": "6px",
|
|
6
|
-
"$dimension.x2": "8px",
|
|
7
|
-
"$dimension.x2_5": "10px",
|
|
8
|
-
"$dimension.x3": "12px",
|
|
9
|
-
"$dimension.x3_5": "14px",
|
|
10
|
-
"$dimension.x4": "16px",
|
|
11
|
-
"$dimension.x4_5": "18px",
|
|
12
|
-
"$dimension.x5": "20px",
|
|
13
|
-
"$dimension.x6": "24px",
|
|
14
|
-
"$dimension.x7": "28px",
|
|
15
|
-
"$dimension.x8": "32px",
|
|
16
|
-
"$dimension.x9": "36px",
|
|
17
|
-
"$dimension.x10": "40px",
|
|
18
|
-
"$dimension.x12": "48px",
|
|
19
|
-
"$dimension.x13": "52px",
|
|
20
|
-
"$dimension.x14": "56px",
|
|
21
|
-
"$dimension.x16": "64px",
|
|
22
|
-
"$dimension.spacing-x.between-chips": "8px",
|
|
23
|
-
"$dimension.spacing-x.global-gutter": "16px",
|
|
24
|
-
"$dimension.spacing-y.component-default": "12px",
|
|
25
|
-
"$dimension.spacing-y.nav-to-title": "20px",
|
|
26
|
-
"$dimension.spacing-y.screen-bottom": "56px",
|
|
27
|
-
"$dimension.spacing-y.between-text": "6px",
|
|
28
|
-
"$font-size.t1": "0.6875rem",
|
|
29
|
-
"$font-size.t2": "0.75rem",
|
|
30
|
-
"$font-size.t3": "0.8125rem",
|
|
31
|
-
"$font-size.t4": "0.875rem",
|
|
32
|
-
"$font-size.t5": "1rem",
|
|
33
|
-
"$font-size.t6": "1.125rem",
|
|
34
|
-
"$font-size.t7": "1.25rem",
|
|
35
|
-
"$font-size.t8": "1.375rem",
|
|
36
|
-
"$font-size.t9": "1.5rem",
|
|
37
|
-
"$font-size.t10": "1.625rem",
|
|
38
|
-
"$font-size.t1-static": "11px",
|
|
39
|
-
"$font-size.t2-static": "12px",
|
|
40
|
-
"$font-size.t3-static": "13px",
|
|
41
|
-
"$font-size.t4-static": "14px",
|
|
42
|
-
"$font-size.t5-static": "16px",
|
|
43
|
-
"$font-size.t6-static": "18px",
|
|
44
|
-
"$font-size.t7-static": "20px",
|
|
45
|
-
"$font-size.t8-static": "22px",
|
|
46
|
-
"$font-size.t9-static": "24px",
|
|
47
|
-
"$font-size.t10-static": "26px",
|
|
48
|
-
"$line-height.t1": "0.9375rem",
|
|
49
|
-
"$line-height.t2": "1rem",
|
|
50
|
-
"$line-height.t3": "1.125rem",
|
|
51
|
-
"$line-height.t4": "1.1875rem",
|
|
52
|
-
"$line-height.t5": "1.375rem",
|
|
53
|
-
"$line-height.t6": "1.5rem",
|
|
54
|
-
"$line-height.t7": "1.6875rem",
|
|
55
|
-
"$line-height.t8": "1.875rem",
|
|
56
|
-
"$line-height.t9": "2rem",
|
|
57
|
-
"$line-height.t10": "2.1875rem",
|
|
58
|
-
"$line-height.t1-static": "15px",
|
|
59
|
-
"$line-height.t2-static": "16px",
|
|
60
|
-
"$line-height.t3-static": "18px",
|
|
61
|
-
"$line-height.t4-static": "19px",
|
|
62
|
-
"$line-height.t5-static": "22px",
|
|
63
|
-
"$line-height.t6-static": "24px",
|
|
64
|
-
"$line-height.t7-static": "27px",
|
|
65
|
-
"$line-height.t8-static": "30px",
|
|
66
|
-
"$line-height.t9-static": "32px",
|
|
67
|
-
"$line-height.t10-static": "35px",
|
|
68
|
-
"$radius.r0_5": "2px",
|
|
69
|
-
"$radius.r1": "4px",
|
|
70
|
-
"$radius.r1_5": "6px",
|
|
71
|
-
"$radius.r2": "8px",
|
|
72
|
-
"$radius.r2_5": "10px",
|
|
73
|
-
"$radius.r3": "12px",
|
|
74
|
-
"$radius.r3_5": "14px",
|
|
75
|
-
"$radius.r4": "16px",
|
|
76
|
-
"$radius.r5": "20px",
|
|
77
|
-
"$radius.r6": "24px",
|
|
78
|
-
"$radius.full": "9999px"
|
|
79
|
-
}
|
|
80
|
-
}
|