jazz-tools 0.20.4 → 0.20.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,10 @@
1
1
  import { CoID, LocalNode, RawAccount } from "cojson";
2
2
  import { type Position } from "./viewer/inspector-button.js";
3
3
  export type InspectorTab = "inspector" | "performance";
4
- export declare function InspectorInApp({ position, localNode, accountId, }: {
4
+ export declare function InspectorInApp({ position, localNode, accountId, showDeleteLocalData, }: {
5
5
  position?: Position;
6
6
  localNode?: LocalNode;
7
7
  accountId?: CoID<RawAccount>;
8
+ showDeleteLocalData?: boolean;
8
9
  }): import("react/jsx-runtime").JSX.Element;
9
10
  //# sourceMappingURL=in-app.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"in-app.d.ts","sourceRoot":"","sources":["../../src/inspector/in-app.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAKrD,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAS9E,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;AAgBvD,wBAAgB,cAAc,CAAC,EAC7B,QAAkB,EAClB,SAAS,EACT,SAAS,GACV,EAAE;IACD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;CAC9B,2CA0CA"}
1
+ {"version":3,"file":"in-app.d.ts","sourceRoot":"","sources":["../../src/inspector/in-app.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAKrD,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAQ9E,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;AAgBvD,wBAAgB,cAAc,CAAC,EAC7B,QAAkB,EAClB,SAAS,EACT,SAAS,EACT,mBAA2B,GAC5B,EAAE;IACD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,2CA0CA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspector/index.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAExD,wBAAgB,eAAe,SAE9B;AAED,wBAAgB,aAAa,CAAC,EAAE,QAAkB,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAE,kDAqB5E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspector/index.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAExD,wBAAgB,eAAe,SAE9B;AAED,wBAAgB,aAAa,CAAC,EAAE,QAAkB,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAE,kDAsB5E"}
@@ -1121,7 +1121,8 @@ function getStoredTab() {
1121
1121
  function InspectorInApp({
1122
1122
  position = "right",
1123
1123
  localNode,
1124
- accountId
1124
+ accountId,
1125
+ showDeleteLocalData = false
1125
1126
  }) {
1126
1127
  const [open, setOpen] = useOpenInspector();
1127
1128
  const [activeTab, setActiveTabState] = useState5(getStoredTab);
@@ -1149,7 +1150,7 @@ function InspectorInApp({
1149
1150
  PageStack,
1150
1151
  {
1151
1152
  style: { display: activeTab === "inspector" ? "flex" : "none" },
1152
- homePage: /* @__PURE__ */ jsx6(HomePage, { showDeleteLocalData: true })
1153
+ homePage: /* @__PURE__ */ jsx6(HomePage, { showDeleteLocalData })
1153
1154
  }
1154
1155
  ),
1155
1156
  /* @__PURE__ */ jsx6(
@@ -1200,7 +1201,8 @@ function JazzInspector({ position = "right" }) {
1200
1201
  {
1201
1202
  position,
1202
1203
  localNode,
1203
- accountId: me?.$jazz.raw.id
1204
+ accountId: me?.$jazz.raw.id,
1205
+ showDeleteLocalData: true
1204
1206
  }
1205
1207
  );
1206
1208
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/inspector/index.tsx","../../src/inspector/in-app.tsx","../../src/inspector/viewer/inspector-button.tsx","../../src/inspector/viewer/use-open-inspector.ts","../../src/inspector/pages/performance/PerformancePage.tsx","../../src/inspector/pages/performance/Timeline.tsx","../../src/inspector/pages/performance/helpers.ts","../../src/inspector/pages/performance/SubscriptionRow.tsx","../../src/inspector/pages/performance/SubscriptionDetailPanel.tsx","../../src/inspector/pages/performance/usePerformanceEntries.ts"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { setup } from \"goober\";\nimport { useJazzContextValue } from \"jazz-tools/react-core\";\nimport { Account, SubscriptionScope } from \"jazz-tools\";\nimport { InspectorInApp } from \"./in-app.js\";\nimport { Position } from \"./viewer/inspector-button.js\";\n\nexport function enableProfiling() {\n SubscriptionScope.enableProfiling();\n}\n\nexport function JazzInspector({ position = \"right\" }: { position?: Position }) {\n const context = useJazzContextValue<Account>();\n const localNode = context.node;\n const me = \"me\" in context ? context.me : undefined;\n\n const [isCSR, setIsCSR] = useState(false);\n useEffect(() => {\n setIsCSR(true);\n }, []);\n\n if (!isCSR) {\n return null;\n }\n\n return (\n <InspectorInApp\n position={position}\n localNode={localNode}\n accountId={me?.$jazz.raw.id}\n />\n );\n}\n\nsetup(React.createElement);\n","import { CoID, LocalNode, RawAccount } from \"cojson\";\nimport { styled } from \"goober\";\nimport { useCallback, useState } from \"react\";\nimport { PageStack } from \"./viewer/page-stack.js\";\nimport { GlobalStyles } from \"./ui/global-styles.js\";\nimport { InspectorButton, type Position } from \"./viewer/inspector-button.js\";\nimport { useOpenInspector } from \"./viewer/use-open-inspector.js\";\nimport { NodeProvider } from \"./contexts/node.js\";\nimport { InMemoryRouterProvider } from \"./router/in-memory-router.js\";\nimport { Header } from \"./viewer/header.js\";\nimport { PerformancePage } from \"./pages/performance/index.js\";\nimport { HomePage } from \"./pages/home.js\";\nimport { SubscriptionScope } from \"jazz-tools\";\n\nexport type InspectorTab = \"inspector\" | \"performance\";\n\nconst STORAGE_KEY = \"jazz-inspector-tab\";\n\nfunction getStoredTab(): InspectorTab {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored === \"inspector\" || stored === \"performance\") {\n return stored;\n }\n } catch {\n // localStorage not available\n }\n return \"inspector\";\n}\n\nexport function InspectorInApp({\n position = \"right\",\n localNode,\n accountId,\n}: {\n position?: Position;\n localNode?: LocalNode;\n accountId?: CoID<RawAccount>;\n}) {\n const [open, setOpen] = useOpenInspector();\n const [activeTab, setActiveTabState] = useState<InspectorTab>(getStoredTab);\n\n const setActiveTab = useCallback((tab: InspectorTab) => {\n setActiveTabState(tab);\n try {\n localStorage.setItem(STORAGE_KEY, tab);\n } catch {\n // localStorage not available\n }\n }, []);\n\n if (!open) {\n return (\n <InspectorButton position={position} onClick={() => setOpen(true)} />\n );\n }\n\n return (\n <NodeProvider localNode={localNode ?? null} accountID={accountId ?? null}>\n <InMemoryRouterProvider>\n <InspectorContainer as={GlobalStyles} style={{ zIndex: 999 }}>\n <Header\n showClose={true}\n onClose={() => setOpen(false)}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n />\n {/* Both components stay mounted, visibility controlled by CSS */}\n <PageStack\n style={{ display: activeTab === \"inspector\" ? \"flex\" : \"none\" }}\n homePage={<HomePage showDeleteLocalData />}\n />\n <PerformancePage\n style={{ display: activeTab === \"performance\" ? \"flex\" : \"none\" }}\n onNavigate={() => setActiveTab(\"inspector\")}\n />\n </InspectorContainer>\n </InMemoryRouterProvider>\n </NodeProvider>\n );\n}\n\nconst InspectorContainer = styled(\"div\")`\n position: fixed;\n height: 50vh;\n max-height: 800px;\n display: flex;\n flex-direction: column;\n bottom: 0;\n left: 0;\n width: 100%;\n background-color: white;\n border-top: 1px solid var(--j-border-color);\n color: var(--j-text-color);\n\n @media (prefers-color-scheme: dark) {\n background-color: var(--j-background);\n }\n`;\n","import { styled } from \"goober\";\nimport React from \"react\";\n\nexport type Position =\n | \"bottom right\"\n | \"bottom left\"\n | \"top right\"\n | \"top left\"\n | \"right\"\n | \"left\";\n\nconst StyledInspectorButton = styled(\"button\")<{ position: Position }>`\n position: fixed;\n width: 2.5rem;\n height: 2.5rem;\n background-color: white;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n margin: 1rem;\n padding: 0.5rem !important;\n border: 1px solid #e5e3e4;\n border-radius: 0.375rem;\n z-index: 999;\n \n ${(props) => {\n switch (props.position) {\n case \"bottom right\":\n return \"bottom: 0; right: 0;\";\n case \"bottom left\":\n return \"bottom: 0; left: 0;\";\n case \"top right\":\n return \"top: 0; right: 0;\";\n case \"top left\":\n return \"top: 0; left: 0;\";\n case \"right\":\n return \"right: 0; top: 50%; transform: translateY(-50%);\";\n case \"left\":\n return \"left: 0; top: 50%; transform: translateY(-50%);\";\n default:\n return \"\";\n }\n }}\n`;\n\nconst JazzIcon = styled(\"svg\")`\n width: 100%;\n height: auto;\n position: relative;\n left: -1px;\n color: #146AFF;\n`;\n\nexport function InspectorButton({\n position = \"right\",\n ...buttonProps\n}: React.ComponentPropsWithoutRef<\"button\"> & { position?: Position }) {\n return (\n <StyledInspectorButton position={position} {...buttonProps}>\n <JazzIcon\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"119\"\n height=\"115\"\n viewBox=\"0 0 119 115\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M118.179 23.8277V0.167999C99.931 7.5527 79.9854 11.6192 59.0897 11.6192C47.1466 11.6192 35.5138 10.2908 24.331 7.7737V30.4076V60.1508C23.2955 59.4385 22.1568 58.8458 20.9405 58.3915C18.1732 57.358 15.128 57.0876 12.1902 57.6145C9.2524 58.1414 6.5539 59.4419 4.4358 61.3516C2.3178 63.2613 0.875401 65.6944 0.291001 68.3433C-0.293399 70.9921 0.00659978 73.7377 1.1528 76.2329C2.2991 78.728 4.2403 80.861 6.7308 82.361C9.2214 83.862 12.1495 84.662 15.1448 84.662C15.6054 84.662 15.8365 84.662 16.0314 84.659C26.5583 84.449 35.042 75.9656 35.2513 65.4386C35.2534 65.3306 35.2544 65.2116 35.2548 65.0486L35.2552 64.7149V64.5521V61.0762V32.1993C43.0533 33.2324 51.0092 33.7656 59.0897 33.7656C59.6696 33.7656 60.2489 33.7629 60.8276 33.7574V89.696C59.792 88.983 58.6533 88.391 57.437 87.936C54.6697 86.903 51.6246 86.632 48.6867 87.159C45.7489 87.686 43.0504 88.987 40.9323 90.896C38.8143 92.806 37.3719 95.239 36.7875 97.888C36.2032 100.537 36.5031 103.283 37.6494 105.778C38.7956 108.273 40.7368 110.405 43.2273 111.906C45.7179 113.406 48.646 114.207 51.6414 114.207C52.1024 114.207 52.3329 114.207 52.5279 114.203C63.0548 113.994 71.5385 105.51 71.7478 94.983C71.7517 94.788 71.7517 94.558 71.7517 94.097V90.621V33.3266C83.962 32.4768 95.837 30.4075 107.255 27.2397V59.9017C106.219 59.1894 105.081 58.5966 103.864 58.1424C101.097 57.1089 98.052 56.8384 95.114 57.3653C92.176 57.8922 89.478 59.1927 87.36 61.1025C85.242 63.0122 83.799 65.4453 83.215 68.0941C82.631 70.743 82.931 73.4886 84.077 75.9837C85.223 78.4789 87.164 80.612 89.655 82.112C92.145 83.612 95.073 84.413 98.069 84.413C98.53 84.413 98.76 84.413 98.955 84.409C109.482 84.2 117.966 75.7164 118.175 65.1895C118.179 64.9945 118.179 64.764 118.179 64.3029V60.8271V23.8277Z\"\n fill=\"currentColor\"\n />\n </JazzIcon>\n <span\n style={{\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n padding: \"0\",\n margin: \"-1px\",\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n border: \"0\",\n }}\n >\n Open Jazz Inspector\n </span>\n </StyledInspectorButton>\n );\n}\n","import { useEffect, useState } from \"react\";\n\nconst STORAGE_KEY = \"jazz-inspector-open\";\n\nexport function useOpenInspector() {\n const [open, setOpen] = useState(() => {\n // Initialize from localStorage if available\n if (typeof window === \"undefined\") return false;\n const stored = localStorage.getItem(STORAGE_KEY);\n return stored ? JSON.parse(stored) : false;\n });\n\n // Update localStorage when open state changes\n useEffect(() => {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(open));\n }, [open]);\n\n return [open, setOpen];\n}\n","import { styled } from \"goober\";\nimport { type CSSProperties, useMemo, useState, useDeferredValue } from \"react\";\nimport { CoID, RawCoValue } from \"cojson\";\nimport { useRouter } from \"../../router/context.js\";\nimport { Timeline } from \"./Timeline.js\";\nimport { SubscriptionRow } from \"./SubscriptionRow.js\";\nimport { SubscriptionDetailPanel } from \"./SubscriptionDetailPanel.js\";\nimport { usePerformanceEntries } from \"./usePerformanceEntries.js\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { SubscriptionScope } from \"jazz-tools\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst Container = styled(\"div\")`\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding: 1rem;\n height: 100%;\n min-height: 0;\n`;\n\nconst MainLayout = styled(\"div\")`\n display: flex;\n flex: 1;\n min-height: 0;\n gap: 1rem;\n`;\n\nconst ListPanel = styled(\"div\")`\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n`;\n\nconst Grid = styled(\"div\")`\n display: grid;\n grid-template-columns:\n minmax(100px, 150px)\n minmax(150px, 1fr)\n minmax(100px, 200px)\n 80px;\n grid-template-rows: min-content;\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n min-height: 0;\n position: relative;\n`;\n\nconst HeaderCell = styled(\"div\")`\n padding: 0.5rem;\n font-size: 0.625rem;\n font-weight: 600;\n color: var(--j-neutral-500);\n border-bottom: 1px solid var(--j-border-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n`;\n\nconst EmptyState = styled(\"div\")`\n text-align: center;\n padding: 2rem;\n color: var(--j-neutral-500);\n font-size: 0.875rem;\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface PerformancePageProps {\n onNavigate: () => void;\n style?: CSSProperties;\n}\n\nexport function PerformancePage({ onNavigate, style }: PerformancePageProps) {\n const entries = usePerformanceEntries();\n const [selectedRow, setSelectedRow] = useState<string | null>(null);\n const [timeSelection, setTimeSelection] = useState<[number, number] | null>(\n null,\n );\n const deferredSelection = useDeferredValue(timeSelection);\n const { setPage } = useRouter();\n\n const selectRow = (uuid: string) => {\n setSelectedRow((prev) => (prev === uuid ? null : uuid));\n };\n\n const sortedEntries = useMemo(() => {\n return [...entries].sort((a, b) => a.startTime - b.startTime);\n }, [entries]);\n\n const overallTimeRange = useMemo(() => {\n if (entries.length === 0) return null;\n const now = performance.now();\n return {\n min: Math.min(...entries.map((e) => e.startTime)),\n max: Math.max(...entries.map((e) => e.endTime ?? now)),\n };\n }, [entries]);\n\n const filteredEntries = useMemo(() => {\n if (!deferredSelection) return sortedEntries;\n const [startTime, endTime] = deferredSelection;\n const now = performance.now();\n return sortedEntries.filter((entry) => {\n const entryEnd = entry.endTime ?? now;\n // Entry overlaps with selection if it starts before selection ends and ends after selection starts\n return entry.startTime <= endTime && entryEnd >= startTime;\n });\n }, [sortedEntries, deferredSelection]);\n\n const displayRange = deferredSelection\n ? { min: deferredSelection[0], max: deferredSelection[1] }\n : overallTimeRange;\n\n // Calculate bar position for each entry\n const getBarProps = (entry: SubscriptionEntry) => {\n const range = (displayRange?.max ?? 1) - (displayRange?.min ?? 0) || 1;\n const now = performance.now();\n\n const clampedStart = Math.max(entry.startTime, displayRange?.min ?? 0);\n const clampedEnd = Math.min(entry.endTime ?? now, displayRange?.max ?? now);\n\n const left = Math.max(\n 0,\n ((clampedStart - (displayRange?.min ?? 0)) / range) * 100,\n );\n const width = Math.max(0, ((clampedEnd - clampedStart) / range) * 100);\n\n const color =\n entry.status === \"pending\"\n ? \"var(--j-warning-color)\"\n : entry.status === \"error\"\n ? \"var(--j-error-color)\"\n : \"var(--j-success-color)\";\n\n return {\n barLeft: `${left}%`,\n barWidth: width === 0 ? \"1px\" : `${width}%`,\n barColor: color,\n };\n };\n\n const handleNavigateToCoValue = (id: string) => {\n setPage(id as CoID<RawCoValue>);\n onNavigate();\n };\n\n if (!SubscriptionScope.isProfilingEnabled) {\n return (\n <Container style={style}>\n <EmptyState>Profiling is not enabled in production builds.</EmptyState>\n </Container>\n );\n }\n\n if (entries.length === 0) {\n return (\n <Container style={style}>\n <EmptyState>\n No subscriptions recorded yet. Interact with your app to see\n subscription performance data.\n </EmptyState>\n </Container>\n );\n }\n\n const selectedEntry = selectedRow\n ? filteredEntries.find((e) => e.uuid === selectedRow)\n : null;\n\n return (\n <Container style={style}>\n {overallTimeRange && (\n <Timeline\n entries={sortedEntries}\n timeRange={overallTimeRange}\n selection={timeSelection}\n onSelectionChange={setTimeSelection}\n />\n )}\n <MainLayout>\n <ListPanel>\n <Grid>\n <HeaderCell>Source</HeaderCell>\n <HeaderCell>CoValue</HeaderCell>\n <HeaderCell>Caller</HeaderCell>\n <HeaderCell>Duration</HeaderCell>\n {filteredEntries.map((entry) => (\n <SubscriptionRow\n key={entry.uuid}\n entry={entry}\n isSelected={selectedRow === entry.uuid}\n onSelect={() => selectRow(entry.uuid)}\n {...getBarProps(entry)}\n />\n ))}\n </Grid>\n </ListPanel>\n {selectedEntry && (\n <SubscriptionDetailPanel\n entry={selectedEntry}\n onNavigate={handleNavigateToCoValue}\n onClose={() => setSelectedRow(null)}\n />\n )}\n </MainLayout>\n </Container>\n );\n}\n","import { styled } from \"goober\";\nimport {\n type CSSProperties,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { formatDuration } from \"./helpers.js\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst TimelineContainer = styled(\"div\")`\n position: relative;\n display: flex;\n flex-direction: column;\n background-color: var(--j-foreground);\n border: 1px solid var(--j-border-color);\n border-radius: var(--j-radius-sm);\n overflow: hidden;\n`;\n\nconst TimelineTrack = styled(\"div\")`\n position: relative;\n height: 48px;\n background-color: var(--j-background);\n cursor: crosshair;\n user-select: none;\n`;\n\nconst TimeMarker = styled(\"div\")`\n position: absolute;\n font-size: 0.5rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--j-text-color);\n padding: 2px 4px;\n white-space: nowrap;\n\n @media (prefers-color-scheme: dark) {\n color: var(--j-neutral-500);\n }\n\n &::after {\n content: \"\";\n position: absolute;\n left: 0;\n top: 100%;\n width: 1px;\n height: 32px;\n background-color: var(--j-border-color);\n }\n`;\n\nconst TimelineBars = styled(\"div\")`\n position: absolute;\n top: 16px;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n`;\n\nconst TimelineBar = styled(\"div\")`\n position: absolute;\n border-radius: 1px;\n min-width: 2px;\n`;\n\nconst TimelineSelection = styled(\"div\")`\n position: absolute;\n top: 0;\n bottom: 0;\n background-color: var(--j-primary-color);\n opacity: 0.2;\n cursor: grab;\n pointer-events: auto;\n\n &:active {\n cursor: grabbing;\n }\n`;\n\nconst TimelineSelectionHandle = styled(\"div\")`\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background-color: var(--j-primary-color);\n cursor: ew-resize;\n pointer-events: auto;\n\n &::after {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 8px;\n height: 16px;\n background-color: var(--j-primary-color);\n border-radius: 2px;\n }\n`;\n\nconst ClearSelectionButton = styled(\"button\")`\n position: absolute;\n top: 4px;\n right: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n font-size: 0.5rem;\n background-color: var(--j-foreground);\n border: 1px solid var(--j-border-color);\n border-radius: var(--j-radius-sm);\n cursor: pointer;\n color: var(--j-neutral-500);\n z-index: 10;\n\n &:hover {\n background-color: var(--j-background);\n color: var(--j-text-color);\n }\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface TimelineProps {\n entries: SubscriptionEntry[];\n timeRange: { min: number; max: number };\n selection: [number, number] | null;\n onSelectionChange: (selection: [number, number] | null) => void;\n}\n\ntype DragMode = \"creating\" | \"moving\" | \"resizing-left\" | \"resizing-right\";\n\nexport function Timeline({\n entries,\n timeRange,\n selection,\n onSelectionChange,\n}: TimelineProps) {\n const trackRef = useRef<HTMLDivElement>(null);\n const [dragMode, setDragMode] = useState<DragMode | null>(null);\n const [dragStartTime, setDragStartTime] = useState<number | null>(null);\n const [dragCurrentTime, setDragCurrentTime] = useState<number | null>(null);\n const [dragInitialSelection, setDragInitialSelection] = useState<\n [number, number] | null\n >(null);\n\n const duration = timeRange.max - timeRange.min;\n\n // Generate time markers\n const timeMarkers = useMemo(() => {\n const markers: { time: number; label: string; position: number }[] = [];\n if (duration <= 0) return markers;\n\n const maxMarkers = 5;\n\n // Calculate minimum interval to have at most maxMarkers\n const minInterval = duration / maxMarkers;\n\n // Round up to a \"nice\" number (1, 2, 5, 10, 20, 50, 100, ...)\n const magnitude = Math.pow(10, Math.floor(Math.log10(minInterval)));\n const normalized = minInterval / magnitude;\n let niceMultiplier: number;\n if (normalized <= 1) niceMultiplier = 1;\n else if (normalized <= 2) niceMultiplier = 2;\n else if (normalized <= 5) niceMultiplier = 5;\n else niceMultiplier = 10;\n\n const interval = niceMultiplier * magnitude;\n\n const startMarker = Math.ceil(timeRange.min / interval) * interval;\n for (let time = startMarker; time <= timeRange.max; time += interval) {\n const position = ((time - timeRange.min) / duration) * 100;\n markers.push({\n time,\n label: formatDuration(time),\n position,\n });\n }\n return markers;\n }, [timeRange, duration]);\n\n const getTimeFromPosition = (clientX: number): number => {\n if (!trackRef.current) return 0;\n const rect = trackRef.current.getBoundingClientRect();\n const position = Math.max(\n 0,\n Math.min(1, (clientX - rect.left) / rect.width),\n );\n return timeRange.min + position * duration;\n };\n\n const handleTrackMouseDown = (e: React.MouseEvent) => {\n const time = getTimeFromPosition(e.clientX);\n setDragMode(\"creating\");\n setDragStartTime(time);\n setDragCurrentTime(time);\n };\n\n const handleSelectionMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selection) return;\n const time = getTimeFromPosition(e.clientX);\n setDragMode(\"moving\");\n setDragStartTime(time);\n setDragCurrentTime(time);\n setDragInitialSelection(selection);\n };\n\n const handleLeftHandleMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selection) return;\n setDragMode(\"resizing-left\");\n setDragStartTime(selection[0]);\n setDragCurrentTime(selection[0]);\n setDragInitialSelection(selection);\n };\n\n const handleRightHandleMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selection) return;\n setDragMode(\"resizing-right\");\n setDragStartTime(selection[1]);\n setDragCurrentTime(selection[1]);\n setDragInitialSelection(selection);\n };\n\n useEffect(() => {\n if (!dragMode) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const time = getTimeFromPosition(e.clientX);\n setDragCurrentTime(time);\n };\n\n const handleMouseUp = () => {\n if (\n dragMode === \"creating\" &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n const start = Math.min(dragStartTime, dragCurrentTime);\n const end = Math.max(dragStartTime, dragCurrentTime);\n if ((end - start) / duration > 0.01) {\n onSelectionChange([start, end]);\n }\n } else if (\n dragMode === \"moving\" &&\n dragInitialSelection &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n const delta = dragCurrentTime - dragStartTime;\n const selectionWidth =\n dragInitialSelection[1] - dragInitialSelection[0];\n let newStart = dragInitialSelection[0] + delta;\n let newEnd = dragInitialSelection[1] + delta;\n // Clamp to time range\n if (newStart < timeRange.min) {\n newStart = timeRange.min;\n newEnd = timeRange.min + selectionWidth;\n }\n if (newEnd > timeRange.max) {\n newEnd = timeRange.max;\n newStart = timeRange.max - selectionWidth;\n }\n onSelectionChange([newStart, newEnd]);\n } else if (\n dragMode === \"resizing-left\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newStart = Math.min(\n dragCurrentTime,\n dragInitialSelection[1] - duration * 0.01,\n );\n onSelectionChange([\n Math.max(timeRange.min, newStart),\n dragInitialSelection[1],\n ]);\n } else if (\n dragMode === \"resizing-right\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newEnd = Math.max(\n dragCurrentTime,\n dragInitialSelection[0] + duration * 0.01,\n );\n onSelectionChange([\n dragInitialSelection[0],\n Math.min(timeRange.max, newEnd),\n ]);\n }\n\n setDragMode(null);\n setDragStartTime(null);\n setDragCurrentTime(null);\n setDragInitialSelection(null);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [\n dragMode,\n dragStartTime,\n dragCurrentTime,\n dragInitialSelection,\n duration,\n timeRange,\n onSelectionChange,\n ]);\n\n // Pre-calculate lane assignments to avoid overlaps\n const laneAssignments = useMemo(() => {\n const now = performance.now();\n const barHeight = 3;\n const barGap = 1;\n const maxLanes = 8;\n\n // Sort entries by start time for lane assignment\n const sortedEntries = [...entries].sort(\n (a, b) => a.startTime - b.startTime,\n );\n\n // Track end times for each lane (up to maxLanes)\n const laneEndTimes: number[] = Array(maxLanes).fill(0);\n const assignments = new Map<string, number>();\n\n for (const entry of sortedEntries) {\n const entryEnd = entry.endTime ?? now;\n\n // Find the first lane where this entry fits (no overlap)\n let assignedLane = laneEndTimes.findIndex(\n (endTime) => entry.startTime >= endTime,\n );\n\n if (assignedLane === -1) {\n // All lanes are occupied, find the one that ends earliest\n const earliestEnd = Math.min(...laneEndTimes);\n assignedLane = laneEndTimes.indexOf(earliestEnd);\n }\n\n // Update the lane's end time\n laneEndTimes[assignedLane] = entryEnd;\n\n // Calculate top position\n assignments.set(entry.uuid, assignedLane * (barHeight + barGap));\n }\n\n return assignments;\n }, [entries]);\n\n const getBarStyle = (entry: SubscriptionEntry): CSSProperties => {\n const now = performance.now();\n const start = entry.startTime;\n const end = entry.endTime ?? now;\n const left = ((start - timeRange.min) / duration) * 100;\n const width = Math.max(0.5, ((end - start) / duration) * 100);\n\n const color =\n entry.status === \"pending\"\n ? \"var(--j-warning-color)\"\n : entry.status === \"error\"\n ? \"var(--j-error-color)\"\n : \"var(--j-success-color)\";\n\n const top = laneAssignments.get(entry.uuid) ?? 0;\n\n return {\n left: `${left}%`,\n width: `${width}%`,\n backgroundColor: color,\n top: `${top}px`,\n height: \"3px\",\n };\n };\n\n // Calculate current selection during drag\n const currentSelection = useMemo((): [number, number] | null => {\n if (\n dragMode === \"creating\" &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n return [\n Math.min(dragStartTime, dragCurrentTime),\n Math.max(dragStartTime, dragCurrentTime),\n ];\n }\n if (\n dragMode === \"moving\" &&\n dragInitialSelection &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n const delta = dragCurrentTime - dragStartTime;\n const selectionWidth = dragInitialSelection[1] - dragInitialSelection[0];\n let newStart = dragInitialSelection[0] + delta;\n let newEnd = dragInitialSelection[1] + delta;\n if (newStart < timeRange.min) {\n newStart = timeRange.min;\n newEnd = timeRange.min + selectionWidth;\n }\n if (newEnd > timeRange.max) {\n newEnd = timeRange.max;\n newStart = timeRange.max - selectionWidth;\n }\n return [newStart, newEnd];\n }\n if (\n dragMode === \"resizing-left\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newStart = Math.max(\n timeRange.min,\n Math.min(dragCurrentTime, dragInitialSelection[1] - duration * 0.01),\n );\n return [newStart, dragInitialSelection[1]];\n }\n if (\n dragMode === \"resizing-right\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newEnd = Math.min(\n timeRange.max,\n Math.max(dragCurrentTime, dragInitialSelection[0] + duration * 0.01),\n );\n return [dragInitialSelection[0], newEnd];\n }\n return selection;\n }, [\n dragMode,\n dragStartTime,\n dragCurrentTime,\n dragInitialSelection,\n selection,\n timeRange,\n duration,\n ]);\n\n const selectionLeft = currentSelection\n ? ((currentSelection[0] - timeRange.min) / duration) * 100\n : 0;\n const selectionWidth = currentSelection\n ? ((currentSelection[1] - currentSelection[0]) / duration) * 100\n : 0;\n\n return (\n <TimelineContainer>\n <TimelineTrack ref={trackRef} onMouseDown={handleTrackMouseDown}>\n {timeMarkers.map((marker) => (\n <TimeMarker key={marker.time} style={{ left: `${marker.position}%` }}>\n {marker.label}\n </TimeMarker>\n ))}\n <TimelineBars>\n {entries.map((entry) => (\n <TimelineBar key={entry.uuid} style={getBarStyle(entry)} />\n ))}\n </TimelineBars>\n {currentSelection && (\n <>\n <TimelineSelection\n style={{\n left: `${selectionLeft}%`,\n width: `${selectionWidth}%`,\n }}\n onMouseDown={handleSelectionMouseDown}\n />\n {!dragMode && (\n <>\n <TimelineSelectionHandle\n style={{ left: `${selectionLeft}%` }}\n onMouseDown={handleLeftHandleMouseDown}\n />\n <TimelineSelectionHandle\n style={{ left: `${selectionLeft + selectionWidth}%` }}\n onMouseDown={handleRightHandleMouseDown}\n />\n </>\n )}\n </>\n )}\n </TimelineTrack>\n {currentSelection && !dragMode && (\n <ClearSelectionButton\n onClick={(e) => {\n e.stopPropagation();\n onSelectionChange(null);\n }}\n >\n Clear selection\n </ClearSelectionButton>\n )}\n </TimelineContainer>\n );\n}\n","export function formatTime(startTime: number): string {\n const date = new Date(performance.timeOrigin + startTime);\n return date.toLocaleTimeString(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n fractionalSecondDigits: 3,\n });\n}\n\nexport function formatDuration(duration: number): string {\n if (duration < 1) {\n return `${(duration * 1000).toFixed(0)}μs`;\n }\n if (duration < 1000) {\n return `${duration.toFixed(2)}ms`;\n }\n return `${(duration / 1000).toFixed(2)}s`;\n}\n\nexport function getCallerLocation(\n stack: string | undefined,\n): string | undefined {\n if (!stack) return undefined;\n\n const lines = stack.split(\"\\n\").slice(2, 15);\n\n const normalizeLine = (line: string) =>\n line.replace(/https?:\\/\\/[^/\\s)]+/g, \"\");\n\n const userFrame = lines.find(\n (line) =>\n !line.includes(\"node_modules\") &&\n !line.includes(\"useCoValueSubscription\") &&\n !line.includes(\"useCoState\") &&\n !line.includes(\"useAccount\") &&\n !line.includes(\"useSuspenseCoState\") &&\n !line.includes(\"useSuspenseAccount\") &&\n !line.includes(\"jazz-tools\") &&\n !line.includes(\"trackLoadingPerformance\"),\n );\n\n if (userFrame) {\n const cleanedFrame = normalizeLine(userFrame).trim();\n const match = cleanedFrame.match(/\\(?([^)]+:\\d+:\\d+)\\)?$/);\n if (match) {\n return match[1];\n }\n return cleanedFrame;\n }\n\n return lines[0] ? normalizeLine(lines[0]).trim() : undefined;\n}\n\nexport function getCallerStack(stack: string | undefined): string | undefined {\n if (!stack) return undefined;\n\n const lines = stack.split(\"\\n\").slice(2, 15);\n\n return lines\n .filter(\n (line) =>\n !line.includes(\"Error:\") &&\n !line.includes(\"renderWithHooks\") &&\n !line.includes(\"react-stack-bottom-frame\"),\n )\n .map((line) => line.replace(/https?:\\/\\/[^/\\s)]+/g, \"\").trim())\n .reverse()\n .join(\"\\n\");\n}\n","import { styled } from \"goober\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { formatDuration, getCallerLocation } from \"./helpers.js\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst RowWrapper = styled(\"div\")`\n display: grid;\n grid-template-columns: subgrid;\n grid-column: 1 / -1;\n position: relative;\n cursor: pointer;\n\n &:hover,\n &:focus {\n background-color: var(--j-foreground);\n outline: none;\n }\n\n &:focus-visible {\n outline: 2px solid var(--j-primary-color);\n outline-offset: -2px;\n }\n\n &[data-expanded=\"true\"] {\n background-color: var(--j-foreground);\n }\n`;\n\nconst TimeBar = styled(\"div\")`\n position: absolute;\n bottom: 0;\n height: 4px;\n transition: transform 0.15s ease;\n z-index: 1;\n container-type: inline-size;\n\n .row-wrapper:hover &, [data-expanded=\"true\"] & {\n transform: scaleY(4);\n\n .time-label {\n opacity: 1;\n }\n }\n\n &[data-status=\"pending\"] {\n animation: pulse 1.5s ease-in-out infinite;\n }\n\n @keyframes pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n }\n`;\n\nconst TimeLabel = styled(\"span\")`\n position: absolute;\n top: 50%;\n transform: translateY(-50%) scaleY(0.25);\n font-size: 0.5rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: white;\n white-space: nowrap;\n opacity: 0;\n transition: opacity 0.15s ease;\n pointer-events: none;\n left: 4px;\n --time-label-overflow-color: black;\n\n @media (prefers-color-scheme: dark) {\n --time-label-overflow-color: white;\n }\n\n @container (max-width: 50px) {\n color: var(--time-label-overflow-color);\n left: 100%;\n margin-left: 4px;\n }\n\n [data-near-edge=\"true\"] & {\n @container (max-width: 50px) {\n left: auto;\n right: 100%;\n margin-left: 0;\n margin-right: 4px;\n }\n }\n`;\n\nconst Cell = styled(\"div\")`\n padding: 0.5rem;\n padding-bottom: 0.75rem;\n font-size: 0.625rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n border-bottom: 1px solid var(--j-border-color);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &[data-clickable=\"true\"] {\n cursor: pointer;\n color: var(--j-link-color);\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\nconst StatusBadge = styled(\"span\")`\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n font-size: 0.625rem;\n\n &[data-status=\"pending\"] {\n background-color: var(--j-warning-bg);\n color: var(--j-warning-color);\n }\n &[data-status=\"loaded\"] {\n background-color: var(--j-success-bg);\n color: var(--j-success-color);\n }\n &[data-status=\"error\"] {\n background-color: var(--j-error-bg);\n color: var(--j-error-color);\n }\n`;\n\nconst PendingDot = styled(\"span\")`\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background-color: var(--j-warning-color);\n animation: pendingPulse 1.5s ease-in-out infinite;\n\n @keyframes pendingPulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n }\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface SubscriptionRowProps {\n entry: SubscriptionEntry;\n isSelected: boolean;\n onSelect: () => void;\n barLeft: string;\n barWidth: string;\n barColor: string;\n}\n\nexport function SubscriptionRow({\n entry,\n isSelected,\n onSelect,\n barLeft,\n barWidth,\n barColor,\n}: SubscriptionRowProps) {\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect();\n }\n };\n\n return (\n <RowWrapper\n className=\"row-wrapper\"\n data-expanded={isSelected}\n onClick={onSelect}\n onKeyDown={handleKeyDown}\n tabIndex={0}\n role=\"button\"\n aria-label={`View details for ${entry.source} ${entry.id}`}\n >\n <Cell>\n <StatusBadge data-status={entry.status}>{entry.source}</StatusBadge>\n </Cell>\n <Cell>\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"0.125rem\",\n }}\n >\n <span>{entry.id}</span>\n <span style={{ color: \"var(--j-neutral-500)\" }}>{entry.resolve}</span>\n </div>\n </Cell>\n <Cell>{getCallerLocation(entry.callerStack) ?? \"-\"}</Cell>\n <Cell>\n {entry.duration !== undefined ? (\n entry.duration === 0 ? (\n \"⚡ cached\"\n ) : (\n formatDuration(entry.duration)\n )\n ) : (\n <PendingDot />\n )}\n </Cell>\n <TimeBar\n className=\"time-bar\"\n data-status={entry.status}\n data-near-edge={parseFloat(barLeft) + parseFloat(barWidth) > 85}\n style={{\n left: barLeft,\n width: barWidth,\n backgroundColor: barColor,\n }}\n >\n <TimeLabel className=\"time-label\">\n {entry.duration === 0\n ? \"⚡ cached\"\n : entry.duration\n ? formatDuration(entry.duration)\n : \"-\"}\n </TimeLabel>\n </TimeBar>\n </RowWrapper>\n );\n}\n","import { styled } from \"goober\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { formatTime, formatDuration, getCallerStack } from \"./helpers.js\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst DetailPanel = styled(\"div\")`\n width: 320px;\n flex-shrink: 0;\n padding: 0.75rem 1rem;\n background-color: var(--j-foreground);\n border: 1px solid var(--j-border-color);\n border-radius: var(--j-radius-sm);\n overflow-y: auto;\n position: relative;\n`;\n\nconst CloseButton = styled(\"button\")`\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n background: none;\n border: none;\n border-radius: var(--j-radius-sm);\n cursor: pointer;\n color: var(--j-neutral-500);\n\n &:hover {\n background-color: var(--j-background);\n color: var(--j-text-color);\n }\n\n &:focus-visible {\n outline: 2px solid var(--j-primary-color);\n outline-offset: -2px;\n }\n`;\n\nconst DetailsGrid = styled(\"div\")`\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 0.5rem 1rem;\n font-size: 0.625rem;\n`;\n\nconst DetailLabel = styled(\"span\")`\n color: var(--j-neutral-500);\n font-weight: 500;\n`;\n\nconst DetailValue = styled(\"span\")`\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--j-text-color);\n`;\n\nconst Pre = styled(\"pre\")`\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.625rem;\n color: var(--j-text-color);\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 200px;\n overflow-y: auto;\n background-color: var(--j-background);\n padding: 0.5rem;\n border-radius: var(--j-radius-sm);\n`;\n\nconst StatusBadge = styled(\"span\")`\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n font-size: 0.625rem;\n\n &[data-status=\"pending\"] {\n background-color: var(--j-warning-bg);\n color: var(--j-warning-color);\n }\n &[data-status=\"loaded\"] {\n background-color: var(--j-success-bg);\n color: var(--j-success-color);\n }\n &[data-status=\"error\"] {\n background-color: var(--j-error-bg);\n color: var(--j-error-color);\n }\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface SubscriptionDetailPanelProps {\n entry: SubscriptionEntry;\n onNavigate: (id: string) => void;\n onClose: () => void;\n}\n\nexport function SubscriptionDetailPanel({\n entry,\n onNavigate,\n onClose,\n}: SubscriptionDetailPanelProps) {\n return (\n <DetailPanel>\n <CloseButton onClick={onClose} aria-label=\"Close detail panel\">\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </CloseButton>\n <DetailsGrid>\n <DetailLabel>Source</DetailLabel>\n <DetailValue>\n <StatusBadge data-status={entry.status}>{entry.source}</StatusBadge>\n </DetailValue>\n\n <DetailLabel>CoValue</DetailLabel>\n <DetailValue>\n <button\n title=\"Click to navigate to CoValue\"\n onClick={() => onNavigate(entry.id)}\n style={{\n color: \"var(--j-link-color)\",\n cursor: \"pointer\",\n background: \"none\",\n border: \"none\",\n padding: 0,\n font: \"inherit\",\n }}\n >\n {entry.id}\n </button>\n </DetailValue>\n\n <DetailLabel>Time</DetailLabel>\n <DetailValue>\n {formatTime(entry.startTime)} -{\" \"}\n {entry.duration !== undefined\n ? formatTime(entry.startTime + entry.duration)\n : \"Pending...\"}\n </DetailValue>\n\n <DetailLabel>Duration</DetailLabel>\n <DetailValue>\n {entry.duration !== undefined\n ? formatDuration(entry.duration)\n : \"Pending...\"}\n </DetailValue>\n\n <DetailLabel>Resolve Query</DetailLabel>\n <Pre>{JSON.stringify(JSON.parse(entry.resolve), null, 2)}</Pre>\n\n <DetailLabel>Stack Trace</DetailLabel>\n <Pre>\n {getCallerStack(entry.callerStack) ?? \"No stack trace available\"}\n </Pre>\n </DetailsGrid>\n </DetailPanel>\n );\n}\n","import { useState, useEffect } from \"react\";\nimport { SubscriptionPerformanceDetail } from \"jazz-tools\";\nimport type { SubscriptionEntry } from \"./types.js\";\n\nexport function usePerformanceEntries(): SubscriptionEntry[] {\n const [entries, setEntries] = useState<SubscriptionEntry[]>([]);\n\n useEffect(() => {\n const entriesByUuid = new Map<string, SubscriptionEntry>();\n\n const handlePerformanceEntries = (entries: PerformanceEntry[]) => {\n for (const mark of entries) {\n const detail = (mark as PerformanceMark)\n .detail as SubscriptionPerformanceDetail;\n\n if (detail?.type !== \"jazz-subscription\") continue;\n\n const prevEntry = entriesByUuid.get(detail.uuid);\n\n if (mark.entryType === \"mark\" && prevEntry) continue;\n\n entriesByUuid.set(detail.uuid, {\n uuid: detail.uuid,\n id: detail.id,\n source: detail.source,\n resolve: JSON.stringify(detail.resolve),\n status: detail.status,\n startTime: mark.startTime,\n callerStack: detail.callerStack ?? prevEntry?.callerStack,\n duration: mark.entryType === \"mark\" ? undefined : mark.duration,\n endTime: mark.startTime + mark.duration,\n errorType: detail.errorType,\n });\n }\n };\n\n handlePerformanceEntries(performance.getEntriesByType(\"mark\"));\n handlePerformanceEntries(performance.getEntriesByType(\"measure\"));\n\n setEntries(Array.from(entriesByUuid.values()));\n\n const observer = new PerformanceObserver((list) => {\n handlePerformanceEntries(list.getEntries());\n setEntries(Array.from(entriesByUuid.values()));\n });\n\n observer.observe({ entryTypes: [\"mark\", \"measure\"] });\n\n return () => observer.disconnect();\n }, []);\n\n return entries;\n}\n"],"mappings":"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","names":["useEffect","useState","SubscriptionScope","styled","useState","styled","useMemo","useState","styled","useEffect","useState","jsx","jsxs","styled","useState","useEffect","selectionWidth","styled","jsx","jsxs","styled","styled","jsx","jsxs","styled","StatusBadge","useState","useEffect","entries","jsx","jsxs","styled","useState","useMemo","jsx","jsxs","STORAGE_KEY","useState","styled","jsx","SubscriptionScope","useState","useEffect"]}
1
+ {"version":3,"sources":["../../src/inspector/index.tsx","../../src/inspector/in-app.tsx","../../src/inspector/viewer/inspector-button.tsx","../../src/inspector/viewer/use-open-inspector.ts","../../src/inspector/pages/performance/PerformancePage.tsx","../../src/inspector/pages/performance/Timeline.tsx","../../src/inspector/pages/performance/helpers.ts","../../src/inspector/pages/performance/SubscriptionRow.tsx","../../src/inspector/pages/performance/SubscriptionDetailPanel.tsx","../../src/inspector/pages/performance/usePerformanceEntries.ts"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { setup } from \"goober\";\nimport { useJazzContextValue } from \"jazz-tools/react-core\";\nimport { Account, SubscriptionScope } from \"jazz-tools\";\nimport { InspectorInApp } from \"./in-app.js\";\nimport { Position } from \"./viewer/inspector-button.js\";\n\nexport function enableProfiling() {\n SubscriptionScope.enableProfiling();\n}\n\nexport function JazzInspector({ position = \"right\" }: { position?: Position }) {\n const context = useJazzContextValue<Account>();\n const localNode = context.node;\n const me = \"me\" in context ? context.me : undefined;\n\n const [isCSR, setIsCSR] = useState(false);\n useEffect(() => {\n setIsCSR(true);\n }, []);\n\n if (!isCSR) {\n return null;\n }\n\n return (\n <InspectorInApp\n position={position}\n localNode={localNode}\n accountId={me?.$jazz.raw.id}\n showDeleteLocalData\n />\n );\n}\n\nsetup(React.createElement);\n","import { CoID, LocalNode, RawAccount } from \"cojson\";\nimport { styled } from \"goober\";\nimport { useCallback, useState } from \"react\";\nimport { PageStack } from \"./viewer/page-stack.js\";\nimport { GlobalStyles } from \"./ui/global-styles.js\";\nimport { InspectorButton, type Position } from \"./viewer/inspector-button.js\";\nimport { useOpenInspector } from \"./viewer/use-open-inspector.js\";\nimport { NodeProvider } from \"./contexts/node.js\";\nimport { InMemoryRouterProvider } from \"./router/in-memory-router.js\";\nimport { Header } from \"./viewer/header.js\";\nimport { PerformancePage } from \"./pages/performance/index.js\";\nimport { HomePage } from \"./pages/home.js\";\n\nexport type InspectorTab = \"inspector\" | \"performance\";\n\nconst STORAGE_KEY = \"jazz-inspector-tab\";\n\nfunction getStoredTab(): InspectorTab {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored === \"inspector\" || stored === \"performance\") {\n return stored;\n }\n } catch {\n // localStorage not available\n }\n return \"inspector\";\n}\n\nexport function InspectorInApp({\n position = \"right\",\n localNode,\n accountId,\n showDeleteLocalData = false,\n}: {\n position?: Position;\n localNode?: LocalNode;\n accountId?: CoID<RawAccount>;\n showDeleteLocalData?: boolean;\n}) {\n const [open, setOpen] = useOpenInspector();\n const [activeTab, setActiveTabState] = useState<InspectorTab>(getStoredTab);\n\n const setActiveTab = useCallback((tab: InspectorTab) => {\n setActiveTabState(tab);\n try {\n localStorage.setItem(STORAGE_KEY, tab);\n } catch {\n // localStorage not available\n }\n }, []);\n\n if (!open) {\n return (\n <InspectorButton position={position} onClick={() => setOpen(true)} />\n );\n }\n\n return (\n <NodeProvider localNode={localNode ?? null} accountID={accountId ?? null}>\n <InMemoryRouterProvider>\n <InspectorContainer as={GlobalStyles} style={{ zIndex: 999 }}>\n <Header\n showClose={true}\n onClose={() => setOpen(false)}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n />\n {/* Both components stay mounted, visibility controlled by CSS */}\n <PageStack\n style={{ display: activeTab === \"inspector\" ? \"flex\" : \"none\" }}\n homePage={<HomePage showDeleteLocalData={showDeleteLocalData} />}\n />\n <PerformancePage\n style={{ display: activeTab === \"performance\" ? \"flex\" : \"none\" }}\n onNavigate={() => setActiveTab(\"inspector\")}\n />\n </InspectorContainer>\n </InMemoryRouterProvider>\n </NodeProvider>\n );\n}\n\nconst InspectorContainer = styled(\"div\")`\n position: fixed;\n height: 50vh;\n max-height: 800px;\n display: flex;\n flex-direction: column;\n bottom: 0;\n left: 0;\n width: 100%;\n background-color: white;\n border-top: 1px solid var(--j-border-color);\n color: var(--j-text-color);\n\n @media (prefers-color-scheme: dark) {\n background-color: var(--j-background);\n }\n`;\n","import { styled } from \"goober\";\nimport React from \"react\";\n\nexport type Position =\n | \"bottom right\"\n | \"bottom left\"\n | \"top right\"\n | \"top left\"\n | \"right\"\n | \"left\";\n\nconst StyledInspectorButton = styled(\"button\")<{ position: Position }>`\n position: fixed;\n width: 2.5rem;\n height: 2.5rem;\n background-color: white;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n margin: 1rem;\n padding: 0.5rem !important;\n border: 1px solid #e5e3e4;\n border-radius: 0.375rem;\n z-index: 999;\n \n ${(props) => {\n switch (props.position) {\n case \"bottom right\":\n return \"bottom: 0; right: 0;\";\n case \"bottom left\":\n return \"bottom: 0; left: 0;\";\n case \"top right\":\n return \"top: 0; right: 0;\";\n case \"top left\":\n return \"top: 0; left: 0;\";\n case \"right\":\n return \"right: 0; top: 50%; transform: translateY(-50%);\";\n case \"left\":\n return \"left: 0; top: 50%; transform: translateY(-50%);\";\n default:\n return \"\";\n }\n }}\n`;\n\nconst JazzIcon = styled(\"svg\")`\n width: 100%;\n height: auto;\n position: relative;\n left: -1px;\n color: #146AFF;\n`;\n\nexport function InspectorButton({\n position = \"right\",\n ...buttonProps\n}: React.ComponentPropsWithoutRef<\"button\"> & { position?: Position }) {\n return (\n <StyledInspectorButton position={position} {...buttonProps}>\n <JazzIcon\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"119\"\n height=\"115\"\n viewBox=\"0 0 119 115\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M118.179 23.8277V0.167999C99.931 7.5527 79.9854 11.6192 59.0897 11.6192C47.1466 11.6192 35.5138 10.2908 24.331 7.7737V30.4076V60.1508C23.2955 59.4385 22.1568 58.8458 20.9405 58.3915C18.1732 57.358 15.128 57.0876 12.1902 57.6145C9.2524 58.1414 6.5539 59.4419 4.4358 61.3516C2.3178 63.2613 0.875401 65.6944 0.291001 68.3433C-0.293399 70.9921 0.00659978 73.7377 1.1528 76.2329C2.2991 78.728 4.2403 80.861 6.7308 82.361C9.2214 83.862 12.1495 84.662 15.1448 84.662C15.6054 84.662 15.8365 84.662 16.0314 84.659C26.5583 84.449 35.042 75.9656 35.2513 65.4386C35.2534 65.3306 35.2544 65.2116 35.2548 65.0486L35.2552 64.7149V64.5521V61.0762V32.1993C43.0533 33.2324 51.0092 33.7656 59.0897 33.7656C59.6696 33.7656 60.2489 33.7629 60.8276 33.7574V89.696C59.792 88.983 58.6533 88.391 57.437 87.936C54.6697 86.903 51.6246 86.632 48.6867 87.159C45.7489 87.686 43.0504 88.987 40.9323 90.896C38.8143 92.806 37.3719 95.239 36.7875 97.888C36.2032 100.537 36.5031 103.283 37.6494 105.778C38.7956 108.273 40.7368 110.405 43.2273 111.906C45.7179 113.406 48.646 114.207 51.6414 114.207C52.1024 114.207 52.3329 114.207 52.5279 114.203C63.0548 113.994 71.5385 105.51 71.7478 94.983C71.7517 94.788 71.7517 94.558 71.7517 94.097V90.621V33.3266C83.962 32.4768 95.837 30.4075 107.255 27.2397V59.9017C106.219 59.1894 105.081 58.5966 103.864 58.1424C101.097 57.1089 98.052 56.8384 95.114 57.3653C92.176 57.8922 89.478 59.1927 87.36 61.1025C85.242 63.0122 83.799 65.4453 83.215 68.0941C82.631 70.743 82.931 73.4886 84.077 75.9837C85.223 78.4789 87.164 80.612 89.655 82.112C92.145 83.612 95.073 84.413 98.069 84.413C98.53 84.413 98.76 84.413 98.955 84.409C109.482 84.2 117.966 75.7164 118.175 65.1895C118.179 64.9945 118.179 64.764 118.179 64.3029V60.8271V23.8277Z\"\n fill=\"currentColor\"\n />\n </JazzIcon>\n <span\n style={{\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n padding: \"0\",\n margin: \"-1px\",\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n border: \"0\",\n }}\n >\n Open Jazz Inspector\n </span>\n </StyledInspectorButton>\n );\n}\n","import { useEffect, useState } from \"react\";\n\nconst STORAGE_KEY = \"jazz-inspector-open\";\n\nexport function useOpenInspector() {\n const [open, setOpen] = useState(() => {\n // Initialize from localStorage if available\n if (typeof window === \"undefined\") return false;\n const stored = localStorage.getItem(STORAGE_KEY);\n return stored ? JSON.parse(stored) : false;\n });\n\n // Update localStorage when open state changes\n useEffect(() => {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(open));\n }, [open]);\n\n return [open, setOpen];\n}\n","import { styled } from \"goober\";\nimport { type CSSProperties, useMemo, useState, useDeferredValue } from \"react\";\nimport { CoID, RawCoValue } from \"cojson\";\nimport { useRouter } from \"../../router/context.js\";\nimport { Timeline } from \"./Timeline.js\";\nimport { SubscriptionRow } from \"./SubscriptionRow.js\";\nimport { SubscriptionDetailPanel } from \"./SubscriptionDetailPanel.js\";\nimport { usePerformanceEntries } from \"./usePerformanceEntries.js\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { SubscriptionScope } from \"jazz-tools\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst Container = styled(\"div\")`\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding: 1rem;\n height: 100%;\n min-height: 0;\n`;\n\nconst MainLayout = styled(\"div\")`\n display: flex;\n flex: 1;\n min-height: 0;\n gap: 1rem;\n`;\n\nconst ListPanel = styled(\"div\")`\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n`;\n\nconst Grid = styled(\"div\")`\n display: grid;\n grid-template-columns:\n minmax(100px, 150px)\n minmax(150px, 1fr)\n minmax(100px, 200px)\n 80px;\n grid-template-rows: min-content;\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n min-height: 0;\n position: relative;\n`;\n\nconst HeaderCell = styled(\"div\")`\n padding: 0.5rem;\n font-size: 0.625rem;\n font-weight: 600;\n color: var(--j-neutral-500);\n border-bottom: 1px solid var(--j-border-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n`;\n\nconst EmptyState = styled(\"div\")`\n text-align: center;\n padding: 2rem;\n color: var(--j-neutral-500);\n font-size: 0.875rem;\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface PerformancePageProps {\n onNavigate: () => void;\n style?: CSSProperties;\n}\n\nexport function PerformancePage({ onNavigate, style }: PerformancePageProps) {\n const entries = usePerformanceEntries();\n const [selectedRow, setSelectedRow] = useState<string | null>(null);\n const [timeSelection, setTimeSelection] = useState<[number, number] | null>(\n null,\n );\n const deferredSelection = useDeferredValue(timeSelection);\n const { setPage } = useRouter();\n\n const selectRow = (uuid: string) => {\n setSelectedRow((prev) => (prev === uuid ? null : uuid));\n };\n\n const sortedEntries = useMemo(() => {\n return [...entries].sort((a, b) => a.startTime - b.startTime);\n }, [entries]);\n\n const overallTimeRange = useMemo(() => {\n if (entries.length === 0) return null;\n const now = performance.now();\n return {\n min: Math.min(...entries.map((e) => e.startTime)),\n max: Math.max(...entries.map((e) => e.endTime ?? now)),\n };\n }, [entries]);\n\n const filteredEntries = useMemo(() => {\n if (!deferredSelection) return sortedEntries;\n const [startTime, endTime] = deferredSelection;\n const now = performance.now();\n return sortedEntries.filter((entry) => {\n const entryEnd = entry.endTime ?? now;\n // Entry overlaps with selection if it starts before selection ends and ends after selection starts\n return entry.startTime <= endTime && entryEnd >= startTime;\n });\n }, [sortedEntries, deferredSelection]);\n\n const displayRange = deferredSelection\n ? { min: deferredSelection[0], max: deferredSelection[1] }\n : overallTimeRange;\n\n // Calculate bar position for each entry\n const getBarProps = (entry: SubscriptionEntry) => {\n const range = (displayRange?.max ?? 1) - (displayRange?.min ?? 0) || 1;\n const now = performance.now();\n\n const clampedStart = Math.max(entry.startTime, displayRange?.min ?? 0);\n const clampedEnd = Math.min(entry.endTime ?? now, displayRange?.max ?? now);\n\n const left = Math.max(\n 0,\n ((clampedStart - (displayRange?.min ?? 0)) / range) * 100,\n );\n const width = Math.max(0, ((clampedEnd - clampedStart) / range) * 100);\n\n const color =\n entry.status === \"pending\"\n ? \"var(--j-warning-color)\"\n : entry.status === \"error\"\n ? \"var(--j-error-color)\"\n : \"var(--j-success-color)\";\n\n return {\n barLeft: `${left}%`,\n barWidth: width === 0 ? \"1px\" : `${width}%`,\n barColor: color,\n };\n };\n\n const handleNavigateToCoValue = (id: string) => {\n setPage(id as CoID<RawCoValue>);\n onNavigate();\n };\n\n if (!SubscriptionScope.isProfilingEnabled) {\n return (\n <Container style={style}>\n <EmptyState>Profiling is not enabled in production builds.</EmptyState>\n </Container>\n );\n }\n\n if (entries.length === 0) {\n return (\n <Container style={style}>\n <EmptyState>\n No subscriptions recorded yet. Interact with your app to see\n subscription performance data.\n </EmptyState>\n </Container>\n );\n }\n\n const selectedEntry = selectedRow\n ? filteredEntries.find((e) => e.uuid === selectedRow)\n : null;\n\n return (\n <Container style={style}>\n {overallTimeRange && (\n <Timeline\n entries={sortedEntries}\n timeRange={overallTimeRange}\n selection={timeSelection}\n onSelectionChange={setTimeSelection}\n />\n )}\n <MainLayout>\n <ListPanel>\n <Grid>\n <HeaderCell>Source</HeaderCell>\n <HeaderCell>CoValue</HeaderCell>\n <HeaderCell>Caller</HeaderCell>\n <HeaderCell>Duration</HeaderCell>\n {filteredEntries.map((entry) => (\n <SubscriptionRow\n key={entry.uuid}\n entry={entry}\n isSelected={selectedRow === entry.uuid}\n onSelect={() => selectRow(entry.uuid)}\n {...getBarProps(entry)}\n />\n ))}\n </Grid>\n </ListPanel>\n {selectedEntry && (\n <SubscriptionDetailPanel\n entry={selectedEntry}\n onNavigate={handleNavigateToCoValue}\n onClose={() => setSelectedRow(null)}\n />\n )}\n </MainLayout>\n </Container>\n );\n}\n","import { styled } from \"goober\";\nimport {\n type CSSProperties,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { formatDuration } from \"./helpers.js\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst TimelineContainer = styled(\"div\")`\n position: relative;\n display: flex;\n flex-direction: column;\n background-color: var(--j-foreground);\n border: 1px solid var(--j-border-color);\n border-radius: var(--j-radius-sm);\n overflow: hidden;\n`;\n\nconst TimelineTrack = styled(\"div\")`\n position: relative;\n height: 48px;\n background-color: var(--j-background);\n cursor: crosshair;\n user-select: none;\n`;\n\nconst TimeMarker = styled(\"div\")`\n position: absolute;\n font-size: 0.5rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--j-text-color);\n padding: 2px 4px;\n white-space: nowrap;\n\n @media (prefers-color-scheme: dark) {\n color: var(--j-neutral-500);\n }\n\n &::after {\n content: \"\";\n position: absolute;\n left: 0;\n top: 100%;\n width: 1px;\n height: 32px;\n background-color: var(--j-border-color);\n }\n`;\n\nconst TimelineBars = styled(\"div\")`\n position: absolute;\n top: 16px;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n`;\n\nconst TimelineBar = styled(\"div\")`\n position: absolute;\n border-radius: 1px;\n min-width: 2px;\n`;\n\nconst TimelineSelection = styled(\"div\")`\n position: absolute;\n top: 0;\n bottom: 0;\n background-color: var(--j-primary-color);\n opacity: 0.2;\n cursor: grab;\n pointer-events: auto;\n\n &:active {\n cursor: grabbing;\n }\n`;\n\nconst TimelineSelectionHandle = styled(\"div\")`\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background-color: var(--j-primary-color);\n cursor: ew-resize;\n pointer-events: auto;\n\n &::after {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 8px;\n height: 16px;\n background-color: var(--j-primary-color);\n border-radius: 2px;\n }\n`;\n\nconst ClearSelectionButton = styled(\"button\")`\n position: absolute;\n top: 4px;\n right: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n font-size: 0.5rem;\n background-color: var(--j-foreground);\n border: 1px solid var(--j-border-color);\n border-radius: var(--j-radius-sm);\n cursor: pointer;\n color: var(--j-neutral-500);\n z-index: 10;\n\n &:hover {\n background-color: var(--j-background);\n color: var(--j-text-color);\n }\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface TimelineProps {\n entries: SubscriptionEntry[];\n timeRange: { min: number; max: number };\n selection: [number, number] | null;\n onSelectionChange: (selection: [number, number] | null) => void;\n}\n\ntype DragMode = \"creating\" | \"moving\" | \"resizing-left\" | \"resizing-right\";\n\nexport function Timeline({\n entries,\n timeRange,\n selection,\n onSelectionChange,\n}: TimelineProps) {\n const trackRef = useRef<HTMLDivElement>(null);\n const [dragMode, setDragMode] = useState<DragMode | null>(null);\n const [dragStartTime, setDragStartTime] = useState<number | null>(null);\n const [dragCurrentTime, setDragCurrentTime] = useState<number | null>(null);\n const [dragInitialSelection, setDragInitialSelection] = useState<\n [number, number] | null\n >(null);\n\n const duration = timeRange.max - timeRange.min;\n\n // Generate time markers\n const timeMarkers = useMemo(() => {\n const markers: { time: number; label: string; position: number }[] = [];\n if (duration <= 0) return markers;\n\n const maxMarkers = 5;\n\n // Calculate minimum interval to have at most maxMarkers\n const minInterval = duration / maxMarkers;\n\n // Round up to a \"nice\" number (1, 2, 5, 10, 20, 50, 100, ...)\n const magnitude = Math.pow(10, Math.floor(Math.log10(minInterval)));\n const normalized = minInterval / magnitude;\n let niceMultiplier: number;\n if (normalized <= 1) niceMultiplier = 1;\n else if (normalized <= 2) niceMultiplier = 2;\n else if (normalized <= 5) niceMultiplier = 5;\n else niceMultiplier = 10;\n\n const interval = niceMultiplier * magnitude;\n\n const startMarker = Math.ceil(timeRange.min / interval) * interval;\n for (let time = startMarker; time <= timeRange.max; time += interval) {\n const position = ((time - timeRange.min) / duration) * 100;\n markers.push({\n time,\n label: formatDuration(time),\n position,\n });\n }\n return markers;\n }, [timeRange, duration]);\n\n const getTimeFromPosition = (clientX: number): number => {\n if (!trackRef.current) return 0;\n const rect = trackRef.current.getBoundingClientRect();\n const position = Math.max(\n 0,\n Math.min(1, (clientX - rect.left) / rect.width),\n );\n return timeRange.min + position * duration;\n };\n\n const handleTrackMouseDown = (e: React.MouseEvent) => {\n const time = getTimeFromPosition(e.clientX);\n setDragMode(\"creating\");\n setDragStartTime(time);\n setDragCurrentTime(time);\n };\n\n const handleSelectionMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selection) return;\n const time = getTimeFromPosition(e.clientX);\n setDragMode(\"moving\");\n setDragStartTime(time);\n setDragCurrentTime(time);\n setDragInitialSelection(selection);\n };\n\n const handleLeftHandleMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selection) return;\n setDragMode(\"resizing-left\");\n setDragStartTime(selection[0]);\n setDragCurrentTime(selection[0]);\n setDragInitialSelection(selection);\n };\n\n const handleRightHandleMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selection) return;\n setDragMode(\"resizing-right\");\n setDragStartTime(selection[1]);\n setDragCurrentTime(selection[1]);\n setDragInitialSelection(selection);\n };\n\n useEffect(() => {\n if (!dragMode) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const time = getTimeFromPosition(e.clientX);\n setDragCurrentTime(time);\n };\n\n const handleMouseUp = () => {\n if (\n dragMode === \"creating\" &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n const start = Math.min(dragStartTime, dragCurrentTime);\n const end = Math.max(dragStartTime, dragCurrentTime);\n if ((end - start) / duration > 0.01) {\n onSelectionChange([start, end]);\n }\n } else if (\n dragMode === \"moving\" &&\n dragInitialSelection &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n const delta = dragCurrentTime - dragStartTime;\n const selectionWidth =\n dragInitialSelection[1] - dragInitialSelection[0];\n let newStart = dragInitialSelection[0] + delta;\n let newEnd = dragInitialSelection[1] + delta;\n // Clamp to time range\n if (newStart < timeRange.min) {\n newStart = timeRange.min;\n newEnd = timeRange.min + selectionWidth;\n }\n if (newEnd > timeRange.max) {\n newEnd = timeRange.max;\n newStart = timeRange.max - selectionWidth;\n }\n onSelectionChange([newStart, newEnd]);\n } else if (\n dragMode === \"resizing-left\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newStart = Math.min(\n dragCurrentTime,\n dragInitialSelection[1] - duration * 0.01,\n );\n onSelectionChange([\n Math.max(timeRange.min, newStart),\n dragInitialSelection[1],\n ]);\n } else if (\n dragMode === \"resizing-right\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newEnd = Math.max(\n dragCurrentTime,\n dragInitialSelection[0] + duration * 0.01,\n );\n onSelectionChange([\n dragInitialSelection[0],\n Math.min(timeRange.max, newEnd),\n ]);\n }\n\n setDragMode(null);\n setDragStartTime(null);\n setDragCurrentTime(null);\n setDragInitialSelection(null);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [\n dragMode,\n dragStartTime,\n dragCurrentTime,\n dragInitialSelection,\n duration,\n timeRange,\n onSelectionChange,\n ]);\n\n // Pre-calculate lane assignments to avoid overlaps\n const laneAssignments = useMemo(() => {\n const now = performance.now();\n const barHeight = 3;\n const barGap = 1;\n const maxLanes = 8;\n\n // Sort entries by start time for lane assignment\n const sortedEntries = [...entries].sort(\n (a, b) => a.startTime - b.startTime,\n );\n\n // Track end times for each lane (up to maxLanes)\n const laneEndTimes: number[] = Array(maxLanes).fill(0);\n const assignments = new Map<string, number>();\n\n for (const entry of sortedEntries) {\n const entryEnd = entry.endTime ?? now;\n\n // Find the first lane where this entry fits (no overlap)\n let assignedLane = laneEndTimes.findIndex(\n (endTime) => entry.startTime >= endTime,\n );\n\n if (assignedLane === -1) {\n // All lanes are occupied, find the one that ends earliest\n const earliestEnd = Math.min(...laneEndTimes);\n assignedLane = laneEndTimes.indexOf(earliestEnd);\n }\n\n // Update the lane's end time\n laneEndTimes[assignedLane] = entryEnd;\n\n // Calculate top position\n assignments.set(entry.uuid, assignedLane * (barHeight + barGap));\n }\n\n return assignments;\n }, [entries]);\n\n const getBarStyle = (entry: SubscriptionEntry): CSSProperties => {\n const now = performance.now();\n const start = entry.startTime;\n const end = entry.endTime ?? now;\n const left = ((start - timeRange.min) / duration) * 100;\n const width = Math.max(0.5, ((end - start) / duration) * 100);\n\n const color =\n entry.status === \"pending\"\n ? \"var(--j-warning-color)\"\n : entry.status === \"error\"\n ? \"var(--j-error-color)\"\n : \"var(--j-success-color)\";\n\n const top = laneAssignments.get(entry.uuid) ?? 0;\n\n return {\n left: `${left}%`,\n width: `${width}%`,\n backgroundColor: color,\n top: `${top}px`,\n height: \"3px\",\n };\n };\n\n // Calculate current selection during drag\n const currentSelection = useMemo((): [number, number] | null => {\n if (\n dragMode === \"creating\" &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n return [\n Math.min(dragStartTime, dragCurrentTime),\n Math.max(dragStartTime, dragCurrentTime),\n ];\n }\n if (\n dragMode === \"moving\" &&\n dragInitialSelection &&\n dragStartTime !== null &&\n dragCurrentTime !== null\n ) {\n const delta = dragCurrentTime - dragStartTime;\n const selectionWidth = dragInitialSelection[1] - dragInitialSelection[0];\n let newStart = dragInitialSelection[0] + delta;\n let newEnd = dragInitialSelection[1] + delta;\n if (newStart < timeRange.min) {\n newStart = timeRange.min;\n newEnd = timeRange.min + selectionWidth;\n }\n if (newEnd > timeRange.max) {\n newEnd = timeRange.max;\n newStart = timeRange.max - selectionWidth;\n }\n return [newStart, newEnd];\n }\n if (\n dragMode === \"resizing-left\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newStart = Math.max(\n timeRange.min,\n Math.min(dragCurrentTime, dragInitialSelection[1] - duration * 0.01),\n );\n return [newStart, dragInitialSelection[1]];\n }\n if (\n dragMode === \"resizing-right\" &&\n dragInitialSelection &&\n dragCurrentTime !== null\n ) {\n const newEnd = Math.min(\n timeRange.max,\n Math.max(dragCurrentTime, dragInitialSelection[0] + duration * 0.01),\n );\n return [dragInitialSelection[0], newEnd];\n }\n return selection;\n }, [\n dragMode,\n dragStartTime,\n dragCurrentTime,\n dragInitialSelection,\n selection,\n timeRange,\n duration,\n ]);\n\n const selectionLeft = currentSelection\n ? ((currentSelection[0] - timeRange.min) / duration) * 100\n : 0;\n const selectionWidth = currentSelection\n ? ((currentSelection[1] - currentSelection[0]) / duration) * 100\n : 0;\n\n return (\n <TimelineContainer>\n <TimelineTrack ref={trackRef} onMouseDown={handleTrackMouseDown}>\n {timeMarkers.map((marker) => (\n <TimeMarker key={marker.time} style={{ left: `${marker.position}%` }}>\n {marker.label}\n </TimeMarker>\n ))}\n <TimelineBars>\n {entries.map((entry) => (\n <TimelineBar key={entry.uuid} style={getBarStyle(entry)} />\n ))}\n </TimelineBars>\n {currentSelection && (\n <>\n <TimelineSelection\n style={{\n left: `${selectionLeft}%`,\n width: `${selectionWidth}%`,\n }}\n onMouseDown={handleSelectionMouseDown}\n />\n {!dragMode && (\n <>\n <TimelineSelectionHandle\n style={{ left: `${selectionLeft}%` }}\n onMouseDown={handleLeftHandleMouseDown}\n />\n <TimelineSelectionHandle\n style={{ left: `${selectionLeft + selectionWidth}%` }}\n onMouseDown={handleRightHandleMouseDown}\n />\n </>\n )}\n </>\n )}\n </TimelineTrack>\n {currentSelection && !dragMode && (\n <ClearSelectionButton\n onClick={(e) => {\n e.stopPropagation();\n onSelectionChange(null);\n }}\n >\n Clear selection\n </ClearSelectionButton>\n )}\n </TimelineContainer>\n );\n}\n","export function formatTime(startTime: number): string {\n const date = new Date(performance.timeOrigin + startTime);\n return date.toLocaleTimeString(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n fractionalSecondDigits: 3,\n });\n}\n\nexport function formatDuration(duration: number): string {\n if (duration < 1) {\n return `${(duration * 1000).toFixed(0)}μs`;\n }\n if (duration < 1000) {\n return `${duration.toFixed(2)}ms`;\n }\n return `${(duration / 1000).toFixed(2)}s`;\n}\n\nexport function getCallerLocation(\n stack: string | undefined,\n): string | undefined {\n if (!stack) return undefined;\n\n const lines = stack.split(\"\\n\").slice(2, 15);\n\n const normalizeLine = (line: string) =>\n line.replace(/https?:\\/\\/[^/\\s)]+/g, \"\");\n\n const userFrame = lines.find(\n (line) =>\n !line.includes(\"node_modules\") &&\n !line.includes(\"useCoValueSubscription\") &&\n !line.includes(\"useCoState\") &&\n !line.includes(\"useAccount\") &&\n !line.includes(\"useSuspenseCoState\") &&\n !line.includes(\"useSuspenseAccount\") &&\n !line.includes(\"jazz-tools\") &&\n !line.includes(\"trackLoadingPerformance\"),\n );\n\n if (userFrame) {\n const cleanedFrame = normalizeLine(userFrame).trim();\n const match = cleanedFrame.match(/\\(?([^)]+:\\d+:\\d+)\\)?$/);\n if (match) {\n return match[1];\n }\n return cleanedFrame;\n }\n\n return lines[0] ? normalizeLine(lines[0]).trim() : undefined;\n}\n\nexport function getCallerStack(stack: string | undefined): string | undefined {\n if (!stack) return undefined;\n\n const lines = stack.split(\"\\n\").slice(2, 15);\n\n return lines\n .filter(\n (line) =>\n !line.includes(\"Error:\") &&\n !line.includes(\"renderWithHooks\") &&\n !line.includes(\"react-stack-bottom-frame\"),\n )\n .map((line) => line.replace(/https?:\\/\\/[^/\\s)]+/g, \"\").trim())\n .reverse()\n .join(\"\\n\");\n}\n","import { styled } from \"goober\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { formatDuration, getCallerLocation } from \"./helpers.js\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst RowWrapper = styled(\"div\")`\n display: grid;\n grid-template-columns: subgrid;\n grid-column: 1 / -1;\n position: relative;\n cursor: pointer;\n\n &:hover,\n &:focus {\n background-color: var(--j-foreground);\n outline: none;\n }\n\n &:focus-visible {\n outline: 2px solid var(--j-primary-color);\n outline-offset: -2px;\n }\n\n &[data-expanded=\"true\"] {\n background-color: var(--j-foreground);\n }\n`;\n\nconst TimeBar = styled(\"div\")`\n position: absolute;\n bottom: 0;\n height: 4px;\n transition: transform 0.15s ease;\n z-index: 1;\n container-type: inline-size;\n\n .row-wrapper:hover &, [data-expanded=\"true\"] & {\n transform: scaleY(4);\n\n .time-label {\n opacity: 1;\n }\n }\n\n &[data-status=\"pending\"] {\n animation: pulse 1.5s ease-in-out infinite;\n }\n\n @keyframes pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n }\n`;\n\nconst TimeLabel = styled(\"span\")`\n position: absolute;\n top: 50%;\n transform: translateY(-50%) scaleY(0.25);\n font-size: 0.5rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: white;\n white-space: nowrap;\n opacity: 0;\n transition: opacity 0.15s ease;\n pointer-events: none;\n left: 4px;\n --time-label-overflow-color: black;\n\n @media (prefers-color-scheme: dark) {\n --time-label-overflow-color: white;\n }\n\n @container (max-width: 50px) {\n color: var(--time-label-overflow-color);\n left: 100%;\n margin-left: 4px;\n }\n\n [data-near-edge=\"true\"] & {\n @container (max-width: 50px) {\n left: auto;\n right: 100%;\n margin-left: 0;\n margin-right: 4px;\n }\n }\n`;\n\nconst Cell = styled(\"div\")`\n padding: 0.5rem;\n padding-bottom: 0.75rem;\n font-size: 0.625rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n border-bottom: 1px solid var(--j-border-color);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &[data-clickable=\"true\"] {\n cursor: pointer;\n color: var(--j-link-color);\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\nconst StatusBadge = styled(\"span\")`\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n font-size: 0.625rem;\n\n &[data-status=\"pending\"] {\n background-color: var(--j-warning-bg);\n color: var(--j-warning-color);\n }\n &[data-status=\"loaded\"] {\n background-color: var(--j-success-bg);\n color: var(--j-success-color);\n }\n &[data-status=\"error\"] {\n background-color: var(--j-error-bg);\n color: var(--j-error-color);\n }\n`;\n\nconst PendingDot = styled(\"span\")`\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background-color: var(--j-warning-color);\n animation: pendingPulse 1.5s ease-in-out infinite;\n\n @keyframes pendingPulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n }\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface SubscriptionRowProps {\n entry: SubscriptionEntry;\n isSelected: boolean;\n onSelect: () => void;\n barLeft: string;\n barWidth: string;\n barColor: string;\n}\n\nexport function SubscriptionRow({\n entry,\n isSelected,\n onSelect,\n barLeft,\n barWidth,\n barColor,\n}: SubscriptionRowProps) {\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect();\n }\n };\n\n return (\n <RowWrapper\n className=\"row-wrapper\"\n data-expanded={isSelected}\n onClick={onSelect}\n onKeyDown={handleKeyDown}\n tabIndex={0}\n role=\"button\"\n aria-label={`View details for ${entry.source} ${entry.id}`}\n >\n <Cell>\n <StatusBadge data-status={entry.status}>{entry.source}</StatusBadge>\n </Cell>\n <Cell>\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"0.125rem\",\n }}\n >\n <span>{entry.id}</span>\n <span style={{ color: \"var(--j-neutral-500)\" }}>{entry.resolve}</span>\n </div>\n </Cell>\n <Cell>{getCallerLocation(entry.callerStack) ?? \"-\"}</Cell>\n <Cell>\n {entry.duration !== undefined ? (\n entry.duration === 0 ? (\n \"⚡ cached\"\n ) : (\n formatDuration(entry.duration)\n )\n ) : (\n <PendingDot />\n )}\n </Cell>\n <TimeBar\n className=\"time-bar\"\n data-status={entry.status}\n data-near-edge={parseFloat(barLeft) + parseFloat(barWidth) > 85}\n style={{\n left: barLeft,\n width: barWidth,\n backgroundColor: barColor,\n }}\n >\n <TimeLabel className=\"time-label\">\n {entry.duration === 0\n ? \"⚡ cached\"\n : entry.duration\n ? formatDuration(entry.duration)\n : \"-\"}\n </TimeLabel>\n </TimeBar>\n </RowWrapper>\n );\n}\n","import { styled } from \"goober\";\nimport type { SubscriptionEntry } from \"./types.js\";\nimport { formatTime, formatDuration, getCallerStack } from \"./helpers.js\";\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\nconst DetailPanel = styled(\"div\")`\n width: 320px;\n flex-shrink: 0;\n padding: 0.75rem 1rem;\n background-color: var(--j-foreground);\n border: 1px solid var(--j-border-color);\n border-radius: var(--j-radius-sm);\n overflow-y: auto;\n position: relative;\n`;\n\nconst CloseButton = styled(\"button\")`\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n background: none;\n border: none;\n border-radius: var(--j-radius-sm);\n cursor: pointer;\n color: var(--j-neutral-500);\n\n &:hover {\n background-color: var(--j-background);\n color: var(--j-text-color);\n }\n\n &:focus-visible {\n outline: 2px solid var(--j-primary-color);\n outline-offset: -2px;\n }\n`;\n\nconst DetailsGrid = styled(\"div\")`\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 0.5rem 1rem;\n font-size: 0.625rem;\n`;\n\nconst DetailLabel = styled(\"span\")`\n color: var(--j-neutral-500);\n font-weight: 500;\n`;\n\nconst DetailValue = styled(\"span\")`\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--j-text-color);\n`;\n\nconst Pre = styled(\"pre\")`\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.625rem;\n color: var(--j-text-color);\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 200px;\n overflow-y: auto;\n background-color: var(--j-background);\n padding: 0.5rem;\n border-radius: var(--j-radius-sm);\n`;\n\nconst StatusBadge = styled(\"span\")`\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n font-size: 0.625rem;\n\n &[data-status=\"pending\"] {\n background-color: var(--j-warning-bg);\n color: var(--j-warning-color);\n }\n &[data-status=\"loaded\"] {\n background-color: var(--j-success-bg);\n color: var(--j-success-color);\n }\n &[data-status=\"error\"] {\n background-color: var(--j-error-bg);\n color: var(--j-error-color);\n }\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface SubscriptionDetailPanelProps {\n entry: SubscriptionEntry;\n onNavigate: (id: string) => void;\n onClose: () => void;\n}\n\nexport function SubscriptionDetailPanel({\n entry,\n onNavigate,\n onClose,\n}: SubscriptionDetailPanelProps) {\n return (\n <DetailPanel>\n <CloseButton onClick={onClose} aria-label=\"Close detail panel\">\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </CloseButton>\n <DetailsGrid>\n <DetailLabel>Source</DetailLabel>\n <DetailValue>\n <StatusBadge data-status={entry.status}>{entry.source}</StatusBadge>\n </DetailValue>\n\n <DetailLabel>CoValue</DetailLabel>\n <DetailValue>\n <button\n title=\"Click to navigate to CoValue\"\n onClick={() => onNavigate(entry.id)}\n style={{\n color: \"var(--j-link-color)\",\n cursor: \"pointer\",\n background: \"none\",\n border: \"none\",\n padding: 0,\n font: \"inherit\",\n }}\n >\n {entry.id}\n </button>\n </DetailValue>\n\n <DetailLabel>Time</DetailLabel>\n <DetailValue>\n {formatTime(entry.startTime)} -{\" \"}\n {entry.duration !== undefined\n ? formatTime(entry.startTime + entry.duration)\n : \"Pending...\"}\n </DetailValue>\n\n <DetailLabel>Duration</DetailLabel>\n <DetailValue>\n {entry.duration !== undefined\n ? formatDuration(entry.duration)\n : \"Pending...\"}\n </DetailValue>\n\n <DetailLabel>Resolve Query</DetailLabel>\n <Pre>{JSON.stringify(JSON.parse(entry.resolve), null, 2)}</Pre>\n\n <DetailLabel>Stack Trace</DetailLabel>\n <Pre>\n {getCallerStack(entry.callerStack) ?? \"No stack trace available\"}\n </Pre>\n </DetailsGrid>\n </DetailPanel>\n );\n}\n","import { useState, useEffect } from \"react\";\nimport { SubscriptionPerformanceDetail } from \"jazz-tools\";\nimport type { SubscriptionEntry } from \"./types.js\";\n\nexport function usePerformanceEntries(): SubscriptionEntry[] {\n const [entries, setEntries] = useState<SubscriptionEntry[]>([]);\n\n useEffect(() => {\n const entriesByUuid = new Map<string, SubscriptionEntry>();\n\n const handlePerformanceEntries = (entries: PerformanceEntry[]) => {\n for (const mark of entries) {\n const detail = (mark as PerformanceMark)\n .detail as SubscriptionPerformanceDetail;\n\n if (detail?.type !== \"jazz-subscription\") continue;\n\n const prevEntry = entriesByUuid.get(detail.uuid);\n\n if (mark.entryType === \"mark\" && prevEntry) continue;\n\n entriesByUuid.set(detail.uuid, {\n uuid: detail.uuid,\n id: detail.id,\n source: detail.source,\n resolve: JSON.stringify(detail.resolve),\n status: detail.status,\n startTime: mark.startTime,\n callerStack: detail.callerStack ?? prevEntry?.callerStack,\n duration: mark.entryType === \"mark\" ? undefined : mark.duration,\n endTime: mark.startTime + mark.duration,\n errorType: detail.errorType,\n });\n }\n };\n\n handlePerformanceEntries(performance.getEntriesByType(\"mark\"));\n handlePerformanceEntries(performance.getEntriesByType(\"measure\"));\n\n setEntries(Array.from(entriesByUuid.values()));\n\n const observer = new PerformanceObserver((list) => {\n handlePerformanceEntries(list.getEntries());\n setEntries(Array.from(entriesByUuid.values()));\n });\n\n observer.observe({ entryTypes: [\"mark\", \"measure\"] });\n\n return () => observer.disconnect();\n }, []);\n\n return entries;\n}\n"],"mappings":";;;;;;;;;;;;AAAA,OAAO,SAAS,aAAAA,YAAW,YAAAC,iBAAgB;AAC3C,SAAS,aAAa;AACtB,SAAS,2BAA2B;AACpC,SAAkB,qBAAAC,0BAAyB;;;ACF3C,SAAS,UAAAC,eAAc;AACvB,SAAS,aAAa,YAAAC,iBAAgB;;;ACFtC,SAAS,cAAc;AAwDnB,SAQI,KARJ;AA7CJ,IAAM,wBAAwB,OAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYzC,CAAC,UAAU;AACX,UAAQ,MAAM,UAAU;AAAA,IACtB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF,CAAC;AAAA;AAGH,IAAM,WAAW,OAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQtB,SAAS,gBAAgB;AAAA,EAC9B,WAAW;AAAA,EACX,GAAG;AACL,GAAuE;AACrE,SACE,qBAAC,yBAAsB,UAAqB,GAAG,aAC7C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAM;AAAA,QACN,QAAO;AAAA,QACP,SAAQ;AAAA,QACR,MAAK;AAAA,QAEL;AAAA,UAAC;AAAA;AAAA,YACC,UAAS;AAAA,YACT,UAAS;AAAA,YACT,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,QAAQ;AAAA,QACV;AAAA,QACD;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;;;ACxFA,SAAS,WAAW,gBAAgB;AAEpC,IAAM,cAAc;AAEb,SAAS,mBAAmB;AACjC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM;AAErC,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,UAAM,SAAS,aAAa,QAAQ,WAAW;AAC/C,WAAO,SAAS,KAAK,MAAM,MAAM,IAAI;AAAA,EACvC,CAAC;AAGD,YAAU,MAAM;AACd,iBAAa,QAAQ,aAAa,KAAK,UAAU,IAAI,CAAC;AAAA,EACxD,GAAG,CAAC,IAAI,CAAC;AAET,SAAO,CAAC,MAAM,OAAO;AACvB;;;AClBA,SAAS,UAAAC,eAAc;AACvB,SAA6B,WAAAC,UAAS,YAAAC,WAAU,wBAAwB;;;ACDxE,SAAS,UAAAC,eAAc;AACvB;AAAA,EAEE,aAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAAC;AAAA,OACK;;;ACPA,SAAS,WAAW,WAA2B;AACpD,QAAM,OAAO,IAAI,KAAK,YAAY,aAAa,SAAS;AACxD,SAAO,KAAK,mBAAmB,QAAW;AAAA,IACxC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,wBAAwB;AAAA,EAC1B,CAAC;AACH;AAEO,SAAS,eAAe,UAA0B;AACvD,MAAI,WAAW,GAAG;AAChB,WAAO,IAAI,WAAW,KAAM,QAAQ,CAAC,CAAC;AAAA,EACxC;AACA,MAAI,WAAW,KAAM;AACnB,WAAO,GAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,EAC/B;AACA,SAAO,IAAI,WAAW,KAAM,QAAQ,CAAC,CAAC;AACxC;AAEO,SAAS,kBACd,OACoB;AACpB,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAQ,MAAM,MAAM,IAAI,EAAE,MAAM,GAAG,EAAE;AAE3C,QAAM,gBAAgB,CAAC,SACrB,KAAK,QAAQ,wBAAwB,EAAE;AAEzC,QAAM,YAAY,MAAM;AAAA,IACtB,CAAC,SACC,CAAC,KAAK,SAAS,cAAc,KAC7B,CAAC,KAAK,SAAS,wBAAwB,KACvC,CAAC,KAAK,SAAS,YAAY,KAC3B,CAAC,KAAK,SAAS,YAAY,KAC3B,CAAC,KAAK,SAAS,oBAAoB,KACnC,CAAC,KAAK,SAAS,oBAAoB,KACnC,CAAC,KAAK,SAAS,YAAY,KAC3B,CAAC,KAAK,SAAS,yBAAyB;AAAA,EAC5C;AAEA,MAAI,WAAW;AACb,UAAM,eAAe,cAAc,SAAS,EAAE,KAAK;AACnD,UAAM,QAAQ,aAAa,MAAM,wBAAwB;AACzD,QAAI,OAAO;AACT,aAAO,MAAM,CAAC;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,CAAC,IAAI,cAAc,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI;AACrD;AAEO,SAAS,eAAe,OAA+C;AAC5E,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAQ,MAAM,MAAM,IAAI,EAAE,MAAM,GAAG,EAAE;AAE3C,SAAO,MACJ;AAAA,IACC,CAAC,SACC,CAAC,KAAK,SAAS,QAAQ,KACvB,CAAC,KAAK,SAAS,iBAAiB,KAChC,CAAC,KAAK,SAAS,0BAA0B;AAAA,EAC7C,EACC,IAAI,CAAC,SAAS,KAAK,QAAQ,wBAAwB,EAAE,EAAE,KAAK,CAAC,EAC7D,QAAQ,EACR,KAAK,IAAI;AACd;;;AD8YU,SAmBI,UAnBJ,OAAAC,MAmBI,QAAAC,aAnBJ;AApcV,IAAM,oBAAoBC,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUtC,IAAM,gBAAgBA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQlC,IAAM,aAAaA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuB/B,IAAM,eAAeA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASjC,IAAM,cAAcA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAMhC,IAAM,oBAAoBA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AActC,IAAM,0BAA0BA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsB5C,IAAM,uBAAuBA,QAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCrC,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,WAAW,OAAuB,IAAI;AAC5C,QAAM,CAAC,UAAU,WAAW,IAAIC,UAA0B,IAAI;AAC9D,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAAwB,IAAI;AACtE,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAwB,IAAI;AAC1E,QAAM,CAAC,sBAAsB,uBAAuB,IAAIA,UAEtD,IAAI;AAEN,QAAM,WAAW,UAAU,MAAM,UAAU;AAG3C,QAAM,cAAc,QAAQ,MAAM;AAChC,UAAM,UAA+D,CAAC;AACtE,QAAI,YAAY,EAAG,QAAO;AAE1B,UAAM,aAAa;AAGnB,UAAM,cAAc,WAAW;AAG/B,UAAM,YAAY,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,MAAM,WAAW,CAAC,CAAC;AAClE,UAAM,aAAa,cAAc;AACjC,QAAI;AACJ,QAAI,cAAc,EAAG,kBAAiB;AAAA,aAC7B,cAAc,EAAG,kBAAiB;AAAA,aAClC,cAAc,EAAG,kBAAiB;AAAA,QACtC,kBAAiB;AAEtB,UAAM,WAAW,iBAAiB;AAElC,UAAM,cAAc,KAAK,KAAK,UAAU,MAAM,QAAQ,IAAI;AAC1D,aAAS,OAAO,aAAa,QAAQ,UAAU,KAAK,QAAQ,UAAU;AACpE,YAAM,YAAa,OAAO,UAAU,OAAO,WAAY;AACvD,cAAQ,KAAK;AAAA,QACX;AAAA,QACA,OAAO,eAAe,IAAI;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT,GAAG,CAAC,WAAW,QAAQ,CAAC;AAExB,QAAM,sBAAsB,CAAC,YAA4B;AACvD,QAAI,CAAC,SAAS,QAAS,QAAO;AAC9B,UAAM,OAAO,SAAS,QAAQ,sBAAsB;AACpD,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA,KAAK,IAAI,IAAI,UAAU,KAAK,QAAQ,KAAK,KAAK;AAAA,IAChD;AACA,WAAO,UAAU,MAAM,WAAW;AAAA,EACpC;AAEA,QAAM,uBAAuB,CAAC,MAAwB;AACpD,UAAM,OAAO,oBAAoB,EAAE,OAAO;AAC1C,gBAAY,UAAU;AACtB,qBAAiB,IAAI;AACrB,uBAAmB,IAAI;AAAA,EACzB;AAEA,QAAM,2BAA2B,CAAC,MAAwB;AACxD,MAAE,gBAAgB;AAClB,QAAI,CAAC,UAAW;AAChB,UAAM,OAAO,oBAAoB,EAAE,OAAO;AAC1C,gBAAY,QAAQ;AACpB,qBAAiB,IAAI;AACrB,uBAAmB,IAAI;AACvB,4BAAwB,SAAS;AAAA,EACnC;AAEA,QAAM,4BAA4B,CAAC,MAAwB;AACzD,MAAE,gBAAgB;AAClB,QAAI,CAAC,UAAW;AAChB,gBAAY,eAAe;AAC3B,qBAAiB,UAAU,CAAC,CAAC;AAC7B,uBAAmB,UAAU,CAAC,CAAC;AAC/B,4BAAwB,SAAS;AAAA,EACnC;AAEA,QAAM,6BAA6B,CAAC,MAAwB;AAC1D,MAAE,gBAAgB;AAClB,QAAI,CAAC,UAAW;AAChB,gBAAY,gBAAgB;AAC5B,qBAAiB,UAAU,CAAC,CAAC;AAC7B,uBAAmB,UAAU,CAAC,CAAC;AAC/B,4BAAwB,SAAS;AAAA,EACnC;AAEA,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,kBAAkB,CAAC,MAAkB;AACzC,YAAM,OAAO,oBAAoB,EAAE,OAAO;AAC1C,yBAAmB,IAAI;AAAA,IACzB;AAEA,UAAM,gBAAgB,MAAM;AAC1B,UACE,aAAa,cACb,kBAAkB,QAClB,oBAAoB,MACpB;AACA,cAAM,QAAQ,KAAK,IAAI,eAAe,eAAe;AACrD,cAAM,MAAM,KAAK,IAAI,eAAe,eAAe;AACnD,aAAK,MAAM,SAAS,WAAW,MAAM;AACnC,4BAAkB,CAAC,OAAO,GAAG,CAAC;AAAA,QAChC;AAAA,MACF,WACE,aAAa,YACb,wBACA,kBAAkB,QAClB,oBAAoB,MACpB;AACA,cAAM,QAAQ,kBAAkB;AAChC,cAAMC,kBACJ,qBAAqB,CAAC,IAAI,qBAAqB,CAAC;AAClD,YAAI,WAAW,qBAAqB,CAAC,IAAI;AACzC,YAAI,SAAS,qBAAqB,CAAC,IAAI;AAEvC,YAAI,WAAW,UAAU,KAAK;AAC5B,qBAAW,UAAU;AACrB,mBAAS,UAAU,MAAMA;AAAA,QAC3B;AACA,YAAI,SAAS,UAAU,KAAK;AAC1B,mBAAS,UAAU;AACnB,qBAAW,UAAU,MAAMA;AAAA,QAC7B;AACA,0BAAkB,CAAC,UAAU,MAAM,CAAC;AAAA,MACtC,WACE,aAAa,mBACb,wBACA,oBAAoB,MACpB;AACA,cAAM,WAAW,KAAK;AAAA,UACpB;AAAA,UACA,qBAAqB,CAAC,IAAI,WAAW;AAAA,QACvC;AACA,0BAAkB;AAAA,UAChB,KAAK,IAAI,UAAU,KAAK,QAAQ;AAAA,UAChC,qBAAqB,CAAC;AAAA,QACxB,CAAC;AAAA,MACH,WACE,aAAa,oBACb,wBACA,oBAAoB,MACpB;AACA,cAAM,SAAS,KAAK;AAAA,UAClB;AAAA,UACA,qBAAqB,CAAC,IAAI,WAAW;AAAA,QACvC;AACA,0BAAkB;AAAA,UAChB,qBAAqB,CAAC;AAAA,UACtB,KAAK,IAAI,UAAU,KAAK,MAAM;AAAA,QAChC,CAAC;AAAA,MACH;AAEA,kBAAY,IAAI;AAChB,uBAAiB,IAAI;AACrB,yBAAmB,IAAI;AACvB,8BAAwB,IAAI;AAAA,IAC9B;AAEA,WAAO,iBAAiB,aAAa,eAAe;AACpD,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM;AACX,aAAO,oBAAoB,aAAa,eAAe;AACvD,aAAO,oBAAoB,WAAW,aAAa;AAAA,IACrD;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,QAAM,kBAAkB,QAAQ,MAAM;AACpC,UAAM,MAAM,YAAY,IAAI;AAC5B,UAAM,YAAY;AAClB,UAAM,SAAS;AACf,UAAM,WAAW;AAGjB,UAAM,gBAAgB,CAAC,GAAG,OAAO,EAAE;AAAA,MACjC,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE;AAAA,IAC5B;AAGA,UAAM,eAAyB,MAAM,QAAQ,EAAE,KAAK,CAAC;AACrD,UAAM,cAAc,oBAAI,IAAoB;AAE5C,eAAW,SAAS,eAAe;AACjC,YAAM,WAAW,MAAM,WAAW;AAGlC,UAAI,eAAe,aAAa;AAAA,QAC9B,CAAC,YAAY,MAAM,aAAa;AAAA,MAClC;AAEA,UAAI,iBAAiB,IAAI;AAEvB,cAAM,cAAc,KAAK,IAAI,GAAG,YAAY;AAC5C,uBAAe,aAAa,QAAQ,WAAW;AAAA,MACjD;AAGA,mBAAa,YAAY,IAAI;AAG7B,kBAAY,IAAI,MAAM,MAAM,gBAAgB,YAAY,OAAO;AAAA,IACjE;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,cAAc,CAAC,UAA4C;AAC/D,UAAM,MAAM,YAAY,IAAI;AAC5B,UAAM,QAAQ,MAAM;AACpB,UAAM,MAAM,MAAM,WAAW;AAC7B,UAAM,QAAS,QAAQ,UAAU,OAAO,WAAY;AACpD,UAAM,QAAQ,KAAK,IAAI,MAAO,MAAM,SAAS,WAAY,GAAG;AAE5D,UAAM,QACJ,MAAM,WAAW,YACb,2BACA,MAAM,WAAW,UACf,yBACA;AAER,UAAM,MAAM,gBAAgB,IAAI,MAAM,IAAI,KAAK;AAE/C,WAAO;AAAA,MACL,MAAM,GAAG,IAAI;AAAA,MACb,OAAO,GAAG,KAAK;AAAA,MACf,iBAAiB;AAAA,MACjB,KAAK,GAAG,GAAG;AAAA,MACX,QAAQ;AAAA,IACV;AAAA,EACF;AAGA,QAAM,mBAAmB,QAAQ,MAA+B;AAC9D,QACE,aAAa,cACb,kBAAkB,QAClB,oBAAoB,MACpB;AACA,aAAO;AAAA,QACL,KAAK,IAAI,eAAe,eAAe;AAAA,QACvC,KAAK,IAAI,eAAe,eAAe;AAAA,MACzC;AAAA,IACF;AACA,QACE,aAAa,YACb,wBACA,kBAAkB,QAClB,oBAAoB,MACpB;AACA,YAAM,QAAQ,kBAAkB;AAChC,YAAMA,kBAAiB,qBAAqB,CAAC,IAAI,qBAAqB,CAAC;AACvE,UAAI,WAAW,qBAAqB,CAAC,IAAI;AACzC,UAAI,SAAS,qBAAqB,CAAC,IAAI;AACvC,UAAI,WAAW,UAAU,KAAK;AAC5B,mBAAW,UAAU;AACrB,iBAAS,UAAU,MAAMA;AAAA,MAC3B;AACA,UAAI,SAAS,UAAU,KAAK;AAC1B,iBAAS,UAAU;AACnB,mBAAW,UAAU,MAAMA;AAAA,MAC7B;AACA,aAAO,CAAC,UAAU,MAAM;AAAA,IAC1B;AACA,QACE,aAAa,mBACb,wBACA,oBAAoB,MACpB;AACA,YAAM,WAAW,KAAK;AAAA,QACpB,UAAU;AAAA,QACV,KAAK,IAAI,iBAAiB,qBAAqB,CAAC,IAAI,WAAW,IAAI;AAAA,MACrE;AACA,aAAO,CAAC,UAAU,qBAAqB,CAAC,CAAC;AAAA,IAC3C;AACA,QACE,aAAa,oBACb,wBACA,oBAAoB,MACpB;AACA,YAAM,SAAS,KAAK;AAAA,QAClB,UAAU;AAAA,QACV,KAAK,IAAI,iBAAiB,qBAAqB,CAAC,IAAI,WAAW,IAAI;AAAA,MACrE;AACA,aAAO,CAAC,qBAAqB,CAAC,GAAG,MAAM;AAAA,IACzC;AACA,WAAO;AAAA,EACT,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,oBAChB,iBAAiB,CAAC,IAAI,UAAU,OAAO,WAAY,MACrD;AACJ,QAAM,iBAAiB,oBACjB,iBAAiB,CAAC,IAAI,iBAAiB,CAAC,KAAK,WAAY,MAC3D;AAEJ,SACE,gBAAAJ,MAAC,qBACC;AAAA,oBAAAA,MAAC,iBAAc,KAAK,UAAU,aAAa,sBACxC;AAAA,kBAAY,IAAI,CAAC,WAChB,gBAAAD,KAAC,cAA6B,OAAO,EAAE,MAAM,GAAG,OAAO,QAAQ,IAAI,GAChE,iBAAO,SADO,OAAO,IAExB,CACD;AAAA,MACD,gBAAAA,KAAC,gBACE,kBAAQ,IAAI,CAAC,UACZ,gBAAAA,KAAC,eAA6B,OAAO,YAAY,KAAK,KAApC,MAAM,IAAiC,CAC1D,GACH;AAAA,MACC,oBACC,gBAAAC,MAAA,YACE;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,MAAM,GAAG,aAAa;AAAA,cACtB,OAAO,GAAG,cAAc;AAAA,YAC1B;AAAA,YACA,aAAa;AAAA;AAAA,QACf;AAAA,QACC,CAAC,YACA,gBAAAC,MAAA,YACE;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,EAAE,MAAM,GAAG,aAAa,IAAI;AAAA,cACnC,aAAa;AAAA;AAAA,UACf;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,EAAE,MAAM,GAAG,gBAAgB,cAAc,IAAI;AAAA,cACpD,aAAa;AAAA;AAAA,UACf;AAAA,WACF;AAAA,SAEJ;AAAA,OAEJ;AAAA,IACC,oBAAoB,CAAC,YACpB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,CAAC,MAAM;AACd,YAAE,gBAAgB;AAClB,4BAAkB,IAAI;AAAA,QACxB;AAAA,QACD;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;;;AEhgBA,SAAS,UAAAM,eAAc;AAmMf,gBAAAC,MAGA,QAAAC,aAHA;AA3LR,IAAM,aAAaC,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuB/B,IAAM,UAAUA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+B5B,IAAM,YAAYA,QAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkC/B,IAAM,OAAOA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBzB,IAAM,cAAcA,QAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBjC,IAAM,aAAaA,QAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCzB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,gBAAgB,CAAC,MAA2B;AAChD,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,eAAe;AACjB,eAAS;AAAA,IACX;AAAA,EACF;AAEA,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,iBAAe;AAAA,MACf,SAAS;AAAA,MACT,WAAW;AAAA,MACX,UAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAY,oBAAoB,MAAM,MAAM,IAAI,MAAM,EAAE;AAAA,MAExD;AAAA,wBAAAD,KAAC,QACC,0BAAAA,KAAC,eAAY,eAAa,MAAM,QAAS,gBAAM,QAAO,GACxD;AAAA,QACA,gBAAAA,KAAC,QACC,0BAAAC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,eAAe;AAAA,cACf,KAAK;AAAA,YACP;AAAA,YAEA;AAAA,8BAAAD,KAAC,UAAM,gBAAM,IAAG;AAAA,cAChB,gBAAAA,KAAC,UAAK,OAAO,EAAE,OAAO,uBAAuB,GAAI,gBAAM,SAAQ;AAAA;AAAA;AAAA,QACjE,GACF;AAAA,QACA,gBAAAA,KAAC,QAAM,4BAAkB,MAAM,WAAW,KAAK,KAAI;AAAA,QACnD,gBAAAA,KAAC,QACE,gBAAM,aAAa,SAClB,MAAM,aAAa,IACjB,kBAEA,eAAe,MAAM,QAAQ,IAG/B,gBAAAA,KAAC,cAAW,GAEhB;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,eAAa,MAAM;AAAA,YACnB,kBAAgB,WAAW,OAAO,IAAI,WAAW,QAAQ,IAAI;AAAA,YAC7D,OAAO;AAAA,cACL,MAAM;AAAA,cACN,OAAO;AAAA,cACP,iBAAiB;AAAA,YACnB;AAAA,YAEA,0BAAAA,KAAC,aAAU,WAAU,cAClB,gBAAM,aAAa,IAChB,kBACA,MAAM,WACJ,eAAe,MAAM,QAAQ,IAC7B,KACR;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACjPA,SAAS,UAAAG,eAAc;AA4Hb,gBAAAC,MAiCF,QAAAC,aAjCE;AApHV,IAAM,cAAcC,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWhC,IAAM,cAAcA,QAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BnC,IAAM,cAAcA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAOhC,IAAM,cAAcA,QAAO,MAAM;AAAA;AAAA;AAAA;AAKjC,IAAM,cAAcA,QAAO,MAAM;AAAA;AAAA;AAAA;AAKjC,IAAM,MAAMA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcxB,IAAMC,eAAcD,QAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgC1B,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,gBAAAD,MAAC,eACC;AAAA,oBAAAD,KAAC,eAAY,SAAS,SAAS,cAAW,sBACxC,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAO;AAAA,QACP,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,OAAM;AAAA,QAEN,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,QAAO;AAAA,YACP,aAAY;AAAA,YACZ,eAAc;AAAA;AAAA,QAChB;AAAA;AAAA,IACF,GACF;AAAA,IACA,gBAAAC,MAAC,eACC;AAAA,sBAAAD,KAAC,eAAY,oBAAM;AAAA,MACnB,gBAAAA,KAAC,eACC,0BAAAA,KAACG,cAAA,EAAY,eAAa,MAAM,QAAS,gBAAM,QAAO,GACxD;AAAA,MAEA,gBAAAH,KAAC,eAAY,qBAAO;AAAA,MACpB,gBAAAA,KAAC,eACC,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,SAAS,MAAM,WAAW,MAAM,EAAE;AAAA,UAClC,OAAO;AAAA,YACL,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,YAAY;AAAA,YACZ,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,MAAM;AAAA,UACR;AAAA,UAEC,gBAAM;AAAA;AAAA,MACT,GACF;AAAA,MAEA,gBAAAA,KAAC,eAAY,kBAAI;AAAA,MACjB,gBAAAC,MAAC,eACE;AAAA,mBAAW,MAAM,SAAS;AAAA,QAAE;AAAA,QAAG;AAAA,QAC/B,MAAM,aAAa,SAChB,WAAW,MAAM,YAAY,MAAM,QAAQ,IAC3C;AAAA,SACN;AAAA,MAEA,gBAAAD,KAAC,eAAY,sBAAQ;AAAA,MACrB,gBAAAA,KAAC,eACE,gBAAM,aAAa,SAChB,eAAe,MAAM,QAAQ,IAC7B,cACN;AAAA,MAEA,gBAAAA,KAAC,eAAY,2BAAa;AAAA,MAC1B,gBAAAA,KAAC,OAAK,eAAK,UAAU,KAAK,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,GAAE;AAAA,MAEzD,gBAAAA,KAAC,eAAY,yBAAW;AAAA,MACxB,gBAAAA,KAAC,OACE,yBAAe,MAAM,WAAW,KAAK,4BACxC;AAAA,OACF;AAAA,KACF;AAEJ;;;ACrLA,SAAS,YAAAI,WAAU,aAAAC,kBAAiB;AAI7B,SAAS,wBAA6C;AAC3D,QAAM,CAAC,SAAS,UAAU,IAAID,UAA8B,CAAC,CAAC;AAE9D,EAAAC,WAAU,MAAM;AACd,UAAM,gBAAgB,oBAAI,IAA+B;AAEzD,UAAM,2BAA2B,CAACC,aAAgC;AAChE,iBAAW,QAAQA,UAAS;AAC1B,cAAM,SAAU,KACb;AAEH,YAAI,QAAQ,SAAS,oBAAqB;AAE1C,cAAM,YAAY,cAAc,IAAI,OAAO,IAAI;AAE/C,YAAI,KAAK,cAAc,UAAU,UAAW;AAE5C,sBAAc,IAAI,OAAO,MAAM;AAAA,UAC7B,MAAM,OAAO;AAAA,UACb,IAAI,OAAO;AAAA,UACX,QAAQ,OAAO;AAAA,UACf,SAAS,KAAK,UAAU,OAAO,OAAO;AAAA,UACtC,QAAQ,OAAO;AAAA,UACf,WAAW,KAAK;AAAA,UAChB,aAAa,OAAO,eAAe,WAAW;AAAA,UAC9C,UAAU,KAAK,cAAc,SAAS,SAAY,KAAK;AAAA,UACvD,SAAS,KAAK,YAAY,KAAK;AAAA,UAC/B,WAAW,OAAO;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,6BAAyB,YAAY,iBAAiB,MAAM,CAAC;AAC7D,6BAAyB,YAAY,iBAAiB,SAAS,CAAC;AAEhE,eAAW,MAAM,KAAK,cAAc,OAAO,CAAC,CAAC;AAE7C,UAAM,WAAW,IAAI,oBAAoB,CAAC,SAAS;AACjD,+BAAyB,KAAK,WAAW,CAAC;AAC1C,iBAAW,MAAM,KAAK,cAAc,OAAO,CAAC,CAAC;AAAA,IAC/C,CAAC;AAED,aAAS,QAAQ,EAAE,YAAY,CAAC,QAAQ,SAAS,EAAE,CAAC;AAEpD,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;;;AL3CA,SAAS,yBAAyB;AAmJ1B,gBAAAC,MAgCE,QAAAC,aAhCF;AA7IR,IAAM,YAAYC,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS9B,IAAM,aAAaA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAO/B,IAAM,YAAYA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAO9B,IAAM,OAAOA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAezB,IAAM,aAAaA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU/B,IAAM,aAAaA,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBxB,SAAS,gBAAgB,EAAE,YAAY,MAAM,GAAyB;AAC3E,QAAM,UAAU,sBAAsB;AACtC,QAAM,CAAC,aAAa,cAAc,IAAIC,UAAwB,IAAI;AAClE,QAAM,CAAC,eAAe,gBAAgB,IAAIA;AAAA,IACxC;AAAA,EACF;AACA,QAAM,oBAAoB,iBAAiB,aAAa;AACxD,QAAM,EAAE,QAAQ,IAAI,UAAU;AAE9B,QAAM,YAAY,CAAC,SAAiB;AAClC,mBAAe,CAAC,SAAU,SAAS,OAAO,OAAO,IAAK;AAAA,EACxD;AAEA,QAAM,gBAAgBC,SAAQ,MAAM;AAClC,WAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAAA,EAC9D,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,mBAAmBA,SAAQ,MAAM;AACrC,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,UAAM,MAAM,YAAY,IAAI;AAC5B,WAAO;AAAA,MACL,KAAK,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,MAChD,KAAK,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,CAAC;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,kBAAkBA,SAAQ,MAAM;AACpC,QAAI,CAAC,kBAAmB,QAAO;AAC/B,UAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,UAAM,MAAM,YAAY,IAAI;AAC5B,WAAO,cAAc,OAAO,CAAC,UAAU;AACrC,YAAM,WAAW,MAAM,WAAW;AAElC,aAAO,MAAM,aAAa,WAAW,YAAY;AAAA,IACnD,CAAC;AAAA,EACH,GAAG,CAAC,eAAe,iBAAiB,CAAC;AAErC,QAAM,eAAe,oBACjB,EAAE,KAAK,kBAAkB,CAAC,GAAG,KAAK,kBAAkB,CAAC,EAAE,IACvD;AAGJ,QAAM,cAAc,CAAC,UAA6B;AAChD,UAAM,SAAS,cAAc,OAAO,MAAM,cAAc,OAAO,MAAM;AACrE,UAAM,MAAM,YAAY,IAAI;AAE5B,UAAM,eAAe,KAAK,IAAI,MAAM,WAAW,cAAc,OAAO,CAAC;AACrE,UAAM,aAAa,KAAK,IAAI,MAAM,WAAW,KAAK,cAAc,OAAO,GAAG;AAE1E,UAAM,OAAO,KAAK;AAAA,MAChB;AAAA,OACE,gBAAgB,cAAc,OAAO,MAAM,QAAS;AAAA,IACxD;AACA,UAAM,QAAQ,KAAK,IAAI,IAAK,aAAa,gBAAgB,QAAS,GAAG;AAErE,UAAM,QACJ,MAAM,WAAW,YACb,2BACA,MAAM,WAAW,UACf,yBACA;AAER,WAAO;AAAA,MACL,SAAS,GAAG,IAAI;AAAA,MAChB,UAAU,UAAU,IAAI,QAAQ,GAAG,KAAK;AAAA,MACxC,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,0BAA0B,CAAC,OAAe;AAC9C,YAAQ,EAAsB;AAC9B,eAAW;AAAA,EACb;AAEA,MAAI,CAAC,kBAAkB,oBAAoB;AACzC,WACE,gBAAAJ,KAAC,aAAU,OACT,0BAAAA,KAAC,cAAW,4DAA8C,GAC5D;AAAA,EAEJ;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,gBAAAA,KAAC,aAAU,OACT,0BAAAA,KAAC,cAAW,yGAGZ,GACF;AAAA,EAEJ;AAEA,QAAM,gBAAgB,cAClB,gBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW,IAClD;AAEJ,SACE,gBAAAC,MAAC,aAAU,OACR;AAAA,wBACC,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAW;AAAA,QACX,WAAW;AAAA,QACX,mBAAmB;AAAA;AAAA,IACrB;AAAA,IAEF,gBAAAC,MAAC,cACC;AAAA,sBAAAD,KAAC,aACC,0BAAAC,MAAC,QACC;AAAA,wBAAAD,KAAC,cAAW,oBAAM;AAAA,QAClB,gBAAAA,KAAC,cAAW,qBAAO;AAAA,QACnB,gBAAAA,KAAC,cAAW,oBAAM;AAAA,QAClB,gBAAAA,KAAC,cAAW,sBAAQ;AAAA,QACnB,gBAAgB,IAAI,CAAC,UACpB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,YAAY,gBAAgB,MAAM;AAAA,YAClC,UAAU,MAAM,UAAU,MAAM,IAAI;AAAA,YACnC,GAAG,YAAY,KAAK;AAAA;AAAA,UAJhB,MAAM;AAAA,QAKb,CACD;AAAA,SACH,GACF;AAAA,MACC,iBACC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,SAAS,MAAM,eAAe,IAAI;AAAA;AAAA,MACpC;AAAA,OAEJ;AAAA,KACF;AAEJ;;;AHhKM,gBAAAK,MAOE,QAAAC,aAPF;AAvCN,IAAMC,eAAc;AAEpB,SAAS,eAA6B;AACpC,MAAI;AACF,UAAM,SAAS,aAAa,QAAQA,YAAW;AAC/C,QAAI,WAAW,eAAe,WAAW,eAAe;AACtD,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEO,SAAS,eAAe;AAAA,EAC7B,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,sBAAsB;AACxB,GAKG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,iBAAiB;AACzC,QAAM,CAAC,WAAW,iBAAiB,IAAIC,UAAuB,YAAY;AAE1E,QAAM,eAAe,YAAY,CAAC,QAAsB;AACtD,sBAAkB,GAAG;AACrB,QAAI;AACF,mBAAa,QAAQD,cAAa,GAAG;AAAA,IACvC,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,MAAI,CAAC,MAAM;AACT,WACE,gBAAAF,KAAC,mBAAgB,UAAoB,SAAS,MAAM,QAAQ,IAAI,GAAG;AAAA,EAEvE;AAEA,SACE,gBAAAA,KAAC,gBAAa,WAAW,aAAa,MAAM,WAAW,aAAa,MAClE,0BAAAA,KAAC,0BACC,0BAAAC,MAAC,sBAAmB,IAAI,cAAc,OAAO,EAAE,QAAQ,IAAI,GACzD;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QACX,SAAS,MAAM,QAAQ,KAAK;AAAA,QAC5B;AAAA,QACA,aAAa;AAAA;AAAA,IACf;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,SAAS,cAAc,cAAc,SAAS,OAAO;AAAA,QAC9D,UAAU,gBAAAA,KAAC,YAAS,qBAA0C;AAAA;AAAA,IAChE;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,SAAS,cAAc,gBAAgB,SAAS,OAAO;AAAA,QAChE,YAAY,MAAM,aAAa,WAAW;AAAA;AAAA,IAC5C;AAAA,KACF,GACF,GACF;AAEJ;AAEA,IAAM,qBAAqBI,QAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ADzDnC,gBAAAC,YAAA;AAnBG,SAAS,kBAAkB;AAChC,EAAAC,mBAAkB,gBAAgB;AACpC;AAEO,SAAS,cAAc,EAAE,WAAW,QAAQ,GAA4B;AAC7E,QAAM,UAAU,oBAA6B;AAC7C,QAAM,YAAY,QAAQ;AAC1B,QAAM,KAAK,QAAQ,UAAU,QAAQ,KAAK;AAE1C,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,KAAK;AACxC,EAAAC,WAAU,MAAM;AACd,aAAS,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SACE,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,WAAW,IAAI,MAAM,IAAI;AAAA,MACzB,qBAAmB;AAAA;AAAA,EACrB;AAEJ;AAEA,MAAM,MAAM,aAAa;","names":["useEffect","useState","SubscriptionScope","styled","useState","styled","useMemo","useState","styled","useEffect","useState","jsx","jsxs","styled","useState","useEffect","selectionWidth","styled","jsx","jsxs","styled","styled","jsx","jsxs","styled","StatusBadge","useState","useEffect","entries","jsx","jsxs","styled","useState","useMemo","jsx","jsxs","STORAGE_KEY","useState","styled","jsx","SubscriptionScope","useState","useEffect"]}
@@ -2,6 +2,6 @@
2
2
  import { SubscriptionScope } from "jazz-tools";
3
3
  if (typeof window !== "undefined" && process.env.NODE_ENV === "development") {
4
4
  SubscriptionScope.enableProfiling();
5
- import("./custom-element-WOQY2M4W.js");
5
+ import("./custom-element-TJNWN4WC.js");
6
6
  }
7
7
  //# sourceMappingURL=register-custom-element.js.map
package/dist/testing.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  coValueClassFromCoValueClassOrSchema,
8
8
  createAnonymousJazzContext,
9
9
  createJazzContext
10
- } from "./chunk-XQ27DEA5.js";
10
+ } from "./chunk-HBWUGW37.js";
11
11
  import "./chunk-ZQWSQH6L.js";
12
12
 
13
13
  // src/tools/testing.ts
package/package.json CHANGED
@@ -196,7 +196,7 @@
196
196
  },
197
197
  "type": "module",
198
198
  "license": "MIT",
199
- "version": "0.20.4",
199
+ "version": "0.20.6",
200
200
  "dependencies": {
201
201
  "@manuscripts/prosemirror-recreate-steps": "^0.1.4",
202
202
  "@scure/base": "1.2.1",
@@ -213,9 +213,9 @@
213
213
  "prosemirror-transform": "^1.9.0",
214
214
  "use-sync-external-store": "^1.5.0",
215
215
  "zod": "4.1.11",
216
- "cojson": "0.20.4",
217
- "cojson-storage-indexeddb": "0.20.4",
218
- "cojson-transport-ws": "0.20.4"
216
+ "cojson": "0.20.6",
217
+ "cojson-storage-indexeddb": "0.20.6",
218
+ "cojson-transport-ws": "0.20.6"
219
219
  },
220
220
  "devDependencies": {
221
221
  "@scure/bip39": "^1.3.0",
@@ -10,7 +10,6 @@ import { InMemoryRouterProvider } from "./router/in-memory-router.js";
10
10
  import { Header } from "./viewer/header.js";
11
11
  import { PerformancePage } from "./pages/performance/index.js";
12
12
  import { HomePage } from "./pages/home.js";
13
- import { SubscriptionScope } from "jazz-tools";
14
13
 
15
14
  export type InspectorTab = "inspector" | "performance";
16
15
 
@@ -32,10 +31,12 @@ export function InspectorInApp({
32
31
  position = "right",
33
32
  localNode,
34
33
  accountId,
34
+ showDeleteLocalData = false,
35
35
  }: {
36
36
  position?: Position;
37
37
  localNode?: LocalNode;
38
38
  accountId?: CoID<RawAccount>;
39
+ showDeleteLocalData?: boolean;
39
40
  }) {
40
41
  const [open, setOpen] = useOpenInspector();
41
42
  const [activeTab, setActiveTabState] = useState<InspectorTab>(getStoredTab);
@@ -68,7 +69,7 @@ export function InspectorInApp({
68
69
  {/* Both components stay mounted, visibility controlled by CSS */}
69
70
  <PageStack
70
71
  style={{ display: activeTab === "inspector" ? "flex" : "none" }}
71
- homePage={<HomePage showDeleteLocalData />}
72
+ homePage={<HomePage showDeleteLocalData={showDeleteLocalData} />}
72
73
  />
73
74
  <PerformancePage
74
75
  style={{ display: activeTab === "performance" ? "flex" : "none" }}
@@ -28,6 +28,7 @@ export function JazzInspector({ position = "right" }: { position?: Position }) {
28
28
  position={position}
29
29
  localNode={localNode}
30
30
  accountId={me?.$jazz.raw.id}
31
+ showDeleteLocalData
31
32
  />
32
33
  );
33
34
  }
@@ -1025,4 +1025,71 @@ describe("useCoState", () => {
1025
1025
  assertLoaded(result.current);
1026
1026
  expect(result.current.value).toBe("test");
1027
1027
  });
1028
+
1029
+ it("should render without infinite re-renders when accessing 2-level nested unresolved co-values", async () => {
1030
+ const account = await createJazzTestAccount({
1031
+ isCurrentActiveAccount: true,
1032
+ });
1033
+
1034
+ // 3-level schema: Organization -> Project -> Task
1035
+ const Task = co.map({
1036
+ title: z.string(),
1037
+ });
1038
+
1039
+ const Project = co.map({
1040
+ name: z.string(),
1041
+ task: co.optional(Task),
1042
+ });
1043
+
1044
+ const Organization = co.map({
1045
+ name: z.string(),
1046
+ project: co.optional(Project),
1047
+ });
1048
+
1049
+ const org = Organization.create({
1050
+ name: "Test Org",
1051
+ project: Project.create({
1052
+ name: "Test Project",
1053
+ task: Task.create({ title: "Test Task" }),
1054
+ }),
1055
+ });
1056
+
1057
+ let renderCount = 0;
1058
+
1059
+ const { result } = renderHook(
1060
+ () => {
1061
+ renderCount++;
1062
+ const orgState = useCoState(Organization, org.$jazz.id, {
1063
+ resolve: {
1064
+ project: {},
1065
+ },
1066
+ });
1067
+
1068
+ // Access 2-level nested unresolved co-values
1069
+ if (orgState.$isLoaded) {
1070
+ const project = orgState.project;
1071
+ if (project?.$isLoaded) {
1072
+ // This should not cause infinite re-renders
1073
+ const _ = project.task;
1074
+ }
1075
+ }
1076
+
1077
+ return orgState;
1078
+ },
1079
+ {
1080
+ account,
1081
+ },
1082
+ );
1083
+
1084
+ await waitFor(() => {
1085
+ assertLoaded(result.current);
1086
+ expect(result.current.name).toBe("Test Org");
1087
+ });
1088
+
1089
+ // Wait a bit to ensure no additional re-renders occur
1090
+ await new Promise((resolve) => setTimeout(resolve, 100));
1091
+
1092
+ // Should not have excessive re-renders
1093
+ expect(renderCount).toBeLessThan(10);
1094
+ });
1028
1095
  });
@@ -153,7 +153,7 @@ export class SubscriptionScope<D extends CoValue> {
153
153
  }
154
154
 
155
155
  trackLoadingPerformance(source: string) {
156
- if (!SubscriptionScope.isProfilingEnabled) {
156
+ if (!SubscriptionScope.isProfilingEnabled || !crypto.randomUUID) {
157
157
  return;
158
158
  }
159
159