reflet-sdk 0.7.10 → 0.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +26 -12
- package/dist/desktop.js +1 -1
- package/dist/{devtools-layer-COilp7Ht.js → devtools-layer-CSEp-eZw.js} +3 -3
- package/dist/{devtools-layer-COilp7Ht.js.map → devtools-layer-CSEp-eZw.js.map} +1 -1
- package/dist/devtools-next.js +1 -1
- package/dist/devtools-vite.js +3 -3
- package/dist/feedback.js +4 -4
- package/dist/{handler-D8c3woEz.js → handler-BX8ITlGZ.js} +3 -3
- package/dist/{handler-D8c3woEz.js.map → handler-BX8ITlGZ.js.map} +1 -1
- package/dist/{protocol-ClxYWmhu.js → protocol-P5T66Bs3.js} +4 -1
- package/dist/protocol-P5T66Bs3.js.map +1 -0
- package/dist/{reflet-proxy-Dg6mea-4.js → reflet-proxy-CiMPGYzD.js} +2 -2
- package/dist/{reflet-proxy-Dg6mea-4.js.map → reflet-proxy-CiMPGYzD.js.map} +1 -1
- package/dist/{submit-D7XKlgee.js → submit-CqeMuBPt.js} +2 -2
- package/dist/{submit-D7XKlgee.js.map → submit-CqeMuBPt.js.map} +1 -1
- package/dist/{team-layer-By_81DBU.js → team-layer-BdytvHiG.js} +3 -3
- package/dist/{team-layer-By_81DBU.js.map → team-layer-BdytvHiG.js.map} +1 -1
- package/dist/{use-sheet-tab-QLQ1oeso.js → use-sheet-tab-DTGgQ_1c.js} +786 -57
- package/dist/use-sheet-tab-DTGgQ_1c.js.map +1 -0
- package/package.json +1 -1
- package/dist/protocol-ClxYWmhu.js.map +0 -1
- package/dist/use-sheet-tab-QLQ1oeso.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ All notable changes to `reflet-sdk` will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.7.12] - 2026-10-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Devtools: the dev server route forwards the live session feed, so `reflet session watch` from `reflet-cli` can hand what you say while recording a session to a coding agent on your machine (`/reflet-live`), which fixes it before you finish. Only your own devtools sessions, under your Connect sign-in.
|
|
13
|
+
- Sessions: speaker detection for sessions with several people. Tick "Several people are talking" before you start and each passage shows who spoke (Speaker 1, Speaker 2…, the same number for the same person all session) in the review, the copied transcript, the brief and the live feed for `/reflet-live`. The voice is then also streamed to Mistral (Voxtral), which keeps API inputs up to 30 days and does not train on them; the "What a session records" list says so.
|
|
14
|
+
|
|
15
|
+
## [0.7.11] - 2026-10-18
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Session voice is transcribed by ElevenLabs Scribe instead of Whisper, still through OpenRouter with zero data retention. It keeps English tech terms said in French ("border radius", "save bar", "preview") and answers faster; the disclosure shown before a session names the new provider.
|
|
20
|
+
|
|
8
21
|
## [0.7.10] - 2026-10-17
|
|
9
22
|
|
|
10
23
|
### Fixed
|
package/README.md
CHANGED
|
@@ -224,8 +224,17 @@ users. Pass `devtools={false}` to turn it off.
|
|
|
224
224
|
a `.zip` with its screenshots (nothing is shared until you copy or download
|
|
225
225
|
it), and **Add to board** turns them into internal feedback, one by one or
|
|
226
226
|
all at once.
|
|
227
|
+
With several people around the same screen, tick "Several people are
|
|
228
|
+
talking" before you start: Mistral tells the voices apart, so each passage
|
|
229
|
+
shows who spoke (Speaker 1, Speaker 2…), with the same number for the same
|
|
230
|
+
person through the whole session. If the page sends a
|
|
231
|
+
`Content-Security-Policy`, add `wss://api.mistral.ai` to `connect-src` for
|
|
232
|
+
this; without it the session records without telling voices apart.
|
|
227
233
|
Sessions are recorded under your own name, so they need Connect rather than
|
|
228
|
-
`REFLET_SECRET_KEY`.
|
|
234
|
+
`REFLET_SECRET_KEY`. While you record, `reflet session watch` from
|
|
235
|
+
`reflet-cli` hands each passage to a coding agent on your machine, with what
|
|
236
|
+
you pointed at, its source location and, with several people, who spoke, so
|
|
237
|
+
the agent (`/reflet-live`) can fix it before you finish.
|
|
229
238
|
|
|
230
239
|
Code view and the board go through one dev-only route that reads files from
|
|
231
240
|
your repository and holds the board credential server-side.
|
|
@@ -272,12 +281,13 @@ export default defineConfig({ plugins: [react(), refletDevtools()] });
|
|
|
272
281
|
|
|
273
282
|
The route only answers on `localhost`, `*.localhost`, loopback IPs and the
|
|
274
283
|
hostnames you allow — so a rebound DNS name pointing at your machine gets a 403
|
|
275
|
-
— and only to same-origin browser requests
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
source files (`.ts`, `.tsx`, `.js`,
|
|
279
|
-
`.mdx`…) inside the repository and never
|
|
280
|
-
forwards the feedback and session endpoints the
|
|
284
|
+
— and only to same-origin browser requests or tools run on this machine, like
|
|
285
|
+
`reflet session watch` (`Sec-Fetch-Site`), carrying the devtools header. These
|
|
286
|
+
checks stop other sites in your browser, not other machines: that is what the
|
|
287
|
+
loopback binding is for. It only serves source files (`.ts`, `.tsx`, `.js`,
|
|
288
|
+
`.jsx`, `.vue`, `.svelte`, `.astro`, `.mdx`…) inside the repository and never
|
|
289
|
+
under `node_modules`, and only forwards the feedback and session endpoints the
|
|
290
|
+
devtools and the session watcher use.
|
|
281
291
|
|
|
282
292
|
#### Sessions in production (team tools)
|
|
283
293
|
|
|
@@ -296,11 +306,15 @@ Two things on your side:
|
|
|
296
306
|
- The page must allow the microphone. A `Permissions-Policy` header with
|
|
297
307
|
`microphone=()` blocks it; use `microphone=(self)`.
|
|
298
308
|
|
|
299
|
-
Pass `teamTools={false}` to turn it off. Voice is transcribed by
|
|
300
|
-
OpenRouter with zero data retention
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
309
|
+
Pass `teamTools={false}` to turn it off. Voice is transcribed by ElevenLabs
|
|
310
|
+
Scribe through OpenRouter with zero data retention. When "Several people are
|
|
311
|
+
talking" is ticked, the voice is also streamed live to Mistral (Voxtral) to
|
|
312
|
+
tell the speakers apart; Mistral keeps API inputs up to 30 days and does not
|
|
313
|
+
train on them. Reflet deletes the audio once its transcript is saved, within
|
|
314
|
+
24 hours at most. Pausing stops all
|
|
315
|
+
collection; keystrokes are never recorded, form fields appear empty in
|
|
316
|
+
screenshots, and password fields and elements marked `data-reflet-redact` are
|
|
317
|
+
hidden from them.
|
|
304
318
|
|
|
305
319
|
##### Desktop apps (Electron)
|
|
306
320
|
|
package/dist/desktop.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as connectCallbackUriFor, f as PENDING_CONNECT_TTL_MS, i as connectAuthorizeUrl, l as forgetConnection, m as readConnection, o as connectOutcomePage, p as htmlPage, r as resolveDevtoolsOptions, t as proxyWithBoardCredential, u as redeemConnectCode } from "./reflet-proxy-
|
|
1
|
+
import { a as connectCallbackUriFor, f as PENDING_CONNECT_TTL_MS, i as connectAuthorizeUrl, l as forgetConnection, m as readConnection, o as connectOutcomePage, p as htmlPage, r as resolveDevtoolsOptions, t as proxyWithBoardCredential, u as redeemConnectCode } from "./reflet-proxy-CiMPGYzD.js";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
3
|
//#region src/devtools/server/desktop.ts
|
|
4
4
|
const LOOPBACK_HOST = "127.0.0.1";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as SelectionOutline } from "./submit-
|
|
2
|
-
import { A as sessionSheetPlace, C as AccountFooter, D as MissingRouteHint, E as MISSING_SECRET_KEY_HINT, F as useWorkspaceLoader, H as disconnectBoard, J as reportFailure, M as RecordingLayer, N as SessionWorkspaceProvider, O as SESSIONS_STYLES, S as InboxPanel, T as CONNECT_REQUIREMENT, U as probeDevRoute, V as callReflet, W as startBoardConnect, _ as DevtoolsBarButtons, a as NotePicker, b as CodeTab, c as isActiveNote, d as useNotes, f as findOnPage, g as DevtoolsBar, h as DevtoolsSheet, i as NotesPanel, j as useSessionNavigation, k as SessionsPanel, l as isNoteOnPage, m as DEVTOOLS_STYLES, n as useSheetTab, o as enrichNote, p as usePageHighlight, q as Notices, r as NotePins, s as hasTriedToLocate, u as unsentNoteCount, v as SHEET_TABS, w as AccountNote, x as useCodeLookup, z as devtoolsTransport } from "./use-sheet-tab-
|
|
1
|
+
import { d as SelectionOutline } from "./submit-CqeMuBPt.js";
|
|
2
|
+
import { A as sessionSheetPlace, C as AccountFooter, D as MissingRouteHint, E as MISSING_SECRET_KEY_HINT, F as useWorkspaceLoader, H as disconnectBoard, J as reportFailure, M as RecordingLayer, N as SessionWorkspaceProvider, O as SESSIONS_STYLES, S as InboxPanel, T as CONNECT_REQUIREMENT, U as probeDevRoute, V as callReflet, W as startBoardConnect, _ as DevtoolsBarButtons, a as NotePicker, b as CodeTab, c as isActiveNote, d as useNotes, f as findOnPage, g as DevtoolsBar, h as DevtoolsSheet, i as NotesPanel, j as useSessionNavigation, k as SessionsPanel, l as isNoteOnPage, m as DEVTOOLS_STYLES, n as useSheetTab, o as enrichNote, p as usePageHighlight, q as Notices, r as NotePins, s as hasTriedToLocate, u as unsentNoteCount, v as SHEET_TABS, w as AccountNote, x as useCodeLookup, z as devtoolsTransport } from "./use-sheet-tab-DTGgQ_1c.js";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/devtools/client/account/connect-footer.tsx
|
|
@@ -369,4 +369,4 @@ function DevtoolsLayer({ isWidgetOpen, position, publicKey }) {
|
|
|
369
369
|
//#endregion
|
|
370
370
|
export { DevtoolsLayer };
|
|
371
371
|
|
|
372
|
-
//# sourceMappingURL=devtools-layer-
|
|
372
|
+
//# sourceMappingURL=devtools-layer-CSEp-eZw.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools-layer-COilp7Ht.js","names":[],"sources":["../src/devtools/client/account/connect-footer.tsx","../src/devtools/client/account/devtools-account.tsx","../src/devtools/client/board/board-tab.tsx","../src/devtools/client/route/use-dev-route.ts","../src/devtools/client/sessions/devtools-sessions.tsx","../src/devtools/client/devtools-layer.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { reportFailure } from \"../notices\";\nimport { startBoardConnect } from \"../route/dev-route\";\n\ntype ConnectState =\n | { kind: \"idle\" }\n | { kind: \"starting\" }\n | { authorizeUrl: string; kind: \"waiting\" };\n\nfunction useBoardConnect(publicKey: string) {\n const [state, setState] = useState<ConnectState>({ kind: \"idle\" });\n\n const connect = async () => {\n // Opened before any await: browsers only allow popups inside the click.\n const tab = window.open(\"\", \"_blank\");\n if (tab) {\n tab.opener = null;\n }\n setState({ kind: \"starting\" });\n try {\n const { authorizeUrl } = await startBoardConnect(publicKey);\n if (tab) {\n tab.location.href = authorizeUrl;\n } else {\n window.open(authorizeUrl, \"_blank\", \"noopener\");\n }\n setState({ authorizeUrl, kind: \"waiting\" });\n } catch (error) {\n tab?.close();\n setState({ kind: \"idle\" });\n reportFailure(\"Could not connect to Reflet\", error);\n }\n };\n return { connect, state };\n}\n\nexport function ConnectFooter({ publicKey }: { publicKey: string }) {\n const { connect, state } = useBoardConnect(publicKey);\n\n if (state.kind === \"waiting\") {\n return (\n <div className=\"dt-sheet-account\" role=\"status\">\n <p className=\"dt-meta\">\n Finish connecting in the Reflet tab. This panel updates when you come\n back.\n </p>\n <div className=\"dt-actions\">\n <a\n className=\"dt-btn\"\n href={state.authorizeUrl}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Open Reflet again\n </a>\n <button className=\"dt-btn\" onClick={connect} type=\"button\">\n Start again\n </button>\n </div>\n </div>\n );\n }\n return (\n <div className=\"dt-sheet-account\">\n <p className=\"dt-meta\">Not connected</p>\n <button\n className=\"dt-btn\"\n data-variant=\"primary\"\n disabled={state.kind === \"starting\"}\n onClick={connect}\n type=\"button\"\n >\n Connect to Reflet\n </button>\n </div>\n );\n}\n","import type { WorkspaceState } from \"../../../sessions/ui/session-workspace\";\nimport { reportFailure } from \"../notices\";\nimport { disconnectBoard } from \"../route/dev-route\";\nimport { CONNECT_REQUIREMENT } from \"../route/route-hint\";\nimport type { DevRouteState } from \"../route/use-dev-route\";\nimport { AccountFooter, AccountNote } from \"./account-footer\";\nimport { ConnectFooter } from \"./connect-footer\";\n\nasync function disconnect(refresh: () => void) {\n try {\n const { revoked } = await disconnectBoard();\n if (!revoked) {\n reportFailure(\n \"The Reflet token was not revoked\",\n new Error(\n \"Disconnected here, but Reflet could not be reached. Revoke it from Account → Devtools on reflet.app.\"\n )\n );\n }\n } catch (error) {\n reportFailure(\"The dev server did not disconnect\", error);\n }\n refresh();\n}\n\nexport function DevtoolsAccount({\n connectKey,\n refresh,\n route,\n workspace,\n}: {\n connectKey: string | null;\n refresh: () => void;\n route: DevRouteState;\n workspace: WorkspaceState;\n}) {\n if (route.kind !== \"ready\") {\n return null;\n }\n const { board } = route.status;\n if (board.kind === \"secretKey\") {\n return <AccountNote>Reaching the board with REFLET_SECRET_KEY</AccountNote>;\n }\n if (board.kind === \"disconnected\") {\n return connectKey === null ? (\n <AccountNote>Not connected. {CONNECT_REQUIREMENT}</AccountNote>\n ) : (\n <ConnectFooter publicKey={connectKey} />\n );\n }\n return (\n <AccountFooter\n actions={[\n {\n label: \"Disconnect\",\n onSelect: () => disconnect(refresh),\n variant: \"danger\",\n },\n ]}\n organizationName={board.organizationName}\n person={\n workspace.kind === \"ready\" ? workspace.workspace.identity.user : null\n }\n />\n );\n}\n","import type { CodeTarget } from \"../code/code-panel\";\nimport { InboxPanel } from \"../inbox/inbox-panel\";\nimport { callReflet } from \"../route/dev-route\";\nimport { MISSING_SECRET_KEY_HINT, MissingRouteHint } from \"../route/route-hint\";\nimport type { DevRouteState } from \"../route/use-dev-route\";\n\nexport function BoardTab({\n canConnect,\n onOpenCode,\n onShowSelector,\n route,\n}: {\n canConnect: boolean;\n onOpenCode: (target: CodeTarget) => void;\n onShowSelector: (selector: string) => boolean;\n route: DevRouteState;\n}) {\n if (route.kind === \"missing\") {\n return (\n <MissingRouteHint purpose=\"see your board's feedback for this page\" />\n );\n }\n if (route.kind === \"checking\") {\n return null;\n }\n if (route.status.board.kind === \"disconnected\") {\n return (\n <p className=\"dt-empty\">\n {canConnect\n ? \"Connect to Reflet below to see this page's feedback and add notes to your board.\"\n : MISSING_SECRET_KEY_HINT}\n </p>\n );\n }\n return (\n <InboxPanel\n boardCall={callReflet}\n onOpenCode={onOpenCode}\n onShowSelector={onShowSelector}\n />\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { DevtoolsStatus } from \"../../protocol\";\nimport { probeDevRoute } from \"./dev-route\";\n\nexport type DevRouteState =\n | { kind: \"checking\" }\n | { kind: \"missing\" }\n | { kind: \"ready\"; status: DevtoolsStatus };\n\n/** Re-probes on window focus so a connection finished in another tab shows up; keeps the last state meanwhile. */\nexport function useDevRoute(): { refresh: () => void; route: DevRouteState } {\n const [route, setRoute] = useState<DevRouteState>({ kind: \"checking\" });\n const latestProbe = useRef(0);\n\n const refresh = useCallback(() => {\n latestProbe.current += 1;\n const probe = latestProbe.current;\n probeDevRoute().then((status) => {\n if (probe === latestProbe.current) {\n setRoute(status ? { kind: \"ready\", status } : { kind: \"missing\" });\n }\n });\n }, []);\n\n useEffect(() => {\n refresh();\n window.addEventListener(\"focus\", refresh);\n return () => {\n window.removeEventListener(\"focus\", refresh);\n latestProbe.current += 1;\n };\n }, [refresh]);\n\n return { refresh, route };\n}\n","import type { ReactNode } from \"react\";\nimport { devtoolsTransport } from \"../../../sessions/api/session-transports\";\nimport {\n SessionWorkspaceProvider,\n useWorkspaceLoader,\n type WorkspaceState,\n} from \"../../../sessions/ui/session-workspace\";\nimport {\n type SessionNavigation,\n SessionsPanel,\n useSessionNavigation,\n} from \"../../../sessions/ui/sessions-panel\";\nimport { CONNECT_REQUIREMENT, MissingRouteHint } from \"../route/route-hint\";\nimport type { DevRouteState } from \"../route/use-dev-route\";\n\nconst DEVTOOLS_TRANSPORT = devtoolsTransport();\n\nexport interface DevtoolsSessions {\n navigation: SessionNavigation;\n state: WorkspaceState;\n}\n\n/** Sessions go through the dev route with the developer's own Connect token, never the secret key. */\nexport function useDevtoolsSessions(options: {\n onUnauthorized: () => void;\n route: DevRouteState;\n}): DevtoolsSessions {\n const { route } = options;\n const isConnected =\n route.kind === \"ready\" && route.status.board.kind === \"connected\";\n const state = useWorkspaceLoader({\n onUnauthorized: options.onUnauthorized,\n surface: \"devtools\",\n transport: isConnected ? DEVTOOLS_TRANSPORT : null,\n });\n return { navigation: useSessionNavigation(), state };\n}\n\nexport function SessionsScope({\n children,\n sessions,\n}: {\n children: ReactNode;\n sessions: DevtoolsSessions;\n}) {\n const workspace =\n sessions.state.kind === \"ready\" ? sessions.state.workspace : null;\n return (\n <SessionWorkspaceProvider workspace={workspace}>\n {children}\n </SessionWorkspaceProvider>\n );\n}\n\nconst SESSIONS_NEED_ACCOUNT =\n \"Sessions are recorded under your Reflet account.\";\n\nfunction WorkspaceGate({\n actions,\n sessions,\n}: {\n actions: SessionsTabActions;\n sessions: DevtoolsSessions;\n}) {\n const { state } = sessions;\n if (state.kind === \"ready\") {\n return (\n <SessionsPanel\n navigation={sessions.navigation}\n onStarted={actions.onStarted}\n onWriteNote={actions.onWriteNote}\n />\n );\n }\n if (state.kind === \"failed\") {\n return (\n <div className=\"dt-empty\" role=\"alert\">\n <p>Sessions did not open: {state.message}</p>\n <button className=\"dt-btn\" onClick={state.retry} type=\"button\">\n Try again\n </button>\n </div>\n );\n }\n return <p className=\"dt-status\">Opening your sessions…</p>;\n}\n\nexport interface SessionsTabActions {\n onStarted: () => void;\n onWriteNote?: () => void;\n}\n\nexport function SessionsTab({\n actions,\n canConnect,\n route,\n sessions,\n}: {\n actions: SessionsTabActions;\n canConnect: boolean;\n route: DevRouteState;\n sessions: DevtoolsSessions;\n}) {\n if (route.kind === \"checking\") {\n return <p className=\"dt-status\">Connecting to the Reflet dev route…</p>;\n }\n if (route.kind === \"missing\") {\n return (\n <MissingRouteHint purpose=\"record sessions under your Reflet account\" />\n );\n }\n const { board } = route.status;\n if (board.kind === \"disconnected\") {\n return (\n <p className=\"dt-empty\">\n {SESSIONS_NEED_ACCOUNT}{\" \"}\n {canConnect\n ? \"Connect to Reflet below to start one.\"\n : CONNECT_REQUIREMENT}\n </p>\n );\n }\n if (board.kind === \"secretKey\") {\n return (\n <p className=\"dt-empty\">\n {SESSIONS_NEED_ACCOUNT} REFLET_SECRET_KEY can't stand for you: remove it\n from the dev server environment, then connect to Reflet.\n </p>\n );\n }\n return <WorkspaceGate actions={actions} sessions={sessions} />;\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { RefletFeedbackProps } from \"../../feedback/types\";\nimport { SelectionOutline } from \"../../feedback/ui/selection-outline\";\nimport { RecordingLayer } from \"../../sessions/ui/recording/recording-layer\";\nimport { sessionSheetPlace } from \"../../sessions/ui/sessions-panel\";\nimport { SESSIONS_STYLES } from \"../../sessions/ui/sessions-styles\";\nimport { DevtoolsAccount } from \"./account/devtools-account\";\nimport { BoardTab } from \"./board/board-tab\";\nimport type { CodeTarget } from \"./code/code-panel\";\nimport { type CodeLookup, CodeTab, useCodeLookup } from \"./code/code-tab\";\nimport {\n DevtoolsBar,\n DevtoolsBarButtons,\n SHEET_TABS,\n type SheetTab,\n} from \"./devtools-bar\";\nimport { DevtoolsSheet } from \"./devtools-sheet\";\nimport { DEVTOOLS_STYLES } from \"./devtools-styles\";\nimport { findOnPage, usePageHighlight } from \"./find-on-page\";\nimport { enrichNote, hasTriedToLocate } from \"./notes/capture-note\";\nimport { NotePicker } from \"./notes/note-picker\";\nimport {\n isActiveNote,\n isNoteOnPage,\n type NotesSnapshot,\n unsentNoteCount,\n useNotes,\n} from \"./notes/note-store\";\nimport { NotesPanel } from \"./notes/notes-panel\";\nimport { Notices } from \"./notices\";\nimport { NotePins } from \"./pins/note-pins\";\nimport { callReflet } from \"./route/dev-route\";\nimport { MISSING_SECRET_KEY_HINT } from \"./route/route-hint\";\nimport { type DevRouteState, useDevRoute } from \"./route/use-dev-route\";\nimport {\n type DevtoolsSessions,\n SessionsScope,\n SessionsTab,\n useDevtoolsSessions,\n} from \"./sessions/devtools-sessions\";\nimport { FIRST_SHEET_TAB, useSheetTab } from \"./use-sheet-tab\";\n\nfunction sendBlockedReason(\n route: DevRouteState,\n canConnect: boolean\n): string | null {\n if (route.kind === \"checking\") {\n return \"Connecting to the Reflet dev route…\";\n }\n if (route.kind === \"missing\") {\n return \"Add the Reflet dev route to add notes to your board.\";\n }\n if (route.status.board.kind !== \"disconnected\") {\n return null;\n }\n return canConnect\n ? \"Connect to Reflet below to add notes to your board.\"\n : MISSING_SECRET_KEY_HINT;\n}\nfunction canConnectBoard(route: DevRouteState, publicKey: string | null) {\n return (\n route.kind === \"ready\" &&\n route.status.board.kind === \"disconnected\" &&\n route.status.board.canConnect &&\n publicKey !== null\n );\n}\n\n/** A reload in the middle of locating left these without a source; finish the job once. */\nfunction useResumeLocating(notes: NotesSnapshot, route: DevRouteState) {\n useEffect(() => {\n if (route.kind === \"checking\") {\n return;\n }\n for (const note of notes.notes) {\n const isUnlocated =\n note.source === null &&\n isActiveNote(note) &&\n notes.activity[note.id] === undefined &&\n !hasTriedToLocate(note.id) &&\n isNoteOnPage(note, window.location.pathname);\n const element = isUnlocated ? findOnPage(note.selection.selector) : null;\n if (element) {\n enrichNote(note.id, element, route.kind === \"ready\").catch(() => null);\n }\n }\n }, [notes, route.kind]);\n}\n\nfunction SheetPanel({\n canConnect,\n codeLookup,\n handlers,\n notes,\n openTab,\n route,\n sessions,\n}: {\n canConnect: boolean;\n codeLookup: CodeLookup | null;\n handlers: {\n onClose: () => void;\n onOpenCode: (target: CodeTarget) => void;\n onPick: () => void;\n onShowSelector: (selector: string) => boolean;\n };\n notes: NotesSnapshot;\n openTab: SheetTab;\n route: DevRouteState;\n sessions: DevtoolsSessions;\n}) {\n if (openTab === \"notes\") {\n return (\n <NotesPanel\n boardCall={callReflet}\n notes={notes}\n onOpenCode={handlers.onOpenCode}\n onPick={handlers.onPick}\n onShowSelector={handlers.onShowSelector}\n sendBlockedReason={sendBlockedReason(route, canConnect)}\n />\n );\n }\n if (openTab === \"inbox\") {\n return (\n <BoardTab\n canConnect={canConnect}\n onOpenCode={handlers.onOpenCode}\n onShowSelector={handlers.onShowSelector}\n route={route}\n />\n );\n }\n if (openTab === \"sessions\") {\n return (\n <SessionsTab\n actions={{\n onStarted: handlers.onClose,\n onWriteNote: () => {\n handlers.onClose();\n handlers.onPick();\n },\n }}\n canConnect={canConnect}\n route={route}\n sessions={sessions}\n />\n );\n }\n return codeLookup && <CodeTab lookup={codeLookup} route={route} />;\n}\n\nexport function DevtoolsLayer({\n isWidgetOpen,\n position,\n publicKey,\n}: {\n isWidgetOpen: boolean;\n position: NonNullable<RefletFeedbackProps[\"position\"]>;\n publicKey: string | null;\n}) {\n const { refresh, route } = useDevRoute();\n const notes = useNotes();\n useResumeLocating(notes, route);\n const sessions = useDevtoolsSessions({ onUnauthorized: refresh, route });\n const [isPicking, setIsPicking] = useState(false);\n const sheet = useSheetTab();\n const { openTab } = sheet;\n const { clearHighlight, highlighted, showSelector } = usePageHighlight();\n const { codeLookup, inspectElement, openCode } = useCodeLookup(sheet.select);\n\n const edge = position.startsWith(\"top\") ? \"top\" : \"bottom\";\n const side = position.endsWith(\"right\") ? \"right\" : \"left\";\n const canReadSource = route.kind === \"ready\";\n const canConnect = canConnectBoard(route, publicKey);\n const isRecessed = isWidgetOpen || isPicking;\n\n const closeSheet = () => {\n sheet.close();\n clearHighlight();\n };\n\n const startPick = useCallback(() => setIsPicking(true), []);\n const cancelPick = useCallback(() => setIsPicking(false), []);\n\n const inspect = useMemo(\n () => ({\n label: \"Code\",\n onInspect: (element: Element) => {\n setIsPicking(false);\n inspectElement(element);\n },\n }),\n [inspectElement]\n );\n\n const tabs = SHEET_TABS.filter((tab) => tab !== \"code\" || codeLookup);\n const openPanel = (tab: SheetTab | null) =>\n sheet.select(\n tab ?? (tabs.includes(sheet.lastTab) ? sheet.lastTab : FIRST_SHEET_TAB)\n );\n const sheetPlace =\n openTab === \"sessions\" && sessions.state.kind === \"ready\"\n ? sessionSheetPlace(sessions.navigation)\n : null;\n\n return (\n <SessionsScope sessions={sessions}>\n <div\n className=\"dt\"\n data-recessed={isRecessed}\n data-sheet-open={openTab !== null}\n >\n <style>{`${DEVTOOLS_STYLES}${SESSIONS_STYLES}`}</style>\n <NotePins isVisible={!isRecessed} notes={notes} onOpenCode={openCode} />\n {openTab && (\n <DevtoolsSheet\n footer={\n sheetPlace === null && (\n <DevtoolsAccount\n connectKey={canConnect ? publicKey : null}\n refresh={refresh}\n route={route}\n workspace={sessions.state}\n />\n )\n }\n navigation={{\n onSelectTab: sheet.select,\n place: sheetPlace,\n tab: openTab,\n tabs,\n }}\n onClose={closeSheet}\n side={side}\n >\n <SheetPanel\n canConnect={canConnect}\n codeLookup={codeLookup}\n handlers={{\n onClose: closeSheet,\n onOpenCode: openCode,\n onPick: startPick,\n onShowSelector: showSelector,\n }}\n notes={notes}\n openTab={openTab}\n route={route}\n sessions={sessions}\n />\n </DevtoolsSheet>\n )}\n <DevtoolsBar edge={edge} side={side}>\n <DevtoolsBarButtons\n canOpenCode\n onOpen={openPanel}\n onPick={startPick}\n unsentNoteCount={unsentNoteCount(notes)}\n />\n </DevtoolsBar>\n {openTab && <SelectionOutline node={highlighted} />}\n <Notices />\n {sessions.state.kind === \"ready\" && (\n <RecordingLayer\n onFinished={(target) => {\n sessions.navigation.go({ target, view: \"review\" });\n sheet.select(\"sessions\");\n }}\n />\n )}\n {isPicking && (\n <NotePicker\n canReadSource={canReadSource}\n inspect={inspect}\n onDone={cancelPick}\n />\n )}\n </div>\n </SessionsScope>\n );\n}\n"],"mappings":";;;;;AASA,SAAS,gBAAgB,WAAmB;CAC1C,MAAM,CAAC,OAAO,YAAY,SAAuB,EAAE,MAAM,OAAO,CAAC;CAEjE,MAAM,UAAU,YAAY;EAE1B,MAAM,MAAM,OAAO,KAAK,IAAI,QAAQ;EACpC,IAAI,KACF,IAAI,SAAS;EAEf,SAAS,EAAE,MAAM,WAAW,CAAC;EAC7B,IAAI;GACF,MAAM,EAAE,iBAAiB,MAAM,kBAAkB,SAAS;GAC1D,IAAI,KACF,IAAI,SAAS,OAAO;QAEpB,OAAO,KAAK,cAAc,UAAU,UAAU;GAEhD,SAAS;IAAE;IAAc,MAAM;GAAU,CAAC;EAC5C,SAAS,OAAO;GACd,KAAK,MAAM;GACX,SAAS,EAAE,MAAM,OAAO,CAAC;GACzB,cAAc,+BAA+B,KAAK;EACpD;CACF;CACA,OAAO;EAAE;EAAS;CAAM;AAC1B;AAEA,SAAgB,cAAc,EAAE,aAAoC;CAClE,MAAM,EAAE,SAAS,UAAU,gBAAgB,SAAS;CAEpD,IAAI,MAAM,SAAS,WACjB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAmB,MAAK;EAAvC,UAAA,CACE,oBAAC,KAAD;GAAG,WAAU;GAAU,UAAA;EAGpB,CAAA,GACH,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,KAAD;IACE,WAAU;IACV,MAAM,MAAM;IACZ,KAAI;IACJ,QAAO;IACR,UAAA;GAEE,CAAA,GACH,oBAAC,UAAD;IAAQ,WAAU;IAAS,SAAS;IAAS,MAAK;IAAS,UAAA;GAEnD,CAAA,CACL;EACF,CAAA,CAAA;;CAGT,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,KAAD;GAAG,WAAU;GAAU,UAAA;EAAgB,CAAA,GACvC,oBAAC,UAAD;GACE,WAAU;GACV,gBAAa;GACb,UAAU,MAAM,SAAS;GACzB,SAAS;GACT,MAAK;GACN,UAAA;EAEO,CAAA,CACL;;AAET;;;ACpEA,eAAe,WAAW,SAAqB;CAC7C,IAAI;EACF,MAAM,EAAE,YAAY,MAAM,gBAAgB;EAC1C,IAAI,CAAC,SACH,cACE,oDACA,IAAI,MACF,sGACF,CACF;CAEJ,SAAS,OAAO;EACd,cAAc,qCAAqC,KAAK;CAC1D;CACA,QAAQ;AACV;AAEA,SAAgB,gBAAgB,EAC9B,YACA,SACA,OACA,aAMC;CACD,IAAI,MAAM,SAAS,SACjB,OAAO;CAET,MAAM,EAAE,UAAU,MAAM;CACxB,IAAI,MAAM,SAAS,aACjB,OAAO,oBAAC,aAAD,EAAA,UAAa,4CAAsD,CAAA;CAE5E,IAAI,MAAM,SAAS,gBACjB,OAAO,eAAe,OACpB,qBAAC,aAAD,EAAA,UAAA,CAAa,mBAAgB,mBAAiC,EAAA,CAAA,IAE9D,oBAAC,eAAD,EAAe,WAAW,WAAa,CAAA;CAG3C,OACE,oBAAC,eAAD;EACE,SAAS,CACP;GACE,OAAO;GACP,gBAAgB,WAAW,OAAO;GAClC,SAAS;EACX,CACF;EACA,kBAAkB,MAAM;EACxB,QACE,UAAU,SAAS,UAAU,UAAU,UAAU,SAAS,OAAO;CAEpE,CAAA;AAEL;;;AC3DA,SAAgB,SAAS,EACvB,YACA,YACA,gBACA,SAMC;CACD,IAAI,MAAM,SAAS,WACjB,OACE,oBAAC,kBAAD,EAAkB,SAAQ,0CAA2C,CAAA;CAGzE,IAAI,MAAM,SAAS,YACjB,OAAO;CAET,IAAI,MAAM,OAAO,MAAM,SAAS,gBAC9B,OACE,oBAAC,KAAD;EAAG,WAAU;EACV,UAAA,aACG,qFACA;CACH,CAAA;CAGP,OACE,oBAAC,YAAD;EACE,WAAW;EACC;EACI;CACjB,CAAA;AAEL;;;;AC/BA,SAAgB,cAA6D;CAC3E,MAAM,CAAC,OAAO,YAAY,SAAwB,EAAE,MAAM,WAAW,CAAC;CACtE,MAAM,cAAc,OAAO,CAAC;CAE5B,MAAM,UAAU,kBAAkB;EAChC,YAAY,WAAW;EACvB,MAAM,QAAQ,YAAY;EAC1B,cAAc,CAAC,CAAC,MAAM,WAAW;GAC/B,IAAI,UAAU,YAAY,SACxB,SAAS,SAAS;IAAE,MAAM;IAAS;GAAO,IAAI,EAAE,MAAM,UAAU,CAAC;EAErE,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,QAAQ;EACR,OAAO,iBAAiB,SAAS,OAAO;EACxC,aAAa;GACX,OAAO,oBAAoB,SAAS,OAAO;GAC3C,YAAY,WAAW;EACzB;CACF,GAAG,CAAC,OAAO,CAAC;CAEZ,OAAO;EAAE;EAAS;CAAM;AAC1B;;;ACnBA,MAAM,qBAAqB,kBAAkB;;AAQ7C,SAAgB,oBAAoB,SAGf;CACnB,MAAM,EAAE,UAAU;CAClB,MAAM,cACJ,MAAM,SAAS,WAAW,MAAM,OAAO,MAAM,SAAS;CACxD,MAAM,QAAQ,mBAAmB;EAC/B,gBAAgB,QAAQ;EACxB,SAAS;EACT,WAAW,cAAc,qBAAqB;CAChD,CAAC;CACD,OAAO;EAAE,YAAY,qBAAqB;EAAG;CAAM;AACrD;AAEA,SAAgB,cAAc,EAC5B,UACA,YAIC;CACD,MAAM,YACJ,SAAS,MAAM,SAAS,UAAU,SAAS,MAAM,YAAY;CAC/D,OACE,oBAAC,0BAAD;EAAqC;EAClC;CACuB,CAAA;AAE9B;AAEA,MAAM,wBACJ;AAEF,SAAS,cAAc,EACrB,SACA,YAIC;CACD,MAAM,EAAE,UAAU;CAClB,IAAI,MAAM,SAAS,SACjB,OACE,oBAAC,eAAD;EACE,YAAY,SAAS;EACrB,WAAW,QAAQ;EACnB,aAAa,QAAQ;CACtB,CAAA;CAGL,IAAI,MAAM,SAAS,UACjB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAW,MAAK;EAA/B,UAAA,CACE,qBAAC,KAAD,EAAA,UAAA,CAAG,2BAAwB,MAAM,OAAW,EAAA,CAAA,GAC5C,oBAAC,UAAD;GAAQ,WAAU;GAAS,SAAS,MAAM;GAAO,MAAK;GAAS,UAAA;EAEvD,CAAA,CACL;;CAGT,OAAO,oBAAC,KAAD;EAAG,WAAU;EAAY,UAAA;CAAyB,CAAA;AAC3D;AAOA,SAAgB,YAAY,EAC1B,SACA,YACA,OACA,YAMC;CACD,IAAI,MAAM,SAAS,YACjB,OAAO,oBAAC,KAAD;EAAG,WAAU;EAAY,UAAA;CAAsC,CAAA;CAExE,IAAI,MAAM,SAAS,WACjB,OACE,oBAAC,kBAAD,EAAkB,SAAQ,4CAA6C,CAAA;CAG3E,MAAM,EAAE,UAAU,MAAM;CACxB,IAAI,MAAM,SAAS,gBACjB,OACE,qBAAC,KAAD;EAAG,WAAU;EAAb,UAAA;GACG;GAAuB;GACvB,aACG,0CACA;EACH;;CAGP,IAAI,MAAM,SAAS,aACjB,OACE,qBAAC,KAAD;EAAG,WAAU;EAAb,UAAA,CACG,uBAAsB,4GAEtB;;CAGP,OAAO,oBAAC,eAAD;EAAwB;EAAmB;CAAW,CAAA;AAC/D;;;ACzFA,SAAS,kBACP,OACA,YACe;CACf,IAAI,MAAM,SAAS,YACjB,OAAO;CAET,IAAI,MAAM,SAAS,WACjB,OAAO;CAET,IAAI,MAAM,OAAO,MAAM,SAAS,gBAC9B,OAAO;CAET,OAAO,aACH,wDACA;AACN;AACA,SAAS,gBAAgB,OAAsB,WAA0B;CACvE,OACE,MAAM,SAAS,WACf,MAAM,OAAO,MAAM,SAAS,kBAC5B,MAAM,OAAO,MAAM,cACnB,cAAc;AAElB;;AAGA,SAAS,kBAAkB,OAAsB,OAAsB;CACrE,gBAAgB;EACd,IAAI,MAAM,SAAS,YACjB;EAEF,KAAK,MAAM,QAAQ,MAAM,OAAO;GAO9B,MAAM,UALJ,KAAK,WAAW,QAChB,aAAa,IAAI,KACjB,MAAM,SAAS,KAAK,QAAQ,KAAA,KAC5B,CAAC,iBAAiB,KAAK,EAAE,KACzB,aAAa,MAAM,OAAO,SAAS,QAAQ,IACf,WAAW,KAAK,UAAU,QAAQ,IAAI;GACpE,IAAI,SACF,WAAW,KAAK,IAAI,SAAS,MAAM,SAAS,OAAO,CAAC,CAAC,YAAY,IAAI;EAEzE;CACF,GAAG,CAAC,OAAO,MAAM,IAAI,CAAC;AACxB;AAEA,SAAS,WAAW,EAClB,YACA,YACA,UACA,OACA,SACA,OACA,YAcC;CACD,IAAI,YAAY,SACd,OACE,oBAAC,YAAD;EACE,WAAW;EACJ;EACP,YAAY,SAAS;EACrB,QAAQ,SAAS;EACjB,gBAAgB,SAAS;EACzB,mBAAmB,kBAAkB,OAAO,UAAU;CACvD,CAAA;CAGL,IAAI,YAAY,SACd,OACE,oBAAC,UAAD;EACc;EACZ,YAAY,SAAS;EACrB,gBAAgB,SAAS;EAClB;CACR,CAAA;CAGL,IAAI,YAAY,YACd,OACE,oBAAC,aAAD;EACE,SAAS;GACP,WAAW,SAAS;GACpB,mBAAmB;IACjB,SAAS,QAAQ;IACjB,SAAS,OAAO;GAClB;EACF;EACY;EACL;EACG;CACX,CAAA;CAGL,OAAO,cAAc,oBAAC,SAAD;EAAS,QAAQ;EAAmB;CAAQ,CAAA;AACnE;AAEA,SAAgB,cAAc,EAC5B,cACA,UACA,aAKC;CACD,MAAM,EAAE,SAAS,UAAU,YAAY;CACvC,MAAM,QAAQ,SAAS;CACvB,kBAAkB,OAAO,KAAK;CAC9B,MAAM,WAAW,oBAAoB;EAAE,gBAAgB;EAAS;CAAM,CAAC;CACvE,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,QAAQ,YAAY;CAC1B,MAAM,EAAE,YAAY;CACpB,MAAM,EAAE,gBAAgB,aAAa,iBAAiB,iBAAiB;CACvE,MAAM,EAAE,YAAY,gBAAgB,aAAa,cAAc,MAAM,MAAM;CAE3E,MAAM,OAAO,SAAS,WAAW,KAAK,IAAI,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,IAAI,UAAU;CACpD,MAAM,gBAAgB,MAAM,SAAS;CACrC,MAAM,aAAa,gBAAgB,OAAO,SAAS;CACnD,MAAM,aAAa,gBAAgB;CAEnC,MAAM,mBAAmB;EACvB,MAAM,MAAM;EACZ,eAAe;CACjB;CAEA,MAAM,YAAY,kBAAkB,aAAa,IAAI,GAAG,CAAC,CAAC;CAC1D,MAAM,aAAa,kBAAkB,aAAa,KAAK,GAAG,CAAC,CAAC;CAE5D,MAAM,UAAU,eACP;EACL,OAAO;EACP,YAAY,YAAqB;GAC/B,aAAa,KAAK;GAClB,eAAe,OAAO;EACxB;CACF,IACA,CAAC,cAAc,CACjB;CAEA,MAAM,OAAO,WAAW,QAAQ,QAAQ,QAAQ,UAAU,UAAU;CACpE,MAAM,aAAa,QACjB,MAAM,OACJ,QAAQ,KAAK,SAAS,MAAM,OAAO,IAAI,MAAM,UAAA,QAC/C;CACF,MAAM,aACJ,YAAY,cAAc,SAAS,MAAM,SAAS,UAC9C,kBAAkB,SAAS,UAAU,IACrC;CAEN,OACE,oBAAC,eAAD;EAAyB;EACvB,UAAA,qBAAC,OAAD;GACE,WAAU;GACV,iBAAe;GACf,mBAAiB,YAAY;GAH/B,UAAA;IAKE,oBAAC,SAAD,EAAA,UAAQ,GAAG,kBAAkB,kBAAyB,CAAA;IACtD,oBAAC,UAAD;KAAU,WAAW,CAAC;KAAmB;KAAO,YAAY;IAAW,CAAA;IACtE,WACC,oBAAC,eAAD;KACE,QACE,eAAe,QACb,oBAAC,iBAAD;MACE,YAAY,aAAa,YAAY;MAC5B;MACF;MACP,WAAW,SAAS;KACrB,CAAA;KAGL,YAAY;MACV,aAAa,MAAM;MACnB,OAAO;MACP,KAAK;MACL;KACF;KACA,SAAS;KACH;KAEN,UAAA,oBAAC,YAAD;MACc;MACA;MACZ,UAAU;OACR,SAAS;OACT,YAAY;OACZ,QAAQ;OACR,gBAAgB;MAClB;MACO;MACE;MACF;MACG;KACX,CAAA;IACY,CAAA;IAEjB,oBAAC,aAAD;KAAmB;KAAY;KAC7B,UAAA,oBAAC,oBAAD;MACE,aAAA;MACA,QAAQ;MACR,QAAQ;MACR,iBAAiB,gBAAgB,KAAK;KACvC,CAAA;IACU,CAAA;IACZ,WAAW,oBAAC,kBAAD,EAAkB,MAAM,YAAc,CAAA;IAClD,oBAAC,SAAD,CAAU,CAAA;IACT,SAAS,MAAM,SAAS,WACvB,oBAAC,gBAAD,EACE,aAAa,WAAW;KACtB,SAAS,WAAW,GAAG;MAAE;MAAQ,MAAM;KAAS,CAAC;KACjD,MAAM,OAAO,UAAU;IACzB,EACD,CAAA;IAEF,aACC,oBAAC,YAAD;KACiB;KACN;KACT,QAAQ;IACT,CAAA;GAEA;;CACQ,CAAA;AAEnB"}
|
|
1
|
+
{"version":3,"file":"devtools-layer-CSEp-eZw.js","names":[],"sources":["../src/devtools/client/account/connect-footer.tsx","../src/devtools/client/account/devtools-account.tsx","../src/devtools/client/board/board-tab.tsx","../src/devtools/client/route/use-dev-route.ts","../src/devtools/client/sessions/devtools-sessions.tsx","../src/devtools/client/devtools-layer.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { reportFailure } from \"../notices\";\nimport { startBoardConnect } from \"../route/dev-route\";\n\ntype ConnectState =\n | { kind: \"idle\" }\n | { kind: \"starting\" }\n | { authorizeUrl: string; kind: \"waiting\" };\n\nfunction useBoardConnect(publicKey: string) {\n const [state, setState] = useState<ConnectState>({ kind: \"idle\" });\n\n const connect = async () => {\n // Opened before any await: browsers only allow popups inside the click.\n const tab = window.open(\"\", \"_blank\");\n if (tab) {\n tab.opener = null;\n }\n setState({ kind: \"starting\" });\n try {\n const { authorizeUrl } = await startBoardConnect(publicKey);\n if (tab) {\n tab.location.href = authorizeUrl;\n } else {\n window.open(authorizeUrl, \"_blank\", \"noopener\");\n }\n setState({ authorizeUrl, kind: \"waiting\" });\n } catch (error) {\n tab?.close();\n setState({ kind: \"idle\" });\n reportFailure(\"Could not connect to Reflet\", error);\n }\n };\n return { connect, state };\n}\n\nexport function ConnectFooter({ publicKey }: { publicKey: string }) {\n const { connect, state } = useBoardConnect(publicKey);\n\n if (state.kind === \"waiting\") {\n return (\n <div className=\"dt-sheet-account\" role=\"status\">\n <p className=\"dt-meta\">\n Finish connecting in the Reflet tab. This panel updates when you come\n back.\n </p>\n <div className=\"dt-actions\">\n <a\n className=\"dt-btn\"\n href={state.authorizeUrl}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Open Reflet again\n </a>\n <button className=\"dt-btn\" onClick={connect} type=\"button\">\n Start again\n </button>\n </div>\n </div>\n );\n }\n return (\n <div className=\"dt-sheet-account\">\n <p className=\"dt-meta\">Not connected</p>\n <button\n className=\"dt-btn\"\n data-variant=\"primary\"\n disabled={state.kind === \"starting\"}\n onClick={connect}\n type=\"button\"\n >\n Connect to Reflet\n </button>\n </div>\n );\n}\n","import type { WorkspaceState } from \"../../../sessions/ui/session-workspace\";\nimport { reportFailure } from \"../notices\";\nimport { disconnectBoard } from \"../route/dev-route\";\nimport { CONNECT_REQUIREMENT } from \"../route/route-hint\";\nimport type { DevRouteState } from \"../route/use-dev-route\";\nimport { AccountFooter, AccountNote } from \"./account-footer\";\nimport { ConnectFooter } from \"./connect-footer\";\n\nasync function disconnect(refresh: () => void) {\n try {\n const { revoked } = await disconnectBoard();\n if (!revoked) {\n reportFailure(\n \"The Reflet token was not revoked\",\n new Error(\n \"Disconnected here, but Reflet could not be reached. Revoke it from Account → Devtools on reflet.app.\"\n )\n );\n }\n } catch (error) {\n reportFailure(\"The dev server did not disconnect\", error);\n }\n refresh();\n}\n\nexport function DevtoolsAccount({\n connectKey,\n refresh,\n route,\n workspace,\n}: {\n connectKey: string | null;\n refresh: () => void;\n route: DevRouteState;\n workspace: WorkspaceState;\n}) {\n if (route.kind !== \"ready\") {\n return null;\n }\n const { board } = route.status;\n if (board.kind === \"secretKey\") {\n return <AccountNote>Reaching the board with REFLET_SECRET_KEY</AccountNote>;\n }\n if (board.kind === \"disconnected\") {\n return connectKey === null ? (\n <AccountNote>Not connected. {CONNECT_REQUIREMENT}</AccountNote>\n ) : (\n <ConnectFooter publicKey={connectKey} />\n );\n }\n return (\n <AccountFooter\n actions={[\n {\n label: \"Disconnect\",\n onSelect: () => disconnect(refresh),\n variant: \"danger\",\n },\n ]}\n organizationName={board.organizationName}\n person={\n workspace.kind === \"ready\" ? workspace.workspace.identity.user : null\n }\n />\n );\n}\n","import type { CodeTarget } from \"../code/code-panel\";\nimport { InboxPanel } from \"../inbox/inbox-panel\";\nimport { callReflet } from \"../route/dev-route\";\nimport { MISSING_SECRET_KEY_HINT, MissingRouteHint } from \"../route/route-hint\";\nimport type { DevRouteState } from \"../route/use-dev-route\";\n\nexport function BoardTab({\n canConnect,\n onOpenCode,\n onShowSelector,\n route,\n}: {\n canConnect: boolean;\n onOpenCode: (target: CodeTarget) => void;\n onShowSelector: (selector: string) => boolean;\n route: DevRouteState;\n}) {\n if (route.kind === \"missing\") {\n return (\n <MissingRouteHint purpose=\"see your board's feedback for this page\" />\n );\n }\n if (route.kind === \"checking\") {\n return null;\n }\n if (route.status.board.kind === \"disconnected\") {\n return (\n <p className=\"dt-empty\">\n {canConnect\n ? \"Connect to Reflet below to see this page's feedback and add notes to your board.\"\n : MISSING_SECRET_KEY_HINT}\n </p>\n );\n }\n return (\n <InboxPanel\n boardCall={callReflet}\n onOpenCode={onOpenCode}\n onShowSelector={onShowSelector}\n />\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { DevtoolsStatus } from \"../../protocol\";\nimport { probeDevRoute } from \"./dev-route\";\n\nexport type DevRouteState =\n | { kind: \"checking\" }\n | { kind: \"missing\" }\n | { kind: \"ready\"; status: DevtoolsStatus };\n\n/** Re-probes on window focus so a connection finished in another tab shows up; keeps the last state meanwhile. */\nexport function useDevRoute(): { refresh: () => void; route: DevRouteState } {\n const [route, setRoute] = useState<DevRouteState>({ kind: \"checking\" });\n const latestProbe = useRef(0);\n\n const refresh = useCallback(() => {\n latestProbe.current += 1;\n const probe = latestProbe.current;\n probeDevRoute().then((status) => {\n if (probe === latestProbe.current) {\n setRoute(status ? { kind: \"ready\", status } : { kind: \"missing\" });\n }\n });\n }, []);\n\n useEffect(() => {\n refresh();\n window.addEventListener(\"focus\", refresh);\n return () => {\n window.removeEventListener(\"focus\", refresh);\n latestProbe.current += 1;\n };\n }, [refresh]);\n\n return { refresh, route };\n}\n","import type { ReactNode } from \"react\";\nimport { devtoolsTransport } from \"../../../sessions/api/session-transports\";\nimport {\n SessionWorkspaceProvider,\n useWorkspaceLoader,\n type WorkspaceState,\n} from \"../../../sessions/ui/session-workspace\";\nimport {\n type SessionNavigation,\n SessionsPanel,\n useSessionNavigation,\n} from \"../../../sessions/ui/sessions-panel\";\nimport { CONNECT_REQUIREMENT, MissingRouteHint } from \"../route/route-hint\";\nimport type { DevRouteState } from \"../route/use-dev-route\";\n\nconst DEVTOOLS_TRANSPORT = devtoolsTransport();\n\nexport interface DevtoolsSessions {\n navigation: SessionNavigation;\n state: WorkspaceState;\n}\n\n/** Sessions go through the dev route with the developer's own Connect token, never the secret key. */\nexport function useDevtoolsSessions(options: {\n onUnauthorized: () => void;\n route: DevRouteState;\n}): DevtoolsSessions {\n const { route } = options;\n const isConnected =\n route.kind === \"ready\" && route.status.board.kind === \"connected\";\n const state = useWorkspaceLoader({\n onUnauthorized: options.onUnauthorized,\n surface: \"devtools\",\n transport: isConnected ? DEVTOOLS_TRANSPORT : null,\n });\n return { navigation: useSessionNavigation(), state };\n}\n\nexport function SessionsScope({\n children,\n sessions,\n}: {\n children: ReactNode;\n sessions: DevtoolsSessions;\n}) {\n const workspace =\n sessions.state.kind === \"ready\" ? sessions.state.workspace : null;\n return (\n <SessionWorkspaceProvider workspace={workspace}>\n {children}\n </SessionWorkspaceProvider>\n );\n}\n\nconst SESSIONS_NEED_ACCOUNT =\n \"Sessions are recorded under your Reflet account.\";\n\nfunction WorkspaceGate({\n actions,\n sessions,\n}: {\n actions: SessionsTabActions;\n sessions: DevtoolsSessions;\n}) {\n const { state } = sessions;\n if (state.kind === \"ready\") {\n return (\n <SessionsPanel\n navigation={sessions.navigation}\n onStarted={actions.onStarted}\n onWriteNote={actions.onWriteNote}\n />\n );\n }\n if (state.kind === \"failed\") {\n return (\n <div className=\"dt-empty\" role=\"alert\">\n <p>Sessions did not open: {state.message}</p>\n <button className=\"dt-btn\" onClick={state.retry} type=\"button\">\n Try again\n </button>\n </div>\n );\n }\n return <p className=\"dt-status\">Opening your sessions…</p>;\n}\n\nexport interface SessionsTabActions {\n onStarted: () => void;\n onWriteNote?: () => void;\n}\n\nexport function SessionsTab({\n actions,\n canConnect,\n route,\n sessions,\n}: {\n actions: SessionsTabActions;\n canConnect: boolean;\n route: DevRouteState;\n sessions: DevtoolsSessions;\n}) {\n if (route.kind === \"checking\") {\n return <p className=\"dt-status\">Connecting to the Reflet dev route…</p>;\n }\n if (route.kind === \"missing\") {\n return (\n <MissingRouteHint purpose=\"record sessions under your Reflet account\" />\n );\n }\n const { board } = route.status;\n if (board.kind === \"disconnected\") {\n return (\n <p className=\"dt-empty\">\n {SESSIONS_NEED_ACCOUNT}{\" \"}\n {canConnect\n ? \"Connect to Reflet below to start one.\"\n : CONNECT_REQUIREMENT}\n </p>\n );\n }\n if (board.kind === \"secretKey\") {\n return (\n <p className=\"dt-empty\">\n {SESSIONS_NEED_ACCOUNT} REFLET_SECRET_KEY can't stand for you: remove it\n from the dev server environment, then connect to Reflet.\n </p>\n );\n }\n return <WorkspaceGate actions={actions} sessions={sessions} />;\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { RefletFeedbackProps } from \"../../feedback/types\";\nimport { SelectionOutline } from \"../../feedback/ui/selection-outline\";\nimport { RecordingLayer } from \"../../sessions/ui/recording/recording-layer\";\nimport { sessionSheetPlace } from \"../../sessions/ui/sessions-panel\";\nimport { SESSIONS_STYLES } from \"../../sessions/ui/sessions-styles\";\nimport { DevtoolsAccount } from \"./account/devtools-account\";\nimport { BoardTab } from \"./board/board-tab\";\nimport type { CodeTarget } from \"./code/code-panel\";\nimport { type CodeLookup, CodeTab, useCodeLookup } from \"./code/code-tab\";\nimport {\n DevtoolsBar,\n DevtoolsBarButtons,\n SHEET_TABS,\n type SheetTab,\n} from \"./devtools-bar\";\nimport { DevtoolsSheet } from \"./devtools-sheet\";\nimport { DEVTOOLS_STYLES } from \"./devtools-styles\";\nimport { findOnPage, usePageHighlight } from \"./find-on-page\";\nimport { enrichNote, hasTriedToLocate } from \"./notes/capture-note\";\nimport { NotePicker } from \"./notes/note-picker\";\nimport {\n isActiveNote,\n isNoteOnPage,\n type NotesSnapshot,\n unsentNoteCount,\n useNotes,\n} from \"./notes/note-store\";\nimport { NotesPanel } from \"./notes/notes-panel\";\nimport { Notices } from \"./notices\";\nimport { NotePins } from \"./pins/note-pins\";\nimport { callReflet } from \"./route/dev-route\";\nimport { MISSING_SECRET_KEY_HINT } from \"./route/route-hint\";\nimport { type DevRouteState, useDevRoute } from \"./route/use-dev-route\";\nimport {\n type DevtoolsSessions,\n SessionsScope,\n SessionsTab,\n useDevtoolsSessions,\n} from \"./sessions/devtools-sessions\";\nimport { FIRST_SHEET_TAB, useSheetTab } from \"./use-sheet-tab\";\n\nfunction sendBlockedReason(\n route: DevRouteState,\n canConnect: boolean\n): string | null {\n if (route.kind === \"checking\") {\n return \"Connecting to the Reflet dev route…\";\n }\n if (route.kind === \"missing\") {\n return \"Add the Reflet dev route to add notes to your board.\";\n }\n if (route.status.board.kind !== \"disconnected\") {\n return null;\n }\n return canConnect\n ? \"Connect to Reflet below to add notes to your board.\"\n : MISSING_SECRET_KEY_HINT;\n}\nfunction canConnectBoard(route: DevRouteState, publicKey: string | null) {\n return (\n route.kind === \"ready\" &&\n route.status.board.kind === \"disconnected\" &&\n route.status.board.canConnect &&\n publicKey !== null\n );\n}\n\n/** A reload in the middle of locating left these without a source; finish the job once. */\nfunction useResumeLocating(notes: NotesSnapshot, route: DevRouteState) {\n useEffect(() => {\n if (route.kind === \"checking\") {\n return;\n }\n for (const note of notes.notes) {\n const isUnlocated =\n note.source === null &&\n isActiveNote(note) &&\n notes.activity[note.id] === undefined &&\n !hasTriedToLocate(note.id) &&\n isNoteOnPage(note, window.location.pathname);\n const element = isUnlocated ? findOnPage(note.selection.selector) : null;\n if (element) {\n enrichNote(note.id, element, route.kind === \"ready\").catch(() => null);\n }\n }\n }, [notes, route.kind]);\n}\n\nfunction SheetPanel({\n canConnect,\n codeLookup,\n handlers,\n notes,\n openTab,\n route,\n sessions,\n}: {\n canConnect: boolean;\n codeLookup: CodeLookup | null;\n handlers: {\n onClose: () => void;\n onOpenCode: (target: CodeTarget) => void;\n onPick: () => void;\n onShowSelector: (selector: string) => boolean;\n };\n notes: NotesSnapshot;\n openTab: SheetTab;\n route: DevRouteState;\n sessions: DevtoolsSessions;\n}) {\n if (openTab === \"notes\") {\n return (\n <NotesPanel\n boardCall={callReflet}\n notes={notes}\n onOpenCode={handlers.onOpenCode}\n onPick={handlers.onPick}\n onShowSelector={handlers.onShowSelector}\n sendBlockedReason={sendBlockedReason(route, canConnect)}\n />\n );\n }\n if (openTab === \"inbox\") {\n return (\n <BoardTab\n canConnect={canConnect}\n onOpenCode={handlers.onOpenCode}\n onShowSelector={handlers.onShowSelector}\n route={route}\n />\n );\n }\n if (openTab === \"sessions\") {\n return (\n <SessionsTab\n actions={{\n onStarted: handlers.onClose,\n onWriteNote: () => {\n handlers.onClose();\n handlers.onPick();\n },\n }}\n canConnect={canConnect}\n route={route}\n sessions={sessions}\n />\n );\n }\n return codeLookup && <CodeTab lookup={codeLookup} route={route} />;\n}\n\nexport function DevtoolsLayer({\n isWidgetOpen,\n position,\n publicKey,\n}: {\n isWidgetOpen: boolean;\n position: NonNullable<RefletFeedbackProps[\"position\"]>;\n publicKey: string | null;\n}) {\n const { refresh, route } = useDevRoute();\n const notes = useNotes();\n useResumeLocating(notes, route);\n const sessions = useDevtoolsSessions({ onUnauthorized: refresh, route });\n const [isPicking, setIsPicking] = useState(false);\n const sheet = useSheetTab();\n const { openTab } = sheet;\n const { clearHighlight, highlighted, showSelector } = usePageHighlight();\n const { codeLookup, inspectElement, openCode } = useCodeLookup(sheet.select);\n\n const edge = position.startsWith(\"top\") ? \"top\" : \"bottom\";\n const side = position.endsWith(\"right\") ? \"right\" : \"left\";\n const canReadSource = route.kind === \"ready\";\n const canConnect = canConnectBoard(route, publicKey);\n const isRecessed = isWidgetOpen || isPicking;\n\n const closeSheet = () => {\n sheet.close();\n clearHighlight();\n };\n\n const startPick = useCallback(() => setIsPicking(true), []);\n const cancelPick = useCallback(() => setIsPicking(false), []);\n\n const inspect = useMemo(\n () => ({\n label: \"Code\",\n onInspect: (element: Element) => {\n setIsPicking(false);\n inspectElement(element);\n },\n }),\n [inspectElement]\n );\n\n const tabs = SHEET_TABS.filter((tab) => tab !== \"code\" || codeLookup);\n const openPanel = (tab: SheetTab | null) =>\n sheet.select(\n tab ?? (tabs.includes(sheet.lastTab) ? sheet.lastTab : FIRST_SHEET_TAB)\n );\n const sheetPlace =\n openTab === \"sessions\" && sessions.state.kind === \"ready\"\n ? sessionSheetPlace(sessions.navigation)\n : null;\n\n return (\n <SessionsScope sessions={sessions}>\n <div\n className=\"dt\"\n data-recessed={isRecessed}\n data-sheet-open={openTab !== null}\n >\n <style>{`${DEVTOOLS_STYLES}${SESSIONS_STYLES}`}</style>\n <NotePins isVisible={!isRecessed} notes={notes} onOpenCode={openCode} />\n {openTab && (\n <DevtoolsSheet\n footer={\n sheetPlace === null && (\n <DevtoolsAccount\n connectKey={canConnect ? publicKey : null}\n refresh={refresh}\n route={route}\n workspace={sessions.state}\n />\n )\n }\n navigation={{\n onSelectTab: sheet.select,\n place: sheetPlace,\n tab: openTab,\n tabs,\n }}\n onClose={closeSheet}\n side={side}\n >\n <SheetPanel\n canConnect={canConnect}\n codeLookup={codeLookup}\n handlers={{\n onClose: closeSheet,\n onOpenCode: openCode,\n onPick: startPick,\n onShowSelector: showSelector,\n }}\n notes={notes}\n openTab={openTab}\n route={route}\n sessions={sessions}\n />\n </DevtoolsSheet>\n )}\n <DevtoolsBar edge={edge} side={side}>\n <DevtoolsBarButtons\n canOpenCode\n onOpen={openPanel}\n onPick={startPick}\n unsentNoteCount={unsentNoteCount(notes)}\n />\n </DevtoolsBar>\n {openTab && <SelectionOutline node={highlighted} />}\n <Notices />\n {sessions.state.kind === \"ready\" && (\n <RecordingLayer\n onFinished={(target) => {\n sessions.navigation.go({ target, view: \"review\" });\n sheet.select(\"sessions\");\n }}\n />\n )}\n {isPicking && (\n <NotePicker\n canReadSource={canReadSource}\n inspect={inspect}\n onDone={cancelPick}\n />\n )}\n </div>\n </SessionsScope>\n );\n}\n"],"mappings":"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"}
|
package/dist/devtools-next.js
CHANGED
package/dist/devtools-vite.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { r as DEVTOOLS_ROUTE_BASE } from "./protocol-
|
|
2
|
-
import { h as isLoopbackAddress, v as errorResponse } from "./reflet-proxy-
|
|
3
|
-
import { t as createDevtoolsHandler } from "./handler-
|
|
1
|
+
import { r as DEVTOOLS_ROUTE_BASE } from "./protocol-P5T66Bs3.js";
|
|
2
|
+
import { h as isLoopbackAddress, v as errorResponse } from "./reflet-proxy-CiMPGYzD.js";
|
|
3
|
+
import { t as createDevtoolsHandler } from "./handler-BX8ITlGZ.js";
|
|
4
4
|
import { loadEnv } from "vite";
|
|
5
5
|
//#region src/devtools/server/vite.ts
|
|
6
6
|
const MAX_BODY_BYTES = 1048576;
|
package/dist/feedback.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { n as Reflet } from "./client-oFFfRxAM.js";
|
|
3
|
-
import { A as PencilIcon, B as DEFAULT_WIDGET_LABELS, C as CheckIcon, D as GripIcon, F as TextIcon, G as buildElementSelection, I as TrashIcon, L as UndoIcon, M as SquareIcon, O as HighlightIcon, P as TargetIcon, R as isDegenerate, S as ChatIcon, T as CloseIcon, U as collectPageContext, V as SDK_VERSION, W as MAX_SELECTION_COMMENT_LENGTH, X as maskSecrets, _ as isSubmitEnter, at as capturedViewportSize, b as BlurIcon, c as useFloatingPosition, d as SelectionOutline, f as drawAnnotations, g as stopClicksAtHost, i as submitWidgetFeedback, j as SpotlightIcon, k as MoreIcon, m as listenToKeydown, n as createFeedbackTransport, nt as WIDGET_MARKER, o as ElementPicker, ot as releaseCapture, p as listenOnPageAndWidget, rt as captureViewport, t as attachPreparedScreenshots, v as matchesHotkey, w as ChevronDownIcon, x as CameraIcon, y as ArrowIcon, z as normalizeRect } from "./submit-
|
|
3
|
+
import { A as PencilIcon, B as DEFAULT_WIDGET_LABELS, C as CheckIcon, D as GripIcon, F as TextIcon, G as buildElementSelection, I as TrashIcon, L as UndoIcon, M as SquareIcon, O as HighlightIcon, P as TargetIcon, R as isDegenerate, S as ChatIcon, T as CloseIcon, U as collectPageContext, V as SDK_VERSION, W as MAX_SELECTION_COMMENT_LENGTH, X as maskSecrets, _ as isSubmitEnter, at as capturedViewportSize, b as BlurIcon, c as useFloatingPosition, d as SelectionOutline, f as drawAnnotations, g as stopClicksAtHost, i as submitWidgetFeedback, j as SpotlightIcon, k as MoreIcon, m as listenToKeydown, n as createFeedbackTransport, nt as WIDGET_MARKER, o as ElementPicker, ot as releaseCapture, p as listenOnPageAndWidget, rt as captureViewport, t as attachPreparedScreenshots, v as matchesHotkey, w as ChevronDownIcon, x as CameraIcon, y as ArrowIcon, z as normalizeRect } from "./submit-CqeMuBPt.js";
|
|
4
4
|
import { t as RefletContext } from "./react-context-Kazo_JCz.js";
|
|
5
5
|
import { n as hasTeamActivation } from "./team-activation-Cv5U7OF1.js";
|
|
6
6
|
import { t as REFLET_Z_INDEX } from "./z-index-CwokqVq_.js";
|
|
@@ -2303,7 +2303,7 @@ function useWidgetState(props) {
|
|
|
2303
2303
|
setStep("compose");
|
|
2304
2304
|
return submission.submit({
|
|
2305
2305
|
context: {
|
|
2306
|
-
...activeScreenshot?.context ?? collectPageContext({ sdkVersion: "0.7.
|
|
2306
|
+
...activeScreenshot?.context ?? collectPageContext({ sdkVersion: "0.7.12" }),
|
|
2307
2307
|
consoleEvents: consoleRef.current?.events(),
|
|
2308
2308
|
metadata: props.metadata,
|
|
2309
2309
|
selections
|
|
@@ -2369,8 +2369,8 @@ function useWidgetState(props) {
|
|
|
2369
2369
|
}
|
|
2370
2370
|
//#endregion
|
|
2371
2371
|
//#region src/feedback/widget.tsx
|
|
2372
|
-
const DevtoolsLayer = process.env.NODE_ENV === "development" ? lazy(() => import("./devtools-layer-
|
|
2373
|
-
const TeamLayer = lazy(() => import("./team-layer-
|
|
2372
|
+
const DevtoolsLayer = process.env.NODE_ENV === "development" ? lazy(() => import("./devtools-layer-CSEp-eZw.js").then((module) => ({ default: module.DevtoolsLayer }))) : null;
|
|
2373
|
+
const TeamLayer = lazy(() => import("./team-layer-BdytvHiG.js").then((module) => ({ default: module.TeamLayer })));
|
|
2374
2374
|
const DEFAULT_APP_URL = "https://www.reflet.app";
|
|
2375
2375
|
const ignoreChanges = () => () => void 0;
|
|
2376
2376
|
/** Activation reads the URL and storage, which only exist in the browser: the server renders without team tools. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as DEVTOOLS_STATUS_MARKER, r as DEVTOOLS_ROUTE_BASE, t as DEVTOOLS_ENDPOINTS } from "./protocol-
|
|
2
|
-
import { _ as rejectUntrustedHost, b as jsonResponse, c as finishConnect, d as startConnect, g as rejectUntrustedCaller, n as boardAccess, r as resolveDevtoolsOptions, s as disconnect, t as proxyWithBoardCredential, v as errorResponse, y as failure } from "./reflet-proxy-
|
|
1
|
+
import { i as DEVTOOLS_STATUS_MARKER, r as DEVTOOLS_ROUTE_BASE, t as DEVTOOLS_ENDPOINTS } from "./protocol-P5T66Bs3.js";
|
|
2
|
+
import { _ as rejectUntrustedHost, b as jsonResponse, c as finishConnect, d as startConnect, g as rejectUntrustedCaller, n as boardAccess, r as resolveDevtoolsOptions, s as disconnect, t as proxyWithBoardCredential, v as errorResponse, y as failure } from "./reflet-proxy-CiMPGYzD.js";
|
|
3
3
|
import { SourceMap } from "node:module";
|
|
4
4
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
5
5
|
import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -594,4 +594,4 @@ function createDevtoolsHandler(options = {}, env = process.env) {
|
|
|
594
594
|
//#endregion
|
|
595
595
|
export { createDevtoolsHandler as t };
|
|
596
596
|
|
|
597
|
-
//# sourceMappingURL=handler-
|
|
597
|
+
//# sourceMappingURL=handler-BX8ITlGZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler-D8c3woEz.js","names":["QUERY_OR_HASH"],"sources":["../src/devtools/server/source/code-search.ts","../src/devtools/server/source/project-roots.ts","../src/devtools/server/source/jsx-range.ts","../src/devtools/server/source/workspace-path.ts","../src/devtools/server/source/server-frame.ts","../src/devtools/server/source/source-file.ts","../src/devtools/server/handler.ts"],"sourcesContent":["import { type ExecFileException, execFile } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport type { CodeMatch, CodeSearchResult } from \"../../protocol\";\nimport { type DevtoolsOutcome, failure } from \"../json-response\";\n\nconst MIN_QUERY_LENGTH = 2;\nconst MAX_QUERY_LENGTH = 200;\nconst MAX_MATCHES = 20;\nconst PREVIEW_LENGTH = 160;\nconst PREVIEW_LEAD = 40;\nconst SEARCH_TIMEOUT_MS = 4000;\nconst MAX_OUTPUT_BYTES = 1_048_576;\nconst NO_MATCHES_EXIT_CODE = 1;\nconst NOT_A_REPOSITORY_EXIT_CODE = 128;\nconst SEARCHED_FILES = [\n \"*.tsx\",\n \"*.jsx\",\n \"*.ts\",\n \"*.js\",\n \"*.vue\",\n \"*.svelte\",\n \"*.astro\",\n \"*.mdx\",\n];\nconst LINE_BREAK = /[\\r\\n]/;\n\ninterface GitGrepRun {\n error: ExecFileException | null;\n stdout: string;\n}\n\nfunction runGitGrep(workspaceRoot: string, query: string): Promise<GitGrepRun> {\n const args = [\n \"grep\",\n \"-n\",\n \"-z\",\n \"-I\",\n \"-F\",\n \"--no-color\",\n \"--untracked\",\n \"-e\",\n query,\n \"--\",\n ...SEARCHED_FILES,\n ];\n return new Promise((resolveRun) => {\n execFile(\n \"git\",\n args,\n {\n cwd: workspaceRoot,\n encoding: \"utf8\",\n maxBuffer: MAX_OUTPUT_BYTES,\n timeout: SEARCH_TIMEOUT_MS,\n },\n (error, stdout) => resolveRun({ error, stdout })\n );\n });\n}\n\nfunction previewLine(content: string, query: string): string {\n const text = content.trim();\n if (text.length <= PREVIEW_LENGTH) {\n return text;\n }\n const matchIndex = text.indexOf(query);\n const start = Math.max(\n 0,\n Math.min(matchIndex - PREVIEW_LEAD, text.length - PREVIEW_LENGTH)\n );\n const end = start + PREVIEW_LENGTH;\n const head = start > 0 ? \"…\" : \"\";\n const tail = end < text.length ? \"…\" : \"\";\n return `${head}${text.slice(start, end)}${tail}`;\n}\n\nfunction parseMatches(\n stdout: string,\n workspaceRoot: string,\n query: string\n): CodeMatch[] {\n const matches: CodeMatch[] = [];\n for (const record of stdout.split(\"\\n\")) {\n const [path, lineText, content] = record.split(\"\\0\");\n const line = Number(lineText);\n const isComplete =\n path !== undefined && content !== undefined && Number.isInteger(line);\n if (isComplete && !path.split(\"/\").includes(\"node_modules\")) {\n matches.push({\n absolutePath: join(workspaceRoot, path),\n line,\n path,\n preview: previewLine(content, query),\n });\n if (matches.length === MAX_MATCHES) {\n break;\n }\n }\n }\n return matches;\n}\n\nfunction describeGitFailure(error: ExecFileException): DevtoolsOutcome<never> {\n if (error.code === \"ENOENT\") {\n return failure(\"Code search needs git installed on the dev server.\", 503);\n }\n if (error.code === NOT_A_REPOSITORY_EXIT_CODE) {\n return failure(\n \"Code search needs the app to live in a git repository.\",\n 503\n );\n }\n if (error.killed) {\n return failure(\"Code search timed out.\", 504);\n }\n return failure(`Code search failed: ${error.message}`, 500);\n}\n\nexport async function searchCode(\n workspaceRoot: string,\n rawQuery: string\n): Promise<DevtoolsOutcome<CodeSearchResult>> {\n const query = rawQuery.trim();\n if (query.length < MIN_QUERY_LENGTH || query.length > MAX_QUERY_LENGTH) {\n return failure(\n `Search for ${MIN_QUERY_LENGTH} to ${MAX_QUERY_LENGTH} characters.`,\n 400\n );\n }\n if (LINE_BREAK.test(query)) {\n return failure(\"Search for a single line of text.\", 400);\n }\n\n const { error, stdout } = await runGitGrep(workspaceRoot, query);\n const matches = parseMatches(stdout, workspaceRoot, query);\n const hasNoMatches = error?.code === NO_MATCHES_EXIT_CODE;\n if (!error || hasNoMatches || matches.length > 0) {\n return { ok: true, value: { matches } };\n }\n return describeGitFailure(error);\n}\n","import { existsSync, realpathSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\n\nexport interface ProjectRoots {\n /** The app directory, where the dev server runs. */\n root: string;\n /** Nearest ancestor of the app directory holding `.git`, else the app directory. */\n workspaceRoot: string;\n}\n\nexport function resolveProjectRoots(appRoot: string): ProjectRoots {\n const resolvedRoot = resolve(appRoot);\n const root = existsSync(resolvedRoot)\n ? realpathSync(resolvedRoot)\n : resolvedRoot;\n\n for (let directory = root; ; directory = dirname(directory)) {\n if (existsSync(join(directory, \".git\"))) {\n return { root, workspaceRoot: directory };\n }\n if (dirname(directory) === directory) {\n return { root, workspaceRoot: root };\n }\n }\n}\n","import type { LineRange } from \"../../protocol\";\n\nconst FAILED = -1;\nconst MAX_TAG_LOOKBACK = 2;\nconst TAG_NAME_START = /[A-Za-z_$]/;\nconst TAG_NAME_CHAR = /[\\w$.:-]/;\nconst IDENTIFIER_CHAR = /[\\w$]/;\nconst WHITESPACE = /\\s/;\nconst JSX_EXPRESSION_LEAD = /[([{,;=?:&|!>]/;\nconst JSX_KEYWORD_LEADS = [\"return\", \"yield\", \"default\", \"await\"];\n\ninterface OpeningTag {\n end: number;\n name: string;\n selfClosing: boolean;\n}\n\nfunction isTagStart(code: string, index: number): boolean {\n if (code.charAt(index) !== \"<\") {\n return false;\n }\n const next = code.charAt(index + 1);\n return next === \">\" || TAG_NAME_START.test(next);\n}\n\nfunction startsJsxInExpression(code: string, index: number): boolean {\n let cursor = index - 1;\n while (cursor >= 0 && WHITESPACE.test(code.charAt(cursor))) {\n cursor -= 1;\n }\n if (cursor < 0) {\n return true;\n }\n const previous = code.charAt(cursor);\n if (JSX_EXPRESSION_LEAD.test(previous)) {\n return true;\n }\n let wordStart = cursor;\n while (wordStart > 0 && IDENTIFIER_CHAR.test(code.charAt(wordStart - 1))) {\n wordStart -= 1;\n }\n return JSX_KEYWORD_LEADS.includes(code.slice(wordStart, cursor + 1));\n}\n\nfunction skipJsString(code: string, index: number): number {\n const quote = code.charAt(index);\n let cursor = index + 1;\n while (cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"\\\\\") {\n cursor += 2;\n } else if (char === quote) {\n return cursor + 1;\n } else if (char === \"\\n\") {\n return index + 1;\n } else {\n cursor += 1;\n }\n }\n return index + 1;\n}\n\nfunction skipTemplate(code: string, index: number): number {\n let cursor = index + 1;\n while (cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"\\\\\") {\n cursor += 2;\n } else if (char === \"`\") {\n return cursor + 1;\n } else if (char === \"$\" && code.charAt(cursor + 1) === \"{\") {\n cursor = skipJsExpression(code, cursor + 1);\n if (cursor === FAILED) {\n return FAILED;\n }\n } else {\n cursor += 1;\n }\n }\n return FAILED;\n}\n\nfunction skipJsToken(code: string, index: number): number {\n const char = code.charAt(index);\n const next = code.charAt(index + 1);\n if (char === '\"' || char === \"'\") {\n return skipJsString(code, index);\n }\n if (char === \"`\") {\n return skipTemplate(code, index);\n }\n if (char === \"/\" && next === \"/\") {\n const lineEnd = code.indexOf(\"\\n\", index);\n return lineEnd === -1 ? code.length : lineEnd;\n }\n if (char === \"/\" && next === \"*\") {\n const commentEnd = code.indexOf(\"*/\", index + 2);\n return commentEnd === -1 ? FAILED : commentEnd + 2;\n }\n if (isTagStart(code, index) && startsJsxInExpression(code, index)) {\n return skipElement(code, index);\n }\n return index + 1;\n}\n\nfunction skipJsExpression(code: string, index: number): number {\n let depth = 0;\n let cursor = index;\n while (cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"{\" || char === \"}\") {\n depth += char === \"{\" ? 1 : -1;\n cursor += 1;\n if (depth === 0) {\n return cursor;\n }\n } else {\n cursor = skipJsToken(code, cursor);\n if (cursor === FAILED) {\n return FAILED;\n }\n }\n }\n return FAILED;\n}\n\nfunction skipTypeArguments(code: string, index: number): number {\n let depth = 0;\n for (let cursor = index; cursor < code.length; cursor += 1) {\n const char = code.charAt(cursor);\n if (char === \"<\") {\n depth += 1;\n } else if (char === \">\") {\n depth -= 1;\n if (depth === 0) {\n return cursor + 1;\n }\n }\n }\n return FAILED;\n}\n\nfunction skipAttributeToken(code: string, index: number): number {\n const char = code.charAt(index);\n if (char === \"{\") {\n return skipJsExpression(code, index);\n }\n if (char === '\"' || char === \"'\") {\n const closingQuote = code.indexOf(char, index + 1);\n return closingQuote === -1 ? FAILED : closingQuote + 1;\n }\n return index + 1;\n}\n\nfunction readTagName(code: string, index: number): number {\n let cursor = index;\n while (TAG_NAME_CHAR.test(code.charAt(cursor))) {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction readOpeningTag(code: string, index: number): OpeningTag | null {\n const nameEnd = readTagName(code, index + 1);\n const name = code.slice(index + 1, nameEnd);\n let cursor =\n code.charAt(nameEnd) === \"<\" ? skipTypeArguments(code, nameEnd) : nameEnd;\n\n while (cursor !== FAILED && cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \">\") {\n return { end: cursor + 1, name, selfClosing: false };\n }\n if (char === \"/\" && code.charAt(cursor + 1) === \">\") {\n return { end: cursor + 2, name, selfClosing: true };\n }\n cursor = skipAttributeToken(code, cursor);\n }\n return null;\n}\n\nfunction readClosingTagEnd(code: string, index: number, name: string): number {\n let cursor = index + 2;\n while (WHITESPACE.test(code.charAt(cursor))) {\n cursor += 1;\n }\n const nameEnd = readTagName(code, cursor);\n if (code.slice(cursor, nameEnd) !== name) {\n return FAILED;\n }\n cursor = nameEnd;\n while (WHITESPACE.test(code.charAt(cursor))) {\n cursor += 1;\n }\n return code.charAt(cursor) === \">\" ? cursor + 1 : FAILED;\n}\n\nfunction skipChildren(code: string, index: number, name: string): number {\n let cursor = index;\n while (cursor !== FAILED && cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"<\" && code.charAt(cursor + 1) === \"/\") {\n return readClosingTagEnd(code, cursor, name);\n }\n if (char === \"{\") {\n cursor = skipJsExpression(code, cursor);\n } else if (isTagStart(code, cursor)) {\n cursor = skipElement(code, cursor);\n } else {\n cursor += 1;\n }\n }\n return FAILED;\n}\n\nfunction skipElement(code: string, index: number): number {\n const tag = readOpeningTag(code, index);\n if (!tag) {\n return FAILED;\n }\n return tag.selfClosing ? tag.end : skipChildren(code, tag.end, tag.name);\n}\n\nfunction lineOffset(code: string, line: number): number {\n if (!Number.isInteger(line) || line < 1) {\n return FAILED;\n }\n let offset = 0;\n for (let current = 1; current < line; current += 1) {\n const newline = code.indexOf(\"\\n\", offset);\n if (newline === -1) {\n return FAILED;\n }\n offset = newline + 1;\n }\n return offset;\n}\n\nfunction findTagStart(\n code: string,\n lineStart: number,\n lineEnd: number,\n column: number\n): number {\n const origin = Math.min(lineStart + Math.max(column, 0), lineEnd);\n for (let back = 0; back <= MAX_TAG_LOOKBACK; back += 1) {\n const candidate = origin - back;\n if (candidate >= lineStart && isTagStart(code, candidate)) {\n return candidate;\n }\n }\n for (let candidate = origin + 1; candidate < lineEnd; candidate += 1) {\n if (isTagStart(code, candidate)) {\n return candidate;\n }\n }\n return FAILED;\n}\n\nfunction countNewlines(code: string, from: number, to: number): number {\n let count = 0;\n let newline = code.indexOf(\"\\n\", from);\n while (newline !== -1 && newline < to) {\n count += 1;\n newline = code.indexOf(\"\\n\", newline + 1);\n }\n return count;\n}\n\n/** Lines spanned by the JSX element at a 1-based line and 0-based column. */\nexport function jsxElementLines(\n code: string,\n line: number,\n column: number\n): LineRange | null {\n const lineStart = lineOffset(code, line);\n if (lineStart === FAILED) {\n return null;\n }\n const newline = code.indexOf(\"\\n\", lineStart);\n const lineEnd = newline === -1 ? code.length : newline;\n const tagStart = findTagStart(code, lineStart, lineEnd, column);\n if (tagStart === FAILED) {\n return null;\n }\n const elementEnd = skipElement(code, tagStart);\n if (elementEnd === FAILED) {\n return null;\n }\n return {\n end: line + countNewlines(code, tagStart, elementEnd - 1),\n start: line,\n };\n}\n","import { isAbsolute, relative, sep } from \"node:path\";\n\n/** Forward-slash path from the workspace root, or null when `realPath` escapes it (including another Windows drive). */\nexport function workspaceRelativePath(\n realPath: string,\n workspaceRoot: string\n): string | null {\n const relativePath = relative(workspaceRoot, realPath);\n const escapes =\n relativePath === \"\" ||\n relativePath === \"..\" ||\n relativePath.startsWith(`..${sep}`) ||\n isAbsolute(relativePath);\n return escapes ? null : relativePath.split(sep).join(\"/\");\n}\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { SourceMap } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { type DevtoolsOutcome, failure } from \"../json-response\";\nimport type { SourceRequest } from \"./source-file\";\nimport { workspaceRelativePath } from \"./workspace-path\";\n\nconst SERVER_FRAME_PREFIX = /^(?:about|rsc):\\/\\/React\\/Server\\//;\nconst QUERY_OR_HASH = /[?#].*$/;\nconst SOURCE_MAPPING_URL = /\\/\\/# sourceMappingURL=(\\S+)\\s*$/;\nconst MAX_MAP_BYTES = 50 * 1_048_576;\n\nconst mapCache = new Map<string, { map: SourceMap; mtimeMs: number }>();\n\nexport function isServerFrame(fileName: string): boolean {\n return SERVER_FRAME_PREFIX.test(fileName);\n}\n\nasync function mapPathFor(chunkPath: string): Promise<string> {\n const code = await readFile(chunkPath, \"utf8\");\n const declared = SOURCE_MAPPING_URL.exec(code)?.[1];\n return declared\n ? join(dirname(chunkPath), decodeURIComponent(declared))\n : `${chunkPath}.map`;\n}\n\nasync function loadMap(mapPath: string): Promise<SourceMap> {\n const { mtimeMs, size } = await stat(mapPath);\n if (size > MAX_MAP_BYTES) {\n throw new Error(\"source map too large\");\n }\n const cached = mapCache.get(mapPath);\n if (cached?.mtimeMs === mtimeMs) {\n return cached.map;\n }\n const map = new SourceMap(JSON.parse(await readFile(mapPath, \"utf8\")));\n mapCache.set(mapPath, { map, mtimeMs });\n return map;\n}\n\n/**\n * Server Components stamp their elements with frames into the dev server's\n * own chunks (`about://React/Server/file:///…/.next/…`); the browser cannot\n * fetch those maps, so they are resolved here from disk.\n */\nexport async function mapServerFrame(\n request: SourceRequest,\n workspaceRoot: string\n): Promise<DevtoolsOutcome<SourceRequest>> {\n const unreadable = failure<SourceRequest>(\n \"This element comes from a Server Component whose source map could not be read.\",\n 404\n );\n if (request.line === null) {\n return unreadable;\n }\n try {\n const chunkUrl = request.fileName\n .replace(SERVER_FRAME_PREFIX, \"\")\n .replace(QUERY_OR_HASH, \"\");\n const chunkPath = await realpath(fileURLToPath(chunkUrl));\n if (workspaceRelativePath(chunkPath, workspaceRoot) === null) {\n return failure<SourceRequest>(\n \"Reflet devtools only reads files inside your repository.\",\n 403\n );\n }\n const map = await loadMap(await mapPathFor(chunkPath));\n const origin = map.findOrigin(request.line, (request.column ?? 0) + 1);\n if (!(\"fileName\" in origin)) {\n return unreadable;\n }\n return {\n ok: true,\n value: {\n column: origin.columnNumber - 1,\n fileName: origin.fileName,\n line: origin.lineNumber,\n },\n };\n } catch {\n return unreadable;\n }\n}\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { extname, isAbsolute, join } from \"node:path\";\nimport type { SourceFile } from \"../../protocol\";\nimport { type DevtoolsOutcome, failure } from \"../json-response\";\nimport { jsxElementLines } from \"./jsx-range\";\nimport type { ProjectRoots } from \"./project-roots\";\nimport { isServerFrame, mapServerFrame } from \"./server-frame\";\nimport { workspaceRelativePath } from \"./workspace-path\";\n\nconst MAX_SOURCE_BYTES = 1_048_576;\nconst MAX_FILE_NAME_LENGTH = 2048;\nconst MAX_NORMALIZE_PASSES = 8;\nconst SOURCE_EXTENSIONS = [\n \".astro\",\n \".cjs\",\n \".js\",\n \".jsx\",\n \".mdx\",\n \".mjs\",\n \".svelte\",\n \".ts\",\n \".tsx\",\n \".vue\",\n];\nconst EXTENSION_REFUSAL = `Reflet devtools only reads source files (${SOURCE_EXTENSIONS.join(\", \")}).`;\nconst OUTSIDE_WORKSPACE_REFUSAL =\n \"Reflet devtools only reads files inside your repository.\";\nconst NODE_MODULES_REFUSAL =\n \"Reflet devtools does not read files inside node_modules.\";\nconst QUERY_OR_HASH = /[?#].*$/;\nconst TURBOPACK_MODULE_SUFFIX = /(?: \\[[\\w-]+\\])+(?: \\([\\w-]+\\))*$/;\nconst URL_PREFIXES = [/^file:\\/\\//, /^https?:\\/\\/[^/]*/];\nconst SLASH_BEFORE_DRIVE = /^\\/(?=[a-z]:[\\\\/])/i;\nconst BUNDLER_PREFIXES = [\n /^rsc:\\/\\/React\\/[^/]+\\//,\n /^webpack-internal:\\/{2,}/,\n /^webpack:\\/\\/[^/]*\\//,\n /^turbopack:\\/{2,}/,\n /^\\[project\\]\\//,\n /^\\(app-pages-browser\\)\\//,\n /^\\([\\w-]+\\)\\/(?=\\.\\/)/,\n /^\\/@fs(?=\\/)/,\n /^\\.\\//,\n];\n\ninterface LocatedFile {\n realPath: string;\n relativePath: string;\n size: number;\n}\n\ntype CandidateCheck =\n | ({ kind: \"found\" } & LocatedFile)\n | { kind: \"missing\" }\n | { kind: \"refused\"; reason: string };\n\nexport interface SourceRequest {\n column: number | null;\n fileName: string;\n line: number | null;\n}\n\nfunction decodePath(path: string): string {\n try {\n return decodeURIComponent(path);\n } catch {\n return path;\n }\n}\n\nfunction stripFirstPrefix(fileName: string, prefixes: RegExp[]): string {\n for (const prefix of prefixes) {\n if (prefix.test(fileName)) {\n return fileName.replace(prefix, \"\");\n }\n }\n return fileName;\n}\n\n/** Turns a file name from a React debug stack into a filesystem path. */\nexport function normalizeSourceFileName(rawFileName: string): string {\n let fileName = rawFileName\n .trim()\n .replace(QUERY_OR_HASH, \"\")\n .replace(TURBOPACK_MODULE_SUFFIX, \"\");\n let isUrlEncoded = false;\n\n for (let pass = 0; pass < MAX_NORMALIZE_PASSES; pass += 1) {\n const withoutUrl = stripFirstPrefix(fileName, URL_PREFIXES);\n isUrlEncoded ||= withoutUrl !== fileName;\n const stripped = stripFirstPrefix(withoutUrl, BUNDLER_PREFIXES);\n if (stripped === fileName) {\n break;\n }\n fileName = stripped;\n }\n\n const path = isUrlEncoded ? decodePath(fileName) : fileName;\n return path.replace(SLASH_BEFORE_DRIVE, \"\");\n}\n\nfunction candidatePaths(fileName: string, roots: ProjectRoots): string[] {\n const candidates = [\n join(roots.root, fileName),\n join(roots.workspaceRoot, fileName),\n ];\n if (isAbsolute(fileName)) {\n candidates.unshift(fileName);\n }\n return [...new Set(candidates)];\n}\n\nfunction isSourceExtension(path: string): boolean {\n return SOURCE_EXTENSIONS.includes(extname(path).toLowerCase());\n}\n\nasync function checkCandidate(\n candidate: string,\n workspaceRoot: string\n): Promise<CandidateCheck> {\n let realPath: string;\n let size: number;\n try {\n realPath = await realpath(candidate);\n const stats = await stat(realPath);\n if (!stats.isFile()) {\n return { kind: \"missing\" };\n }\n size = stats.size;\n } catch {\n return { kind: \"missing\" };\n }\n\n const relativePath = workspaceRelativePath(realPath, workspaceRoot);\n if (relativePath === null) {\n return { kind: \"refused\", reason: OUTSIDE_WORKSPACE_REFUSAL };\n }\n if (relativePath.split(\"/\").includes(\"node_modules\")) {\n return { kind: \"refused\", reason: NODE_MODULES_REFUSAL };\n }\n if (!isSourceExtension(realPath)) {\n return { kind: \"refused\", reason: EXTENSION_REFUSAL };\n }\n return { kind: \"found\", realPath, relativePath, size };\n}\n\nasync function locateSourceFile(\n fileName: string,\n roots: ProjectRoots\n): Promise<DevtoolsOutcome<LocatedFile>> {\n let refusal: string | null = null;\n for (const candidate of candidatePaths(fileName, roots)) {\n const check = await checkCandidate(candidate, roots.workspaceRoot);\n if (check.kind === \"found\") {\n return { ok: true, value: check };\n }\n if (check.kind === \"refused\") {\n refusal ??= check.reason;\n }\n }\n if (refusal) {\n return failure(refusal, 403);\n }\n return failure(`Could not find ${fileName} in ${roots.workspaceRoot}.`, 404);\n}\n\n/** Server-map columns can point past the line; the element then starts at its first tag. */\nfunction columnWithinLine(code: string, line: number, column: number | null) {\n const text = code.split(\"\\n\")[line - 1] ?? \"\";\n return column !== null && column < text.length ? column : null;\n}\n\nexport async function readSourceFile(\n frame: SourceRequest,\n roots: ProjectRoots\n): Promise<DevtoolsOutcome<SourceFile>> {\n if (\n frame.fileName.length > MAX_FILE_NAME_LENGTH ||\n frame.fileName.includes(\"\\0\")\n ) {\n return failure(\"That source file name is not a valid path.\", 400);\n }\n const mapped = isServerFrame(frame.fileName)\n ? await mapServerFrame(frame, roots.workspaceRoot)\n : { ok: true as const, value: frame };\n if (!mapped.ok) {\n return mapped;\n }\n const request = mapped.value;\n const fileName = normalizeSourceFileName(request.fileName);\n if (!fileName) {\n return failure(\"A source file name is required.\", 400);\n }\n if (!isSourceExtension(fileName)) {\n return failure(EXTENSION_REFUSAL, 403);\n }\n\n const located = await locateSourceFile(fileName, roots);\n if (!located.ok) {\n return located;\n }\n const { realPath, relativePath, size } = located.value;\n if (size > MAX_SOURCE_BYTES) {\n return failure(\n `${relativePath} is larger than 1 MB, too big to preview.`,\n 413\n );\n }\n\n const code = await readFile(realPath, \"utf8\");\n const column =\n request.line === null\n ? request.column\n : columnWithinLine(code, request.line, request.column);\n const elementLines =\n request.line === null\n ? null\n : jsxElementLines(code, request.line, column ?? 0);\n\n return {\n ok: true,\n value: {\n absolutePath: realPath,\n code,\n column,\n elementLines,\n line: request.line,\n path: relativePath,\n },\n };\n}\n","import {\n DEVTOOLS_ENDPOINTS,\n DEVTOOLS_ROUTE_BASE,\n DEVTOOLS_STATUS_MARKER,\n type DevtoolsStatus,\n} from \"../protocol\";\nimport { boardAccess } from \"./connect/board-credential\";\nimport {\n disconnect,\n finishConnect,\n startConnect,\n} from \"./connect/connect-routes\";\nimport {\n type DevtoolsOutcome,\n errorResponse,\n jsonResponse,\n} from \"./json-response\";\nimport {\n type DevtoolsEnv,\n type DevtoolsServerOptions,\n type ResolvedDevtoolsOptions,\n resolveDevtoolsOptions,\n} from \"./options\";\nimport { proxyWithBoardCredential } from \"./reflet-proxy\";\nimport { rejectUntrustedCaller, rejectUntrustedHost } from \"./request-guard\";\nimport { searchCode } from \"./source/code-search\";\nimport { type ProjectRoots, resolveProjectRoots } from \"./source/project-roots\";\nimport { readSourceFile } from \"./source/source-file\";\n\nexport type DevtoolsHandler = (request: Request) => Promise<Response>;\n\nconst TRAILING_SLASHES = /\\/+$/;\n\nconst ENDPOINT_METHODS: Record<string, \"GET\" | \"POST\"> = {\n [DEVTOOLS_ENDPOINTS.connectCallback]: \"GET\",\n [DEVTOOLS_ENDPOINTS.connectStart]: \"POST\",\n [DEVTOOLS_ENDPOINTS.disconnect]: \"POST\",\n [DEVTOOLS_ENDPOINTS.search]: \"GET\",\n [DEVTOOLS_ENDPOINTS.source]: \"GET\",\n [DEVTOOLS_ENDPOINTS.status]: \"GET\",\n};\n\nfunction outcomeResponse<T>(outcome: DevtoolsOutcome<T>): Response {\n return outcome.ok\n ? jsonResponse(outcome.value)\n : errorResponse(outcome.error, outcome.status);\n}\n\nfunction routeSubPath(pathname: string): string | null {\n const baseIndex = pathname.indexOf(DEVTOOLS_ROUTE_BASE);\n if (baseIndex === -1) {\n return null;\n }\n return pathname\n .slice(baseIndex + DEVTOOLS_ROUTE_BASE.length)\n .replace(TRAILING_SLASHES, \"\");\n}\n\nfunction readInteger(value: string | null, minimum: number): number | null {\n if (value === null || value === \"\") {\n return null;\n }\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed >= minimum ? parsed : null;\n}\n\nasync function routeRequest(\n request: Request,\n subPath: string | null,\n settings: ResolvedDevtoolsOptions,\n projectRoots: () => ProjectRoots\n): Promise<Response> {\n const url = new URL(request.url);\n\n if (subPath?.startsWith(`${DEVTOOLS_ENDPOINTS.proxy}/`)) {\n const apiPath = subPath.slice(DEVTOOLS_ENDPOINTS.proxy.length);\n return await proxyWithBoardCredential(request, apiPath, settings);\n }\n\n const requiredMethod = subPath ? ENDPOINT_METHODS[subPath] : undefined;\n if (requiredMethod && request.method !== requiredMethod) {\n return errorResponse(\n `${subPath} only answers ${requiredMethod} requests.`,\n 405\n );\n }\n\n switch (subPath) {\n case DEVTOOLS_ENDPOINTS.status:\n return jsonResponse({\n board: await boardAccess(request, settings),\n editor: settings.editor,\n marker: DEVTOOLS_STATUS_MARKER,\n } satisfies DevtoolsStatus);\n case DEVTOOLS_ENDPOINTS.connectStart:\n return await startConnect(request, settings);\n case DEVTOOLS_ENDPOINTS.connectCallback:\n return await finishConnect(request, settings);\n case DEVTOOLS_ENDPOINTS.disconnect:\n return await disconnect(settings);\n case DEVTOOLS_ENDPOINTS.source:\n return outcomeResponse(\n await readSourceFile(\n {\n column: readInteger(url.searchParams.get(\"column\"), 0),\n fileName: url.searchParams.get(\"file\") ?? \"\",\n line: readInteger(url.searchParams.get(\"line\"), 1),\n },\n projectRoots()\n )\n );\n case DEVTOOLS_ENDPOINTS.search:\n return outcomeResponse(\n await searchCode(\n projectRoots().workspaceRoot,\n url.searchParams.get(\"q\") ?? \"\"\n )\n );\n default:\n return errorResponse(\n `No Reflet devtools endpoint at ${url.pathname}.`,\n 404\n );\n }\n}\n\nexport function createDevtoolsHandler(\n options: DevtoolsServerOptions = {},\n env: DevtoolsEnv = process.env\n): DevtoolsHandler {\n const settings = resolveDevtoolsOptions(options, env);\n let roots: ProjectRoots | null = null;\n const projectRoots = (): ProjectRoots => {\n roots ??= resolveProjectRoots(settings.root);\n return roots;\n };\n\n return async (request) => {\n const hostRejection = rejectUntrustedHost(request, settings.allowedHosts);\n if (hostRejection) {\n return hostRejection;\n }\n const subPath = routeSubPath(new URL(request.url).pathname);\n const isConnectCallback =\n request.method === \"GET\" &&\n subPath === DEVTOOLS_ENDPOINTS.connectCallback;\n const callerRejection = isConnectCallback\n ? null\n : rejectUntrustedCaller(request, settings.allowedHosts);\n if (callerRejection) {\n return callerRejection;\n }\n try {\n return await routeRequest(request, subPath, settings, projectRoots);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n return errorResponse(`Reflet devtools route failed: ${reason}`, 500);\n }\n };\n}\n"],"mappings":";;;;;;;;;AAKA,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;AACzB,MAAM,cAAc;AACpB,MAAM,iBAAiB;AACvB,MAAM,eAAe;AACrB,MAAM,oBAAoB;AAC1B,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,6BAA6B;AACnC,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AACA,MAAM,aAAa;AAOnB,SAAS,WAAW,eAAuB,OAAoC;CAC7E,MAAM,OAAO;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAG;CACL;CACA,OAAO,IAAI,SAAS,eAAe;EACjC,SACE,OACA,MACA;GACE,KAAK;GACL,UAAU;GACV,WAAW;GACX,SAAS;EACX,IACC,OAAO,WAAW,WAAW;GAAE;GAAO;EAAO,CAAC,CACjD;CACF,CAAC;AACH;AAEA,SAAS,YAAY,SAAiB,OAAuB;CAC3D,MAAM,OAAO,QAAQ,KAAK;CAC1B,IAAI,KAAK,UAAU,gBACjB,OAAO;CAET,MAAM,aAAa,KAAK,QAAQ,KAAK;CACrC,MAAM,QAAQ,KAAK,IACjB,GACA,KAAK,IAAI,aAAa,cAAc,KAAK,SAAS,cAAc,CAClE;CACA,MAAM,MAAM,QAAQ;CACpB,MAAM,OAAO,QAAQ,IAAI,MAAM;CAC/B,MAAM,OAAO,MAAM,KAAK,SAAS,MAAM;CACvC,OAAO,GAAG,OAAO,KAAK,MAAM,OAAO,GAAG,IAAI;AAC5C;AAEA,SAAS,aACP,QACA,eACA,OACa;CACb,MAAM,UAAuB,CAAC;CAC9B,KAAK,MAAM,UAAU,OAAO,MAAM,IAAI,GAAG;EACvC,MAAM,CAAC,MAAM,UAAU,WAAW,OAAO,MAAM,IAAI;EACnD,MAAM,OAAO,OAAO,QAAQ;EAG5B,IADE,SAAS,KAAA,KAAa,YAAY,KAAA,KAAa,OAAO,UAAU,IAAI,KACpD,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,SAAS,cAAc,GAAG;GAC3D,QAAQ,KAAK;IACX,cAAc,KAAK,eAAe,IAAI;IACtC;IACA;IACA,SAAS,YAAY,SAAS,KAAK;GACrC,CAAC;GACD,IAAI,QAAQ,WAAW,aACrB;EAEJ;CACF;CACA,OAAO;AACT;AAEA,SAAS,mBAAmB,OAAkD;CAC5E,IAAI,MAAM,SAAS,UACjB,OAAO,QAAQ,sDAAsD,GAAG;CAE1E,IAAI,MAAM,SAAS,4BACjB,OAAO,QACL,0DACA,GACF;CAEF,IAAI,MAAM,QACR,OAAO,QAAQ,0BAA0B,GAAG;CAE9C,OAAO,QAAQ,uBAAuB,MAAM,WAAW,GAAG;AAC5D;AAEA,eAAsB,WACpB,eACA,UAC4C;CAC5C,MAAM,QAAQ,SAAS,KAAK;CAC5B,IAAI,MAAM,SAAS,oBAAoB,MAAM,SAAS,kBACpD,OAAO,QACL,cAAc,iBAAiB,MAAM,iBAAiB,eACtD,GACF;CAEF,IAAI,WAAW,KAAK,KAAK,GACvB,OAAO,QAAQ,qCAAqC,GAAG;CAGzD,MAAM,EAAE,OAAO,WAAW,MAAM,WAAW,eAAe,KAAK;CAC/D,MAAM,UAAU,aAAa,QAAQ,eAAe,KAAK;CACzD,MAAM,eAAe,OAAO,SAAS;CACrC,IAAI,CAAC,SAAS,gBAAgB,QAAQ,SAAS,GAC7C,OAAO;EAAE,IAAI;EAAM,OAAO,EAAE,QAAQ;CAAE;CAExC,OAAO,mBAAmB,KAAK;AACjC;;;AClIA,SAAgB,oBAAoB,SAA+B;CACjE,MAAM,eAAe,QAAQ,OAAO;CACpC,MAAM,OAAO,WAAW,YAAY,IAChC,aAAa,YAAY,IACzB;CAEJ,KAAK,IAAI,YAAY,OAAQ,YAAY,QAAQ,SAAS,GAAG;EAC3D,IAAI,WAAW,KAAK,WAAW,MAAM,CAAC,GACpC,OAAO;GAAE;GAAM,eAAe;EAAU;EAE1C,IAAI,QAAQ,SAAS,MAAM,WACzB,OAAO;GAAE;GAAM,eAAe;EAAK;CAEvC;AACF;;;ACtBA,MAAM,SAAS;AACf,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;AACtB,MAAM,kBAAkB;AACxB,MAAM,aAAa;AACnB,MAAM,sBAAsB;AAC5B,MAAM,oBAAoB;CAAC;CAAU;CAAS;CAAW;AAAO;AAQhE,SAAS,WAAW,MAAc,OAAwB;CACxD,IAAI,KAAK,OAAO,KAAK,MAAM,KACzB,OAAO;CAET,MAAM,OAAO,KAAK,OAAO,QAAQ,CAAC;CAClC,OAAO,SAAS,OAAO,eAAe,KAAK,IAAI;AACjD;AAEA,SAAS,sBAAsB,MAAc,OAAwB;CACnE,IAAI,SAAS,QAAQ;CACrB,OAAO,UAAU,KAAK,WAAW,KAAK,KAAK,OAAO,MAAM,CAAC,GACvD,UAAU;CAEZ,IAAI,SAAS,GACX,OAAO;CAET,MAAM,WAAW,KAAK,OAAO,MAAM;CACnC,IAAI,oBAAoB,KAAK,QAAQ,GACnC,OAAO;CAET,IAAI,YAAY;CAChB,OAAO,YAAY,KAAK,gBAAgB,KAAK,KAAK,OAAO,YAAY,CAAC,CAAC,GACrE,aAAa;CAEf,OAAO,kBAAkB,SAAS,KAAK,MAAM,WAAW,SAAS,CAAC,CAAC;AACrE;AAEA,SAAS,aAAa,MAAc,OAAuB;CACzD,MAAM,QAAQ,KAAK,OAAO,KAAK;CAC/B,IAAI,SAAS,QAAQ;CACrB,OAAO,SAAS,KAAK,QAAQ;EAC3B,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,SAAS,MACX,UAAU;OACL,IAAI,SAAS,OAClB,OAAO,SAAS;OACX,IAAI,SAAS,MAClB,OAAO,QAAQ;OAEf,UAAU;CAEd;CACA,OAAO,QAAQ;AACjB;AAEA,SAAS,aAAa,MAAc,OAAuB;CACzD,IAAI,SAAS,QAAQ;CACrB,OAAO,SAAS,KAAK,QAAQ;EAC3B,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,SAAS,MACX,UAAU;OACL,IAAI,SAAS,KAClB,OAAO,SAAS;OACX,IAAI,SAAS,OAAO,KAAK,OAAO,SAAS,CAAC,MAAM,KAAK;GAC1D,SAAS,iBAAiB,MAAM,SAAS,CAAC;GAC1C,IAAI,WAAW,QACb,OAAO;EAEX,OACE,UAAU;CAEd;CACA,OAAO;AACT;AAEA,SAAS,YAAY,MAAc,OAAuB;CACxD,MAAM,OAAO,KAAK,OAAO,KAAK;CAC9B,MAAM,OAAO,KAAK,OAAO,QAAQ,CAAC;CAClC,IAAI,SAAS,QAAO,SAAS,KAC3B,OAAO,aAAa,MAAM,KAAK;CAEjC,IAAI,SAAS,KACX,OAAO,aAAa,MAAM,KAAK;CAEjC,IAAI,SAAS,OAAO,SAAS,KAAK;EAChC,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK;EACxC,OAAO,YAAY,KAAK,KAAK,SAAS;CACxC;CACA,IAAI,SAAS,OAAO,SAAS,KAAK;EAChC,MAAM,aAAa,KAAK,QAAQ,MAAM,QAAQ,CAAC;EAC/C,OAAO,eAAe,KAAK,SAAS,aAAa;CACnD;CACA,IAAI,WAAW,MAAM,KAAK,KAAK,sBAAsB,MAAM,KAAK,GAC9D,OAAO,YAAY,MAAM,KAAK;CAEhC,OAAO,QAAQ;AACjB;AAEA,SAAS,iBAAiB,MAAc,OAAuB;CAC7D,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,OAAO,SAAS,KAAK,QAAQ;EAC3B,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,SAAS,OAAO,SAAS,KAAK;GAChC,SAAS,SAAS,MAAM,IAAI;GAC5B,UAAU;GACV,IAAI,UAAU,GACZ,OAAO;EAEX,OAAO;GACL,SAAS,YAAY,MAAM,MAAM;GACjC,IAAI,WAAW,QACb,OAAO;EAEX;CACF;CACA,OAAO;AACT;AAEA,SAAS,kBAAkB,MAAc,OAAuB;CAC9D,IAAI,QAAQ;CACZ,KAAK,IAAI,SAAS,OAAO,SAAS,KAAK,QAAQ,UAAU,GAAG;EAC1D,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,SAAS,KACX,SAAS;OACJ,IAAI,SAAS,KAAK;GACvB,SAAS;GACT,IAAI,UAAU,GACZ,OAAO,SAAS;EAEpB;CACF;CACA,OAAO;AACT;AAEA,SAAS,mBAAmB,MAAc,OAAuB;CAC/D,MAAM,OAAO,KAAK,OAAO,KAAK;CAC9B,IAAI,SAAS,KACX,OAAO,iBAAiB,MAAM,KAAK;CAErC,IAAI,SAAS,QAAO,SAAS,KAAK;EAChC,MAAM,eAAe,KAAK,QAAQ,MAAM,QAAQ,CAAC;EACjD,OAAO,iBAAiB,KAAK,SAAS,eAAe;CACvD;CACA,OAAO,QAAQ;AACjB;AAEA,SAAS,YAAY,MAAc,OAAuB;CACxD,IAAI,SAAS;CACb,OAAO,cAAc,KAAK,KAAK,OAAO,MAAM,CAAC,GAC3C,UAAU;CAEZ,OAAO;AACT;AAEA,SAAS,eAAe,MAAc,OAAkC;CACtE,MAAM,UAAU,YAAY,MAAM,QAAQ,CAAC;CAC3C,MAAM,OAAO,KAAK,MAAM,QAAQ,GAAG,OAAO;CAC1C,IAAI,SACF,KAAK,OAAO,OAAO,MAAM,MAAM,kBAAkB,MAAM,OAAO,IAAI;CAEpE,OAAO,WAAW,UAAU,SAAS,KAAK,QAAQ;EAChD,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,SAAS,KACX,OAAO;GAAE,KAAK,SAAS;GAAG;GAAM,aAAa;EAAM;EAErD,IAAI,SAAS,OAAO,KAAK,OAAO,SAAS,CAAC,MAAM,KAC9C,OAAO;GAAE,KAAK,SAAS;GAAG;GAAM,aAAa;EAAK;EAEpD,SAAS,mBAAmB,MAAM,MAAM;CAC1C;CACA,OAAO;AACT;AAEA,SAAS,kBAAkB,MAAc,OAAe,MAAsB;CAC5E,IAAI,SAAS,QAAQ;CACrB,OAAO,WAAW,KAAK,KAAK,OAAO,MAAM,CAAC,GACxC,UAAU;CAEZ,MAAM,UAAU,YAAY,MAAM,MAAM;CACxC,IAAI,KAAK,MAAM,QAAQ,OAAO,MAAM,MAClC,OAAO;CAET,SAAS;CACT,OAAO,WAAW,KAAK,KAAK,OAAO,MAAM,CAAC,GACxC,UAAU;CAEZ,OAAO,KAAK,OAAO,MAAM,MAAM,MAAM,SAAS,IAAI;AACpD;AAEA,SAAS,aAAa,MAAc,OAAe,MAAsB;CACvE,IAAI,SAAS;CACb,OAAO,WAAW,UAAU,SAAS,KAAK,QAAQ;EAChD,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,SAAS,OAAO,KAAK,OAAO,SAAS,CAAC,MAAM,KAC9C,OAAO,kBAAkB,MAAM,QAAQ,IAAI;EAE7C,IAAI,SAAS,KACX,SAAS,iBAAiB,MAAM,MAAM;OACjC,IAAI,WAAW,MAAM,MAAM,GAChC,SAAS,YAAY,MAAM,MAAM;OAEjC,UAAU;CAEd;CACA,OAAO;AACT;AAEA,SAAS,YAAY,MAAc,OAAuB;CACxD,MAAM,MAAM,eAAe,MAAM,KAAK;CACtC,IAAI,CAAC,KACH,OAAO;CAET,OAAO,IAAI,cAAc,IAAI,MAAM,aAAa,MAAM,IAAI,KAAK,IAAI,IAAI;AACzE;AAEA,SAAS,WAAW,MAAc,MAAsB;CACtD,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GACpC,OAAO;CAET,IAAI,SAAS;CACb,KAAK,IAAI,UAAU,GAAG,UAAU,MAAM,WAAW,GAAG;EAClD,MAAM,UAAU,KAAK,QAAQ,MAAM,MAAM;EACzC,IAAI,YAAY,IACd,OAAO;EAET,SAAS,UAAU;CACrB;CACA,OAAO;AACT;AAEA,SAAS,aACP,MACA,WACA,SACA,QACQ;CACR,MAAM,SAAS,KAAK,IAAI,YAAY,KAAK,IAAI,QAAQ,CAAC,GAAG,OAAO;CAChE,KAAK,IAAI,OAAO,GAAG,QAAQ,kBAAkB,QAAQ,GAAG;EACtD,MAAM,YAAY,SAAS;EAC3B,IAAI,aAAa,aAAa,WAAW,MAAM,SAAS,GACtD,OAAO;CAEX;CACA,KAAK,IAAI,YAAY,SAAS,GAAG,YAAY,SAAS,aAAa,GACjE,IAAI,WAAW,MAAM,SAAS,GAC5B,OAAO;CAGX,OAAO;AACT;AAEA,SAAS,cAAc,MAAc,MAAc,IAAoB;CACrE,IAAI,QAAQ;CACZ,IAAI,UAAU,KAAK,QAAQ,MAAM,IAAI;CACrC,OAAO,YAAY,MAAM,UAAU,IAAI;EACrC,SAAS;EACT,UAAU,KAAK,QAAQ,MAAM,UAAU,CAAC;CAC1C;CACA,OAAO;AACT;;AAGA,SAAgB,gBACd,MACA,MACA,QACkB;CAClB,MAAM,YAAY,WAAW,MAAM,IAAI;CACvC,IAAI,cAAc,QAChB,OAAO;CAET,MAAM,UAAU,KAAK,QAAQ,MAAM,SAAS;CAE5C,MAAM,WAAW,aAAa,MAAM,WADpB,YAAY,KAAK,KAAK,SAAS,SACS,MAAM;CAC9D,IAAI,aAAa,QACf,OAAO;CAET,MAAM,aAAa,YAAY,MAAM,QAAQ;CAC7C,IAAI,eAAe,QACjB,OAAO;CAET,OAAO;EACL,KAAK,OAAO,cAAc,MAAM,UAAU,aAAa,CAAC;EACxD,OAAO;CACT;AACF;;;;AClSA,SAAgB,sBACd,UACA,eACe;CACf,MAAM,eAAe,SAAS,eAAe,QAAQ;CAMrD,OAJE,iBAAiB,MACjB,iBAAiB,QACjB,aAAa,WAAW,KAAK,KAAK,KAClC,WAAW,YAAY,IACR,OAAO,aAAa,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG;AAC1D;;;ACNA,MAAM,sBAAsB;AAC5B,MAAMA,kBAAgB;AACtB,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AAEtB,MAAM,2BAAW,IAAI,IAAiD;AAEtE,SAAgB,cAAc,UAA2B;CACvD,OAAO,oBAAoB,KAAK,QAAQ;AAC1C;AAEA,eAAe,WAAW,WAAoC;CAC5D,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM;CAC7C,MAAM,WAAW,mBAAmB,KAAK,IAAI,CAAC,GAAG;CACjD,OAAO,WACH,KAAK,QAAQ,SAAS,GAAG,mBAAmB,QAAQ,CAAC,IACrD,GAAG,UAAU;AACnB;AAEA,eAAe,QAAQ,SAAqC;CAC1D,MAAM,EAAE,SAAS,SAAS,MAAM,KAAK,OAAO;CAC5C,IAAI,OAAO,eACT,MAAM,IAAI,MAAM,sBAAsB;CAExC,MAAM,SAAS,SAAS,IAAI,OAAO;CACnC,IAAI,QAAQ,YAAY,SACtB,OAAO,OAAO;CAEhB,MAAM,MAAM,IAAI,UAAU,KAAK,MAAM,MAAM,SAAS,SAAS,MAAM,CAAC,CAAC;CACrE,SAAS,IAAI,SAAS;EAAE;EAAK;CAAQ,CAAC;CACtC,OAAO;AACT;;;;;;AAOA,eAAsB,eACpB,SACA,eACyC;CACzC,MAAM,aAAa,QACjB,kFACA,GACF;CACA,IAAI,QAAQ,SAAS,MACnB,OAAO;CAET,IAAI;EACF,MAAM,WAAW,QAAQ,SACtB,QAAQ,qBAAqB,EAAE,CAAC,CAChC,QAAQA,iBAAe,EAAE;EAC5B,MAAM,YAAY,MAAM,SAAS,cAAc,QAAQ,CAAC;EACxD,IAAI,sBAAsB,WAAW,aAAa,MAAM,MACtD,OAAO,QACL,4DACA,GACF;EAGF,MAAM,UAAS,MADG,QAAQ,MAAM,WAAW,SAAS,CAAC,EAAA,CAClC,WAAW,QAAQ,OAAO,QAAQ,UAAU,KAAK,CAAC;EACrE,IAAI,EAAE,cAAc,SAClB,OAAO;EAET,OAAO;GACL,IAAI;GACJ,OAAO;IACL,QAAQ,OAAO,eAAe;IAC9B,UAAU,OAAO;IACjB,MAAM,OAAO;GACf;EACF;CACF,QAAQ;EACN,OAAO;CACT;AACF;;;AC3EA,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AACA,MAAM,oBAAoB,4CAA4C,kBAAkB,KAAK,IAAI,EAAE;AACnG,MAAM,4BACJ;AACF,MAAM,uBACJ;AACF,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAChC,MAAM,eAAe,CAAC,cAAc,mBAAmB;AACvD,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAmBA,SAAS,WAAW,MAAsB;CACxC,IAAI;EACF,OAAO,mBAAmB,IAAI;CAChC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,iBAAiB,UAAkB,UAA4B;CACtE,KAAK,MAAM,UAAU,UACnB,IAAI,OAAO,KAAK,QAAQ,GACtB,OAAO,SAAS,QAAQ,QAAQ,EAAE;CAGtC,OAAO;AACT;;AAGA,SAAgB,wBAAwB,aAA6B;CACnE,IAAI,WAAW,YACZ,KAAK,CAAC,CACN,QAAQ,eAAe,EAAE,CAAC,CAC1B,QAAQ,yBAAyB,EAAE;CACtC,IAAI,eAAe;CAEnB,KAAK,IAAI,OAAO,GAAG,OAAO,sBAAsB,QAAQ,GAAG;EACzD,MAAM,aAAa,iBAAiB,UAAU,YAAY;EAC1D,iBAAiB,eAAe;EAChC,MAAM,WAAW,iBAAiB,YAAY,gBAAgB;EAC9D,IAAI,aAAa,UACf;EAEF,WAAW;CACb;CAGA,QADa,eAAe,WAAW,QAAQ,IAAI,SAAA,CACvC,QAAQ,oBAAoB,EAAE;AAC5C;AAEA,SAAS,eAAe,UAAkB,OAA+B;CACvE,MAAM,aAAa,CACjB,KAAK,MAAM,MAAM,QAAQ,GACzB,KAAK,MAAM,eAAe,QAAQ,CACpC;CACA,IAAI,WAAW,QAAQ,GACrB,WAAW,QAAQ,QAAQ;CAE7B,OAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC;AAChC;AAEA,SAAS,kBAAkB,MAAuB;CAChD,OAAO,kBAAkB,SAAS,QAAQ,IAAI,CAAC,CAAC,YAAY,CAAC;AAC/D;AAEA,eAAe,eACb,WACA,eACyB;CACzB,IAAI;CACJ,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,SAAS,SAAS;EACnC,MAAM,QAAQ,MAAM,KAAK,QAAQ;EACjC,IAAI,CAAC,MAAM,OAAO,GAChB,OAAO,EAAE,MAAM,UAAU;EAE3B,OAAO,MAAM;CACf,QAAQ;EACN,OAAO,EAAE,MAAM,UAAU;CAC3B;CAEA,MAAM,eAAe,sBAAsB,UAAU,aAAa;CAClE,IAAI,iBAAiB,MACnB,OAAO;EAAE,MAAM;EAAW,QAAQ;CAA0B;CAE9D,IAAI,aAAa,MAAM,GAAG,CAAC,CAAC,SAAS,cAAc,GACjD,OAAO;EAAE,MAAM;EAAW,QAAQ;CAAqB;CAEzD,IAAI,CAAC,kBAAkB,QAAQ,GAC7B,OAAO;EAAE,MAAM;EAAW,QAAQ;CAAkB;CAEtD,OAAO;EAAE,MAAM;EAAS;EAAU;EAAc;CAAK;AACvD;AAEA,eAAe,iBACb,UACA,OACuC;CACvC,IAAI,UAAyB;CAC7B,KAAK,MAAM,aAAa,eAAe,UAAU,KAAK,GAAG;EACvD,MAAM,QAAQ,MAAM,eAAe,WAAW,MAAM,aAAa;EACjE,IAAI,MAAM,SAAS,SACjB,OAAO;GAAE,IAAI;GAAM,OAAO;EAAM;EAElC,IAAI,MAAM,SAAS,WACjB,YAAY,MAAM;CAEtB;CACA,IAAI,SACF,OAAO,QAAQ,SAAS,GAAG;CAE7B,OAAO,QAAQ,kBAAkB,SAAS,MAAM,MAAM,cAAc,IAAI,GAAG;AAC7E;;AAGA,SAAS,iBAAiB,MAAc,MAAc,QAAuB;CAC3E,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,MAAM;CAC3C,OAAO,WAAW,QAAQ,SAAS,KAAK,SAAS,SAAS;AAC5D;AAEA,eAAsB,eACpB,OACA,OACsC;CACtC,IACE,MAAM,SAAS,SAAS,wBACxB,MAAM,SAAS,SAAS,IAAI,GAE5B,OAAO,QAAQ,8CAA8C,GAAG;CAElE,MAAM,SAAS,cAAc,MAAM,QAAQ,IACvC,MAAM,eAAe,OAAO,MAAM,aAAa,IAC/C;EAAE,IAAI;EAAe,OAAO;CAAM;CACtC,IAAI,CAAC,OAAO,IACV,OAAO;CAET,MAAM,UAAU,OAAO;CACvB,MAAM,WAAW,wBAAwB,QAAQ,QAAQ;CACzD,IAAI,CAAC,UACH,OAAO,QAAQ,mCAAmC,GAAG;CAEvD,IAAI,CAAC,kBAAkB,QAAQ,GAC7B,OAAO,QAAQ,mBAAmB,GAAG;CAGvC,MAAM,UAAU,MAAM,iBAAiB,UAAU,KAAK;CACtD,IAAI,CAAC,QAAQ,IACX,OAAO;CAET,MAAM,EAAE,UAAU,cAAc,SAAS,QAAQ;CACjD,IAAI,OAAO,kBACT,OAAO,QACL,GAAG,aAAa,4CAChB,GACF;CAGF,MAAM,OAAO,MAAM,SAAS,UAAU,MAAM;CAC5C,MAAM,SACJ,QAAQ,SAAS,OACb,QAAQ,SACR,iBAAiB,MAAM,QAAQ,MAAM,QAAQ,MAAM;CAMzD,OAAO;EACL,IAAI;EACJ,OAAO;GACL,cAAc;GACd;GACA;GACA,cAVF,QAAQ,SAAS,OACb,OACA,gBAAgB,MAAM,QAAQ,MAAM,UAAU,CAAC;GASjD,MAAM,QAAQ;GACd,MAAM;EACR;CACF;AACF;;;ACvMA,MAAM,mBAAmB;AAEzB,MAAM,mBAAmD;EACtD,mBAAmB,kBAAkB;EACrC,mBAAmB,eAAe;EAClC,mBAAmB,aAAa;EAChC,mBAAmB,SAAS;EAC5B,mBAAmB,SAAS;EAC5B,mBAAmB,SAAS;AAC/B;AAEA,SAAS,gBAAmB,SAAuC;CACjE,OAAO,QAAQ,KACX,aAAa,QAAQ,KAAK,IAC1B,cAAc,QAAQ,OAAO,QAAQ,MAAM;AACjD;AAEA,SAAS,aAAa,UAAiC;CACrD,MAAM,YAAY,SAAS,QAAQ,mBAAmB;CACtD,IAAI,cAAc,IAChB,OAAO;CAET,OAAO,SACJ,MAAM,YAAY,oBAAoB,MAAM,CAAC,CAC7C,QAAQ,kBAAkB,EAAE;AACjC;AAEA,SAAS,YAAY,OAAsB,SAAgC;CACzE,IAAI,UAAU,QAAQ,UAAU,IAC9B,OAAO;CAET,MAAM,SAAS,OAAO,KAAK;CAC3B,OAAO,OAAO,UAAU,MAAM,KAAK,UAAU,UAAU,SAAS;AAClE;AAEA,eAAe,aACb,SACA,SACA,UACA,cACmB;CACnB,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;CAE/B,IAAI,SAAS,WAAW,GAAG,mBAAmB,MAAM,EAAE,GAAG;EACvD,MAAM,UAAU,QAAQ,MAAM,mBAAmB,MAAM,MAAM;EAC7D,OAAO,MAAM,yBAAyB,SAAS,SAAS,QAAQ;CAClE;CAEA,MAAM,iBAAiB,UAAU,iBAAiB,WAAW,KAAA;CAC7D,IAAI,kBAAkB,QAAQ,WAAW,gBACvC,OAAO,cACL,GAAG,QAAQ,gBAAgB,eAAe,aAC1C,GACF;CAGF,QAAQ,SAAR;EACE,KAAK,mBAAmB,QACtB,OAAO,aAAa;GAClB,OAAO,MAAM,YAAY,SAAS,QAAQ;GAC1C,QAAQ,SAAS;GACjB,QAAQ;EACV,CAA0B;EAC5B,KAAK,mBAAmB,cACtB,OAAO,MAAM,aAAa,SAAS,QAAQ;EAC7C,KAAK,mBAAmB,iBACtB,OAAO,MAAM,cAAc,SAAS,QAAQ;EAC9C,KAAK,mBAAmB,YACtB,OAAO,MAAM,WAAW,QAAQ;EAClC,KAAK,mBAAmB,QACtB,OAAO,gBACL,MAAM,eACJ;GACE,QAAQ,YAAY,IAAI,aAAa,IAAI,QAAQ,GAAG,CAAC;GACrD,UAAU,IAAI,aAAa,IAAI,MAAM,KAAK;GAC1C,MAAM,YAAY,IAAI,aAAa,IAAI,MAAM,GAAG,CAAC;EACnD,GACA,aAAa,CACf,CACF;EACF,KAAK,mBAAmB,QACtB,OAAO,gBACL,MAAM,WACJ,aAAa,CAAC,CAAC,eACf,IAAI,aAAa,IAAI,GAAG,KAAK,EAC/B,CACF;EACF,SACE,OAAO,cACL,kCAAkC,IAAI,SAAS,IAC/C,GACF;CACJ;AACF;AAEA,SAAgB,sBACd,UAAiC,CAAC,GAClC,MAAmB,QAAQ,KACV;CACjB,MAAM,WAAW,uBAAuB,SAAS,GAAG;CACpD,IAAI,QAA6B;CACjC,MAAM,qBAAmC;EACvC,UAAU,oBAAoB,SAAS,IAAI;EAC3C,OAAO;CACT;CAEA,OAAO,OAAO,YAAY;EACxB,MAAM,gBAAgB,oBAAoB,SAAS,SAAS,YAAY;EACxE,IAAI,eACF,OAAO;EAET,MAAM,UAAU,aAAa,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,QAAQ;EAI1D,MAAM,kBAFJ,QAAQ,WAAW,SACnB,YAAY,mBAAmB,kBAE7B,OACA,sBAAsB,SAAS,SAAS,YAAY;EACxD,IAAI,iBACF,OAAO;EAET,IAAI;GACF,OAAO,MAAM,aAAa,SAAS,SAAS,UAAU,YAAY;EACpE,SAAS,OAAO;GACd,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GACpE,OAAO,cAAc,iCAAiC,UAAU,GAAG;EACrE;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"handler-BX8ITlGZ.js","names":["QUERY_OR_HASH"],"sources":["../src/devtools/server/source/code-search.ts","../src/devtools/server/source/project-roots.ts","../src/devtools/server/source/jsx-range.ts","../src/devtools/server/source/workspace-path.ts","../src/devtools/server/source/server-frame.ts","../src/devtools/server/source/source-file.ts","../src/devtools/server/handler.ts"],"sourcesContent":["import { type ExecFileException, execFile } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport type { CodeMatch, CodeSearchResult } from \"../../protocol\";\nimport { type DevtoolsOutcome, failure } from \"../json-response\";\n\nconst MIN_QUERY_LENGTH = 2;\nconst MAX_QUERY_LENGTH = 200;\nconst MAX_MATCHES = 20;\nconst PREVIEW_LENGTH = 160;\nconst PREVIEW_LEAD = 40;\nconst SEARCH_TIMEOUT_MS = 4000;\nconst MAX_OUTPUT_BYTES = 1_048_576;\nconst NO_MATCHES_EXIT_CODE = 1;\nconst NOT_A_REPOSITORY_EXIT_CODE = 128;\nconst SEARCHED_FILES = [\n \"*.tsx\",\n \"*.jsx\",\n \"*.ts\",\n \"*.js\",\n \"*.vue\",\n \"*.svelte\",\n \"*.astro\",\n \"*.mdx\",\n];\nconst LINE_BREAK = /[\\r\\n]/;\n\ninterface GitGrepRun {\n error: ExecFileException | null;\n stdout: string;\n}\n\nfunction runGitGrep(workspaceRoot: string, query: string): Promise<GitGrepRun> {\n const args = [\n \"grep\",\n \"-n\",\n \"-z\",\n \"-I\",\n \"-F\",\n \"--no-color\",\n \"--untracked\",\n \"-e\",\n query,\n \"--\",\n ...SEARCHED_FILES,\n ];\n return new Promise((resolveRun) => {\n execFile(\n \"git\",\n args,\n {\n cwd: workspaceRoot,\n encoding: \"utf8\",\n maxBuffer: MAX_OUTPUT_BYTES,\n timeout: SEARCH_TIMEOUT_MS,\n },\n (error, stdout) => resolveRun({ error, stdout })\n );\n });\n}\n\nfunction previewLine(content: string, query: string): string {\n const text = content.trim();\n if (text.length <= PREVIEW_LENGTH) {\n return text;\n }\n const matchIndex = text.indexOf(query);\n const start = Math.max(\n 0,\n Math.min(matchIndex - PREVIEW_LEAD, text.length - PREVIEW_LENGTH)\n );\n const end = start + PREVIEW_LENGTH;\n const head = start > 0 ? \"…\" : \"\";\n const tail = end < text.length ? \"…\" : \"\";\n return `${head}${text.slice(start, end)}${tail}`;\n}\n\nfunction parseMatches(\n stdout: string,\n workspaceRoot: string,\n query: string\n): CodeMatch[] {\n const matches: CodeMatch[] = [];\n for (const record of stdout.split(\"\\n\")) {\n const [path, lineText, content] = record.split(\"\\0\");\n const line = Number(lineText);\n const isComplete =\n path !== undefined && content !== undefined && Number.isInteger(line);\n if (isComplete && !path.split(\"/\").includes(\"node_modules\")) {\n matches.push({\n absolutePath: join(workspaceRoot, path),\n line,\n path,\n preview: previewLine(content, query),\n });\n if (matches.length === MAX_MATCHES) {\n break;\n }\n }\n }\n return matches;\n}\n\nfunction describeGitFailure(error: ExecFileException): DevtoolsOutcome<never> {\n if (error.code === \"ENOENT\") {\n return failure(\"Code search needs git installed on the dev server.\", 503);\n }\n if (error.code === NOT_A_REPOSITORY_EXIT_CODE) {\n return failure(\n \"Code search needs the app to live in a git repository.\",\n 503\n );\n }\n if (error.killed) {\n return failure(\"Code search timed out.\", 504);\n }\n return failure(`Code search failed: ${error.message}`, 500);\n}\n\nexport async function searchCode(\n workspaceRoot: string,\n rawQuery: string\n): Promise<DevtoolsOutcome<CodeSearchResult>> {\n const query = rawQuery.trim();\n if (query.length < MIN_QUERY_LENGTH || query.length > MAX_QUERY_LENGTH) {\n return failure(\n `Search for ${MIN_QUERY_LENGTH} to ${MAX_QUERY_LENGTH} characters.`,\n 400\n );\n }\n if (LINE_BREAK.test(query)) {\n return failure(\"Search for a single line of text.\", 400);\n }\n\n const { error, stdout } = await runGitGrep(workspaceRoot, query);\n const matches = parseMatches(stdout, workspaceRoot, query);\n const hasNoMatches = error?.code === NO_MATCHES_EXIT_CODE;\n if (!error || hasNoMatches || matches.length > 0) {\n return { ok: true, value: { matches } };\n }\n return describeGitFailure(error);\n}\n","import { existsSync, realpathSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\n\nexport interface ProjectRoots {\n /** The app directory, where the dev server runs. */\n root: string;\n /** Nearest ancestor of the app directory holding `.git`, else the app directory. */\n workspaceRoot: string;\n}\n\nexport function resolveProjectRoots(appRoot: string): ProjectRoots {\n const resolvedRoot = resolve(appRoot);\n const root = existsSync(resolvedRoot)\n ? realpathSync(resolvedRoot)\n : resolvedRoot;\n\n for (let directory = root; ; directory = dirname(directory)) {\n if (existsSync(join(directory, \".git\"))) {\n return { root, workspaceRoot: directory };\n }\n if (dirname(directory) === directory) {\n return { root, workspaceRoot: root };\n }\n }\n}\n","import type { LineRange } from \"../../protocol\";\n\nconst FAILED = -1;\nconst MAX_TAG_LOOKBACK = 2;\nconst TAG_NAME_START = /[A-Za-z_$]/;\nconst TAG_NAME_CHAR = /[\\w$.:-]/;\nconst IDENTIFIER_CHAR = /[\\w$]/;\nconst WHITESPACE = /\\s/;\nconst JSX_EXPRESSION_LEAD = /[([{,;=?:&|!>]/;\nconst JSX_KEYWORD_LEADS = [\"return\", \"yield\", \"default\", \"await\"];\n\ninterface OpeningTag {\n end: number;\n name: string;\n selfClosing: boolean;\n}\n\nfunction isTagStart(code: string, index: number): boolean {\n if (code.charAt(index) !== \"<\") {\n return false;\n }\n const next = code.charAt(index + 1);\n return next === \">\" || TAG_NAME_START.test(next);\n}\n\nfunction startsJsxInExpression(code: string, index: number): boolean {\n let cursor = index - 1;\n while (cursor >= 0 && WHITESPACE.test(code.charAt(cursor))) {\n cursor -= 1;\n }\n if (cursor < 0) {\n return true;\n }\n const previous = code.charAt(cursor);\n if (JSX_EXPRESSION_LEAD.test(previous)) {\n return true;\n }\n let wordStart = cursor;\n while (wordStart > 0 && IDENTIFIER_CHAR.test(code.charAt(wordStart - 1))) {\n wordStart -= 1;\n }\n return JSX_KEYWORD_LEADS.includes(code.slice(wordStart, cursor + 1));\n}\n\nfunction skipJsString(code: string, index: number): number {\n const quote = code.charAt(index);\n let cursor = index + 1;\n while (cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"\\\\\") {\n cursor += 2;\n } else if (char === quote) {\n return cursor + 1;\n } else if (char === \"\\n\") {\n return index + 1;\n } else {\n cursor += 1;\n }\n }\n return index + 1;\n}\n\nfunction skipTemplate(code: string, index: number): number {\n let cursor = index + 1;\n while (cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"\\\\\") {\n cursor += 2;\n } else if (char === \"`\") {\n return cursor + 1;\n } else if (char === \"$\" && code.charAt(cursor + 1) === \"{\") {\n cursor = skipJsExpression(code, cursor + 1);\n if (cursor === FAILED) {\n return FAILED;\n }\n } else {\n cursor += 1;\n }\n }\n return FAILED;\n}\n\nfunction skipJsToken(code: string, index: number): number {\n const char = code.charAt(index);\n const next = code.charAt(index + 1);\n if (char === '\"' || char === \"'\") {\n return skipJsString(code, index);\n }\n if (char === \"`\") {\n return skipTemplate(code, index);\n }\n if (char === \"/\" && next === \"/\") {\n const lineEnd = code.indexOf(\"\\n\", index);\n return lineEnd === -1 ? code.length : lineEnd;\n }\n if (char === \"/\" && next === \"*\") {\n const commentEnd = code.indexOf(\"*/\", index + 2);\n return commentEnd === -1 ? FAILED : commentEnd + 2;\n }\n if (isTagStart(code, index) && startsJsxInExpression(code, index)) {\n return skipElement(code, index);\n }\n return index + 1;\n}\n\nfunction skipJsExpression(code: string, index: number): number {\n let depth = 0;\n let cursor = index;\n while (cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"{\" || char === \"}\") {\n depth += char === \"{\" ? 1 : -1;\n cursor += 1;\n if (depth === 0) {\n return cursor;\n }\n } else {\n cursor = skipJsToken(code, cursor);\n if (cursor === FAILED) {\n return FAILED;\n }\n }\n }\n return FAILED;\n}\n\nfunction skipTypeArguments(code: string, index: number): number {\n let depth = 0;\n for (let cursor = index; cursor < code.length; cursor += 1) {\n const char = code.charAt(cursor);\n if (char === \"<\") {\n depth += 1;\n } else if (char === \">\") {\n depth -= 1;\n if (depth === 0) {\n return cursor + 1;\n }\n }\n }\n return FAILED;\n}\n\nfunction skipAttributeToken(code: string, index: number): number {\n const char = code.charAt(index);\n if (char === \"{\") {\n return skipJsExpression(code, index);\n }\n if (char === '\"' || char === \"'\") {\n const closingQuote = code.indexOf(char, index + 1);\n return closingQuote === -1 ? FAILED : closingQuote + 1;\n }\n return index + 1;\n}\n\nfunction readTagName(code: string, index: number): number {\n let cursor = index;\n while (TAG_NAME_CHAR.test(code.charAt(cursor))) {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction readOpeningTag(code: string, index: number): OpeningTag | null {\n const nameEnd = readTagName(code, index + 1);\n const name = code.slice(index + 1, nameEnd);\n let cursor =\n code.charAt(nameEnd) === \"<\" ? skipTypeArguments(code, nameEnd) : nameEnd;\n\n while (cursor !== FAILED && cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \">\") {\n return { end: cursor + 1, name, selfClosing: false };\n }\n if (char === \"/\" && code.charAt(cursor + 1) === \">\") {\n return { end: cursor + 2, name, selfClosing: true };\n }\n cursor = skipAttributeToken(code, cursor);\n }\n return null;\n}\n\nfunction readClosingTagEnd(code: string, index: number, name: string): number {\n let cursor = index + 2;\n while (WHITESPACE.test(code.charAt(cursor))) {\n cursor += 1;\n }\n const nameEnd = readTagName(code, cursor);\n if (code.slice(cursor, nameEnd) !== name) {\n return FAILED;\n }\n cursor = nameEnd;\n while (WHITESPACE.test(code.charAt(cursor))) {\n cursor += 1;\n }\n return code.charAt(cursor) === \">\" ? cursor + 1 : FAILED;\n}\n\nfunction skipChildren(code: string, index: number, name: string): number {\n let cursor = index;\n while (cursor !== FAILED && cursor < code.length) {\n const char = code.charAt(cursor);\n if (char === \"<\" && code.charAt(cursor + 1) === \"/\") {\n return readClosingTagEnd(code, cursor, name);\n }\n if (char === \"{\") {\n cursor = skipJsExpression(code, cursor);\n } else if (isTagStart(code, cursor)) {\n cursor = skipElement(code, cursor);\n } else {\n cursor += 1;\n }\n }\n return FAILED;\n}\n\nfunction skipElement(code: string, index: number): number {\n const tag = readOpeningTag(code, index);\n if (!tag) {\n return FAILED;\n }\n return tag.selfClosing ? tag.end : skipChildren(code, tag.end, tag.name);\n}\n\nfunction lineOffset(code: string, line: number): number {\n if (!Number.isInteger(line) || line < 1) {\n return FAILED;\n }\n let offset = 0;\n for (let current = 1; current < line; current += 1) {\n const newline = code.indexOf(\"\\n\", offset);\n if (newline === -1) {\n return FAILED;\n }\n offset = newline + 1;\n }\n return offset;\n}\n\nfunction findTagStart(\n code: string,\n lineStart: number,\n lineEnd: number,\n column: number\n): number {\n const origin = Math.min(lineStart + Math.max(column, 0), lineEnd);\n for (let back = 0; back <= MAX_TAG_LOOKBACK; back += 1) {\n const candidate = origin - back;\n if (candidate >= lineStart && isTagStart(code, candidate)) {\n return candidate;\n }\n }\n for (let candidate = origin + 1; candidate < lineEnd; candidate += 1) {\n if (isTagStart(code, candidate)) {\n return candidate;\n }\n }\n return FAILED;\n}\n\nfunction countNewlines(code: string, from: number, to: number): number {\n let count = 0;\n let newline = code.indexOf(\"\\n\", from);\n while (newline !== -1 && newline < to) {\n count += 1;\n newline = code.indexOf(\"\\n\", newline + 1);\n }\n return count;\n}\n\n/** Lines spanned by the JSX element at a 1-based line and 0-based column. */\nexport function jsxElementLines(\n code: string,\n line: number,\n column: number\n): LineRange | null {\n const lineStart = lineOffset(code, line);\n if (lineStart === FAILED) {\n return null;\n }\n const newline = code.indexOf(\"\\n\", lineStart);\n const lineEnd = newline === -1 ? code.length : newline;\n const tagStart = findTagStart(code, lineStart, lineEnd, column);\n if (tagStart === FAILED) {\n return null;\n }\n const elementEnd = skipElement(code, tagStart);\n if (elementEnd === FAILED) {\n return null;\n }\n return {\n end: line + countNewlines(code, tagStart, elementEnd - 1),\n start: line,\n };\n}\n","import { isAbsolute, relative, sep } from \"node:path\";\n\n/** Forward-slash path from the workspace root, or null when `realPath` escapes it (including another Windows drive). */\nexport function workspaceRelativePath(\n realPath: string,\n workspaceRoot: string\n): string | null {\n const relativePath = relative(workspaceRoot, realPath);\n const escapes =\n relativePath === \"\" ||\n relativePath === \"..\" ||\n relativePath.startsWith(`..${sep}`) ||\n isAbsolute(relativePath);\n return escapes ? null : relativePath.split(sep).join(\"/\");\n}\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { SourceMap } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { type DevtoolsOutcome, failure } from \"../json-response\";\nimport type { SourceRequest } from \"./source-file\";\nimport { workspaceRelativePath } from \"./workspace-path\";\n\nconst SERVER_FRAME_PREFIX = /^(?:about|rsc):\\/\\/React\\/Server\\//;\nconst QUERY_OR_HASH = /[?#].*$/;\nconst SOURCE_MAPPING_URL = /\\/\\/# sourceMappingURL=(\\S+)\\s*$/;\nconst MAX_MAP_BYTES = 50 * 1_048_576;\n\nconst mapCache = new Map<string, { map: SourceMap; mtimeMs: number }>();\n\nexport function isServerFrame(fileName: string): boolean {\n return SERVER_FRAME_PREFIX.test(fileName);\n}\n\nasync function mapPathFor(chunkPath: string): Promise<string> {\n const code = await readFile(chunkPath, \"utf8\");\n const declared = SOURCE_MAPPING_URL.exec(code)?.[1];\n return declared\n ? join(dirname(chunkPath), decodeURIComponent(declared))\n : `${chunkPath}.map`;\n}\n\nasync function loadMap(mapPath: string): Promise<SourceMap> {\n const { mtimeMs, size } = await stat(mapPath);\n if (size > MAX_MAP_BYTES) {\n throw new Error(\"source map too large\");\n }\n const cached = mapCache.get(mapPath);\n if (cached?.mtimeMs === mtimeMs) {\n return cached.map;\n }\n const map = new SourceMap(JSON.parse(await readFile(mapPath, \"utf8\")));\n mapCache.set(mapPath, { map, mtimeMs });\n return map;\n}\n\n/**\n * Server Components stamp their elements with frames into the dev server's\n * own chunks (`about://React/Server/file:///…/.next/…`); the browser cannot\n * fetch those maps, so they are resolved here from disk.\n */\nexport async function mapServerFrame(\n request: SourceRequest,\n workspaceRoot: string\n): Promise<DevtoolsOutcome<SourceRequest>> {\n const unreadable = failure<SourceRequest>(\n \"This element comes from a Server Component whose source map could not be read.\",\n 404\n );\n if (request.line === null) {\n return unreadable;\n }\n try {\n const chunkUrl = request.fileName\n .replace(SERVER_FRAME_PREFIX, \"\")\n .replace(QUERY_OR_HASH, \"\");\n const chunkPath = await realpath(fileURLToPath(chunkUrl));\n if (workspaceRelativePath(chunkPath, workspaceRoot) === null) {\n return failure<SourceRequest>(\n \"Reflet devtools only reads files inside your repository.\",\n 403\n );\n }\n const map = await loadMap(await mapPathFor(chunkPath));\n const origin = map.findOrigin(request.line, (request.column ?? 0) + 1);\n if (!(\"fileName\" in origin)) {\n return unreadable;\n }\n return {\n ok: true,\n value: {\n column: origin.columnNumber - 1,\n fileName: origin.fileName,\n line: origin.lineNumber,\n },\n };\n } catch {\n return unreadable;\n }\n}\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { extname, isAbsolute, join } from \"node:path\";\nimport type { SourceFile } from \"../../protocol\";\nimport { type DevtoolsOutcome, failure } from \"../json-response\";\nimport { jsxElementLines } from \"./jsx-range\";\nimport type { ProjectRoots } from \"./project-roots\";\nimport { isServerFrame, mapServerFrame } from \"./server-frame\";\nimport { workspaceRelativePath } from \"./workspace-path\";\n\nconst MAX_SOURCE_BYTES = 1_048_576;\nconst MAX_FILE_NAME_LENGTH = 2048;\nconst MAX_NORMALIZE_PASSES = 8;\nconst SOURCE_EXTENSIONS = [\n \".astro\",\n \".cjs\",\n \".js\",\n \".jsx\",\n \".mdx\",\n \".mjs\",\n \".svelte\",\n \".ts\",\n \".tsx\",\n \".vue\",\n];\nconst EXTENSION_REFUSAL = `Reflet devtools only reads source files (${SOURCE_EXTENSIONS.join(\", \")}).`;\nconst OUTSIDE_WORKSPACE_REFUSAL =\n \"Reflet devtools only reads files inside your repository.\";\nconst NODE_MODULES_REFUSAL =\n \"Reflet devtools does not read files inside node_modules.\";\nconst QUERY_OR_HASH = /[?#].*$/;\nconst TURBOPACK_MODULE_SUFFIX = /(?: \\[[\\w-]+\\])+(?: \\([\\w-]+\\))*$/;\nconst URL_PREFIXES = [/^file:\\/\\//, /^https?:\\/\\/[^/]*/];\nconst SLASH_BEFORE_DRIVE = /^\\/(?=[a-z]:[\\\\/])/i;\nconst BUNDLER_PREFIXES = [\n /^rsc:\\/\\/React\\/[^/]+\\//,\n /^webpack-internal:\\/{2,}/,\n /^webpack:\\/\\/[^/]*\\//,\n /^turbopack:\\/{2,}/,\n /^\\[project\\]\\//,\n /^\\(app-pages-browser\\)\\//,\n /^\\([\\w-]+\\)\\/(?=\\.\\/)/,\n /^\\/@fs(?=\\/)/,\n /^\\.\\//,\n];\n\ninterface LocatedFile {\n realPath: string;\n relativePath: string;\n size: number;\n}\n\ntype CandidateCheck =\n | ({ kind: \"found\" } & LocatedFile)\n | { kind: \"missing\" }\n | { kind: \"refused\"; reason: string };\n\nexport interface SourceRequest {\n column: number | null;\n fileName: string;\n line: number | null;\n}\n\nfunction decodePath(path: string): string {\n try {\n return decodeURIComponent(path);\n } catch {\n return path;\n }\n}\n\nfunction stripFirstPrefix(fileName: string, prefixes: RegExp[]): string {\n for (const prefix of prefixes) {\n if (prefix.test(fileName)) {\n return fileName.replace(prefix, \"\");\n }\n }\n return fileName;\n}\n\n/** Turns a file name from a React debug stack into a filesystem path. */\nexport function normalizeSourceFileName(rawFileName: string): string {\n let fileName = rawFileName\n .trim()\n .replace(QUERY_OR_HASH, \"\")\n .replace(TURBOPACK_MODULE_SUFFIX, \"\");\n let isUrlEncoded = false;\n\n for (let pass = 0; pass < MAX_NORMALIZE_PASSES; pass += 1) {\n const withoutUrl = stripFirstPrefix(fileName, URL_PREFIXES);\n isUrlEncoded ||= withoutUrl !== fileName;\n const stripped = stripFirstPrefix(withoutUrl, BUNDLER_PREFIXES);\n if (stripped === fileName) {\n break;\n }\n fileName = stripped;\n }\n\n const path = isUrlEncoded ? decodePath(fileName) : fileName;\n return path.replace(SLASH_BEFORE_DRIVE, \"\");\n}\n\nfunction candidatePaths(fileName: string, roots: ProjectRoots): string[] {\n const candidates = [\n join(roots.root, fileName),\n join(roots.workspaceRoot, fileName),\n ];\n if (isAbsolute(fileName)) {\n candidates.unshift(fileName);\n }\n return [...new Set(candidates)];\n}\n\nfunction isSourceExtension(path: string): boolean {\n return SOURCE_EXTENSIONS.includes(extname(path).toLowerCase());\n}\n\nasync function checkCandidate(\n candidate: string,\n workspaceRoot: string\n): Promise<CandidateCheck> {\n let realPath: string;\n let size: number;\n try {\n realPath = await realpath(candidate);\n const stats = await stat(realPath);\n if (!stats.isFile()) {\n return { kind: \"missing\" };\n }\n size = stats.size;\n } catch {\n return { kind: \"missing\" };\n }\n\n const relativePath = workspaceRelativePath(realPath, workspaceRoot);\n if (relativePath === null) {\n return { kind: \"refused\", reason: OUTSIDE_WORKSPACE_REFUSAL };\n }\n if (relativePath.split(\"/\").includes(\"node_modules\")) {\n return { kind: \"refused\", reason: NODE_MODULES_REFUSAL };\n }\n if (!isSourceExtension(realPath)) {\n return { kind: \"refused\", reason: EXTENSION_REFUSAL };\n }\n return { kind: \"found\", realPath, relativePath, size };\n}\n\nasync function locateSourceFile(\n fileName: string,\n roots: ProjectRoots\n): Promise<DevtoolsOutcome<LocatedFile>> {\n let refusal: string | null = null;\n for (const candidate of candidatePaths(fileName, roots)) {\n const check = await checkCandidate(candidate, roots.workspaceRoot);\n if (check.kind === \"found\") {\n return { ok: true, value: check };\n }\n if (check.kind === \"refused\") {\n refusal ??= check.reason;\n }\n }\n if (refusal) {\n return failure(refusal, 403);\n }\n return failure(`Could not find ${fileName} in ${roots.workspaceRoot}.`, 404);\n}\n\n/** Server-map columns can point past the line; the element then starts at its first tag. */\nfunction columnWithinLine(code: string, line: number, column: number | null) {\n const text = code.split(\"\\n\")[line - 1] ?? \"\";\n return column !== null && column < text.length ? column : null;\n}\n\nexport async function readSourceFile(\n frame: SourceRequest,\n roots: ProjectRoots\n): Promise<DevtoolsOutcome<SourceFile>> {\n if (\n frame.fileName.length > MAX_FILE_NAME_LENGTH ||\n frame.fileName.includes(\"\\0\")\n ) {\n return failure(\"That source file name is not a valid path.\", 400);\n }\n const mapped = isServerFrame(frame.fileName)\n ? await mapServerFrame(frame, roots.workspaceRoot)\n : { ok: true as const, value: frame };\n if (!mapped.ok) {\n return mapped;\n }\n const request = mapped.value;\n const fileName = normalizeSourceFileName(request.fileName);\n if (!fileName) {\n return failure(\"A source file name is required.\", 400);\n }\n if (!isSourceExtension(fileName)) {\n return failure(EXTENSION_REFUSAL, 403);\n }\n\n const located = await locateSourceFile(fileName, roots);\n if (!located.ok) {\n return located;\n }\n const { realPath, relativePath, size } = located.value;\n if (size > MAX_SOURCE_BYTES) {\n return failure(\n `${relativePath} is larger than 1 MB, too big to preview.`,\n 413\n );\n }\n\n const code = await readFile(realPath, \"utf8\");\n const column =\n request.line === null\n ? request.column\n : columnWithinLine(code, request.line, request.column);\n const elementLines =\n request.line === null\n ? null\n : jsxElementLines(code, request.line, column ?? 0);\n\n return {\n ok: true,\n value: {\n absolutePath: realPath,\n code,\n column,\n elementLines,\n line: request.line,\n path: relativePath,\n },\n };\n}\n","import {\n DEVTOOLS_ENDPOINTS,\n DEVTOOLS_ROUTE_BASE,\n DEVTOOLS_STATUS_MARKER,\n type DevtoolsStatus,\n} from \"../protocol\";\nimport { boardAccess } from \"./connect/board-credential\";\nimport {\n disconnect,\n finishConnect,\n startConnect,\n} from \"./connect/connect-routes\";\nimport {\n type DevtoolsOutcome,\n errorResponse,\n jsonResponse,\n} from \"./json-response\";\nimport {\n type DevtoolsEnv,\n type DevtoolsServerOptions,\n type ResolvedDevtoolsOptions,\n resolveDevtoolsOptions,\n} from \"./options\";\nimport { proxyWithBoardCredential } from \"./reflet-proxy\";\nimport { rejectUntrustedCaller, rejectUntrustedHost } from \"./request-guard\";\nimport { searchCode } from \"./source/code-search\";\nimport { type ProjectRoots, resolveProjectRoots } from \"./source/project-roots\";\nimport { readSourceFile } from \"./source/source-file\";\n\nexport type DevtoolsHandler = (request: Request) => Promise<Response>;\n\nconst TRAILING_SLASHES = /\\/+$/;\n\nconst ENDPOINT_METHODS: Record<string, \"GET\" | \"POST\"> = {\n [DEVTOOLS_ENDPOINTS.connectCallback]: \"GET\",\n [DEVTOOLS_ENDPOINTS.connectStart]: \"POST\",\n [DEVTOOLS_ENDPOINTS.disconnect]: \"POST\",\n [DEVTOOLS_ENDPOINTS.search]: \"GET\",\n [DEVTOOLS_ENDPOINTS.source]: \"GET\",\n [DEVTOOLS_ENDPOINTS.status]: \"GET\",\n};\n\nfunction outcomeResponse<T>(outcome: DevtoolsOutcome<T>): Response {\n return outcome.ok\n ? jsonResponse(outcome.value)\n : errorResponse(outcome.error, outcome.status);\n}\n\nfunction routeSubPath(pathname: string): string | null {\n const baseIndex = pathname.indexOf(DEVTOOLS_ROUTE_BASE);\n if (baseIndex === -1) {\n return null;\n }\n return pathname\n .slice(baseIndex + DEVTOOLS_ROUTE_BASE.length)\n .replace(TRAILING_SLASHES, \"\");\n}\n\nfunction readInteger(value: string | null, minimum: number): number | null {\n if (value === null || value === \"\") {\n return null;\n }\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed >= minimum ? parsed : null;\n}\n\nasync function routeRequest(\n request: Request,\n subPath: string | null,\n settings: ResolvedDevtoolsOptions,\n projectRoots: () => ProjectRoots\n): Promise<Response> {\n const url = new URL(request.url);\n\n if (subPath?.startsWith(`${DEVTOOLS_ENDPOINTS.proxy}/`)) {\n const apiPath = subPath.slice(DEVTOOLS_ENDPOINTS.proxy.length);\n return await proxyWithBoardCredential(request, apiPath, settings);\n }\n\n const requiredMethod = subPath ? ENDPOINT_METHODS[subPath] : undefined;\n if (requiredMethod && request.method !== requiredMethod) {\n return errorResponse(\n `${subPath} only answers ${requiredMethod} requests.`,\n 405\n );\n }\n\n switch (subPath) {\n case DEVTOOLS_ENDPOINTS.status:\n return jsonResponse({\n board: await boardAccess(request, settings),\n editor: settings.editor,\n marker: DEVTOOLS_STATUS_MARKER,\n } satisfies DevtoolsStatus);\n case DEVTOOLS_ENDPOINTS.connectStart:\n return await startConnect(request, settings);\n case DEVTOOLS_ENDPOINTS.connectCallback:\n return await finishConnect(request, settings);\n case DEVTOOLS_ENDPOINTS.disconnect:\n return await disconnect(settings);\n case DEVTOOLS_ENDPOINTS.source:\n return outcomeResponse(\n await readSourceFile(\n {\n column: readInteger(url.searchParams.get(\"column\"), 0),\n fileName: url.searchParams.get(\"file\") ?? \"\",\n line: readInteger(url.searchParams.get(\"line\"), 1),\n },\n projectRoots()\n )\n );\n case DEVTOOLS_ENDPOINTS.search:\n return outcomeResponse(\n await searchCode(\n projectRoots().workspaceRoot,\n url.searchParams.get(\"q\") ?? \"\"\n )\n );\n default:\n return errorResponse(\n `No Reflet devtools endpoint at ${url.pathname}.`,\n 404\n );\n }\n}\n\nexport function createDevtoolsHandler(\n options: DevtoolsServerOptions = {},\n env: DevtoolsEnv = process.env\n): DevtoolsHandler {\n const settings = resolveDevtoolsOptions(options, env);\n let roots: ProjectRoots | null = null;\n const projectRoots = (): ProjectRoots => {\n roots ??= resolveProjectRoots(settings.root);\n return roots;\n };\n\n return async (request) => {\n const hostRejection = rejectUntrustedHost(request, settings.allowedHosts);\n if (hostRejection) {\n return hostRejection;\n }\n const subPath = routeSubPath(new URL(request.url).pathname);\n const isConnectCallback =\n request.method === \"GET\" &&\n subPath === DEVTOOLS_ENDPOINTS.connectCallback;\n const callerRejection = isConnectCallback\n ? null\n : rejectUntrustedCaller(request, settings.allowedHosts);\n if (callerRejection) {\n return callerRejection;\n }\n try {\n return await routeRequest(request, subPath, settings, projectRoots);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n return errorResponse(`Reflet devtools route failed: ${reason}`, 500);\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -18,6 +18,7 @@ const SESSION_API_PATHS = [
|
|
|
18
18
|
"/api/v1/sessions/intentions/detach",
|
|
19
19
|
"/api/v1/sessions/intentions/keep-separate",
|
|
20
20
|
"/api/v1/sessions/list",
|
|
21
|
+
"/api/v1/sessions/live",
|
|
21
22
|
"/api/v1/sessions/proposals/clarify",
|
|
22
23
|
"/api/v1/sessions/proposals/decide",
|
|
23
24
|
"/api/v1/sessions/proposals/delete",
|
|
@@ -31,6 +32,8 @@ const SESSION_API_PATHS = [
|
|
|
31
32
|
"/api/v1/sessions/segments/context-choices",
|
|
32
33
|
"/api/v1/sessions/segments/correct",
|
|
33
34
|
"/api/v1/sessions/segments/retry",
|
|
35
|
+
"/api/v1/sessions/speakers",
|
|
36
|
+
"/api/v1/sessions/speakers/token",
|
|
34
37
|
"/api/v1/sessions/start",
|
|
35
38
|
"/api/v1/sessions/update",
|
|
36
39
|
"/api/v1/sessions/upload-url"
|
|
@@ -71,4 +74,4 @@ const DEVTOOLS_STATUS_MARKER = "reflet-devtools";
|
|
|
71
74
|
//#endregion
|
|
72
75
|
export { EDITORS as a, DEVTOOLS_STATUS_MARKER as i, DEVTOOLS_REQUEST_HEADER as n, PROXIED_API_PATHS as o, DEVTOOLS_ROUTE_BASE as r, DEVTOOLS_ENDPOINTS as t };
|
|
73
76
|
|
|
74
|
-
//# sourceMappingURL=protocol-
|
|
77
|
+
//# sourceMappingURL=protocol-P5T66Bs3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol-P5T66Bs3.js","names":[],"sources":["../src/sessions/api-paths.ts","../src/devtools/protocol.ts"],"sourcesContent":["export const SESSION_API_PATHS = [\n \"/api/v1/sessions/analyze\",\n \"/api/v1/sessions/collection\",\n \"/api/v1/sessions/delete\",\n \"/api/v1/sessions/detail\",\n \"/api/v1/sessions/events\",\n \"/api/v1/sessions/evidence\",\n \"/api/v1/sessions/evidence/remove\",\n \"/api/v1/sessions/handoffs\",\n \"/api/v1/sessions/handoffs/delivered\",\n \"/api/v1/sessions/handoffs/preview\",\n \"/api/v1/sessions/identity\",\n \"/api/v1/sessions/intentions/accept\",\n \"/api/v1/sessions/intentions/answer\",\n \"/api/v1/sessions/intentions/attach\",\n \"/api/v1/sessions/intentions/change\",\n \"/api/v1/sessions/intentions/detach\",\n \"/api/v1/sessions/intentions/keep-separate\",\n \"/api/v1/sessions/list\",\n \"/api/v1/sessions/live\",\n \"/api/v1/sessions/proposals/clarify\",\n \"/api/v1/sessions/proposals/decide\",\n \"/api/v1/sessions/proposals/delete\",\n \"/api/v1/sessions/proposals/edit\",\n \"/api/v1/sessions/proposals/feedback\",\n \"/api/v1/sessions/proposals/merge\",\n \"/api/v1/sessions/proposals/separate\",\n \"/api/v1/sessions/proposals/verify\",\n \"/api/v1/sessions/segments\",\n \"/api/v1/sessions/segments/context\",\n \"/api/v1/sessions/segments/context-choices\",\n \"/api/v1/sessions/segments/correct\",\n \"/api/v1/sessions/segments/retry\",\n \"/api/v1/sessions/speakers\",\n \"/api/v1/sessions/speakers/token\",\n \"/api/v1/sessions/start\",\n \"/api/v1/sessions/update\",\n \"/api/v1/sessions/upload-url\",\n] as const;\n\nexport type SessionApiPath = (typeof SESSION_API_PATHS)[number];\n","import { SESSION_API_PATHS } from \"../sessions/api-paths\";\n\nexport const DEVTOOLS_ROUTE_BASE = \"/api/reflet-devtools\";\n\n/**\n * Sent on every devtools request. A custom header forces a CORS preflight, so\n * a page on another origin cannot drive the route from the developer's browser.\n */\nexport const DEVTOOLS_REQUEST_HEADER = \"x-reflet-devtools\";\n\nexport const DEVTOOLS_ENDPOINTS = {\n connectCallback: \"/connect/callback\",\n connectStart: \"/connect/start\",\n disconnect: \"/connect/disconnect\",\n proxy: \"/proxy\",\n search: \"/search\",\n source: \"/source\",\n status: \"/status\",\n} as const;\n\nexport const PROXIED_API_PATHS = [\n \"/api/v1/feedback/create\",\n \"/api/v1/feedback/item\",\n \"/api/v1/feedback/list\",\n \"/api/v1/feedback/screenshot/save\",\n \"/api/v1/feedback/screenshot/upload-url\",\n ...SESSION_API_PATHS,\n] as const;\n\nexport const EDITORS = [\n \"cursor\",\n \"vscode\",\n \"webstorm\",\n \"windsurf\",\n \"zed\",\n] as const;\n\nexport type EditorId = (typeof EDITORS)[number];\n\nexport const DEVTOOLS_STATUS_MARKER = \"reflet-devtools\";\n\nexport type BoardAccess =\n | { kind: \"secretKey\" }\n | { kind: \"connected\"; organizationName: string }\n | { canConnect: boolean; kind: \"disconnected\" };\n\nexport interface DevtoolsStatus {\n board: BoardAccess;\n editor: EditorId;\n marker: typeof DEVTOOLS_STATUS_MARKER;\n}\n\nexport interface ConnectStartResponse {\n authorizeUrl: string;\n}\n\nexport interface DisconnectResponse {\n revoked: boolean;\n}\n\nexport interface LineRange {\n end: number;\n start: number;\n}\n\nexport interface SourceFile {\n absolutePath: string;\n code: string;\n /** 0-based, like React's frames; null when the map only knows the line. */\n column: number | null;\n /** Lines spanned by the JSX element the frame points at, 1-based. */\n elementLines: LineRange | null;\n line: number | null;\n /** Relative to the repository root, for display. */\n path: string;\n}\n\nexport interface CodeMatch {\n absolutePath: string;\n line: number;\n path: string;\n preview: string;\n}\n\nexport interface CodeSearchResult {\n matches: CodeMatch[];\n}\n\nexport interface DevtoolsErrorBody {\n error: string;\n}\n"],"mappings":";AAAA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACpCA,MAAa,sBAAsB;;;;;AAMnC,MAAa,0BAA0B;AAEvC,MAAa,qBAAqB;CAChC,iBAAiB;CACjB,cAAc;CACd,YAAY;CACZ,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,QAAQ;AACV;AAEA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA,GAAG;AACL;AAEA,MAAa,UAAU;CACrB;CACA;CACA;CACA;CACA;AACF;AAIA,MAAa,yBAAyB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as EDITORS, n as DEVTOOLS_REQUEST_HEADER, o as PROXIED_API_PATHS, r as DEVTOOLS_ROUTE_BASE, t as DEVTOOLS_ENDPOINTS } from "./protocol-
|
|
1
|
+
import { a as EDITORS, n as DEVTOOLS_REQUEST_HEADER, o as PROXIED_API_PATHS, r as DEVTOOLS_ROUTE_BASE, t as DEVTOOLS_ENDPOINTS } from "./protocol-P5T66Bs3.js";
|
|
2
2
|
import "./client-oFFfRxAM.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
@@ -471,4 +471,4 @@ async function proxyWithBoardCredential(request, apiPath, settings) {
|
|
|
471
471
|
//#endregion
|
|
472
472
|
export { rejectUntrustedHost as _, connectCallbackUriFor as a, jsonResponse as b, finishConnect as c, startConnect as d, PENDING_CONNECT_TTL_MS as f, rejectUntrustedCaller as g, isLoopbackAddress as h, connectAuthorizeUrl as i, forgetConnection as l, readConnection as m, boardAccess as n, connectOutcomePage as o, htmlPage as p, resolveDevtoolsOptions as r, disconnect as s, proxyWithBoardCredential as t, redeemConnectCode as u, errorResponse as v, failure as y };
|
|
473
473
|
|
|
474
|
-
//# sourceMappingURL=reflet-proxy-
|
|
474
|
+
//# sourceMappingURL=reflet-proxy-CiMPGYzD.js.map
|