• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vinceau / slp-realtime / 24874401154

24 Apr 2026 05:46AM UTC coverage: 88.418% (+11.4%) from 77.007%
24874401154

push

github

web-flow
refactor: remove slpFolderStream and slpLiveStream (#96)

* update slippi dependency

* extend SlpStream instead of SlpFileWriter

* fix rxjs fromEvent

* fix issues with fromEvent and null/undefined

* remove old node-only files

* move pipeFileContents into test-only file

* fix build and tests from slippi-js changes

* remove lodash

* remove more dependencies

* rename spec to test

* remove more stuff

* remove melee data from slp-realtime

* update to latest slippi-js

* remove as any cast

* use newly exported MoveId from slippi-js

* remove test exclusions

* also lint test files

* fix tsconfig

* update typescript

* update some more dependencies

* more deps updates

* questionable changes

* revert tsconfig.json

* add back test/tsconfig.json

* fix test eslinting not working

* remove dolphin stuff

* fix bundling external

* fix renaming

* remove unused auto-external dependency

196 of 234 branches covered (83.76%)

Branch coverage included in aggregate %.

56 of 63 new or added lines in 9 files covered. (88.89%)

1 existing line in 1 file now uncovered.

430 of 474 relevant lines covered (90.72%)

26363.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.5
/src/operators/inputs.ts
1
import type { FrameEntryType } from "@slippi/slippi-js";
2
import { Frames } from "@slippi/slippi-js";
16✔
3
import type { MonoTypeOperatorFunction, Observable, OperatorFunction } from "rxjs";
4
import { distinctUntilChanged, filter, map, scan } from "rxjs/operators";
16✔
5

6
import type { InputButtonCombo } from "../types";
7
import { bitmaskToButtons, generateInputBitmask } from "../utils";
16✔
8
import { exists } from "../utils/exists";
16✔
9
import { playerFrameFilter } from "./frames";
16✔
10

11
/**
12
 * Throttle inputs for a number of frames
13
 */
14
export function throttleInputButtons(frames: number): MonoTypeOperatorFunction<InputButtonCombo> {
16✔
15
  return (source: Observable<InputButtonCombo>): Observable<InputButtonCombo> =>
4✔
16
    source.pipe(
4✔
17
      distinctUntilChanged((prev, curr) => {
18
        // Should we discard this value?
19
        // Discard if the current frame is still within the lockout duration
20
        return curr.frame < prev.frame + frames;
10✔
21
      }),
22
    );
23
}
24

25
export function mapFramesToButtonInputs(
16✔
26
  index: number,
27
  buttons: string[],
28
  duration = 1,
×
29
): OperatorFunction<FrameEntryType, InputButtonCombo> {
30
  const controlBitMask = generateInputBitmask(...buttons);
8✔
31
  return (source: Observable<FrameEntryType>): Observable<InputButtonCombo> =>
8✔
32
    source.pipe(
8✔
33
      // Filter for the specific player
34
      playerFrameFilter(index),
35
      // Map the frames to whether the button combination was pressed or not
36
      // while tracking the frame number
37
      map(
38
        (
39
          f,
40
        ): {
41
          frame: number;
42
          buttonPressed: boolean;
43
          buttonCombo: string[];
44
        } | null => {
45
          const buttonCombo = f.players[index]?.pre.physicalButtons;
16,244✔
46
          if (!exists(buttonCombo)) {
16,244!
NEW
47
            return null;
×
48
          }
49
          const buttonComboPressed = (buttonCombo & controlBitMask) === controlBitMask;
16,244✔
50
          return {
16,244✔
51
            frame: f.frame,
52
            buttonPressed: buttonComboPressed,
53
            buttonCombo: bitmaskToButtons(buttonCombo),
54
          };
55
        },
56
      ),
57
      filter(exists),
58
      // Count the number of consecutively pressed frames
59
      scan(
60
        (
61
          acc,
62
          data,
63
        ): {
64
          count: number;
65
          frame: number;
66
          buttonCombo: string[];
67
        } => {
68
          const count = data.buttonPressed ? acc.count + 1 : 0;
16,244✔
69
          return {
16,244✔
70
            count,
71
            frame: data.frame,
72
            buttonCombo: data.buttonCombo,
73
          };
74
        },
75
        {
76
          count: 0,
77
          frame: Frames.FIRST,
78
          buttonCombo: [] as string[],
79
        },
80
      ),
81
      // Filter to be the exact frame when we pressed the combination for sufficient frames
82
      filter((n) => n.count === duration),
16,244✔
83
      // Return the player index which triggered the button press
84
      map((data) => ({
4✔
85
        playerIndex: index,
86
        combo: data.buttonCombo,
87
        frame: data.frame,
88
        duration,
89
      })),
90
    );
91
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc