reflet-sdk 0.7.3 → 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.
- package/CHANGELOG.md +28 -0
- package/README.md +54 -17
- package/dist/desktop.d.ts +24 -0
- package/dist/desktop.d.ts.map +1 -0
- package/dist/desktop.js +118 -0
- package/dist/desktop.js.map +1 -0
- package/dist/{devtools-layer-CsIcpepI.js → devtools-layer-o1O55wu1.js} +396 -277
- package/dist/devtools-layer-o1O55wu1.js.map +1 -0
- package/dist/devtools-next.d.ts.map +1 -1
- package/dist/devtools-next.js +1 -1
- package/dist/{sessions-panel-BYM0UUgT.js → devtools-styles-TWR5Ps34.js} +2078 -1686
- package/dist/devtools-styles-TWR5Ps34.js.map +1 -0
- package/dist/devtools-vite.js +2 -1
- package/dist/devtools-vite.js.map +1 -1
- package/dist/feedback.d.ts +7 -3
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +21 -12
- package/dist/feedback.js.map +1 -1
- package/dist/{handler-17FmwoSX.js → handler-ndF3gZBx.js} +11 -416
- package/dist/handler-ndF3gZBx.js.map +1 -0
- package/dist/reflet-proxy-BW6q9xds.js +467 -0
- package/dist/reflet-proxy-BW6q9xds.js.map +1 -0
- package/dist/{submit-Dl0rm6TV.js → submit-DJIKxRUp.js} +2 -2
- package/dist/submit-DJIKxRUp.js.map +1 -0
- package/dist/{team-layer-Dvjkh-_y.js → team-layer-_It1_oSo.js} +159 -95
- package/dist/team-layer-_It1_oSo.js.map +1 -0
- package/dist/team-tools-bridge-C51PpkUI.d.ts +31 -0
- package/dist/team-tools-bridge-C51PpkUI.d.ts.map +1 -0
- package/package.json +5 -1
- package/dist/devtools-layer-CsIcpepI.js.map +0 -1
- package/dist/handler-17FmwoSX.js.map +0 -1
- package/dist/sessions-panel-BYM0UUgT.js.map +0 -1
- package/dist/submit-Dl0rm6TV.js.map +0 -1
- package/dist/team-layer-Dvjkh-_y.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { r as teamAccessStorageKey, t as TEAM_ACTIVATION_PARAM } from "./team-activation-Cv5U7OF1.js";
|
|
2
|
-
import {
|
|
2
|
+
import { B as reportFailure, C as bridgeTransport, L as sessionApiErrorSchema, R as Notices, S as purgeAccount, T as teamTransport, _ as RecordingLayer, b as failureMessage, d as sessionSheetPlace, f as useSessionNavigation, l as SESSIONS_STYLES, n as DevtoolsSheet, o as SessionsBarButton, r as DevtoolsBar, s as AccountFooter, t as DEVTOOLS_STYLES, u as SessionsPanel, x as useWorkspaceLoader, y as SessionWorkspaceProvider } from "./devtools-styles-TWR5Ps34.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
|
-
import {
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/sessions/team/team-auth.ts
|
|
7
7
|
const RETURN_CODE_PARAM = "reflet-team-code";
|
|
8
8
|
const RETURN_ERROR_PARAM = "reflet-team-error";
|
|
@@ -181,32 +181,32 @@ async function forgetTeamAccess(options) {
|
|
|
181
181
|
}
|
|
182
182
|
//#endregion
|
|
183
183
|
//#region src/sessions/team/team-sign-in-card.tsx
|
|
184
|
-
function useTeamSignIn(
|
|
185
|
-
const [
|
|
184
|
+
function useTeamSignIn(onSignIn) {
|
|
185
|
+
const [isSigningIn, setIsSigningIn] = useState(false);
|
|
186
186
|
const [failure, setFailure] = useState(null);
|
|
187
187
|
const signIn = async () => {
|
|
188
|
-
|
|
188
|
+
setIsSigningIn(true);
|
|
189
189
|
setFailure(null);
|
|
190
190
|
try {
|
|
191
|
-
|
|
191
|
+
await onSignIn();
|
|
192
192
|
} catch (error) {
|
|
193
193
|
setFailure(failureMessage(error));
|
|
194
|
-
|
|
194
|
+
setIsSigningIn(false);
|
|
195
195
|
}
|
|
196
196
|
};
|
|
197
197
|
return {
|
|
198
198
|
failure,
|
|
199
|
-
|
|
199
|
+
isSigningIn,
|
|
200
200
|
signIn
|
|
201
201
|
};
|
|
202
202
|
}
|
|
203
|
-
function SignInActions({
|
|
203
|
+
function SignInActions({ canSignIn, onHide, onSignIn }) {
|
|
204
204
|
return /* @__PURE__ */ jsxs("div", {
|
|
205
205
|
className: "dt-actions",
|
|
206
206
|
children: [/* @__PURE__ */ jsx("button", {
|
|
207
207
|
className: "dt-btn",
|
|
208
208
|
"data-variant": "primary",
|
|
209
|
-
disabled:
|
|
209
|
+
disabled: !canSignIn,
|
|
210
210
|
onClick: onSignIn,
|
|
211
211
|
type: "button",
|
|
212
212
|
children: "Sign in with Reflet"
|
|
@@ -218,9 +218,11 @@ function SignInActions({ isSigningIn, onHide, onSignIn }) {
|
|
|
218
218
|
})]
|
|
219
219
|
});
|
|
220
220
|
}
|
|
221
|
-
function TeamSignInCard({
|
|
221
|
+
function TeamSignInCard({ isFinishing, notice, onSignIn, continuesInBrowser }) {
|
|
222
222
|
const [isHidden, setIsHidden] = useState(false);
|
|
223
|
-
const { failure,
|
|
223
|
+
const { failure, isSigningIn, signIn } = useTeamSignIn(onSignIn);
|
|
224
|
+
const isWaitingForBrowser = continuesInBrowser && isSigningIn;
|
|
225
|
+
const isLeavingPage = isSigningIn && !continuesInBrowser;
|
|
224
226
|
if (isHidden) return null;
|
|
225
227
|
return /* @__PURE__ */ jsxs("section", {
|
|
226
228
|
"aria-labelledby": "rf-team-title",
|
|
@@ -244,6 +246,11 @@ function TeamSignInCard({ connection, isFinishing, notice }) {
|
|
|
244
246
|
role: "status",
|
|
245
247
|
children: "Finishing sign-in…"
|
|
246
248
|
}),
|
|
249
|
+
isWaitingForBrowser && /* @__PURE__ */ jsx("p", {
|
|
250
|
+
className: "dt-meta",
|
|
251
|
+
role: "status",
|
|
252
|
+
children: "Finish signing in in your browser."
|
|
253
|
+
}),
|
|
247
254
|
notice && /* @__PURE__ */ jsx("p", {
|
|
248
255
|
className: "dt-meta",
|
|
249
256
|
role: "status",
|
|
@@ -255,7 +262,7 @@ function TeamSignInCard({ connection, isFinishing, notice }) {
|
|
|
255
262
|
children: failure
|
|
256
263
|
}),
|
|
257
264
|
/* @__PURE__ */ jsx(SignInActions, {
|
|
258
|
-
|
|
265
|
+
canSignIn: !(isLeavingPage || isFinishing),
|
|
259
266
|
onHide: () => setIsHidden(true),
|
|
260
267
|
onSignIn: signIn
|
|
261
268
|
})
|
|
@@ -266,22 +273,6 @@ function TeamSignInCard({ connection, isFinishing, notice }) {
|
|
|
266
273
|
//#region src/sessions/team/team-layer.tsx
|
|
267
274
|
const TEAM_TOOLS_LABEL = "Reflet team tools";
|
|
268
275
|
const REFUSED_SIGN_IN_COPY = "Reflet no longer accepts this sign-in. Sign in again to record.";
|
|
269
|
-
function AccountControls({ access, onSignOut, workspace }) {
|
|
270
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
271
|
-
const user = workspace?.account.userName ?? workspace?.account.userEmail;
|
|
272
|
-
const label = user ? `Signed in as ${user} · ${access.organizationName}` : `Signed in · ${access.organizationName}`;
|
|
273
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BarButton, {
|
|
274
|
-
label,
|
|
275
|
-
onClick: () => setIsOpen(!isOpen),
|
|
276
|
-
pressed: isOpen,
|
|
277
|
-
children: /* @__PURE__ */ jsx(PersonIcon, {})
|
|
278
|
-
}), isOpen && /* @__PURE__ */ jsx("button", {
|
|
279
|
-
className: "dt-btn",
|
|
280
|
-
onClick: onSignOut,
|
|
281
|
-
type: "button",
|
|
282
|
-
children: "Sign out"
|
|
283
|
-
})] });
|
|
284
|
-
}
|
|
285
276
|
function SessionsBody({ navigation, onStarted, state }) {
|
|
286
277
|
if (state.kind === "ready") return /* @__PURE__ */ jsx(SessionsPanel, {
|
|
287
278
|
navigation,
|
|
@@ -302,44 +293,40 @@ function SessionsBody({ navigation, onStarted, state }) {
|
|
|
302
293
|
children: "Opening your sessions…"
|
|
303
294
|
});
|
|
304
295
|
}
|
|
305
|
-
function TeamSheet({ navigation,
|
|
296
|
+
function TeamSheet({ account, navigation, onClose, side }) {
|
|
297
|
+
const { state } = account;
|
|
298
|
+
const place = state.kind === "ready" ? sessionSheetPlace(navigation) : null;
|
|
306
299
|
return /* @__PURE__ */ jsx(DevtoolsSheet, {
|
|
300
|
+
footer: place === null && /* @__PURE__ */ jsx(AccountFooter, {
|
|
301
|
+
actions: [{
|
|
302
|
+
label: "Sign out",
|
|
303
|
+
onSelect: account.onSignOut
|
|
304
|
+
}],
|
|
305
|
+
organizationName: account.organizationName,
|
|
306
|
+
person: state.kind === "ready" ? state.workspace.identity.user : null
|
|
307
|
+
}),
|
|
307
308
|
label: TEAM_TOOLS_LABEL,
|
|
308
|
-
|
|
309
|
-
|
|
309
|
+
navigation: {
|
|
310
|
+
onSelectTab: () => void 0,
|
|
311
|
+
place,
|
|
312
|
+
tab: "sessions",
|
|
313
|
+
tabs: ["sessions"]
|
|
314
|
+
},
|
|
315
|
+
onClose,
|
|
310
316
|
side,
|
|
311
|
-
tab: "sessions",
|
|
312
|
-
tabs: ["sessions"],
|
|
313
317
|
children: /* @__PURE__ */ jsx(SessionsBody, {
|
|
314
318
|
navigation,
|
|
315
|
-
onStarted:
|
|
319
|
+
onStarted: onClose,
|
|
316
320
|
state
|
|
317
321
|
})
|
|
318
322
|
});
|
|
319
323
|
}
|
|
320
|
-
function useTeamTransport(team) {
|
|
321
|
-
const createTransport = () => ({
|
|
322
|
-
apiUrl: team.apiUrl,
|
|
323
|
-
transport: teamTransport({
|
|
324
|
-
apiUrl: team.apiUrl,
|
|
325
|
-
token: team.access.token
|
|
326
|
-
})
|
|
327
|
-
});
|
|
328
|
-
const [current, setCurrent] = useState(createTransport);
|
|
329
|
-
if (current.apiUrl !== team.apiUrl) {
|
|
330
|
-
const next = createTransport();
|
|
331
|
-
setCurrent(next);
|
|
332
|
-
return next.transport;
|
|
333
|
-
}
|
|
334
|
-
return current.transport;
|
|
335
|
-
}
|
|
336
324
|
function useTeamWorkspace(team) {
|
|
337
325
|
const { onSignOut } = team;
|
|
338
|
-
const transport = useTeamTransport(team);
|
|
339
326
|
const state = useWorkspaceLoader({
|
|
340
327
|
onUnauthorized: () => onSignOut(REFUSED_SIGN_IN_COPY),
|
|
341
328
|
surface: "app",
|
|
342
|
-
transport
|
|
329
|
+
transport: team.transport
|
|
343
330
|
});
|
|
344
331
|
const workspace = state.kind === "ready" ? state.workspace : null;
|
|
345
332
|
const signOut = async () => {
|
|
@@ -355,50 +342,54 @@ function useTeamWorkspace(team) {
|
|
|
355
342
|
function TeamTools({ team, placement }) {
|
|
356
343
|
const { signOut, state, workspace } = useTeamWorkspace(team);
|
|
357
344
|
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
358
|
-
const
|
|
345
|
+
const navigation = useSessionNavigation();
|
|
359
346
|
return /* @__PURE__ */ jsxs(SessionWorkspaceProvider, {
|
|
360
347
|
workspace,
|
|
361
348
|
children: [
|
|
362
349
|
isSheetOpen && /* @__PURE__ */ jsx(TeamSheet, {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
350
|
+
account: {
|
|
351
|
+
onSignOut: signOut,
|
|
352
|
+
organizationName: team.organizationName,
|
|
353
|
+
state
|
|
366
354
|
},
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
355
|
+
navigation,
|
|
356
|
+
onClose: () => setIsSheetOpen(false),
|
|
357
|
+
side: placement.side
|
|
370
358
|
}),
|
|
371
|
-
/* @__PURE__ */
|
|
359
|
+
/* @__PURE__ */ jsx(DevtoolsBar, {
|
|
372
360
|
edge: placement.edge,
|
|
373
361
|
label: TEAM_TOOLS_LABEL,
|
|
374
362
|
side: placement.side,
|
|
375
|
-
children:
|
|
376
|
-
isOpen: isSheetOpen,
|
|
377
|
-
onToggle: () => setIsSheetOpen(!isSheetOpen)
|
|
378
|
-
}), /* @__PURE__ */ jsx(AccountControls, {
|
|
379
|
-
access: team.access,
|
|
380
|
-
onSignOut: signOut,
|
|
381
|
-
workspace
|
|
382
|
-
})]
|
|
363
|
+
children: /* @__PURE__ */ jsx(SessionsBarButton, { onOpen: () => setIsSheetOpen(true) })
|
|
383
364
|
}),
|
|
384
365
|
workspace && /* @__PURE__ */ jsx(RecordingLayer, { onFinished: (target) => {
|
|
385
|
-
|
|
366
|
+
navigation.go({
|
|
367
|
+
target,
|
|
368
|
+
view: "review"
|
|
369
|
+
});
|
|
386
370
|
setIsSheetOpen(true);
|
|
387
371
|
} })
|
|
388
372
|
]
|
|
389
373
|
});
|
|
390
374
|
}
|
|
391
|
-
function
|
|
392
|
-
return {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
375
|
+
function SignedOutAnchor({ children, placement }) {
|
|
376
|
+
return /* @__PURE__ */ jsx("div", {
|
|
377
|
+
className: "dt-team-anchor",
|
|
378
|
+
"data-edge": placement.edge,
|
|
379
|
+
"data-side": placement.side,
|
|
380
|
+
children
|
|
381
|
+
});
|
|
396
382
|
}
|
|
397
|
-
|
|
383
|
+
/** A web page signs in by leaving for reflet.app and coming back with a token for its own origin. */
|
|
384
|
+
function BrowserTeamAccount({ connection, placement }) {
|
|
398
385
|
const { apiUrl, publicKey } = connection;
|
|
399
386
|
const [access, setAccess] = useState(() => readTeamAccess(publicKey));
|
|
400
387
|
const [notice, setNotice] = useState(null);
|
|
401
388
|
const [isFinishing, setIsFinishing] = useState(hasTeamSignInReturn);
|
|
389
|
+
const transport = useMemo(() => access && teamTransport({
|
|
390
|
+
apiUrl,
|
|
391
|
+
token: access.token
|
|
392
|
+
}), [access, apiUrl]);
|
|
402
393
|
useEffect(() => {
|
|
403
394
|
finishTeamSignIn({
|
|
404
395
|
apiUrl,
|
|
@@ -416,27 +407,100 @@ function TeamLayer({ connection, position }) {
|
|
|
416
407
|
publicKey
|
|
417
408
|
}).catch((error) => reportFailure("Signing out of Reflet did not finish", error));
|
|
418
409
|
};
|
|
419
|
-
|
|
410
|
+
if (access && transport) return /* @__PURE__ */ jsx(TeamTools, {
|
|
411
|
+
placement,
|
|
412
|
+
team: {
|
|
413
|
+
onSignOut: signOut,
|
|
414
|
+
organizationName: access.organizationName,
|
|
415
|
+
transport
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
return /* @__PURE__ */ jsx(SignedOutAnchor, {
|
|
419
|
+
placement,
|
|
420
|
+
children: /* @__PURE__ */ jsx(TeamSignInCard, {
|
|
421
|
+
continuesInBrowser: false,
|
|
422
|
+
isFinishing,
|
|
423
|
+
notice,
|
|
424
|
+
onSignIn: async () => window.location.assign(await prepareTeamSignIn(connection))
|
|
425
|
+
})
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
/** A desktop app signs in through the system browser; its privileged process keeps the credential. */
|
|
429
|
+
function BridgeTeamAccount({ bridge, placement }) {
|
|
430
|
+
const [accountState, setAccountState] = useState({ kind: "loading" });
|
|
431
|
+
const [notice, setNotice] = useState(null);
|
|
432
|
+
const transport = useMemo(() => bridgeTransport(bridge), [bridge]);
|
|
433
|
+
useEffect(() => {
|
|
434
|
+
let isCurrent = true;
|
|
435
|
+
bridge.account().then((account) => isCurrent && setAccountState({
|
|
436
|
+
account,
|
|
437
|
+
kind: "loaded"
|
|
438
|
+
}), (error) => {
|
|
439
|
+
if (isCurrent) {
|
|
440
|
+
setAccountState({
|
|
441
|
+
account: null,
|
|
442
|
+
kind: "loaded"
|
|
443
|
+
});
|
|
444
|
+
setNotice(failureMessage(error));
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
return () => {
|
|
448
|
+
isCurrent = false;
|
|
449
|
+
};
|
|
450
|
+
}, [bridge]);
|
|
451
|
+
const signIn = async () => {
|
|
452
|
+
const account = await bridge.signIn();
|
|
453
|
+
setAccountState({
|
|
454
|
+
account,
|
|
455
|
+
kind: "loaded"
|
|
456
|
+
});
|
|
457
|
+
setNotice(null);
|
|
458
|
+
};
|
|
459
|
+
const signOut = (reason) => {
|
|
460
|
+
setAccountState({
|
|
461
|
+
account: null,
|
|
462
|
+
kind: "loaded"
|
|
463
|
+
});
|
|
464
|
+
setNotice(reason);
|
|
465
|
+
bridge.signOut().catch((error) => reportFailure("Signing out of Reflet did not finish", error));
|
|
466
|
+
};
|
|
467
|
+
if (accountState.kind === "loading") return null;
|
|
468
|
+
if (accountState.account) return /* @__PURE__ */ jsx(TeamTools, {
|
|
469
|
+
placement,
|
|
470
|
+
team: {
|
|
471
|
+
onSignOut: signOut,
|
|
472
|
+
organizationName: accountState.account.organizationName,
|
|
473
|
+
transport
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
return /* @__PURE__ */ jsx(SignedOutAnchor, {
|
|
477
|
+
placement,
|
|
478
|
+
children: /* @__PURE__ */ jsx(TeamSignInCard, {
|
|
479
|
+
continuesInBrowser: true,
|
|
480
|
+
isFinishing: false,
|
|
481
|
+
notice,
|
|
482
|
+
onSignIn: signIn
|
|
483
|
+
})
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
function placementFor(position) {
|
|
487
|
+
return {
|
|
488
|
+
edge: position.startsWith("top") ? "top" : "bottom",
|
|
489
|
+
side: position.endsWith("right") ? "right" : "left"
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
function TeamLayer(props) {
|
|
493
|
+
const placement = placementFor(props.position);
|
|
420
494
|
return /* @__PURE__ */ jsxs("div", {
|
|
421
495
|
className: "dt",
|
|
422
496
|
children: [
|
|
423
497
|
/* @__PURE__ */ jsx("style", { children: `${DEVTOOLS_STYLES}${SESSIONS_STYLES}` }),
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
}) : /* @__PURE__ */ jsx("div", {
|
|
432
|
-
className: "dt-team-anchor",
|
|
433
|
-
"data-edge": placement.edge,
|
|
434
|
-
"data-side": placement.side,
|
|
435
|
-
children: /* @__PURE__ */ jsx(TeamSignInCard, {
|
|
436
|
-
connection,
|
|
437
|
-
isFinishing,
|
|
438
|
-
notice
|
|
439
|
-
})
|
|
498
|
+
"bridge" in props ? /* @__PURE__ */ jsx(BridgeTeamAccount, {
|
|
499
|
+
bridge: props.bridge,
|
|
500
|
+
placement
|
|
501
|
+
}) : /* @__PURE__ */ jsx(BrowserTeamAccount, {
|
|
502
|
+
connection: props.connection,
|
|
503
|
+
placement
|
|
440
504
|
}),
|
|
441
505
|
/* @__PURE__ */ jsx(Notices, {})
|
|
442
506
|
]
|
|
@@ -445,4 +509,4 @@ function TeamLayer({ connection, position }) {
|
|
|
445
509
|
//#endregion
|
|
446
510
|
export { TeamLayer };
|
|
447
511
|
|
|
448
|
-
//# sourceMappingURL=team-layer-
|
|
512
|
+
//# sourceMappingURL=team-layer-_It1_oSo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-layer-_It1_oSo.js","names":[],"sources":["../src/sessions/team/team-auth.ts","../src/sessions/team/team-sign-in-card.tsx","../src/sessions/team/team-layer.tsx"],"sourcesContent":["import { z } from \"zod\";\nimport { sessionApiErrorSchema } from \"../protocol\";\nimport { TEAM_ACTIVATION_PARAM, teamAccessStorageKey } from \"./team-activation\";\n\nconst RETURN_CODE_PARAM = \"reflet-team-code\";\nconst RETURN_ERROR_PARAM = \"reflet-team-error\";\nconst RETURN_STATE_PARAM = \"reflet-team-state\";\nconst RETURN_PARAMS = [\n RETURN_CODE_PARAM,\n RETURN_ERROR_PARAM,\n RETURN_STATE_PARAM,\n];\nconst PENDING_SIGN_IN_PREFIX = \"reflet-team-sign-in:\";\nconst PKCE_RANDOM_BYTES = 32;\nconst TRAILING_SLASHES = /\\/+$/;\nconst BASE64_PADDING = /[=]+$/;\n\nconst teamAccessSchema = z.object({\n expiresAt: z.number(),\n organizationName: z.string(),\n token: z.string().startsWith(\"fb_team_\"),\n});\n\nexport type TeamAccess = z.infer<typeof teamAccessSchema>;\n\nconst pendingSignInSchema = z.object({\n codeVerifier: z.string(),\n state: z.string(),\n});\n\ntype PendingSignIn = z.infer<typeof pendingSignInSchema>;\n\nconst SIGN_IN_FAILURE_MESSAGES = {\n cancelled: \"Sign-in was cancelled.\",\n exchange_failed: \"Couldn't finish signing in to Reflet. Try again.\",\n interrupted:\n \"This sign-in was started in another tab or has expired. Sign in again.\",\n storage_blocked:\n \"Your browser blocks storage for this site, so Reflet sign-in can't finish. Allow site data, then try again.\",\n} as const;\n\nexport type TeamSignInFailure = keyof typeof SIGN_IN_FAILURE_MESSAGES;\n\nexport class TeamSignInError extends Error {\n readonly reason: TeamSignInFailure;\n\n constructor(reason: TeamSignInFailure, message?: string) {\n super(message ?? SIGN_IN_FAILURE_MESSAGES[reason]);\n this.name = \"TeamSignInError\";\n this.reason = reason;\n }\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n return btoa(String.fromCharCode(...bytes))\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(BASE64_PADDING, \"\");\n}\n\nfunction randomBase64Url(): string {\n return base64Url(crypto.getRandomValues(new Uint8Array(PKCE_RANDOM_BYTES)));\n}\n\nasync function pkceChallengeFor(codeVerifier: string): Promise<string> {\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(codeVerifier)\n );\n return base64Url(new Uint8Array(digest));\n}\n\nfunction apiEndpoint(apiUrl: string, path: string): string {\n return `${apiUrl.replace(TRAILING_SLASHES, \"\")}${path}`;\n}\n\nfunction parseStoredJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\nfunction storedTeamAccess(publicKey: string): TeamAccess | null {\n try {\n const raw = localStorage.getItem(teamAccessStorageKey(publicKey));\n const parsed = teamAccessSchema.safeParse(\n raw === null ? null : parseStoredJson(raw)\n );\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n}\n\nfunction persistTeamAccess(publicKey: string, access: TeamAccess | null): void {\n try {\n if (access) {\n localStorage.setItem(\n teamAccessStorageKey(publicKey),\n JSON.stringify(access)\n );\n } else {\n localStorage.removeItem(teamAccessStorageKey(publicKey));\n }\n } catch {\n // Storage disabled by browser policy: access then only lasts for this page.\n }\n}\n\nexport function readTeamAccess(publicKey: string): TeamAccess | null {\n const access = storedTeamAccess(publicKey);\n if (access && access.expiresAt > Date.now()) {\n return access;\n }\n persistTeamAccess(publicKey, null);\n return null;\n}\n\nfunction pendingSignInKey(publicKey: string): string {\n return `${PENDING_SIGN_IN_PREFIX}${publicKey}`;\n}\n\nfunction takePendingSignIn(publicKey: string): PendingSignIn | null {\n try {\n const key = pendingSignInKey(publicKey);\n const raw = sessionStorage.getItem(key);\n sessionStorage.removeItem(key);\n const parsed = pendingSignInSchema.safeParse(\n raw === null ? null : parseStoredJson(raw)\n );\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n}\n\nfunction rememberPendingSignIn(publicKey: string, pending: PendingSignIn) {\n try {\n sessionStorage.setItem(\n pendingSignInKey(publicKey),\n JSON.stringify(pending)\n );\n } catch {\n throw new TeamSignInError(\"storage_blocked\");\n }\n}\n\nfunction returnUrl(): string {\n const url = new URL(window.location.href);\n for (const param of RETURN_PARAMS) {\n url.searchParams.delete(param);\n }\n if (!url.searchParams.has(TEAM_ACTIVATION_PARAM)) {\n url.searchParams.set(TEAM_ACTIVATION_PARAM, \"\");\n }\n return url.href;\n}\n\nasync function exchangeCode(options: {\n apiUrl: string;\n code: string;\n codeVerifier: string;\n}): Promise<TeamAccess> {\n const response = await fetch(\n apiEndpoint(options.apiUrl, \"/api/v1/team/token\"),\n {\n body: JSON.stringify({\n code: options.code,\n codeVerifier: options.codeVerifier,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n }\n );\n if (!response.ok) {\n const failure = sessionApiErrorSchema.safeParse(\n await response.json().catch(() => null)\n );\n throw new TeamSignInError(\n \"exchange_failed\",\n failure.success ? failure.data.error : undefined\n );\n }\n const access = teamAccessSchema.safeParse(\n await response.json().catch(() => null)\n );\n if (!access.success) {\n throw new TeamSignInError(\"exchange_failed\");\n }\n return access.data;\n}\n\nexport async function prepareTeamSignIn(options: {\n appUrl: string;\n publicKey: string;\n}): Promise<string> {\n const pending = { codeVerifier: randomBase64Url(), state: randomBase64Url() };\n rememberPendingSignIn(options.publicKey, pending);\n const consentUrl = new URL(\"/auth/team\", options.appUrl);\n consentUrl.search = new URLSearchParams({\n code_challenge: await pkceChallengeFor(pending.codeVerifier),\n origin: window.location.origin,\n public_key: options.publicKey,\n return_to: returnUrl(),\n state: pending.state,\n }).toString();\n return consentUrl.href;\n}\n\nexport function hasTeamSignInReturn(): boolean {\n return new URL(window.location.href).searchParams.has(RETURN_STATE_PARAM);\n}\n\nasync function completeReturnedSignIn(options: {\n apiUrl: string;\n code: string | null;\n pending: PendingSignIn | null;\n publicKey: string;\n state: string;\n}): Promise<TeamAccess> {\n if (options.pending?.state !== options.state) {\n throw new TeamSignInError(\"interrupted\");\n }\n if (options.code === null) {\n throw new TeamSignInError(\"cancelled\");\n }\n const access = await exchangeCode({\n apiUrl: options.apiUrl,\n code: options.code,\n codeVerifier: options.pending.codeVerifier,\n });\n persistTeamAccess(options.publicKey, access);\n return access;\n}\n\n/** Strips the returned code from the address bar at once, so it is consumed by one caller only. */\nexport function finishTeamSignIn(options: {\n apiUrl: string;\n publicKey: string;\n}): Promise<TeamAccess> | null {\n const url = new URL(window.location.href);\n const state = url.searchParams.get(RETURN_STATE_PARAM);\n if (state === null) {\n return null;\n }\n const code = url.searchParams.get(RETURN_CODE_PARAM);\n for (const param of RETURN_PARAMS) {\n url.searchParams.delete(param);\n }\n window.history.replaceState(window.history.state, \"\", url.href);\n return completeReturnedSignIn({\n apiUrl: options.apiUrl,\n code,\n pending: takePendingSignIn(options.publicKey),\n publicKey: options.publicKey,\n state,\n });\n}\n\nexport async function forgetTeamAccess(options: {\n apiUrl: string;\n publicKey: string;\n}): Promise<void> {\n const access = storedTeamAccess(options.publicKey);\n persistTeamAccess(options.publicKey, null);\n if (!access) {\n return;\n }\n await fetch(apiEndpoint(options.apiUrl, \"/api/v1/team/revoke\"), {\n headers: { Authorization: `Bearer ${access.token}` },\n method: \"POST\",\n });\n}\n","import { useState } from \"react\";\nimport { failureMessage } from \"../ui/session-workspace\";\n\nexport interface TeamConnection {\n apiUrl: string;\n appUrl: string;\n publicKey: string;\n}\n\nfunction useTeamSignIn(onSignIn: () => Promise<void>) {\n const [isSigningIn, setIsSigningIn] = useState(false);\n const [failure, setFailure] = useState<string | null>(null);\n\n const signIn = async () => {\n setIsSigningIn(true);\n setFailure(null);\n try {\n await onSignIn();\n } catch (error) {\n setFailure(failureMessage(error));\n setIsSigningIn(false);\n }\n };\n\n return { failure, isSigningIn, signIn };\n}\n\nfunction SignInActions({\n canSignIn,\n onHide,\n onSignIn,\n}: {\n canSignIn: boolean;\n onHide: () => void;\n onSignIn: () => void;\n}) {\n return (\n <div className=\"dt-actions\">\n <button\n className=\"dt-btn\"\n data-variant=\"primary\"\n disabled={!canSignIn}\n onClick={onSignIn}\n type=\"button\"\n >\n Sign in with Reflet\n </button>\n <button className=\"dt-btn\" onClick={onHide} type=\"button\">\n Hide\n </button>\n </div>\n );\n}\n\nexport function TeamSignInCard({\n isFinishing,\n notice,\n onSignIn,\n continuesInBrowser,\n}: {\n isFinishing: boolean;\n notice: string | null;\n onSignIn: () => Promise<void>;\n continuesInBrowser: boolean;\n}) {\n const [isHidden, setIsHidden] = useState(false);\n const { failure, isSigningIn, signIn } = useTeamSignIn(onSignIn);\n const isWaitingForBrowser = continuesInBrowser && isSigningIn;\n const isLeavingPage = isSigningIn && !continuesInBrowser;\n\n if (isHidden) {\n return null;\n }\n return (\n <section aria-labelledby=\"rf-team-title\" className=\"dt-team-card glass\">\n <h2 className=\"dt-ses-subhead\" id=\"rf-team-title\">\n Reflet team tools\n </h2>\n <p className=\"dt-meta\">\n Sign in with your Reflet account to record a session on this app.\n </p>\n <p className=\"dt-meta\">\n Only members of the app's Reflet organization can sign in.\n </p>\n {isFinishing && (\n <p className=\"dt-meta\" role=\"status\">\n Finishing sign-in…\n </p>\n )}\n {isWaitingForBrowser && (\n <p className=\"dt-meta\" role=\"status\">\n Finish signing in in your browser.\n </p>\n )}\n {notice && (\n <p className=\"dt-meta\" role=\"status\">\n {notice}\n </p>\n )}\n {failure && (\n <p className=\"dt-error\" role=\"alert\">\n {failure}\n </p>\n )}\n <SignInActions\n canSignIn={!(isLeavingPage || isFinishing)}\n onHide={() => setIsHidden(true)}\n onSignIn={signIn}\n />\n </section>\n );\n}\n","import { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { AccountFooter } from \"../../devtools/client/account/account-footer\";\nimport {\n DevtoolsBar,\n SessionsBarButton,\n} from \"../../devtools/client/devtools-bar\";\nimport { DevtoolsSheet } from \"../../devtools/client/devtools-sheet\";\nimport { DEVTOOLS_STYLES } from \"../../devtools/client/devtools-styles\";\nimport { Notices, reportFailure } from \"../../devtools/client/notices\";\nimport type { RefletFeedbackProps } from \"../../feedback/types\";\nimport type { SessionTransport } from \"../api/session-api\";\nimport { bridgeTransport, teamTransport } from \"../api/session-transports\";\nimport { purgeAccount } from \"../local/local-sessions\";\nimport { RecordingLayer } from \"../ui/recording/recording-layer\";\nimport {\n failureMessage,\n SessionWorkspaceProvider,\n useWorkspaceLoader,\n type WorkspaceState,\n} from \"../ui/session-workspace\";\nimport {\n type SessionNavigation,\n SessionsPanel,\n sessionSheetPlace,\n useSessionNavigation,\n} from \"../ui/sessions-panel\";\nimport { SESSIONS_STYLES } from \"../ui/sessions-styles\";\nimport {\n finishTeamSignIn,\n forgetTeamAccess,\n hasTeamSignInReturn,\n prepareTeamSignIn,\n readTeamAccess,\n} from \"./team-auth\";\nimport { type TeamConnection, TeamSignInCard } from \"./team-sign-in-card\";\nimport type { TeamToolsAccount, TeamToolsBridge } from \"./team-tools-bridge\";\n\nconst TEAM_TOOLS_LABEL = \"Reflet team tools\";\nconst REFUSED_SIGN_IN_COPY =\n \"Reflet no longer accepts this sign-in. Sign in again to record.\";\n\ninterface TeamPlacement {\n edge: \"bottom\" | \"top\";\n side: \"left\" | \"right\";\n}\n\ninterface SignedInTeam {\n onSignOut: (reason: string | null) => void;\n organizationName: string;\n transport: SessionTransport;\n}\n\nfunction SessionsBody({\n navigation,\n onStarted,\n state,\n}: {\n navigation: SessionNavigation;\n onStarted: () => void;\n state: WorkspaceState;\n}) {\n if (state.kind === \"ready\") {\n return <SessionsPanel navigation={navigation} onStarted={onStarted} />;\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\nfunction TeamSheet({\n account,\n navigation,\n onClose,\n side,\n}: {\n account: {\n onSignOut: () => void;\n organizationName: string;\n state: WorkspaceState;\n };\n navigation: SessionNavigation;\n onClose: () => void;\n side: TeamPlacement[\"side\"];\n}) {\n const { state } = account;\n const place = state.kind === \"ready\" ? sessionSheetPlace(navigation) : null;\n return (\n <DevtoolsSheet\n footer={\n place === null && (\n <AccountFooter\n actions={[{ label: \"Sign out\", onSelect: account.onSignOut }]}\n organizationName={account.organizationName}\n person={\n state.kind === \"ready\" ? state.workspace.identity.user : null\n }\n />\n )\n }\n label={TEAM_TOOLS_LABEL}\n navigation={{\n onSelectTab: () => undefined,\n place,\n tab: \"sessions\",\n tabs: [\"sessions\"],\n }}\n onClose={onClose}\n side={side}\n >\n <SessionsBody navigation={navigation} onStarted={onClose} state={state} />\n </DevtoolsSheet>\n );\n}\n\nfunction useTeamWorkspace(team: SignedInTeam) {\n const { onSignOut } = team;\n const state = useWorkspaceLoader({\n onUnauthorized: () => onSignOut(REFUSED_SIGN_IN_COPY),\n surface: \"app\",\n transport: team.transport,\n });\n const workspace = state.kind === \"ready\" ? state.workspace : null;\n\n const signOut = async () => {\n if (workspace) {\n await purgeAccount(workspace.account.key).catch((error: unknown) =>\n reportFailure(\"This device's session data was not removed\", error)\n );\n }\n onSignOut(null);\n };\n\n return { signOut, state, workspace };\n}\n\nfunction TeamTools({\n team,\n placement,\n}: {\n placement: TeamPlacement;\n team: SignedInTeam;\n}) {\n const { signOut, state, workspace } = useTeamWorkspace(team);\n const [isSheetOpen, setIsSheetOpen] = useState(false);\n const navigation = useSessionNavigation();\n\n return (\n <SessionWorkspaceProvider workspace={workspace}>\n {isSheetOpen && (\n <TeamSheet\n account={{\n onSignOut: signOut,\n organizationName: team.organizationName,\n state,\n }}\n navigation={navigation}\n onClose={() => setIsSheetOpen(false)}\n side={placement.side}\n />\n )}\n <DevtoolsBar\n edge={placement.edge}\n label={TEAM_TOOLS_LABEL}\n side={placement.side}\n >\n <SessionsBarButton onOpen={() => setIsSheetOpen(true)} />\n </DevtoolsBar>\n {workspace && (\n <RecordingLayer\n onFinished={(target) => {\n navigation.go({ target, view: \"review\" });\n setIsSheetOpen(true);\n }}\n />\n )}\n </SessionWorkspaceProvider>\n );\n}\n\nfunction SignedOutAnchor({\n children,\n placement,\n}: {\n children: ReactNode;\n placement: TeamPlacement;\n}) {\n return (\n <div\n className=\"dt-team-anchor\"\n data-edge={placement.edge}\n data-side={placement.side}\n >\n {children}\n </div>\n );\n}\n\n/** A web page signs in by leaving for reflet.app and coming back with a token for its own origin. */\nfunction BrowserTeamAccount({\n connection,\n placement,\n}: {\n connection: TeamConnection;\n placement: TeamPlacement;\n}) {\n const { apiUrl, publicKey } = connection;\n const [access, setAccess] = useState(() => readTeamAccess(publicKey));\n const [notice, setNotice] = useState<string | null>(null);\n const [isFinishing, setIsFinishing] = useState(hasTeamSignInReturn);\n const transport = useMemo(\n () => access && teamTransport({ apiUrl, token: access.token }),\n [access, apiUrl]\n );\n useEffect(() => {\n finishTeamSignIn({ apiUrl, publicKey })\n ?.then(\n (signedIn) => {\n setAccess(signedIn);\n setNotice(null);\n },\n (error: unknown) => setNotice(failureMessage(error))\n )\n .finally(() => setIsFinishing(false));\n }, [apiUrl, publicKey]);\n const signOut = (reason: string | null) => {\n setAccess(null);\n setNotice(reason);\n forgetTeamAccess({ apiUrl, publicKey }).catch((error: unknown) =>\n reportFailure(\"Signing out of Reflet did not finish\", error)\n );\n };\n\n if (access && transport) {\n return (\n <TeamTools\n placement={placement}\n team={{\n onSignOut: signOut,\n organizationName: access.organizationName,\n transport,\n }}\n />\n );\n }\n return (\n <SignedOutAnchor placement={placement}>\n <TeamSignInCard\n continuesInBrowser={false}\n isFinishing={isFinishing}\n notice={notice}\n onSignIn={async () =>\n window.location.assign(await prepareTeamSignIn(connection))\n }\n />\n </SignedOutAnchor>\n );\n}\n\ntype BridgeAccountState =\n | { kind: \"loading\" }\n | { account: TeamToolsAccount | null; kind: \"loaded\" };\n\n/** A desktop app signs in through the system browser; its privileged process keeps the credential. */\nfunction BridgeTeamAccount({\n bridge,\n placement,\n}: {\n bridge: TeamToolsBridge;\n placement: TeamPlacement;\n}) {\n const [accountState, setAccountState] = useState<BridgeAccountState>({\n kind: \"loading\",\n });\n const [notice, setNotice] = useState<string | null>(null);\n const transport = useMemo(() => bridgeTransport(bridge), [bridge]);\n useEffect(() => {\n let isCurrent = true;\n bridge.account().then(\n (account) => isCurrent && setAccountState({ account, kind: \"loaded\" }),\n (error: unknown) => {\n if (isCurrent) {\n setAccountState({ account: null, kind: \"loaded\" });\n setNotice(failureMessage(error));\n }\n }\n );\n return () => {\n isCurrent = false;\n };\n }, [bridge]);\n const signIn = async () => {\n const account = await bridge.signIn();\n setAccountState({ account, kind: \"loaded\" });\n setNotice(null);\n };\n const signOut = (reason: string | null) => {\n setAccountState({ account: null, kind: \"loaded\" });\n setNotice(reason);\n bridge\n .signOut()\n .catch((error: unknown) =>\n reportFailure(\"Signing out of Reflet did not finish\", error)\n );\n };\n\n if (accountState.kind === \"loading\") {\n return null;\n }\n if (accountState.account) {\n return (\n <TeamTools\n placement={placement}\n team={{\n onSignOut: signOut,\n organizationName: accountState.account.organizationName,\n transport,\n }}\n />\n );\n }\n return (\n <SignedOutAnchor placement={placement}>\n <TeamSignInCard\n continuesInBrowser\n isFinishing={false}\n notice={notice}\n onSignIn={signIn}\n />\n </SignedOutAnchor>\n );\n}\n\nfunction placementFor(\n position: NonNullable<RefletFeedbackProps[\"position\"]>\n): TeamPlacement {\n return {\n edge: position.startsWith(\"top\") ? \"top\" : \"bottom\",\n side: position.endsWith(\"right\") ? \"right\" : \"left\",\n };\n}\n\nexport function TeamLayer(\n props: { position: NonNullable<RefletFeedbackProps[\"position\"]> } & (\n | { bridge: TeamToolsBridge }\n | { connection: TeamConnection }\n )\n) {\n const placement = placementFor(props.position);\n return (\n <div className=\"dt\">\n <style>{`${DEVTOOLS_STYLES}${SESSIONS_STYLES}`}</style>\n {\"bridge\" in props ? (\n <BridgeTeamAccount bridge={props.bridge} placement={placement} />\n ) : (\n <BrowserTeamAccount\n connection={props.connection}\n placement={placement}\n />\n )}\n <Notices />\n </div>\n );\n}\n"],"mappings":";;;;;;AAIA,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAC3B,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;CACpB;CACA;CACA;AACF;AACA,MAAM,yBAAyB;AAC/B,MAAM,oBAAoB;AAC1B,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AAEvB,MAAM,mBAAmB,EAAE,OAAO;CAChC,WAAW,EAAE,OAAO;CACpB,kBAAkB,EAAE,OAAO;CAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,WAAW,UAAU;AACzC,CAAC;AAID,MAAM,sBAAsB,EAAE,OAAO;CACnC,cAAc,EAAE,OAAO;CACvB,OAAO,EAAE,OAAO;AAClB,CAAC;AAID,MAAM,2BAA2B;CAC/B,WAAW;CACX,iBAAiB;CACjB,aACE;CACF,iBACE;AACJ;AAIA,IAAa,kBAAb,cAAqC,MAAM;CACzC;CAEA,YAAY,QAA2B,SAAkB;EACvD,MAAM,WAAW,yBAAyB,OAAO;EACjD,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,SAAS,UAAU,OAA2B;CAC5C,OAAO,KAAK,OAAO,aAAa,GAAG,KAAK,CAAC,CAAC,CACvC,WAAW,KAAK,GAAG,CAAC,CACpB,WAAW,KAAK,GAAG,CAAC,CACpB,QAAQ,gBAAgB,EAAE;AAC/B;AAEA,SAAS,kBAA0B;CACjC,OAAO,UAAU,OAAO,gBAAgB,IAAI,WAAW,iBAAiB,CAAC,CAAC;AAC5E;AAEA,eAAe,iBAAiB,cAAuC;CACrE,MAAM,SAAS,MAAM,OAAO,OAAO,OACjC,WACA,IAAI,YAAY,CAAC,CAAC,OAAO,YAAY,CACvC;CACA,OAAO,UAAU,IAAI,WAAW,MAAM,CAAC;AACzC;AAEA,SAAS,YAAY,QAAgB,MAAsB;CACzD,OAAO,GAAG,OAAO,QAAQ,kBAAkB,EAAE,IAAI;AACnD;AAEA,SAAS,gBAAgB,KAAsB;CAC7C,IAAI;EACF,OAAO,KAAK,MAAM,GAAG;CACvB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,iBAAiB,WAAsC;CAC9D,IAAI;EACF,MAAM,MAAM,aAAa,QAAQ,qBAAqB,SAAS,CAAC;EAChE,MAAM,SAAS,iBAAiB,UAC9B,QAAQ,OAAO,OAAO,gBAAgB,GAAG,CAC3C;EACA,OAAO,OAAO,UAAU,OAAO,OAAO;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,kBAAkB,WAAmB,QAAiC;CAC7E,IAAI;EACF,IAAI,QACF,aAAa,QACX,qBAAqB,SAAS,GAC9B,KAAK,UAAU,MAAM,CACvB;OAEA,aAAa,WAAW,qBAAqB,SAAS,CAAC;CAE3D,QAAQ,CAER;AACF;AAEA,SAAgB,eAAe,WAAsC;CACnE,MAAM,SAAS,iBAAiB,SAAS;CACzC,IAAI,UAAU,OAAO,YAAY,KAAK,IAAI,GACxC,OAAO;CAET,kBAAkB,WAAW,IAAI;CACjC,OAAO;AACT;AAEA,SAAS,iBAAiB,WAA2B;CACnD,OAAO,GAAG,yBAAyB;AACrC;AAEA,SAAS,kBAAkB,WAAyC;CAClE,IAAI;EACF,MAAM,MAAM,iBAAiB,SAAS;EACtC,MAAM,MAAM,eAAe,QAAQ,GAAG;EACtC,eAAe,WAAW,GAAG;EAC7B,MAAM,SAAS,oBAAoB,UACjC,QAAQ,OAAO,OAAO,gBAAgB,GAAG,CAC3C;EACA,OAAO,OAAO,UAAU,OAAO,OAAO;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,sBAAsB,WAAmB,SAAwB;CACxE,IAAI;EACF,eAAe,QACb,iBAAiB,SAAS,GAC1B,KAAK,UAAU,OAAO,CACxB;CACF,QAAQ;EACN,MAAM,IAAI,gBAAgB,iBAAiB;CAC7C;AACF;AAEA,SAAS,YAAoB;CAC3B,MAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;CACxC,KAAK,MAAM,SAAS,eAClB,IAAI,aAAa,OAAO,KAAK;CAE/B,IAAI,CAAC,IAAI,aAAa,IAAA,aAAyB,GAC7C,IAAI,aAAa,IAAI,uBAAuB,EAAE;CAEhD,OAAO,IAAI;AACb;AAEA,eAAe,aAAa,SAIJ;CACtB,MAAM,WAAW,MAAM,MACrB,YAAY,QAAQ,QAAQ,oBAAoB,GAChD;EACE,MAAM,KAAK,UAAU;GACnB,MAAM,QAAQ;GACd,cAAc,QAAQ;EACxB,CAAC;EACD,SAAS,EAAE,gBAAgB,mBAAmB;EAC9C,QAAQ;CACV,CACF;CACA,IAAI,CAAC,SAAS,IAAI;EAChB,MAAM,UAAU,sBAAsB,UACpC,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,IAAI,CACxC;EACA,MAAM,IAAI,gBACR,mBACA,QAAQ,UAAU,QAAQ,KAAK,QAAQ,KAAA,CACzC;CACF;CACA,MAAM,SAAS,iBAAiB,UAC9B,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,IAAI,CACxC;CACA,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,gBAAgB,iBAAiB;CAE7C,OAAO,OAAO;AAChB;AAEA,eAAsB,kBAAkB,SAGpB;CAClB,MAAM,UAAU;EAAE,cAAc,gBAAgB;EAAG,OAAO,gBAAgB;CAAE;CAC5E,sBAAsB,QAAQ,WAAW,OAAO;CAChD,MAAM,aAAa,IAAI,IAAI,cAAc,QAAQ,MAAM;CACvD,WAAW,SAAS,IAAI,gBAAgB;EACtC,gBAAgB,MAAM,iBAAiB,QAAQ,YAAY;EAC3D,QAAQ,OAAO,SAAS;EACxB,YAAY,QAAQ;EACpB,WAAW,UAAU;EACrB,OAAO,QAAQ;CACjB,CAAC,CAAC,CAAC,SAAS;CACZ,OAAO,WAAW;AACpB;AAEA,SAAgB,sBAA+B;CAC7C,OAAO,IAAI,IAAI,OAAO,SAAS,IAAI,CAAC,CAAC,aAAa,IAAI,kBAAkB;AAC1E;AAEA,eAAe,uBAAuB,SAMd;CACtB,IAAI,QAAQ,SAAS,UAAU,QAAQ,OACrC,MAAM,IAAI,gBAAgB,aAAa;CAEzC,IAAI,QAAQ,SAAS,MACnB,MAAM,IAAI,gBAAgB,WAAW;CAEvC,MAAM,SAAS,MAAM,aAAa;EAChC,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,cAAc,QAAQ,QAAQ;CAChC,CAAC;CACD,kBAAkB,QAAQ,WAAW,MAAM;CAC3C,OAAO;AACT;;AAGA,SAAgB,iBAAiB,SAGF;CAC7B,MAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;CACxC,MAAM,QAAQ,IAAI,aAAa,IAAI,kBAAkB;CACrD,IAAI,UAAU,MACZ,OAAO;CAET,MAAM,OAAO,IAAI,aAAa,IAAI,iBAAiB;CACnD,KAAK,MAAM,SAAS,eAClB,IAAI,aAAa,OAAO,KAAK;CAE/B,OAAO,QAAQ,aAAa,OAAO,QAAQ,OAAO,IAAI,IAAI,IAAI;CAC9D,OAAO,uBAAuB;EAC5B,QAAQ,QAAQ;EAChB;EACA,SAAS,kBAAkB,QAAQ,SAAS;EAC5C,WAAW,QAAQ;EACnB;CACF,CAAC;AACH;AAEA,eAAsB,iBAAiB,SAGrB;CAChB,MAAM,SAAS,iBAAiB,QAAQ,SAAS;CACjD,kBAAkB,QAAQ,WAAW,IAAI;CACzC,IAAI,CAAC,QACH;CAEF,MAAM,MAAM,YAAY,QAAQ,QAAQ,qBAAqB,GAAG;EAC9D,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ;EACnD,QAAQ;CACV,CAAC;AACH;;;ACzQA,SAAS,cAAc,UAA+B;CACpD,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,SAAS,cAAc,SAAwB,IAAI;CAE1D,MAAM,SAAS,YAAY;EACzB,eAAe,IAAI;EACnB,WAAW,IAAI;EACf,IAAI;GACF,MAAM,SAAS;EACjB,SAAS,OAAO;GACd,WAAW,eAAe,KAAK,CAAC;GAChC,eAAe,KAAK;EACtB;CACF;CAEA,OAAO;EAAE;EAAS;EAAa;CAAO;AACxC;AAEA,SAAS,cAAc,EACrB,WACA,QACA,YAKC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,UAAD;GACE,WAAU;GACV,gBAAa;GACb,UAAU,CAAC;GACX,SAAS;GACT,MAAK;GACN,UAAA;EAEO,CAAA,GACR,oBAAC,UAAD;GAAQ,WAAU;GAAS,SAAS;GAAQ,MAAK;GAAS,UAAA;EAElD,CAAA,CACL;;AAET;AAEA,SAAgB,eAAe,EAC7B,aACA,QACA,UACA,sBAMC;CACD,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK;CAC9C,MAAM,EAAE,SAAS,aAAa,WAAW,cAAc,QAAQ;CAC/D,MAAM,sBAAsB,sBAAsB;CAClD,MAAM,gBAAgB,eAAe,CAAC;CAEtC,IAAI,UACF,OAAO;CAET,OACE,qBAAC,WAAD;EAAS,mBAAgB;EAAgB,WAAU;EAAnD,UAAA;GACE,oBAAC,MAAD;IAAI,WAAU;IAAiB,IAAG;IAAgB,UAAA;GAE9C,CAAA;GACJ,oBAAC,KAAD;IAAG,WAAU;IAAU,UAAA;GAEpB,CAAA;GACH,oBAAC,KAAD;IAAG,WAAU;IAAU,UAAA;GAEpB,CAAA;GACF,eACC,oBAAC,KAAD;IAAG,WAAU;IAAU,MAAK;IAAS,UAAA;GAElC,CAAA;GAEJ,uBACC,oBAAC,KAAD;IAAG,WAAU;IAAU,MAAK;IAAS,UAAA;GAElC,CAAA;GAEJ,UACC,oBAAC,KAAD;IAAG,WAAU;IAAU,MAAK;IACzB,UAAA;GACA,CAAA;GAEJ,WACC,oBAAC,KAAD;IAAG,WAAU;IAAW,MAAK;IAC1B,UAAA;GACA,CAAA;GAEL,oBAAC,eAAD;IACE,WAAW,EAAE,iBAAiB;IAC9B,cAAc,YAAY,IAAI;IAC9B,UAAU;GACX,CAAA;EACM;;AAEb;;;AC1EA,MAAM,mBAAmB;AACzB,MAAM,uBACJ;AAaF,SAAS,aAAa,EACpB,YACA,WACA,SAKC;CACD,IAAI,MAAM,SAAS,SACjB,OAAO,oBAAC,eAAD;EAA2B;EAAuB;CAAY,CAAA;CAEvE,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;AAEA,SAAS,UAAU,EACjB,SACA,YACA,SACA,QAUC;CACD,MAAM,EAAE,UAAU;CAClB,MAAM,QAAQ,MAAM,SAAS,UAAU,kBAAkB,UAAU,IAAI;CACvE,OACE,oBAAC,eAAD;EACE,QACE,UAAU,QACR,oBAAC,eAAD;GACE,SAAS,CAAC;IAAE,OAAO;IAAY,UAAU,QAAQ;GAAU,CAAC;GAC5D,kBAAkB,QAAQ;GAC1B,QACE,MAAM,SAAS,UAAU,MAAM,UAAU,SAAS,OAAO;EAE5D,CAAA;EAGL,OAAO;EACP,YAAY;GACV,mBAAmB,KAAA;GACnB;GACA,KAAK;GACL,MAAM,CAAC,UAAU;EACnB;EACS;EACH;EAEN,UAAA,oBAAC,cAAD;GAA0B;GAAY,WAAW;GAAgB;EAAQ,CAAA;CAC5D,CAAA;AAEnB;AAEA,SAAS,iBAAiB,MAAoB;CAC5C,MAAM,EAAE,cAAc;CACtB,MAAM,QAAQ,mBAAmB;EAC/B,sBAAsB,UAAU,oBAAoB;EACpD,SAAS;EACT,WAAW,KAAK;CAClB,CAAC;CACD,MAAM,YAAY,MAAM,SAAS,UAAU,MAAM,YAAY;CAE7D,MAAM,UAAU,YAAY;EAC1B,IAAI,WACF,MAAM,aAAa,UAAU,QAAQ,GAAG,CAAC,CAAC,OAAO,UAC/C,cAAc,8CAA8C,KAAK,CACnE;EAEF,UAAU,IAAI;CAChB;CAEA,OAAO;EAAE;EAAS;EAAO;CAAU;AACrC;AAEA,SAAS,UAAU,EACjB,MACA,aAIC;CACD,MAAM,EAAE,SAAS,OAAO,cAAc,iBAAiB,IAAI;CAC3D,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,aAAa,qBAAqB;CAExC,OACE,qBAAC,0BAAD;EAAqC;EAArC,UAAA;GACG,eACC,oBAAC,WAAD;IACE,SAAS;KACP,WAAW;KACX,kBAAkB,KAAK;KACvB;IACF;IACY;IACZ,eAAe,eAAe,KAAK;IACnC,MAAM,UAAU;GACjB,CAAA;GAEH,oBAAC,aAAD;IACE,MAAM,UAAU;IAChB,OAAO;IACP,MAAM,UAAU;IAEhB,UAAA,oBAAC,mBAAD,EAAmB,cAAc,eAAe,IAAI,EAAI,CAAA;GAC7C,CAAA;GACZ,aACC,oBAAC,gBAAD,EACE,aAAa,WAAW;IACtB,WAAW,GAAG;KAAE;KAAQ,MAAM;IAAS,CAAC;IACxC,eAAe,IAAI;GACrB,EACD,CAAA;EAEqB;;AAE9B;AAEA,SAAS,gBAAgB,EACvB,UACA,aAIC;CACD,OACE,oBAAC,OAAD;EACE,WAAU;EACV,aAAW,UAAU;EACrB,aAAW,UAAU;EAEpB;CACE,CAAA;AAET;;AAGA,SAAS,mBAAmB,EAC1B,YACA,aAIC;CACD,MAAM,EAAE,QAAQ,cAAc;CAC9B,MAAM,CAAC,QAAQ,aAAa,eAAe,eAAe,SAAS,CAAC;CACpE,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,CAAC,aAAa,kBAAkB,SAAS,mBAAmB;CAClE,MAAM,YAAY,cACV,UAAU,cAAc;EAAE;EAAQ,OAAO,OAAO;CAAM,CAAC,GAC7D,CAAC,QAAQ,MAAM,CACjB;CACA,gBAAgB;EACd,iBAAiB;GAAE;GAAQ;EAAU,CAAC,CAAC,EACnC,MACC,aAAa;GACZ,UAAU,QAAQ;GAClB,UAAU,IAAI;EAChB,IACC,UAAmB,UAAU,eAAe,KAAK,CAAC,CACrD,CAAC,CACA,cAAc,eAAe,KAAK,CAAC;CACxC,GAAG,CAAC,QAAQ,SAAS,CAAC;CACtB,MAAM,WAAW,WAA0B;EACzC,UAAU,IAAI;EACd,UAAU,MAAM;EAChB,iBAAiB;GAAE;GAAQ;EAAU,CAAC,CAAC,CAAC,OAAO,UAC7C,cAAc,wCAAwC,KAAK,CAC7D;CACF;CAEA,IAAI,UAAU,WACZ,OACE,oBAAC,WAAD;EACa;EACX,MAAM;GACJ,WAAW;GACX,kBAAkB,OAAO;GACzB;EACF;CACD,CAAA;CAGL,OACE,oBAAC,iBAAD;EAA4B;EAC1B,UAAA,oBAAC,gBAAD;GACE,oBAAoB;GACP;GACL;GACR,UAAU,YACR,OAAO,SAAS,OAAO,MAAM,kBAAkB,UAAU,CAAC;EAE7D,CAAA;CACc,CAAA;AAErB;;AAOA,SAAS,kBAAkB,EACzB,QACA,aAIC;CACD,MAAM,CAAC,cAAc,mBAAmB,SAA6B,EACnE,MAAM,UACR,CAAC;CACD,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,YAAY,cAAc,gBAAgB,MAAM,GAAG,CAAC,MAAM,CAAC;CACjE,gBAAgB;EACd,IAAI,YAAY;EAChB,OAAO,QAAQ,CAAC,CAAC,MACd,YAAY,aAAa,gBAAgB;GAAE;GAAS,MAAM;EAAS,CAAC,IACpE,UAAmB;GAClB,IAAI,WAAW;IACb,gBAAgB;KAAE,SAAS;KAAM,MAAM;IAAS,CAAC;IACjD,UAAU,eAAe,KAAK,CAAC;GACjC;EACF,CACF;EACA,aAAa;GACX,YAAY;EACd;CACF,GAAG,CAAC,MAAM,CAAC;CACX,MAAM,SAAS,YAAY;EACzB,MAAM,UAAU,MAAM,OAAO,OAAO;EACpC,gBAAgB;GAAE;GAAS,MAAM;EAAS,CAAC;EAC3C,UAAU,IAAI;CAChB;CACA,MAAM,WAAW,WAA0B;EACzC,gBAAgB;GAAE,SAAS;GAAM,MAAM;EAAS,CAAC;EACjD,UAAU,MAAM;EAChB,OACG,QAAQ,CAAC,CACT,OAAO,UACN,cAAc,wCAAwC,KAAK,CAC7D;CACJ;CAEA,IAAI,aAAa,SAAS,WACxB,OAAO;CAET,IAAI,aAAa,SACf,OACE,oBAAC,WAAD;EACa;EACX,MAAM;GACJ,WAAW;GACX,kBAAkB,aAAa,QAAQ;GACvC;EACF;CACD,CAAA;CAGL,OACE,oBAAC,iBAAD;EAA4B;EAC1B,UAAA,oBAAC,gBAAD;GACE,oBAAA;GACA,aAAa;GACL;GACR,UAAU;EACX,CAAA;CACc,CAAA;AAErB;AAEA,SAAS,aACP,UACe;CACf,OAAO;EACL,MAAM,SAAS,WAAW,KAAK,IAAI,QAAQ;EAC3C,MAAM,SAAS,SAAS,OAAO,IAAI,UAAU;CAC/C;AACF;AAEA,SAAgB,UACd,OAIA;CACA,MAAM,YAAY,aAAa,MAAM,QAAQ;CAC7C,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,SAAD,EAAA,UAAQ,GAAG,kBAAkB,kBAAyB,CAAA;GACrD,YAAY,QACX,oBAAC,mBAAD;IAAmB,QAAQ,MAAM;IAAmB;GAAY,CAAA,IAEhE,oBAAC,oBAAD;IACE,YAAY,MAAM;IACP;GACZ,CAAA;GAEH,oBAAC,SAAD,CAAU,CAAA;EACP;;AAET"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/sessions/team/team-tools-bridge.d.ts
|
|
2
|
+
interface TeamToolsAccount {
|
|
3
|
+
organizationName: string;
|
|
4
|
+
}
|
|
5
|
+
/** One Reflet API call; `path` is the API path, e.g. `/api/v1/sessions/list`. */
|
|
6
|
+
interface TeamToolsCall {
|
|
7
|
+
body?: string;
|
|
8
|
+
method: "GET" | "POST";
|
|
9
|
+
path: string;
|
|
10
|
+
query?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
interface TeamToolsReply {
|
|
13
|
+
body: string;
|
|
14
|
+
status: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Team tools for a desktop app whose pages have no web origin Reflet can bind a
|
|
18
|
+
* sign-in to, such as Electron's `file://`. The app's privileged process
|
|
19
|
+
* implements it with `createTeamToolsHost` from `reflet-sdk/desktop` and keeps
|
|
20
|
+
* the credential; the page only sees calls and replies.
|
|
21
|
+
*/
|
|
22
|
+
interface TeamToolsBridge {
|
|
23
|
+
account: () => Promise<TeamToolsAccount | null>;
|
|
24
|
+
request: (call: TeamToolsCall) => Promise<TeamToolsReply>;
|
|
25
|
+
/** Opens Reflet sign-in in the system browser; resolves once the member approves. Calling it again reopens the same sign-in. */
|
|
26
|
+
signIn: () => Promise<TeamToolsAccount>;
|
|
27
|
+
signOut: () => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { TeamToolsReply as i, TeamToolsBridge as n, TeamToolsCall as r, TeamToolsAccount as t };
|
|
31
|
+
//# sourceMappingURL=team-tools-bridge-C51PpkUI.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-tools-bridge-C51PpkUI.d.ts","names":[],"sources":["../src/sessions/team/team-tools-bridge.ts"],"mappings":";UAAiB;EACf;;;UAIe;EACf;EACA;EACA;EACA,QAAQ;;UAGO;EACf;EACA;;;;;;;;UASe;EACf,eAAe,QAAQ;EACvB,UAAU,MAAM,kBAAkB,QAAQ;;EAE1C,cAAc,QAAQ;EACtB,eAAe"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reflet-sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "Official Reflet SDK - Collect user feedback, feature requests, and bug reports from your app",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"feedback",
|
|
@@ -58,6 +58,10 @@
|
|
|
58
58
|
"./devtools/vite": {
|
|
59
59
|
"types": "./dist/devtools-vite.d.ts",
|
|
60
60
|
"import": "./dist/devtools-vite.js"
|
|
61
|
+
},
|
|
62
|
+
"./desktop": {
|
|
63
|
+
"types": "./dist/desktop.d.ts",
|
|
64
|
+
"import": "./dist/desktop.js"
|
|
61
65
|
}
|
|
62
66
|
},
|
|
63
67
|
"main": "./dist/index.js",
|