lynx-console 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/assets/src/components/BottomSheet.css.ts.vanilla-D-1A77Ik.css +83 -0
  2. package/dist/assets/src/components/ConsolePanel.css.ts.vanilla-B3avfSlI.css +246 -0
  3. package/dist/assets/src/components/FloatingButton.css.ts.vanilla-rPj35oLW.css +55 -0
  4. package/dist/assets/src/components/NetworkPanel.css.ts.vanilla-DFMduT0T.css +247 -0
  5. package/dist/assets/src/components/PerformancePanel.css.ts.vanilla-D35LuXlW.css +216 -0
  6. package/dist/assets/src/components/Tabs.css.ts.vanilla-DD7L2oXt.css +50 -0
  7. package/dist/index.cjs +1058 -0
  8. package/dist/index.css +466 -0
  9. package/dist/index.css.map +1 -0
  10. package/dist/index.d.cts +17 -0
  11. package/dist/index.d.cts.map +1 -0
  12. package/dist/index.d.mts +17 -0
  13. package/dist/index.d.mts.map +1 -0
  14. package/dist/index.mjs +1059 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/setup.cjs +377 -0
  17. package/dist/setup.d.cts +15 -0
  18. package/dist/setup.d.cts.map +1 -0
  19. package/dist/setup.d.mts +15 -0
  20. package/dist/setup.d.mts.map +1 -0
  21. package/dist/setup.mjs +374 -0
  22. package/dist/setup.mjs.map +1 -0
  23. package/package.json +51 -0
  24. package/src/components/BottomSheet.css.ts +93 -0
  25. package/src/components/BottomSheet.tsx +142 -0
  26. package/src/components/ConsolePanel.css.ts +261 -0
  27. package/src/components/ConsolePanel.tsx +41 -0
  28. package/src/components/FloatingButton.css.ts +62 -0
  29. package/src/components/FloatingButton.tsx +37 -0
  30. package/src/components/LogPanel.tsx +241 -0
  31. package/src/components/NetworkDetailSection.tsx +42 -0
  32. package/src/components/NetworkPanel.css.ts +280 -0
  33. package/src/components/NetworkPanel.tsx +222 -0
  34. package/src/components/PerformancePanel.css.ts +224 -0
  35. package/src/components/PerformancePanel.tsx +209 -0
  36. package/src/components/Tabs.css.ts +66 -0
  37. package/src/components/Tabs.tsx +81 -0
  38. package/src/globals.d.ts +9 -0
  39. package/src/hooks/index.ts +3 -0
  40. package/src/hooks/useConsole.ts +35 -0
  41. package/src/hooks/useNetwork.ts +36 -0
  42. package/src/hooks/usePerformance.ts +39 -0
  43. package/src/index.tsx +110 -0
  44. package/src/setup/_setupMainThreadConsole.ts +80 -0
  45. package/src/setup/index.ts +4 -0
  46. package/src/setup/setupLogMonitor.ts +78 -0
  47. package/src/setup/setupMainThreadConsole.ts +34 -0
  48. package/src/setup/setupNetworkMonitor.ts +247 -0
  49. package/src/setup/setupPerformanceMonitor.ts +70 -0
  50. package/src/shared/ensureConsoleStructure.ts +20 -0
  51. package/src/styles/getDimensionValue.ts +7 -0
  52. package/src/styles/global.css.ts +10 -0
  53. package/src/styles/tokens.json +80 -0
  54. package/src/styles/typography.ts +25 -0
  55. package/src/styles/vars/color.ts +228 -0
  56. package/src/styles/vars/dimension.ts +79 -0
  57. package/src/styles/vars/index.css +463 -0
  58. package/src/styles/vars/index.ts +22 -0
  59. package/src/styles/vars/radius.ts +12 -0
  60. package/src/types.ts +96 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["css.backdrop","css.overlay","css.content","css.handleContainer","css.handle","css.header","css.title","css.body","footer","css.footer","css.argNull","css.argUndefined","css.argString","css.argObject","css.argObjectHeader","css.toggleIndicator","css.argPrimitive","css.argObjectPreview","css.argObjectContent","css.argObjectJson","css.logContainer","css.logHeader","css.logCount","css.clearButton","css.clearButtonText","css.logList","css.placeholder","css.placeholderText","css.logItem","css.logItemHeader","css.logLevel","css.logTime","css.logArgsContainer","css.logArgItem","css.replInputRow","css.replPrompt","css.replInput","css.replRunButton","css.replRunButtonText","css.detailSection","css.detailSectionTitle","css.table","css.tableRow","css.tableKey","css.tableValue","css.emptyText","css.errorText","css.bodyText","css.container","css.header","css.count","css.clearButton","css.clearButtonText","css.placeholder","css.placeholderText","css.list","css.item","css.itemHeader","css.method","css.statusCode","css.time","css.path","css.detailsContainer","css.tabs","css.tab","css.tabText","css.tabContent","css.table","css.tableRow","css.tableKey","css.tableValue","css.container","css.header","css.count","css.clearButton","css.clearButtonText","css.placeholder","css.placeholderText","css.list","css.item","css.itemHeader","css.entryType","css.entryName","css.timestamp","css.fcpHighlight","css.detailsContainer","css.fcpSection","css.fcpMetric","css.fcpMetricHeader","css.fcpMetricName","css.fcpMetricValue","css.fcpMetricDescription","css.rawEntrySection","css.detailTitle","css.rawEntry","css.tabs","css.tabHeader","css.tabTriggerButton","css.tabTriggerButtonText","css.tabTriggerIndicator","css.tabTriggerIndicatorLine","css.tabContents","css.tabContent","css.container","css.wrapper","css.container","css.button","css.reloadButton","css.reloadIcon","floatingButtonCss.title","floatingButtonCss.subtitle"],"sources":["../src/components/BottomSheet.css.ts","../src/components/BottomSheet.tsx","../src/hooks/useConsole.ts","../src/hooks/useNetwork.ts","../src/hooks/usePerformance.ts","../../node_modules/@vanilla-extract/recipes/dist/createRuntimeFn-62c9670f.esm.js","../src/components/ConsolePanel.css.ts","../src/components/LogPanel.tsx","../src/components/NetworkPanel.css.ts","../src/components/NetworkDetailSection.tsx","../src/components/NetworkPanel.tsx","../src/components/PerformancePanel.css.ts","../src/components/PerformancePanel.tsx","../src/components/Tabs.css.ts","../src/components/Tabs.tsx","../src/components/ConsolePanel.tsx","../src/components/FloatingButton.css.ts","../src/components/FloatingButton.tsx","../src/index.tsx"],"sourcesContent":["import { style } from \"@vanilla-extract/css\";\nimport { typography } from \"../styles/typography\";\nimport { vars } from \"../styles/vars\";\n\nexport const overlay = style({\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"flex-end\",\n zIndex: 3,\n});\n\nexport const backdrop = style({\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n zIndex: 2,\n background: vars.$color.bg.overlay,\n transition: `opacity ${vars.$duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n});\n\nexport const content = style({\n position: \"relative\",\n display: \"flex\",\n flex: 1,\n flexDirection: \"column\",\n boxSizing: \"border-box\",\n wordBreak: \"break-all\",\n background: vars.$color.bg.layerFloating,\n borderTopLeftRadius: vars.$radius.r6,\n borderTopRightRadius: vars.$radius.r6,\n transition: `transform ${vars.$duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n height: \"500px\",\n overflow: \"hidden\",\n});\n\nexport const handleContainer = style({\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n height: \"48px\",\n display: \"flex\",\n justifyContent: \"center\",\n zIndex: 10,\n});\n\nexport const handle = style({\n width: \"36px\",\n height: 4,\n backgroundColor: vars.$color.palette.gray400,\n borderRadius: \"9999px\",\n marginTop: \"12px\",\n});\n\nexport const header = style({\n display: \"flex\",\n flexDirection: \"column\",\n gap: vars.$dimension.x2,\n paddingTop: vars.$dimension.x6,\n paddingBottom: vars.$dimension.x4,\n justifyContent: \"flex-start\",\n paddingLeft: vars.$dimension.spacingX.globalGutter,\n paddingRight: \"50px\",\n});\n\nexport const title = style({\n ...typography(\"t7\", \"bold\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const body = style({\n display: \"flex\",\n flexDirection: \"column\",\n flex: 1,\n padding: `0 ${vars.$dimension.x4}`,\n overflow: \"hidden\",\n});\n\nexport const footer = style({\n display: \"flex\",\n flexDirection: \"column\",\n paddingLeft: vars.$dimension.spacingX.globalGutter,\n paddingRight: vars.$dimension.spacingX.globalGutter,\n paddingTop: vars.$dimension.x3,\n paddingBottom: vars.$dimension.x4,\n});\n","import { type ReactNode, useEffect, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\nimport * as css from \"./BottomSheet.css\";\n\ninterface BottomSheetProps {\n children: ReactNode;\n title?: string;\n footer?: ReactNode;\n onClose: () => void;\n isOpen: boolean;\n shouldClose?: boolean;\n safeAreaInsetBottom?: string;\n}\n\nconst MIN_HEIGHT = 200;\nconst MAX_HEIGHT = 700;\nconst DEFAULT_HEIGHT = 500;\nconst CLOSE_DRAG_THRESHOLD = 30; // 30px 이상 아래로 드래그하면 닫힘\n\n// 마지막 높이 저장\nlet savedHeight: number | null = null;\n\nexport default function BottomSheet({\n children,\n title,\n footer,\n onClose,\n isOpen,\n shouldClose = false,\n safeAreaInsetBottom = \"25px\",\n}: BottomSheetProps) {\n const [sheetHeight, setSheetHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [tempHeight, setTempHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [isDragging, setIsDragging] = useState(false);\n const [dragStartY, setDragStartY] = useState(0);\n const [dragStartHeight, setDragStartHeight] = useState(\n savedHeight ?? DEFAULT_HEIGHT,\n );\n const [isOpening, setIsOpening] = useState(true);\n const [isClosing, setIsClosing] = useState(false);\n\n // 닫기 애니메이션 처리\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => {\n onClose();\n }, 300);\n };\n\n // 아래에서 올라오는 애니메이션\n useEffect(() => {\n requestAnimationFrame(() => {\n setIsOpening(false);\n });\n }, []);\n\n // 외부에서 닫기 요청 시 애니메이션 처리\n useEffect(() => {\n if (shouldClose && !isClosing) {\n handleClose();\n }\n }, [shouldClose, isClosing]);\n\n // 높이 변경 시 저장\n useEffect(() => {\n savedHeight = sheetHeight;\n }, [sheetHeight]);\n\n if (!isOpen) return null;\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n setIsDragging(true);\n setDragStartY(e.detail.y);\n setDragStartHeight(sheetHeight);\n setTempHeight(sheetHeight);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n if (!isDragging) return;\n const deltaY = dragStartY - e.detail.y;\n const newHeight = Math.min(\n Math.max(dragStartHeight + deltaY, MIN_HEIGHT),\n MAX_HEIGHT,\n );\n setTempHeight(newHeight);\n };\n\n const handleTouchEnd = () => {\n setIsDragging(false);\n\n // 아래로 일정 30px 이상 드래그하면 닫기\n const dragDistance = dragStartHeight - tempHeight;\n setSheetHeight(tempHeight);\n if (dragDistance > CLOSE_DRAG_THRESHOLD) {\n handleClose();\n }\n };\n\n return (\n <scroll-view\n className={css.backdrop}\n style={{\n opacity: isOpening || isClosing ? 0 : 1,\n }}\n >\n <view className={css.overlay} bindtap={handleClose}>\n <view\n className={css.content}\n catchtap={() => {}}\n style={{\n height: `${isDragging ? tempHeight : sheetHeight}px`,\n transform:\n isOpening || isClosing ? \"translateY(100%)\" : \"translateY(0)\",\n transition: isDragging ? \"none\" : undefined,\n }}\n >\n {/* catchtap: 이벤트 버블링 차단 */}\n <view\n className={css.handleContainer}\n bindtouchstart={handleTouchStart}\n bindtouchmove={handleTouchMove}\n bindtouchend={handleTouchEnd}\n >\n <view className={css.handle} />\n </view>\n <view className={css.header}>\n {title && <text className={css.title}>{title}</text>}\n </view>\n <view\n className={css.body}\n style={{\n paddingBottom: safeAreaInsetBottom,\n }}\n >\n {children}\n </view>\n {footer && <view className={css.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","function toPrimitive(t, r) {\n if (\"object\" != typeof t || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || \"default\");\n if (\"object\" != typeof i) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\n\nfunction toPropertyKey(t) {\n var i = toPrimitive(t, \"string\");\n return \"symbol\" == typeof i ? i : String(i);\n}\n\nfunction _defineProperty(obj, key, value) {\n key = toPropertyKey(key);\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n}\n\nfunction ownKeys(e, r) {\n var t = Object.keys(e);\n if (Object.getOwnPropertySymbols) {\n var o = Object.getOwnPropertySymbols(e);\n r && (o = o.filter(function (r) {\n return Object.getOwnPropertyDescriptor(e, r).enumerable;\n })), t.push.apply(t, o);\n }\n return t;\n}\nfunction _objectSpread2(e) {\n for (var r = 1; r < arguments.length; r++) {\n var t = null != arguments[r] ? arguments[r] : {};\n r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {\n _defineProperty(e, r, t[r]);\n }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n });\n }\n return e;\n}\n\nfunction mapValues(input, fn) {\n var result = {};\n for (var _key in input) {\n result[_key] = fn(input[_key], _key);\n }\n return result;\n}\n\nvar shouldApplyCompound = (compoundCheck, selections, defaultVariants) => {\n for (var key of Object.keys(compoundCheck)) {\n var _selections$key;\n if (compoundCheck[key] !== ((_selections$key = selections[key]) !== null && _selections$key !== void 0 ? _selections$key : defaultVariants[key])) {\n return false;\n }\n }\n return true;\n};\nvar createRuntimeFn = config => {\n var runtimeFn = options => {\n var className = config.defaultClassName;\n var selections = _objectSpread2(_objectSpread2({}, config.defaultVariants), options);\n for (var variantName in selections) {\n var _selections$variantNa;\n var variantSelection = (_selections$variantNa = selections[variantName]) !== null && _selections$variantNa !== void 0 ? _selections$variantNa : config.defaultVariants[variantName];\n if (variantSelection != null) {\n var selection = variantSelection;\n if (typeof selection === 'boolean') {\n // @ts-expect-error\n selection = selection === true ? 'true' : 'false';\n }\n var selectionClassName =\n // @ts-expect-error\n config.variantClassNames[variantName][selection];\n if (selectionClassName) {\n className += ' ' + selectionClassName;\n }\n }\n }\n for (var [compoundCheck, compoundClassName] of config.compoundVariants) {\n if (shouldApplyCompound(compoundCheck, selections, config.defaultVariants)) {\n className += ' ' + compoundClassName;\n }\n }\n return className;\n };\n runtimeFn.variants = () => Object.keys(config.variantClassNames);\n runtimeFn.classNames = {\n get base() {\n return config.defaultClassName.split(' ')[0];\n },\n get variants() {\n return mapValues(config.variantClassNames, classNames => mapValues(classNames, className => className.split(' ')[0]));\n }\n };\n return runtimeFn;\n};\n\nexport { createRuntimeFn as c, mapValues as m };\n","import { style } from \"@vanilla-extract/css\";\nimport { recipe } from \"@vanilla-extract/recipes\";\nimport { typography } from \"../styles/typography\";\nimport { vars } from \"../styles/vars\";\n\nexport const container = style({\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n});\n\nexport const placeholder = style({\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n height: \"100%\",\n});\n\nexport const placeholderText = style({\n ...typography(\"t4\", \"regular\"),\n color: vars.$color.fg.disabled,\n});\n\nexport const logContainer = style({\n display: \"flex\",\n flexDirection: \"column\",\n flex: 1,\n paddingTop: 4,\n});\n\nexport const logHeader = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n marginBottom: 8,\n paddingBottom: 4,\n borderBottomWidth: 1,\n borderBottomColor: vars.$color.stroke.neutralSubtle,\n borderBottomStyle: \"solid\",\n});\n\nexport const logCount = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const clearButton = style({\n padding: \"6px 12px\",\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 4,\n});\n\nexport const clearButtonText = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const logList = style({\n flex: 1,\n});\n\nexport const logItem = recipe({\n base: {\n padding: \"8px\",\n borderBottomWidth: 1,\n borderBottomColor: vars.$color.stroke.neutralWeak,\n borderBottomStyle: \"solid\",\n },\n variants: {\n level: {\n log: {},\n info: {},\n warn: {\n backgroundColor: vars.$color.palette.yellow100,\n },\n error: {\n backgroundColor: vars.$color.palette.red100,\n },\n },\n },\n});\n\nexport const logItemHeader = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n marginBottom: 4,\n});\n\nexport const logLevel = recipe({\n base: {\n ...typography(\"t2\", \"bold\"),\n marginRight: 8,\n },\n variants: {\n level: {\n log: {\n color: vars.$color.palette.green600,\n },\n info: {\n color: vars.$color.palette.blue600,\n },\n warn: {\n color: vars.$color.palette.yellow600,\n },\n error: {\n color: vars.$color.palette.red600,\n },\n },\n },\n});\n\nexport const logTime = style({\n ...typography(\"t2\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const toggleIndicator = style({\n ...typography(\"t2\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n marginLeft: 4,\n alignSelf: \"flex-start\",\n});\n\nexport const logMessage = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutral,\n wordBreak: \"break-all\",\n});\n\nexport const logArgsContainer = style({\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"wrap\",\n gap: 8,\n});\n\nexport const logArgItem = style({\n ...typography(\"t3\", \"regular\"),\n});\n\nexport const argNull = style({\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const argUndefined = style({\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const argString = recipe({\n base: {\n ...typography(\"t3\", \"regular\"),\n },\n variants: {\n level: {\n log: { color: vars.$color.fg.neutral },\n info: { color: vars.$color.fg.neutral },\n warn: { color: vars.$color.palette.yellow900 },\n error: { color: vars.$color.palette.red900 },\n },\n },\n});\n\nexport const argPrimitive = recipe({\n base: {\n ...typography(\"t3\", \"regular\"),\n },\n variants: {\n level: {\n log: { color: vars.$color.palette.blue600 },\n info: { color: vars.$color.palette.blue600 },\n warn: { color: vars.$color.palette.yellow900 },\n error: { color: vars.$color.palette.red900 },\n },\n },\n});\n\nexport const argObject = style({\n display: \"flex\",\n flexDirection: \"column\",\n});\n\nexport const argObjectHeader = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 4,\n});\n\nexport const argObjectPreview = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const argObjectContent = style({\n marginTop: 4,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n});\n\nexport const argObjectProperty = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n});\n\nexport const argObjectKey = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.palette.purple600,\n});\n\nexport const argObjectJson = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const replInputRow = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 8,\n paddingTop: 8,\n paddingBottom: 8,\n marginTop: -1,\n borderTopWidth: 1,\n borderTopColor: vars.$color.stroke.neutralSubtle,\n borderTopStyle: \"solid\",\n backgroundImage: `linear-gradient(to bottom, transparent, ${vars.$color.bg.layerDefault})`,\n backgroundSize: \"100% 32px\",\n backgroundRepeat: \"no-repeat\",\n backgroundPosition: \"top\",\n backgroundColor: vars.$color.bg.layerDefault,\n});\n\nexport const replPrompt = style({\n ...typography(\"t10\", \"medium\"),\n color: vars.$color.fg.placeholder,\n paddingBottom: 8,\n});\n\nexport const replInput = style({\n flex: 1,\n ...typography(\"t5\", \"regular\"),\n color: vars.$color.fg.neutral,\n caretColor: vars.$color.palette.green600,\n paddingBottom: 8,\n});\n\nexport const replRunButton = style({\n padding: \"4px 10px\",\n backgroundColor: vars.$color.palette.green100,\n borderRadius: 4,\n marginBottom: 8,\n});\n\nexport const replRunButtonText = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.palette.green600,\n});\n","import { useEffect, useRef, useState } from \"@lynx-js/react\";\nimport type { BaseEvent, InputInputEvent, NodesRef } from \"@lynx-js/types\";\nimport { stringify } from \"javascript-stringify\";\nimport type { LogEntry } from \"../types\";\nimport * as css from \"./ConsolePanel.css\";\n\ninterface LogPanelProps {\n logs: LogEntry[];\n clearLogs: () => void;\n}\n\nconst runCode = (code: string) => {\n try {\n // biome-ignore lint: intentional REPL tool\n const result = eval(code);\n if (result instanceof Promise) {\n result.then((r) => console.log(r)).catch((e) => console.error(e));\n } else {\n console.log(result);\n }\n } catch (e) {\n console.error(e);\n }\n};\n\nexport const LogPanel = ({ logs, clearLogs }: LogPanelProps) => {\n const [expandedArgs, setExpandedArgs] = useState(new Set());\n const [code, setCode] = useState(\"\");\n const inputRef = useRef<NodesRef>(null);\n const listRef = useRef<NodesRef>(null);\n const logsRef = useRef(logs);\n logsRef.current = logs;\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 }, [logs]);\n\n const toggleArg = (key: string) => {\n setExpandedArgs((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n };\n\n const handleRun = () => {\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCode(\"\");\n inputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n runCode(trimmed);\n setTimeout(() => scrollToBottom(false), 100);\n };\n\n const renderArg = (\n arg: unknown,\n parentKey: string,\n level: \"log\" | \"info\" | \"warn\" | \"error\",\n ): React.ReactNode => {\n const key = parentKey;\n const isExpanded = expandedArgs.has(key);\n\n if (arg === null) {\n return <text className={css.argNull}>null</text>;\n }\n\n if (arg === undefined) {\n return <text className={css.argUndefined}>undefined</text>;\n }\n\n if (typeof arg === \"string\") {\n const MAX_LENGTH = 80;\n const shouldTruncate = arg.length > MAX_LENGTH;\n\n if (!shouldTruncate) {\n return <text className={css.argString({ level })}>{arg}</text>;\n }\n\n // 문자열이 길 경우 토글 버튼 추가\n return (\n <view className={css.argObject}>\n <view className={css.argObjectHeader} bindtap={() => toggleArg(key)}>\n <text className={css.toggleIndicator}>\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text className={css.argString({ level })}>\n {isExpanded ? arg : `${arg.slice(0, MAX_LENGTH)}...`}\n </text>\n </view>\n </view>\n );\n }\n\n if (typeof arg === \"number\" || typeof arg === \"boolean\") {\n return <text className={css.argPrimitive({ level })}>{String(arg)}</text>;\n }\n\n if (typeof arg === \"object\") {\n let preview = \"Object\";\n if (Array.isArray(arg)) {\n preview = `Array(${arg.length})`;\n } else if (arg instanceof Map) {\n preview = `Map(${arg.size})`;\n } else if (arg instanceof Set) {\n preview = `Set(${arg.size})`;\n } else if (arg instanceof Date) {\n preview = `Date`;\n } else if (arg instanceof RegExp) {\n preview = `RegExp`;\n } else if (arg instanceof Error) {\n preview = `${arg.constructor.name}`;\n } else if (arg?.constructor?.name && arg.constructor.name !== \"Object\") {\n preview = arg.constructor.name;\n }\n\n let jsonString: string;\n if (arg instanceof Map) {\n const entries = Array.from(arg.entries()).map(\n ([k, v]) => ` [${stringify(k)}, ${stringify(v)}]`,\n );\n jsonString = `{\\n${entries.join(\",\\n\")}\\n}`;\n } else if (arg instanceof Set) {\n const values = Array.from(arg.values()).map((v) => stringify(v));\n jsonString = `{\\n${values.join(\", \")}\\n}`;\n } else {\n jsonString =\n stringify(arg, null, 2, { references: true }) ?? String(arg);\n }\n\n return (\n <view className={css.argObject}>\n <view className={css.argObjectHeader} bindtap={() => toggleArg(key)}>\n <text className={css.toggleIndicator}>\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text className={css.argObjectPreview}>{preview}</text>\n </view>\n {isExpanded && (\n <view className={css.argObjectContent}>\n <text className={css.argObjectJson}>{jsonString}</text>\n </view>\n )}\n </view>\n );\n }\n\n return <text className={css.argPrimitive({ level })}>{String(arg)}</text>;\n };\n\n return (\n <view className={css.logContainer}>\n <view className={css.logHeader}>\n <text className={css.logCount}>Total {logs.length} logs</text>\n <view style={{ display: \"flex\", flexDirection: \"row\", gap: 8 }}>\n <view className={css.clearButton} bindtap={clearLogs}>\n <text className={css.clearButtonText}>Clear</text>\n </view>\n </view>\n </view>\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\n className={css.logList}\n initial-scroll-index={Math.max(0, logs.length - 1)}\n >\n {logs.length === 0 ? (\n <list-item item-key=\"empty-state\">\n <view className={css.placeholder}>\n <text className={css.placeholderText}>\n No logs yet. Try console.log(\"Hello!\")\n </text>\n </view>\n </list-item>\n ) : (\n logs.map((log) => {\n return (\n <list-item key={log.id} item-key={log.id}>\n <view className={css.logItem({ level: log.level })}>\n <view className={css.logItemHeader}>\n <text className={css.logLevel({ level: log.level })}>\n {log.level.toUpperCase()}\n </text>\n <text className={css.logTime}>\n {new Date(log.timestamp).toISOString()}\n </text>\n </view>\n <view className={css.logArgsContainer}>\n {log.args.map((arg, index) => (\n <view\n key={`${log.id}-${index.toString()}`}\n className={css.logArgItem}\n >\n {renderArg(\n arg,\n `${log.id}-${index.toString()}`,\n log.level,\n )}\n </view>\n ))}\n </view>\n </view>\n </list-item>\n );\n })\n )}\n </list>\n <view className={css.replInputRow}>\n <text className={css.replPrompt}>{\"›\"}</text>\n <input\n ref={inputRef}\n className={css.replInput}\n placeholder=\"enter code...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setCode(e.detail.value)\n }\n bindconfirm={handleRun}\n />\n <view className={css.replRunButton} bindtap={handleRun}>\n <text className={css.replRunButtonText}>Run</text>\n </view>\n </view>\n </view>\n );\n};\n","import { style } from \"@vanilla-extract/css\";\nimport { recipe } from \"@vanilla-extract/recipes\";\nimport { typography } from \"../styles/typography\";\nimport { vars } from \"../styles/vars\";\n\nexport const container = style({\n display: \"flex\",\n flexDirection: \"column\",\n flex: 1,\n paddingTop: 4,\n});\n\nexport const header = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n marginBottom: 8,\n paddingBottom: 4,\n borderBottomWidth: 1,\n borderBottomColor: vars.$color.stroke.neutralSubtle,\n borderBottomStyle: \"solid\",\n});\n\nexport const count = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const clearButton = style({\n padding: \"6px 12px\",\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 4,\n});\n\nexport const clearButtonText = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const list = style({\n flex: 1,\n});\n\nexport const placeholder = style({\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n height: \"100%\",\n});\n\nexport const placeholderText = style({\n ...typography(\"t4\", \"regular\"),\n color: vars.$color.fg.disabled,\n});\n\nexport const item = recipe({\n base: {\n padding: \"8px\",\n borderBottomWidth: 1,\n borderBottomColor: vars.$color.stroke.neutralWeak,\n borderBottomStyle: \"solid\",\n },\n variants: {\n status: {\n pending: {\n backgroundColor: vars.$color.palette.gray100,\n },\n success: {},\n error: {\n backgroundColor: vars.$color.palette.red100,\n },\n },\n },\n});\n\nexport const itemHeader = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n marginBottom: 4,\n gap: 8,\n});\n\nexport const method = recipe({\n base: {\n ...typography(\"t2\", \"bold\"),\n padding: \"0 4px\",\n borderRadius: 2,\n color: vars.$color.fg.neutral,\n backgroundColor: vars.$color.bg.neutralWeak,\n },\n variants: {\n type: {\n GET: {\n color: vars.$color.palette.blue600,\n backgroundColor: vars.$color.palette.blue100,\n },\n POST: {\n color: vars.$color.palette.green600,\n backgroundColor: vars.$color.palette.green100,\n },\n PUT: {\n color: vars.$color.palette.yellow600,\n backgroundColor: vars.$color.palette.yellow100,\n },\n PATCH: {\n color: vars.$color.palette.purple600,\n backgroundColor: vars.$color.palette.purple100,\n },\n DELETE: {\n color: vars.$color.palette.red600,\n backgroundColor: vars.$color.palette.red100,\n },\n },\n },\n});\n\nexport const statusCode = recipe({\n base: {\n ...typography(\"t2\", \"bold\"),\n },\n variants: {\n type: {\n success: {\n color: vars.$color.palette.green600,\n },\n error: {\n color: vars.$color.palette.red600,\n },\n pending: {\n color: vars.$color.fg.neutralSubtle,\n },\n },\n },\n});\n\nexport const time = style({\n ...typography(\"t2\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const url = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutral,\n wordBreak: \"break-all\",\n marginBottom: 4,\n});\n\nexport const path = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutral,\n wordBreak: \"break-all\",\n whiteSpace: \"pre-wrap\",\n overflow: \"visible\",\n marginBottom: 4,\n});\n\nexport const details = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const detailsContainer = style({\n marginTop: 12,\n paddingTop: 12,\n borderTopWidth: 1,\n borderTopColor: vars.$color.stroke.neutralSubtle,\n borderTopStyle: \"solid\",\n});\n\nexport const tabs = style({\n display: \"flex\",\n flexDirection: \"row\",\n gap: 4,\n paddingBottom: 6,\n});\n\nexport const tab = recipe({\n base: {\n padding: \"4px 8px\",\n borderRadius: 4,\n cursor: \"pointer\",\n },\n variants: {\n active: {\n true: {\n backgroundColor: vars.$color.bg.neutralWeak,\n },\n false: {\n backgroundColor: \"transparent\",\n },\n },\n },\n});\n\nexport const tabText = recipe({\n base: {\n ...typography(\"t4\", \"medium\"),\n },\n variants: {\n active: {\n true: {\n color: vars.$color.fg.neutral,\n },\n false: {\n color: vars.$color.fg.neutralSubtle,\n },\n },\n },\n});\n\nexport const tabContent = style({\n paddingTop: 8,\n});\n\nexport const detailSection = style({\n marginBottom: 12,\n});\n\nexport const detailSectionTitle = style({\n ...typography(\"t3\", \"bold\"),\n color: vars.$color.fg.neutral,\n marginBottom: 8,\n});\n\nexport const table = style({\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n});\n\nexport const tableRow = style({\n display: \"flex\",\n flexDirection: \"row\",\n gap: 8,\n padding: \"4px 8px\",\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 2,\n});\n\nexport const tableKey = style({\n ...typography(\"t3\", \"bold\"),\n color: vars.$color.fg.neutralSubtle,\n minWidth: 70,\n flexShrink: 0,\n});\n\nexport const tableValue = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutral,\n wordBreak: \"break-all\",\n flex: 1,\n});\n\nexport const bodyText = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutral,\n padding: 8,\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 4,\n wordBreak: \"break-all\",\n whiteSpace: \"pre-wrap\",\n});\n\nexport const errorText = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.palette.red600,\n padding: 8,\n backgroundColor: vars.$color.palette.red100,\n borderRadius: 4,\n wordBreak: \"break-all\",\n});\n\nexport const emptyText = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.disabled,\n textAlign: \"center\",\n padding: \"16px 0\",\n});\n","import * as css from \"./NetworkPanel.css\";\n\ninterface NetworkDetailSectionProps {\n headers?: Record<string, string> | undefined;\n body?: string | undefined;\n error?: string | undefined;\n}\n\nexport const NetworkDetailSection = ({\n headers = {},\n body = \"\",\n error = \"\",\n}: NetworkDetailSectionProps) => {\n return (\n <>\n {/* Headers */}\n <view className={css.detailSection}>\n <text className={css.detailSectionTitle}>Headers</text>\n {headers && Object.keys(headers).length > 0 ? (\n <view className={css.table}>\n {Object.entries(headers).map(([key, value]) => (\n <view key={key} className={css.tableRow}>\n <text className={css.tableKey}>{key}</text>\n <text className={css.tableValue}>{value}</text>\n </view>\n ))}\n </view>\n ) : (\n <text className={css.emptyText}>No headers</text>\n )}\n </view>\n\n {/* Body */}\n <view className={css.detailSection}>\n <text className={css.detailSectionTitle}>Body</text>\n {error && <text className={css.errorText}>{error}</text>}\n {body && <text className={css.bodyText}>{body}</text>}\n {!error && !body && <text className={css.emptyText}>No body</text>}\n </view>\n </>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport type { NetworkEntry } from \"../types\";\nimport { NetworkDetailSection } from \"./NetworkDetailSection\";\nimport * as css from \"./NetworkPanel.css\";\n\ninterface NetworkPanelProps {\n networks: NetworkEntry[];\n clearNetworks: () => void;\n}\n\ntype TabType = \"general\" | \"request\" | \"response\";\n\nexport const NetworkPanel = ({\n networks,\n clearNetworks,\n}: NetworkPanelProps) => {\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<TabType>(\"general\");\n\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={css.container}>\n <view className={css.header}>\n <text className={css.count}>Total: {networks.length} requests</text>\n <view className={css.clearButton} bindtap={clearNetworks}>\n <text className={css.clearButtonText}>Clear</text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={css.placeholder}>\n <text className={css.placeholderText}>No network requests yet</text>\n </view>\n ) : (\n <list className={css.list}>\n {networks.map((network) => (\n <list-item key={network.id} item-key={network.id}>\n <view className={css.item({ status: network.status })}>\n <view\n className={css.itemHeader}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n <text\n className={css.method({\n type: network.method as\n | \"GET\"\n | \"POST\"\n | \"PUT\"\n | \"PATCH\"\n | \"DELETE\",\n })}\n >\n {network.method}\n </text>\n {network.statusCode && (\n <text\n className={css.statusCode({\n type: getStatusCodeVariant(\n network.status,\n network.statusCode,\n ),\n })}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text className={css.statusCode({ type: \"pending\" })}>\n Pending...\n </text>\n )}\n <text className={css.time}>\n {formatDuration(network.duration)}\n </text>\n <text className={css.time}>\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={css.path}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n {extractPath(network.url)}\n </text>\n\n {selectedId === network.id && (\n <view className={css.detailsContainer}>\n {/* Tabs */}\n <view className={css.tabs}>\n <view\n className={css.tab({ active: activeTab === \"general\" })}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={css.tabText({\n active: activeTab === \"general\",\n })}\n >\n General\n </text>\n </view>\n <view\n className={css.tab({ active: activeTab === \"request\" })}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={css.tabText({\n active: activeTab === \"request\",\n })}\n >\n Request\n </text>\n </view>\n <view\n className={css.tab({\n active: activeTab === \"response\",\n })}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={css.tabText({\n active: activeTab === \"response\",\n })}\n >\n Response\n </text>\n </view>\n </view>\n\n {/* Tab Content */}\n <view className={css.tabContent}>\n {activeTab === \"general\" && (\n <view className={css.table}>\n {getGeneralInfo(network).map((item) => (\n <view key={item.key} className={css.tableRow}>\n <text className={css.tableKey}>{item.key}</text>\n <text className={css.tableValue}>\n {item.value}\n </text>\n </view>\n ))}\n </view>\n )}\n\n {activeTab === \"request\" && (\n <NetworkDetailSection\n headers={network.requestHeaders}\n body={network.requestBody}\n />\n )}\n\n {activeTab === \"response\" && (\n <NetworkDetailSection\n headers={network.responseHeaders}\n body={network.responseBody}\n error={network.error}\n />\n )}\n </view>\n </view>\n )}\n </view>\n </list-item>\n ))}\n </list>\n )}\n </view>\n );\n};\n","import { style } from \"@vanilla-extract/css\";\nimport { recipe } from \"@vanilla-extract/recipes\";\nimport { typography } from \"../styles/typography\";\nimport { vars } from \"../styles/vars\";\n\nexport const container = style({\n display: \"flex\",\n flexDirection: \"column\",\n flex: 1,\n paddingTop: 4,\n});\n\nexport const header = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n marginBottom: 8,\n paddingBottom: 4,\n borderBottomWidth: 1,\n borderBottomColor: vars.$color.stroke.neutralSubtle,\n borderBottomStyle: \"solid\",\n});\n\nexport const count = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const clearButton = style({\n padding: \"6px 12px\",\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 4,\n});\n\nexport const clearButtonText = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const list = style({\n flex: 1,\n});\n\nexport const placeholder = style({\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n height: \"100%\",\n});\n\nexport const placeholderText = style({\n ...typography(\"t4\", \"regular\"),\n color: vars.$color.fg.disabled,\n});\n\nexport const item = style({\n padding: \"8px\",\n borderBottomWidth: 1,\n borderBottomColor: vars.$color.stroke.neutralWeak,\n borderBottomStyle: \"solid\",\n});\n\nexport const itemHeader = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n marginBottom: 4,\n gap: 8,\n});\n\nexport const entryType = recipe({\n base: {\n ...typography(\"t2\", \"bold\"),\n padding: \"0 6px\",\n borderRadius: 2,\n color: vars.$color.fg.neutral,\n backgroundColor: vars.$color.bg.neutralWeak,\n },\n variants: {\n type: {\n init: {\n color: vars.$color.palette.blue600,\n backgroundColor: vars.$color.palette.blue100,\n },\n metric: {\n color: vars.$color.palette.green600,\n backgroundColor: vars.$color.palette.green100,\n },\n pipeline: {\n color: vars.$color.palette.purple600,\n backgroundColor: vars.$color.palette.purple100,\n },\n resource: {\n color: vars.$color.palette.yellow600,\n backgroundColor: vars.$color.palette.yellow100,\n },\n },\n },\n});\n\nexport const entryName = style({\n ...typography(\"t2\", \"medium\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const timestamp = style({\n ...typography(\"t2\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const fcpMetricHeader = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 8,\n});\n\nexport const fcpHighlight = style({\n ...typography(\"t3\", \"bold\"),\n color: vars.$color.palette.blue600,\n backgroundColor: vars.$color.palette.blue100,\n padding: \"4px 8px\",\n borderRadius: 4,\n marginTop: 4,\n});\n\nexport const metrics = style({\n marginTop: 8,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n});\n\nexport const metric = style({\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 8,\n padding: \"4px 8px\",\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 2,\n});\n\nexport const metricName = style({\n ...typography(\"t3\", \"medium\"),\n color: vars.$color.fg.neutralSubtle,\n minWidth: 100,\n flexShrink: 0,\n});\n\nexport const metricValue = style({\n ...typography(\"t3\", \"bold\"),\n color: vars.$color.palette.green600,\n flex: 1,\n});\n\nexport const detailsContainer = style({\n marginTop: 12,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n});\n\nexport const fcpSection = style({\n display: \"flex\",\n flexDirection: \"column\",\n gap: 8,\n});\n\nexport const fcpSectionDescription = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n marginBottom: 4,\n});\n\nexport const fcpMetric = style({\n backgroundColor: vars.$color.bg.layerDefault,\n borderRadius: 4,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n});\n\nexport const fcpMetricName = style({\n ...typography(\"t2\", \"bold\"),\n color: vars.$color.fg.neutral,\n});\n\nexport const fcpMetricValue = style({\n ...typography(\"t1\", \"bold\"),\n color: vars.$color.palette.blue600,\n});\n\nexport const fcpMetricDescription = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n});\n\nexport const fcpMetricFormula = style({\n ...typography(\"t4\", \"regular\"),\n color: vars.$color.fg.disabled,\n fontFamily: \"monospace\",\n});\n\nexport const rawEntrySection = style({\n padding: 12,\n backgroundColor: vars.$color.bg.neutralWeak,\n borderRadius: 4,\n});\n\nexport const detailTitle = style({\n ...typography(\"t3\", \"bold\"),\n color: vars.$color.fg.neutral,\n marginBottom: 8,\n});\n\nexport const rawEntry = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.fg.neutralSubtle,\n fontFamily: \"monospace\",\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-all\",\n});\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport type { PerformanceEntryData } from \"../types\";\nimport * as css from \"./PerformancePanel.css\";\n\ninterface PerformancePanelProps {\n performances: PerformanceEntryData[];\n clearPerformances: () => void;\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst isMetricFcpEntry = (entry: PerformanceEntryData): boolean => {\n return entry.entryType === \"metric\" && entry.name === \"fcp\";\n};\n\nconst extractFcpMetrics = (entry: PerformanceEntryData) => {\n if (!isMetricFcpEntry(entry) || !entry.rawEntry) {\n return null;\n }\n\n const metricEntry = entry.rawEntry as MetricFcpEntry;\n\n return {\n totalFcp: metricEntry.totalFcp ?? undefined,\n lynxFcp: metricEntry.lynxFcp ?? undefined,\n fcp: metricEntry.fcp ?? undefined,\n };\n};\n\nconst formatDuration = (ms?: number): string => {\n if (ms === undefined) return \"-\";\n return `${ms.toFixed(2)}ms`;\n};\n\nconst getPrimaryFcpLabel = (entry: PerformanceEntryData): string => {\n const fcpMetrics = extractFcpMetrics(entry);\n if (!fcpMetrics) return \"\";\n\n const { totalFcp, lynxFcp, fcp } = fcpMetrics;\n\n if (totalFcp?.duration !== undefined) {\n return `totalFcp: ${formatDuration(totalFcp.duration)}`;\n }\n if (lynxFcp?.duration !== undefined) {\n return `lynxFcp: ${formatDuration(lynxFcp.duration)}`;\n }\n if (fcp?.duration !== undefined) {\n return `fcp: ${formatDuration(fcp.duration)}`;\n }\n return \"\";\n};\n\nexport const PerformancePanel = ({\n performances,\n clearPerformances,\n}: PerformancePanelProps) => {\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n if (performances.length === 0) {\n return (\n <view className={css.container}>\n <view className={css.header}>\n <text className={css.count}>0 entries</text>\n <view\n bindtap={() => {\n console.log(\"[PerformancePanel] performances\", performances);\n }}\n style={{ padding: \"10px\", backgroundColor: \"red\" }}\n >\n <text>Log</text>\n </view>\n <view bindtap={clearPerformances} className={css.clearButton}>\n <text className={css.clearButtonText}>Clear</text>\n </view>\n </view>\n <view className={css.placeholder}>\n <text className={css.placeholderText}>\n No performance data yet...\n </text>\n </view>\n </view>\n );\n }\n\n return (\n <view className={css.container}>\n <view className={css.header}>\n <text className={css.count}>{performances.length} entries</text>\n <view bindtap={clearPerformances} className={css.clearButton}>\n <text className={css.clearButtonText}>Clear</text>\n </view>\n </view>\n\n <list className={css.list}>\n {performances.map((perf) => {\n const isMetricFcp = isMetricFcpEntry(perf);\n const fcpMetrics = extractFcpMetrics(perf);\n const primaryFcp = getPrimaryFcpLabel(perf);\n const { totalFcp, lynxFcp, fcp } = fcpMetrics ?? {};\n\n return (\n <list-item key={perf.id} item-key={perf.id}>\n <view className={css.item}>\n <view\n className={css.itemHeader}\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n <text className={css.entryType({ type: perf.entryType })}>\n {perf.entryType}\n </text>\n <text className={css.entryName}>{perf.name}</text>\n <text className={css.timestamp}>\n {new Date(perf.timestamp).toISOString()}\n </text>\n </view>\n\n <view\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n {isMetricFcp && primaryFcp && (\n <text className={css.fcpHighlight}>{primaryFcp}</text>\n )}\n </view>\n\n {selectedId === perf.id && (\n <view className={css.detailsContainer}>\n {isMetricFcp && fcpMetrics && (\n <view className={css.fcpSection}>\n {totalFcp !== undefined && (\n <view className={css.fcpMetric}>\n <view className={css.fcpMetricHeader}>\n <text className={css.fcpMetricName}>\n 전체 FCP\n </text>\n <text className={css.fcpMetricValue}>\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text className={css.fcpMetricDescription}>\n PrepareTemplate Start부터 Paint End 까지 걸리는\n 시간\n </text>\n </view>\n )}\n\n {lynxFcp !== undefined && (\n <view className={css.fcpMetric}>\n <view className={css.fcpMetricHeader}>\n <text className={css.fcpMetricName}>LynxFCP</text>\n <text className={css.fcpMetricValue}>\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text className={css.fcpMetricDescription}>\n Bundle Load 시작부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n\n {fcp !== undefined && (\n <view className={css.fcpMetric}>\n <view className={css.fcpMetricHeader}>\n <text className={css.fcpMetricName}>\n 렌더링 FCP\n </text>\n <text className={css.fcpMetricValue}>\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text className={css.fcpMetricDescription}>\n TemplateBundle 준비부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n </view>\n )}\n\n {!!perf.rawEntry && (\n <view className={css.rawEntrySection}>\n <text className={css.detailTitle}>Raw Entry</text>\n <text className={css.rawEntry}>\n {String(stringify(perf.rawEntry, null, 2, { references: true }))}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </list>\n </view>\n );\n};\n","import { style } from \"@vanilla-extract/css\";\nimport { recipe } from \"@vanilla-extract/recipes\";\nimport { typography } from \"../styles/typography\";\nimport { vars } from \"../styles/vars\";\n\nexport const tabs = style({\n flex: 1,\n display: \"flex\",\n flexDirection: \"column\",\n});\n\nexport const tabHeader = style({\n display: \"flex\",\n boxShadow: `inset 0 -1px 0 0 ${vars.$color.stroke.neutralSubtle}`,\n});\n\nexport const tabTriggerButton = style({\n flex: 1,\n color: vars.$color.fg.neutralSubtle,\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n padding: \"12px 0 10px 0\",\n position: \"relative\",\n});\n\nexport const tabTriggerButtonText = recipe({\n base: {\n ...typography(\"t5\", \"bold\"),\n color: vars.$color.fg.neutralSubtle,\n },\n variants: {\n active: {\n true: {\n color: vars.$color.fg.neutral,\n },\n },\n },\n});\n\nexport const tabTriggerIndicator = style({\n position: \"absolute\",\n bottom: 0,\n left: 0,\n padding: \"0 16px\",\n width: \"100%\",\n transition: \"200ms\",\n transitionTimingFunction: \"cubic-bezier(.35, 0, .35, 1)\",\n});\n\nexport const tabTriggerIndicatorLine = style({\n backgroundColor: vars.$color.fg.neutral,\n width: \"100%\",\n height: \"2px\",\n});\n\nexport const tabContents = style({\n flex: 1,\n width: \"100%\",\n});\n\nexport const tabContent = style({\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n});\n","import { type ReactNode, useRef, useState } from \"@lynx-js/react\";\nimport type { ListSnapEvent, NodesRef } from \"@lynx-js/types\";\nimport * as css from \"./Tabs.css\";\n\ntype TabsProps = {\n items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }>;\n};\n\nexport default function Tabs(props: TabsProps) {\n const tabContentsRef = useRef<NodesRef>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n\n return (\n <view className={css.tabs}>\n <view className={css.tabHeader}>\n {props.items.map((item, i) => (\n <view\n key={item.key}\n className={css.tabTriggerButton}\n bindtap={() => {\n setActiveIndex(i);\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={css.tabTriggerButtonText({\n active: i === activeIndex,\n })}\n >\n {item.label}\n </text>\n {i === 0 && (\n <view\n className={css.tabTriggerIndicator}\n style={{ transform: `translateX(${activeIndex * 100}%)` }}\n >\n <view className={css.tabTriggerIndicatorLine} />\n </view>\n )}\n </view>\n ))}\n </view>\n\n <list\n ref={tabContentsRef}\n className={css.tabContents}\n scroll-orientation=\"horizontal\"\n item-snap={{ factor: 0, offset: 0 }}\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={css.tabContent}\n >\n {item.renderContent()}\n </list-item>\n ))}\n </list>\n </view>\n );\n}\n","import { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport * as css from \"./ConsolePanel.css\";\nimport { LogPanel } from \"./LogPanel\";\nimport { NetworkPanel } from \"./NetworkPanel\";\nimport { PerformancePanel } from \"./PerformancePanel\";\nimport Tabs from \"./Tabs\";\n\nexport const ConsolePanel = () => {\n const { logs, clearLogs } = useConsole();\n const { networks, clearNetworks } = useNetwork();\n const { performances, clearPerformances } = usePerformance();\n\n return (\n <view className={css.container}>\n <Tabs\n items={[\n {\n key: \"log\",\n label: \"Log\",\n renderContent: () => <LogPanel logs={logs} clearLogs={clearLogs} />,\n },\n {\n key: \"network\",\n label: \"Network\",\n renderContent: () => <NetworkPanel networks={networks} clearNetworks={clearNetworks} />,\n },\n {\n key: \"performance\",\n label: \"Performance\",\n renderContent: () => (\n <PerformancePanel\n performances={performances}\n clearPerformances={clearPerformances}\n />\n ),\n },\n ]}\n />\n </view>\n );\n};\n","import { style } from \"@vanilla-extract/css\";\nimport { typography } from \"../styles/typography\";\nimport { vars } from \"../styles/vars\";\n\nexport const wrapper = style({\n position: \"fixed\",\n right: \"16px\",\n bottom: \"84px\",\n zIndex: 9999,\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: \"8px\",\n});\n\nexport const container = style({});\n\nexport const button = style({\n paddingLeft: \"8px\",\n paddingRight: \"8px\",\n paddingTop: \"4px\",\n paddingBottom: \"4px\",\n borderRadius: \"12px\",\n backgroundColor: vars.$color.palette.green600,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: \"2px\",\n boxShadow: \"0 4px 12px rgba(0, 0, 0, 0.15)\",\n});\n\nexport const title = style({\n ...typography(\"t4\", \"regular\"),\n color: vars.$color.palette.staticWhite,\n textAlign: \"center\",\n});\n\nexport const subtitle = style({\n ...typography(\"t3\", \"regular\"),\n color: vars.$color.palette.staticWhite,\n textAlign: \"center\",\n});\n\nexport const reloadButton = style({\n width: \"32px\",\n height: \"32px\",\n borderRadius: \"16px\",\n backgroundColor: vars.$color.palette.green600,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 12px rgba(0, 0, 0, 0.15)\",\n});\n\nexport const reloadIcon = style({\n fontSize: \"20px\",\n lineHeight: \"32px\",\n marginBottom: \"5px\",\n color: vars.$color.palette.staticWhite,\n textAlign: \"center\",\n});\n","import type { ReactNode } from \"@lynx-js/react\";\nimport * as css from \"./FloatingButton.css\";\n\ninterface FloatingButtonProps {\n bindtap: () => void;\n isVisible: boolean;\n children: ReactNode;\n}\n\nexport const FloatingButton = ({\n bindtap,\n isVisible,\n children,\n}: FloatingButtonProps) => {\n if (!isVisible) return null;\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 return (\n <view className={css.wrapper}>\n <view className={css.container} bindtap={bindtap}>\n <view className={css.button}>{children}</view>\n </view>\n <view className={css.reloadButton} bindtap={handleReload}>\n <text className={css.reloadIcon}>{\"\\u21BB\"}</text>\n </view>\n </view>\n );\n};\n","import \"./styles/vars/index.css\";\nimport {\n type ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useState,\n} from \"@lynx-js/react\";\nimport BottomSheet from \"./components/BottomSheet.jsx\";\nimport { ConsolePanel } from \"./components/ConsolePanel.jsx\";\nimport * as floatingButtonCss from \"./components/FloatingButton.css\";\nimport { FloatingButton } from \"./components/FloatingButton.jsx\";\nimport { usePerformance } from \"./hooks/usePerformance\";\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}\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\" },\n ref: ForwardedRef<LynxConsoleHandle>,\n ) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shouldClose, setShouldClose] = useState(false);\n const { performances } = usePerformance();\n\n const latestFcp = useMemo(() => {\n for (let i = performances.length - 1; i >= 0; i--) {\n const perf = performances[i];\n if (perf && perf.entryType === \"metric\" && perf.name === \"fcp\") {\n const metricEntry = perf.rawEntry as MetricFcpEntry | undefined;\n // totalFcp를 먼저 시도하고, 없으면 lynxFcp 반환\n if (metricEntry?.totalFcp?.duration !== undefined) {\n return metricEntry.totalFcp;\n }\n if (metricEntry?.lynxFcp?.duration !== undefined) {\n return metricEntry.lynxFcp;\n }\n }\n }\n return undefined;\n }, [performances]);\n\n useImperativeHandle(ref, () => ({\n open: () => {\n setIsOpen(true);\n setShouldClose(false);\n },\n close: () => {\n setShouldClose(true);\n },\n isOpen: () => isOpen,\n }));\n\n const handleOpenBottomSheet = () => {\n setIsOpen(true);\n setShouldClose(false);\n };\n\n const handleCloseBottomSheet = () => {\n setIsOpen(false);\n setShouldClose(false);\n };\n\n const themeClass = `data-seed-color-mode__${theme}-only`;\n\n return (\n <view className={themeClass}>\n <FloatingButton bindtap={handleOpenBottomSheet} isVisible={!isOpen}>\n <text className={floatingButtonCss.title}>LynxConsole</text>\n <text className={floatingButtonCss.subtitle}>\n {`${latestFcp?.name ?? \"FCP\"}: ${latestFcp?.duration ? latestFcp.duration.toFixed(2) : \"--\"}ms`}\n </text>\n </FloatingButton>\n {isOpen && (\n <BottomSheet\n isOpen={isOpen}\n shouldClose={shouldClose}\n onClose={handleCloseBottomSheet}\n title=\"Lynx Console\"\n safeAreaInsetBottom={safeAreaInsetBottom}\n >\n <ConsolePanel />\n </BottomSheet>\n )}\n </view>\n );\n },\n);\n\nexport default LynxConsole;\n"],"x_google_ignoreList":[5],"mappings":"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"}
package/dist/setup.cjs ADDED
@@ -0,0 +1,377 @@
1
+ import "./index.css";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
+ let _lynx_js_react = require("@lynx-js/react");
4
+ let javascript_stringify = require("javascript-stringify");
5
+
6
+ //#region src/shared/ensureConsoleStructure.ts
7
+ const ensureConsoleStructure = () => {
8
+ if (!globalThis.__LYNX_CONSOLE__) globalThis.__LYNX_CONSOLE__ = {};
9
+ if (!globalThis.__LYNX_CONSOLE__.state) globalThis.__LYNX_CONSOLE__.state = {};
10
+ return {
11
+ lynxConsole: globalThis.__LYNX_CONSOLE__,
12
+ state: globalThis.__LYNX_CONSOLE__.state
13
+ };
14
+ };
15
+
16
+ //#endregion
17
+ //#region src/setup/setupLogMonitor.ts
18
+ const LOG_METHODS = [
19
+ "log",
20
+ "warn",
21
+ "error",
22
+ "info"
23
+ ];
24
+ const LOG_ID_PREFIX = "background-thread";
25
+ const generateLogId = () => {
26
+ return `${LOG_ID_PREFIX}-${Date.now()}-${Math.random()}`;
27
+ };
28
+ const createLogEntry = (method, args) => {
29
+ return {
30
+ id: generateLogId(),
31
+ level: method,
32
+ message: "",
33
+ timestamp: Date.now(),
34
+ args
35
+ };
36
+ };
37
+ const addLogEntry = (entry) => {
38
+ const state = globalThis.__LYNX_CONSOLE__?.state;
39
+ if (!state?.logs || !state?.logListeners) {
40
+ console.error("[LynxConsole] Cannot add log entry: Log monitor not initialized. Call initLogMonitor() first.");
41
+ return;
42
+ }
43
+ state.logs.push(entry);
44
+ state.logListeners.forEach((listener) => {
45
+ listener(entry);
46
+ });
47
+ };
48
+ const initLogMonitor = () => {
49
+ "background only";
50
+ const { lynxConsole, state } = ensureConsoleStructure();
51
+ if (lynxConsole.originalConsole) {
52
+ console.warn("[LynxConsole] Log monitor already initialized");
53
+ return;
54
+ }
55
+ const originalConsole = globalThis.console;
56
+ lynxConsole.originalConsole = {
57
+ log: originalConsole.log.bind(originalConsole),
58
+ warn: originalConsole.warn.bind(originalConsole),
59
+ error: originalConsole.error.bind(originalConsole),
60
+ info: originalConsole.info.bind(originalConsole)
61
+ };
62
+ state.logs = [];
63
+ state.logListeners = /* @__PURE__ */ new Set();
64
+ state.logSubscribe = (listener) => {
65
+ state.logListeners?.add(listener);
66
+ return () => {
67
+ state.logListeners?.delete(listener);
68
+ };
69
+ };
70
+ LOG_METHODS.forEach((method) => {
71
+ globalThis.console[method] = ((...args) => {
72
+ lynxConsole.originalConsole?.[method](...args);
73
+ addLogEntry(createLogEntry(method, args));
74
+ }).bind(globalThis.console);
75
+ });
76
+ lynxConsole.originalConsole?.log("[LynxConsole] ✅ Log monitoring initialized");
77
+ };
78
+
79
+ //#endregion
80
+ //#region src/setup/_setupMainThreadConsole.ts
81
+ const _setupMainThreadConsole = () => {
82
+ "main thread";
83
+ if (!globalThis.__LYNX_CONSOLE__) globalThis.__LYNX_CONSOLE__ = {};
84
+ const lynxConsole = globalThis.__LYNX_CONSOLE__;
85
+ if (lynxConsole.mainThreadInitialized) {
86
+ console.warn("[LynxConsole] Main thread console already initialized");
87
+ return;
88
+ }
89
+ const LOG_METHODS = [
90
+ "log",
91
+ "warn",
92
+ "error",
93
+ "info"
94
+ ];
95
+ const LOG_ID_PREFIX = "main-thread";
96
+ const serializeArgs = (args) => {
97
+ return args.map((arg) => {
98
+ try {
99
+ JSON.stringify(arg);
100
+ return arg;
101
+ } catch {
102
+ return String(arg);
103
+ }
104
+ });
105
+ };
106
+ const generateLogId = () => {
107
+ return `${LOG_ID_PREFIX}-${Date.now()}-${Math.random()}`;
108
+ };
109
+ const sendLogToBackground = (0, _lynx_js_react.runOnBackground)((entry) => {
110
+ const state = globalThis.__LYNX_CONSOLE__?.state;
111
+ if (!state) return;
112
+ state.logs?.push(entry);
113
+ state.logListeners?.forEach((listener) => {
114
+ listener(entry);
115
+ });
116
+ });
117
+ const originalConsole = globalThis.console;
118
+ const originalMethods = {
119
+ log: originalConsole.log.bind(originalConsole),
120
+ warn: originalConsole.warn.bind(originalConsole),
121
+ error: originalConsole.error.bind(originalConsole),
122
+ info: originalConsole.info.bind(originalConsole)
123
+ };
124
+ LOG_METHODS.forEach((method) => {
125
+ const original = originalMethods[method];
126
+ originalConsole[method] = ((...args) => {
127
+ original(...args);
128
+ const serializedArgs = serializeArgs(args);
129
+ const timestamp = Date.now();
130
+ sendLogToBackground({
131
+ id: generateLogId(),
132
+ level: method,
133
+ message: "",
134
+ timestamp,
135
+ args: serializedArgs
136
+ });
137
+ }).bind(originalConsole);
138
+ });
139
+ lynxConsole.mainThreadInitialized = true;
140
+ originalConsole.log("[LynxConsole] ✅ Main thread console initialized");
141
+ };
142
+
143
+ //#endregion
144
+ //#region src/setup/setupMainThreadConsole.ts
145
+ const initMainThreadConsole = async () => {
146
+ "background only";
147
+ const { lynxConsole, state } = ensureConsoleStructure();
148
+ if (lynxConsole.mainThreadInitialized) {
149
+ console.error("[LynxConsole] Main thread console already initialized");
150
+ return;
151
+ }
152
+ if (!state.logs) {
153
+ console.error("[LynxConsole] Background thread console not initialized");
154
+ return;
155
+ }
156
+ try {
157
+ await (0, _lynx_js_react.runOnMainThread)(_setupMainThreadConsole)();
158
+ } catch (error) {
159
+ console.error("[LynxConsole] Failed to initialize main thread console:", error);
160
+ }
161
+ };
162
+
163
+ //#endregion
164
+ //#region src/setup/setupNetworkMonitor.ts
165
+ const generateNetworkId = () => {
166
+ return `network-${Date.now()}-${Math.random()}`;
167
+ };
168
+ const extractUrl = (input) => {
169
+ if (typeof input === "string") return input;
170
+ if (input instanceof URL) return input.href;
171
+ return input.url;
172
+ };
173
+ const extractMethod = (input, init) => {
174
+ if (init?.method) return init.method;
175
+ if (typeof input === "object" && "method" in input) return input.method;
176
+ return "GET";
177
+ };
178
+ const extractHeaders = (headers) => {
179
+ const result = {};
180
+ if (!headers) return result;
181
+ try {
182
+ if (headers instanceof Headers) headers.forEach((value, key) => {
183
+ result[key] = value;
184
+ });
185
+ else if (Array.isArray(headers)) headers.forEach(([key, value]) => {
186
+ result[key] = value;
187
+ });
188
+ else Object.entries(headers).forEach(([key, value]) => {
189
+ result[key] = value;
190
+ });
191
+ } catch (error) {
192
+ console.error("[LynxConsole] Failed to extract headers:", error);
193
+ }
194
+ return result;
195
+ };
196
+ const mergeRequestHeaders = (input, init) => {
197
+ const merged = {};
198
+ if (typeof input === "object" && "headers" in input) Object.assign(merged, extractHeaders(input.headers));
199
+ if (init?.headers) Object.assign(merged, extractHeaders(init.headers));
200
+ return merged;
201
+ };
202
+ const addNetworkEntry = (entry) => {
203
+ const state = globalThis.__LYNX_CONSOLE__?.state;
204
+ if (!state?.networks || !state?.networksMap || !state?.networkListeners) {
205
+ console.error("[LynxConsole] Cannot add network entry: Network monitor not initialized. Call initNetworkMonitor() first.");
206
+ return;
207
+ }
208
+ state.networks.push(entry);
209
+ state.networksMap.set(entry.id, entry);
210
+ state.networkListeners.forEach((listener) => {
211
+ listener(entry);
212
+ });
213
+ };
214
+ const updateNetworkEntry = (id, updates) => {
215
+ const state = globalThis.__LYNX_CONSOLE__?.state;
216
+ if (!state?.networks || !state?.networksMap || !state?.networkListeners) {
217
+ console.error("[LynxConsole] Cannot update network entry: Network monitor not initialized. Call initNetworkMonitor() first.");
218
+ return;
219
+ }
220
+ const existingEntry = state.networksMap.get(id);
221
+ if (!existingEntry) {
222
+ console.error(`[LynxConsole] Cannot update network entry: Entry with id '${id}' not found.`);
223
+ return;
224
+ }
225
+ const updatedEntry = {
226
+ ...existingEntry,
227
+ ...updates
228
+ };
229
+ const index = state.networks.findIndex((entry) => entry.id === id);
230
+ if (index !== -1) state.networks[index] = updatedEntry;
231
+ state.networksMap.set(id, updatedEntry);
232
+ state.networkListeners.forEach((listener) => {
233
+ listener(updatedEntry);
234
+ });
235
+ };
236
+ const initNetworkMonitor = () => {
237
+ if (!lynx.fetch) {
238
+ console.warn("[LynxConsole] lynx.fetch not available, skipping network monitor");
239
+ return;
240
+ }
241
+ const { state } = ensureConsoleStructure();
242
+ if (state.networks !== void 0) {
243
+ console.warn("[LynxConsole] Network monitor already initialized");
244
+ return;
245
+ }
246
+ state.networks = [];
247
+ state.networksMap = /* @__PURE__ */ new Map();
248
+ state.networkListeners = /* @__PURE__ */ new Set();
249
+ state.subscribeNetwork = (listener) => {
250
+ state.networkListeners?.add(listener);
251
+ return () => {
252
+ state.networkListeners?.delete(listener);
253
+ };
254
+ };
255
+ const originalFetch = fetch.bind(lynx);
256
+ const monitoredFetch = async (input, init) => {
257
+ const id = generateNetworkId();
258
+ const startTime = Date.now();
259
+ const url = extractUrl(input);
260
+ const method = extractMethod(input, init);
261
+ const requestHeaders = mergeRequestHeaders(input, init);
262
+ let requestBody;
263
+ if (init?.body) if (typeof init.body === "string") requestBody = init.body;
264
+ else if (init.body instanceof URLSearchParams) requestBody = init.body.toString();
265
+ else requestBody = String(init.body);
266
+ addNetworkEntry({
267
+ id,
268
+ url,
269
+ method: method || "default",
270
+ status: "pending",
271
+ startTime,
272
+ requestHeaders,
273
+ requestBody: requestBody ?? ""
274
+ });
275
+ try {
276
+ const response = await originalFetch(input, init);
277
+ const endTime = Date.now();
278
+ const responseHeaders = {};
279
+ response.headers.forEach((value, key) => {
280
+ responseHeaders[key] = value;
281
+ });
282
+ const clonedResponse = response.clone();
283
+ let responseBody;
284
+ try {
285
+ const headerMap = {};
286
+ response.headers.forEach((value, key) => {
287
+ headerMap[key.toLowerCase()] = value;
288
+ });
289
+ const contentType = headerMap["content-type"];
290
+ if (contentType?.includes("application/json")) responseBody = (0, javascript_stringify.stringify)(await clonedResponse.json(), null, 2, { references: true }) ?? "";
291
+ else if (contentType?.includes("text")) responseBody = await clonedResponse.text();
292
+ } catch (error) {
293
+ responseBody = `[Unable to read response body] ${error}`;
294
+ console.error("[LynxConsole] Error reading response body:", error);
295
+ }
296
+ updateNetworkEntry(id, {
297
+ status: "success",
298
+ statusCode: response.status,
299
+ statusText: response.statusText,
300
+ endTime,
301
+ duration: endTime - startTime,
302
+ responseHeaders,
303
+ responseBody: responseBody ?? ""
304
+ });
305
+ return response;
306
+ } catch (error) {
307
+ const endTime = Date.now();
308
+ updateNetworkEntry(id, {
309
+ status: "error",
310
+ endTime,
311
+ duration: endTime - startTime,
312
+ error: error instanceof Error ? error.message : String(error)
313
+ });
314
+ throw error;
315
+ }
316
+ };
317
+ fetch = monitoredFetch;
318
+ lynx.fetch = monitoredFetch;
319
+ console.log("[LynxConsole] ✅ Network monitoring initialized");
320
+ };
321
+
322
+ //#endregion
323
+ //#region src/setup/setupPerformanceMonitor.ts
324
+ const generatePerformanceId = () => {
325
+ return `performance-${Date.now()}-${Math.random()}`;
326
+ };
327
+ const addPerformanceEntry = (entry) => {
328
+ const state = globalThis.__LYNX_CONSOLE__?.state;
329
+ if (!state?.performances || !state?.performanceListeners) {
330
+ console.error("[LynxConsole] Cannot add performance entry: Performance monitor not initialized. Call initPerformanceMonitor() first.");
331
+ return;
332
+ }
333
+ state.performances.push(entry);
334
+ state.performanceListeners.forEach((listener) => {
335
+ listener(entry);
336
+ });
337
+ };
338
+ const initPerformanceMonitor = () => {
339
+ "background only";
340
+ if (!lynx.performance) {
341
+ console.warn("[LynxConsole] lynx.performance not available, skipping performance monitor");
342
+ return;
343
+ }
344
+ const { state } = ensureConsoleStructure();
345
+ if (state.performances !== void 0) {
346
+ console.warn("[LynxConsole] Performance monitor already initialized");
347
+ return;
348
+ }
349
+ state.performances = [];
350
+ state.performanceListeners = /* @__PURE__ */ new Set();
351
+ state.subscribePerformance = (listener) => {
352
+ state.performanceListeners?.add(listener);
353
+ return () => {
354
+ state.performanceListeners?.delete(listener);
355
+ };
356
+ };
357
+ lynx.performance.createObserver((entry) => {
358
+ addPerformanceEntry({
359
+ id: generatePerformanceId(),
360
+ entryType: entry.entryType,
361
+ name: entry.name,
362
+ timestamp: Date.now(),
363
+ rawEntry: entry
364
+ });
365
+ }).observe([
366
+ "pipeline",
367
+ "init",
368
+ "metric"
369
+ ]);
370
+ console.log("[LynxConsole] ✅ Performance monitoring initialized");
371
+ };
372
+
373
+ //#endregion
374
+ exports.initLogMonitor = initLogMonitor;
375
+ exports.initMainThreadConsole = initMainThreadConsole;
376
+ exports.initNetworkMonitor = initNetworkMonitor;
377
+ exports.initPerformanceMonitor = initPerformanceMonitor;
@@ -0,0 +1,15 @@
1
+
2
+ //#region src/setup/setupLogMonitor.d.ts
3
+ declare const initLogMonitor: () => void;
4
+ //#endregion
5
+ //#region src/setup/setupMainThreadConsole.d.ts
6
+ declare const initMainThreadConsole: () => Promise<void>;
7
+ //#endregion
8
+ //#region src/setup/setupNetworkMonitor.d.ts
9
+ declare const initNetworkMonitor: () => void;
10
+ //#endregion
11
+ //#region src/setup/setupPerformanceMonitor.d.ts
12
+ declare const initPerformanceMonitor: () => void;
13
+ //#endregion
14
+ export { initLogMonitor, initMainThreadConsole, initNetworkMonitor, initPerformanceMonitor };
15
+ //# sourceMappingURL=setup.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.cts","names":[],"sources":["../src/setup/setupLogMonitor.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"mappings":";;cAsCa,cAAA;;;cC7BA,qBAAA,QAAkC,OAAA;;;cCiHlC,kBAAA;;;cClGA,sBAAA"}
@@ -0,0 +1,15 @@
1
+
2
+ //#region src/setup/setupLogMonitor.d.ts
3
+ declare const initLogMonitor: () => void;
4
+ //#endregion
5
+ //#region src/setup/setupMainThreadConsole.d.ts
6
+ declare const initMainThreadConsole: () => Promise<void>;
7
+ //#endregion
8
+ //#region src/setup/setupNetworkMonitor.d.ts
9
+ declare const initNetworkMonitor: () => void;
10
+ //#endregion
11
+ //#region src/setup/setupPerformanceMonitor.d.ts
12
+ declare const initPerformanceMonitor: () => void;
13
+ //#endregion
14
+ export { initLogMonitor, initMainThreadConsole, initNetworkMonitor, initPerformanceMonitor };
15
+ //# sourceMappingURL=setup.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.mts","names":[],"sources":["../src/setup/setupLogMonitor.ts","../src/setup/setupMainThreadConsole.ts","../src/setup/setupNetworkMonitor.ts","../src/setup/setupPerformanceMonitor.ts"],"mappings":";;cAsCa,cAAA;;;cC7BA,qBAAA,QAAkC,OAAA;;;cCiHlC,kBAAA;;;cClGA,sBAAA"}