reflet-sdk 0.7.4 → 0.7.5

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 +6 -0
  2. package/README.md +32 -1
  3. package/dist/desktop.d.ts +24 -0
  4. package/dist/desktop.d.ts.map +1 -0
  5. package/dist/desktop.js +118 -0
  6. package/dist/desktop.js.map +1 -0
  7. package/dist/{devtools-layer-CcTmlikp.js → devtools-layer-o1O55wu1.js} +3 -3
  8. package/dist/{devtools-layer-CcTmlikp.js.map → devtools-layer-o1O55wu1.js.map} +1 -1
  9. package/dist/devtools-next.d.ts.map +1 -1
  10. package/dist/devtools-next.js +1 -1
  11. package/dist/{devtools-styles-teRMfSzW.js → devtools-styles-TWR5Ps34.js} +24 -3
  12. package/dist/devtools-styles-TWR5Ps34.js.map +1 -0
  13. package/dist/devtools-vite.js +2 -1
  14. package/dist/devtools-vite.js.map +1 -1
  15. package/dist/feedback.d.ts +7 -3
  16. package/dist/feedback.d.ts.map +1 -1
  17. package/dist/feedback.js +21 -12
  18. package/dist/feedback.js.map +1 -1
  19. package/dist/{handler-B3_PQB1q.js → handler-ndF3gZBx.js} +11 -416
  20. package/dist/handler-ndF3gZBx.js.map +1 -0
  21. package/dist/reflet-proxy-BW6q9xds.js +467 -0
  22. package/dist/reflet-proxy-BW6q9xds.js.map +1 -0
  23. package/dist/{submit-CG4LXioK.js → submit-DJIKxRUp.js} +2 -2
  24. package/dist/submit-DJIKxRUp.js.map +1 -0
  25. package/dist/{team-layer-zLj_QPQX.js → team-layer-_It1_oSo.js} +127 -57
  26. package/dist/team-layer-_It1_oSo.js.map +1 -0
  27. package/dist/team-tools-bridge-C51PpkUI.d.ts +31 -0
  28. package/dist/team-tools-bridge-C51PpkUI.d.ts.map +1 -0
  29. package/package.json +5 -1
  30. package/dist/devtools-styles-teRMfSzW.js.map +0 -1
  31. package/dist/handler-B3_PQB1q.js.map +0 -1
  32. package/dist/submit-CG4LXioK.js.map +0 -1
  33. package/dist/team-layer-zLj_QPQX.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,12 @@ 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.5] - 2026-10-17
9
+
10
+ ### Added
11
+
12
+ - Team tools in desktop apps: `createTeamToolsHost` from `reflet-sdk/desktop` runs them in an Electron main process, and `<RefletFeedback teamTools={bridge} />` takes the bridge it returns. Pages loaded from `file://` can now record sessions: sign-in opens the system browser and returns to a loopback listener, and the token stays in `~/.reflet/devtools/`, out of the page.
13
+
8
14
  ## [0.7.4] - 2026-10-15
9
15
 
10
16
  ### Changed
package/README.md CHANGED
@@ -167,7 +167,7 @@ builds do; production builds strip React's debug data).
167
167
  | `categories` | `("bug" \| "idea" \| "question")[]` | all three | Category chips to show. |
168
168
  | `labels` | `Partial<FeedbackWidgetLabels>` | — | Override any string for i18n. |
169
169
  | `devtools` | `boolean` | `true` | Dev-only team tools; see below. Never loaded outside `NODE_ENV=development`. |
170
- | `teamTools` | `boolean` | `true` | Lets signed-in members of your Reflet organization record sessions in production; see below. |
170
+ | `teamTools` | `boolean \| TeamToolsBridge` | `true` | Lets signed-in members of your Reflet organization record sessions in production; see below. Desktop apps pass a bridge. |
171
171
  | `appUrl` | `string` | `"https://www.reflet.app"` | Reflet web app origin team tools sign in on. |
172
172
  | `onSubmit` | `(result: { feedbackId: string }) => void` | — | Fires after a successful send. |
173
173
 
@@ -299,6 +299,37 @@ transcript is saved, within 24 hours at most. Pausing stops all collection;
299
299
  keystrokes are never recorded, form fields appear empty in screenshots, and
300
300
  password fields and elements marked `data-reflet-redact` are hidden from them.
301
301
 
302
+ ##### Desktop apps (Electron)
303
+
304
+ A page loaded from `file://` has no origin Reflet can bind a sign-in to, so the
305
+ browser flow above can't work there. Run team tools from the app's main
306
+ process instead: sign-in opens the system browser and comes back to a one-shot
307
+ listener on `127.0.0.1`, like the devtools' Connect, and the token stays on disk
308
+ in `~/.reflet/devtools/`, never in the page. Members approve it on reflet.app as
309
+ a local connection; revoke it from Account → Devtools. The key needs no allowed
310
+ domain for this.
311
+
312
+ ```ts
313
+ // main process
314
+ import { app, ipcMain, shell } from 'electron';
315
+ import { createTeamToolsHost } from 'reflet-sdk/desktop';
316
+
317
+ const teamTools = createTeamToolsHost({
318
+ appDataDirectory: app.getPath('userData'),
319
+ openExternal: (url) => shell.openExternal(url),
320
+ publicKey: 'fb_pub_xxx',
321
+ });
322
+ ipcMain.handle('reflet-team-tools:account', () => teamTools.account());
323
+ ipcMain.handle('reflet-team-tools:request', (_event, call) => teamTools.request(call));
324
+ ipcMain.handle('reflet-team-tools:sign-in', () => teamTools.signIn());
325
+ ipcMain.handle('reflet-team-tools:sign-out', () => teamTools.signOut());
326
+ ```
327
+
328
+ Expose the four calls from the preload script, then pass them as the bridge:
329
+ `<RefletFeedback publicKey="fb_pub_xxx" teamTools={bridge} />`. Team tools show
330
+ at once, so only pass the bridge in builds meant for your team. `request` only
331
+ forwards the session and feedback endpoints the devtools use.
332
+
302
333
  ### 5. In-App Surveys
303
334
 
304
335
  Create surveys in the Reflet dashboard (NPS, ratings, choices, text, statements,
@@ -0,0 +1,24 @@
1
+ import { i as TeamToolsReply, n as TeamToolsBridge, r as TeamToolsCall, t as TeamToolsAccount } from "./team-tools-bridge-C51PpkUI.js";
2
+ //#region src/devtools/server/desktop.d.ts
3
+ export interface TeamToolsHostOptions {
4
+ /** Reflet API origin. Defaults to the hosted API. */
5
+ apiUrl?: string;
6
+ /** A directory only this app uses, such as Electron's `app.getPath("userData")`. Keeps its sign-in apart from other apps and dev servers. */
7
+ appDataDirectory: string;
8
+ /** Reflet web app origin sign-in happens on. Defaults to https://www.reflet.app. */
9
+ appUrl?: string;
10
+ /** Opens a URL in the system browser, such as Electron's `shell.openExternal`. */
11
+ openExternal: (url: string) => Promise<void>;
12
+ publicKey: string;
13
+ }
14
+ /**
15
+ * Runs team tools for a desktop app in its privileged process (Electron's
16
+ * main): sign-in goes through the system browser back to a one-shot loopback
17
+ * listener, and the token stays on disk outside the page, like the dev
18
+ * server's Connect. Expose the returned bridge to the page over IPC and pass it
19
+ * to `<RefletFeedback teamTools={bridge} />`.
20
+ */
21
+ export declare function createTeamToolsHost(options: TeamToolsHostOptions): TeamToolsBridge;
22
+ //#endregion
23
+ export type { TeamToolsAccount, TeamToolsBridge, TeamToolsCall, TeamToolsReply };
24
+ //# sourceMappingURL=desktop.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,118 @@
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";
2
+ import { createServer } from "node:http";
3
+ //#region src/devtools/server/desktop.ts
4
+ const LOOPBACK_HOST = "127.0.0.1";
5
+ const SIGN_IN_TIMED_OUT = "Reflet sign-in timed out. Sign in again.";
6
+ async function sendPage(response, page) {
7
+ response.writeHead(page.status, Object.fromEntries(page.headers));
8
+ response.end(await page.text());
9
+ }
10
+ async function listenOnLoopback(server) {
11
+ await new Promise((resolve, reject) => {
12
+ server.once("error", reject);
13
+ server.listen(0, LOOPBACK_HOST, resolve);
14
+ });
15
+ const address = server.address();
16
+ if (address === null || typeof address === "string") throw new Error("The Reflet sign-in listener has no port.");
17
+ return address.port;
18
+ }
19
+ /** Settles on the first callback carrying this sign-in's state; anything else gets a 404 and changes nothing. */
20
+ function awaitConnectCallback(server, pending) {
21
+ const callbackPath = new URL(pending.redirectUri).pathname;
22
+ return new Promise((resolve, reject) => {
23
+ const timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(SIGN_IN_TIMED_OUT)), PENDING_CONNECT_TTL_MS);
24
+ let isRedeeming = false;
25
+ const redeem = async (url, response) => {
26
+ const outcome = await redeemConnectCode(pending.settings, {
27
+ code: url.searchParams.get("code"),
28
+ redirectUri: pending.redirectUri,
29
+ state: pending.state
30
+ });
31
+ await sendPage(response, connectOutcomePage(outcome));
32
+ if (!outcome.ok) throw new Error(outcome.message);
33
+ return { organizationName: outcome.organizationName };
34
+ };
35
+ server.on("request", (request, response) => {
36
+ const url = new URL(request.url ?? "/", pending.redirectUri);
37
+ const isThisSignIn = request.method === "GET" && url.pathname === callbackPath && url.searchParams.get("state") === pending.state;
38
+ if (isRedeeming || !isThisSignIn) {
39
+ sendPage(response, htmlPage("Not found", "Nothing here answers this link.", 404)).catch(() => void 0);
40
+ return;
41
+ }
42
+ isRedeeming = true;
43
+ clearTimeout(timeout);
44
+ redeem(url, response).then(resolve, reject);
45
+ });
46
+ });
47
+ }
48
+ async function startBrowserSignIn(settings, publicKey) {
49
+ const server = createServer();
50
+ const port = await listenOnLoopback(server);
51
+ const redirectUri = connectCallbackUriFor(`http://${LOOPBACK_HOST}:${port}`);
52
+ const { authorizeUrl, state } = connectAuthorizeUrl(settings, {
53
+ publicKey,
54
+ redirectUri
55
+ });
56
+ return {
57
+ account: awaitConnectCallback(server, {
58
+ redirectUri,
59
+ settings,
60
+ state
61
+ }).finally(() => server.close()),
62
+ authorizeUrl
63
+ };
64
+ }
65
+ /**
66
+ * Runs team tools for a desktop app in its privileged process (Electron's
67
+ * main): sign-in goes through the system browser back to a one-shot loopback
68
+ * listener, and the token stays on disk outside the page, like the dev
69
+ * server's Connect. Expose the returned bridge to the page over IPC and pass it
70
+ * to `<RefletFeedback teamTools={bridge} />`.
71
+ */
72
+ function createTeamToolsHost(options) {
73
+ const settings = resolveDevtoolsOptions({
74
+ apiUrl: options.apiUrl,
75
+ appUrl: options.appUrl,
76
+ root: options.appDataDirectory
77
+ }, {});
78
+ let pendingSignIn = null;
79
+ const currentSignIn = () => {
80
+ if (pendingSignIn) return pendingSignIn;
81
+ const started = startBrowserSignIn(settings, options.publicKey);
82
+ pendingSignIn = started;
83
+ const release = () => {
84
+ if (pendingSignIn === started) pendingSignIn = null;
85
+ };
86
+ started.then((signIn) => signIn.account).then(release, release);
87
+ return started;
88
+ };
89
+ return {
90
+ account: async () => {
91
+ const connection = await readConnection(settings.root, settings.apiUrl);
92
+ return connection && { organizationName: connection.organizationName };
93
+ },
94
+ request: async (call) => {
95
+ const search = call.query ? `?${new URLSearchParams(call.query)}` : "";
96
+ const response = await proxyWithBoardCredential(new Request(`${settings.apiUrl}/${search}`, {
97
+ body: call.method === "POST" ? call.body : void 0,
98
+ method: call.method
99
+ }), call.path, settings);
100
+ return {
101
+ body: await response.text(),
102
+ status: response.status
103
+ };
104
+ },
105
+ signIn: async () => {
106
+ const signIn = await currentSignIn();
107
+ await options.openExternal(signIn.authorizeUrl);
108
+ return await signIn.account;
109
+ },
110
+ signOut: async () => {
111
+ await forgetConnection(settings);
112
+ }
113
+ };
114
+ }
115
+ //#endregion
116
+ export { createTeamToolsHost };
117
+
118
+ //# sourceMappingURL=desktop.js.map
@@ -0,0 +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,6 +1,6 @@
1
- import { $ as shortenSourcePath, G as describeElement, M as TargetIcon, Q as resolveComponentStack, R as DEFAULT_WIDGET_LABELS, U as buildElementSelection, V as collectPageContext, X as getFiberFromNode, a as uploadBlob, f as listenOnPageAndWidget, g as isSubmitEnter, it as releaseCapture, nt as capturedFromCanvas, o as ElementPicker, p as listenToKeydown, r as deriveTitle, rt as capturedViewportSize, s as isWidgetOwned, tt as captureViewport, z as SDK_VERSION } from "./submit-CG4LXioK.js";
1
+ import { $ as shortenSourcePath, G as describeElement, M as TargetIcon, Q as resolveComponentStack, R as DEFAULT_WIDGET_LABELS, U as buildElementSelection, V as collectPageContext, X as getFiberFromNode, a as uploadBlob, f as listenOnPageAndWidget, g as isSubmitEnter, it as releaseCapture, nt as capturedFromCanvas, o as ElementPicker, p as listenToKeydown, r as deriveTitle, rt as capturedViewportSize, s as isWidgetOwned, tt as captureViewport, z as SDK_VERSION } from "./submit-DJIKxRUp.js";
2
2
  import { t as SelectionOutline } from "./selection-outline-NzAAAZXR.js";
3
- import { A as searchCode, C as devtoolsTransport, D as fetchBoardFeedback, E as disconnectBoard, F as settle, L as Notices, M as committed, N as describeStorageFailure, O as fetchSourceFile, P as openDatabase, R as announce, T as callReflet, _ as RecordingLayer, a as SHEET_TABS, c as AccountNote, d as sessionSheetPlace, f as useSessionNavigation, g as copyToClipboard, h as ViewOptionsIcon, i as DevtoolsBarButtons, j as startBoardConnect, k as probeDevRoute, l as SESSIONS_STYLES, m as RefreshIcon, n as DevtoolsSheet, p as Menu, r as DevtoolsBar, s as AccountFooter, t as DEVTOOLS_STYLES, u as SessionsPanel, v as countLabel, x as useWorkspaceLoader, y as SessionWorkspaceProvider, z as reportFailure } from "./devtools-styles-teRMfSzW.js";
3
+ import { A as probeDevRoute, B as reportFailure, D as disconnectBoard, E as callReflet, F as openDatabase, I as settle, M as startBoardConnect, N as committed, O as fetchBoardFeedback, P as describeStorageFailure, R as Notices, _ as RecordingLayer, a as SHEET_TABS, c as AccountNote, d as sessionSheetPlace, f as useSessionNavigation, g as copyToClipboard, h as ViewOptionsIcon, i as DevtoolsBarButtons, j as searchCode, k as fetchSourceFile, l as SESSIONS_STYLES, m as RefreshIcon, n as DevtoolsSheet, p as Menu, r as DevtoolsBar, s as AccountFooter, t as DEVTOOLS_STYLES, u as SessionsPanel, v as countLabel, w as devtoolsTransport, x as useWorkspaceLoader, y as SessionWorkspaceProvider, z as announce } from "./devtools-styles-TWR5Ps34.js";
4
4
  import * as G$1 from "react";
5
5
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -3815,4 +3815,4 @@ function DevtoolsLayer({ isWidgetOpen, position, publicKey }) {
3815
3815
  //#endregion
3816
3816
  export { DevtoolsLayer };
3817
3817
 
3818
- //# sourceMappingURL=devtools-layer-CcTmlikp.js.map
3818
+ //# sourceMappingURL=devtools-layer-o1O55wu1.js.map