@aperture-browser/session-react 0.0.0-nightly.129.9e2ebce87a2d → 0.0.0-nightly.131.764dc151c439
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/dist/{headless-0KVuQrnF.js → headless-CxE_tawC.js} +11 -2
- package/dist/headless-CxE_tawC.js.map +1 -0
- package/dist/headless.d.ts +2 -2
- package/dist/headless.js +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.js +143 -161
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -5
- package/dist/headless-0KVuQrnF.js.map +0 -1
|
@@ -2,6 +2,7 @@ import { createContext, useCallback, useContext, useEffect, useLayoutEffect, use
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Stream from "effect/Stream";
|
|
4
4
|
import { DEFAULT_VIEWPORT, LiveSessionConnection, LiveSessionError, LiveSessionError as LiveSessionError$1, computeRenderMetrics, createViewportPreset, downloadSessionRecording, evdevKeycodeByCode, getSessionStatus, getTargetThumbnail, keyboardInputMessage, keyboardModifiers, shouldForwardBrowserShortcut, strictParseOptions, windowsVirtualKeyCodeForCodeOrKey } from "@aperture-browser/live-session";
|
|
5
|
+
import * as Equal from "effect/Equal";
|
|
5
6
|
import * as Option from "effect/Option";
|
|
6
7
|
import * as PubSub from "effect/PubSub";
|
|
7
8
|
import * as Schema from "effect/Schema";
|
|
@@ -95,7 +96,9 @@ const pointerButtonCode = {
|
|
|
95
96
|
right: 273,
|
|
96
97
|
middle: 274
|
|
97
98
|
};
|
|
98
|
-
function useLiveSession({ access, displayName = null, enabled, webrtcSupported, iceServers, autoSize }) {
|
|
99
|
+
function useLiveSession({ access: accessOption, displayName = null, enabled, webrtcSupported, iceServers: iceServersOption, autoSize }) {
|
|
100
|
+
const access = useEqualValue(accessOption);
|
|
101
|
+
const iceServers = useEqualValue(iceServersOption);
|
|
99
102
|
const identity = useMemo(() => collaborationIdentity(displayName), [displayName]);
|
|
100
103
|
const [role, setRole] = useState("viewer");
|
|
101
104
|
const runtime = useRuntime();
|
|
@@ -694,6 +697,12 @@ function sendShortcut(sendInputEvent, targetId, code) {
|
|
|
694
697
|
modifiers: 0
|
|
695
698
|
});
|
|
696
699
|
}
|
|
700
|
+
/** Returns the previous value while the new one is equal by value. */
|
|
701
|
+
function useEqualValue(value) {
|
|
702
|
+
const ref = useRef(value);
|
|
703
|
+
if (!Equal.equals(ref.current, value)) ref.current = value;
|
|
704
|
+
return ref.current;
|
|
705
|
+
}
|
|
697
706
|
//#endregion
|
|
698
707
|
//#region src/components/collaboration-paint-overlay.tsx
|
|
699
708
|
const paintColors = [
|
|
@@ -2226,4 +2235,4 @@ function useSession({ access, displayName, onNotice }) {
|
|
|
2226
2235
|
//#endregion
|
|
2227
2236
|
export { makeApertureRuntime as a, collaborationPaintLifetimeMs as c, RuntimeProviderMissingError as d, useBaseUrl as f, useRuntime as g, useRunApi as h, ApertureProvider as i, useLiveSession as l, useFork as m, shareSessionAccess as n, useBrowserControl as o, useEffectCallback as p, useSession as r, SessionViewport as s, LiveSessionError$1 as t, RuntimeProvider as u };
|
|
2228
2237
|
|
|
2229
|
-
//# sourceMappingURL=headless-
|
|
2238
|
+
//# sourceMappingURL=headless-CxE_tawC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-CxE_tawC.js","names":["exhaustive","exhaustive","emptyIceServers"],"sources":["../src/effect.tsx","../src/hooks/use-live-session.ts","../src/components/collaboration-paint-overlay.tsx","../src/components/session-viewport.tsx","../src/hooks/use-browser-control.ts","../src/runtime.ts","../src/provider.tsx","../src/session.ts"],"sourcesContent":["import type * as HttpClient from \"effect/http/HttpClient\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n type DependencyList,\n type ReactNode,\n} from \"react\";\nimport * as Data from \"effect/Data\";\nimport type * as Effect from \"effect/Effect\";\nimport type * as Fiber from \"effect/Fiber\";\nimport type { ApiServices } from \"@aperture-browser/api-client\";\nimport type { ApertureRuntime } from \"./runtime.ts\";\n\ninterface RuntimeContextValue {\n readonly runtime: ApertureRuntime;\n readonly baseUrl: string | undefined;\n}\n\nconst RuntimeContext = createContext<RuntimeContextValue | null>(null);\n\n/** A hook below needed the app runtime, but no RuntimeProvider is above the component. */\nexport class RuntimeProviderMissingError extends Data.TaggedError(\"RuntimeProviderMissingError\") {\n override readonly message = \"useRuntime must be used inside RuntimeProvider\";\n}\n\nexport function RuntimeProvider({\n runtime,\n baseUrl,\n children,\n}: {\n runtime: ApertureRuntime;\n baseUrl?: string;\n children: ReactNode;\n}) {\n const value = useMemo(() => ({ runtime, baseUrl }), [runtime, baseUrl]);\n return <RuntimeContext.Provider value={value}>{children}</RuntimeContext.Provider>;\n}\n\nfunction useRuntimeContext(): RuntimeContextValue {\n const context = useContext(RuntimeContext);\n if (!context) {\n throw new RuntimeProviderMissingError();\n }\n return context;\n}\n\nexport function useRuntime(): ApertureRuntime {\n return useRuntimeContext().runtime;\n}\n\nexport function useBaseUrl(): string | undefined {\n return useRuntimeContext().baseUrl;\n}\n\n/**\n * Runs an effect while the component is mounted, restarting it when `deps` change, like\n * `useEffect`. Return `undefined` to run nothing. The fiber is interrupted synchronously\n * on cleanup, so its synchronous finalizers have run before the next effect starts.\n */\nexport function useFork(\n effect: () => Effect.Effect<unknown, never, ApiServices | HttpClient.HttpClient> | undefined,\n deps: DependencyList,\n): void {\n const runtime = useRuntime();\n useEffect(() => {\n const program = effect();\n if (!program) {\n return;\n }\n const fiber = runtime.runFork(program);\n return () => fiber.interruptUnsafe();\n // The caller's deps describe `effect`, as with useEffect.\n }, [runtime, ...deps]);\n}\n\n/**\n * Returns an event handler that forks the effect `callback` builds. Fibers still running\n * when the component unmounts are interrupted.\n */\nexport function useEffectCallback<Args extends ReadonlyArray<unknown>>(\n callback: (...args: Args) => Effect.Effect<unknown, never, ApiServices | HttpClient.HttpClient>,\n deps: DependencyList,\n): (...args: Args) => void {\n const runtime = useRuntime();\n const fibers = useRef(new Set<Fiber.Fiber<unknown>>());\n\n useEffect(() => {\n const running = fibers.current;\n return () => {\n for (const fiber of running) {\n fiber.interruptUnsafe();\n }\n running.clear();\n };\n }, []);\n\n return useCallback(\n (...args: Args) => {\n const fiber = runtime.runFork(callback(...args));\n if (fiber.pollUnsafe()) {\n return;\n }\n fibers.current.add(fiber);\n fiber.addObserver(() => fibers.current.delete(fiber));\n },\n // The caller's deps describe `callback`, as with useCallback.\n [runtime, ...deps],\n );\n}\n\n/**\n * Returns a function that runs an API call for promise-based callers such as TanStack\n * Query. Aborting the signal interrupts the request.\n */\nexport function useRunApi() {\n const runtime = useRuntime();\n return useCallback(\n <A, E>(\n call: Effect.Effect<A, E, ApiServices>,\n options?: { readonly signal?: AbortSignal },\n ): Promise<A> => runtime.runPromise(call, options),\n [runtime],\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport * as Effect from \"effect/Effect\";\nimport * as Equal from \"effect/Equal\";\nimport * as Option from \"effect/Option\";\nimport * as PubSub from \"effect/PubSub\";\nimport * as Schema from \"effect/Schema\";\nimport * as Stream from \"effect/Stream\";\nimport * as SubscriptionRef from \"effect/SubscriptionRef\";\nimport type { IceServer } from \"@aperture-browser/api-client\";\nimport type { Recording } from \"@aperture-browser/api-client\";\nimport type { BrowserInputMessage } from \"@aperture-browser/live-session\";\nimport { evdevKeycodeByCode } from \"@aperture-browser/live-session\";\nimport { windowsVirtualKeyCodeForCodeOrKey } from \"@aperture-browser/live-session\";\nimport { LiveSessionConnection } from \"@aperture-browser/live-session\";\nimport {\n strictParseOptions,\n type SessionAccess,\n type CollaborationCursor,\n type CollaborationError,\n type CollaborationLeaseMode,\n type CollaborationPaintEvent,\n type CollaborationPaintPoint,\n type CollaborationParticipant,\n type CollaborationPhase,\n type CollaborationRole,\n type LiveSessionCommandResult,\n type LiveSessionPresentation,\n type LiveSessionPresentationQuality,\n type LiveSessionRasterFrame,\n type LiveSessionServerMessage,\n type LiveSessionTarget,\n} from \"@aperture-browser/live-session\";\nimport { useEffectCallback, useFork, useRuntime } from \"../effect.tsx\";\n\ninterface InputDimensions {\n width: number;\n height: number;\n}\n\nexport interface LiveSessionMediaSize {\n width: number;\n height: number;\n deviceScaleFactor: number;\n canvasWidth: number;\n canvasHeight: number;\n}\n\nexport type LiveSessionMediaSelection =\n | { kind: \"jpeg\" }\n | { kind: \"webrtc\"; quality: LiveSessionPresentationQuality }\n | { kind: \"webrtc-retry\" };\n\nexport interface CollaborationControl {\n phase: CollaborationPhase;\n role: CollaborationRole;\n clientId: string;\n holderClientId: string | null;\n leaseMode: CollaborationLeaseMode | null;\n hasControl: boolean;\n canRequestControl: boolean;\n lastError: CollaborationError | null;\n participants: readonly CollaborationParticipant[];\n cursors: ReadonlyMap<string, CollaborationCursor>;\n paintEvents: Stream.Stream<CollaborationPaintEvent>;\n followingClientId: string | null;\n claim: (targetId: string, mode: CollaborationLeaseMode) => boolean;\n release: () => boolean;\n setActiveTarget: (targetId: string | null) => boolean;\n follow: (clientId: string | null) => boolean;\n sendCursor: (targetId: string, x: number, y: number, dimensions: InputDimensions) => boolean;\n sendPaintPoint: (point: CollaborationPaintPoint) => boolean;\n clearCursor: () => boolean;\n sendInput: (message: BrowserInputMessage, dimensions: InputDimensions) => boolean;\n}\n\ninterface UseLiveSessionOptions {\n access: SessionAccess | null;\n displayName?: string | null;\n enabled: boolean;\n webrtcSupported: boolean;\n iceServers: readonly IceServer[];\n autoSize: () => boolean;\n}\n\n/** Session-wide auto-size arbitration, known only when the server supports it. */\nexport interface LiveSessionViewportOwnership {\n ownerClientId: string | null;\n autoSize: boolean;\n}\n\nexport interface LiveSessionControl {\n phase: \"idle\" | \"connecting\" | \"connected\" | \"disconnected\" | \"error\";\n targets: readonly LiveSessionTarget[];\n activeTargetId: string | null;\n /** The newest raster frame, starting with the current one. */\n frames: Stream.Stream<LiveSessionRasterFrame | null>;\n mediaStream: MediaStream | null;\n mediaSize: LiveSessionMediaSize | null;\n transport: \"webrtc\" | \"websocket\" | null;\n presentation: LiveSessionPresentation | null;\n mediaSwitching: boolean;\n recordings: readonly Recording[];\n viewportOwnership: LiveSessionViewportOwnership | null;\n collaboration: CollaborationControl;\n sendBrowserInput: (message: BrowserInputMessage, dimensions: InputDimensions) => boolean;\n selectTarget: (targetId: string) => boolean;\n requestSelectTarget: (\n targetId: string,\n ) => Effect.Effect<void, LiveSessionConnection.LiveSessionError>;\n command: (type: string, payload?: Record<string, unknown>) => boolean;\n request: (\n type: string,\n payload?: Record<string, unknown>,\n ) => Effect.Effect<LiveSessionCommandResult, LiveSessionConnection.LiveSessionError>;\n selectPresentation: (\n selection: LiveSessionMediaSelection,\n ) => Effect.Effect<void, LiveSessionConnection.LiveSessionError>;\n reconnect: () => void;\n}\n\nconst heartbeatIntervalMs = 2_000;\n\nconst transportUnavailable = () =>\n new LiveSessionConnection.LiveSessionError({ message: \"live session transport is unavailable\" });\nconst cursorIntervalMs = 40;\nexport const collaborationPaintLifetimeMs = 7_000;\nconst pointerButtonCode: Record<\"left\" | \"right\" | \"middle\", number> = {\n left: 272,\n right: 273,\n middle: 274,\n};\n\nexport function useLiveSession({\n access: accessOption,\n displayName = null,\n enabled,\n webrtcSupported,\n iceServers: iceServersOption,\n autoSize,\n}: UseLiveSessionOptions): LiveSessionControl {\n // Callers often rebuild these from refetched data, such as a session refetched on window\n // focus; only a change in value may reopen the connection.\n const access = useEqualValue(accessOption);\n const iceServers = useEqualValue(iceServersOption);\n const identity = useMemo(() => collaborationIdentity(displayName), [displayName]);\n const [role, setRole] = useState<CollaborationRole>(\"viewer\");\n const runtime = useRuntime();\n const frameRef = useMemo(\n () => runtime.runSync(SubscriptionRef.make<LiveSessionRasterFrame | null>(null)),\n [runtime],\n );\n const paintPubSub = useMemo(\n () => runtime.runSync(PubSub.unbounded<CollaborationPaintEvent>()),\n [runtime],\n );\n const frames = useMemo(() => SubscriptionRef.changes(frameRef), [frameRef]);\n const paintEvents = useMemo(() => Stream.fromPubSub(paintPubSub), [paintPubSub]);\n const publishFrame = useCallback(\n (frame: LiveSessionRasterFrame | null) => runtime.runSync(SubscriptionRef.set(frameRef, frame)),\n [frameRef, runtime],\n );\n const publishPaint = useCallback(\n (event: CollaborationPaintEvent) => PubSub.publishUnsafe(paintPubSub, event),\n [paintPubSub],\n );\n const connectionRef = useRef<LiveSessionConnection.LiveSessionConnection | null>(null);\n const holderClientIdRef = useRef<string | null>(null);\n const clientIdRef = useRef(\"\");\n const claimPendingRef = useRef(false);\n const releasePendingRef = useRef(false);\n const cursorVisibleRef = useRef(false);\n const lastCursorSentAtRef = useRef(0);\n const participantsRef = useRef<readonly CollaborationParticipant[]>([]);\n const followingClientIdRef = useRef<string | null>(null);\n const mediaSizeRef = useRef<LiveSessionMediaSize | null>(null);\n const transportRef = useRef<LiveSessionControl[\"transport\"]>(null);\n const presentationRef = useRef<LiveSessionPresentation | null>(null);\n const presentationSelectionRef = useRef(false);\n\n const [phase, setPhase] = useState<LiveSessionControl[\"phase\"]>(\"idle\");\n const [targets, setTargets] = useState<readonly LiveSessionTarget[]>([]);\n const [activeTargetId, setActiveTargetId] = useState<string | null>(null);\n const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);\n const [mediaSize, setMediaSize] = useState<LiveSessionMediaSize | null>(null);\n const [transport, setTransport] = useState<LiveSessionControl[\"transport\"]>(null);\n const [targetSwitching, setTargetSwitching] = useState(false);\n const [presentationSwitching, setPresentationSwitching] = useState(false);\n const [presentation, setPresentation] = useState<LiveSessionPresentation | null>(null);\n const [recordings, setRecordings] = useState<readonly Recording[]>([]);\n const [viewportOwnership, setViewportOwnership] = useState<LiveSessionViewportOwnership | null>(\n null,\n );\n const [clientId, setClientId] = useState(\"\");\n const [holderClientId, setHolderClientId] = useState<string | null>(null);\n const [leaseMode, setLeaseMode] = useState<CollaborationLeaseMode | null>(null);\n const [participants, setParticipants] = useState<readonly CollaborationParticipant[]>([]);\n const [cursors, setCursors] = useState<ReadonlyMap<string, CollaborationCursor>>(() => new Map());\n const [lastError, setLastError] = useState<CollaborationError | null>(null);\n\n mediaSizeRef.current = mediaSize;\n transportRef.current = transport;\n presentationRef.current = presentation;\n\n const handleMessage = useCallback(\n (message: LiveSessionServerMessage) => {\n switch (message.type) {\n case \"session.snapshot\":\n setRole(message.role);\n clientIdRef.current = message.clientId;\n setClientId(message.clientId);\n holderClientIdRef.current = message.holderClientId ?? null;\n setHolderClientId(message.holderClientId ?? null);\n setLeaseMode(message.mode ?? null);\n participantsRef.current = message.participants;\n setParticipants(message.participants);\n followingClientIdRef.current =\n message.participants.find((participant) => participant.clientId === message.clientId)\n ?.followingClientId ?? null;\n setTargets(message.targets);\n setActiveTargetId(message.activeTargetId ?? null);\n setMediaSize(resolveMediaSize(message.targets, message.activeTargetId));\n setRecordings(message.recordings);\n setPresentation(message.presentation ?? null);\n setViewportOwnership(\n message.autoSize === undefined\n ? null\n : {\n ownerClientId: message.viewportOwnerClientId ?? null,\n autoSize: message.autoSize,\n },\n );\n setLastError(null);\n return;\n case \"targets.state\":\n setTargets(message.targets);\n setActiveTargetId(message.activeTargetId ?? null);\n setMediaSize(resolveMediaSize(message.targets, message.activeTargetId));\n setTargetSwitching(false);\n return;\n case \"presence.state\": {\n participantsRef.current = message.participants;\n setParticipants(message.participants);\n followingClientIdRef.current =\n message.participants.find((participant) => participant.clientId === clientIdRef.current)\n ?.followingClientId ?? null;\n setCursors((current) => {\n const followed = followingClientIdRef.current;\n if (!followed) {\n return current.size === 0 ? current : new Map();\n }\n const cursor = current.get(followed);\n return cursor ? new Map([[followed, cursor]]) : new Map();\n });\n return;\n }\n case \"input.state\":\n holderClientIdRef.current = message.holderClientId ?? null;\n setHolderClientId(message.holderClientId ?? null);\n setLeaseMode(message.mode ?? null);\n claimPendingRef.current = false;\n releasePendingRef.current = false;\n setLastError((current) =>\n current?.code === \"input_busy\" || current?.code === \"input_not_owned\" ? null : current,\n );\n return;\n case \"viewport.state\":\n setViewportOwnership({\n ownerClientId: message.viewportOwnerClientId ?? null,\n autoSize: message.autoSize,\n });\n return;\n case \"presence.cursor\":\n if (message.clientId !== followingClientIdRef.current) {\n return;\n }\n setCursors((current) => new Map(current).set(message.clientId, message));\n return;\n case \"presence.cursor.clear\":\n setCursors((current) => {\n if (!current.has(message.clientId)) {\n return current;\n }\n const next = new Map(current);\n next.delete(message.clientId);\n return next;\n });\n return;\n case \"paint.point\":\n if (\n participantsRef.current.some((participant) => participant.clientId === message.clientId)\n ) {\n publishPaint({ type: \"point\", message });\n }\n return;\n case \"recordings.state\":\n setRecordings(message.recordings);\n return;\n case \"presentation.state\":\n setPresentation(message.presentation);\n return;\n case \"error\":\n claimPendingRef.current = false;\n releasePendingRef.current = false;\n setLastError({ code: message.code, message: message.message });\n return;\n default:\n if (message.presentation) {\n setPresentation(message.presentation);\n }\n if (!message.ok) {\n setLastError({\n code: message.code ?? \"request_rejected\",\n message: message.message ?? \"Live session command failed.\",\n });\n }\n }\n },\n [publishPaint],\n );\n\n useFork(() => {\n if (!enabled || access === null) {\n connectionRef.current = null;\n setPhase(\"idle\");\n setRole(\"viewer\");\n setTargets([]);\n setActiveTargetId(null);\n setMediaStream(null);\n setMediaSize(null);\n setTransport(null);\n setPresentation(null);\n setTargetSwitching(false);\n setPresentationSwitching(false);\n setParticipants([]);\n setCursors(new Map());\n setRecordings([]);\n setViewportOwnership(null);\n publishFrame(null);\n publishPaint({ type: \"clear\" });\n return undefined;\n }\n\n setRole(\"viewer\");\n // The connection lives as long as this fiber; interrupting it closes the connection.\n return Effect.gen(function* () {\n const connection = yield* LiveSessionConnection.make({\n access,\n identity,\n autoSize,\n iceServers,\n webrtcSupported,\n callbacks: {\n onPhase: setPhase,\n onMessage: handleMessage,\n onFrame: publishFrame,\n onStream: setMediaStream,\n onTransport: setTransport,\n onError: (message) => setLastError({ code: \"connection_failed\", message }),\n },\n });\n connectionRef.current = connection;\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n if (connectionRef.current === connection) {\n connectionRef.current = null;\n }\n }),\n );\n return yield* Effect.never;\n }).pipe(\n Effect.scoped,\n Effect.ensuring(\n Effect.sync(() => {\n publishFrame(null);\n publishPaint({ type: \"clear\" });\n }),\n ),\n );\n }, [\n autoSize,\n access,\n enabled,\n handleMessage,\n iceServers,\n identity,\n publishFrame,\n publishPaint,\n webrtcSupported,\n ]);\n\n const sendReliable = useCallback(\n (message: Record<string, unknown>) => connectionRef.current?.sendReliable(message) ?? false,\n [],\n );\n const sendRealtime = useCallback(\n (message: Record<string, unknown>) => connectionRef.current?.sendRealtime(message) ?? false,\n [],\n );\n const runCommand = useEffectCallback(\n (\n connection: LiveSessionConnection.LiveSessionConnection,\n type: string,\n payload: Record<string, unknown>,\n ) =>\n connection.command(type, payload).pipe(\n Effect.catch((error) =>\n Effect.sync(() => {\n setTargetSwitching(false);\n setLastError({ code: \"request_rejected\", message: error.message });\n }),\n ),\n ),\n [],\n );\n const command = useCallback(\n (type: string, payload: Record<string, unknown> = {}) => {\n const connection = connectionRef.current;\n if (!connection) {\n return false;\n }\n runCommand(connection, type, payload);\n return true;\n },\n [runCommand],\n );\n const request = useCallback(\n (type: string, payload: Record<string, unknown> = {}) =>\n Effect.suspend(() =>\n connectionRef.current\n ? connectionRef.current.command(type, payload)\n : Effect.fail(transportUnavailable()),\n ),\n [],\n );\n const runSelectTarget = useEffectCallback(\n (connection: LiveSessionConnection.LiveSessionConnection, targetId: string) =>\n connection.command(\"target.select\", { targetId }).pipe(\n Effect.match({\n onSuccess: () => setActiveTargetId(targetId),\n onFailure: (error) => setLastError({ code: \"request_rejected\", message: error.message }),\n }),\n Effect.ensuring(Effect.sync(() => setTargetSwitching(false))),\n ),\n [],\n );\n const requestSelectTarget = useCallback(\n (targetId: string) =>\n Effect.suspend(() => {\n const connection = connectionRef.current;\n if (!connection) {\n return Effect.fail(transportUnavailable());\n }\n setTargetSwitching(true);\n return connection.command(\"target.select\", { targetId }).pipe(\n Effect.tap(() => Effect.sync(() => setActiveTargetId(targetId))),\n Effect.tapError((error) =>\n Effect.sync(() => setLastError({ code: \"request_rejected\", message: error.message })),\n ),\n Effect.ensuring(Effect.sync(() => setTargetSwitching(false))),\n Effect.asVoid,\n );\n }),\n [],\n );\n const selectTarget = useCallback(\n (targetId: string) => {\n const connection = connectionRef.current;\n if (!connection) {\n return false;\n }\n setTargetSwitching(true);\n runSelectTarget(connection, targetId);\n return true;\n },\n [runSelectTarget],\n );\n\n const selectPresentation = useCallback(\n (selection: LiveSessionMediaSelection) =>\n Effect.suspend(() => {\n const connection = connectionRef.current;\n if (!connection) {\n return Effect.fail(transportUnavailable());\n }\n if (presentationSelectionRef.current) {\n return Effect.fail(\n new LiveSessionConnection.LiveSessionError({\n message: \"another presentation update is already in progress\",\n }),\n );\n }\n presentationSelectionRef.current = true;\n setPresentationSwitching(true);\n return Effect.gen(function* () {\n switch (selection.kind) {\n case \"jpeg\":\n return yield* connection.selectTransport(\"websocket\");\n case \"webrtc-retry\":\n return yield* connection.selectTransport(\"webrtc\");\n case \"webrtc\": {\n const size = mediaSizeRef.current;\n if (!size) {\n return yield* new LiveSessionConnection.LiveSessionError({\n message: \"presentation size is unavailable\",\n });\n }\n const profileChanged =\n presentationRef.current?.quality?.profile !== selection.quality.profile;\n // A new encoder profile needs a new WebRTC session; present JPEG meanwhile.\n const restoreWebRTC = profileChanged && transportRef.current === \"webrtc\";\n if (restoreWebRTC) {\n yield* connection.selectTransport(\"websocket\");\n }\n const result = yield* connection\n .command(\"presentation.quality.set\", {\n profile: selection.quality.profile,\n width: size.canvasWidth,\n height: size.canvasHeight,\n fps: selection.quality.fps,\n bitrateKbps: selection.quality.bitrateKbps,\n })\n .pipe(\n // Keep the quality update error as the reported failure.\n Effect.tapError(() =>\n restoreWebRTC\n ? Effect.ignore(connection.selectTransport(\"webrtc\"))\n : Effect.void,\n ),\n );\n if (result.presentation) {\n setPresentation(result.presentation);\n }\n return yield* connection.selectTransport(\"webrtc\");\n }\n default: {\n const exhaustive: never = selection;\n return exhaustive;\n }\n }\n }).pipe(\n Effect.tapError((error) =>\n Effect.sync(() =>\n setLastError({ code: \"presentation_update_failed\", message: error.message }),\n ),\n ),\n Effect.ensuring(\n Effect.sync(() => {\n presentationSelectionRef.current = false;\n setPresentationSwitching(false);\n }),\n ),\n );\n }),\n [],\n );\n\n const claim = useCallback(\n (targetId: string, mode: CollaborationLeaseMode) => {\n if (role === \"viewer\" || !sendReliable({ type: \"input.claim\", targetId, mode })) {\n return false;\n }\n claimPendingRef.current = true;\n releasePendingRef.current = false;\n return true;\n },\n [role, sendReliable],\n );\n const release = useCallback(() => {\n if (\n releasePendingRef.current ||\n holderClientIdRef.current !== clientIdRef.current ||\n !sendReliable({ type: \"input.release\" })\n ) {\n return false;\n }\n releasePendingRef.current = true;\n claimPendingRef.current = false;\n return true;\n }, [sendReliable]);\n const setActiveTarget = useCallback(\n (targetId: string | null) => (targetId ? selectTarget(targetId) : false),\n [selectTarget],\n );\n const follow = useCallback(\n (followingClientId: string | null) =>\n sendReliable({ type: \"follow.set\", followingClientId: followingClientId ?? \"\" }),\n [sendReliable],\n );\n const sendCursor = useCallback(\n (targetId: string, x: number, y: number, dimensions: InputDimensions) => {\n const now = performance.now();\n if (now - lastCursorSentAtRef.current < cursorIntervalMs) {\n return false;\n }\n lastCursorSentAtRef.current = now;\n const sent = sendRealtime({\n type: \"presence.cursor\",\n targetId,\n x: normalizedCoordinate(x, dimensions.width),\n y: normalizedCoordinate(y, dimensions.height),\n });\n if (sent) {\n cursorVisibleRef.current = true;\n }\n return sent;\n },\n [sendRealtime],\n );\n const sendPaintPoint = useCallback(\n (point: CollaborationPaintPoint) =>\n point.phase === \"move\"\n ? sendRealtime({ type: \"paint.point\", ...point })\n : sendReliable({ type: \"paint.point\", ...point }),\n [sendRealtime, sendReliable],\n );\n const clearCursor = useCallback(() => {\n if (!cursorVisibleRef.current || !sendReliable({ type: \"presence.cursor.clear\" })) {\n return false;\n }\n cursorVisibleRef.current = false;\n return true;\n }, [sendReliable]);\n\n const sendInputEvent = useCallback(\n (message: Record<string, unknown>, realtime = false) =>\n realtime ? sendRealtime(message) : sendReliable(message),\n [sendRealtime, sendReliable],\n );\n const sendBrowserInput = useCallback(\n (message: BrowserInputMessage, dimensions: InputDimensions) => {\n if (\n role === \"viewer\" ||\n (holderClientIdRef.current !== clientIdRef.current && !claimPendingRef.current)\n ) {\n return false;\n }\n switch (message.type) {\n case \"input.mouse\": {\n const x = normalizedCoordinate(message.x, dimensions.width);\n const y = normalizedCoordinate(message.y, dimensions.height);\n if (message.action === \"move\") {\n return sendInputEvent(\n {\n type: \"input.pointer.motion.absolute\",\n targetId: message.targetId,\n x,\n y,\n width: dimensions.width,\n height: dimensions.height,\n modifiers: message.modifiers ?? 0,\n },\n true,\n );\n }\n if (message.button === \"none\") {\n return true;\n }\n const buttonCode = pointerButtonCode[message.button ?? \"left\"];\n const sendButton = (pressed: boolean, clickCount: number) =>\n sendInputEvent({\n type: \"input.pointer.button\",\n targetId: message.targetId,\n x,\n y,\n width: dimensions.width,\n height: dimensions.height,\n buttonCode,\n pressed,\n clickCount,\n modifiers: message.modifiers ?? 0,\n });\n if (message.action === \"down\" || message.action === \"up\") {\n return sendButton(message.action === \"down\", message.clickCount ?? 1);\n }\n const count = message.action === \"doubleClick\" ? 2 : 1;\n for (let index = 0; index < count; index += 1) {\n const clickCount = message.action === \"doubleClick\" ? index + 1 : 1;\n sendButton(true, clickCount);\n sendButton(false, clickCount);\n }\n return true;\n }\n case \"input.wheel\": {\n const x = normalizedCoordinate(message.x, dimensions.width);\n const y = normalizedCoordinate(message.y, dimensions.height);\n sendInputEvent({\n type: \"input.pointer.scroll\",\n targetId: message.targetId,\n x,\n y,\n width: dimensions.width,\n height: dimensions.height,\n horizontal: message.deltaX,\n vertical: message.deltaY,\n stopHorizontal: false,\n stopVertical: false,\n modifiers: message.modifiers ?? 0,\n });\n return sendInputEvent({\n type: \"input.pointer.scroll\",\n targetId: message.targetId,\n x,\n y,\n width: dimensions.width,\n height: dimensions.height,\n horizontal: 0,\n vertical: 0,\n stopHorizontal: message.deltaX !== 0,\n stopVertical: message.deltaY !== 0,\n modifiers: message.modifiers ?? 0,\n });\n }\n case \"input.key\": {\n if (message.action === \"char\") {\n return message.text\n ? sendInputEvent({\n type: \"input.keyboard.text\",\n targetId: message.targetId,\n text: message.text,\n })\n : false;\n }\n const keycode = evdevKeycodeByCode[message.code ?? \"\"];\n if (!keycode) {\n return false;\n }\n const windowsVirtualKeyCode =\n message.windowsVirtualKeyCode ??\n windowsVirtualKeyCodeForCodeOrKey(message.code, message.key);\n return sendInputEvent({\n type: \"input.keyboard.key\",\n targetId: message.targetId,\n keycode,\n pressed: message.action === \"down\",\n key: message.key,\n code: message.code,\n text: message.text,\n unmodifiedText: message.unmodifiedText,\n modifiers: message.modifiers ?? 0,\n windowsVirtualKeyCode,\n nativeVirtualKeyCode: message.nativeVirtualKeyCode ?? windowsVirtualKeyCode,\n location: message.location ?? 0,\n autoRepeat: message.autoRepeat ?? false,\n isKeypad: message.isKeypad ?? false,\n });\n }\n case \"clipboard.copy\":\n return sendShortcut(sendInputEvent, message.targetId, \"KeyC\");\n case \"clipboard.cut\":\n return sendShortcut(sendInputEvent, message.targetId, \"KeyX\");\n case \"clipboard.paste\": {\n const item = message.items.find((candidate) => candidate.mimeType === \"text/plain\");\n return item\n ? sendInputEvent({\n type: \"input.keyboard.text\",\n targetId: message.targetId,\n text: item.data,\n })\n : false;\n }\n default: {\n const exhaustive: never = message;\n return exhaustive;\n }\n }\n },\n [role, sendInputEvent],\n );\n\n const hasControl = holderClientId === clientId && clientId !== \"\";\n const followingClientId =\n participants.find((participant) => participant.clientId === clientId)?.followingClientId ??\n null;\n useFork(\n () =>\n hasControl\n ? Effect.sleep(heartbeatIntervalMs).pipe(\n Effect.andThen(\n Effect.sync(() => {\n if (holderClientIdRef.current === clientIdRef.current) {\n sendReliable({ type: \"input.heartbeat\" });\n }\n }),\n ),\n Effect.forever,\n )\n : undefined,\n [hasControl, sendReliable],\n );\n\n return {\n phase,\n targets,\n activeTargetId,\n frames,\n mediaStream,\n mediaSize,\n transport,\n presentation,\n mediaSwitching: targetSwitching || presentationSwitching,\n recordings,\n viewportOwnership,\n sendBrowserInput,\n selectTarget,\n requestSelectTarget,\n command,\n request,\n selectPresentation,\n reconnect: () => {\n const connection = connectionRef.current;\n if (connection) {\n runtime.runSync(connection.reconnect);\n }\n },\n collaboration: {\n phase: phase === \"error\" ? \"disconnected\" : phase,\n role,\n clientId,\n holderClientId,\n leaseMode,\n hasControl,\n canRequestControl: role !== \"viewer\" && phase === \"connected\",\n lastError,\n participants,\n cursors,\n paintEvents,\n followingClientId,\n claim,\n release,\n setActiveTarget,\n follow,\n sendCursor,\n sendPaintPoint,\n clearCursor,\n sendInput: sendBrowserInput,\n },\n };\n}\n\nconst StoredIdentity = Schema.Struct({\n name: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(48)),\n avatarHash: Schema.String.check(Schema.isPattern(/^[0-9a-f]{32}$/)),\n});\n\nconst decodeStoredIdentity = Schema.decodeUnknownOption(\n Schema.fromJsonString(StoredIdentity),\n strictParseOptions,\n);\n\nfunction collaborationIdentity(accountName: string | null) {\n const anonymous = loadAnonymousIdentity();\n if (!accountName?.trim()) {\n return anonymous;\n }\n return {\n ...anonymous,\n name: Array.from(accountName.trim()).slice(0, 48).join(\"\"),\n };\n}\n\nfunction loadAnonymousIdentity() {\n const storageKey = \"aperture.collaboration.identity\";\n try {\n const stored = window.localStorage.getItem(storageKey);\n if (stored) {\n const parsed = decodeStoredIdentity(stored);\n if (Option.isSome(parsed)) {\n return parsed.value;\n }\n }\n const created = createAnonymousIdentity();\n window.localStorage.setItem(storageKey, JSON.stringify(created));\n return created;\n } catch {\n return createAnonymousIdentity();\n }\n}\n\nfunction createAnonymousIdentity() {\n const adjectives = [\"Amber\", \"Brisk\", \"Calm\", \"Clever\", \"Misty\", \"Quiet\", \"Swift\", \"Warm\"];\n const animals = [\"Badger\", \"Falcon\", \"Fox\", \"Koala\", \"Otter\", \"Panda\", \"Raven\", \"Tiger\"];\n const random = new Uint8Array(18);\n crypto.getRandomValues(random);\n const adjective = adjectives[(random.at(0) ?? 0) % adjectives.length] ?? \"Quiet\";\n const animal = animals[(random.at(1) ?? 0) % animals.length] ?? \"Otter\";\n return {\n name: `${adjective} ${animal}`,\n avatarHash: Array.from(random.slice(2), (value) => value.toString(16).padStart(2, \"0\")).join(\n \"\",\n ),\n };\n}\n\nfunction resolveMediaSize(\n targets: ReadonlyArray<{\n id: string;\n viewport?: {\n width: number;\n height: number;\n canvasWidth: number;\n canvasHeight: number;\n deviceScaleFactor: number;\n };\n }>,\n activeTargetId: string | undefined,\n): LiveSessionMediaSize | null {\n const viewport = targets.find((target) => target.id === activeTargetId)?.viewport;\n return viewport\n ? {\n width: viewport.width,\n height: viewport.height,\n canvasWidth: viewport.canvasWidth,\n canvasHeight: viewport.canvasHeight,\n deviceScaleFactor: viewport.deviceScaleFactor,\n }\n : null;\n}\n\nfunction normalizedCoordinate(value: number, length: number) {\n if (length <= 1) {\n return 0;\n }\n return Math.min(1, Math.max(0, value / length));\n}\n\nfunction sendShortcut(\n sendInputEvent: (message: Record<string, unknown>, realtime?: boolean) => boolean,\n targetId: string,\n code: \"KeyC\" | \"KeyX\",\n) {\n const controlKeycode = evdevKeycodeByCode.ControlLeft;\n const shortcutKeycode = evdevKeycodeByCode[code];\n if (!controlKeycode || !shortcutKeycode) {\n return false;\n }\n const controlVirtualKeyCode = windowsVirtualKeyCodeForCodeOrKey(\"ControlLeft\", \"Control\");\n const shortcutKey = code === \"KeyC\" ? \"c\" : \"x\";\n const shortcutVirtualKeyCode = windowsVirtualKeyCodeForCodeOrKey(code, shortcutKey);\n sendInputEvent({\n type: \"input.keyboard.key\",\n targetId,\n keycode: controlKeycode,\n pressed: true,\n key: \"Control\",\n code: \"ControlLeft\",\n windowsVirtualKeyCode: controlVirtualKeyCode,\n nativeVirtualKeyCode: controlVirtualKeyCode,\n modifiers: 2,\n });\n sendInputEvent({\n type: \"input.keyboard.key\",\n targetId,\n keycode: shortcutKeycode,\n pressed: true,\n key: shortcutKey,\n code,\n windowsVirtualKeyCode: shortcutVirtualKeyCode,\n nativeVirtualKeyCode: shortcutVirtualKeyCode,\n modifiers: 2,\n });\n sendInputEvent({\n type: \"input.keyboard.key\",\n targetId,\n keycode: shortcutKeycode,\n pressed: false,\n key: shortcutKey,\n code,\n windowsVirtualKeyCode: shortcutVirtualKeyCode,\n nativeVirtualKeyCode: shortcutVirtualKeyCode,\n modifiers: 2,\n });\n return sendInputEvent({\n type: \"input.keyboard.key\",\n targetId,\n keycode: controlKeycode,\n pressed: false,\n key: \"Control\",\n code: \"ControlLeft\",\n windowsVirtualKeyCode: controlVirtualKeyCode,\n nativeVirtualKeyCode: controlVirtualKeyCode,\n modifiers: 0,\n });\n}\n\nexport type {\n CollaborationCursor,\n CollaborationError,\n CollaborationLeaseMode,\n CollaborationPaintEvent,\n CollaborationPaintPoint,\n CollaborationParticipant,\n CollaborationPhase,\n CollaborationRole,\n};\n\n/** Returns the previous value while the new one is equal by value. */\nfunction useEqualValue<A>(value: A): A {\n const ref = useRef(value);\n if (!Equal.equals(ref.current, value)) {\n ref.current = value;\n }\n return ref.current;\n}\n","import { useEffect, useRef, type PointerEvent as ReactPointerEvent } from \"react\";\nimport * as Effect from \"effect/Effect\";\nimport * as Stream from \"effect/Stream\";\nimport type { CollaborationControl } from \"../hooks/use-live-session.ts\";\nimport { collaborationPaintLifetimeMs } from \"../hooks/use-live-session.ts\";\nimport type {\n CollaborationPaintEvent,\n CollaborationPaintPoint,\n} from \"@aperture-browser/live-session\";\nimport { useFork } from \"../effect.tsx\";\n\ninterface CollaborationPaintOverlayProps {\n collaboration: CollaborationControl;\n targetId: string;\n enabled: boolean;\n visible: boolean;\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nconst paintColors = [\"#f43f5e\", \"#f97316\", \"#eab308\", \"#22c55e\", \"#06b6d4\", \"#8b5cf6\"];\nconst paintWidth = 4;\nconst paintSendIntervalMs = 24;\nconst maximumPaintPoints = 2_048;\nconst maximumPaintStrokes = 512;\n\ninterface PaintStroke {\n clientId: string;\n targetId: string;\n color: string;\n width: number;\n points: ReadonlyArray<{ x: number; y: number }>;\n updatedAt: number;\n ended: boolean;\n}\n\nexport function CollaborationPaintOverlay({\n collaboration,\n targetId,\n enabled,\n visible,\n left,\n top,\n width,\n height,\n}: CollaborationPaintOverlayProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const activeStrokeIdRef = useRef<string | null>(null);\n const activePointerIdRef = useRef<number | null>(null);\n const lastPointSentAtRef = useRef(0);\n const strokesRef = useRef(new Map<string, PaintStroke>());\n const color = colorForClient(collaboration.clientId);\n\n useFork(() => {\n const canvas = canvasRef.current;\n if (!canvas) {\n return;\n }\n const pixelRatio = window.devicePixelRatio || 1;\n canvas.width = Math.max(1, Math.round(width * pixelRatio));\n canvas.height = Math.max(1, Math.round(height * pixelRatio));\n\n const context = canvas.getContext(\"2d\");\n if (!context) {\n return;\n }\n\n let animationFrame: number | null = null;\n const participantIds = new Set(\n collaboration.participants.map((participant) => participant.clientId),\n );\n const disconnectedAt = Date.now();\n for (const [key, stroke] of strokesRef.current) {\n if (!stroke.ended && !participantIds.has(stroke.clientId)) {\n strokesRef.current.set(key, { ...stroke, updatedAt: disconnectedAt, ended: true });\n }\n }\n const draw = () => {\n animationFrame = null;\n context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);\n context.clearRect(0, 0, width, height);\n const now = Date.now();\n let fadingStrokeCount = 0;\n\n for (const [key, stroke] of strokesRef.current) {\n const age = now - stroke.updatedAt;\n if (stroke.ended && age >= collaborationPaintLifetimeMs) {\n strokesRef.current.delete(key);\n continue;\n }\n if (stroke.ended) {\n fadingStrokeCount += 1;\n }\n if (stroke.targetId !== targetId || stroke.points.length === 0) {\n continue;\n }\n const opacity = stroke.ended ? 1 - age / collaborationPaintLifetimeMs : 1;\n context.globalAlpha = opacity;\n context.strokeStyle = stroke.color;\n context.fillStyle = stroke.color;\n context.lineWidth = stroke.width;\n context.lineCap = \"round\";\n context.lineJoin = \"round\";\n\n const first = stroke.points[0];\n if (!first) {\n continue;\n }\n if (stroke.points.length === 1) {\n context.beginPath();\n context.arc(first.x * width, first.y * height, stroke.width / 2, 0, Math.PI * 2);\n context.fill();\n continue;\n }\n context.beginPath();\n context.moveTo(first.x * width, first.y * height);\n for (let index = 1; index < stroke.points.length - 1; index += 1) {\n const point = stroke.points[index];\n const next = stroke.points[index + 1];\n if (!point || !next) {\n continue;\n }\n context.quadraticCurveTo(\n point.x * width,\n point.y * height,\n ((point.x + next.x) / 2) * width,\n ((point.y + next.y) / 2) * height,\n );\n }\n const last = stroke.points[stroke.points.length - 1];\n if (last) {\n context.lineTo(last.x * width, last.y * height);\n }\n context.stroke();\n }\n context.globalAlpha = 1;\n if (fadingStrokeCount > 0) {\n animationFrame = window.requestAnimationFrame(draw);\n }\n };\n\n const requestDraw = () => {\n if (animationFrame === null) {\n animationFrame = window.requestAnimationFrame(draw);\n }\n };\n\n const onPaint = (event: CollaborationPaintEvent) => {\n if (event.type === \"clear\") {\n strokesRef.current.clear();\n requestDraw();\n return;\n }\n const message = event.message;\n const key = `${message.clientId}:${message.targetId}:${message.strokeId}`;\n const existing = strokesRef.current.get(key);\n if (\n (message.phase !== \"start\" && !existing) ||\n (existing?.ended && message.phase !== \"start\")\n ) {\n return;\n }\n const updatedAt = Date.now();\n if (message.phase === \"start\") {\n for (const [candidateKey, stroke] of strokesRef.current) {\n if (!stroke.ended && stroke.clientId === message.clientId) {\n strokesRef.current.set(candidateKey, { ...stroke, updatedAt, ended: true });\n }\n }\n }\n let points =\n message.phase === \"start\" || !existing\n ? [{ x: message.x, y: message.y }]\n : [...existing.points, { x: message.x, y: message.y }];\n if (points.length > maximumPaintPoints) {\n points = points.filter((_, index) => index % 2 === 0);\n }\n if (!existing && strokesRef.current.size >= maximumPaintStrokes) {\n let oldestKey: string | null = null;\n let oldestUpdatedAt = Number.POSITIVE_INFINITY;\n for (const [candidateKey, stroke] of strokesRef.current) {\n if (!stroke.ended) {\n continue;\n }\n if (stroke.updatedAt < oldestUpdatedAt) {\n oldestKey = candidateKey;\n oldestUpdatedAt = stroke.updatedAt;\n }\n }\n if (oldestKey) {\n strokesRef.current.delete(oldestKey);\n }\n }\n strokesRef.current.set(key, {\n clientId: message.clientId,\n targetId: message.targetId,\n color: message.color,\n width: message.width,\n points,\n updatedAt,\n ended: message.phase === \"end\",\n });\n requestDraw();\n };\n\n draw();\n return Stream.runForEach(collaboration.paintEvents, (event) =>\n Effect.sync(() => onPaint(event)),\n ).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n if (animationFrame !== null) {\n window.cancelAnimationFrame(animationFrame);\n }\n }),\n ),\n );\n }, [collaboration.paintEvents, collaboration.participants, height, targetId, width]);\n\n useEffect(() => {\n activeStrokeIdRef.current = null;\n activePointerIdRef.current = null;\n }, [enabled, targetId]);\n\n function sendPoint(\n event: ReactPointerEvent<HTMLCanvasElement>,\n phase: CollaborationPaintPoint[\"phase\"],\n ) {\n const strokeId = activeStrokeIdRef.current;\n const point = normalizedPointer(event);\n if (!strokeId || !point) {\n return;\n }\n collaboration.sendPaintPoint({\n targetId,\n strokeId,\n color,\n width: paintWidth,\n phase,\n x: point.x,\n y: point.y,\n });\n }\n\n function handlePointerDown(event: ReactPointerEvent<HTMLCanvasElement>) {\n stopPointerEvent(event);\n if (!event.isPrimary || event.button !== 0 || activePointerIdRef.current !== null) {\n return;\n }\n event.currentTarget.focus();\n activeStrokeIdRef.current = crypto.randomUUID();\n activePointerIdRef.current = event.pointerId;\n lastPointSentAtRef.current = performance.now();\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Synthetic pointer events do not always create a capturable pointer.\n }\n const point = normalizedPointer(event);\n if (point) {\n collaboration.sendCursor(targetId, point.x * width, point.y * height, { width, height });\n }\n sendPoint(event, \"start\");\n }\n\n function handlePointerMove(event: ReactPointerEvent<HTMLCanvasElement>) {\n stopPointerEvent(event);\n if (activePointerIdRef.current !== null && event.pointerId !== activePointerIdRef.current) {\n return;\n }\n const point = normalizedPointer(event);\n if (point) {\n collaboration.sendCursor(targetId, point.x * width, point.y * height, { width, height });\n }\n if (\n !activeStrokeIdRef.current ||\n performance.now() - lastPointSentAtRef.current < paintSendIntervalMs\n ) {\n return;\n }\n lastPointSentAtRef.current = performance.now();\n sendPoint(event, \"move\");\n }\n\n function finishStroke(event: ReactPointerEvent<HTMLCanvasElement>) {\n stopPointerEvent(event);\n if (!activeStrokeIdRef.current || activePointerIdRef.current !== event.pointerId) {\n return;\n }\n sendPoint(event, \"end\");\n activeStrokeIdRef.current = null;\n activePointerIdRef.current = null;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n }\n\n return (\n <canvas\n ref={canvasRef}\n tabIndex={-1}\n style={{\n position: \"absolute\",\n zIndex: 20,\n touchAction: \"none\",\n cursor: enabled ? \"crosshair\" : undefined,\n pointerEvents: enabled ? undefined : \"none\",\n visibility: visible ? undefined : \"hidden\",\n left,\n top,\n width,\n height,\n }}\n aria-label=\"Shared drawing overlay\"\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={finishStroke}\n onPointerCancel={finishStroke}\n onWheel={stopPointerEvent}\n onContextMenu={stopPointerEvent}\n />\n );\n}\n\nfunction normalizedPointer(event: ReactPointerEvent<HTMLCanvasElement>) {\n const rect = event.currentTarget.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) {\n return null;\n }\n return {\n x: Math.max(0, Math.min(1, (event.clientX - rect.left) / rect.width)),\n y: Math.max(0, Math.min(1, (event.clientY - rect.top) / rect.height)),\n };\n}\n\nfunction stopPointerEvent(event: { preventDefault: () => void; stopPropagation: () => void }) {\n event.preventDefault();\n event.stopPropagation();\n}\n\nfunction colorForClient(clientId: string) {\n let hash = 0;\n for (const character of clientId) {\n hash = (hash * 31 + character.charCodeAt(0)) >>> 0;\n }\n return paintColors[hash % paintColors.length] ?? \"#f43f5e\";\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport * as Effect from \"effect/Effect\";\nimport * as Stream from \"effect/Stream\";\nimport {\n keyboardInputMessage,\n keyboardModifiers,\n shouldForwardBrowserShortcut,\n} from \"@aperture-browser/live-session\";\nimport { computeRenderMetrics } from \"@aperture-browser/live-session\";\nimport type { LiveSessionRasterFrame } from \"@aperture-browser/live-session\";\nimport type { ViewportPreset } from \"@aperture-browser/live-session\";\nimport type { SessionNotice, UseBrowserControlResult } from \"../hooks/use-browser-control.ts\";\nimport { CollaborationPaintOverlay } from \"./collaboration-paint-overlay.tsx\";\nimport { useFork } from \"../effect.tsx\";\n\nexport interface SessionViewportProps {\n control: UseBrowserControlResult;\n viewport?: ViewportPreset;\n localCursorEnabled?: boolean;\n paintingEnabled?: boolean;\n onPaintingEnabledChange?: (enabled: boolean) => void;\n onNotice?: (notice: SessionNotice) => void;\n className?: string;\n style?: CSSProperties;\n renderOverlay?: (overlay: SessionViewportOverlay) => ReactNode;\n}\n\nexport type SessionViewportStatus = \"webrtc\" | \"websocket\" | \"offline\";\n\nexport type SessionViewportPlaceholder =\n | \"connecting\"\n | \"connecting-media\"\n | \"switching\"\n | \"disconnected\"\n | \"waiting\";\n\nexport interface SessionViewportOverlay {\n readonly status: SessionViewportStatus;\n readonly placeholder: SessionViewportPlaceholder | null;\n readonly cursorHint: { readonly text: string; readonly x: number; readonly y: number } | null;\n readonly followedCursor: {\n readonly name: string;\n readonly x: number;\n readonly y: number;\n } | null;\n readonly collaborationError: string | null;\n}\n\ntype MouseButton = \"left\" | \"middle\" | \"right\" | \"none\";\ninterface ViewportPoint {\n x: number;\n y: number;\n}\ntype FrameMetadata = Pick<LiveSessionRasterFrame, \"width\" | \"height\">;\ninterface RasterFrameDecoder {\n decodingFrame: LiveSessionRasterFrame | null;\n generation: number;\n pending: LiveSessionRasterFrame | null;\n}\ninterface PressedKey {\n targetId: string;\n input: ReturnType<typeof keyboardInputMessage>;\n}\n\nconst MULTI_CLICK_MS = 500;\nconst MULTI_CLICK_DISTANCE = 5;\n\nexport function SessionViewport({\n control,\n viewport = control.viewport,\n localCursorEnabled = true,\n paintingEnabled = false,\n onPaintingEnabledChange,\n onNotice,\n className,\n style,\n renderOverlay,\n}: SessionViewportProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const imageRef = useRef<HTMLImageElement>(null);\n const videoRef = useRef<HTMLVideoElement>(null);\n const rasterDecoderRef = useRef<RasterFrameDecoder>({\n decodingFrame: null,\n generation: 0,\n pending: null,\n });\n const frameMetadataRef = useRef<FrameMetadata | null>(null);\n const pressedKeysRef = useRef(new Map<string, PressedKey>());\n const releasedKeysRef = useRef(new Set<string>());\n const pointerCaptureRef = useRef<{\n pointerId: number;\n targetId: string;\n button: MouseButton;\n clickCount: number;\n } | null>(null);\n const dragCleanupRef = useRef<(() => void) | null>(null);\n const implicitControlDesiredRef = useRef(false);\n const cursorHintPointRef = useRef<ViewportPoint | null>(null);\n const lastClickRef = useRef<{\n targetId: string;\n button: MouseButton;\n point: ViewportPoint;\n time: number;\n clickCount: number;\n } | null>(null);\n const [cursorHintPoint, setCursorHintPoint] = useState<ViewportPoint | null>(null);\n const [frameMetadata, setFrameMetadata] = useState<FrameMetadata | null>(null);\n const [presentedMedia, setPresentedMedia] = useState<{\n stream: MediaStream;\n targetId: string;\n size: NonNullable<UseBrowserControlResult[\"mediaSize\"]>;\n } | null>(null);\n\n const showingWebRTC =\n control.mediaPath === \"webrtc-live\" &&\n control.mediaPhase === \"live\" &&\n Boolean(control.mediaStream) &&\n Boolean(control.activeTargetId);\n const mediaTransitioning =\n showingWebRTC &&\n (control.mediaSwitching ||\n control.mediaTargetId !== control.activeTargetId ||\n presentedMedia?.stream !== control.mediaStream ||\n presentedMedia?.targetId !== control.activeTargetId);\n const paintOverlayEnabled =\n paintingEnabled &&\n (showingWebRTC || frameMetadata !== null) &&\n control.collaboration.phase === \"connected\" &&\n !control.mediaSwitching &&\n !mediaTransitioning;\n const inputDisabled =\n paintingEnabled ||\n control.mediaSwitching ||\n mediaTransitioning ||\n control.collaboration.phase !== \"connected\" ||\n control.collaboration.role === \"viewer\";\n const displayedMediaSize =\n mediaTransitioning && presentedMedia ? presentedMedia.size : control.mediaSize;\n const renderWidth = showingWebRTC\n ? (displayedMediaSize?.width ?? viewport.width)\n : (frameMetadata?.width ?? viewport.width);\n const renderHeight = showingWebRTC\n ? (displayedMediaSize?.height ?? viewport.height)\n : (frameMetadata?.height ?? viewport.height);\n const inputWidth = showingWebRTC ? renderWidth : viewport.width;\n const inputHeight = showingWebRTC ? renderHeight : viewport.height;\n const contentWidth = showingWebRTC\n ? Math.min(\n displayedMediaSize?.canvasWidth ?? renderWidth,\n Math.round(renderWidth * (displayedMediaSize?.deviceScaleFactor ?? 1)),\n )\n : renderWidth;\n const contentHeight = showingWebRTC\n ? Math.min(\n displayedMediaSize?.canvasHeight ?? renderHeight,\n Math.round(renderHeight * (displayedMediaSize?.deviceScaleFactor ?? 1)),\n )\n : renderHeight;\n const displayMetrics = computeRenderMetrics(\n control.browserViewportSize?.width ?? renderWidth,\n control.browserViewportSize?.height ?? renderHeight,\n renderWidth,\n renderHeight,\n );\n const disconnectedHint = resolveDisconnectedHint(control.phase);\n const collaborationHint = resolveCollaborationHint(control.collaboration);\n const cursorHint = disconnectedHint ?? collaborationHint;\n const displayedCursorHintPoint = cursorHint\n ? (cursorHintPointRef.current ?? cursorHintPoint)\n : null;\n const followedParticipant = control.collaboration.followingClientId\n ? control.collaboration.participants.find(\n (participant) => participant.clientId === control.collaboration.followingClientId,\n )\n : null;\n const followedCursor = followedParticipant\n ? control.collaboration.cursors.get(followedParticipant.clientId)\n : null;\n const followedCursorPoint =\n followedCursor?.targetId === control.activeTargetId\n ? {\n x: displayMetrics.offsetX + followedCursor.x * displayMetrics.renderedWidth,\n y: displayMetrics.offsetY + followedCursor.y * displayMetrics.renderedHeight,\n }\n : null;\n\n useEffect(() => {\n control.setInputDimensions({ width: inputWidth, height: inputHeight });\n }, [control.setInputDimensions, inputHeight, inputWidth]);\n\n const releasePressedKeys = useCallback(() => {\n const pressedKeys = [...pressedKeysRef.current.entries()].reverse();\n pressedKeysRef.current.clear();\n\n for (const [keyId, pressedKey] of pressedKeys) {\n const sent = control.sendInput({\n type: \"input.key\",\n targetId: pressedKey.targetId,\n action: \"up\",\n ...pressedKey.input,\n text: undefined,\n modifiers: 0,\n autoRepeat: false,\n });\n if (sent) {\n releasedKeysRef.current.add(keyId);\n }\n }\n }, [control.sendInput]);\n\n useFork(() => {\n const onFrame = (frame: LiveSessionRasterFrame | null) => {\n if (!frame) {\n if (imageRef.current) {\n resetImageFrames(imageRef.current, rasterDecoderRef.current);\n } else {\n resetRasterFrameDecoder(rasterDecoderRef.current);\n }\n if (frameMetadataRef.current !== null) {\n frameMetadataRef.current = null;\n setFrameMetadata(null);\n }\n return;\n }\n if (frame.targetId !== control.activeTargetId) {\n return;\n }\n\n if (imageRef.current && !showingWebRTC) {\n enqueueImageFrame(imageRef.current, rasterDecoderRef.current, frame);\n } else {\n rasterDecoderRef.current.pending = frame;\n }\n const currentMetadata = frameMetadataRef.current;\n if (currentMetadata?.width !== frame.width || currentMetadata?.height !== frame.height) {\n const nextMetadata = { width: frame.width, height: frame.height };\n frameMetadataRef.current = nextMetadata;\n setFrameMetadata(nextMetadata);\n }\n };\n return Stream.runForEach(control.frames, (frame) => Effect.sync(() => onFrame(frame))).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n if (imageRef.current) {\n resetImageFrames(imageRef.current, rasterDecoderRef.current);\n } else {\n resetRasterFrameDecoder(rasterDecoderRef.current);\n }\n }),\n ),\n );\n }, [control.activeTargetId, control.frames, showingWebRTC]);\n\n useLayoutEffect(() => {\n const decoder = rasterDecoderRef.current;\n const targetId = control.activeTargetId;\n const targetFrame =\n decoder.pending?.targetId === targetId\n ? decoder.pending\n : decoder.decodingFrame?.targetId === targetId\n ? decoder.decodingFrame\n : null;\n const image = imageRef.current;\n if (image) {\n resetImageFrames(image, decoder);\n } else {\n resetRasterFrameDecoder(decoder);\n }\n if (targetFrame) {\n decoder.pending = targetFrame;\n const nextMetadata = { width: targetFrame.width, height: targetFrame.height };\n frameMetadataRef.current = nextMetadata;\n setFrameMetadata(nextMetadata);\n if (image) {\n decodeNextImageFrame(image, decoder);\n }\n } else if (frameMetadataRef.current !== null) {\n frameMetadataRef.current = null;\n setFrameMetadata(null);\n }\n }, [control.activeTargetId]);\n\n useEffect(() => {\n const image = imageRef.current;\n if (showingWebRTC || !image) {\n return;\n }\n decodeNextImageFrame(image, rasterDecoderRef.current);\n }, [frameMetadata, showingWebRTC]);\n\n useEffect(() => {\n if (!videoRef.current) {\n return;\n }\n videoRef.current.srcObject = showingWebRTC ? control.mediaStream : null;\n }, [control.mediaStream, showingWebRTC]);\n\n useEffect(() => {\n const video = videoRef.current;\n const stream = control.mediaStream;\n const targetId = control.activeTargetId;\n const size = control.mediaSize;\n if (\n !showingWebRTC ||\n !video ||\n !stream ||\n !targetId ||\n !size ||\n control.mediaSwitching ||\n control.mediaTargetId !== targetId ||\n (presentedMedia?.stream === stream && presentedMedia.targetId === targetId)\n ) {\n return;\n }\n const callback = video.requestVideoFrameCallback(() => {\n setPresentedMedia({ stream, targetId, size });\n });\n return () => video.cancelVideoFrameCallback(callback);\n }, [\n control.activeTargetId,\n control.mediaSize,\n control.mediaStream,\n control.mediaSwitching,\n control.mediaTargetId,\n presentedMedia,\n showingWebRTC,\n ]);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) {\n return;\n }\n\n const syncSize = (width: number, height: number) => {\n control.setBrowserViewportSize({ width, height });\n };\n\n const rect = element.getBoundingClientRect();\n syncSize(rect.width, rect.height);\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) {\n syncSize(entry.contentRect.width, entry.contentRect.height);\n }\n });\n observer.observe(element);\n\n return () => observer.disconnect();\n }, [control.setBrowserViewportSize]);\n\n useEffect(() => {\n return () => {\n dragCleanupRef.current?.();\n releasePressedKeys();\n };\n }, [releasePressedKeys]);\n\n useEffect(() => {\n const handleWindowBlur = () => {\n releasePressedKeys();\n releaseImplicitControl();\n };\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n releasePressedKeys();\n releaseImplicitControl();\n }\n };\n\n window.addEventListener(\"blur\", handleWindowBlur);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n window.removeEventListener(\"blur\", handleWindowBlur);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [releasePressedKeys, control.collaboration]);\n\n useEffect(() => {\n if (inputDisabled) {\n dragCleanupRef.current?.();\n releasePressedKeys();\n releaseImplicitControl();\n }\n }, [inputDisabled, releasePressedKeys]);\n\n useEffect(() => {\n if (paintingEnabled) {\n control.setCaptured(false);\n implicitControlDesiredRef.current = false;\n }\n if (\n control.collaboration.hasControl &&\n control.collaboration.leaseMode === \"implicit\" &&\n !implicitControlDesiredRef.current\n ) {\n control.collaboration.release();\n }\n }, [\n control.collaboration.hasControl,\n control.collaboration.leaseMode,\n control.collaboration.release,\n control.setCaptured,\n paintingEnabled,\n ]);\n\n function mapPointer(event: { clientX: number; clientY: number }, clamp: boolean) {\n const rect = containerRef.current?.getBoundingClientRect();\n if (!rect) {\n return null;\n }\n const metrics = computeRenderMetrics(rect.width, rect.height, renderWidth, renderHeight);\n const localX = event.clientX - rect.left - metrics.offsetX;\n const localY = event.clientY - rect.top - metrics.offsetY;\n if (\n !clamp &&\n (localX < 0 ||\n localY < 0 ||\n localX > metrics.renderedWidth ||\n localY > metrics.renderedHeight)\n ) {\n return null;\n }\n const x = (localX / metrics.scale) * (inputWidth / renderWidth);\n const y = (localY / metrics.scale) * (inputHeight / renderHeight);\n if (clamp) {\n return {\n x: Math.round(clampNumber(x, 0, Math.max(inputWidth - 1, 0))),\n y: Math.round(clampNumber(y, 0, Math.max(inputHeight - 1, 0))),\n };\n }\n return { x: Math.round(x), y: Math.round(y) };\n }\n\n function resolveInputTarget() {\n if (control.phase !== \"connected\" || !control.activeTargetId || inputDisabled) {\n return null;\n }\n if (!control.captured) {\n control.setCaptured(true);\n }\n requestImplicitControl(control.activeTargetId);\n containerRef.current?.focus();\n return control.activeTargetId;\n }\n\n function requestImplicitControl(targetId: string) {\n implicitControlDesiredRef.current = true;\n if (!control.collaboration.hasControl) {\n control.collaboration.claim(targetId, \"implicit\");\n }\n }\n\n function releaseImplicitControl() {\n implicitControlDesiredRef.current = false;\n if (control.collaboration.hasControl && control.collaboration.leaseMode === \"implicit\") {\n control.collaboration.release();\n }\n }\n\n function preventViewportDefault(event: React.SyntheticEvent) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n function preventNativeDefault(event: PointerEvent) {\n if (event.cancelable) {\n event.preventDefault();\n }\n event.stopPropagation();\n }\n\n function handleCaptureClick() {\n if (control.phase !== \"connected\" || inputDisabled) {\n return;\n }\n control.setCaptured(true);\n if (control.activeTargetId) {\n requestImplicitControl(control.activeTargetId);\n }\n containerRef.current?.focus();\n }\n\n function handlePointerEnter(event: React.PointerEvent) {\n updateCursorHint(event);\n if (inputDisabled || !control.activeTargetId) {\n return;\n }\n control.setCaptured(true);\n requestImplicitControl(control.activeTargetId);\n }\n\n function handlePointerLeave() {\n cursorHintPointRef.current = null;\n setCursorHintPoint(null);\n control.collaboration.clearCursor();\n if (!pointerCaptureRef.current) {\n releasePressedKeys();\n releaseImplicitControl();\n control.setCaptured(false);\n }\n }\n\n function handlePointerClick() {\n if (!control.captured) {\n handleCaptureClick();\n }\n }\n\n function handlePointerMove(event: React.PointerEvent) {\n updateCursorHint(event);\n\n const point = mapPointer(event, false);\n if (control.activeTargetId && point) {\n control.collaboration.sendCursor(control.activeTargetId, point.x, point.y, {\n width: inputWidth,\n height: inputHeight,\n });\n } else if (!point) {\n control.collaboration.clearCursor();\n }\n\n if (inputDisabled) {\n return;\n }\n\n const capturedPointer = pointerCaptureRef.current;\n if (capturedPointer?.pointerId === event.pointerId) {\n return;\n }\n const targetId = control.captured && event.buttons === 0 ? control.activeTargetId : null;\n if (!targetId) {\n return;\n }\n if (!point) {\n return;\n }\n preventViewportDefault(event);\n control.sendInput({\n type: \"input.mouse\",\n targetId,\n action: \"move\",\n x: point.x,\n y: point.y,\n button: \"none\",\n buttons: 0,\n clickCount: 0,\n modifiers: keyboardModifiers(event.nativeEvent),\n });\n }\n\n function handlePointerDown(event: React.PointerEvent) {\n updateCursorHint(event);\n\n const targetId = resolveInputTarget();\n if (!targetId) {\n return;\n }\n const point = mapPointer(event, false);\n if (!point) {\n return;\n }\n const element = containerRef.current;\n if (!element) {\n return;\n }\n const button = resolveMouseButton(event.button);\n const now = Date.now();\n const clickCount = resolveClickCount(targetId, button, point, now, lastClickRef.current);\n lastClickRef.current = {\n targetId,\n button,\n point,\n time: now,\n clickCount,\n };\n preventViewportDefault(event);\n pointerCaptureRef.current = { pointerId: event.pointerId, targetId, button, clickCount };\n dragCleanupRef.current?.();\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Synthetic pointer events and some browser edge cases do not create a capturable pointer.\n }\n bindDragListeners({\n pointerId: event.pointerId,\n targetId,\n button,\n clickCount,\n element,\n });\n control.sendInput({\n type: \"input.mouse\",\n targetId,\n action: \"down\",\n x: point.x,\n y: point.y,\n button,\n buttons: event.buttons,\n clickCount,\n modifiers: keyboardModifiers(event.nativeEvent),\n });\n }\n\n function handlePointerUp(event: React.PointerEvent) {\n if (inputDisabled) {\n return;\n }\n const capturedPointer = pointerCaptureRef.current;\n const targetId =\n capturedPointer?.pointerId === event.pointerId\n ? capturedPointer.targetId\n : control.activeTargetId;\n if (!targetId) {\n return;\n }\n const point = mapPointer(event, capturedPointer?.pointerId === event.pointerId);\n if (!point) {\n return;\n }\n preventViewportDefault(event);\n control.sendInput({\n type: \"input.mouse\",\n targetId,\n action: \"up\",\n x: point.x,\n y: point.y,\n button: capturedPointer?.button ?? resolveMouseButton(event.button),\n buttons: event.buttons,\n clickCount: capturedPointer?.clickCount ?? 1,\n modifiers: keyboardModifiers(event.nativeEvent),\n });\n if (capturedPointer?.pointerId === event.pointerId) {\n pointerCaptureRef.current = null;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n }\n }\n\n function handlePointerCancel(event: React.PointerEvent) {\n const capturedPointer = pointerCaptureRef.current;\n if (capturedPointer?.pointerId !== event.pointerId) {\n return;\n }\n const point = mapPointer(event, true);\n pointerCaptureRef.current = null;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n if (!point || inputDisabled) {\n return;\n }\n preventViewportDefault(event);\n control.sendInput({\n type: \"input.mouse\",\n targetId: capturedPointer.targetId,\n action: \"up\",\n x: point.x,\n y: point.y,\n button: capturedPointer.button,\n buttons: 0,\n clickCount: capturedPointer.clickCount,\n modifiers: keyboardModifiers(event.nativeEvent),\n });\n }\n\n function bindDragListeners({\n pointerId,\n targetId,\n button,\n clickCount,\n element,\n }: {\n pointerId: number;\n targetId: string;\n button: MouseButton;\n clickCount: number;\n element: HTMLDivElement;\n }) {\n const handleMove = (event: PointerEvent) => {\n if (event.pointerId !== pointerId) {\n return;\n }\n const point = mapPointer(event, true);\n preventNativeDefault(event);\n if (!point) {\n return;\n }\n control.collaboration.sendCursor(targetId, point.x, point.y, {\n width: inputWidth,\n height: inputHeight,\n });\n control.sendInput({\n type: \"input.mouse\",\n targetId,\n action: \"move\",\n x: point.x,\n y: point.y,\n button,\n buttons: event.buttons || mouseButtonsForButton(button),\n clickCount,\n modifiers: keyboardModifiers(event),\n });\n };\n\n const finish = (event: PointerEvent, canceled: boolean) => {\n if (event.pointerId !== pointerId) {\n return;\n }\n const point = mapPointer(event, true);\n if (!mapPointer(event, false)) {\n control.collaboration.clearCursor();\n }\n preventNativeDefault(event);\n if (point) {\n control.sendInput({\n type: \"input.mouse\",\n targetId,\n action: \"up\",\n x: point.x,\n y: point.y,\n button,\n buttons: 0,\n clickCount,\n modifiers: keyboardModifiers(event),\n });\n if (!canceled) {\n lastClickRef.current = {\n targetId,\n button,\n point,\n time: Date.now(),\n clickCount,\n };\n }\n }\n cleanup();\n };\n\n const handleUp = (event: PointerEvent) => finish(event, false);\n const handleCancel = (event: PointerEvent) => finish(event, true);\n const cleanup = () => {\n window.removeEventListener(\"pointermove\", handleMove, true);\n window.removeEventListener(\"pointerup\", handleUp, true);\n window.removeEventListener(\"pointercancel\", handleCancel, true);\n try {\n if (element.hasPointerCapture(pointerId)) {\n element.releasePointerCapture(pointerId);\n }\n } catch {\n // Synthetic pointer events and released native pointers may not have active capture.\n }\n if (pointerCaptureRef.current?.pointerId === pointerId) {\n pointerCaptureRef.current = null;\n }\n if (dragCleanupRef.current === cleanup) {\n dragCleanupRef.current = null;\n }\n };\n\n dragCleanupRef.current = cleanup;\n window.addEventListener(\"pointermove\", handleMove, true);\n window.addEventListener(\"pointerup\", handleUp, true);\n window.addEventListener(\"pointercancel\", handleCancel, true);\n }\n\n function handleWheel(event: React.WheelEvent) {\n const targetId = resolveInputTarget();\n if (!targetId) {\n return;\n }\n const point = mapPointer(event, false);\n if (!point) {\n return;\n }\n preventViewportDefault(event);\n const wheelScale = wheelDeltaScale(event.deltaMode, inputHeight);\n control.sendInput({\n type: \"input.wheel\",\n targetId,\n x: point.x,\n y: point.y,\n deltaX: event.deltaX * wheelScale,\n deltaY: event.deltaY * wheelScale,\n modifiers: keyboardModifiers(event.nativeEvent),\n });\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n if (event.key === \"Escape\" && paintingEnabled) {\n event.preventDefault();\n event.stopPropagation();\n onPaintingEnabledChange?.(false);\n return;\n }\n if (event.key === \"Escape\") {\n if (control.captured) {\n event.preventDefault();\n event.stopPropagation();\n control.setCaptured(false);\n releaseImplicitControl();\n }\n return;\n }\n const keyId = event.code || event.key;\n if (event.repeat && releasedKeysRef.current.has(keyId)) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n const targetId = control.activeTargetId;\n if (\n inputDisabled ||\n !targetId ||\n (!control.captured &&\n focusedElement(containerRef.current) !== containerRef.current &&\n !containerRef.current?.contains(event.target as Node))\n ) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const clipboardShortcut = resolveClipboardShortcut(event.nativeEvent);\n if (clipboardShortcut === \"copy\") {\n control.sendInput({ type: \"clipboard.copy\", targetId });\n return;\n }\n if (clipboardShortcut === \"cut\") {\n control.sendInput({ type: \"clipboard.cut\", targetId });\n return;\n }\n if (clipboardShortcut === \"paste\") {\n void pasteClipboard(control, onNotice);\n return;\n }\n\n if (!shouldForwardBrowserShortcut(event.nativeEvent)) {\n return;\n }\n\n const input = keyboardInputMessage(event.nativeEvent, \"down\");\n const sent = control.sendInput({\n type: \"input.key\",\n targetId,\n action: \"down\",\n ...input,\n });\n if (sent) {\n releasedKeysRef.current.delete(keyId);\n pressedKeysRef.current.set(keyId, { targetId, input });\n }\n }\n\n function handleKeyUp(event: React.KeyboardEvent) {\n const keyId = event.code || event.key;\n if (releasedKeysRef.current.delete(keyId)) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n const pressedKey = pressedKeysRef.current.get(keyId);\n const targetId = pressedKey?.targetId ?? control.activeTargetId;\n const canForwardUntrackedKey =\n !inputDisabled &&\n (control.captured ||\n focusedElement(containerRef.current) === containerRef.current ||\n Boolean(containerRef.current?.contains(event.target as Node)));\n if (!targetId || (!pressedKey && !canForwardUntrackedKey)) {\n return;\n }\n if (event.key === \"Escape\") {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n if (!pressedKey && resolveClipboardShortcut(event.nativeEvent)) {\n return;\n }\n\n if (!pressedKey && !shouldForwardBrowserShortcut(event.nativeEvent)) {\n return;\n }\n\n const sent = control.sendInput({\n type: \"input.key\",\n targetId,\n action: \"up\",\n ...keyboardInputMessage(event.nativeEvent, \"up\"),\n });\n if (sent) {\n pressedKeysRef.current.delete(keyId);\n }\n }\n\n function handleBlur(event: React.FocusEvent<HTMLDivElement>) {\n if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) {\n return;\n }\n releasePressedKeys();\n releaseImplicitControl();\n control.setCaptured(false);\n }\n\n function updateCursorHint(event: React.PointerEvent) {\n const rect = containerRef.current?.getBoundingClientRect();\n if (!rect) {\n return;\n }\n const point = {\n x: event.clientX - rect.left,\n y: event.clientY - rect.top,\n };\n cursorHintPointRef.current = point;\n if (cursorHint) {\n setCursorHintPoint(point);\n }\n }\n\n const status = resolveViewportStatus(\n control.phase,\n frameMetadata !== null,\n control.mediaPhase,\n control.mediaPath,\n showingWebRTC,\n );\n const placeholder = resolveViewportPlaceholder(\n control.phase,\n control.mediaPhase,\n control.mediaSwitching,\n );\n const visibleCollaborationError =\n collaborationHint || isInputOwnershipError(control.collaboration.lastError)\n ? null\n : control.collaboration.lastError;\n\n return (\n <div\n ref={containerRef}\n tabIndex={0}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onBlur={handleBlur}\n onClick={handlePointerClick}\n onPointerMove={handlePointerMove}\n onFocus={() => {\n if (!inputDisabled && control.activeTargetId) {\n requestImplicitControl(control.activeTargetId);\n }\n }}\n onPointerEnter={handlePointerEnter}\n onPointerLeave={handlePointerLeave}\n onPointerDown={handlePointerDown}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onWheel={handleWheel}\n onContextMenu={(event) => {\n if (control.captured) {\n event.preventDefault();\n }\n }}\n aria-busy={mediaTransitioning}\n aria-disabled={inputDisabled}\n className={className}\n style={{\n position: \"relative\",\n display: \"flex\",\n flex: \"1 1 0%\",\n minHeight: 0,\n alignItems: \"center\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n outline: \"none\",\n touchAction: \"none\",\n cursor: localCursorEnabled ? undefined : \"none\",\n ...style,\n }}\n >\n {showingWebRTC ? (\n <div\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n background: \"black\",\n transition: \"opacity 150ms\",\n opacity: mediaTransitioning ? 0.75 : 1,\n width: displayMetrics.renderedWidth,\n height: displayMetrics.renderedHeight,\n }}\n >\n <video\n ref={videoRef}\n autoPlay\n muted\n playsInline\n data-viewport-width={renderWidth}\n data-viewport-height={renderHeight}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n maxWidth: \"none\",\n objectFit: \"fill\",\n width:\n displayMetrics.renderedWidth *\n ((displayedMediaSize?.canvasWidth ?? contentWidth) / contentWidth),\n height:\n displayMetrics.renderedHeight *\n ((displayedMediaSize?.canvasHeight ?? contentHeight) / contentHeight),\n }}\n />\n </div>\n ) : frameMetadata ? (\n <div\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n background: \"black\",\n width: displayMetrics.renderedWidth,\n height: displayMetrics.renderedHeight,\n }}\n >\n <img\n ref={imageRef}\n alt=\"\"\n draggable={false}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n }}\n />\n </div>\n ) : null}\n {control.activeTargetId ? (\n <CollaborationPaintOverlay\n collaboration={control.collaboration}\n targetId={control.activeTargetId}\n enabled={paintOverlayEnabled}\n visible={\n !control.mediaSwitching &&\n !mediaTransitioning &&\n (showingWebRTC || frameMetadata !== null)\n }\n left={displayMetrics.offsetX}\n top={displayMetrics.offsetY}\n width={displayMetrics.renderedWidth}\n height={displayMetrics.renderedHeight}\n />\n ) : null}\n {renderOverlay?.({\n status,\n placeholder: showingWebRTC || frameMetadata ? null : placeholder,\n cursorHint:\n cursorHint && displayedCursorHintPoint\n ? { text: cursorHint, ...displayedCursorHintPoint }\n : null,\n followedCursor:\n followedCursorPoint && followedParticipant\n ? { name: followedParticipant.name, ...followedCursorPoint }\n : null,\n collaborationError: visibleCollaborationError?.message ?? null,\n })}\n </div>\n );\n}\n\nfunction resolveDisconnectedHint(phase: UseBrowserControlResult[\"phase\"]): string | null {\n if (phase === \"disconnected\" || phase === \"error\") {\n return \"Session disconnected\";\n }\n return null;\n}\n\nfunction resolveCollaborationHint(\n collaboration: UseBrowserControlResult[\"collaboration\"],\n): string | null {\n if (\n collaboration.holderClientId !== null &&\n collaboration.holderClientId !== collaboration.clientId\n ) {\n return \"Input in use\";\n }\n if (collaboration.hasControl) {\n return null;\n }\n if (\n collaboration.lastError?.code === \"input_busy\" ||\n collaboration.lastError?.code === \"input_not_owned\"\n ) {\n return \"Input in use\";\n }\n if (collaboration.lastError?.code === \"input_unavailable\") {\n return \"Input unavailable\";\n }\n return null;\n}\n\nfunction isInputOwnershipError(error: UseBrowserControlResult[\"collaboration\"][\"lastError\"]) {\n return error?.code === \"input_busy\" || error?.code === \"input_not_owned\";\n}\n\nfunction enqueueImageFrame(\n image: HTMLImageElement,\n decoder: RasterFrameDecoder,\n frame: LiveSessionRasterFrame,\n): void {\n decoder.pending = frame;\n decodeNextImageFrame(image, decoder);\n}\n\nfunction decodeNextImageFrame(image: HTMLImageElement, decoder: RasterFrameDecoder): void {\n if (decoder.decodingFrame !== null || decoder.pending === null) {\n return;\n }\n const frame = decoder.pending;\n const generation = decoder.generation;\n decoder.pending = null;\n decoder.decodingFrame = frame;\n void setImageFrame(image, frame).then(() => {\n if (decoder.generation !== generation) {\n return;\n }\n decoder.decodingFrame = null;\n decodeNextImageFrame(image, decoder);\n });\n}\n\nasync function setImageFrame(\n image: HTMLImageElement,\n frame: LiveSessionRasterFrame,\n): Promise<void> {\n const previousSource = image.src;\n const source = URL.createObjectURL(frame.data);\n image.src = source;\n try {\n await image.decode();\n } catch {\n // A newer transport or target may replace the image while decoding.\n } finally {\n if (previousSource.startsWith(\"blob:\")) {\n URL.revokeObjectURL(previousSource);\n }\n if (image.src !== source) {\n URL.revokeObjectURL(source);\n }\n }\n}\n\nfunction resetImageFrames(image: HTMLImageElement, decoder: RasterFrameDecoder): void {\n resetRasterFrameDecoder(decoder);\n const source = image.src;\n image.removeAttribute(\"src\");\n if (source.startsWith(\"blob:\")) {\n URL.revokeObjectURL(source);\n }\n}\n\nfunction resetRasterFrameDecoder(decoder: RasterFrameDecoder): void {\n decoder.generation += 1;\n decoder.decodingFrame = null;\n decoder.pending = null;\n}\n\nfunction resolveViewportPlaceholder(\n phase: UseBrowserControlResult[\"phase\"],\n mediaPhase: UseBrowserControlResult[\"mediaPhase\"],\n switching: boolean,\n): SessionViewportPlaceholder {\n if (phase === \"connecting\") {\n return \"connecting\";\n }\n if (phase === \"connected\" && mediaPhase === \"connecting\") {\n return \"connecting-media\";\n }\n if (phase === \"connected\" && switching) {\n return \"switching\";\n }\n if (phase === \"disconnected\" || phase === \"error\") {\n return \"disconnected\";\n }\n return \"waiting\";\n}\n\nfunction resolveClipboardShortcut(event: KeyboardEvent): \"copy\" | \"cut\" | \"paste\" | null {\n if (!(event.metaKey || event.ctrlKey) || event.altKey) {\n return null;\n }\n\n switch (event.code) {\n case \"KeyC\":\n return \"copy\";\n case \"KeyX\":\n return \"cut\";\n case \"KeyV\":\n return \"paste\";\n default:\n return null;\n }\n}\n\nfunction resolveMouseButton(button: number): MouseButton {\n if (button === 0) {\n return \"left\";\n }\n if (button === 1) {\n return \"middle\";\n }\n if (button === 2) {\n return \"right\";\n }\n return \"none\";\n}\n\nfunction resolveClickCount(\n targetId: string,\n button: MouseButton,\n point: ViewportPoint,\n time: number,\n previous: {\n targetId: string;\n button: MouseButton;\n point: ViewportPoint;\n time: number;\n clickCount: number;\n } | null,\n): number {\n if (\n previous &&\n previous.targetId === targetId &&\n previous.button === button &&\n time - previous.time <= MULTI_CLICK_MS &&\n Math.abs(previous.point.x - point.x) <= MULTI_CLICK_DISTANCE &&\n Math.abs(previous.point.y - point.y) <= MULTI_CLICK_DISTANCE\n ) {\n return Math.min(previous.clickCount + 1, 3);\n }\n return 1;\n}\n\nfunction mouseButtonsForButton(button: MouseButton): number {\n switch (button) {\n case \"left\":\n return 1;\n case \"right\":\n return 2;\n case \"middle\":\n return 4;\n case \"none\":\n return 0;\n default: {\n const exhaustive: never = button;\n return exhaustive;\n }\n }\n}\n\nfunction clampNumber(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction wheelDeltaScale(deltaMode: number, viewportHeight: number): number {\n if (deltaMode === WheelEvent.DOM_DELTA_LINE) {\n return 16;\n }\n if (deltaMode === WheelEvent.DOM_DELTA_PAGE) {\n return viewportHeight;\n }\n return 1;\n}\n\nasync function pasteClipboard(\n control: UseBrowserControlResult,\n onNotice: SessionViewportProps[\"onNotice\"],\n) {\n if (!control.activeTargetId) {\n return;\n }\n\n let text = \"\";\n try {\n text = await navigator.clipboard.readText();\n } catch (error) {\n console.warn(\"Clipboard read failed\", error);\n onNotice?.({ level: \"error\", message: \"Clipboard read failed\" });\n return;\n }\n\n if (!text) {\n return;\n }\n\n control.sendInput({\n type: \"clipboard.paste\",\n targetId: control.activeTargetId,\n items: [{ mimeType: \"text/plain\", data: text }],\n });\n}\n\nfunction resolveViewportStatus(\n phase: UseBrowserControlResult[\"phase\"],\n hasFrame: boolean,\n mediaPhase: UseBrowserControlResult[\"mediaPhase\"],\n mediaPath: UseBrowserControlResult[\"mediaPath\"],\n showingWebRTC: boolean,\n): SessionViewportStatus {\n if (phase !== \"connected\") {\n return \"offline\";\n }\n if (mediaPhase === \"live\" && showingWebRTC) {\n return \"webrtc\";\n }\n if (!hasFrame) {\n return \"offline\";\n }\n return mediaPath === \"websocket-live\" ? \"websocket\" : \"webrtc\";\n}\n\nfunction focusedElement(node: HTMLElement | null): Element | null {\n const root = node?.getRootNode();\n return root instanceof Document || root instanceof ShadowRoot ? root.activeElement : null;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport * as Effect from \"effect/Effect\";\nimport type * as Stream from \"effect/Stream\";\nimport {\n useLiveSession,\n type CollaborationControl,\n type LiveSessionControl,\n type LiveSessionMediaSelection,\n type LiveSessionViewportOwnership,\n} from \"./use-live-session.ts\";\nimport type * as HttpClient from \"effect/http/HttpClient\";\nimport type { ApiRequestError, IceServer } from \"@aperture-browser/api-client\";\nimport type { Recording, RecordingSettings } from \"@aperture-browser/api-client\";\nimport {\n downloadSessionRecording,\n getTargetThumbnail,\n LiveSessionError,\n type BrowserInputMessage,\n} from \"@aperture-browser/live-session\";\nimport type {\n SessionAccess,\n LiveSessionPresentation,\n LiveSessionPresentationQuality,\n LiveSessionRasterFrame,\n LiveSessionTarget,\n} from \"@aperture-browser/live-session\";\nimport {\n createViewportPreset,\n DEFAULT_VIEWPORT,\n type ViewportPreset,\n} from \"@aperture-browser/live-session\";\nimport { useEffectCallback, useRuntime } from \"../effect.tsx\";\n\nexport interface SessionNotice {\n readonly level: \"error\" | \"success\";\n readonly message: string;\n}\n\ninterface UseBrowserControlOptions {\n access: SessionAccess | null;\n displayName?: string | null;\n enabled?: boolean;\n webrtcProducerSupported?: boolean;\n webrtcIceServers?: readonly IceServer[];\n onNotice?: (notice: SessionNotice) => void;\n}\n\ninterface BrowserViewportSize {\n width: number;\n height: number;\n}\n\nexport interface BrowserCommands {\n readonly navigate: (url: string) => Effect.Effect<void, LiveSessionError>;\n readonly historyBack: () => Effect.Effect<void, LiveSessionError>;\n readonly historyForward: () => Effect.Effect<void, LiveSessionError>;\n readonly reload: (targetId?: string) => Effect.Effect<void, LiveSessionError>;\n readonly stopLoading: () => Effect.Effect<void, LiveSessionError>;\n readonly createTarget: (url?: string) => Effect.Effect<string | null, LiveSessionError>;\n readonly closeTarget: (targetId: string) => Effect.Effect<void, LiveSessionError>;\n readonly activateTarget: (targetId: string) => Effect.Effect<void, LiveSessionError>;\n}\n\nexport type BrowserMediaPath = \"webrtc-live\" | \"websocket-live\";\nexport type BrowserMediaPhase = \"idle\" | \"connecting\" | \"live\" | \"failed\";\n\nexport interface UseBrowserControlResult {\n phase: LiveSessionControl[\"phase\"];\n targets: readonly LiveSessionTarget[];\n activeTargetId: string | null;\n activeTarget: LiveSessionTarget | null;\n frames: Stream.Stream<LiveSessionRasterFrame | null>;\n mediaPhase: BrowserMediaPhase;\n mediaStream: MediaStream | null;\n mediaStreamSettings: LiveSessionPresentationQuality | null;\n mediaVideoProfiles: LiveSessionPresentation[\"profiles\"];\n mediaSize: {\n width: number;\n height: number;\n deviceScaleFactor: number;\n canvasWidth: number;\n canvasHeight: number;\n } | null;\n mediaPath: BrowserMediaPath;\n mediaTargetId: string | null;\n mediaSwitching: boolean;\n viewport: ViewportPreset;\n browserViewportSize: BrowserViewportSize | null;\n viewportAutoSync: boolean;\n /** Whether this client's auto-size currently resizes the browser. */\n viewportAutoSizeActive: boolean;\n /** Session-wide auto-size owner, or null when the server does not arbitrate auto-size. */\n viewportOwnership: LiveSessionViewportOwnership | null;\n /** Auto-size preference new session clients start with, persisted in local storage. */\n viewportAutoSizeDefault: boolean;\n captured: boolean;\n recordings: readonly Recording[];\n /** Loads a JPEG preview of one tab, or is null while the session has no access. */\n loadTargetThumbnail:\n | ((targetId: string) => Effect.Effect<Blob, ApiRequestError, HttpClient.HttpClient>)\n | null;\n /** Owners and editors can start, stop, and download recordings. */\n canRecord: boolean;\n recordingBusy: boolean;\n remoteCursorEnabled: boolean;\n /** Whether agent actions are slowed down so this client can follow them. */\n watchableAutomation: boolean;\n collaboration: CollaborationControl;\n commands: BrowserCommands;\n setCaptured: (captured: boolean) => void;\n setInputDimensions: (size: BrowserViewportSize) => void;\n setViewport: (viewport: ViewportPreset) => void;\n setBrowserViewportSize: (size: BrowserViewportSize) => void;\n setViewportAutoSync: (enabled: boolean) => void;\n setViewportToBrowserSize: () => void;\n setViewportAutoSizeDefault: (enabled: boolean) => void;\n takeOverViewport: () => void;\n setWebRTCStreamSettings: (settings: LiveSessionPresentationQuality) => boolean;\n selectMediaStream: (selection: LiveSessionMediaSelection) => boolean;\n sendInput: (message: BrowserInputMessage) => boolean;\n activateTarget: (targetId: string) => void;\n reorderTargets: (\n sourceTargetId: string,\n destinationTargetId: string,\n placement: \"before\" | \"after\",\n ) => void;\n createTarget: (url?: string) => void;\n duplicateTarget: (target: LiveSessionTarget) => void;\n closeTarget: (targetId: string) => void;\n navigate: (url: string) => void;\n reload: (targetId: string) => void;\n stopLoading: () => void;\n historyBack: () => void;\n historyForward: () => void;\n startRecording: (mode: \"tab\" | \"viewer\", settings: RecordingSettings) => void;\n stopRecording: (recordingId: string) => void;\n cancelRecording: (recordingId: string) => void;\n setRemoteCursorEnabled: (enabled: boolean) => void;\n setWatchableAutomation: (enabled: boolean) => void;\n reconnect: () => void;\n}\n\nconst emptyIceServers: readonly IceServer[] = [];\nconst AUTO_SIZE_DEFAULT_STORAGE_KEY = \"aperture.viewport.auto-size-default\";\n\nexport function useBrowserControl({\n access,\n displayName,\n enabled = true,\n webrtcProducerSupported = false,\n webrtcIceServers = emptyIceServers,\n onNotice,\n}: UseBrowserControlOptions): UseBrowserControlResult {\n const runtime = useRuntime();\n const onNoticeRef = useRef(onNotice);\n onNoticeRef.current = onNotice;\n const notify = (level: SessionNotice[\"level\"], message: string) =>\n Effect.sync(() => onNoticeRef.current?.({ level, message }));\n const [viewportAutoSizeDefault, setViewportAutoSizeDefaultState] = useState(loadAutoSizeDefault);\n // The local preference is sent with every hello; the server state wins once it answers.\n const [viewportAutoSync, setViewportAutoSyncState] = useState(() => viewportAutoSizeDefault);\n const viewportAutoSyncRef = useRef(viewportAutoSync);\n viewportAutoSyncRef.current = viewportAutoSync;\n const autoSizePreference = useCallback(() => viewportAutoSyncRef.current, []);\n const live = useLiveSession({\n access,\n displayName,\n enabled: enabled && access !== null,\n webrtcSupported: webrtcProducerSupported,\n iceServers: webrtcIceServers,\n autoSize: autoSizePreference,\n });\n const collaborationRole = live.collaboration.role;\n const [targetOrder, setTargetOrder] = useState<readonly string[]>([]);\n const targets = useMemo(\n () => mergeTargetsInCurrentOrder(targetOrder, live.targets),\n [live.targets, targetOrder],\n );\n const liveTargetsRef = useRef(live.targets);\n liveTargetsRef.current = live.targets;\n const phaseRef = useRef(live.phase);\n phaseRef.current = live.phase;\n const [viewport, setViewportState] = useState<ViewportPreset>(DEFAULT_VIEWPORT);\n const [browserViewportSize, setBrowserViewportSizeState] = useState<BrowserViewportSize | null>(\n null,\n );\n const [captured, setCaptured] = useState(false);\n const [recordingBusy, setRecordingBusy] = useState(false);\n const canRecord = collaborationRole === \"owner\" || collaborationRole === \"editor\";\n const loadTargetThumbnail = useMemo(\n () => (access === null ? null : (targetId: string) => getTargetThumbnail(access, targetId)),\n [access],\n );\n const activeTargetIdRef = useRef<string | null>(null);\n const viewportRef = useRef(viewport);\n const inputDimensionsRef = useRef<BrowserViewportSize>(DEFAULT_VIEWPORT);\n const browserViewportSizeRef = useRef<BrowserViewportSize | null>(null);\n\n activeTargetIdRef.current = live.activeTargetId;\n viewportRef.current = viewport;\n browserViewportSizeRef.current = browserViewportSize;\n\n useEffect(() => {\n if (live.phase !== \"connected\") {\n setCaptured(false);\n }\n }, [live.phase]);\n\n useEffect(() => {\n if (!live.mediaSize) {\n return;\n }\n const current = viewportRef.current;\n if (\n current.width === live.mediaSize.width &&\n current.height === live.mediaSize.height &&\n current.deviceScaleFactor === live.mediaSize.deviceScaleFactor\n ) {\n return;\n }\n setViewportState(createBrowserViewport(live.mediaSize, live.mediaSize.deviceScaleFactor));\n }, [live.mediaSize]);\n\n const sendInput = useCallback(\n (message: BrowserInputMessage): boolean => {\n if (!enabled || access === null) {\n return false;\n }\n return live.sendBrowserInput(message, inputDimensionsRef.current);\n },\n [access, enabled, live],\n );\n\n const activateTarget = useCallback(\n (targetId: string) => {\n live.selectTarget(targetId);\n },\n [live],\n );\n\n const reorderTargets = useCallback(\n (sourceTargetId: string, destinationTargetId: string, placement: \"before\" | \"after\") => {\n if (sourceTargetId === destinationTargetId) {\n return;\n }\n setTargetOrder((order) => {\n const current = mergeTargetsInCurrentOrder(order, liveTargetsRef.current).map(\n (target) => target.id,\n );\n const sourceIndex = current.indexOf(sourceTargetId);\n const destinationIndex = current.indexOf(destinationTargetId);\n const source = current[sourceIndex];\n if (sourceIndex === -1 || destinationIndex === -1 || !source) {\n return order;\n }\n const next = [...current];\n next.splice(sourceIndex, 1);\n const requestedIndex = placement === \"after\" ? destinationIndex + 1 : destinationIndex;\n const nextIndex = sourceIndex < requestedIndex ? requestedIndex - 1 : requestedIndex;\n if (nextIndex === sourceIndex) {\n return order;\n }\n next.splice(nextIndex, 0, source);\n return next;\n });\n },\n [],\n );\n\n const createAndSelectTarget = useCallback(\n (url: string) =>\n runtime.runPromise(\n live.request(\"target.create\", { url }).pipe(\n Effect.map((result) => result.targetId ?? null),\n Effect.catch((error) =>\n notify(\"error\", errorMessage(error, \"Tab could not be created\")).pipe(Effect.as(null)),\n ),\n ),\n ),\n [live, runtime],\n );\n\n const createTarget = useCallback(\n (url = \"about:blank\") => {\n void createAndSelectTarget(url);\n },\n [createAndSelectTarget],\n );\n\n const duplicateTarget = useCallback(\n (target: LiveSessionTarget) => {\n void createAndSelectTarget(target.url || \"about:blank\").then((targetId) => {\n if (targetId) {\n reorderTargets(targetId, target.id, \"after\");\n }\n });\n },\n [createAndSelectTarget, reorderTargets],\n );\n\n const closeTarget = useCallback(\n (targetId: string) => {\n live.command(\"target.close\", { targetId });\n },\n [live],\n );\n\n const navigate = useCallback(\n (url: string) => {\n const targetId = activeTargetIdRef.current;\n if (targetId) {\n live.command(\"page.navigate\", { targetId, url });\n }\n },\n [live],\n );\n\n const reload = useCallback(\n (targetId: string) => {\n live.command(\"page.reload\", { targetId });\n },\n [live],\n );\n\n const stopLoading = useCallback(() => {\n const targetId = activeTargetIdRef.current;\n if (targetId) {\n live.command(\"page.stop-loading\", { targetId });\n }\n }, [live]);\n\n const historyBack = useCallback(() => {\n const targetId = activeTargetIdRef.current;\n if (targetId) {\n live.command(\"page.history-back\", { targetId });\n }\n }, [live]);\n\n const historyForward = useCallback(() => {\n const targetId = activeTargetIdRef.current;\n if (targetId) {\n live.command(\"page.history-forward\", { targetId });\n }\n }, [live]);\n\n const viewportOwnership = live.viewportOwnership;\n const viewportOwnershipRef = useRef(viewportOwnership);\n viewportOwnershipRef.current = viewportOwnership;\n // Without server arbitration every auto-sizing client resizes, as before ownership existed.\n const viewportAutoSizeActive =\n viewportAutoSync &&\n (viewportOwnership === null || viewportOwnership.ownerClientId === live.collaboration.clientId);\n const viewportAutoSizeActiveRef = useRef(viewportAutoSizeActive);\n viewportAutoSizeActiveRef.current = viewportAutoSizeActive;\n\n useEffect(() => {\n if (viewportOwnership !== null) {\n viewportAutoSyncRef.current = viewportOwnership.autoSize;\n setViewportAutoSyncState(viewportOwnership.autoSize);\n }\n }, [viewportOwnership]);\n\n // Ownership can move while a resize is in flight; the next viewport state decides who resizes.\n const runAutoSizeViewport = useEffectCallback(\n (payload: Record<string, unknown>) => live.request(\"viewport.set\", payload).pipe(Effect.ignore),\n [live.request],\n );\n\n const commitViewport = useCallback(\n (preset: ViewportPreset, autoSize: boolean) => {\n setViewportState(preset);\n const targetId = activeTargetIdRef.current;\n if (targetId === null) {\n return;\n }\n const payload = {\n targetId,\n width: preset.width,\n height: preset.height,\n deviceScaleFactor: preset.deviceScaleFactor,\n };\n if (autoSize && viewportOwnershipRef.current !== null) {\n runAutoSizeViewport({ ...payload, autoSize: true });\n } else {\n live.command(\"viewport.set\", payload);\n }\n },\n [live.command, runAutoSizeViewport],\n );\n\n const setViewportAutoSync = useCallback(\n (nextEnabled: boolean) => {\n if (viewportAutoSyncRef.current === nextEnabled) {\n return;\n }\n viewportAutoSyncRef.current = nextEnabled;\n setViewportAutoSyncState(nextEnabled);\n if (viewportOwnershipRef.current !== null) {\n live.command(\"viewport.auto-size.set\", { enabled: nextEnabled });\n }\n },\n [live.command],\n );\n\n useEffect(() => {\n const size = browserViewportSizeRef.current;\n if (\n viewportAutoSizeActive &&\n live.phase === \"connected\" &&\n live.activeTargetId !== null &&\n size !== null\n ) {\n commitViewport(createBrowserViewport(size, viewportRef.current.deviceScaleFactor), true);\n }\n }, [commitViewport, live.activeTargetId, live.phase, viewportAutoSizeActive]);\n\n const setViewport = useCallback(\n (preset: ViewportPreset) => {\n setViewportAutoSync(false);\n commitViewport(preset, false);\n },\n [commitViewport, setViewportAutoSync],\n );\n\n const setBrowserViewportSize = useCallback(\n (size: BrowserViewportSize) => {\n const next = { width: Math.round(size.width), height: Math.round(size.height) };\n if (next.width < 1 || next.height < 1) {\n return;\n }\n const current = browserViewportSizeRef.current;\n if (current?.width === next.width && current.height === next.height) {\n return;\n }\n browserViewportSizeRef.current = next;\n setBrowserViewportSizeState(next);\n if (viewportAutoSizeActiveRef.current) {\n commitViewport(createBrowserViewport(next, viewportRef.current.deviceScaleFactor), true);\n }\n },\n [commitViewport],\n );\n\n const setViewportToBrowserSize = useCallback(() => {\n const size = browserViewportSizeRef.current;\n if (!size) {\n return;\n }\n setViewportAutoSync(false);\n commitViewport(createBrowserViewport(size, viewportRef.current.deviceScaleFactor), false);\n }, [commitViewport, setViewportAutoSync]);\n\n const takeOverViewport = useCallback(() => {\n viewportAutoSyncRef.current = true;\n setViewportAutoSyncState(true);\n live.command(\"viewport.owner.claim\");\n }, [live.command]);\n\n const setViewportAutoSizeDefault = useCallback((nextEnabled: boolean) => {\n setViewportAutoSizeDefaultState(nextEnabled);\n try {\n window.localStorage.setItem(AUTO_SIZE_DEFAULT_STORAGE_KEY, String(nextEnabled));\n } catch {\n // Keep the default for this page when storage is unavailable.\n }\n }, []);\n\n const settleRecording = <A, E extends Error, R>(\n effect: Effect.Effect<A, E, R>,\n failure: string,\n ) =>\n effect.pipe(\n Effect.catch((error) => notify(\"error\", errorMessage(error, failure))),\n Effect.ensuring(Effect.sync(() => setRecordingBusy(false))),\n );\n\n const runStartRecording = useEffectCallback(\n (mode: \"tab\" | \"viewer\", targetId: string, settings: RecordingSettings) =>\n settleRecording(\n live.request(\"recording.start\", { mode, targetId, ...settings }),\n \"Recording failed to start\",\n ),\n [live],\n );\n const startRecording = useCallback(\n (mode: \"tab\" | \"viewer\", settings: RecordingSettings) => {\n const targetId = activeTargetIdRef.current;\n if (!targetId || !canRecord || recordingBusy) {\n return;\n }\n setRecordingBusy(true);\n runStartRecording(mode, targetId, settings);\n },\n [canRecord, recordingBusy, runStartRecording],\n );\n\n const runStopRecording = useEffectCallback(\n (access: SessionAccess, recordingId: string) =>\n settleRecording(\n live.request(\"recording.stop\", { recordingId }).pipe(\n Effect.andThen(downloadSessionRecording(access, recordingId)),\n Effect.flatMap(({ blob, filename }) => {\n const recording = live.recordings.find(\n (candidate) => candidate.recordingId === recordingId,\n );\n return downloadBlob(\n blob,\n filename ??\n `${access.sessionId}-${recording?.targetId ?? \"target\"}-${recordingId}.webm`,\n );\n }),\n Effect.andThen(notify(\"success\", \"Recording saved\")),\n ),\n \"Recording failed to stop\",\n ),\n [live],\n );\n const stopRecording = useCallback(\n (recordingId: string) => {\n if (access === null || recordingBusy) {\n return;\n }\n setRecordingBusy(true);\n runStopRecording(access, recordingId);\n },\n [access, recordingBusy, runStopRecording],\n );\n\n const runCancelRecording = useEffectCallback(\n (recordingId: string) =>\n settleRecording(\n live\n .request(\"recording.cancel\", { recordingId })\n .pipe(Effect.andThen(notify(\"success\", \"Recording stopped\"))),\n \"Recording failed to stop\",\n ),\n [live],\n );\n const cancelRecording = useCallback(\n (recordingId: string) => {\n if (recordingBusy) {\n return;\n }\n setRecordingBusy(true);\n runCancelRecording(recordingId);\n },\n [recordingBusy, runCancelRecording],\n );\n\n const runSetRemoteCursor = useEffectCallback(\n (visible: boolean) =>\n live\n .request(\"presentation.cursor.set\", { visible })\n .pipe(\n Effect.catch((error) =>\n notify(\"error\", errorMessage(error, \"Remote cursor could not be updated\")),\n ),\n ),\n [live],\n );\n const setRemoteCursorEnabled = useCallback(\n (visible: boolean) => {\n if (access !== null) {\n runSetRemoteCursor(visible);\n }\n },\n [access, runSetRemoteCursor],\n );\n\n // Pacing is per session client and ephemeral, so every new connection announces the preference.\n const [watchableAutomation, setWatchableAutomation] = useState(false);\n const commandRef = useRef(live.command);\n commandRef.current = live.command;\n useEffect(() => {\n if (live.phase === \"connected\" && canRecord) {\n commandRef.current(\"automation.pacing.set\", {\n pacing: watchableAutomation ? \"watchable\" : \"normal\",\n });\n }\n }, [live.phase, canRecord, watchableAutomation]);\n\n const runSelectPresentation = useEffectCallback(\n (selection: LiveSessionMediaSelection) =>\n live\n .selectPresentation(selection)\n .pipe(\n Effect.catch((error) =>\n notify(\"error\", errorMessage(error, \"Presentation could not be updated\")),\n ),\n ),\n [live],\n );\n const selectMediaStream = useCallback(\n (selection: LiveSessionMediaSelection) => {\n if (!enabled || access === null || live.mediaSwitching) {\n return false;\n }\n runSelectPresentation(selection);\n return true;\n },\n [access, enabled, live.mediaSwitching, runSelectPresentation],\n );\n\n const setWebRTCStreamSettings = useCallback(\n (settings: LiveSessionPresentationQuality) =>\n selectMediaStream({ kind: \"webrtc\", quality: settings }),\n [selectMediaStream],\n );\n\n const commands = useMemo<BrowserCommands>(() => {\n const connected = <A>(effect: Effect.Effect<A, LiveSessionError>) =>\n Effect.suspend(() =>\n phaseRef.current === \"connected\"\n ? effect\n : Effect.fail(new LiveSessionError({ message: \"the session is not connected\" })),\n );\n const request = (type: string, payload: Record<string, unknown>) =>\n connected(live.request(type, payload));\n const onActiveTarget = (type: string, payload: Record<string, unknown> = {}) =>\n connected(\n Effect.suspend(() => {\n const targetId = activeTargetIdRef.current;\n return targetId\n ? live.request(type, { targetId, ...payload })\n : Effect.fail(new LiveSessionError({ message: \"no tab is active\" }));\n }),\n ).pipe(Effect.asVoid);\n return {\n navigate: (url) => onActiveTarget(\"page.navigate\", { url }),\n historyBack: () => onActiveTarget(\"page.history-back\"),\n historyForward: () => onActiveTarget(\"page.history-forward\"),\n reload: (targetId) =>\n targetId\n ? request(\"page.reload\", { targetId }).pipe(Effect.asVoid)\n : onActiveTarget(\"page.reload\"),\n stopLoading: () => onActiveTarget(\"page.stop-loading\"),\n createTarget: (url = \"about:blank\") =>\n request(\"target.create\", { url }).pipe(Effect.map((result) => result.targetId ?? null)),\n closeTarget: (targetId) => request(\"target.close\", { targetId }).pipe(Effect.asVoid),\n activateTarget: (targetId) => connected(live.requestSelectTarget(targetId)),\n };\n }, [live.request, live.requestSelectTarget]);\n\n const activeTarget = useMemo(\n () => targets.find((target) => target.id === live.activeTargetId) ?? null,\n [live.activeTargetId, targets],\n );\n const mediaPath: BrowserMediaPath =\n live.transport === \"webrtc\" ? \"webrtc-live\" : \"websocket-live\";\n const mediaPhase: BrowserMediaPhase =\n live.phase === \"connected\"\n ? \"live\"\n : live.phase === \"connecting\"\n ? \"connecting\"\n : live.phase === \"error\"\n ? \"failed\"\n : \"idle\";\n\n return {\n phase: live.phase,\n targets,\n activeTargetId: live.activeTargetId,\n activeTarget,\n frames: live.frames,\n mediaPhase,\n mediaStream: live.mediaStream,\n mediaStreamSettings: live.presentation?.quality ?? null,\n mediaVideoProfiles: live.presentation?.profiles ?? [],\n mediaSize: live.mediaSize,\n mediaPath,\n mediaTargetId: live.activeTargetId,\n mediaSwitching: live.mediaSwitching,\n viewport,\n browserViewportSize,\n viewportAutoSync,\n viewportAutoSizeActive,\n viewportOwnership,\n viewportAutoSizeDefault,\n captured,\n recordings: live.recordings,\n canRecord,\n loadTargetThumbnail,\n recordingBusy,\n remoteCursorEnabled: live.presentation?.cursorVisible ?? true,\n watchableAutomation,\n collaboration: live.collaboration,\n commands,\n setCaptured,\n setInputDimensions: (size) => {\n inputDimensionsRef.current = size;\n },\n setViewport,\n setBrowserViewportSize,\n setViewportAutoSync,\n setViewportToBrowserSize,\n setViewportAutoSizeDefault,\n takeOverViewport,\n setWebRTCStreamSettings,\n selectMediaStream,\n sendInput,\n activateTarget,\n reorderTargets,\n createTarget,\n duplicateTarget,\n closeTarget,\n navigate,\n reload,\n stopLoading,\n historyBack,\n historyForward,\n startRecording,\n stopRecording,\n cancelRecording,\n setRemoteCursorEnabled,\n setWatchableAutomation,\n reconnect: live.reconnect,\n };\n}\n\nfunction mergeTargetsInCurrentOrder(\n order: readonly string[],\n nextTargets: readonly LiveSessionTarget[],\n): LiveSessionTarget[] {\n const nextById = new Map(nextTargets.map((target) => [target.id, target]));\n const seen = new Set<string>();\n const ordered: LiveSessionTarget[] = [];\n for (const targetId of order) {\n const nextTarget = nextById.get(targetId);\n if (nextTarget) {\n ordered.push(nextTarget);\n seen.add(nextTarget.id);\n }\n }\n for (const nextTarget of nextTargets) {\n if (!seen.has(nextTarget.id)) {\n ordered.push(nextTarget);\n }\n }\n return ordered;\n}\n\nfunction loadAutoSizeDefault() {\n try {\n return window.localStorage.getItem(AUTO_SIZE_DEFAULT_STORAGE_KEY) === \"true\";\n } catch {\n return false;\n }\n}\n\nfunction createBrowserViewport(\n size: BrowserViewportSize,\n deviceScaleFactor: number,\n): ViewportPreset {\n return createViewportPreset(size.width, size.height, deviceScaleFactor);\n}\n\n// The object URL is released once the browser has started the download.\nconst downloadBlob = (blob: Blob, filename: string) =>\n Effect.acquireUseRelease(\n Effect.sync(() => URL.createObjectURL(blob)),\n (url) =>\n Effect.sync(() => {\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = filename;\n link.click();\n }),\n (url) => Effect.sync(() => URL.revokeObjectURL(url)).pipe(Effect.delay(0)),\n );\n\nfunction errorMessage(cause: unknown, fallback: string): string {\n return cause instanceof Error && cause.message ? cause.message : fallback;\n}\n","import * as Layer from \"effect/Layer\";\nimport * as ManagedRuntime from \"effect/ManagedRuntime\";\nimport * as FetchHttpClient from \"effect/http/FetchHttpClient\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport { apiClientLayer, baseUrlLayer, type ApiServices } from \"@aperture-browser/api-client\";\n\nexport type ApertureRuntime = ManagedRuntime.ManagedRuntime<\n ApiServices | HttpClient.HttpClient,\n never\n>;\n\nexport interface ApertureRuntimeOptions {\n readonly baseUrl?: string;\n}\n\nexport const makeApertureRuntime = (options: ApertureRuntimeOptions = {}): ApertureRuntime =>\n ManagedRuntime.make(\n Layer.mergeAll(\n FetchHttpClient.layer,\n apiClientLayer.pipe(\n Layer.provide(options.baseUrl ? baseUrlLayer(options.baseUrl) : Layer.empty),\n Layer.provide(FetchHttpClient.layer),\n ),\n Layer.succeed(HttpClient.TracerPropagationEnabled, false),\n ),\n );\n","import { useEffect, useState, type ReactNode } from \"react\";\nimport { RuntimeProvider } from \"./effect.tsx\";\nimport { makeApertureRuntime, type ApertureRuntime } from \"./runtime.ts\";\n\nexport interface ApertureProviderProps {\n readonly baseUrl?: string;\n readonly children?: ReactNode;\n}\n\nexport function ApertureProvider({ baseUrl, children }: ApertureProviderProps) {\n const [runtime, setRuntime] = useState<ApertureRuntime | null>(null);\n\n useEffect(() => {\n const created = makeApertureRuntime({ baseUrl });\n setRuntime(created);\n return () => {\n setRuntime(null);\n void created.dispose();\n };\n }, [baseUrl]);\n\n return runtime ? (\n <RuntimeProvider runtime={runtime} baseUrl={baseUrl}>\n {children}\n </RuntimeProvider>\n ) : null;\n}\n","import { useState } from \"react\";\nimport * as Effect from \"effect/Effect\";\nimport * as Redacted from \"effect/Redacted\";\nimport type { BrowserStatus, IceServer } from \"@aperture-browser/api-client\";\nimport { getSessionStatus, type SessionAccess } from \"@aperture-browser/live-session\";\nimport { useFork } from \"./effect.tsx\";\nimport {\n useBrowserControl,\n type SessionNotice,\n type UseBrowserControlResult,\n} from \"./hooks/use-browser-control.ts\";\n\n/** Convert an editor/viewer share link into direct session access. */\nexport function shareSessionAccess(token: string, baseUrl?: string): SessionAccess | null {\n // Share tokens are `ape_` or `apv_`, the 36-character session ID, `_`, and a secret.\n const sessionId = token.slice(4, 40);\n const hasRolePrefix = token.startsWith(\"ape_\") || token.startsWith(\"apv_\");\n if (!hasRolePrefix || token[40] !== \"_\" || token.length <= 41) {\n return null;\n }\n return {\n kind: \"direct\",\n baseUrl,\n sessionId,\n credentials: {\n kind: \"bearer\",\n token: Redacted.make(token),\n authorityType: null,\n tenantId: null,\n selectedTenantId: null,\n },\n };\n}\n\nexport type SessionStatus = \"invalid\" | \"loading\" | \"denied\" | \"expired\" | \"unavailable\" | \"ready\";\n\ninterface SessionState {\n readonly access: SessionAccess | null;\n readonly status: Exclude<SessionStatus, \"invalid\">;\n readonly browser: BrowserStatus | null;\n}\n\nconst emptyIceServers: readonly IceServer[] = [];\n\nfunction failedStatus(httpStatus: number): SessionState[\"status\"] {\n if (httpStatus === 401 || httpStatus === 403) return \"denied\";\n if (httpStatus === 410) return \"expired\";\n return \"unavailable\";\n}\n\nexport interface UseSessionOptions {\n readonly access: SessionAccess | null;\n readonly displayName?: string | null;\n readonly onNotice?: (notice: SessionNotice) => void;\n}\n\nexport interface UseSessionResult {\n readonly status: SessionStatus;\n readonly browser: BrowserStatus | null;\n readonly control: UseBrowserControlResult;\n}\n\nexport function useSession({ access, displayName, onNotice }: UseSessionOptions): UseSessionResult {\n const [state, setState] = useState<SessionState>({\n access: null,\n status: \"loading\",\n browser: null,\n });\n useFork(() => {\n if (access === null) {\n return undefined;\n }\n setState({ access, status: \"loading\", browser: null });\n return getSessionStatus(access).pipe(\n Effect.match({\n onFailure: (error) =>\n setState({ access, status: failedStatus(error.status), browser: null }),\n // A relay may map an app-owned alias to the Aperture session, so only direct IDs must match.\n onSuccess: (browser) =>\n setState(\n access.kind === \"direct\" && browser.sessionId !== access.sessionId\n ? { access, status: \"unavailable\", browser: null }\n : { access, status: \"ready\", browser },\n ),\n }),\n );\n }, [access]);\n const browser = state.access === access ? state.browser : null;\n const control = useBrowserControl({\n access: browser === null ? null : access,\n displayName,\n webrtcProducerSupported: browser?.media.mode === \"auto\" && browser.media.webrtcProducer,\n webrtcIceServers: browser?.media.iceServers ?? emptyIceServers,\n onNotice,\n });\n const status: SessionStatus =\n access === null ? \"invalid\" : state.access !== access ? \"loading\" : state.status;\n return { status, browser, control };\n}\n"],"mappings":"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"}
|
package/dist/headless.d.ts
CHANGED
|
@@ -85,11 +85,11 @@ interface LiveSessionControl {
|
|
|
85
85
|
}
|
|
86
86
|
declare const collaborationPaintLifetimeMs = 7000;
|
|
87
87
|
declare function useLiveSession({
|
|
88
|
-
access,
|
|
88
|
+
access: accessOption,
|
|
89
89
|
displayName,
|
|
90
90
|
enabled,
|
|
91
91
|
webrtcSupported,
|
|
92
|
-
iceServers,
|
|
92
|
+
iceServers: iceServersOption,
|
|
93
93
|
autoSize
|
|
94
94
|
}: UseLiveSessionOptions): LiveSessionControl;
|
|
95
95
|
//#endregion
|
package/dist/headless.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as makeApertureRuntime, c as collaborationPaintLifetimeMs, d as RuntimeProviderMissingError, f as useBaseUrl, g as useRuntime, h as useRunApi, i as ApertureProvider, l as useLiveSession, m as useFork, n as shareSessionAccess, o as useBrowserControl, p as useEffectCallback, r as useSession, s as SessionViewport, t as LiveSessionError, u as RuntimeProvider } from "./headless-
|
|
1
|
+
import { a as makeApertureRuntime, c as collaborationPaintLifetimeMs, d as RuntimeProviderMissingError, f as useBaseUrl, g as useRuntime, h as useRunApi, i as ApertureProvider, l as useLiveSession, m as useFork, n as shareSessionAccess, o as useBrowserControl, p as useEffectCallback, r as useSession, s as SessionViewport, t as LiveSessionError, u as RuntimeProvider } from "./headless-CxE_tawC.js";
|
|
2
2
|
export { ApertureProvider, LiveSessionError, RuntimeProvider, RuntimeProviderMissingError, SessionViewport, collaborationPaintLifetimeMs, makeApertureRuntime, shareSessionAccess, useBaseUrl, useBrowserControl, useEffectCallback, useFork, useLiveSession, useRunApi, useRuntime, useSession };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,9 +39,11 @@ interface SessionProps {
|
|
|
39
39
|
readonly features?: SessionFeatures;
|
|
40
40
|
/** Rendered at the start of the title bar row, before the tab strip. */
|
|
41
41
|
readonly leading?: ReactNode;
|
|
42
|
+
/** Rendered at the end of the title bar row, after the participants. */
|
|
43
|
+
readonly trailing?: ReactNode;
|
|
42
44
|
/** Rendered at the start of the toolbar row, before the navigation buttons. */
|
|
43
45
|
readonly toolbarLeading?: ReactNode;
|
|
44
|
-
/** Rendered at the end of the toolbar row,
|
|
46
|
+
/** Rendered at the end of the toolbar row, before the menus. */
|
|
45
47
|
readonly toolbarTrailing?: ReactNode;
|
|
46
48
|
}
|
|
47
49
|
interface ApertureSessionProps extends SessionProps {
|
|
@@ -58,6 +60,7 @@ declare function Session({
|
|
|
58
60
|
access,
|
|
59
61
|
features,
|
|
60
62
|
leading,
|
|
63
|
+
trailing,
|
|
61
64
|
toolbarLeading,
|
|
62
65
|
toolbarTrailing
|
|
63
66
|
}: SessionProps): import("react").JSX.Element;
|
|
@@ -80,8 +83,9 @@ declare const copyTextWithToast: (value: string, onCopied?: () => void) => Effec
|
|
|
80
83
|
//#region src/components/browser-control-pane.d.ts
|
|
81
84
|
type BrowserControlPaneProps = {
|
|
82
85
|
control: UseBrowserControlResult; /** Rendered at the start of the title bar row, before the tab strip. */
|
|
83
|
-
leading?: ReactNode; /** Rendered at the
|
|
84
|
-
|
|
86
|
+
leading?: ReactNode; /** Rendered at the end of the title bar row, after the participants. */
|
|
87
|
+
trailing?: ReactNode; /** Rendered at the start of the toolbar row, before the navigation buttons. */
|
|
88
|
+
toolbarLeading?: ReactNode; /** Rendered at the end of the toolbar row, before the browser menu. */
|
|
85
89
|
toolbarTrailing?: ReactNode;
|
|
86
90
|
features?: SessionFeatures;
|
|
87
91
|
collaborationRole: CollaborationRole$1;
|
|
@@ -90,18 +94,25 @@ type BrowserControlPaneProps = {
|
|
|
90
94
|
editor: string;
|
|
91
95
|
viewer: string;
|
|
92
96
|
} | null;
|
|
93
|
-
onSessionDetails?: () => void;
|
|
97
|
+
onSessionDetails?: () => void; /** Extra items at the top of the browser menu, such as actions on the session. */
|
|
98
|
+
menuItems?: ReactNode; /** Extra items in the menu's "Share and connect" submenu. */
|
|
99
|
+
shareMenuItems?: ReactNode; /** Items at the end of the browser menu, such as deleting the session. */
|
|
100
|
+
menuFooterItems?: ReactNode;
|
|
94
101
|
};
|
|
95
102
|
declare function BrowserControlPane({
|
|
96
103
|
control,
|
|
97
104
|
leading,
|
|
105
|
+
trailing,
|
|
98
106
|
toolbarLeading,
|
|
99
107
|
toolbarTrailing,
|
|
100
108
|
features: featureOverrides,
|
|
101
109
|
collaborationRole,
|
|
102
110
|
cdpUrl,
|
|
103
111
|
shareUrls,
|
|
104
|
-
onSessionDetails
|
|
112
|
+
onSessionDetails,
|
|
113
|
+
menuItems,
|
|
114
|
+
shareMenuItems,
|
|
115
|
+
menuFooterItems
|
|
105
116
|
}: BrowserControlPaneProps): import("react").JSX.Element;
|
|
106
117
|
//#endregion
|
|
107
118
|
//#region src/components/browser-viewport.d.ts
|