Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
import type {
BrokerCallbacks,
BrokerFactory,
BrokerLike,
BrokerSocketLike,
BrokerStartOptions,
TrysteroServerMode,
} from "../../src/types/types.js";
/**
* In-memory deterministic implementation of the `BrokerLike` surface
* used by the daemon. The real broker shims (which would `upgrade`
* the daemon's `http.Server` and pump WebSocket frames between peers)
* are intentionally not pulled into the test environment — they
* require browser-WS clients and binding to an OS socket. Every test
* wires this fake via the injected factory and drives lifecycle
* events directly through the captured callbacks.
*/
export class FakeBroker implements BrokerLike {
public readonly mode: TrysteroServerMode;
public activeConnections = 0;
public startCalls = 0;
public stopCalls = 0;
public startError: Error | undefined;
public stopError: Error | undefined;
public lastStartOptions: BrokerStartOptions | undefined;
public callbacks: BrokerCallbacks | undefined;
private readonly sockets = new Map<string, FakeSocket>();
public constructor(mode: TrysteroServerMode) {
this.mode = mode;
}
public async start(options: BrokerStartOptions): Promise<void> {
this.startCalls += 1;
this.lastStartOptions = options;
this.callbacks = options.callbacks;
if (this.startError !== undefined) {
throw this.startError;
}
}
public async stop(): Promise<void> {
this.stopCalls += 1;
for (const id of [...this.sockets.keys()]) {
this.disconnect(id);
}
if (this.stopError !== undefined) {
throw this.stopError;
}
}
/** Test affordance: simulate a new client connecting. */
public connect(id: string): FakeSocket {
const socket = new FakeSocket(id, () => this.disconnect(id));
this.sockets.set(id, socket);
this.activeConnections += 1;
this.callbacks?.onConnect(socket);
return socket;
}
/** Test affordance: simulate a client disconnecting cleanly. */
public disconnect(id: string): void {
const socket = this.sockets.get(id);
if (socket === undefined) return;
this.sockets.delete(id);
this.activeConnections = Math.max(0, this.activeConnections - 1);
this.callbacks?.onDisconnect(id);
}
/** Test affordance: simulate a valid frame from a client. */
public frame(id: string): void {
this.callbacks?.onFrame(id);
}
/** Test affordance: simulate a malformed frame from a client. */
public malformed(id: string): void {
this.callbacks?.onMalformedFrame(id);
}
}
/**
* Trivial `BrokerSocketLike` implementation backed by a string array
* tests can introspect.
*/
export class FakeSocket implements BrokerSocketLike {
public readonly id: string;
public readonly sent: string[] = [];
public closed = false;
private readonly onClose: () => void;
public constructor(id: string, onClose: () => void) {
this.id = id;
this.onClose = onClose;
}
public send(payload: string): void {
this.sent.push(payload);
}
public close(): void {
if (this.closed) return;
this.closed = true;
this.onClose();
}
}
/**
* Factory helper producing `FakeBroker` instances and recording
* every call so tests can introspect or drive the captured
* reference.
*/
export function makeFakeBrokerFactory(mode: TrysteroServerMode): {
readonly instances: FakeBroker[];
readonly factory: BrokerFactory;
} {
const instances: FakeBroker[] = [];
return {
instances,
factory: (deps) => {
const inst = new FakeBroker(deps.mode);
instances.push(inst);
void mode;
return inst;
},
};
}

View File

@@ -0,0 +1,7 @@
import { webcrypto } from "node:crypto";
type WritableGlobal = { crypto?: Crypto };
const g = globalThis as WritableGlobal;
if (g.crypto === undefined) {
g.crypto = webcrypto as unknown as Crypto;
}