port entire project to using parcel + strict TypeScript

Mostly out of cleanliness, and actually bundling the libraries properly.

Yes, this includes the backend, because.. why not? It seems to work, at least.

The VNC client for instance also is now fully strict TypeScript.
This commit is contained in:
Lily Tsuru 2024-04-05 04:30:56 -04:00
parent 7b9c71d534
commit 4212050ae5
29 changed files with 686 additions and 383 deletions

View file

@ -1,4 +1,4 @@
Copyright 2023 Lily Tsuru/modeco80 <lily.modeco80@protonmail.ch>
Copyright 2023-2024 Lily Tsuru/modeco80 <lily.modeco80@protonmail.ch>
Please see qemu/src/rfb/LICENSE for additional terms.
Permission is hereby granted, free of charge, to any person obtaining a copy

View file

@ -3,13 +3,26 @@
"version": "1.0.0",
"private": "true",
"description": "socket 2.0 backend",
"type": "module",
"scripts": {
"build": "tsc"
"build": "parcel build src/index.ts --target node"
},
"author": "modeco80",
"license": "MIT",
"targets": {
"node":{
"context": "node",
"outputFormat": "esmodule"
}
},
"dependencies": {
"parcel": "^2.12.0",
"@fastify/websocket": "^10.0.1",
"@julusian/jpeg-turbo": "^2.1.0",
"@socketcomputer/qemu": "*",

View file

@ -64,7 +64,7 @@ export function Slot_PCDef(
pushOption('-device usb-tablet');
return {
id: "socketvm1",
id: "socketvm2-test",
command: qCommand
};
}

View file

@ -1,4 +1,4 @@
import { QemuVmDefinition, QemuDisplay, QemuVM, VMState, setSnapshot, GenMacAddress } from '@socketcomputer/qemu';
import { QemuVmDefinition, QemuDisplay, QemuVM, VMState, setSnapshot } from '@socketcomputer/qemu';
import { Slot_PCDef } from './SlotQemuDefs.js';
import { ExtendableTimer } from './ExtendableTimer.js';
import { EventEmitter } from 'node:events';
@ -20,7 +20,7 @@ const kCanvasJpegQuality = 0.25;
class VMUser {
public connection: WebSocket;
public address: string;
public username: string;
public username: string = "";
private vm: SocketVM;
@ -49,10 +49,10 @@ class VMUser {
async SendBuffer(buffer: ArrayBuffer): Promise<void> {
return new Promise((res, rej) => {
if (this.connection.readyState !== WebSocket.CLOSED) {
this.connection.send(buffer, (err) => {
res();
});
this.connection.send(buffer);
res();
}
rej(new Error('connection haves closed'));
});
}
@ -73,14 +73,17 @@ type userAndTime = {
class TurnQueue extends EventEmitter {
private queue: Queue<VMUser> = new Queue<VMUser>();
private turnTime = kTurnTimeSeconds;
private interval: NodeJS.Timeout = null;
private interval: NodeJS.Timeout|null = null;
constructor() {
super();
}
public CurrentUser(): VMUser {
return this.queue.peek();
public CurrentUser(): VMUser|null {
if(this.queue.peek() == undefined)
return null;
// We already check if it'll be undefined
return this.queue.peek()!;
}
public TryEnqueue(user: VMUser) {
@ -132,7 +135,7 @@ class TurnQueue extends EventEmitter {
}
private nextTurn() {
clearInterval(this.interval);
clearInterval(this.interval!);
if (this.queue.size === 0) {
} else {
this.turnTime = kTurnTimeSeconds;
@ -145,7 +148,7 @@ class TurnQueue extends EventEmitter {
class SocketVM extends EventEmitter {
private vm: QemuVM;
private display: QemuDisplay;
private display: QemuDisplay|null = null;
private timer: ExtendableTimer = new ExtendableTimer(15);
private users: Array<VMUser> = [];
@ -325,7 +328,7 @@ class SocketVM extends EventEmitter {
let self = this;
// Hook up the display
this.display.on('resize', async (width, height) => {
this.display?.on('resize', async (width: number, height: number) => {
if(self.display == null)
return;
@ -349,7 +352,7 @@ class SocketVM extends EventEmitter {
});
});
this.display.on('rect', async (x, y, rect: ImageData) => {
this.display?.on('rect', async (x: number, y: number, rect: ImageData) => {
let canvas = new Canvas(rect.width, rect.height);
canvas.getContext('2d').putImageData(rect, 0, 0);
@ -372,7 +375,7 @@ class SocketVM extends EventEmitter {
await user.SendMessage((encoder: Shared.MessageEncoder) => {
encoder.Init(8);
encoder.SetDisplaySizeMessage(this.display.Size().width, this.display.Size().height);
encoder.SetDisplaySizeMessage(this.display!.Size().width, this.display!.Size().height);
return encoder.Finish();
});
@ -402,7 +405,7 @@ export type SocketComputerConfig = {
};
export class SocketComputerServer {
private vm: SocketVM = null;
private vm: SocketVM|null = null;
private fastify: FastifyInstance = fastify({
exposeHeadRoutes: false
});
@ -442,12 +445,13 @@ export class SocketComputerServer {
CTRoutes(app: FastifyInstance) {
let self = this;
// @ts-ignore (fastify types are broken...)
app.get('/', { websocket: true }, (connection: fastifyWebsocket.WebSocket, req: FastifyRequest) => {
let address = req.ip;
if(req.headers["cf-connecting-ip"] !== undefined) {
address = req.headers["cf-connecting-ip"] as string;
}
new VMUser(connection, self.vm, address);
new VMUser(connection, self.vm!, address);
});
}
}

View file

@ -8,15 +8,20 @@
"webapp"
],
"scripts": {
"build:frontend": "npm -w shared run build && npm -w webapp run build",
"build:service": "npm -w shared run build && npm -w qemu run build && npm -w backend run build"
"build": "yarn build:service && yarn build:frontend",
"build:service": "npm -w shared run build && npm -w qemu run build && npm -w backend run build",
"build:frontend": "npm -w shared run build && npm -w webapp run build"
},
"dependencies": {
"canvas": "^2.11.2",
"parcel": "^2.12.0"
},
"dependencies": {
"canvas": "^2.11.2"
},
"devDependencies": {
"@parcel/packager-ts": "2.12.0",
"@parcel/transformer-typescript-types": "2.12.0",
"@types/node": "^20.12.2",
"prettier": "^3.2.5",
"stream-http": "^3.1.0",
"typescript": "^5.4.3"
}
}

View file

@ -3,17 +3,30 @@
"version": "1.0.0",
"private": "true",
"description": "QEMU runtime for socketcomputer backend",
"main": "dist/src/index.js",
"exports": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module",
"scripts": {
"build": "tsc"
"build": "parcel build src/index.ts --target node --target types"
},
"author": "",
"license": "MIT",
"targets": {
"types": {},
"node": {
"context": "node",
"isLibrary": true,
"outputFormat": "esmodule"
}
},
"dependencies": {
"canvas": "^2.11.2",
"execa": "^8.0.1",
"parcel": "^2.12.0",
"split": "^1.0.1"
},
"devDependencies": {
"@types/node": "^20.12.2",
"@types/split": "^1.0.5"
}
}

View file

@ -138,11 +138,11 @@ export class QemuDisplay extends EventEmitter {
};
}
MouseEvent(x, y, buttons) {
MouseEvent(x: number, y: number, buttons: number) {
this.displayVnc.sendPointerEvent(x, y, buttons);
}
KeyboardEvent(keysym, pressed) {
KeyboardEvent(keysym: number, pressed: boolean) {
this.displayVnc.sendKeyEvent(keysym, pressed);
}
}

View file

@ -25,7 +25,7 @@ const kMaxFailCount = 5;
let gVMShouldSnapshot = false;
async function Sleep(ms) {
async function Sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@ -145,7 +145,7 @@ export class QemuVM extends EventEmitter {
if (this.state !== stateShouldBe) throw new Error(message);
}
private SetState(state) {
private SetState(state: VMState) {
this.state = state;
this.emit('statechange', this.state);
}
@ -158,7 +158,7 @@ export class QemuVM extends EventEmitter {
return `${kVmTmpPathBase}/socket2-${this.definition.id}-vnc`;
}
private async StartQemu(split) {
private async StartQemu(split: Array<string>) {
let self = this;
this.SetState(VMState.Starting);
@ -227,11 +227,11 @@ export class QemuVM extends EventEmitter {
switch (ev.event) {
// Handle the STOP event sent when using -no-shutdown
case 'STOP':
await self.qmpInstance.Execute('system_reset');
await self.qmpInstance?.Execute('system_reset');
break;
case 'RESET':
self.VMLog('got a reset event!');
await self.qmpInstance.Execute('cont');
await self.qmpInstance?.Execute('cont');
break;
}
});
@ -250,7 +250,7 @@ export class QemuVM extends EventEmitter {
try {
await Sleep(500);
this.qmpInstance.ConnectUNIX(this.GetQmpPath());
this.qmpInstance?.ConnectUNIX(this.GetQmpPath());
} catch (err) {
// just try again
await Sleep(500);
@ -261,7 +261,7 @@ export class QemuVM extends EventEmitter {
private async DisconnectDisplay() {
try {
this.display.Disconnect();
this.display?.Disconnect();
this.display = null; // disassociate with that display object.
await unlink(this.GetVncPath());

View file

@ -123,7 +123,7 @@ export default class QmpClient extends Socket {
});
}
Connect(host, port) {
Connect(host: string, port: number) {
super.connect(port, host);
this.ConnectImpl();
}

View file

@ -1,6 +1,6 @@
Copyright 2021 Filipe Calaça Barbosa
Copyright 2022 dither
Copyright 2023 Lily Tsuru/modeco80 <lily.modeco80@protonmail.ch>
Copyright 2023-2024 Lily Tsuru/modeco80 <lily.modeco80@protonmail.ch>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -2,9 +2,10 @@
The source here was originally taken from a fork of [vnc-rfb-client](https://github.com/ayunami2000/vnc-rfb-client) made for the LucidVM project, available [here](https://github.com/lucidvm/rfb).
It has been grossly modified for the usecases for the `@socketcomputer/qemu` package:
It has been grossly modified for the usecases for the socket2 backend, but is more than likely usable to other clients.
- converted to TypeScript
- converted to (strict) TypeScript; my initial port beforehand was not strict and it Sucked
- Also, actually use interfaces, and reduce the amount of code duplicated significantly in the rect decoders.
- all modules rewritten to use ESM
- some noisy debug prints removed
- (some, very tiny) code cleanup

View file

@ -1,3 +1,5 @@
import { IRectDecoder } from './decoders/decoder.js';
import { HextileDecoder } from './decoders/hextile.js';
import { RawDecoder } from './decoders/raw.js';
import { ZrleDecoder } from './decoders/zrle.js';
@ -13,57 +15,79 @@ import * as crypto from 'node:crypto';
import { SocketBuffer } from './socketbuffer.js';
import { VncRectangle, Color3, PixelFormat, Cursor } from './types.js';
export class VncClient extends EventEmitter {
// These are in no particular order.
public debug: Boolean;
public debug: boolean = false;
private _connected: Boolean;
private _authenticated: Boolean;
private _version: string;
private _password: string;
private _connected: boolean = false;
private _authenticated: boolean = false;
private _version: string = "";
private _password: string = "";
private _audioChannels: number;
private _audioFrequency: number;
private _audioChannels: number = 2;
private _audioFrequency: number = 22050;
private _rects: number;
private _rects: number = 0;
private _decoders: any; // no real good way to type this yet. will do it later
private _decoders: Array<IRectDecoder> = [];
private _fps: number;
private _timerInterval: number;
private _timerPointer;
private _timerPointer : NodeJS.Timeout|null = null;
public fb: Buffer;
public fb: Buffer = Buffer.from([]);
private _handshaked: Boolean;
private _waitingServerInit: Boolean;
private _expectingChallenge: Boolean;
private _challengeResponseSent: Boolean;
private _handshaked: boolean = false;
private _waitingServerInit: boolean = false;
private _expectingChallenge: boolean = false;
private _challengeResponseSent: boolean = false;
private _set8BitColor: Boolean;
private _set8BitColor: boolean = false;
private _frameBufferReady = false;
private _firstFrameReceived = false;
private _processingFrame = false;
private _relativePointer: Boolean;
private _relativePointer: boolean = false;
public bigEndianFlag: Boolean;
public bigEndianFlag: boolean = false;
public clientWidth: number;
public clientHeight: number;
public clientName: string;
public clientWidth: number = 0;
public clientHeight: number = 0;
public clientName: string = "";
public pixelFormat: any;
public pixelFormat: PixelFormat = {
bitsPerPixel: 0,
depth: 0,
bigEndianFlag: 0,
trueColorFlag: 0,
redMax: 0,
greenMax: 0,
blueMax: 0,
redShift: 0,
greenShift: 0,
blueShift: 0
};
private _colorMap: any[];
private _audioData: Buffer;
private _colorMap: Color3[] = [];
private _audioData: Buffer = Buffer.from([]);
private _cursor: any;
private _cursor: Cursor = {
width: 0,
height: 0,
x: 0,
y: 0,
cursorPixels: null,
bitmask: null,
posX: 0,
posY: 0
};
public encodings: number[];
private _connection: net.Socket;
private _connection: net.Socket|null = null;
private _socketBuffer: SocketBuffer;
static get consts() {
@ -101,7 +125,7 @@ export class VncClient extends EventEmitter {
* @returns {number}
*/
get localPort() {
return this._connection ? this._connection.localPort : 0;
return this._connection ? this._connection?.localPort : 0;
}
constructor(options: any = { debug: false, fps: 0, encodings: [] }) {
@ -125,7 +149,7 @@ export class VncClient extends EventEmitter {
this._audioFrequency = options.audioFrequency || 22050;
this._rects = 0;
this._decoders = {};
this._decoders[consts.encodings.raw] = new RawDecoder();
// TODO: Implement tight encoding
// this._decoders[encodings.tight] = new tightDecoder();
@ -155,7 +179,7 @@ export class VncClient extends EventEmitter {
* Adjuste the configured FPS
* @param fps {number} - Number of update requests send by second
*/
changeFps(fps) {
changeFps(fps: number) {
if (!Number.isNaN(fps)) {
this._fps = Number(fps);
this._timerInterval = this._fps > 0 ? 1000 / this._fps : 0;
@ -178,7 +202,7 @@ export class VncClient extends EventEmitter {
* @param options
*/
connect(
options /* = {
options: any /* = {
host: '',
password: '',
path: '',
@ -199,31 +223,31 @@ export class VncClient extends EventEmitter {
this._connection = net.connect(options.port || 5900, options.host);
// disable nagle's algorithm for TCP
this._connection.setNoDelay();
this._connection?.setNoDelay();
} else {
// unix socket. bodged in but oh well
this._connection = net.connect(options.path);
}
this._connection.on('connect', () => {
this._connection?.on('connect', () => {
this._connected = true;
this.emit('connected');
});
this._connection.on('close', () => {
this._connection?.on('close', () => {
this.resetState();
this.emit('closed');
});
this._connection.on('timeout', () => {
this._connection?.on('timeout', () => {
this.emit('connectTimeout');
});
this._connection.on('error', (err) => {
this._connection?.on('error', (err) => {
this.emit('connectError', err);
});
this._connection.on('data', async (data) => {
this._connection?.on('data', async (data) => {
this._socketBuffer.pushData(data);
if (!this._handshaked) {
@ -243,7 +267,7 @@ export class VncClient extends EventEmitter {
*/
disconnect() {
if (this._connection) {
this._connection.end();
this._connection?.end();
this.resetState();
this.emit('disconnected');
}
@ -269,7 +293,7 @@ export class VncClient extends EventEmitter {
message.writeUInt16BE(width, 6); // Width
message.writeUInt16BE(height, 8); // Height
this._connection.write(message);
this._connection?.write(message);
this._frameBufferReady = true;
}
@ -283,15 +307,15 @@ export class VncClient extends EventEmitter {
// Handshake, negotiating protocol version
if (this._socketBuffer.toString() === consts.versionString.V3_003) {
this._log('Sending 3.3', true);
this._connection.write(consts.versionString.V3_003);
this._connection?.write(consts.versionString.V3_003);
this._version = '3.3';
} else if (this._socketBuffer.toString() === consts.versionString.V3_007) {
this._log('Sending 3.7', true);
this._connection.write(consts.versionString.V3_007);
this._connection?.write(consts.versionString.V3_007);
this._version = '3.7';
} else if (this._socketBuffer.toString() === consts.versionString.V3_008) {
this._log('Sending 3.8', true);
this._connection.write(consts.versionString.V3_008);
this._connection?.write(consts.versionString.V3_008);
this._version = '3.8';
} else {
// Negotiating auth mechanism
@ -299,10 +323,10 @@ export class VncClient extends EventEmitter {
if (this._socketBuffer.includes(0x02) && this._password) {
this._log('Password provided and server support VNC auth. Choosing VNC auth.', true);
this._expectingChallenge = true;
this._connection.write(Buffer.from([0x02]));
this._connection?.write(Buffer.from([0x02]));
} else if (this._socketBuffer.includes(1)) {
this._log('Password not provided or server does not support VNC auth. Trying none.', true);
this._connection.write(Buffer.from([0x01]));
this._connection?.write(Buffer.from([0x01]));
if (this._version === '3.7') {
this._waitingServerInit = true;
} else {
@ -352,7 +376,7 @@ export class VncClient extends EventEmitter {
response.fill(des1.update(this._socketBuffer.buffer.slice(0, 8)), 0, 8);
response.fill(des2.update(this._socketBuffer.buffer.slice(8, 16)), 8, 16);
this._connection.write(response);
this._connection?.write(response);
this._challengeResponseSent = true;
}
@ -363,7 +387,7 @@ export class VncClient extends EventEmitter {
* Reverse bits order of a byte
* @param buf - Buffer to be flipped
*/
reverseBits(buf) {
reverseBits(buf: Buffer) {
for (let x = 0; x < buf.length; x++) {
let newByte = 0;
newByte += buf[x] & 128 ? 1 : 0;
@ -390,6 +414,7 @@ export class VncClient extends EventEmitter {
this.clientWidth = this._socketBuffer.readUInt16BE();
this.clientHeight = this._socketBuffer.readUInt16BE();
this.pixelFormat.bitsPerPixel = this._socketBuffer.readUInt8();
this.pixelFormat.depth = this._socketBuffer.readUInt8();
this.pixelFormat.bigEndianFlag = this._socketBuffer.readUInt8();
@ -457,7 +482,7 @@ export class VncClient extends EventEmitter {
message.writeUInt8(0, 19); // PixelFormat - Padding
// Envia um setPixelFormat trocando para mapa de cores
this._connection.write(message);
this._connection?.write(message);
this.pixelFormat.bitsPerPixel = 8;
this.pixelFormat.depth = 8;
@ -487,7 +512,7 @@ export class VncClient extends EventEmitter {
message.writeInt32BE(consts.encodings.raw, offset + 4);
}
this._connection.write(message);
this._connection?.write(message);
}
/**
@ -498,7 +523,7 @@ export class VncClient extends EventEmitter {
//this._log(`Sending clientInit`);
this._waitingServerInit = true;
// Shared bit set
this._connection.write('1');
this._connection?.write('1');
}
/**
@ -558,6 +583,10 @@ export class VncClient extends EventEmitter {
data: Buffer.alloc(4)
};
const { width, height, bitmask, cursorPixels } = this._cursor;
if(bitmask == null || cursorPixels == null)
throw new Error('No cursor data to get!');
const data = Buffer.alloc(height * width * 4);
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
@ -568,6 +597,7 @@ export class VncClient extends EventEmitter {
case 8:
console.log(8);
const index = cursorPixels.readUInt8(offset);
// @ts-ignore (This line is extremely suspect anyways. I bet this is horribly broken!!)
const color = this._colorMap[index] | 0xff;
data.writeIntBE(color, offset, 4);
break;
@ -606,12 +636,14 @@ export class VncClient extends EventEmitter {
while (this._rects) {
await this._socketBuffer.waitBytes(12);
const rect: any = {};
rect.x = this._socketBuffer.readUInt16BE();
rect.y = this._socketBuffer.readUInt16BE();
rect.width = this._socketBuffer.readUInt16BE();
rect.height = this._socketBuffer.readUInt16BE();
rect.encoding = this._socketBuffer.readInt32BE();
const rect: VncRectangle = {
x: this._socketBuffer.readUInt16BE(),
y: this._socketBuffer.readUInt16BE(),
width: this._socketBuffer.readUInt16BE(),
height: this._socketBuffer.readUInt16BE(),
encoding: this._socketBuffer.readInt32BE(),
data: null // for now
};
if (rect.encoding === consts.encodings.pseudoQemuAudio) {
this.sendAudio(true);
@ -700,7 +732,7 @@ export class VncClient extends EventEmitter {
this._colorMap[firstColor] = {
r: Math.floor((this._socketBuffer.readUInt16BE() / 65535) * 255),
g: Math.floor((this._socketBuffer.readUInt16BE() / 65535) * 255),
b: Math.floor((this._socketBuffer.readUInt16BE() / 65535) * 255)
b: Math.floor((this._socketBuffer.readUInt16BE() / 65535) * 255),
};
firstColor++;
}
@ -733,7 +765,7 @@ export class VncClient extends EventEmitter {
*/
resetState() {
if (this._connection) {
this._connection.end();
this._connection?.end();
}
if (this._timerPointer) {
@ -782,7 +814,7 @@ export class VncClient extends EventEmitter {
this._rects = 0;
this._colorMap = [];
this.fb = null;
this.fb = Buffer.from([]);
this._socketBuffer?.flush(false);
@ -792,7 +824,9 @@ export class VncClient extends EventEmitter {
x: 0,
y: 0,
cursorPixels: null,
bitmask: null
bitmask: null,
posX: 0,
posY: 0
};
}
@ -803,7 +837,7 @@ export class VncClient extends EventEmitter {
* @param key - Key code (keysym) defined by X Window System, check https://wiki.linuxquestions.org/wiki/List_of_keysyms
* @param down - True if the key is pressed, false if it is not
*/
sendKeyEvent(key, down = false) {
sendKeyEvent(key: number, down: boolean = false) {
const message = Buffer.alloc(8);
message.writeUInt8(4); // Message type
message.writeUInt8(down ? 1 : 0, 1); // Down flag
@ -812,7 +846,7 @@ export class VncClient extends EventEmitter {
message.writeUInt32BE(key, 4); // Key code
this._connection.write(message);
this._connection?.write(message);
}
/**
@ -821,7 +855,7 @@ export class VncClient extends EventEmitter {
* @param yPosition - Y Position
* @param mask - Raw RFB button mask
*/
sendPointerEvent(xPosition, yPosition, buttonMask) {
sendPointerEvent(xPosition: number, yPosition: number, buttonMask: number) {
const message = Buffer.alloc(6);
message.writeUInt8(consts.clientMsgTypes.pointerEvent); // Message type
message.writeUInt8(buttonMask, 1); // Button Mask
@ -832,14 +866,14 @@ export class VncClient extends EventEmitter {
this._cursor.posX = xPosition;
this._cursor.posY = yPosition;
this._connection.write(message);
this._connection?.write(message);
}
/**
* Send client cut message to server
* @param text - latin1 encoded
*/
clientCutText(text) {
clientCutText(text: string) {
const textBuffer = Buffer.from(text, 'latin1');
const message = Buffer.alloc(8 + textBuffer.length);
message.writeUInt8(6); // Message type
@ -849,18 +883,18 @@ export class VncClient extends EventEmitter {
message.writeUInt32BE(textBuffer.length, 4); // Padding
textBuffer.copy(message, 8);
this._connection.write(message);
this._connection?.write(message);
}
sendAudio(enable) {
sendAudio(enable: boolean) {
const message = Buffer.alloc(4);
message.writeUInt8(consts.clientMsgTypes.qemuAudio); // Message type
message.writeUInt8(1, 1); // Submessage Type
message.writeUInt16BE(enable ? 0 : 1, 2); // Operation
this._connection.write(message);
this._connection?.write(message);
}
sendAudioConfig(channels, frequency) {
sendAudioConfig(channels: number, frequency: number) {
const message = Buffer.alloc(10);
message.writeUInt8(consts.clientMsgTypes.qemuAudio); // Message type
message.writeUInt8(1, 1); // Submessage Type
@ -868,7 +902,7 @@ export class VncClient extends EventEmitter {
message.writeUInt8(0 /*U8*/, 4); // Sample Format
message.writeUInt8(channels, 5); // Number of Channels
message.writeUInt32BE(frequency, 6); // Frequency
this._connection.write(message);
this._connection?.write(message);
}
/**
@ -877,7 +911,7 @@ export class VncClient extends EventEmitter {
* @param debug
* @private
*/
_log(text, debug = false) {
_log(text: string, debug = false) {
if (!debug || (debug && this.debug)) {
console.log(text);
}

View file

@ -1,9 +1,11 @@
export class CopyRectDecoder {
getPixelBytePos(x, y, width, height) {
return (y * width + x) * 4;
}
import { SocketBuffer } from "../socketbuffer";
import { IRectDecoder } from "./decoder";
import { getPixelBytePos } from "./util";
async decode(rect, fb, bitsPerPixel, colorMap, screenW, screenH, socket, depth): Promise<void> {
import { VncRectangle, Color3 } from "../types";
export class CopyRectDecoder implements IRectDecoder {
async decode(rect: VncRectangle, fb: Buffer, bitsPerPixel: number, colorMap: Array<Color3>, screenW: number, screenH: number, socket: SocketBuffer, depth: number): Promise<void> {
return new Promise(async (resolve, reject) => {
await socket.waitBytes(4);
rect.data = socket.readNBytesOffset(4);
@ -13,8 +15,8 @@ export class CopyRectDecoder {
for (let h = 0; h < rect.height; h++) {
for (let w = 0; w < rect.width; w++) {
const fbOrigBytePosOffset = this.getPixelBytePos(x + w, y + h, screenW, screenH);
const fbBytePosOffset = this.getPixelBytePos(rect.x + w, rect.y + h, screenW, screenH);
const fbOrigBytePosOffset = getPixelBytePos(x + w, y + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(rect.x + w, rect.y + h, screenW, screenH);
fb.writeUInt8(fb.readUInt8(fbOrigBytePosOffset), fbBytePosOffset);
fb.writeUInt8(fb.readUInt8(fbOrigBytePosOffset + 1), fbBytePosOffset + 1);

View file

@ -0,0 +1,7 @@
import { SocketBuffer } from "../socketbuffer";
import { Color3, VncRectangle } from "../types";
export interface IRectDecoder {
decode(rect: VncRectangle, fb: Buffer, bitsPerPixel: number, colorMap: Array<Color3>, screenW: number, screenH: number, socket: SocketBuffer, depth: number): Promise<void>;
}

View file

@ -1,27 +1,25 @@
export class HextileDecoder {
getPixelBytePos(x, y, width, height) {
return (y * width + x) * 4;
}
import { SocketBuffer } from "../socketbuffer";
import { IRectDecoder } from "./decoder";
import { applyColor, getPixelBytePos } from "./util";
async decode(rect, fb, bitsPerPixel, colorMap, screenW, screenH, socket, depth): Promise<void> {
import { VncRectangle, Color3 } from "../types";
export class HextileDecoder implements IRectDecoder {
async decode(rect: VncRectangle, fb: Buffer, bitsPerPixel: number, colorMap: Array<Color3>, screenW: number, screenH: number, socket: SocketBuffer, depth: number): Promise<void> {
return new Promise(async (resolve, reject) => {
const initialOffset = socket.offset;
let dataSize = 0;
let tiles;
let totalTiles;
let tilesX;
let tilesY;
let lastSubEncoding;
let lastSubEncoding = 0;
const backgroundColor = { r: 0, g: 0, b: 0, a: 255 };
const foregroundColor = { r: 0, g: 0, b: 0, a: 255 };
tilesX = Math.ceil(rect.width / 16);
tilesY = Math.ceil(rect.height / 16);
tiles = tilesX * tilesY;
totalTiles = tiles;
let tilesX = Math.ceil(rect.width / 16);
let tilesY = Math.ceil(rect.height / 16);
let tiles = tilesX * tilesY;
let totalTiles = tiles;
while (tiles) {
await socket.waitBytes(1);
@ -42,7 +40,7 @@ export class HextileDecoder {
// We need to ignore zeroed tile after a raw tile
} else {
// If zeroed tile and last tile was not raw, use the last backgroundColor
this.applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
}
} else if (subEncoding & 0x01) {
// If Raw, ignore all other bits
@ -50,7 +48,7 @@ export class HextileDecoder {
dataSize += th * tw * (bitsPerPixel / 8);
for (let h = 0; h < th; h++) {
for (let w = 0; w < tw; w++) {
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(tx + w, ty + h, screenW, screenH);
if (bitsPerPixel === 8) {
const index = socket.readUInt8();
const color = colorMap[index];
@ -148,7 +146,7 @@ export class HextileDecoder {
}
// Initialize tile with the background color
this.applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
// AnySubrects bit
if (subEncoding & 0x08) {
@ -206,13 +204,13 @@ export class HextileDecoder {
const sw = (wh >> 4) + 1;
const sh = (wh & 0x0f) + 1;
this.applyColor(sw, sh, tx + sx, ty + sy, screenW, screenH, color, fb);
applyColor(sw, sh, tx + sx, ty + sy, screenW, screenH, color, fb);
}
} else {
this.applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
}
} else {
this.applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
applyColor(tw, th, tx, ty, screenW, screenH, backgroundColor, fb);
}
lastSubEncoding = subEncoding;
@ -226,16 +224,5 @@ export class HextileDecoder {
});
}
// Apply color to a rect on buffer
applyColor(tw, th, tx, ty, screenW, screenH, color, fb) {
for (let h = 0; h < th; h++) {
for (let w = 0; w < tw; w++) {
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
fb.writeUInt8(color.r || 255, fbBytePosOffset + 2);
fb.writeUInt8(color.g || 255, fbBytePosOffset + 1);
fb.writeUInt8(color.b || 255, fbBytePosOffset);
fb.writeUInt8(255, fbBytePosOffset + 3);
}
}
}
}

View file

@ -1,16 +1,19 @@
export class RawDecoder {
getPixelBytePos(x, y, width, height) {
return (y * width + x) * 4;
}
import { SocketBuffer } from "../socketbuffer";
import { IRectDecoder } from "./decoder";
import { getPixelBytePos } from "./util";
async decode(rect, fb, bitsPerPixel, colorMap, screenW, screenH, socket, depth): Promise<void> {
import { VncRectangle, Color3 } from "../types";
export class RawDecoder implements IRectDecoder {
async decode(rect: VncRectangle, fb: Buffer, bitsPerPixel: number, colorMap: Array<Color3>, screenW: number, screenH: number, socket: SocketBuffer, depth: number): Promise<void> {
return new Promise(async (resolve, reject) => {
await socket.waitBytes(rect.width * rect.height * (bitsPerPixel / 8));
rect.data = socket.readNBytesOffset(rect.width * rect.height * (bitsPerPixel / 8));
for (let h = 0; h < rect.height; h++) {
for (let w = 0; w < rect.width; w++) {
const fbBytePosOffset = this.getPixelBytePos(rect.x + w, rect.y + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(rect.x + w, rect.y + h, screenW, screenH);
if (bitsPerPixel === 8) {
const bytePosOffset = h * rect.width + w;
const index = rect.data.readUInt8(bytePosOffset);

View file

@ -0,0 +1,19 @@
import { Color3 } from "../types";
export function getPixelBytePos(x: number, y: number, width: number, height: number, stride: number = 4): number {
return (y * width + x) * stride;
}
// Apply color to a rect on buffer
export function applyColor(tw: number, th: number, tx: number, ty: number, screenW: number, screenH: number, color: Color3, fb: Buffer) {
for (let h = 0; h < th; h++) {
for (let w = 0; w < tw; w++) {
const fbBytePosOffset = getPixelBytePos(tx + w, ty + h, screenW, screenH);
fb.writeUInt8(color.r || 255, fbBytePosOffset + 2);
fb.writeUInt8(color.g || 255, fbBytePosOffset + 1);
fb.writeUInt8(color.b || 255, fbBytePosOffset);
fb.writeUInt8(255, fbBytePosOffset + 3);
}
}
}

View file

@ -1,7 +1,11 @@
import * as zlib from 'node:zlib';
import { SocketBuffer } from '../socketbuffer.js';
import { SocketBuffer } from "../socketbuffer";
import { IRectDecoder } from "./decoder";
import { applyColor, getPixelBytePos } from "./util";
export class ZrleDecoder {
import { VncRectangle, Color3, Color4 } from "../types";
export class ZrleDecoder implements IRectDecoder {
private zlib: zlib.Inflate;
private unBuffer: SocketBuffer;
@ -14,11 +18,7 @@ export class ZrleDecoder {
});
}
getPixelBytePos(x, y, width, height) {
return (y * width + x) * 4;
}
async decode(rect, fb, bitsPerPixel, colorMap, screenW, screenH, socket, depth): Promise<void> {
async decode(rect: VncRectangle, fb: Buffer, bitsPerPixel: number, colorMap: Array<Color3>, screenW: number, screenH: number, socket: SocketBuffer, depth: number): Promise<void> {
return new Promise(async (resolve, reject) => {
await socket.waitBytes(4);
@ -35,15 +35,10 @@ export class ZrleDecoder {
this.zlib.write(compressedData, async () => {
this.zlib.flush();
let tiles;
let totalTiles;
let tilesX;
let tilesY;
tilesX = Math.ceil(rect.width / 64);
tilesY = Math.ceil(rect.height / 64);
tiles = tilesX * tilesY;
totalTiles = tiles;
let tilesX = Math.ceil(rect.width / 64);
let tilesY = Math.ceil(rect.height / 64);
let tiles = tilesX * tilesY;
let totalTiles = tiles;
while (tiles) {
await this.unBuffer.waitBytes(1, 'tile begin.');
@ -67,7 +62,7 @@ export class ZrleDecoder {
// Raw
for (let h = 0; h < th; h++) {
for (let w = 0; w < tw; w++) {
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(tx + w, ty + h, screenW, screenH);
if (bitsPerPixel === 8) {
await this.unBuffer.waitBytes(1, 'raw 8bits');
const index = this.unBuffer.readUInt8();
@ -105,11 +100,11 @@ export class ZrleDecoder {
}
} else if (subEncoding === 1) {
// Single Color
let color = { r: 0, g: 0, b: 0, a: 255 };
let color: Color4 = { r: 0, g: 0, b: 0, a: 255 };
if (bitsPerPixel === 8) {
await this.unBuffer.waitBytes(1, 'single color 8bits');
const index = this.unBuffer.readUInt8();
color = colorMap[index];
color = (colorMap[index] as Color4);
} else if (bitsPerPixel === 24 || (bitsPerPixel === 32 && depth === 24)) {
await this.unBuffer.waitBytes(3, 'single color 24bits');
color.r = this.unBuffer.readUInt8();
@ -122,7 +117,7 @@ export class ZrleDecoder {
color.b = this.unBuffer.readUInt8();
color.a = this.unBuffer.readUInt8();
}
this.applyColor(tw, th, tx, ty, screenW, screenH, color, fb);
applyColor(tw, th, tx, ty, screenW, screenH, color, fb);
} else if (subEncoding >= 2 && subEncoding <= 16) {
// Palette
const palette = [];
@ -152,7 +147,7 @@ export class ZrleDecoder {
// const i = (tw * th) / (8 / bitsPerIndex);
// const pixels = [];
let byte;
let byte = 0;
let bitPos = 0;
for (let h = 0; h < th; h++) {
@ -162,7 +157,7 @@ export class ZrleDecoder {
byte = this.unBuffer.readUInt8();
bitPos = 0;
}
let color;
let color : Color4 = { r: 0, g: 0, b: 0, a: 255 };
switch (bitsPerIndex) {
case 1:
if (bitPos === 0) {
@ -216,7 +211,7 @@ export class ZrleDecoder {
}
break;
}
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(tx + w, ty + h, screenW, screenH);
fb.writeUInt8(color.b ?? 0, fbBytePosOffset);
fb.writeUInt8(color.g ?? 0, fbBytePosOffset + 1);
fb.writeUInt8(color.r ?? 0, fbBytePosOffset + 2);
@ -259,7 +254,7 @@ export class ZrleDecoder {
totalRun += runLength;
runs++;
}
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(tx + w, ty + h, screenW, screenH);
fb.writeUInt8(color.b ?? 0, fbBytePosOffset);
fb.writeUInt8(color.g ?? 0, fbBytePosOffset + 1);
fb.writeUInt8(color.r ?? 0, fbBytePosOffset + 2);
@ -321,7 +316,7 @@ export class ZrleDecoder {
totalRun += runLength;
runs++;
}
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
const fbBytePosOffset = getPixelBytePos(tx + w, ty + h, screenW, screenH);
fb.writeUInt8(color.b ?? 0, fbBytePosOffset);
fb.writeUInt8(color.g ?? 0, fbBytePosOffset + 1);
fb.writeUInt8(color.r ?? 0, fbBytePosOffset + 2);
@ -342,16 +337,4 @@ export class ZrleDecoder {
});
}
// Apply color to a rect on buffer
applyColor(tw, th, tx, ty, screenW, screenH, color, fb) {
for (let h = 0; h < th; h++) {
for (let w = 0; w < tw; w++) {
const fbBytePosOffset = this.getPixelBytePos(tx + w, ty + h, screenW, screenH);
fb.writeUInt8(color.b || 255, fbBytePosOffset);
fb.writeUInt8(color.g || 255, fbBytePosOffset + 1);
fb.writeUInt8(color.r || 255, fbBytePosOffset + 2);
fb.writeUInt8(255, fbBytePosOffset + 3);
}
}
}
}

View file

@ -1,9 +1,11 @@
/// this is a pretty poor name.
export class SocketBuffer {
public buffer?: Buffer;
private offset: number;
public buffer: Buffer;
public offset: number; // :(
constructor() {
this.buffer = Buffer.from([]);
this.offset = 0;
this.flush();
}
@ -21,11 +23,11 @@ export class SocketBuffer {
return this.buffer.toString();
}
includes(check) {
includes(check: Buffer|number|string) {
return this.buffer.includes(check);
}
pushData(data) {
pushData(data: Buffer) {
this.buffer = Buffer.concat([this.buffer, data]);
}
@ -77,17 +79,17 @@ export class SocketBuffer {
return data;
}
readNBytes(bytes, offset = this.offset) {
readNBytes(bytes: number, offset = this.offset) {
return this.buffer.slice(offset, offset + bytes);
}
readNBytesOffset(bytes) {
readNBytesOffset(bytes: number) {
const data = this.buffer.slice(this.offset, this.offset + bytes);
this.offset += bytes;
return data;
}
setOffset(n) {
setOffset(n: number) {
this.offset = n;
}
@ -96,7 +98,7 @@ export class SocketBuffer {
}
// name is nullable because there are Many(yay....) times it just isn't passed
waitBytes(bytes, name: any | null = null): Promise<void> {
async waitBytes(bytes: number, name: any | null = null): Promise<void> {
if (this.bytesLeft() >= bytes) {
return;
}
@ -114,17 +116,17 @@ export class SocketBuffer {
});
}
fill(data) {
fill(data: Buffer) {
this.buffer.fill(data, this.offset, this.offset + data.length);
this.offset += data.length;
}
fillMultiple(data, repeats) {
fillMultiple(data: Buffer, repeats: number) {
this.buffer.fill(data, this.offset, this.offset + data.length * repeats);
this.offset += data.length * repeats;
}
sleep(n): Promise<void> {
sleep(n: number): Promise<void> {
return new Promise((resolve, reject) => {
setTimeout(resolve, n);
});

44
qemu/src/rfb/types.ts Normal file
View file

@ -0,0 +1,44 @@
export type Rect = {
x: number,
y: number,
width: number,
height: number,
}
export type VncRectangle = Rect & {
encoding: number,
data: Buffer | null // ?
};
export type PixelFormat = {
bitsPerPixel: number,
depth: number,
bigEndianFlag: number,
trueColorFlag: number,
redMax: number,
greenMax: number,
blueMax: number,
redShift: number,
blueShift: number,
greenShift: number
}
export type Cursor = Rect & {
cursorPixels: Buffer|null,
bitmask: Buffer|null,
posX: number,
posY: number
}
export type Color3 = {
r: number,
g: number,
b: number
}
export type Color4 = Color3 & {
a: number,
};

View file

@ -4,14 +4,28 @@
"private": "true",
"description": "crusttest shared bits",
"type": "module",
"main": "dist/src/index.js",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"targets": {
"types": {},
"shared":{
"context": "browser",
"isLibrary": true,
"outputFormat": "esmodule"
}
},
"dependencies": {
"parcel": "^2.12.0"
},
"devDependencies": {},
"scripts": {
"build": "tsc"
"build": "parcel build src/index.ts --target shared --target types"
},
"author": "",
"license": "ISC"

View file

@ -103,84 +103,90 @@ export type DeserializedMessage = AnyMessage;
export const kProtocolHeaderSize = 8;
export class MessageEncoder {
private struct: Struct;
private buffer: ArrayBuffer;
private struct: Struct|null = null;
private buffer: ArrayBuffer|null = null;
Init(byteSize) {
Init(byteSize: number) {
this.buffer = new ArrayBuffer(byteSize + kProtocolHeaderSize);
this.struct = new Struct(this.buffer);
this.InitHeader();
}
SetKeyMessage(keysym, pressed) {
SetKeyMessage(keysym: number, pressed: boolean) {
this.SetTypeCode(MessageType.Key);
this.struct.WriteU16(keysym);
this.struct.WriteU8(pressed == true ? 1 : 0);
this.struct?.WriteU16(keysym);
this.struct?.WriteU8(pressed == true ? 1 : 0);
}
SetMouseMessage(x, y, buttons: MouseButtons) {
SetMouseMessage(x: number, y: number, buttons: MouseButtons) {
this.SetTypeCode(MessageType.Mouse);
this.struct.WriteU16(x);
this.struct.WriteU16(y);
this.struct.WriteU8(buttons);
this.struct?.WriteU16(x);
this.struct?.WriteU16(y);
this.struct?.WriteU8(buttons);
}
SetTurnMessage() {
this.SetTypeCode(MessageType.Turn);
}
SetTurnSrvMessage(ms, usersQueue) {
SetTurnSrvMessage(ms: number, usersQueue: Array<string>) {
this.SetTypeCode(MessageType.Turn);
this.struct.WriteU32(ms);
this.struct.WriteArray(usersQueue, this.struct.WriteString);
this.struct?.WriteU32(ms);
this.struct?.WriteArray(usersQueue, this.struct?.WriteString);
}
SetDisplayRectMessage(x, y, buffer: ArrayBuffer) {
SetDisplayRectMessage(x: number, y: number, buffer: ArrayBuffer) {
this.SetTypeCode(MessageType.DisplayRect);
this.struct.WriteU16(x);
this.struct.WriteU16(y);
this.struct.WriteBuffer(buffer);
this.struct?.WriteU16(x);
this.struct?.WriteU16(y);
this.struct?.WriteBuffer(buffer);
}
SetDisplaySizeMessage(w, h) {
SetDisplaySizeMessage(w: number, h: number) {
this.SetTypeCode(MessageType.DisplaySize);
this.struct.WriteU16(w);
this.struct.WriteU16(h);
this.struct?.WriteU16(w);
this.struct?.WriteU16(h);
}
SetAddUserMessage(user: string) {
this.SetTypeCode(MessageType.AddUser);
this.struct.WriteString(user);
this.struct?.WriteString(user);
}
SetRemUserMessage(user: string) {
this.SetTypeCode(MessageType.RemUser);
this.struct.WriteString(user);
this.struct?.WriteString(user);
}
// Setup some stuff and then return the final message
Finish() {
let endOffset = this.struct.Tell();
this.struct.Seek(4); // seek to size offset
this.struct.WriteU32(endOffset - kProtocolHeaderSize);
this.struct.Seek(endOffset);
return this.buffer.slice(0, endOffset);
if(this.struct == null || this.buffer == null)
throw new Error('no');
let endOffset :number = this.struct?.Tell();
this.struct?.Seek(4); // seek to size offset
this.struct?.WriteU32(endOffset - kProtocolHeaderSize);
this.struct?.Seek(endOffset);
return this.buffer?.slice(0, endOffset);
}
private InitHeader() {
this.struct.Seek(0);
this.struct.WriteU16(kProtocolMagic);
this.struct.WriteU16(0); // No message type yet
this.struct.WriteU32(0); // No payload size yet
this.struct?.Seek(0);
this.struct?.WriteU16(kProtocolMagic);
this.struct?.WriteU16(0); // No message type yet
this.struct?.WriteU32(0); // No payload size yet
}
private SetTypeCode(type: MessageType) {
let oldOff = this.struct.Tell();
this.struct.Seek(2); // seek to type offset
this.struct.WriteU16(type);
this.struct.Seek(oldOff);
if(this.struct == null)
throw new Error('no');
let oldOff = this.struct?.Tell();
this.struct?.Seek(2); // seek to type offset
this.struct?.WriteU16(type);
this.struct?.Seek(oldOff);
}
}
@ -189,14 +195,17 @@ export class MessageDecoder {
static async ReadMessage(buffer: ArrayBuffer, asClient: boolean): Promise<DeserializedMessage> {
return new Promise((res, rej) => {
MessageDecoder.ReadMessageSync(buffer, asClient, (err: Error, message: DeserializedMessage) => {
MessageDecoder.ReadMessageSync(buffer, asClient, (err: Error|null, message: DeserializedMessage|null) => {
if (err) rej(err);
res(message);
if(message != null) {
res(message);
}
});
});
}
private static ReadMessageSync(buffer: ArrayBuffer, asClient: boolean, callback: (err: Error, message:DeserializedMessage) => void) {
private static ReadMessageSync(buffer: ArrayBuffer, asClient: boolean, callback: (err: Error|null, message: DeserializedMessage|null) => void) {
let struct = new Struct(buffer);
// Read and verify the header

View file

@ -36,7 +36,7 @@ export class Struct {
return s;
}
ReadStringLen(maxStringLength) {
ReadStringLen(maxStringLength: number) {
let stringLength = this.ReadU32();
let s = '';
@ -97,20 +97,21 @@ export class Struct {
// then copying
// Add an array with a fixed type
WriteArray(arr, functor) {
WriteArray(arr: any[], functor: any) {
this.WriteU32(arr.length);
for (let elem of arr) functor.call(this, elem);
}
// Add a pascal UTF-16 string.
WriteString(str) {
WriteString(str: string) {
this.WriteU32(str.length);
for (let i in str) this.WriteU16(str.charCodeAt(i));
for (var i = 0; i < str.length; ++i)
this.WriteU16(str.charCodeAt(i));
}
// writes a string with a max length.
// will trim strings that are too long
WriteStringLen(str, len) {
WriteStringLen(str: string, len: number) {
let length = len;
// pick the string length, but ONLY
@ -125,38 +126,39 @@ export class Struct {
this.WriteU16(str.charCodeAt(i));
}
WriteU8(i) {
WriteU8(i: number) {
this.dv.setUint8(this.byteOffset, i);
this.byteOffset++;
}
WriteS8(i) {
WriteS8(i: number) {
this.dv.setInt8(this.byteOffset, i);
this.byteOffset++;
}
WriteU16(i) {
WriteU16(i: number) {
this.dv.setUint16(this.byteOffset, i, false);
this.byteOffset += 2;
}
WriteS16(i) {
WriteS16(i: number) {
this.dv.setInt16(this.byteOffset, i, false);
this.byteOffset += 2;
}
WriteU32(i) {
WriteU32(i: number) {
this.dv.setUint32(this.byteOffset, i, false);
this.byteOffset += 4;
}
WriteS32(i) {
WriteS32(i: number) {
this.dv.setInt32(this.byteOffset, i, false);
this.byteOffset += 4;
}
WriteBuffer(buffer: ArrayBuffer) {
let u8ar = new Uint8Array(buffer);
this.WriteU32(buffer.byteLength);
for (let i = 0; i < buffer.byteLength; ++i) this.WriteU8(buffer[i]);
for (let i = 0; i < buffer.byteLength; ++i) this.WriteU8(u8ar[i]);
}
}

View file

@ -1,13 +0,0 @@
// This is the base tsconfig
{
"compilerOptions": {
"target": "ES2021",
"module": "ES2020",
"moduleResolution": "Node",
"declaration": true,
"sourceMap": true,
// more compiler options?
"strict": false, // maybe enable later..?
}
}

View file

@ -1,27 +1,10 @@
// This is the base tsconfig the entire Socket2 project uses
{
"files": [],
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"noEmitOnError": true,
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"@socketcomputer/shared*": [ "shared/src/*" ],
"@socketcomputer/backend*": [ "backend/src/*" ],
"@socketcomputer/qemu*": [ "qemu/src/*" ]
},
},
"exclude": [
"node_modules",
"dist"
],
"references": [
{ "path": "./backend" },
{ "path": "./qemu" },
{ "path": "./shared" },
]
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"strict": true,
}
}

View file

@ -15,6 +15,5 @@
"typescript": "^5.4.3"
},
"dependencies": {
"nanoevents": "^9.0.0"
}
}

View file

@ -3,12 +3,10 @@ import * as Shared from '@socketcomputer/shared';
import {GetKeysym} from "./keyboard";
import {Mouse} from "./mouse";
type UserRecord = {
username: string
};
let turnInt: number = -1;
async function sleep(ms: number) : Promise<void> {
return new Promise((res) => {
@ -16,7 +14,10 @@ async function sleep(ms: number) : Promise<void> {
});
}
function waitingTimer(text, ms, dot: boolean = true) {
let turnInt: number = -1;
function waitingTimer(text: string, ms: number, dot: boolean = true) {
let dots = '';
let timer = document.querySelector('.turn-timer') as HTMLDivElement;
@ -24,6 +25,7 @@ function waitingTimer(text, ms, dot: boolean = true) {
clearInterval(turnInt);
}
// @ts-ignore (for some reason it's assuming these are Node)
turnInt = setInterval(() => {
ms -= 1000;
let seconds = Math.floor(ms / 1000);
@ -47,7 +49,7 @@ function waitingTimer(text, ms, dot: boolean = true) {
// client for
class SocketClient {
private websocket: WebSocket = null;
private websocket: WebSocket|null = null;
private url = "";
private selfNamed = false;
@ -57,8 +59,8 @@ class SocketClient {
private hasTurn = false;
private mouse = new Mouse();
private canvas:HTMLCanvasElement = null;
private canvasCtx : CanvasRenderingContext2D = null;
private canvas:HTMLCanvasElement|null = null;
private canvasCtx : CanvasRenderingContext2D|null = null;
constructor(url: string, canvas: HTMLCanvasElement) {
@ -219,9 +221,9 @@ class SocketClient {
}
private async onWsClose() {
this.websocket.removeEventListener("open", this.onWsOpen);
this.websocket.removeEventListener("message", this.onWsMessage);
this.websocket.removeEventListener("close", this.onWsClose);
this.websocket?.removeEventListener("open", this.onWsOpen);
this.websocket?.removeEventListener("message", this.onWsMessage);
this.websocket?.removeEventListener("close", this.onWsClose);
this.websocket = null;
// reset state
@ -245,7 +247,7 @@ class SocketClient {
async SendBuffer(buffer: ArrayBuffer): Promise<void> {
return new Promise((res, rej) => {
this.websocket.send(buffer);
this.websocket?.send(buffer);
res();
});
}
@ -275,8 +277,10 @@ class SocketClient {
}
private resizeDisplay(message: Shared.DisplaySizeMessage) {
this.canvas.width = message.width;
this.canvas.height = message.height;
if(this.canvas == null)
return;
this.canvas!.width = message.width;
this.canvas!.height = message.height;
}
private updateUserCount() {
@ -327,7 +331,7 @@ class SocketClient {
let blob = new Blob([message.data]);
createImageBitmap(blob)
.then((image) => {
this.canvasCtx.drawImage(image, message.x, message.y);
this.canvasCtx?.drawImage(image, message.x, message.y);
}).catch((err) => {
console.error(`Error decoding rect for some reason...`, err);
});

View file

@ -1,19 +1,6 @@
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
"composite": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"lib": ["DOM", "ESNext"],
"module": "ESNext",
"moduleResolution": "Node",
"target": "ES6",
"outDir": "./dist",
"baseUrl": "."
},
"references": [
{ "path": "../shared" }
]
"extends": "../tsconfig.json",
"compilerOptions": {
"lib": ["DOM"],
}
}

323
yarn.lock
View file

@ -83,11 +83,36 @@
dependencies:
"@lezer/common" "^1.0.0"
"@lmdb/lmdb-darwin-arm64@2.8.5":
version "2.8.5"
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.8.5.tgz#895d8cb16a9d709ce5fedd8b60022903b875e08e"
integrity sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==
"@lmdb/lmdb-darwin-x64@2.8.5":
version "2.8.5"
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.8.5.tgz#ca243534c8b37d5516c557e4624256d18dd63184"
integrity sha512-w/sLhN4T7MW1nB3R/U8WK5BgQLz904wh+/SmA2jD8NnF7BLLoUgflCNxOeSPOWp8geP6nP/+VjWzZVip7rZ1ug==
"@lmdb/lmdb-linux-arm64@2.8.5":
version "2.8.5"
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.8.5.tgz#b44a8023057e21512eefb9f6120096843b531c1e"
integrity sha512-vtbZRHH5UDlL01TT5jB576Zox3+hdyogvpcbvVJlmU5PdL3c5V7cj1EODdh1CHPksRl+cws/58ugEHi8bcj4Ww==
"@lmdb/lmdb-linux-arm@2.8.5":
version "2.8.5"
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.8.5.tgz#17bd54740779c3e4324e78e8f747c21416a84b3d"
integrity sha512-c0TGMbm2M55pwTDIfkDLB6BpIsgxV4PjYck2HiOX+cy/JWiBXz32lYbarPqejKs9Flm7YVAKSILUducU9g2RVg==
"@lmdb/lmdb-linux-x64@2.8.5":
version "2.8.5"
resolved "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.8.5.tgz"
integrity sha512-Xkc8IUx9aEhP0zvgeKy7IQ3ReX2N8N1L0WPcQwnZweWmOuKfwpS3GRIYqLtK5za/w3E60zhFfNdS+3pBZPytqQ==
"@lmdb/lmdb-win32-x64@2.8.5":
version "2.8.5"
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz#8233e8762440b0f4632c47a09b1b6f23de8b934c"
integrity sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==
"@mapbox/node-pre-gyp@^1.0.0":
version "1.0.11"
resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz"
@ -112,11 +137,36 @@
"@lezer/lr" "^1.0.0"
json5 "^2.2.1"
"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38"
integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==
"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3"
integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==
"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367"
integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==
"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399"
integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==
"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2":
version "3.0.2"
resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz"
integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==
"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407"
integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==
"@parcel/bundler-default@2.12.0":
version "2.12.0"
resolved "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.12.0.tgz"
@ -190,7 +240,7 @@
"@parcel/transformer-react-refresh-wrap" "2.12.0"
"@parcel/transformer-svg" "2.12.0"
"@parcel/core@^2.12.0", "@parcel/core@2.12.0":
"@parcel/core@2.12.0":
version "2.12.0"
resolved "https://registry.npmjs.org/@parcel/core/-/core-2.12.0.tgz"
integrity sha512-s+6pwEj+GfKf7vqGUzN9iSEPueUssCCQrCBUlcAfKrJe0a22hTUCjewpB0I7lNrCIULt8dkndD+sMdOrXsRl6Q==
@ -415,6 +465,13 @@
"@parcel/utils" "2.12.0"
posthtml "^0.16.4"
"@parcel/packager-ts@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@parcel/packager-ts/-/packager-ts-2.12.0.tgz#7422c07ff3a327fdb592f6d707d31bc146590a17"
integrity sha512-8wR0BNN2NBD+IIU0tjioK+lRD4p2Qi/fKxDH5ixEW912tRV+Vd4kE8k++U6YQIpSlK4FRnjFod5zYYhNSLuiXg==
dependencies:
"@parcel/plugin" "2.12.0"
"@parcel/packager-wasm@2.12.0":
version "2.12.0"
resolved "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.12.0.tgz"
@ -667,6 +724,25 @@
posthtml-render "^3.0.0"
semver "^7.5.2"
"@parcel/transformer-typescript-types@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@parcel/transformer-typescript-types/-/transformer-typescript-types-2.12.0.tgz#63e3fc4d1c5d61e1d3a2d56ff58454cf58b514ca"
integrity sha512-uxF4UBMYvbjiV3zHTWMrZX8cFD92VUvD3ArcGi5WEtuVROUm9Sc47o0mOzxKfMFlJu2KOfZVHYlzK9f/UKA2kQ==
dependencies:
"@parcel/diagnostic" "2.12.0"
"@parcel/plugin" "2.12.0"
"@parcel/source-map" "^2.1.1"
"@parcel/ts-utils" "2.12.0"
"@parcel/utils" "2.12.0"
nullthrows "^1.1.1"
"@parcel/ts-utils@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@parcel/ts-utils/-/ts-utils-2.12.0.tgz#47878a6f3baff77d2fa6f9878fe235c9c5d75da8"
integrity sha512-zou+W6dcqnXXUOfN5zGM+ePIWbYOhGp8bVB2jICoNkoKmNAHd4l4zeHl5yQXnbZfynVw88cZVqxtXS8tYebelg==
dependencies:
nullthrows "^1.1.1"
"@parcel/types@2.12.0":
version "2.12.0"
resolved "https://registry.npmjs.org/@parcel/types/-/types-2.12.0.tgz"
@ -694,6 +770,41 @@
chalk "^4.1.0"
nullthrows "^1.1.1"
"@parcel/watcher-android-arm64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84"
integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==
"@parcel/watcher-darwin-arm64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34"
integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==
"@parcel/watcher-darwin-x64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020"
integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==
"@parcel/watcher-freebsd-x64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8"
integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==
"@parcel/watcher-linux-arm-glibc@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d"
integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==
"@parcel/watcher-linux-arm64-glibc@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7"
integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==
"@parcel/watcher-linux-arm64-musl@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635"
integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==
"@parcel/watcher-linux-x64-glibc@2.4.1":
version "2.4.1"
resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz"
@ -704,6 +815,21 @@
resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz"
integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==
"@parcel/watcher-win32-arm64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc"
integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==
"@parcel/watcher-win32-ia32@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7"
integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==
"@parcel/watcher-win32-x64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf"
integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==
"@parcel/watcher@^2.0.7":
version "2.4.1"
resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz"
@ -739,35 +865,30 @@
"@parcel/utils" "2.12.0"
nullthrows "^1.1.1"
"@socketcomputer/backend@file:/home/lily/source/socket-revamp/backend":
version "1.0.0"
resolved "file:backend"
dependencies:
"@fastify/websocket" "^10.0.1"
"@julusian/jpeg-turbo" "^2.1.0"
"@socketcomputer/qemu" "*"
"@socketcomputer/shared" "*"
canvas "^2.11.2"
fastify "^4.26.2"
mnemonist "^0.39.8"
"@swc/core-darwin-arm64@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.11.tgz#91ef40816e10495a4038a98dc6c8dfcc85d9c59b"
integrity sha512-C1j1Qp/IHSelVWdEnT7f0iONWxQz6FAqzjCF2iaL+0vFg4V5f2nlgrueY8vj5pNNzSGhrAlxsMxEIp4dj1MXkg==
"@socketcomputer/qemu@*", "@socketcomputer/qemu@file:/home/lily/source/socket-revamp/qemu":
version "1.0.0"
resolved "file:qemu"
dependencies:
canvas "^2.11.2"
execa "^8.0.1"
split "^1.0.1"
"@swc/core-darwin-x64@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.11.tgz#6f71e3cd4687ef5df226ba0b8a20adc52fa7dc9e"
integrity sha512-0TTy3Ni8ncgaMCchSQ7FK8ZXQLlamy0FXmGWbR58c+pVZWYZltYPTmheJUvVcR0H2+gPAymRKyfC0iLszDALjg==
"@socketcomputer/shared@*", "@socketcomputer/shared@file:/home/lily/source/socket-revamp/shared":
version "1.0.0"
resolved "file:shared"
"@swc/core-linux-arm-gnueabihf@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.11.tgz#08521822b5510cb506bc49e728f416636ff0306f"
integrity sha512-XJLB71uw0rog4DjYAPxFGAuGCBQpgJDlPZZK6MTmZOvI/1t0+DelJ24IjHIxk500YYM26Yv47xPabqFPD7I2zQ==
"@socketcomputer/webapp@file:/home/lily/source/socket-revamp/webapp":
version "1.0.0"
resolved "file:webapp"
dependencies:
nanoevents "^9.0.0"
"@swc/core-linux-arm64-gnu@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.11.tgz#9485bc591aa573b282d08b168b80a60badb8df9b"
integrity sha512-vYQwzJvm/iu052d5Iw27UFALIN5xSrGkPZXxLNMHPySVko2QMNNBv35HLatkEQHbQ3X+VKSW9J9SkdtAvAVRAQ==
"@swc/core-linux-arm64-musl@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.11.tgz#85eecad7aaab7e94b1ff15ab9d95e80a1e95f356"
integrity sha512-eV+KduiRYUFjPsvbZuJ9aknQH9Tj0U2/G9oIZSzLx/18WsYi+upzHbgxmIIHJ2VJgfd7nN40RI/hMtxNsUzR/g==
"@swc/core-linux-x64-gnu@1.4.11":
version "1.4.11"
@ -779,6 +900,21 @@
resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.11.tgz"
integrity sha512-UkVJToKf0owwQYRnGvjHAeYVDfeimCEcx0VQSbJoN7Iy0ckRZi7YPlmWJU31xtKvikE2bQWCOVe0qbSDqqcWXA==
"@swc/core-win32-arm64-msvc@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.11.tgz#d836b79d8730bf83e6b38a5b888e83944d6fb233"
integrity sha512-35khwkyly7lF5NDSyvIrukBMzxPorgc5iTSDfVO/LvnmN5+fm4lTlrDr4tUfTdOhv3Emy7CsKlsNAeFRJ+Pm+w==
"@swc/core-win32-ia32-msvc@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.11.tgz#bc60bbdc65134aaa5b214e2aaf209acfce401d17"
integrity sha512-Wx8/6f0ufgQF2pbVPsJ2dAmFLwIOW+xBE5fxnb7VnEbGkTgP1qMDWiiAtD9rtvDSuODG3i1AEmAak/2HAc6i6A==
"@swc/core-win32-x64-msvc@1.4.11":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.11.tgz#92fd6d4e2d70bbd4fda438f02310d998db8c7b7c"
integrity sha512-0xRFW6K9UZQH2NVC/0pVB0GJXS45lY24f+6XaPBF1YnMHd8A8GoHl7ugyM5yNUTe2AKhSgk5fJV00EJt/XBtdQ==
"@swc/core@^1.3.36":
version "1.4.11"
resolved "https://registry.npmjs.org/@swc/core/-/core-1.4.11.tgz"
@ -829,6 +965,21 @@
dependencies:
undici-types "~5.26.4"
"@types/split@^1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/split/-/split-1.0.5.tgz#4bd47164b81d6381db37978d5344b374b6825f6c"
integrity sha512-gMiDr4vA6YofTpAkPQtP+5pvStIf3CMYphf32YAG/3RwogNL8ii1CQKDc+sxN62KuxPoRaJXcf2zDCDkEBH4FA==
dependencies:
"@types/node" "*"
"@types/through" "*"
"@types/through@*":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.33.tgz#14ebf599320e1c7851e7d598149af183c6b9ea56"
integrity sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==
dependencies:
"@types/node" "*"
"@types/ws@^8.5.10":
version "8.5.10"
resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz"
@ -1011,7 +1162,7 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
browserslist@^4.6.6, "browserslist@>= 4.21.0":
browserslist@^4.6.6:
version "4.23.0"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz"
integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==
@ -1029,6 +1180,11 @@ buffer@^6.0.3:
base64-js "^1.3.1"
ieee754 "^1.2.1"
builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
@ -1137,16 +1293,16 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-support@^1.1.2, color-support@^1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz"
@ -1229,7 +1385,7 @@ csso@^4.2.0:
dependencies:
css-tree "^1.1.2"
debug@^4, debug@^4.0.0, debug@4:
debug@4, debug@^4, debug@^4.0.0:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -1263,12 +1419,7 @@ detect-libc@^1.0.3:
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz"
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
detect-libc@^2.0.0:
version "2.0.3"
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz"
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
detect-libc@^2.0.1:
detect-libc@^2.0.0, detect-libc@^2.0.1:
version "2.0.3"
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz"
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
@ -1527,6 +1678,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
gauge@^3.0.0:
version "3.0.2"
resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz"
@ -1675,7 +1831,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@^2.0.3, inherits@2:
inherits@2, inherits@^2.0.3, inherits@^2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -1791,6 +1947,36 @@ light-my-request@^5.11.0:
process-warning "^3.0.0"
set-cookie-parser "^2.4.1"
lightningcss-darwin-arm64@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.24.1.tgz#551735defa1e092ecf91244ca081f65f10ebd5f0"
integrity sha512-1jQ12jBy+AE/73uGQWGSafK5GoWgmSiIQOGhSEXiFJSZxzV+OXIx+a9h2EYHxdJfX864M+2TAxWPWb0Vv+8y4w==
lightningcss-darwin-x64@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.24.1.tgz#5acb1338ac0aae38e405efd854ed97ba11509eea"
integrity sha512-R4R1d7VVdq2mG4igMU+Di8GPf0b64ZLnYVkubYnGG0Qxq1KaXQtAzcLI43EkpnoWvB/kUg8JKCWH4S13NfiLcQ==
lightningcss-freebsd-x64@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.24.1.tgz#ff692c41ed0bbf37ab5a239db4c2fc04c11195e6"
integrity sha512-z6NberUUw5ALES6Ixn2shmjRRrM1cmEn1ZQPiM5IrZ6xHHL5a1lPin9pRv+w6eWfcrEo+qGG6R9XfJrpuY3e4g==
lightningcss-linux-arm-gnueabihf@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.24.1.tgz#ba41556f4422a6a889553ad897898a314386153e"
integrity sha512-NLQLnBQW/0sSg74qLNI8F8QKQXkNg4/ukSTa+XhtkO7v3BnK19TS1MfCbDHt+TTdSgNEBv0tubRuapcKho2EWw==
lightningcss-linux-arm64-gnu@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.24.1.tgz#6b569b6078634233bc470c4179dd67e535f22d73"
integrity sha512-AQxWU8c9E9JAjAi4Qw9CvX2tDIPjgzCTrZCSXKELfs4mCwzxRkHh2RCxX8sFK19RyJoJAjA/Kw8+LMNRHS5qEg==
lightningcss-linux-arm64-musl@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.24.1.tgz#644abd32c09c87228bfb5dda21e8d3f75da6f731"
integrity sha512-JCgH/SrNrhqsguUA0uJUM1PvN5+dVuzPIlXcoWDHSv2OU/BWlj2dUYr3XNzEw748SmNZPfl2NjQrAdzaPOn1lA==
lightningcss-linux-x64-gnu@1.24.1:
version "1.24.1"
resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.24.1.tgz"
@ -1801,6 +1987,11 @@ lightningcss-linux-x64-musl@1.24.1:
resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.24.1.tgz"
integrity sha512-HLfzVik3RToot6pQ2Rgc3JhfZkGi01hFetHt40HrUMoeKitLoqUUT5owM6yTZPTytTUW9ukLBJ1pc3XNMSvlLw==
lightningcss-win32-x64-msvc@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.24.1.tgz#bd6b562d902e0f92904ac3754c722d9e63e00480"
integrity sha512-joEupPjYJ7PjZtDsS5lzALtlAudAbgIBMGJPNeFe5HfdmJXFd13ECmEM+5rXNxYVMRHua2w8132R6ab5Z6K9Ow==
lightningcss@^1.22.1:
version "1.24.1"
resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.24.1.tgz"
@ -1982,11 +2173,6 @@ nan@^2.17.0:
resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz"
integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==
nanoevents@^9.0.0:
version "9.0.0"
resolved "https://registry.npmjs.org/nanoevents/-/nanoevents-9.0.0.tgz"
integrity sha512-X8pU7IOpgKXVLPxYUI55ymXc8XuBE+uypfEyEFBtHkD1EX9KavYTVc+vXZHFyHKzA1TaZoVDqklLdQBBrxIuAw==
node-addon-api@^5.0.0:
version "5.1.0"
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz"
@ -2492,6 +2678,11 @@ source-map@^0.6.1:
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
split2@^4.0.0:
version "4.2.0"
resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz"
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
split@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz"
@ -2499,12 +2690,7 @@ split@^1.0.1:
dependencies:
through "2"
split2@^4.0.0:
version "4.2.0"
resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz"
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
srcset@4, srcset@4.0.0:
srcset@4:
version "4.0.0"
resolved "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz"
integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==
@ -2514,18 +2700,21 @@ stable@^0.1.8:
resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
stream-http@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5"
integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.4"
readable-stream "^3.6.0"
xtend "^4.0.2"
stream-shift@^1.0.2:
version "1.0.3"
resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz"
integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==
string_decoder@^1.1.1, string_decoder@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
@ -2535,6 +2724,13 @@ string_decoder@^1.1.1, string_decoder@^1.3.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string_decoder@^1.1.1, string_decoder@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
@ -2566,7 +2762,7 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
svgo@^2.4.0, svgo@^3.0.2:
svgo@^2.4.0:
version "2.8.0"
resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz"
integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
@ -2640,7 +2836,7 @@ type-fest@^0.20.2:
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
typescript@^5.4.3, typescript@>=4.9.5:
typescript@^5.4.3:
version "5.4.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz"
integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==
@ -2736,6 +2932,11 @@ ws@^8.0.0:
resolved "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz"
integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==
xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"