@2018kguo/jumpseat 0.1.0 → 0.2.0
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 +2 -2
- package/dist/jumpseat.d.ts +5 -35
- package/dist/jumpseat.js +10 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,12 +5,12 @@ computer-use agent's Linux desktop live (H.264 over one websocket, decoded with
|
|
|
5
5
|
WebCodecs) and take over when it needs you. No dependencies.
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
import { connect
|
|
8
|
+
import { connect } from "@2018kguo/jumpseat";
|
|
9
9
|
|
|
10
|
-
if (!(await supportsStream())) showFallback(); // no WebCodecs H.264 decoder
|
|
11
10
|
const view = connect(element, `wss://host/stream?token=${token}`, {
|
|
12
11
|
connected: () => {},
|
|
13
12
|
dropped: () => {},
|
|
13
|
+
unsupported: () => {}, // no WebCodecs H.264 decoder in this browser
|
|
14
14
|
status: ({ kind, text }) => {}, // "acting" | "waiting" | "handoff" | "idle"
|
|
15
15
|
});
|
|
16
16
|
view.setControlling(true); // the person's keys, pointer and scrolls reach the desktop
|
package/dist/jumpseat.d.ts
CHANGED
|
@@ -3,13 +3,6 @@
|
|
|
3
3
|
* WebCodecs onto a canvas, and the user's input sent back while they have
|
|
4
4
|
* taken over. The wire format is in docs/reference.md.
|
|
5
5
|
*/
|
|
6
|
-
/** The desktop's size until the server says otherwise. */
|
|
7
|
-
export declare const DESKTOP_WIDTH = 1280;
|
|
8
|
-
export declare const DESKTOP_HEIGHT = 800;
|
|
9
|
-
type Size = {
|
|
10
|
-
height: number;
|
|
11
|
-
width: number;
|
|
12
|
-
};
|
|
13
6
|
/** What the agent is doing on the desktop, as the VM reports it. */
|
|
14
7
|
export type AgentStatus = {
|
|
15
8
|
kind: "idle" | "acting" | "waiting" | "handoff";
|
|
@@ -19,36 +12,16 @@ export type DesktopStream = {
|
|
|
19
12
|
close(): void;
|
|
20
13
|
setControlling(controlling: boolean): void;
|
|
21
14
|
};
|
|
22
|
-
type Rect = {
|
|
23
|
-
height: number;
|
|
24
|
-
left: number;
|
|
25
|
-
top: number;
|
|
26
|
-
width: number;
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* The desktop pixel under a client point, or null outside the picture. The
|
|
30
|
-
* canvas is letterboxed (object-fit: contain), so the picture is the largest
|
|
31
|
-
* box of the desktop's size centered in the element.
|
|
32
|
-
*/
|
|
33
|
-
export declare function desktopPoint(rect: Rect, clientX: number, clientY: number, size?: Size): {
|
|
34
|
-
x: number;
|
|
35
|
-
y: number;
|
|
36
|
-
} | null;
|
|
37
|
-
/**
|
|
38
|
-
* The key the VM gets for a KeyboardEvent.key. Meta is Control there, so
|
|
39
|
-
* Cmd+A, Cmd+L and Cmd+C on a Mac do what they do at home.
|
|
40
|
-
*/
|
|
41
|
-
export declare function desktopKey(event: Pick<KeyboardEvent, "altKey" | "code" | "ctrlKey" | "key" | "metaKey">): string;
|
|
42
|
-
/** Whether this browser can decode the stream (WebCodecs H.264). */
|
|
43
|
-
export declare function canDecodeDesktop(): boolean;
|
|
44
|
-
/** The codec the server sends: H.264 High profile (CABAC, no B-frames). */
|
|
45
|
-
export declare const STREAM_CODEC = "avc1.640029";
|
|
46
15
|
/**
|
|
47
16
|
* Whether this browser decodes the stream: WebCodecs exists and has an H.264
|
|
48
17
|
* decoder (some Linux Chromium builds ship without one).
|
|
49
18
|
*/
|
|
50
19
|
export declare function supportsStream(): Promise<boolean>;
|
|
51
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Streams the desktop at socketUrl into container, which it fills. A browser
|
|
22
|
+
* that cannot decode the stream gets on.unsupported (or on.dropped) instead.
|
|
23
|
+
*/
|
|
24
|
+
export declare function connect(container: HTMLElement, socketUrl: string, on: {
|
|
52
25
|
connected: () => void;
|
|
53
26
|
dropped: () => void;
|
|
54
27
|
status?: (status: AgentStatus) => void;
|
|
@@ -62,6 +35,3 @@ export declare function connectDesktopStream(container: HTMLElement, socketUrl:
|
|
|
62
35
|
options?: {
|
|
63
36
|
resize?: boolean;
|
|
64
37
|
}): DesktopStream;
|
|
65
|
-
/** connect(container, url, handlers): the same as connectDesktopStream. */
|
|
66
|
-
export declare const connect: typeof connectDesktopStream;
|
|
67
|
-
export {};
|
package/dist/jumpseat.js
CHANGED
|
@@ -59,12 +59,9 @@ var HEARTBEAT_MS = 5000;
|
|
|
59
59
|
var FIRST_FRAME_MS = 20000;
|
|
60
60
|
var X_BUTTONS = { 0: 1, 1: 2, 2: 3 };
|
|
61
61
|
var POINTER_ARROW = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='20'%3E%3Cpath d='M1 1v15l4-4 3 7 3-1-3-7h6z' fill='white' stroke='black'/%3E%3C/svg%3E")`;
|
|
62
|
-
function canDecodeDesktop() {
|
|
63
|
-
return typeof window !== "undefined" && "VideoDecoder" in window;
|
|
64
|
-
}
|
|
65
62
|
var STREAM_CODEC = "avc1.640029";
|
|
66
63
|
async function supportsStream() {
|
|
67
|
-
if (
|
|
64
|
+
if (typeof VideoDecoder === "undefined") {
|
|
68
65
|
return false;
|
|
69
66
|
}
|
|
70
67
|
try {
|
|
@@ -73,7 +70,11 @@ async function supportsStream() {
|
|
|
73
70
|
return false;
|
|
74
71
|
}
|
|
75
72
|
}
|
|
76
|
-
function
|
|
73
|
+
function connect(container, socketUrl, on, options = {}) {
|
|
74
|
+
if (typeof VideoDecoder === "undefined") {
|
|
75
|
+
setTimeout(on.unsupported ?? on.dropped);
|
|
76
|
+
return { close() {}, setControlling() {} };
|
|
77
|
+
}
|
|
77
78
|
const canvas = document.createElement("canvas");
|
|
78
79
|
const size = { height: DESKTOP_HEIGHT, width: DESKTOP_WIDTH };
|
|
79
80
|
canvas.width = size.width;
|
|
@@ -109,23 +110,18 @@ function connectDesktopStream(container, socketUrl, on, options = {}) {
|
|
|
109
110
|
});
|
|
110
111
|
const socket = new WebSocket(socketUrl);
|
|
111
112
|
socket.binaryType = "arraybuffer";
|
|
112
|
-
|
|
113
|
-
if (!await supportsStream() && !closed) {
|
|
114
|
-
closed = true;
|
|
115
|
-
socket.close();
|
|
116
|
-
(on.unsupported ?? on.dropped)();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
function drop() {
|
|
113
|
+
function stop(notify) {
|
|
120
114
|
if (!closed) {
|
|
121
115
|
closed = true;
|
|
122
116
|
clearInterval(heartbeat);
|
|
123
117
|
clearTimeout(firstFrame);
|
|
124
118
|
resizer?.disconnect();
|
|
125
119
|
socket.close();
|
|
126
|
-
|
|
120
|
+
notify();
|
|
127
121
|
}
|
|
128
122
|
}
|
|
123
|
+
const drop = () => stop(on.dropped);
|
|
124
|
+
supportsStream().then((ok) => ok || stop(on.unsupported ?? on.dropped));
|
|
129
125
|
const sendAlways = (message) => {
|
|
130
126
|
if (socket.readyState === WebSocket.OPEN) {
|
|
131
127
|
socket.send(JSON.stringify(message));
|
|
@@ -193,7 +189,6 @@ function connectDesktopStream(container, socketUrl, on, options = {}) {
|
|
|
193
189
|
if (!key) {
|
|
194
190
|
return;
|
|
195
191
|
}
|
|
196
|
-
checkDecoderSupport();
|
|
197
192
|
decoder.configure({
|
|
198
193
|
codec: STREAM_CODEC,
|
|
199
194
|
optimizeForLatency: true
|
|
@@ -448,15 +443,7 @@ function desktopPerCssPixel(canvas) {
|
|
|
448
443
|
const rect = canvas.getBoundingClientRect();
|
|
449
444
|
return 1 / Math.min(rect.width / canvas.width, rect.height / canvas.height);
|
|
450
445
|
}
|
|
451
|
-
var connect = connectDesktopStream;
|
|
452
446
|
export {
|
|
453
|
-
DESKTOP_HEIGHT,
|
|
454
|
-
DESKTOP_WIDTH,
|
|
455
|
-
STREAM_CODEC,
|
|
456
|
-
canDecodeDesktop,
|
|
457
447
|
connect,
|
|
458
|
-
connectDesktopStream,
|
|
459
|
-
desktopKey,
|
|
460
|
-
desktopPoint,
|
|
461
448
|
supportsStream
|
|
462
449
|
};
|
package/package.json
CHANGED