@aperture-browser/live-session 0.0.0-init.0 → 0.0.0-nightly.100.78b4e7ef6edc
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/README.md +6 -0
- package/dist/index.d.ts +389 -45
- package/dist/index.js +138 -52
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Schema from "effect/Schema";
|
|
4
|
-
import { Recording, resolveTenantHeader } from "@aperture-browser/api-client";
|
|
4
|
+
import { BrowserStatus, Recording, contentDispositionFilename, resolveTenantHeader, toApiRequestError } from "@aperture-browser/api-client";
|
|
5
5
|
import * as Data from "effect/Data";
|
|
6
6
|
import * as Deferred from "effect/Deferred";
|
|
7
7
|
import "effect/Fiber";
|
|
8
8
|
import * as FiberSet from "effect/FiberSet";
|
|
9
9
|
import * as Option from "effect/Option";
|
|
10
|
+
import * as Redacted from "effect/Redacted";
|
|
11
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
12
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
13
|
+
import * as HttpClientResponse from "effect/http/HttpClientResponse";
|
|
10
14
|
//#region src/input-keycodes.ts
|
|
11
15
|
const evdevKeycodeByCode = {
|
|
12
16
|
Escape: 1,
|
|
@@ -315,6 +319,8 @@ const Target = Schema.Struct({
|
|
|
315
319
|
title: Schema.String,
|
|
316
320
|
url: Schema.String,
|
|
317
321
|
loading: Schema.Boolean,
|
|
322
|
+
canGoBack: Schema.optionalKey(Schema.Boolean),
|
|
323
|
+
canGoForward: Schema.optionalKey(Schema.Boolean),
|
|
318
324
|
viewport: Schema.optionalKey(Schema.Struct({
|
|
319
325
|
width: positive,
|
|
320
326
|
height: positive,
|
|
@@ -357,7 +363,9 @@ const Snapshot = Schema.Struct({
|
|
|
357
363
|
targets: arrayOrEmpty(Target),
|
|
358
364
|
participants: arrayOrEmpty(Participant),
|
|
359
365
|
recordings: arrayOrEmpty(Recording),
|
|
360
|
-
presentation: Presentation
|
|
366
|
+
presentation: Presentation,
|
|
367
|
+
viewportOwnerClientId: Schema.optionalKey(Schema.String),
|
|
368
|
+
autoSize: Schema.optionalKey(Schema.Boolean)
|
|
361
369
|
});
|
|
362
370
|
const PresenceState = Schema.Struct({
|
|
363
371
|
type: Schema.Literal("presence.state"),
|
|
@@ -368,6 +376,11 @@ const InputState = Schema.Struct({
|
|
|
368
376
|
holderClientId: Schema.optionalKey(Schema.String),
|
|
369
377
|
mode: Schema.optionalKey(LeaseMode)
|
|
370
378
|
});
|
|
379
|
+
const ViewportState = Schema.Struct({
|
|
380
|
+
type: Schema.Literal("viewport.state"),
|
|
381
|
+
viewportOwnerClientId: Schema.optionalKey(Schema.String),
|
|
382
|
+
autoSize: Schema.Boolean
|
|
383
|
+
});
|
|
371
384
|
const Cursor = Schema.Struct({
|
|
372
385
|
type: Schema.Literal("presence.cursor"),
|
|
373
386
|
clientId: Schema.String,
|
|
@@ -429,8 +442,11 @@ const CommandResult = Schema.Struct({
|
|
|
429
442
|
"page.reload.result",
|
|
430
443
|
"page.stop-loading.result",
|
|
431
444
|
"viewport.set.result",
|
|
445
|
+
"viewport.auto-size.set.result",
|
|
446
|
+
"viewport.owner.claim.result",
|
|
432
447
|
"presentation.quality.set.result",
|
|
433
448
|
"presentation.cursor.set.result",
|
|
449
|
+
"automation.pacing.set.result",
|
|
434
450
|
"recording.start.result",
|
|
435
451
|
"recording.stop.result",
|
|
436
452
|
"recording.cancel.result"
|
|
@@ -447,6 +463,7 @@ const LiveSessionServerMessage = Schema.Union([
|
|
|
447
463
|
Snapshot,
|
|
448
464
|
PresenceState,
|
|
449
465
|
InputState,
|
|
466
|
+
ViewportState,
|
|
450
467
|
Cursor,
|
|
451
468
|
CursorClear,
|
|
452
469
|
Paint,
|
|
@@ -524,6 +541,73 @@ function mapClientToViewport(clientX, clientY, rect, viewportWidth, viewportHeig
|
|
|
524
541
|
};
|
|
525
542
|
}
|
|
526
543
|
//#endregion
|
|
544
|
+
//#region src/access.ts
|
|
545
|
+
/** Resolve a path under the access mount, including relative relay mounts. */
|
|
546
|
+
function mountURL(access, path) {
|
|
547
|
+
const base = new URL(access.baseUrl ?? "/", window.location.href);
|
|
548
|
+
if (base.protocol !== "http:" && base.protocol !== "https:") throw new Error("session base URL must use HTTP or HTTPS");
|
|
549
|
+
if (access.kind === "relay" && base.origin !== window.location.origin) throw new Error("session relay must use the page's origin");
|
|
550
|
+
base.pathname = `${base.pathname.replace(/\/$/, "")}/${path}`;
|
|
551
|
+
base.search = "";
|
|
552
|
+
base.hash = "";
|
|
553
|
+
return base;
|
|
554
|
+
}
|
|
555
|
+
/** Resolve all session endpoints under the same mount. */
|
|
556
|
+
function sessionURL(access, route) {
|
|
557
|
+
return mountURL(access, `sessions/${encodeURIComponent(access.sessionId)}/${route}`);
|
|
558
|
+
}
|
|
559
|
+
function sessionWebSocketURL(access, route) {
|
|
560
|
+
const url = sessionURL(access, route);
|
|
561
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
562
|
+
return url.toString();
|
|
563
|
+
}
|
|
564
|
+
/** Credentials the browser sends itself; relay access is authenticated by the consumer backend instead. */
|
|
565
|
+
function directAuthorization(access) {
|
|
566
|
+
if (access.kind !== "direct") return {
|
|
567
|
+
token: void 0,
|
|
568
|
+
tenantId: void 0
|
|
569
|
+
};
|
|
570
|
+
const { credentials } = access;
|
|
571
|
+
return {
|
|
572
|
+
token: credentials.kind === "bearer" ? Redacted.value(credentials.token) : void 0,
|
|
573
|
+
tenantId: resolveTenantHeader(credentials, "tenant-scoped")
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
function sessionProtocols(access) {
|
|
577
|
+
const { token, tenantId } = directAuthorization(access);
|
|
578
|
+
const protocols = [LIVE_SESSION_PROTOCOL];
|
|
579
|
+
if (token !== void 0) protocols.push(`authorization.bearer.${token}`);
|
|
580
|
+
if (tenantId !== void 0) protocols.push(`x-aperture-tenant-id.${tenantId}`);
|
|
581
|
+
return protocols;
|
|
582
|
+
}
|
|
583
|
+
/** GETs a session route with the credentials this access sends itself. */
|
|
584
|
+
function sessionGet(access, url) {
|
|
585
|
+
const { token, tenantId } = directAuthorization(access);
|
|
586
|
+
const headers = {};
|
|
587
|
+
if (token !== void 0) headers.Authorization = `Bearer ${token}`;
|
|
588
|
+
if (tenantId !== void 0) headers["X-Aperture-Tenant-Id"] = tenantId;
|
|
589
|
+
return Effect.flatMap(HttpClient.HttpClient, (http) => HttpClient.filterStatusOk(http).get(url.toString(), { headers })).pipe(Effect.provideService(FetchHttpClient.RequestInit, {
|
|
590
|
+
credentials: token === void 0 ? "same-origin" : "omit",
|
|
591
|
+
redirect: "error",
|
|
592
|
+
cache: "no-store"
|
|
593
|
+
}));
|
|
594
|
+
}
|
|
595
|
+
const getSessionStatus = Effect.fn("getSessionStatus")(function* (access) {
|
|
596
|
+
return yield* sessionGet(access, sessionURL(access, "browser/status")).pipe(Effect.flatMap(HttpClientResponse.schemaBodyJson(BrowserStatus)), toApiRequestError);
|
|
597
|
+
});
|
|
598
|
+
const downloadSessionRecording = Effect.fn("downloadSessionRecording")(function* (access, recordingId) {
|
|
599
|
+
return yield* sessionGet(access, sessionURL(access, `recordings/${encodeURIComponent(recordingId)}/content`)).pipe(Effect.flatMap((response) => Effect.map(response.arrayBuffer, (body) => ({
|
|
600
|
+
blob: new Blob([body], { type: response.headers["content-type"] ?? "" }),
|
|
601
|
+
filename: contentDispositionFilename(response.headers["content-disposition"])
|
|
602
|
+
}))), toApiRequestError);
|
|
603
|
+
});
|
|
604
|
+
/** A JPEG of one tab, authorized through the relay, session access, or account API. */
|
|
605
|
+
const getTargetThumbnail = Effect.fn("getTargetThumbnail")(function* (access, targetId) {
|
|
606
|
+
const route = `targets/${encodeURIComponent(targetId)}/thumbnail`;
|
|
607
|
+
const token = directAuthorization(access).token;
|
|
608
|
+
return yield* sessionGet(access, access.kind === "relay" || token !== void 0 && (token.startsWith("aps_") || token.startsWith("ape_") || token.startsWith("apv_")) ? sessionURL(access, route) : mountURL(access, `api/sessions/${encodeURIComponent(access.sessionId)}/${route}`)).pipe(Effect.flatMap((response) => Effect.map(response.arrayBuffer, (body) => new Blob([body], { type: "image/jpeg" }))), toApiRequestError);
|
|
609
|
+
});
|
|
610
|
+
//#endregion
|
|
527
611
|
//#region src/connection.ts
|
|
528
612
|
var connection_exports = /* @__PURE__ */ __exportAll({
|
|
529
613
|
LiveSessionError: () => LiveSessionError,
|
|
@@ -577,6 +661,7 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
577
661
|
let preferredTransport = options.webrtcSupported ? "webrtc" : "websocket";
|
|
578
662
|
let transportRequest = null;
|
|
579
663
|
let disposed = false;
|
|
664
|
+
let terminalError = null;
|
|
580
665
|
let retryTimer = null;
|
|
581
666
|
let webrtcRetryMs = 1e3;
|
|
582
667
|
let nextRequestId = 0;
|
|
@@ -587,7 +672,8 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
587
672
|
const pendingCommands = /* @__PURE__ */ new Map();
|
|
588
673
|
const hello = () => ({
|
|
589
674
|
type: "session.hello",
|
|
590
|
-
...identity ?? options.identity
|
|
675
|
+
...identity ?? options.identity,
|
|
676
|
+
...options.autoSize === void 0 ? {} : { autoSize: options.autoSize() }
|
|
591
677
|
});
|
|
592
678
|
const transportCallbacks = {
|
|
593
679
|
hello,
|
|
@@ -625,14 +711,11 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
625
711
|
else startWebSocket();
|
|
626
712
|
};
|
|
627
713
|
const startWebRTC = () => {
|
|
628
|
-
if (disposed || candidate) return;
|
|
714
|
+
if (disposed || terminalError !== null || candidate) return;
|
|
629
715
|
let transport;
|
|
630
716
|
try {
|
|
631
717
|
transport = new WebRTCSessionTransport({
|
|
632
|
-
|
|
633
|
-
sessionId: options.sessionId,
|
|
634
|
-
credentials: options.credentials,
|
|
635
|
-
sessionToken: options.sessionToken,
|
|
718
|
+
access: options.access,
|
|
636
719
|
iceServers: options.iceServers,
|
|
637
720
|
callbacks: transportCallbacks,
|
|
638
721
|
fork
|
|
@@ -652,14 +735,11 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
652
735
|
});
|
|
653
736
|
};
|
|
654
737
|
const startWebSocket = () => {
|
|
655
|
-
if (disposed || candidate) return;
|
|
738
|
+
if (disposed || terminalError !== null || candidate) return;
|
|
656
739
|
let transport;
|
|
657
740
|
try {
|
|
658
741
|
transport = new WebSocketSessionTransport({
|
|
659
|
-
|
|
660
|
-
sessionId: options.sessionId,
|
|
661
|
-
credentials: options.credentials,
|
|
662
|
-
sessionToken: options.sessionToken,
|
|
742
|
+
access: options.access,
|
|
663
743
|
callbacks: transportCallbacks,
|
|
664
744
|
fork
|
|
665
745
|
});
|
|
@@ -709,8 +789,27 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
709
789
|
if (transport.kind === "websocket" && preferredTransport === "webrtc" && options.webrtcSupported) scheduleWebRTCRetry();
|
|
710
790
|
if (previous && previous !== transport) previous.close();
|
|
711
791
|
};
|
|
792
|
+
/** Closes every transport and clears what they presented; the connection itself stays usable. */
|
|
793
|
+
const stopTransports = (reason) => {
|
|
794
|
+
clearRetry();
|
|
795
|
+
dropCandidate();
|
|
796
|
+
active?.close();
|
|
797
|
+
active = null;
|
|
798
|
+
rejectTransportRequest(reason);
|
|
799
|
+
rejectPending(reason);
|
|
800
|
+
callbacks.onFrame(null);
|
|
801
|
+
callbacks.onStream(null);
|
|
802
|
+
callbacks.onTransport(null);
|
|
803
|
+
};
|
|
712
804
|
const transportFailed = (transport, error) => {
|
|
713
805
|
if (disposed) return;
|
|
806
|
+
if (error.terminalReason !== void 0 && (candidate === transport || active === transport)) {
|
|
807
|
+
terminalError = error;
|
|
808
|
+
stopTransports(error.message);
|
|
809
|
+
callbacks.onPhase("error");
|
|
810
|
+
callbacks.onError(error.message);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
714
813
|
if (candidate === transport) {
|
|
715
814
|
dropCandidate();
|
|
716
815
|
candidateFailed(transport.kind, error);
|
|
@@ -791,21 +890,14 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
791
890
|
};
|
|
792
891
|
const close = () => {
|
|
793
892
|
disposed = true;
|
|
794
|
-
|
|
795
|
-
dropCandidate();
|
|
796
|
-
active?.close();
|
|
797
|
-
active = null;
|
|
798
|
-
rejectTransportRequest("live session connection closed");
|
|
799
|
-
rejectPending("live session connection closed");
|
|
800
|
-
callbacks.onFrame(null);
|
|
801
|
-
callbacks.onStream(null);
|
|
802
|
-
callbacks.onTransport(null);
|
|
893
|
+
stopTransports("live session connection closed");
|
|
803
894
|
};
|
|
804
895
|
yield* Effect.addFinalizer(() => Effect.sync(close));
|
|
805
896
|
callbacks.onPhase("connecting");
|
|
806
897
|
startPreferredTransport();
|
|
807
898
|
return {
|
|
808
899
|
reconnect: Effect.sync(() => {
|
|
900
|
+
terminalError = null;
|
|
809
901
|
clearRetry();
|
|
810
902
|
dropCandidate();
|
|
811
903
|
active?.close();
|
|
@@ -813,9 +905,10 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
813
905
|
rejectTransportRequest("live session transport replaced");
|
|
814
906
|
rejectPending("live session transport replaced");
|
|
815
907
|
callbacks.onPhase("connecting");
|
|
816
|
-
|
|
908
|
+
startWebSocket();
|
|
817
909
|
}),
|
|
818
910
|
selectTransport: (kind) => Effect.suspend(() => {
|
|
911
|
+
if (terminalError !== null) return Effect.fail(terminalError);
|
|
819
912
|
if (kind === "webrtc" && !options.webrtcSupported) return Effect.fail(new LiveSessionError({ message: "WebRTC presentation is unavailable" }));
|
|
820
913
|
preferredTransport = kind;
|
|
821
914
|
clearRetry();
|
|
@@ -867,7 +960,7 @@ var WebSocketSessionTransport = class {
|
|
|
867
960
|
constructor(options) {
|
|
868
961
|
this.callbacks = options.callbacks;
|
|
869
962
|
this.fork = options.fork;
|
|
870
|
-
this.socket = new WebSocket(sessionWebSocketURL(options.
|
|
963
|
+
this.socket = new WebSocket(sessionWebSocketURL(options.access, "session"), sessionProtocols(options.access));
|
|
871
964
|
this.socket.binaryType = "blob";
|
|
872
965
|
}
|
|
873
966
|
connect() {
|
|
@@ -888,8 +981,8 @@ var WebSocketSessionTransport = class {
|
|
|
888
981
|
}
|
|
889
982
|
}
|
|
890
983
|
});
|
|
891
|
-
this.socket.addEventListener("close", () => {
|
|
892
|
-
if (!this.closed) this.callbacks.failed(this,
|
|
984
|
+
this.socket.addEventListener("close", (event) => {
|
|
985
|
+
if (!this.closed) this.callbacks.failed(this, transportError("WebSocket session transport closed", event.code));
|
|
893
986
|
});
|
|
894
987
|
this.socket.addEventListener("error", () => {
|
|
895
988
|
if (!this.closed) this.callbacks.failed(this, new LiveSessionError({ message: "WebSocket session transport failed" }));
|
|
@@ -969,8 +1062,9 @@ var WebRTCSessionTransport = class {
|
|
|
969
1062
|
this.callbacks = options.callbacks;
|
|
970
1063
|
this.fork = options.fork;
|
|
971
1064
|
this.connection = new RTCPeerConnection({ iceServers: options.iceServers.map((server) => ({
|
|
972
|
-
...server,
|
|
973
|
-
|
|
1065
|
+
urls: [...server.urls],
|
|
1066
|
+
username: server.username,
|
|
1067
|
+
credential: server.credential === void 0 ? void 0 : Redacted.value(server.credential)
|
|
974
1068
|
})) });
|
|
975
1069
|
this.reliable = this.connection.createDataChannel("application", { ordered: true });
|
|
976
1070
|
this.realtime = this.connection.createDataChannel("application-realtime", {
|
|
@@ -978,7 +1072,7 @@ var WebRTCSessionTransport = class {
|
|
|
978
1072
|
maxRetransmits: 0
|
|
979
1073
|
});
|
|
980
1074
|
this.connection.addTransceiver("video", { direction: "recvonly" });
|
|
981
|
-
this.signal = new WebSocket(
|
|
1075
|
+
this.signal = new WebSocket(sessionWebSocketURL(options.access, "webrtc/signal"), sessionProtocols(options.access));
|
|
982
1076
|
}
|
|
983
1077
|
connect() {
|
|
984
1078
|
this.reliable.addEventListener("open", () => {
|
|
@@ -1019,7 +1113,7 @@ var WebRTCSessionTransport = class {
|
|
|
1019
1113
|
this.fork(this.sendOffer().pipe(Effect.catchTag("LiveSessionError", (error) => Effect.sync(() => this.fail(error.message)))));
|
|
1020
1114
|
});
|
|
1021
1115
|
this.signal.addEventListener("message", (event) => this.handleSignal(event));
|
|
1022
|
-
this.signal.addEventListener("close", () => this.fail("WebRTC signaling closed"));
|
|
1116
|
+
this.signal.addEventListener("close", (event) => this.fail("WebRTC signaling closed", event.code));
|
|
1023
1117
|
this.signal.addEventListener("error", () => this.fail("WebRTC signaling failed"));
|
|
1024
1118
|
}
|
|
1025
1119
|
sendReliable(message) {
|
|
@@ -1106,10 +1200,21 @@ var WebRTCSessionTransport = class {
|
|
|
1106
1200
|
maybeReady() {
|
|
1107
1201
|
if (this.snapshotReceived && this.stream && this.streamReady) this.callbacks.ready(this);
|
|
1108
1202
|
}
|
|
1109
|
-
fail(message) {
|
|
1110
|
-
if (!this.closed) this.callbacks.failed(this,
|
|
1203
|
+
fail(message, closeCode = 0) {
|
|
1204
|
+
if (!this.closed) this.callbacks.failed(this, transportError(message, closeCode));
|
|
1111
1205
|
}
|
|
1112
1206
|
};
|
|
1207
|
+
function transportError(message, closeCode) {
|
|
1208
|
+
if (closeCode === 4401 || closeCode === 4403) return new LiveSessionError({
|
|
1209
|
+
message: "Session access denied. Sign in or request access before reconnecting.",
|
|
1210
|
+
terminalReason: "access_denied"
|
|
1211
|
+
});
|
|
1212
|
+
if (closeCode === 4404 || closeCode === 4410) return new LiveSessionError({
|
|
1213
|
+
message: "Session is no longer available.",
|
|
1214
|
+
terminalReason: "session_unavailable"
|
|
1215
|
+
});
|
|
1216
|
+
return new LiveSessionError({ message });
|
|
1217
|
+
}
|
|
1113
1218
|
function decodeRasterFrame(packet) {
|
|
1114
1219
|
return Effect.gen(function* () {
|
|
1115
1220
|
if (packet.size < 4) return Option.none();
|
|
@@ -1125,26 +1230,7 @@ function decodeRasterFrame(packet) {
|
|
|
1125
1230
|
}));
|
|
1126
1231
|
}).pipe(Effect.orElseSucceed(() => Option.none()));
|
|
1127
1232
|
}
|
|
1128
|
-
function sessionWebSocketURL(baseUrl, sessionId) {
|
|
1129
|
-
return webSocketURL(baseUrl, `/sessions/${encodeURIComponent(sessionId)}/session`);
|
|
1130
|
-
}
|
|
1131
|
-
function signalWebSocketURL(baseUrl, sessionId) {
|
|
1132
|
-
return webSocketURL(baseUrl, `/sessions/${encodeURIComponent(sessionId)}/webrtc/signal`);
|
|
1133
|
-
}
|
|
1134
|
-
function webSocketURL(baseUrl, path) {
|
|
1135
|
-
const url = new URL(path, baseUrl ?? window.location.href);
|
|
1136
|
-
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
1137
|
-
return url.toString();
|
|
1138
|
-
}
|
|
1139
|
-
function sessionProtocols(credentials, sessionToken) {
|
|
1140
|
-
const protocols = [LIVE_SESSION_PROTOCOL];
|
|
1141
|
-
if (sessionToken) protocols.push(`authorization.bearer.${sessionToken}`);
|
|
1142
|
-
else if (credentials.kind === "bearer") protocols.push(`authorization.bearer.${credentials.token}`);
|
|
1143
|
-
const tenantId = resolveTenantHeader(credentials, "tenant-scoped");
|
|
1144
|
-
if (tenantId) protocols.push(`x-aperture-tenant-id.${tenantId}`);
|
|
1145
|
-
return protocols;
|
|
1146
|
-
}
|
|
1147
1233
|
//#endregion
|
|
1148
|
-
export { DEFAULT_VIEWPORT, LIVE_SESSION_PROTOCOL, connection_exports as LiveSessionConnection, LiveSessionError, LiveSessionServerMessage, RasterFrameHeader, STALE_FRAME_MS, VIEWPORT_DEVICE_SCALE_FACTORS, VIEWPORT_PRESETS, computeRenderMetrics, createViewportPreset, decodeServerMessage, evdevKeycodeByCode, formatViewportScale, isPrintableKey, keyboardInputMessage, keyboardModifiers, mapClientToViewport, shouldForwardBrowserShortcut, strictParseOptions, windowsVirtualKeyCodeForCodeOrKey };
|
|
1234
|
+
export { DEFAULT_VIEWPORT, LIVE_SESSION_PROTOCOL, connection_exports as LiveSessionConnection, LiveSessionError, LiveSessionServerMessage, RasterFrameHeader, STALE_FRAME_MS, VIEWPORT_DEVICE_SCALE_FACTORS, VIEWPORT_PRESETS, computeRenderMetrics, createViewportPreset, decodeServerMessage, downloadSessionRecording, evdevKeycodeByCode, formatViewportScale, getSessionStatus, getTargetThumbnail, isPrintableKey, keyboardInputMessage, keyboardModifiers, mapClientToViewport, sessionProtocols, sessionURL, sessionWebSocketURL, shouldForwardBrowserShortcut, strictParseOptions, windowsVirtualKeyCodeForCodeOrKey };
|
|
1149
1235
|
|
|
1150
1236
|
//# sourceMappingURL=index.js.map
|