reflet-sdk 0.7.5 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +16 -8
  3. package/dist/desktop.d.ts.map +1 -1
  4. package/dist/desktop.js +3 -2
  5. package/dist/desktop.js.map +1 -1
  6. package/dist/devtools-layer-CYIoe3Vo.js +372 -0
  7. package/dist/devtools-layer-CYIoe3Vo.js.map +1 -0
  8. package/dist/devtools-next.js +1 -1
  9. package/dist/devtools-vite.js +3 -3
  10. package/dist/feedback.js +6 -6
  11. package/dist/feedback.js.map +1 -1
  12. package/dist/{handler-ndF3gZBx.js → handler-1XhfZvZ0.js} +3 -3
  13. package/dist/{handler-ndF3gZBx.js.map → handler-1XhfZvZ0.js.map} +1 -1
  14. package/dist/{protocol-cJVVwnPe.js → protocol-BnurX0CF.js} +2 -1
  15. package/dist/protocol-BnurX0CF.js.map +1 -0
  16. package/dist/{reflet-proxy-BW6q9xds.js → reflet-proxy-DVE6ov2f.js} +14 -7
  17. package/dist/reflet-proxy-DVE6ov2f.js.map +1 -0
  18. package/dist/{submit-DJIKxRUp.js → submit-r3_M1ITo.js} +71 -9
  19. package/dist/submit-r3_M1ITo.js.map +1 -0
  20. package/dist/{team-layer-_It1_oSo.js → team-layer-5-uPYTjV.js} +162 -33
  21. package/dist/team-layer-5-uPYTjV.js.map +1 -0
  22. package/dist/{devtools-styles-TWR5Ps34.js → use-sheet-tab-CacYFVjI.js} +4241 -685
  23. package/dist/use-sheet-tab-CacYFVjI.js.map +1 -0
  24. package/package.json +1 -1
  25. package/dist/devtools-layer-o1O55wu1.js +0 -3818
  26. package/dist/devtools-layer-o1O55wu1.js.map +0 -1
  27. package/dist/devtools-styles-TWR5Ps34.js.map +0 -1
  28. package/dist/protocol-cJVVwnPe.js.map +0 -1
  29. package/dist/reflet-proxy-BW6q9xds.js.map +0 -1
  30. package/dist/selection-outline-NzAAAZXR.js +0 -51
  31. package/dist/selection-outline-NzAAAZXR.js.map +0 -1
  32. package/dist/submit-DJIKxRUp.js.map +0 -1
  33. package/dist/team-layer-_It1_oSo.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ 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.7] - 2026-10-17
9
+
10
+ ### Added
11
+
12
+ - Team tools in desktop apps: the bar now opens the full panel, with Board, Notes and Sessions. Members pick an element, note it and add it to the board, or read the board's feedback, all through the bridge. There is no Code tab and no source lookup, since a production build has no dev server. Team tools in a browser stay Sessions only.
13
+
14
+ ### Changed
15
+
16
+ - Team tools: the bar's grip tooltip names the organization you are signed in to.
17
+ - Desktop sign-in: the reflet.app page says "Sign in to a desktop app" and "Go back to the app" instead of asking to connect a dev server.
18
+ - Sessions: Prepare brief shows the brief right away, with Copy brief and Download .zip. Ticking or unticking an intention or a screenshot updates it in place; Build brief and Edit selection are gone. The brief is only saved under Earlier briefs once you copy or download it. Requires the matching Reflet backend.
19
+ - Sessions: until a finished session is processed, the review lists its steps in order (upload, voice transcription, finding intentions with AI, or the comparison with the revision it continues), each marked done, running, waiting for the one before, or failed with its reason. A session whose analysis is still waiting to upload no longer offers Analyze. The session list says "Finding intentions" instead of "Reading".
20
+
21
+ ## [0.7.6] - 2026-10-17
22
+
23
+ ### Changed
24
+
25
+ - Pick: the note card's actions are smaller. Pick another and Copy are icon buttons (their names show on hover), and View code is now Code with an icon.
26
+ - Devtools: an empty Board says "This page" or "Whole board" above its message instead of "0 on this page" or "0 on the board".
27
+ - Devtools: the panel has no divider lines under its tabs or above the account footer.
28
+
8
29
  ## [0.7.5] - 2026-10-17
9
30
 
10
31
  ### Added
package/README.md CHANGED
@@ -192,12 +192,12 @@ builds drop it at bundle time — the devtools chunk is never shipped to your
192
192
  users. Pass `devtools={false}` to turn it off.
193
193
 
194
194
  - **Pick** — click an element to write a note on it. The note card has a
195
- "View code" button, and Shift+click (or Shift+Enter) skips the note and opens
195
+ Code button, and Shift+click (or Shift+Enter) skips the note and opens
196
196
  the source file with the JSX element highlighted, ready to jump to in your
197
197
  editor. Locations come from React's debug stacks resolved through the dev
198
198
  server's source maps, Server Components included. Press ⌘C (Ctrl+C) on the
199
- aimed element, or Copy on the note card, to put the element and its source on
200
- the clipboard for a coding agent, without saving a note.
199
+ aimed element, or the note card's copy button, to put the element and its
200
+ source on the clipboard for a coding agent, without saving a note.
201
201
  - **Notes** — a note appears the moment you press Enter, as a numbered pin on
202
202
  its element, Figma-style; click the pin to read, edit or delete it, and find
203
203
  the same number on its card in the panel. Its source location and a
@@ -215,12 +215,14 @@ users. Pass `devtools={false}` to turn it off.
215
215
  source location, and a code search for the element's text.
216
216
  - **Sessions** — talk through the app while you use it: Reflet records your
217
217
  voice, what you point at and mark, and a screenshot at the start, at each
218
- mark and on each page change. Finish, and Reflet transcribes the session and
219
- proposes the intentions behind what you said. Confirm, edit or dismiss each
218
+ mark and on each page change. Finish, and Reflet uploads and transcribes the
219
+ session, then its AI proposes the intentions behind what you said; the review
220
+ shows which of these steps is running. Confirm, edit or dismiss each
220
221
  one. Like notes, confirmed intentions have two ways out: **Prepare brief**
221
- builds a brief you copy into a coding agent or download as a `.zip` with its
222
- screenshots (nothing is shared until you copy or download it), and **Add to
223
- board** turns them into internal feedback, one by one or all at once.
222
+ shows the brief right away, ready to copy into a coding agent or download as
223
+ a `.zip` with its screenshots (nothing is shared until you copy or download
224
+ it), and **Add to board** turns them into internal feedback, one by one or
225
+ all at once.
224
226
  Sessions are recorded under your own name, so they need Connect rather than
225
227
  `REFLET_SECRET_KEY`.
226
228
 
@@ -330,6 +332,12 @@ Expose the four calls from the preload script, then pass them as the bridge:
330
332
  at once, so only pass the bridge in builds meant for your team. `request` only
331
333
  forwards the session and feedback endpoints the devtools use.
332
334
 
335
+ A desktop app gets more than sessions: the bar opens the devtools panel with
336
+ Board, Notes and Sessions, so members can pick an element, note it, add it to
337
+ the board, and read the board's feedback. Everything that needs your source
338
+ code (the Code tab, source locations you can open) stays in development. The
339
+ browser flow above records sessions only.
340
+
333
341
  ### 5. In-App Surveys
334
342
 
335
343
  Create surveys in the Reflet dashboard (NPS, ratings, choices, text, statements,
@@ -1 +1 @@
1
- {"version":3,"file":"desktop.d.ts","names":[],"sources":["../src/devtools/server/desktop.ts"],"mappings":";;iBA4BiB;;EAEf;;EAEA;;EAEA;;EAEA,eAAe,gBAAgB;EAC/B;;;;;;;;;wBAsGc,oBACd,SAAS,uBACR"}
1
+ {"version":3,"file":"desktop.d.ts","names":[],"sources":["../src/devtools/server/desktop.ts"],"mappings":";;iBA4BiB;;EAEf;;EAEA;;EAEA;;EAEA,eAAe,gBAAgB;EAC/B;;;;;;;;;wBAuGc,oBACd,SAAS,uBACR"}
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-BW6q9xds.js";
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-DVE6ov2f.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";
@@ -28,7 +28,7 @@ function awaitConnectCallback(server, pending) {
28
28
  redirectUri: pending.redirectUri,
29
29
  state: pending.state
30
30
  });
31
- await sendPage(response, connectOutcomePage(outcome));
31
+ await sendPage(response, connectOutcomePage(outcome, "desktopApp"));
32
32
  if (!outcome.ok) throw new Error(outcome.message);
33
33
  return { organizationName: outcome.organizationName };
34
34
  };
@@ -50,6 +50,7 @@ async function startBrowserSignIn(settings, publicKey) {
50
50
  const port = await listenOnLoopback(server);
51
51
  const redirectUri = connectCallbackUriFor(`http://${LOOPBACK_HOST}:${port}`);
52
52
  const { authorizeUrl, state } = connectAuthorizeUrl(settings, {
53
+ client: "desktopApp",
53
54
  publicKey,
54
55
  redirectUri
55
56
  });
@@ -1 +1 @@
1
- {"version":3,"file":"desktop.js","names":[],"sources":["../src/devtools/server/desktop.ts"],"sourcesContent":["import { createServer, type Server, type ServerResponse } from \"node:http\";\nimport type {\n TeamToolsAccount,\n TeamToolsBridge,\n} from \"../../sessions/team/team-tools-bridge\";\nimport {\n connectAuthorizeUrl,\n connectCallbackUriFor,\n connectOutcomePage,\n forgetConnection,\n redeemConnectCode,\n} from \"./connect/connect-routes\";\nimport { readConnection } from \"./connect/connection-store\";\nimport { htmlPage } from \"./connect/html-page\";\nimport { PENDING_CONNECT_TTL_MS } from \"./connect/pending-connects\";\nimport {\n type ResolvedDevtoolsOptions,\n resolveDevtoolsOptions,\n} from \"./options\";\nimport { proxyWithBoardCredential } from \"./reflet-proxy\";\n\nexport type {\n TeamToolsAccount,\n TeamToolsBridge,\n TeamToolsCall,\n TeamToolsReply,\n} from \"../../sessions/team/team-tools-bridge\";\n\nexport interface TeamToolsHostOptions {\n /** Reflet API origin. Defaults to the hosted API. */\n apiUrl?: string;\n /** A directory only this app uses, such as Electron's `app.getPath(\"userData\")`. Keeps its sign-in apart from other apps and dev servers. */\n appDataDirectory: string;\n /** Reflet web app origin sign-in happens on. Defaults to https://www.reflet.app. */\n appUrl?: string;\n /** Opens a URL in the system browser, such as Electron's `shell.openExternal`. */\n openExternal: (url: string) => Promise<void>;\n publicKey: string;\n}\n\ninterface BrowserSignIn {\n account: Promise<TeamToolsAccount>;\n authorizeUrl: string;\n}\n\nconst LOOPBACK_HOST = \"127.0.0.1\";\nconst SIGN_IN_TIMED_OUT = \"Reflet sign-in timed out. Sign in again.\";\n\nasync function sendPage(response: ServerResponse, page: Response) {\n response.writeHead(page.status, Object.fromEntries(page.headers));\n response.end(await page.text());\n}\n\nasync function listenOnLoopback(server: Server): Promise<number> {\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, LOOPBACK_HOST, resolve);\n });\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n throw new Error(\"The Reflet sign-in listener has no port.\");\n }\n return address.port;\n}\n\n/** Settles on the first callback carrying this sign-in's state; anything else gets a 404 and changes nothing. */\nfunction awaitConnectCallback(\n server: Server,\n pending: {\n redirectUri: string;\n settings: ResolvedDevtoolsOptions;\n state: string;\n }\n): Promise<TeamToolsAccount> {\n const callbackPath = new URL(pending.redirectUri).pathname;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(\n () => reject(new Error(SIGN_IN_TIMED_OUT)),\n PENDING_CONNECT_TTL_MS\n );\n let isRedeeming = false;\n const redeem = async (url: URL, response: ServerResponse) => {\n const outcome = await redeemConnectCode(pending.settings, {\n code: url.searchParams.get(\"code\"),\n redirectUri: pending.redirectUri,\n state: pending.state,\n });\n await sendPage(response, connectOutcomePage(outcome));\n if (!outcome.ok) {\n throw new Error(outcome.message);\n }\n return { organizationName: outcome.organizationName };\n };\n server.on(\"request\", (request, response) => {\n const url = new URL(request.url ?? \"/\", pending.redirectUri);\n const isThisSignIn =\n request.method === \"GET\" &&\n url.pathname === callbackPath &&\n url.searchParams.get(\"state\") === pending.state;\n if (isRedeeming || !isThisSignIn) {\n sendPage(\n response,\n htmlPage(\"Not found\", \"Nothing here answers this link.\", 404)\n ).catch(() => undefined);\n return;\n }\n isRedeeming = true;\n clearTimeout(timeout);\n redeem(url, response).then(resolve, reject);\n });\n });\n}\n\nasync function startBrowserSignIn(\n settings: ResolvedDevtoolsOptions,\n publicKey: string\n): Promise<BrowserSignIn> {\n const server = createServer();\n const port = await listenOnLoopback(server);\n const redirectUri = connectCallbackUriFor(`http://${LOOPBACK_HOST}:${port}`);\n const { authorizeUrl, state } = connectAuthorizeUrl(settings, {\n publicKey,\n redirectUri,\n });\n const account = awaitConnectCallback(server, {\n redirectUri,\n settings,\n state,\n }).finally(() => server.close());\n return { account, authorizeUrl };\n}\n\n/**\n * Runs team tools for a desktop app in its privileged process (Electron's\n * main): sign-in goes through the system browser back to a one-shot loopback\n * listener, and the token stays on disk outside the page, like the dev\n * server's Connect. Expose the returned bridge to the page over IPC and pass it\n * to `<RefletFeedback teamTools={bridge} />`.\n */\nexport function createTeamToolsHost(\n options: TeamToolsHostOptions\n): TeamToolsBridge {\n const settings = resolveDevtoolsOptions(\n {\n apiUrl: options.apiUrl,\n appUrl: options.appUrl,\n root: options.appDataDirectory,\n },\n {}\n );\n let pendingSignIn: Promise<BrowserSignIn> | null = null;\n\n const currentSignIn = (): Promise<BrowserSignIn> => {\n if (pendingSignIn) {\n return pendingSignIn;\n }\n const started = startBrowserSignIn(settings, options.publicKey);\n pendingSignIn = started;\n const release = () => {\n if (pendingSignIn === started) {\n pendingSignIn = null;\n }\n };\n started.then((signIn) => signIn.account).then(release, release);\n return started;\n };\n\n return {\n account: async () => {\n const connection = await readConnection(settings.root, settings.apiUrl);\n return connection && { organizationName: connection.organizationName };\n },\n request: async (call) => {\n const search = call.query ? `?${new URLSearchParams(call.query)}` : \"\";\n const response = await proxyWithBoardCredential(\n new Request(`${settings.apiUrl}/${search}`, {\n body: call.method === \"POST\" ? call.body : undefined,\n method: call.method,\n }),\n call.path,\n settings\n );\n return { body: await response.text(), status: response.status };\n },\n signIn: async () => {\n const signIn = await currentSignIn();\n await options.openExternal(signIn.authorizeUrl);\n return await signIn.account;\n },\n signOut: async () => {\n await forgetConnection(settings);\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"desktop.js","names":[],"sources":["../src/devtools/server/desktop.ts"],"sourcesContent":["import { createServer, type Server, type ServerResponse } from \"node:http\";\nimport type {\n TeamToolsAccount,\n TeamToolsBridge,\n} from \"../../sessions/team/team-tools-bridge\";\nimport {\n connectAuthorizeUrl,\n connectCallbackUriFor,\n connectOutcomePage,\n forgetConnection,\n redeemConnectCode,\n} from \"./connect/connect-routes\";\nimport { readConnection } from \"./connect/connection-store\";\nimport { htmlPage } from \"./connect/html-page\";\nimport { PENDING_CONNECT_TTL_MS } from \"./connect/pending-connects\";\nimport {\n type ResolvedDevtoolsOptions,\n resolveDevtoolsOptions,\n} from \"./options\";\nimport { proxyWithBoardCredential } from \"./reflet-proxy\";\n\nexport type {\n TeamToolsAccount,\n TeamToolsBridge,\n TeamToolsCall,\n TeamToolsReply,\n} from \"../../sessions/team/team-tools-bridge\";\n\nexport interface TeamToolsHostOptions {\n /** Reflet API origin. Defaults to the hosted API. */\n apiUrl?: string;\n /** A directory only this app uses, such as Electron's `app.getPath(\"userData\")`. Keeps its sign-in apart from other apps and dev servers. */\n appDataDirectory: string;\n /** Reflet web app origin sign-in happens on. Defaults to https://www.reflet.app. */\n appUrl?: string;\n /** Opens a URL in the system browser, such as Electron's `shell.openExternal`. */\n openExternal: (url: string) => Promise<void>;\n publicKey: string;\n}\n\ninterface BrowserSignIn {\n account: Promise<TeamToolsAccount>;\n authorizeUrl: string;\n}\n\nconst LOOPBACK_HOST = \"127.0.0.1\";\nconst SIGN_IN_TIMED_OUT = \"Reflet sign-in timed out. Sign in again.\";\n\nasync function sendPage(response: ServerResponse, page: Response) {\n response.writeHead(page.status, Object.fromEntries(page.headers));\n response.end(await page.text());\n}\n\nasync function listenOnLoopback(server: Server): Promise<number> {\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, LOOPBACK_HOST, resolve);\n });\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n throw new Error(\"The Reflet sign-in listener has no port.\");\n }\n return address.port;\n}\n\n/** Settles on the first callback carrying this sign-in's state; anything else gets a 404 and changes nothing. */\nfunction awaitConnectCallback(\n server: Server,\n pending: {\n redirectUri: string;\n settings: ResolvedDevtoolsOptions;\n state: string;\n }\n): Promise<TeamToolsAccount> {\n const callbackPath = new URL(pending.redirectUri).pathname;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(\n () => reject(new Error(SIGN_IN_TIMED_OUT)),\n PENDING_CONNECT_TTL_MS\n );\n let isRedeeming = false;\n const redeem = async (url: URL, response: ServerResponse) => {\n const outcome = await redeemConnectCode(pending.settings, {\n code: url.searchParams.get(\"code\"),\n redirectUri: pending.redirectUri,\n state: pending.state,\n });\n await sendPage(response, connectOutcomePage(outcome, \"desktopApp\"));\n if (!outcome.ok) {\n throw new Error(outcome.message);\n }\n return { organizationName: outcome.organizationName };\n };\n server.on(\"request\", (request, response) => {\n const url = new URL(request.url ?? \"/\", pending.redirectUri);\n const isThisSignIn =\n request.method === \"GET\" &&\n url.pathname === callbackPath &&\n url.searchParams.get(\"state\") === pending.state;\n if (isRedeeming || !isThisSignIn) {\n sendPage(\n response,\n htmlPage(\"Not found\", \"Nothing here answers this link.\", 404)\n ).catch(() => undefined);\n return;\n }\n isRedeeming = true;\n clearTimeout(timeout);\n redeem(url, response).then(resolve, reject);\n });\n });\n}\n\nasync function startBrowserSignIn(\n settings: ResolvedDevtoolsOptions,\n publicKey: string\n): Promise<BrowserSignIn> {\n const server = createServer();\n const port = await listenOnLoopback(server);\n const redirectUri = connectCallbackUriFor(`http://${LOOPBACK_HOST}:${port}`);\n const { authorizeUrl, state } = connectAuthorizeUrl(settings, {\n client: \"desktopApp\",\n publicKey,\n redirectUri,\n });\n const account = awaitConnectCallback(server, {\n redirectUri,\n settings,\n state,\n }).finally(() => server.close());\n return { account, authorizeUrl };\n}\n\n/**\n * Runs team tools for a desktop app in its privileged process (Electron's\n * main): sign-in goes through the system browser back to a one-shot loopback\n * listener, and the token stays on disk outside the page, like the dev\n * server's Connect. Expose the returned bridge to the page over IPC and pass it\n * to `<RefletFeedback teamTools={bridge} />`.\n */\nexport function createTeamToolsHost(\n options: TeamToolsHostOptions\n): TeamToolsBridge {\n const settings = resolveDevtoolsOptions(\n {\n apiUrl: options.apiUrl,\n appUrl: options.appUrl,\n root: options.appDataDirectory,\n },\n {}\n );\n let pendingSignIn: Promise<BrowserSignIn> | null = null;\n\n const currentSignIn = (): Promise<BrowserSignIn> => {\n if (pendingSignIn) {\n return pendingSignIn;\n }\n const started = startBrowserSignIn(settings, options.publicKey);\n pendingSignIn = started;\n const release = () => {\n if (pendingSignIn === started) {\n pendingSignIn = null;\n }\n };\n started.then((signIn) => signIn.account).then(release, release);\n return started;\n };\n\n return {\n account: async () => {\n const connection = await readConnection(settings.root, settings.apiUrl);\n return connection && { organizationName: connection.organizationName };\n },\n request: async (call) => {\n const search = call.query ? `?${new URLSearchParams(call.query)}` : \"\";\n const response = await proxyWithBoardCredential(\n new Request(`${settings.apiUrl}/${search}`, {\n body: call.method === \"POST\" ? call.body : undefined,\n method: call.method,\n }),\n call.path,\n settings\n );\n return { body: await response.text(), status: response.status };\n },\n signIn: async () => {\n const signIn = await currentSignIn();\n await options.openExternal(signIn.authorizeUrl);\n return await signIn.account;\n },\n signOut: async () => {\n await forgetConnection(settings);\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,372 @@
1
+ import { d as SelectionOutline } from "./submit-r3_M1ITo.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-CacYFVjI.js";
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/devtools/client/account/connect-footer.tsx
6
+ function useBoardConnect(publicKey) {
7
+ const [state, setState] = useState({ kind: "idle" });
8
+ const connect = async () => {
9
+ const tab = window.open("", "_blank");
10
+ if (tab) tab.opener = null;
11
+ setState({ kind: "starting" });
12
+ try {
13
+ const { authorizeUrl } = await startBoardConnect(publicKey);
14
+ if (tab) tab.location.href = authorizeUrl;
15
+ else window.open(authorizeUrl, "_blank", "noopener");
16
+ setState({
17
+ authorizeUrl,
18
+ kind: "waiting"
19
+ });
20
+ } catch (error) {
21
+ tab?.close();
22
+ setState({ kind: "idle" });
23
+ reportFailure("Could not connect to Reflet", error);
24
+ }
25
+ };
26
+ return {
27
+ connect,
28
+ state
29
+ };
30
+ }
31
+ function ConnectFooter({ publicKey }) {
32
+ const { connect, state } = useBoardConnect(publicKey);
33
+ if (state.kind === "waiting") return /* @__PURE__ */ jsxs("div", {
34
+ className: "dt-sheet-account",
35
+ role: "status",
36
+ children: [/* @__PURE__ */ jsx("p", {
37
+ className: "dt-meta",
38
+ children: "Finish connecting in the Reflet tab. This panel updates when you come back."
39
+ }), /* @__PURE__ */ jsxs("div", {
40
+ className: "dt-actions",
41
+ children: [/* @__PURE__ */ jsx("a", {
42
+ className: "dt-btn",
43
+ href: state.authorizeUrl,
44
+ rel: "noopener noreferrer",
45
+ target: "_blank",
46
+ children: "Open Reflet again"
47
+ }), /* @__PURE__ */ jsx("button", {
48
+ className: "dt-btn",
49
+ onClick: connect,
50
+ type: "button",
51
+ children: "Start again"
52
+ })]
53
+ })]
54
+ });
55
+ return /* @__PURE__ */ jsxs("div", {
56
+ className: "dt-sheet-account",
57
+ children: [/* @__PURE__ */ jsx("p", {
58
+ className: "dt-meta",
59
+ children: "Not connected"
60
+ }), /* @__PURE__ */ jsx("button", {
61
+ className: "dt-btn",
62
+ "data-variant": "primary",
63
+ disabled: state.kind === "starting",
64
+ onClick: connect,
65
+ type: "button",
66
+ children: "Connect to Reflet"
67
+ })]
68
+ });
69
+ }
70
+ //#endregion
71
+ //#region src/devtools/client/account/devtools-account.tsx
72
+ async function disconnect(refresh) {
73
+ try {
74
+ const { revoked } = await disconnectBoard();
75
+ if (!revoked) reportFailure("The Reflet token was not revoked", /* @__PURE__ */ new Error("Disconnected here, but Reflet could not be reached. Revoke it from Account → Devtools on reflet.app."));
76
+ } catch (error) {
77
+ reportFailure("The dev server did not disconnect", error);
78
+ }
79
+ refresh();
80
+ }
81
+ function DevtoolsAccount({ connectKey, refresh, route, workspace }) {
82
+ if (route.kind !== "ready") return null;
83
+ const { board } = route.status;
84
+ if (board.kind === "secretKey") return /* @__PURE__ */ jsx(AccountNote, { children: "Reaching the board with REFLET_SECRET_KEY" });
85
+ if (board.kind === "disconnected") return connectKey === null ? /* @__PURE__ */ jsxs(AccountNote, { children: ["Not connected. ", CONNECT_REQUIREMENT] }) : /* @__PURE__ */ jsx(ConnectFooter, { publicKey: connectKey });
86
+ return /* @__PURE__ */ jsx(AccountFooter, {
87
+ actions: [{
88
+ label: "Disconnect",
89
+ onSelect: () => disconnect(refresh),
90
+ variant: "danger"
91
+ }],
92
+ organizationName: board.organizationName,
93
+ person: workspace.kind === "ready" ? workspace.workspace.identity.user : null
94
+ });
95
+ }
96
+ //#endregion
97
+ //#region src/devtools/client/board/board-tab.tsx
98
+ function BoardTab({ canConnect, onOpenCode, onShowSelector, route }) {
99
+ if (route.kind === "missing") return /* @__PURE__ */ jsx(MissingRouteHint, { purpose: "see your board's feedback for this page" });
100
+ if (route.kind === "checking") return null;
101
+ if (route.status.board.kind === "disconnected") return /* @__PURE__ */ jsx("p", {
102
+ className: "dt-empty",
103
+ children: canConnect ? "Connect to Reflet below to see this page's feedback and add notes to your board." : MISSING_SECRET_KEY_HINT
104
+ });
105
+ return /* @__PURE__ */ jsx(InboxPanel, {
106
+ boardCall: callReflet,
107
+ onOpenCode,
108
+ onShowSelector
109
+ });
110
+ }
111
+ //#endregion
112
+ //#region src/devtools/client/route/use-dev-route.ts
113
+ /** Re-probes on window focus so a connection finished in another tab shows up; keeps the last state meanwhile. */
114
+ function useDevRoute() {
115
+ const [route, setRoute] = useState({ kind: "checking" });
116
+ const latestProbe = useRef(0);
117
+ const refresh = useCallback(() => {
118
+ latestProbe.current += 1;
119
+ const probe = latestProbe.current;
120
+ probeDevRoute().then((status) => {
121
+ if (probe === latestProbe.current) setRoute(status ? {
122
+ kind: "ready",
123
+ status
124
+ } : { kind: "missing" });
125
+ });
126
+ }, []);
127
+ useEffect(() => {
128
+ refresh();
129
+ window.addEventListener("focus", refresh);
130
+ return () => {
131
+ window.removeEventListener("focus", refresh);
132
+ latestProbe.current += 1;
133
+ };
134
+ }, [refresh]);
135
+ return {
136
+ refresh,
137
+ route
138
+ };
139
+ }
140
+ //#endregion
141
+ //#region src/devtools/client/sessions/devtools-sessions.tsx
142
+ const DEVTOOLS_TRANSPORT = devtoolsTransport();
143
+ /** Sessions go through the dev route with the developer's own Connect token, never the secret key. */
144
+ function useDevtoolsSessions(options) {
145
+ const { route } = options;
146
+ const isConnected = route.kind === "ready" && route.status.board.kind === "connected";
147
+ const state = useWorkspaceLoader({
148
+ onUnauthorized: options.onUnauthorized,
149
+ surface: "devtools",
150
+ transport: isConnected ? DEVTOOLS_TRANSPORT : null
151
+ });
152
+ return {
153
+ navigation: useSessionNavigation(),
154
+ state
155
+ };
156
+ }
157
+ function SessionsScope({ children, sessions }) {
158
+ const workspace = sessions.state.kind === "ready" ? sessions.state.workspace : null;
159
+ return /* @__PURE__ */ jsx(SessionWorkspaceProvider, {
160
+ workspace,
161
+ children
162
+ });
163
+ }
164
+ const SESSIONS_NEED_ACCOUNT = "Sessions are recorded under your Reflet account.";
165
+ function WorkspaceGate({ actions, sessions }) {
166
+ const { state } = sessions;
167
+ if (state.kind === "ready") return /* @__PURE__ */ jsx(SessionsPanel, {
168
+ navigation: sessions.navigation,
169
+ onStarted: actions.onStarted,
170
+ onWriteNote: actions.onWriteNote
171
+ });
172
+ if (state.kind === "failed") return /* @__PURE__ */ jsxs("div", {
173
+ className: "dt-empty",
174
+ role: "alert",
175
+ children: [/* @__PURE__ */ jsxs("p", { children: ["Sessions did not open: ", state.message] }), /* @__PURE__ */ jsx("button", {
176
+ className: "dt-btn",
177
+ onClick: state.retry,
178
+ type: "button",
179
+ children: "Try again"
180
+ })]
181
+ });
182
+ return /* @__PURE__ */ jsx("p", {
183
+ className: "dt-status",
184
+ children: "Opening your sessions…"
185
+ });
186
+ }
187
+ function SessionsTab({ actions, canConnect, route, sessions }) {
188
+ if (route.kind === "checking") return /* @__PURE__ */ jsx("p", {
189
+ className: "dt-status",
190
+ children: "Connecting to the Reflet dev route…"
191
+ });
192
+ if (route.kind === "missing") return /* @__PURE__ */ jsx(MissingRouteHint, { purpose: "record sessions under your Reflet account" });
193
+ const { board } = route.status;
194
+ if (board.kind === "disconnected") return /* @__PURE__ */ jsxs("p", {
195
+ className: "dt-empty",
196
+ children: [
197
+ SESSIONS_NEED_ACCOUNT,
198
+ " ",
199
+ canConnect ? "Connect to Reflet below to start one." : CONNECT_REQUIREMENT
200
+ ]
201
+ });
202
+ if (board.kind === "secretKey") return /* @__PURE__ */ jsxs("p", {
203
+ className: "dt-empty",
204
+ children: [SESSIONS_NEED_ACCOUNT, " REFLET_SECRET_KEY can't stand for you: remove it from the dev server environment, then connect to Reflet."]
205
+ });
206
+ return /* @__PURE__ */ jsx(WorkspaceGate, {
207
+ actions,
208
+ sessions
209
+ });
210
+ }
211
+ //#endregion
212
+ //#region src/devtools/client/devtools-layer.tsx
213
+ function sendBlockedReason(route, canConnect) {
214
+ if (route.kind === "checking") return "Connecting to the Reflet dev route…";
215
+ if (route.kind === "missing") return "Add the Reflet dev route to add notes to your board.";
216
+ if (route.status.board.kind !== "disconnected") return null;
217
+ return canConnect ? "Connect to Reflet below to add notes to your board." : MISSING_SECRET_KEY_HINT;
218
+ }
219
+ function canConnectBoard(route, publicKey) {
220
+ return route.kind === "ready" && route.status.board.kind === "disconnected" && route.status.board.canConnect && publicKey !== null;
221
+ }
222
+ /** A reload in the middle of locating left these without a source; finish the job once. */
223
+ function useResumeLocating(notes, route) {
224
+ useEffect(() => {
225
+ if (route.kind === "checking") return;
226
+ for (const note of notes.notes) {
227
+ const element = note.source === null && isActiveNote(note) && notes.activity[note.id] === void 0 && !hasTriedToLocate(note.id) && isNoteOnPage(note, window.location.pathname) ? findOnPage(note.selection.selector) : null;
228
+ if (element) enrichNote(note.id, element, route.kind === "ready").catch(() => null);
229
+ }
230
+ }, [notes, route.kind]);
231
+ }
232
+ function SheetPanel({ canConnect, codeLookup, handlers, notes, openTab, route, sessions }) {
233
+ if (openTab === "notes") return /* @__PURE__ */ jsx(NotesPanel, {
234
+ boardCall: callReflet,
235
+ notes,
236
+ onOpenCode: handlers.onOpenCode,
237
+ onPick: handlers.onPick,
238
+ onShowSelector: handlers.onShowSelector,
239
+ sendBlockedReason: sendBlockedReason(route, canConnect)
240
+ });
241
+ if (openTab === "inbox") return /* @__PURE__ */ jsx(BoardTab, {
242
+ canConnect,
243
+ onOpenCode: handlers.onOpenCode,
244
+ onShowSelector: handlers.onShowSelector,
245
+ route
246
+ });
247
+ if (openTab === "sessions") return /* @__PURE__ */ jsx(SessionsTab, {
248
+ actions: {
249
+ onStarted: handlers.onClose,
250
+ onWriteNote: () => {
251
+ handlers.onClose();
252
+ handlers.onPick();
253
+ }
254
+ },
255
+ canConnect,
256
+ route,
257
+ sessions
258
+ });
259
+ return codeLookup && /* @__PURE__ */ jsx(CodeTab, {
260
+ lookup: codeLookup,
261
+ route
262
+ });
263
+ }
264
+ function DevtoolsLayer({ isWidgetOpen, position, publicKey }) {
265
+ const { refresh, route } = useDevRoute();
266
+ const notes = useNotes();
267
+ useResumeLocating(notes, route);
268
+ const sessions = useDevtoolsSessions({
269
+ onUnauthorized: refresh,
270
+ route
271
+ });
272
+ const [isPicking, setIsPicking] = useState(false);
273
+ const sheet = useSheetTab();
274
+ const { openTab } = sheet;
275
+ const { clearHighlight, highlighted, showSelector } = usePageHighlight();
276
+ const { codeLookup, inspectElement, openCode } = useCodeLookup(sheet.select);
277
+ const edge = position.startsWith("top") ? "top" : "bottom";
278
+ const side = position.endsWith("right") ? "right" : "left";
279
+ const canReadSource = route.kind === "ready";
280
+ const canConnect = canConnectBoard(route, publicKey);
281
+ const isRecessed = isWidgetOpen || isPicking;
282
+ const closeSheet = () => {
283
+ sheet.close();
284
+ clearHighlight();
285
+ };
286
+ const startPick = useCallback(() => setIsPicking(true), []);
287
+ const cancelPick = useCallback(() => setIsPicking(false), []);
288
+ const inspect = useMemo(() => ({
289
+ label: "Code",
290
+ onInspect: (element) => {
291
+ setIsPicking(false);
292
+ inspectElement(element);
293
+ }
294
+ }), [inspectElement]);
295
+ const tabs = SHEET_TABS.filter((tab) => tab !== "code" || codeLookup);
296
+ const openPanel = (tab) => sheet.select(tab ?? (tabs.includes(sheet.lastTab) ? sheet.lastTab : "inbox"));
297
+ const sheetPlace = openTab === "sessions" && sessions.state.kind === "ready" ? sessionSheetPlace(sessions.navigation) : null;
298
+ return /* @__PURE__ */ jsx(SessionsScope, {
299
+ sessions,
300
+ children: /* @__PURE__ */ jsxs("div", {
301
+ className: "dt",
302
+ "data-recessed": isRecessed,
303
+ "data-sheet-open": openTab !== null,
304
+ children: [
305
+ /* @__PURE__ */ jsx("style", { children: `${DEVTOOLS_STYLES}${SESSIONS_STYLES}` }),
306
+ /* @__PURE__ */ jsx(NotePins, {
307
+ isVisible: !isRecessed,
308
+ notes,
309
+ onOpenCode: openCode
310
+ }),
311
+ openTab && /* @__PURE__ */ jsx(DevtoolsSheet, {
312
+ footer: sheetPlace === null && /* @__PURE__ */ jsx(DevtoolsAccount, {
313
+ connectKey: canConnect ? publicKey : null,
314
+ refresh,
315
+ route,
316
+ workspace: sessions.state
317
+ }),
318
+ navigation: {
319
+ onSelectTab: sheet.select,
320
+ place: sheetPlace,
321
+ tab: openTab,
322
+ tabs
323
+ },
324
+ onClose: closeSheet,
325
+ side,
326
+ children: /* @__PURE__ */ jsx(SheetPanel, {
327
+ canConnect,
328
+ codeLookup,
329
+ handlers: {
330
+ onClose: closeSheet,
331
+ onOpenCode: openCode,
332
+ onPick: startPick,
333
+ onShowSelector: showSelector
334
+ },
335
+ notes,
336
+ openTab,
337
+ route,
338
+ sessions
339
+ })
340
+ }),
341
+ /* @__PURE__ */ jsx(DevtoolsBar, {
342
+ edge,
343
+ side,
344
+ children: /* @__PURE__ */ jsx(DevtoolsBarButtons, {
345
+ canOpenCode: true,
346
+ onOpen: openPanel,
347
+ onPick: startPick,
348
+ unsentNoteCount: unsentNoteCount(notes)
349
+ })
350
+ }),
351
+ openTab && /* @__PURE__ */ jsx(SelectionOutline, { node: highlighted }),
352
+ /* @__PURE__ */ jsx(Notices, {}),
353
+ sessions.state.kind === "ready" && /* @__PURE__ */ jsx(RecordingLayer, { onFinished: (target) => {
354
+ sessions.navigation.go({
355
+ target,
356
+ view: "review"
357
+ });
358
+ sheet.select("sessions");
359
+ } }),
360
+ isPicking && /* @__PURE__ */ jsx(NotePicker, {
361
+ canReadSource,
362
+ inspect,
363
+ onDone: cancelPick
364
+ })
365
+ ]
366
+ })
367
+ });
368
+ }
369
+ //#endregion
370
+ export { DevtoolsLayer };
371
+
372
+ //# sourceMappingURL=devtools-layer-CYIoe3Vo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools-layer-CYIoe3Vo.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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"}
@@ -1,4 +1,4 @@
1
- import { t as createDevtoolsHandler } from "./handler-ndF3gZBx.js";
1
+ import { t as createDevtoolsHandler } from "./handler-1XhfZvZ0.js";
2
2
  //#region src/devtools/server/next.ts
3
3
  /**
4
4
  * Route handlers for `app/api/reflet-devtools/[...path]/route.ts`. They answer
@@ -1,6 +1,6 @@
1
- import { r as DEVTOOLS_ROUTE_BASE } from "./protocol-cJVVwnPe.js";
2
- import { h as isLoopbackAddress, v as errorResponse } from "./reflet-proxy-BW6q9xds.js";
3
- import { t as createDevtoolsHandler } from "./handler-ndF3gZBx.js";
1
+ import { r as DEVTOOLS_ROUTE_BASE } from "./protocol-BnurX0CF.js";
2
+ import { h as isLoopbackAddress, v as errorResponse } from "./reflet-proxy-DVE6ov2f.js";
3
+ import { t as createDevtoolsHandler } from "./handler-1XhfZvZ0.js";
4
4
  import { loadEnv } from "vite";
5
5
  //#region src/devtools/server/vite.ts
6
6
  const MAX_BODY_BYTES = 1048576;