quake2ts 0.0.562 → 0.0.564

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.
@@ -30,24 +30,31 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ HandshakeStage: () => HandshakeStage,
33
34
  InputInjector: () => InputInjector,
34
35
  MockPointerLock: () => MockPointerLock,
35
36
  MockTransport: () => MockTransport,
36
37
  captureAudioEvents: () => captureAudioEvents,
37
38
  captureCanvasDrawCalls: () => captureCanvasDrawCalls,
39
+ captureGameScreenshot: () => captureGameScreenshot,
38
40
  captureGameState: () => captureGameState,
41
+ compareScreenshots: () => compareScreenshots,
39
42
  createBinaryStreamMock: () => createBinaryStreamMock,
40
43
  createBinaryWriterMock: () => createBinaryWriterMock,
41
44
  createControlledTimer: () => createControlledTimer,
45
+ createCustomNetworkCondition: () => createCustomNetworkCondition,
46
+ createDeltaSnapshot: () => createDeltaSnapshot,
42
47
  createEntity: () => createEntity,
43
48
  createEntityStateFactory: () => createEntityStateFactory,
44
49
  createGameStateSnapshotFactory: () => createGameStateSnapshotFactory,
45
50
  createMockAudioContext: () => createMockAudioContext,
46
51
  createMockCanvas: () => createMockCanvas,
47
52
  createMockCanvasContext2D: () => createMockCanvasContext2D,
53
+ createMockConnection: () => createMockConnection,
48
54
  createMockEngine: () => createMockEngine,
49
55
  createMockGame: () => createMockGame,
50
56
  createMockGameState: () => createMockGameState,
57
+ createMockHandshake: () => createMockHandshake,
51
58
  createMockImage: () => createMockImage,
52
59
  createMockImageData: () => createMockImageData,
53
60
  createMockIndexedDB: () => createMockIndexedDB,
@@ -62,13 +69,17 @@ __export(index_exports, {
62
69
  createMockSessionStorage: () => createMockSessionStorage,
63
70
  createMockTransport: () => createMockTransport,
64
71
  createMockUDPSocket: () => createMockUDPSocket,
72
+ createMockUserInfo: () => createMockUserInfo,
65
73
  createMockWebGL2Context: () => createMockWebGL2Context,
74
+ createMultiplayerTestScenario: () => createMultiplayerTestScenario,
66
75
  createNetChanMock: () => createNetChanMock,
67
76
  createPlayerStateFactory: () => createPlayerStateFactory,
68
77
  createPlaywrightTestClient: () => createPlaywrightTestClient,
78
+ createServerSnapshot: () => createServerSnapshot,
69
79
  createSpawnContext: () => createSpawnContext,
70
80
  createStorageTestScenario: () => createStorageTestScenario,
71
81
  createTestContext: () => createTestContext,
82
+ createVisualTestScenario: () => createVisualTestScenario,
72
83
  intersects: () => import_shared3.intersects,
73
84
  ladderTrace: () => import_shared3.ladderTrace,
74
85
  makeAxisBrush: () => makeAxisBrush,
@@ -78,14 +89,24 @@ __export(index_exports, {
78
89
  makeLeafModel: () => makeLeafModel,
79
90
  makeNode: () => makeNode,
80
91
  makePlane: () => makePlane,
92
+ serializeUserInfo: () => serializeUserInfo,
81
93
  setupBrowserEnvironment: () => setupBrowserEnvironment,
82
94
  setupMockAudioContext: () => setupMockAudioContext,
83
95
  setupNodeEnvironment: () => setupNodeEnvironment,
84
96
  simulateFrames: () => simulateFrames,
85
97
  simulateFramesWithMock: () => simulateFramesWithMock,
98
+ simulateHandshake: () => simulateHandshake,
99
+ simulateNetworkCondition: () => simulateNetworkCondition,
100
+ simulatePlayerInput: () => simulatePlayerInput,
101
+ simulatePlayerJoin: () => simulatePlayerJoin,
102
+ simulatePlayerLeave: () => simulatePlayerLeave,
103
+ simulateServerTick: () => simulateServerTick,
104
+ simulateSnapshotDelivery: () => simulateSnapshotDelivery,
86
105
  stairTrace: () => import_shared3.stairTrace,
87
106
  teardownBrowserEnvironment: () => teardownBrowserEnvironment,
88
107
  teardownMockAudioContext: () => teardownMockAudioContext,
108
+ throttleBandwidth: () => throttleBandwidth,
109
+ verifySnapshotConsistency: () => verifySnapshotConsistency,
89
110
  waitForGameReady: () => waitForGameReady
90
111
  });
91
112
  module.exports = __toCommonJS(index_exports);
@@ -692,6 +713,214 @@ function createMockServer(overrides) {
692
713
  };
693
714
  }
694
715
 
716
+ // src/server/mocks/connection.ts
717
+ var import_server2 = require("@quake2ts/server");
718
+ var HandshakeStage = /* @__PURE__ */ ((HandshakeStage2) => {
719
+ HandshakeStage2[HandshakeStage2["None"] = 0] = "None";
720
+ HandshakeStage2[HandshakeStage2["Challenge"] = 1] = "Challenge";
721
+ HandshakeStage2[HandshakeStage2["Connect"] = 2] = "Connect";
722
+ HandshakeStage2[HandshakeStage2["Info"] = 3] = "Info";
723
+ HandshakeStage2[HandshakeStage2["Active"] = 4] = "Active";
724
+ return HandshakeStage2;
725
+ })(HandshakeStage || {});
726
+ function serializeUserInfo(info) {
727
+ return Object.entries(info).reduce((acc, [key, value]) => {
728
+ if (value !== void 0) {
729
+ return `${acc}\\${key}\\${value}`;
730
+ }
731
+ return acc;
732
+ }, "");
733
+ }
734
+ function createMockUserInfo(overrides) {
735
+ return {
736
+ name: "Player",
737
+ skin: "male/grunt",
738
+ model: "male/grunt",
739
+ fov: 90,
740
+ hand: 0,
741
+ rate: 25e3,
742
+ msg: 1,
743
+ ...overrides
744
+ };
745
+ }
746
+ function createMockConnection(state = import_server2.ClientState.Connected, overrides) {
747
+ return createMockServerClient(0, {
748
+ state,
749
+ userInfo: serializeUserInfo(createMockUserInfo()),
750
+ challenge: Math.floor(Math.random() * 1e5),
751
+ ...overrides
752
+ });
753
+ }
754
+ function createMockHandshake(stage = 0 /* None */) {
755
+ return {
756
+ stage,
757
+ clientNum: -1,
758
+ challenge: 0,
759
+ qport: Math.floor(Math.random() * 65536)
760
+ };
761
+ }
762
+ async function simulateHandshake(client, server) {
763
+ const challenge = Math.floor(Math.random() * 1e5);
764
+ client.challenge = challenge;
765
+ if (server && server.clients) {
766
+ }
767
+ client.state = import_server2.ClientState.Connected;
768
+ client.state = import_server2.ClientState.Active;
769
+ return true;
770
+ }
771
+
772
+ // src/server/helpers/multiplayer.ts
773
+ var import_server3 = require("@quake2ts/server");
774
+ function createMultiplayerTestScenario(numPlayers = 2) {
775
+ const baseServer = createMockServerState();
776
+ const clients = [];
777
+ const entities = [];
778
+ const server = {
779
+ ...baseServer,
780
+ clients: new Array(numPlayers).fill(null),
781
+ entities: []
782
+ };
783
+ for (let i = 0; i < numPlayers; i++) {
784
+ const client = createMockServerClient(i, {
785
+ state: import_server3.ClientState.Active,
786
+ userInfo: serializeUserInfo(createMockUserInfo({ name: `Player${i}` }))
787
+ });
788
+ const entity = {
789
+ classname: "player",
790
+ s: { origin: { x: 0, y: 0, z: 0 }, number: i + 1 },
791
+ client
792
+ };
793
+ client.edict = entity;
794
+ server.clients[i] = client;
795
+ clients.push(client);
796
+ entities.push(entity);
797
+ }
798
+ server.entities = entities;
799
+ return {
800
+ server,
801
+ clients,
802
+ entities
803
+ };
804
+ }
805
+ async function simulatePlayerJoin(server, userInfo) {
806
+ const index = server.clients.findIndex((c) => !c || c.state === import_server3.ClientState.Free);
807
+ if (index === -1) {
808
+ throw new Error("Server full");
809
+ }
810
+ const client = createMockServerClient(index, {
811
+ state: import_server3.ClientState.Connected,
812
+ userInfo: serializeUserInfo(createMockUserInfo(userInfo))
813
+ });
814
+ server.clients[index] = client;
815
+ client.state = import_server3.ClientState.Active;
816
+ const entity = {
817
+ classname: "player",
818
+ s: { origin: { x: 0, y: 0, z: 0 }, number: index + 1 },
819
+ client
820
+ };
821
+ client.edict = entity;
822
+ if (server.entities && Array.isArray(server.entities)) {
823
+ server.entities[index + 1] = entity;
824
+ }
825
+ return client;
826
+ }
827
+ function simulatePlayerLeave(server, clientNum) {
828
+ const client = server.clients[clientNum];
829
+ if (client) {
830
+ client.state = import_server3.ClientState.Free;
831
+ client.edict = null;
832
+ }
833
+ }
834
+ function simulateServerTick(server, deltaTime = 0.1) {
835
+ server.time += deltaTime;
836
+ server.frame++;
837
+ server.clients.forEach((client) => {
838
+ if (client && client.state === import_server3.ClientState.Active) {
839
+ }
840
+ });
841
+ }
842
+ function simulatePlayerInput(client, input) {
843
+ const cmd = {
844
+ msec: 100,
845
+ buttons: 0,
846
+ angles: { x: 0, y: 0, z: 0 },
847
+ forwardmove: 0,
848
+ sidemove: 0,
849
+ upmove: 0,
850
+ sequence: client.lastCmd.sequence + 1,
851
+ lightlevel: 0,
852
+ impulse: 0,
853
+ ...input
854
+ };
855
+ client.lastCmd = cmd;
856
+ client.commandQueue.push(cmd);
857
+ client.commandCount++;
858
+ }
859
+
860
+ // src/server/helpers/snapshot.ts
861
+ function createServerSnapshot(serverState, clientNum) {
862
+ const visibleEntities = [];
863
+ if (serverState.baselines) {
864
+ serverState.baselines.forEach((ent, index) => {
865
+ if (ent && index !== clientNum + 1) {
866
+ visibleEntities.push({ ...ent });
867
+ }
868
+ });
869
+ }
870
+ return {
871
+ serverTime: serverState.time,
872
+ playerState: {
873
+ origin: { x: 0, y: 0, z: 0 },
874
+ viewangles: { x: 0, y: 0, z: 0 },
875
+ pm_type: 0
876
+ },
877
+ entities: visibleEntities
878
+ };
879
+ }
880
+ function createDeltaSnapshot(oldSnapshot, newSnapshot) {
881
+ const deltaEntities = [];
882
+ const removedEntities = [];
883
+ const oldMap = new Map(oldSnapshot.entities.map((e) => [e.number, e]));
884
+ const newMap = new Map(newSnapshot.entities.map((e) => [e.number, e]));
885
+ newSnapshot.entities.forEach((newEnt) => {
886
+ const oldEnt = oldMap.get(newEnt.number);
887
+ if (!oldEnt) {
888
+ deltaEntities.push(newEnt);
889
+ } else if (JSON.stringify(newEnt) !== JSON.stringify(oldEnt)) {
890
+ deltaEntities.push(newEnt);
891
+ }
892
+ });
893
+ oldSnapshot.entities.forEach((oldEnt) => {
894
+ if (!newMap.has(oldEnt.number)) {
895
+ removedEntities.push(oldEnt.number);
896
+ }
897
+ });
898
+ return {
899
+ snapshot: newSnapshot,
900
+ deltaEntities,
901
+ removedEntities
902
+ };
903
+ }
904
+ function verifySnapshotConsistency(snapshots) {
905
+ const report = { valid: true, errors: [] };
906
+ if (snapshots.length < 2) return report;
907
+ for (let i = 1; i < snapshots.length; i++) {
908
+ const prev = snapshots[i - 1];
909
+ const curr = snapshots[i];
910
+ if (curr.serverTime <= prev.serverTime) {
911
+ report.valid = false;
912
+ report.errors.push(`Snapshot ${i} has time ${curr.serverTime} <= prev ${prev.serverTime}`);
913
+ }
914
+ }
915
+ return report;
916
+ }
917
+ async function simulateSnapshotDelivery(snapshot, reliability = 1) {
918
+ if (Math.random() > reliability) {
919
+ return null;
920
+ }
921
+ return snapshot;
922
+ }
923
+
695
924
  // src/setup/browser.ts
696
925
  var import_jsdom = require("jsdom");
697
926
  var import_canvas = require("@napi-rs/canvas");
@@ -1169,8 +1398,8 @@ function createMockImage(width, height, src) {
1169
1398
  }
1170
1399
 
1171
1400
  // src/setup/node.ts
1172
- function setupNodeEnvironment() {
1173
- if (typeof global.fetch === "undefined") {
1401
+ function setupNodeEnvironment(options = {}) {
1402
+ if (options.polyfillFetch && typeof global.fetch === "undefined") {
1174
1403
  }
1175
1404
  }
1176
1405
 
@@ -1199,6 +1428,61 @@ function createMockIndexedDB() {
1199
1428
  return indexedDB;
1200
1429
  }
1201
1430
  function createStorageTestScenario(storageType = "local") {
1431
+ if (storageType === "indexed") {
1432
+ const dbName = `test-db-${Math.random().toString(36).substring(7)}`;
1433
+ const storeName = "test-store";
1434
+ const storage2 = createMockIndexedDB();
1435
+ return {
1436
+ storage: storage2,
1437
+ populate: async (data) => {
1438
+ return new Promise((resolve, reject) => {
1439
+ const req = storage2.open(dbName, 1);
1440
+ req.onupgradeneeded = (e) => {
1441
+ const db = e.target.result;
1442
+ db.createObjectStore(storeName);
1443
+ };
1444
+ req.onsuccess = (e) => {
1445
+ const db = e.target.result;
1446
+ const tx = db.transaction(storeName, "readwrite");
1447
+ const store = tx.objectStore(storeName);
1448
+ Object.entries(data).forEach(([k, v]) => store.put(v, k));
1449
+ tx.oncomplete = () => {
1450
+ db.close();
1451
+ resolve();
1452
+ };
1453
+ tx.onerror = () => reject(tx.error);
1454
+ };
1455
+ req.onerror = () => reject(req.error);
1456
+ });
1457
+ },
1458
+ verify: async (key, value) => {
1459
+ return new Promise((resolve, reject) => {
1460
+ const req = storage2.open(dbName, 1);
1461
+ req.onsuccess = (e) => {
1462
+ const db = e.target.result;
1463
+ if (!db.objectStoreNames.contains(storeName)) {
1464
+ db.close();
1465
+ resolve(false);
1466
+ return;
1467
+ }
1468
+ const tx = db.transaction(storeName, "readonly");
1469
+ const store = tx.objectStore(storeName);
1470
+ const getReq = store.get(key);
1471
+ getReq.onsuccess = () => {
1472
+ const result = getReq.result === value;
1473
+ db.close();
1474
+ resolve(result);
1475
+ };
1476
+ getReq.onerror = () => {
1477
+ db.close();
1478
+ resolve(false);
1479
+ };
1480
+ };
1481
+ req.onerror = () => reject(req.error);
1482
+ });
1483
+ }
1484
+ };
1485
+ }
1202
1486
  const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
1203
1487
  return {
1204
1488
  storage,
@@ -1213,7 +1497,7 @@ function createStorageTestScenario(storageType = "local") {
1213
1497
 
1214
1498
  // src/setup/audio.ts
1215
1499
  function createMockAudioContext() {
1216
- return {
1500
+ const context = {
1217
1501
  createGain: () => ({
1218
1502
  connect: () => {
1219
1503
  },
@@ -1262,8 +1546,23 @@ function createMockAudioContext() {
1262
1546
  sampleRate,
1263
1547
  numberOfChannels: channels,
1264
1548
  getChannelData: () => new Float32Array(length)
1265
- })
1549
+ }),
1550
+ // Helper to track events if needed
1551
+ _events: []
1266
1552
  };
1553
+ return new Proxy(context, {
1554
+ get(target, prop, receiver) {
1555
+ if (prop === "_events") return target._events;
1556
+ const value = Reflect.get(target, prop, receiver);
1557
+ if (typeof value === "function") {
1558
+ return (...args) => {
1559
+ target._events.push({ type: String(prop), args });
1560
+ return Reflect.apply(value, target, args);
1561
+ };
1562
+ }
1563
+ return value;
1564
+ }
1565
+ });
1267
1566
  }
1268
1567
  function setupMockAudioContext() {
1269
1568
  if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
@@ -1284,7 +1583,7 @@ function teardownMockAudioContext() {
1284
1583
  }
1285
1584
  }
1286
1585
  function captureAudioEvents(context) {
1287
- return [];
1586
+ return context._events || [];
1288
1587
  }
1289
1588
 
1290
1589
  // src/setup/timing.ts
@@ -1576,26 +1875,143 @@ async function captureGameState(page) {
1576
1875
  return {};
1577
1876
  });
1578
1877
  }
1878
+
1879
+ // src/e2e/network.ts
1880
+ var CONDITIONS = {
1881
+ "good": {
1882
+ offline: false,
1883
+ downloadThroughput: 10 * 1024 * 1024,
1884
+ // 10 Mbps
1885
+ uploadThroughput: 5 * 1024 * 1024,
1886
+ // 5 Mbps
1887
+ latency: 20
1888
+ },
1889
+ "slow": {
1890
+ offline: false,
1891
+ downloadThroughput: 500 * 1024,
1892
+ // 500 Kbps
1893
+ uploadThroughput: 500 * 1024,
1894
+ latency: 400
1895
+ },
1896
+ "unstable": {
1897
+ offline: false,
1898
+ downloadThroughput: 1 * 1024 * 1024,
1899
+ uploadThroughput: 1 * 1024 * 1024,
1900
+ latency: 100
1901
+ },
1902
+ "offline": {
1903
+ offline: true,
1904
+ downloadThroughput: 0,
1905
+ uploadThroughput: 0,
1906
+ latency: 0
1907
+ }
1908
+ };
1909
+ function simulateNetworkCondition(condition) {
1910
+ const config = CONDITIONS[condition];
1911
+ return createCustomNetworkCondition(config.latency, 0, 0, config);
1912
+ }
1913
+ function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
1914
+ return {
1915
+ async apply(page) {
1916
+ const client = await page.context().newCDPSession(page);
1917
+ await client.send("Network.enable");
1918
+ await client.send("Network.emulateNetworkConditions", {
1919
+ offline: baseConfig?.offline || false,
1920
+ latency: latency + Math.random() * jitter,
1921
+ downloadThroughput: baseConfig?.downloadThroughput || -1,
1922
+ uploadThroughput: baseConfig?.uploadThroughput || -1
1923
+ });
1924
+ },
1925
+ async clear(page) {
1926
+ const client = await page.context().newCDPSession(page);
1927
+ await client.send("Network.emulateNetworkConditions", {
1928
+ offline: false,
1929
+ latency: 0,
1930
+ downloadThroughput: -1,
1931
+ uploadThroughput: -1
1932
+ });
1933
+ }
1934
+ };
1935
+ }
1936
+ async function throttleBandwidth(page, bytesPerSecond) {
1937
+ const simulator = createCustomNetworkCondition(0, 0, 0, {
1938
+ offline: false,
1939
+ latency: 0,
1940
+ downloadThroughput: bytesPerSecond,
1941
+ uploadThroughput: bytesPerSecond
1942
+ });
1943
+ await simulator.apply(page);
1944
+ }
1945
+
1946
+ // src/e2e/visual.ts
1947
+ var import_path = __toESM(require("path"), 1);
1948
+ var import_promises = __toESM(require("fs/promises"), 1);
1949
+ async function captureGameScreenshot(page, name, options = {}) {
1950
+ const dir = options.dir || "__screenshots__";
1951
+ const screenshotPath = import_path.default.join(dir, `${name}.png`);
1952
+ await import_promises.default.mkdir(dir, { recursive: true });
1953
+ return await page.screenshot({
1954
+ path: screenshotPath,
1955
+ fullPage: options.fullPage ?? false,
1956
+ animations: "disabled",
1957
+ caret: "hide"
1958
+ });
1959
+ }
1960
+ async function compareScreenshots(baseline, current, threshold = 0.1) {
1961
+ if (baseline.equals(current)) {
1962
+ return { pixelDiff: 0, matched: true };
1963
+ }
1964
+ return {
1965
+ pixelDiff: -1,
1966
+ // Unknown magnitude
1967
+ matched: false
1968
+ };
1969
+ }
1970
+ function createVisualTestScenario(page, sceneName) {
1971
+ return {
1972
+ async capture(snapshotName) {
1973
+ return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
1974
+ },
1975
+ async compare(snapshotName, baselineDir) {
1976
+ const name = `${sceneName}-${snapshotName}`;
1977
+ const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
1978
+ try {
1979
+ const baselinePath = import_path.default.join(baselineDir, `${name}.png`);
1980
+ const baseline = await import_promises.default.readFile(baselinePath);
1981
+ return await compareScreenshots(baseline, current);
1982
+ } catch (e) {
1983
+ return { pixelDiff: -1, matched: false };
1984
+ }
1985
+ }
1986
+ };
1987
+ }
1579
1988
  // Annotate the CommonJS export names for ESM import in node:
1580
1989
  0 && (module.exports = {
1990
+ HandshakeStage,
1581
1991
  InputInjector,
1582
1992
  MockPointerLock,
1583
1993
  MockTransport,
1584
1994
  captureAudioEvents,
1585
1995
  captureCanvasDrawCalls,
1996
+ captureGameScreenshot,
1586
1997
  captureGameState,
1998
+ compareScreenshots,
1587
1999
  createBinaryStreamMock,
1588
2000
  createBinaryWriterMock,
1589
2001
  createControlledTimer,
2002
+ createCustomNetworkCondition,
2003
+ createDeltaSnapshot,
1590
2004
  createEntity,
1591
2005
  createEntityStateFactory,
1592
2006
  createGameStateSnapshotFactory,
1593
2007
  createMockAudioContext,
1594
2008
  createMockCanvas,
1595
2009
  createMockCanvasContext2D,
2010
+ createMockConnection,
1596
2011
  createMockEngine,
1597
2012
  createMockGame,
1598
2013
  createMockGameState,
2014
+ createMockHandshake,
1599
2015
  createMockImage,
1600
2016
  createMockImageData,
1601
2017
  createMockIndexedDB,
@@ -1610,13 +2026,17 @@ async function captureGameState(page) {
1610
2026
  createMockSessionStorage,
1611
2027
  createMockTransport,
1612
2028
  createMockUDPSocket,
2029
+ createMockUserInfo,
1613
2030
  createMockWebGL2Context,
2031
+ createMultiplayerTestScenario,
1614
2032
  createNetChanMock,
1615
2033
  createPlayerStateFactory,
1616
2034
  createPlaywrightTestClient,
2035
+ createServerSnapshot,
1617
2036
  createSpawnContext,
1618
2037
  createStorageTestScenario,
1619
2038
  createTestContext,
2039
+ createVisualTestScenario,
1620
2040
  intersects,
1621
2041
  ladderTrace,
1622
2042
  makeAxisBrush,
@@ -1626,14 +2046,24 @@ async function captureGameState(page) {
1626
2046
  makeLeafModel,
1627
2047
  makeNode,
1628
2048
  makePlane,
2049
+ serializeUserInfo,
1629
2050
  setupBrowserEnvironment,
1630
2051
  setupMockAudioContext,
1631
2052
  setupNodeEnvironment,
1632
2053
  simulateFrames,
1633
2054
  simulateFramesWithMock,
2055
+ simulateHandshake,
2056
+ simulateNetworkCondition,
2057
+ simulatePlayerInput,
2058
+ simulatePlayerJoin,
2059
+ simulatePlayerLeave,
2060
+ simulateServerTick,
2061
+ simulateSnapshotDelivery,
1634
2062
  stairTrace,
1635
2063
  teardownBrowserEnvironment,
1636
2064
  teardownMockAudioContext,
2065
+ throttleBandwidth,
2066
+ verifySnapshotConsistency,
1637
2067
  waitForGameReady
1638
2068
  });
1639
2069
  //# sourceMappingURL=index.cjs.map