@kar-mi/spirit-vale-tools-capture 2.5.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capture/drop-diagnostics.d.ts +42 -0
- package/dist/capture/drop-diagnostics.d.ts.map +1 -0
- package/dist/capture/duplicate-filter.d.ts +39 -0
- package/dist/capture/duplicate-filter.d.ts.map +1 -0
- package/dist/capture/packet-capture.d.ts +24 -1
- package/dist/capture/packet-capture.d.ts.map +1 -1
- package/dist/capture.js +184 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CapturedTransportPacket } from "../types.ts";
|
|
2
|
+
/** Flows tracked before new ones are ignored. */
|
|
3
|
+
export declare const DROP_FLOW_LIMIT = 64;
|
|
4
|
+
/** Flows named in a summary. */
|
|
5
|
+
export declare const DROP_FLOW_REPORT_COUNT = 5;
|
|
6
|
+
/** Sequenced packets a flow must show before its verdict is trusted. */
|
|
7
|
+
export declare const DROP_VERDICT_MIN_SAMPLES = 20;
|
|
8
|
+
/**
|
|
9
|
+
* Fraction of consecutive sequence numbers above which a flow is called game traffic. A real stream
|
|
10
|
+
* sits far above this and traffic that merely parses as LiteNetLib far below, so it is not delicate.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DROP_VERDICT_THRESHOLD = 0.25;
|
|
13
|
+
export interface DroppedFlow {
|
|
14
|
+
flow: string;
|
|
15
|
+
packets: number;
|
|
16
|
+
verdict: "game traffic" | "unrelated" | "unknown";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Explains what unattributed capture is throwing away, without keeping any of it.
|
|
20
|
+
*
|
|
21
|
+
* A high give-up count reads as lost game traffic and usually is not. Per flow this keeps a count
|
|
22
|
+
* and one statistic - how often a LiteNetLib sequence number follows its predecessor - which tells
|
|
23
|
+
* a real stream from traffic that merely parses as one, since nothing else maintains a sequence.
|
|
24
|
+
* No payload is retained, so a summary is safe to share.
|
|
25
|
+
*/
|
|
26
|
+
export declare class DropDiagnostics {
|
|
27
|
+
private readonly flows;
|
|
28
|
+
/** Records a packet that could not be attributed and was given up on. */
|
|
29
|
+
record(packet: CapturedTransportPacket): void;
|
|
30
|
+
/**
|
|
31
|
+
* The busiest dropped flows, worst first, each with a verdict.
|
|
32
|
+
*
|
|
33
|
+
* Counts run for the whole session rather than since the last call, because a verdict needs
|
|
34
|
+
* accumulated sequence samples to settle. Callers reporting a windowed count should say so.
|
|
35
|
+
*/
|
|
36
|
+
topFlows(limit?: number): DroppedFlow[];
|
|
37
|
+
/** Whether any dropped flow looks like game traffic - the only case worth acting on. */
|
|
38
|
+
get hasGameTraffic(): boolean;
|
|
39
|
+
reset(): void;
|
|
40
|
+
private countSequence;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=drop-diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop-diagnostics.d.ts","sourceRoot":"","sources":["../../src/capture/drop-diagnostics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,iDAAiD;AACjD,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,gCAAgC;AAChC,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAS3C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,GAAG,WAAW,GAAG,SAAS,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAEtD,yEAAyE;IACzE,MAAM,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAU5C;IAED;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,SAAyB,GAAG,WAAW,EAAE,CAKtD;IAED,wFAAwF;IACxF,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,OAAO,CAAC,aAAa;CAoBtB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CapturedTransportPacket } from "../types.ts";
|
|
2
|
+
/** How long a payload stays remembered. Relayed copies arrive within about a millisecond. */
|
|
3
|
+
export declare const DUPLICATE_WINDOW_MS = 5;
|
|
4
|
+
/** Entries retained before the oldest are evicted, mirroring the pending-packet ceiling. */
|
|
5
|
+
export declare const DUPLICATE_ENTRY_LIMIT = 16384;
|
|
6
|
+
export interface DuplicateFilterOptions {
|
|
7
|
+
windowMs?: number;
|
|
8
|
+
entryLimit?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Suppresses the redundant copies a redirecting VPN puts on the wire.
|
|
12
|
+
*
|
|
13
|
+
* Relays such as ExitLag rewrite addresses and ports rather than encapsulating, and send a datagram
|
|
14
|
+
* over several routes at once, so one datagram is captured more than once. The key is the payload
|
|
15
|
+
* with the direction and local port, which a relay preserves, never the peer's endpoint, which it
|
|
16
|
+
* rewrites. Direction keeps a peer's echo of an identical control payload distinct; the local port
|
|
17
|
+
* keeps two sockets distinct when they send the same bytes at once, as two connections opening
|
|
18
|
+
* together do.
|
|
19
|
+
*/
|
|
20
|
+
export declare class DuplicateFilter {
|
|
21
|
+
private readonly windowMs;
|
|
22
|
+
private readonly entryLimit;
|
|
23
|
+
private readonly seen;
|
|
24
|
+
private suppressed;
|
|
25
|
+
constructor(options?: DuplicateFilterOptions);
|
|
26
|
+
/** Total copies suppressed since the last {@link takeSuppressedCount}. */
|
|
27
|
+
get suppressedCount(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Reports whether a packet is the first sighting of its payload and should be decoded.
|
|
30
|
+
*
|
|
31
|
+
* Payload-free packets are always admitted; they carry nothing to tell copies apart.
|
|
32
|
+
*/
|
|
33
|
+
admit(packet: CapturedTransportPacket, nowMs?: number): boolean;
|
|
34
|
+
/** Returns the suppressed count and resets it, for periodic reporting. */
|
|
35
|
+
takeSuppressedCount(): number;
|
|
36
|
+
reset(): void;
|
|
37
|
+
private evict;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=duplicate-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicate-filter.d.ts","sourceRoot":"","sources":["../../src/capture/duplicate-filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE5E,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,4FAA4F;AAC5F,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,UAAU,CAAK;IAEvB,YAAY,OAAO,GAAE,sBAA2B,EAG/C;IAED,0EAA0E;IAC1E,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,uBAAuB,EAAE,KAAK,GAAE,MAAmB,GAAG,OAAO,CAa1E;IAED,0EAA0E;IAC1E,mBAAmB,IAAI,MAAM,CAI5B;IAED,KAAK,IAAI,IAAI,CAGZ;IAED,OAAO,CAAC,KAAK;CAQd"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import type { CapturedLiteNetLibPacket } from "../litenetlib/types.ts";
|
|
3
3
|
import type { CapturedFishNetPacket } from "../fishnet/types.ts";
|
|
4
|
+
import type { DroppedFlow } from "./drop-diagnostics.ts";
|
|
4
5
|
import type { NpcapDevice, NpcapRuntime, NpcapStatus } from "./npcap.ts";
|
|
5
6
|
import type { TargetSnapshotProvider } from "./target-tracker.ts";
|
|
6
|
-
import type { CaptureConfig, CaptureTargetStatus, CapturedTcpPacket, CapturedTransportPacket, CapturedUdpPacket, CaptureState } from "../types.ts";
|
|
7
|
+
import type { CaptureConfig, CaptureConnectionEvent, CaptureTargetStatus, CapturedTcpPacket, CapturedTransportPacket, CapturedUdpPacket, CaptureState } from "../types.ts";
|
|
7
8
|
export interface PacketCaptureDependencies {
|
|
8
9
|
runtime?: NpcapRuntime;
|
|
9
10
|
targetProvider?: TargetSnapshotProvider;
|
|
@@ -24,29 +25,51 @@ export declare class PacketCapture extends EventEmitter {
|
|
|
24
25
|
private decodeFishNet;
|
|
25
26
|
private fishNetRpcMap;
|
|
26
27
|
private fishNetSessionDecoder;
|
|
28
|
+
private currentConnectionId?;
|
|
27
29
|
private droppedPending;
|
|
28
30
|
private droppedReportedAtMs;
|
|
31
|
+
private duplicateFilter;
|
|
32
|
+
private duplicateReportedAtMs;
|
|
33
|
+
private relayObserved;
|
|
34
|
+
private readonly dropDiagnostics;
|
|
35
|
+
private deviceLabel;
|
|
29
36
|
private _state;
|
|
30
37
|
constructor(dependencies?: PacketCaptureDependencies);
|
|
31
38
|
get state(): CaptureState;
|
|
39
|
+
/** The connection last seen opening and not since closing, undefined until one is observed. */
|
|
40
|
+
get connectionId(): string | undefined;
|
|
32
41
|
on(event: "started", listener: () => void): this;
|
|
33
42
|
on(event: "packet", listener: (packet: CapturedTcpPacket) => void): this;
|
|
34
43
|
on(event: "udpPacket", listener: (packet: CapturedUdpPacket) => void): this;
|
|
35
44
|
on(event: "transportPacket", listener: (packet: CapturedTransportPacket) => void): this;
|
|
36
45
|
on(event: "liteNetPacket", listener: (packet: CapturedLiteNetLibPacket) => void): this;
|
|
37
46
|
on(event: "fishNetPacket", listener: (packet: CapturedFishNetPacket) => void): this;
|
|
47
|
+
on(event: "connection", listener: (event: CaptureConnectionEvent) => void): this;
|
|
38
48
|
on(event: "targetStatus", listener: (status: CaptureTargetStatus) => void): this;
|
|
49
|
+
on(event: "droppedFlows", listener: (flows: DroppedFlow[]) => void): this;
|
|
39
50
|
on(event: "warning", listener: (message: string) => void): this;
|
|
40
51
|
on(event: "error", listener: (error: Error) => void): this;
|
|
41
52
|
on(event: "stopped", listener: () => void): this;
|
|
42
53
|
start(config?: CaptureConfig): Promise<void>;
|
|
43
54
|
stop(): Promise<void>;
|
|
44
55
|
private poll;
|
|
56
|
+
/** Counts a packet given up on and folds it into the drop diagnostics. */
|
|
57
|
+
private recordDropped;
|
|
45
58
|
private flushPending;
|
|
59
|
+
/** Reports copies a relay put on the wire, naming the adapter in case a better one exists. */
|
|
60
|
+
private reportSuppressedDuplicates;
|
|
46
61
|
/** Reports packets given up on unattributed, which is how a connection loses its opening. */
|
|
47
62
|
private reportDroppedPending;
|
|
48
63
|
private emitTransportPacket;
|
|
49
64
|
private emitLiteNetLibPackets;
|
|
65
|
+
/**
|
|
66
|
+
* Follows the connection the game is playing on.
|
|
67
|
+
*
|
|
68
|
+
* FishNet says so once per connection, in `authenticated`; a consumer that misses that packet
|
|
69
|
+
* stays pinned to a connection the game has left, discarding everything the live one sends.
|
|
70
|
+
* Connects and disconnects are announced continually, so losing one of those costs nothing.
|
|
71
|
+
*/
|
|
72
|
+
private trackConnection;
|
|
50
73
|
private emitFishNetPacket;
|
|
51
74
|
private emitSafely;
|
|
52
75
|
private closeResources;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packet-capture.d.ts","sourceRoot":"","sources":["../../src/capture/packet-capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"packet-capture.d.ts","sourceRoot":"","sources":["../../src/capture/packet-capture.ts"],"names":[],"mappings":"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"}
|
package/dist/capture.js
CHANGED
|
@@ -15452,6 +15452,120 @@ function isUsable(device) {
|
|
|
15452
15452
|
return !device.loopback && device.addresses.length > 0 && !["bluetooth", "wan miniport", "vmware", "hyper-v", "zerotier"].some((value) => label.includes(value));
|
|
15453
15453
|
}
|
|
15454
15454
|
|
|
15455
|
+
// src/capture/duplicate-filter.ts
|
|
15456
|
+
var DUPLICATE_WINDOW_MS = 5;
|
|
15457
|
+
var DUPLICATE_ENTRY_LIMIT = 16384;
|
|
15458
|
+
|
|
15459
|
+
class DuplicateFilter {
|
|
15460
|
+
windowMs;
|
|
15461
|
+
entryLimit;
|
|
15462
|
+
seen = new Map;
|
|
15463
|
+
suppressed = 0;
|
|
15464
|
+
constructor(options = {}) {
|
|
15465
|
+
this.windowMs = options.windowMs ?? DUPLICATE_WINDOW_MS;
|
|
15466
|
+
this.entryLimit = options.entryLimit ?? DUPLICATE_ENTRY_LIMIT;
|
|
15467
|
+
}
|
|
15468
|
+
get suppressedCount() {
|
|
15469
|
+
return this.suppressed;
|
|
15470
|
+
}
|
|
15471
|
+
admit(packet, nowMs = Date.now()) {
|
|
15472
|
+
if (packet.payload.length === 0)
|
|
15473
|
+
return true;
|
|
15474
|
+
const key = digest(packet.protocol, packet.direction, localPortOf(packet), packet.payload);
|
|
15475
|
+
const previous = this.seen.get(key);
|
|
15476
|
+
if (previous !== undefined && nowMs - previous < this.windowMs) {
|
|
15477
|
+
this.suppressed += 1;
|
|
15478
|
+
return false;
|
|
15479
|
+
}
|
|
15480
|
+
this.seen.delete(key);
|
|
15481
|
+
this.seen.set(key, nowMs);
|
|
15482
|
+
this.evict(nowMs);
|
|
15483
|
+
return true;
|
|
15484
|
+
}
|
|
15485
|
+
takeSuppressedCount() {
|
|
15486
|
+
const total = this.suppressed;
|
|
15487
|
+
this.suppressed = 0;
|
|
15488
|
+
return total;
|
|
15489
|
+
}
|
|
15490
|
+
reset() {
|
|
15491
|
+
this.seen.clear();
|
|
15492
|
+
this.suppressed = 0;
|
|
15493
|
+
}
|
|
15494
|
+
evict(nowMs) {
|
|
15495
|
+
const cutoff = nowMs - this.windowMs;
|
|
15496
|
+
for (const [key, observedAt] of this.seen) {
|
|
15497
|
+
if (observedAt >= cutoff && this.seen.size <= this.entryLimit)
|
|
15498
|
+
break;
|
|
15499
|
+
this.seen.delete(key);
|
|
15500
|
+
}
|
|
15501
|
+
}
|
|
15502
|
+
}
|
|
15503
|
+
function digest(protocol, direction, localPort, payload) {
|
|
15504
|
+
return `${protocol}:${direction}:${localPort}:${payload.toString("latin1")}`;
|
|
15505
|
+
}
|
|
15506
|
+
function localPortOf(packet) {
|
|
15507
|
+
return packet.direction === "outbound" ? packet.sourcePort : packet.destinationPort;
|
|
15508
|
+
}
|
|
15509
|
+
|
|
15510
|
+
// src/capture/drop-diagnostics.ts
|
|
15511
|
+
var DROP_FLOW_LIMIT = 64;
|
|
15512
|
+
var DROP_FLOW_REPORT_COUNT = 5;
|
|
15513
|
+
var DROP_VERDICT_MIN_SAMPLES = 20;
|
|
15514
|
+
var DROP_VERDICT_THRESHOLD = 0.25;
|
|
15515
|
+
|
|
15516
|
+
class DropDiagnostics {
|
|
15517
|
+
flows = new Map;
|
|
15518
|
+
record(packet) {
|
|
15519
|
+
const flow = flowName(packet);
|
|
15520
|
+
let stats = this.flows.get(flow);
|
|
15521
|
+
if (!stats) {
|
|
15522
|
+
if (this.flows.size >= DROP_FLOW_LIMIT)
|
|
15523
|
+
return;
|
|
15524
|
+
stats = { packets: 0, sequenced: 0, consecutive: 0 };
|
|
15525
|
+
this.flows.set(flow, stats);
|
|
15526
|
+
}
|
|
15527
|
+
stats.packets += 1;
|
|
15528
|
+
this.countSequence(stats, packet);
|
|
15529
|
+
}
|
|
15530
|
+
topFlows(limit = DROP_FLOW_REPORT_COUNT) {
|
|
15531
|
+
return [...this.flows].sort(([, a], [, b]) => b.packets - a.packets).slice(0, limit).map(([flow, stats]) => ({ flow, packets: stats.packets, verdict: verdictFor(stats) }));
|
|
15532
|
+
}
|
|
15533
|
+
get hasGameTraffic() {
|
|
15534
|
+
return [...this.flows.values()].some((stats) => verdictFor(stats) === "game traffic");
|
|
15535
|
+
}
|
|
15536
|
+
reset() {
|
|
15537
|
+
this.flows.clear();
|
|
15538
|
+
}
|
|
15539
|
+
countSequence(stats, packet) {
|
|
15540
|
+
if (packet.protocol !== "udp" || packet.payload.length === 0)
|
|
15541
|
+
return;
|
|
15542
|
+
let decoded;
|
|
15543
|
+
try {
|
|
15544
|
+
decoded = decodeLiteNetLibDatagram(packet.payload);
|
|
15545
|
+
} catch {
|
|
15546
|
+
return;
|
|
15547
|
+
}
|
|
15548
|
+
for (const { packet: inner } of decoded) {
|
|
15549
|
+
const sequence = "sequence" in inner ? inner.sequence : undefined;
|
|
15550
|
+
if (sequence === undefined)
|
|
15551
|
+
continue;
|
|
15552
|
+
stats.sequenced += 1;
|
|
15553
|
+
if (stats.previous !== undefined && sequence === (stats.previous + 1) % 32768) {
|
|
15554
|
+
stats.consecutive += 1;
|
|
15555
|
+
}
|
|
15556
|
+
stats.previous = sequence;
|
|
15557
|
+
}
|
|
15558
|
+
}
|
|
15559
|
+
}
|
|
15560
|
+
function verdictFor(stats) {
|
|
15561
|
+
if (stats.sequenced < DROP_VERDICT_MIN_SAMPLES)
|
|
15562
|
+
return "unknown";
|
|
15563
|
+
return stats.consecutive / stats.sequenced >= DROP_VERDICT_THRESHOLD ? "game traffic" : "unrelated";
|
|
15564
|
+
}
|
|
15565
|
+
function flowName(packet) {
|
|
15566
|
+
return `${packet.protocol} ${packet.sourceIP}:${packet.sourcePort} -> ${packet.destinationIP}:${packet.destinationPort}`;
|
|
15567
|
+
}
|
|
15568
|
+
|
|
15455
15569
|
// src/capture/link-layer.ts
|
|
15456
15570
|
var DATA_LINK = {
|
|
15457
15571
|
NULL: 0,
|
|
@@ -15928,6 +16042,7 @@ var MAX_POLL_BATCH = 128;
|
|
|
15928
16042
|
var PENDING_PACKET_LIMIT = 16384;
|
|
15929
16043
|
var PENDING_PACKET_MAX_AGE_MS = TARGET_REFRESH_INTERVAL_MS * 5;
|
|
15930
16044
|
var PENDING_DROP_REPORT_MS = 1e4;
|
|
16045
|
+
var DUPLICATE_REPORT_MS = 1e4;
|
|
15931
16046
|
var systemRuntime = new SystemNpcapRuntime;
|
|
15932
16047
|
async function getNpcapStatus() {
|
|
15933
16048
|
return systemRuntime.status();
|
|
@@ -15949,8 +16064,14 @@ class PacketCapture extends EventEmitter {
|
|
|
15949
16064
|
decodeFishNet = false;
|
|
15950
16065
|
fishNetRpcMap;
|
|
15951
16066
|
fishNetSessionDecoder = null;
|
|
16067
|
+
currentConnectionId;
|
|
15952
16068
|
droppedPending = 0;
|
|
15953
16069
|
droppedReportedAtMs = 0;
|
|
16070
|
+
duplicateFilter = null;
|
|
16071
|
+
duplicateReportedAtMs = 0;
|
|
16072
|
+
relayObserved = false;
|
|
16073
|
+
dropDiagnostics = new DropDiagnostics;
|
|
16074
|
+
deviceLabel = "";
|
|
15954
16075
|
_state = "stopped";
|
|
15955
16076
|
constructor(dependencies = {}) {
|
|
15956
16077
|
super();
|
|
@@ -15961,6 +16082,9 @@ class PacketCapture extends EventEmitter {
|
|
|
15961
16082
|
get state() {
|
|
15962
16083
|
return this._state;
|
|
15963
16084
|
}
|
|
16085
|
+
get connectionId() {
|
|
16086
|
+
return this.currentConnectionId;
|
|
16087
|
+
}
|
|
15964
16088
|
on(event, listener) {
|
|
15965
16089
|
return super.on(event, listener);
|
|
15966
16090
|
}
|
|
@@ -15983,10 +16107,12 @@ class PacketCapture extends EventEmitter {
|
|
|
15983
16107
|
this.decodeLiteNetLib = (config.decodeLiteNetLib ?? false) || decodeFishNet;
|
|
15984
16108
|
this.fishNetRpcMap = decodeFishNet ? config.fishNetRpcMap ?? loadBundledFishNetRpcMap(config.fishNetBuildFingerprint) : undefined;
|
|
15985
16109
|
this.fishNetSessionDecoder = decodeFishNet ? new FishNetSessionDecoder(this.fishNetRpcMap) : null;
|
|
16110
|
+
this.duplicateFilter = config.suppressDuplicates ?? true ? new DuplicateFilter : null;
|
|
15986
16111
|
const devices = await this.runtime.listDevices();
|
|
15987
16112
|
const resolved = await resolveCaptureDevice(devices, config.deviceName);
|
|
15988
16113
|
if (!resolved.device)
|
|
15989
16114
|
throw new Error("Npcap did not report a usable network adapter");
|
|
16115
|
+
this.deviceLabel = resolved.device.description || resolved.device.name;
|
|
15990
16116
|
const filter = config.filter ?? Array.from(new Set(protocols)).join(" or ");
|
|
15991
16117
|
this.session = await this.runtime.open(resolved.device, filter);
|
|
15992
16118
|
if (!supportsDataLink(this.session.dataLink)) {
|
|
@@ -16023,6 +16149,7 @@ class PacketCapture extends EventEmitter {
|
|
|
16023
16149
|
this.polling = true;
|
|
16024
16150
|
try {
|
|
16025
16151
|
this.flushPending();
|
|
16152
|
+
this.reportSuppressedDuplicates();
|
|
16026
16153
|
for (let index = 0;index < MAX_POLL_BATCH; index += 1) {
|
|
16027
16154
|
const captured = this.session.nextPacket();
|
|
16028
16155
|
if (!captured)
|
|
@@ -16050,7 +16177,7 @@ class PacketCapture extends EventEmitter {
|
|
|
16050
16177
|
this.emitTransportPacket(packet);
|
|
16051
16178
|
} else {
|
|
16052
16179
|
if (this.pending.length >= PENDING_PACKET_LIMIT)
|
|
16053
|
-
this.
|
|
16180
|
+
this.recordDropped(packet);
|
|
16054
16181
|
else
|
|
16055
16182
|
this.pending.push({ packet, observedAt: Date.now() });
|
|
16056
16183
|
}
|
|
@@ -16067,6 +16194,10 @@ class PacketCapture extends EventEmitter {
|
|
|
16067
16194
|
this.polling = false;
|
|
16068
16195
|
}
|
|
16069
16196
|
}
|
|
16197
|
+
recordDropped(packet) {
|
|
16198
|
+
this.droppedPending += 1;
|
|
16199
|
+
this.dropDiagnostics.record(packet);
|
|
16200
|
+
}
|
|
16070
16201
|
flushPending() {
|
|
16071
16202
|
if (!this.target)
|
|
16072
16203
|
return;
|
|
@@ -16078,7 +16209,7 @@ class PacketCapture extends EventEmitter {
|
|
|
16078
16209
|
const remaining = [];
|
|
16079
16210
|
for (const candidate of this.pending) {
|
|
16080
16211
|
if (candidate.observedAt < cutoff) {
|
|
16081
|
-
this.
|
|
16212
|
+
this.recordDropped(candidate.packet);
|
|
16082
16213
|
continue;
|
|
16083
16214
|
}
|
|
16084
16215
|
const direction = this.target.classify(candidate.packet);
|
|
@@ -16092,6 +16223,17 @@ class PacketCapture extends EventEmitter {
|
|
|
16092
16223
|
this.pending = remaining;
|
|
16093
16224
|
this.reportDroppedPending();
|
|
16094
16225
|
}
|
|
16226
|
+
reportSuppressedDuplicates() {
|
|
16227
|
+
if (!this.duplicateFilter || this.duplicateFilter.suppressedCount === 0)
|
|
16228
|
+
return;
|
|
16229
|
+
const now = Date.now();
|
|
16230
|
+
this.duplicateReportedAtMs ||= now;
|
|
16231
|
+
if (now - this.duplicateReportedAtMs < DUPLICATE_REPORT_MS)
|
|
16232
|
+
return;
|
|
16233
|
+
const total = this.duplicateFilter.takeSuppressedCount();
|
|
16234
|
+
this.emitSafely("warning", `suppressed ${total} duplicate packets on ${this.deviceLabel}; a VPN or proxy is relaying this traffic` + ", so select the adapter carrying it directly if decoding looks incomplete");
|
|
16235
|
+
this.duplicateReportedAtMs = now;
|
|
16236
|
+
}
|
|
16095
16237
|
reportDroppedPending() {
|
|
16096
16238
|
if (this.droppedPending === 0)
|
|
16097
16239
|
return;
|
|
@@ -16099,11 +16241,20 @@ class PacketCapture extends EventEmitter {
|
|
|
16099
16241
|
this.droppedReportedAtMs ||= now;
|
|
16100
16242
|
if (now - this.droppedReportedAtMs < PENDING_DROP_REPORT_MS)
|
|
16101
16243
|
return;
|
|
16102
|
-
this.
|
|
16244
|
+
const relay = this.relayObserved ? "; a VPN or proxy is also relaying traffic on this adapter" : "";
|
|
16245
|
+
this.emitSafely("warning", `gave up on ${this.droppedPending} packets that could not be attributed to the target process${relay}`);
|
|
16246
|
+
this.emitSafely("droppedFlows", this.dropDiagnostics.topFlows());
|
|
16247
|
+
if (this.dropDiagnostics.hasGameTraffic) {
|
|
16248
|
+
this.emitSafely("warning", "some discarded traffic carries sequenced game packets, so the target process does not own" + " every socket its traffic uses; capture that adapter directly or report these flows");
|
|
16249
|
+
}
|
|
16103
16250
|
this.droppedPending = 0;
|
|
16104
16251
|
this.droppedReportedAtMs = now;
|
|
16105
16252
|
}
|
|
16106
16253
|
emitTransportPacket(packet) {
|
|
16254
|
+
if (this.duplicateFilter && !this.duplicateFilter.admit(packet)) {
|
|
16255
|
+
this.relayObserved = true;
|
|
16256
|
+
return;
|
|
16257
|
+
}
|
|
16107
16258
|
if (packet.protocol === "tcp")
|
|
16108
16259
|
this.emitSafely("packet", packet);
|
|
16109
16260
|
else
|
|
@@ -16117,6 +16268,7 @@ class PacketCapture extends EventEmitter {
|
|
|
16117
16268
|
for (const decoded of decodeLiteNetLibDatagram(packet.payload)) {
|
|
16118
16269
|
const captured = { ...decoded, udpPacket: packet };
|
|
16119
16270
|
this.emitSafely("liteNetPacket", captured);
|
|
16271
|
+
this.trackConnection(captured);
|
|
16120
16272
|
if (this.decodeFishNet)
|
|
16121
16273
|
this.emitFishNetPacket(captured);
|
|
16122
16274
|
}
|
|
@@ -16125,11 +16277,26 @@ class PacketCapture extends EventEmitter {
|
|
|
16125
16277
|
this.emitSafely("warning", `skipped LiteNetLib decode: ${detail}`);
|
|
16126
16278
|
}
|
|
16127
16279
|
}
|
|
16280
|
+
trackConnection(packet) {
|
|
16281
|
+
const { property } = packet.packet;
|
|
16282
|
+
if (property !== "connectRequest" && property !== "connectAccept" && property !== "disconnect")
|
|
16283
|
+
return;
|
|
16284
|
+
const connectionId = connectionIdFor(packet);
|
|
16285
|
+
if (property === "disconnect") {
|
|
16286
|
+
if (this.currentConnectionId === connectionId)
|
|
16287
|
+
this.currentConnectionId = undefined;
|
|
16288
|
+
this.emitSafely("connection", { connectionId, state: "closed" });
|
|
16289
|
+
return;
|
|
16290
|
+
}
|
|
16291
|
+
if (this.currentConnectionId === connectionId)
|
|
16292
|
+
return;
|
|
16293
|
+
this.currentConnectionId = connectionId;
|
|
16294
|
+
this.emitSafely("connection", { connectionId, state: "opened" });
|
|
16295
|
+
}
|
|
16128
16296
|
emitFishNetPacket(packet) {
|
|
16129
16297
|
const { property, payload } = packet.packet;
|
|
16130
16298
|
const udp = packet.udpPacket;
|
|
16131
|
-
const
|
|
16132
|
-
const connectionId = `${endpoints[0]}<->${endpoints[1]}#${packet.packet.connectionNumber}`;
|
|
16299
|
+
const connectionId = connectionIdFor(packet);
|
|
16133
16300
|
if (property === "connectRequest" || property === "connectAccept" || property === "disconnect") {
|
|
16134
16301
|
this.fishNetSessionDecoder?.reset(connectionId);
|
|
16135
16302
|
return;
|
|
@@ -16184,10 +16351,22 @@ class PacketCapture extends EventEmitter {
|
|
|
16184
16351
|
this.fishNetRpcMap = undefined;
|
|
16185
16352
|
this.fishNetSessionDecoder?.reset();
|
|
16186
16353
|
this.fishNetSessionDecoder = null;
|
|
16354
|
+
this.currentConnectionId = undefined;
|
|
16187
16355
|
this.droppedPending = 0;
|
|
16188
16356
|
this.droppedReportedAtMs = 0;
|
|
16357
|
+
this.duplicateFilter?.reset();
|
|
16358
|
+
this.duplicateFilter = null;
|
|
16359
|
+
this.duplicateReportedAtMs = 0;
|
|
16360
|
+
this.relayObserved = false;
|
|
16361
|
+
this.dropDiagnostics.reset();
|
|
16362
|
+
this.deviceLabel = "";
|
|
16189
16363
|
}
|
|
16190
16364
|
}
|
|
16365
|
+
function connectionIdFor(packet) {
|
|
16366
|
+
const udp = packet.udpPacket;
|
|
16367
|
+
const localPort = udp.direction === "outbound" ? udp.sourcePort : udp.destinationPort;
|
|
16368
|
+
return `local:${localPort}#${packet.packet.connectionNumber}`;
|
|
16369
|
+
}
|
|
16191
16370
|
function inferDirection(ipPacket, device) {
|
|
16192
16371
|
if (ipPacket[0] >> 4 === 4 && ipPacket.length >= 20) {
|
|
16193
16372
|
const source = `${ipPacket[12]}.${ipPacket[13]}.${ipPacket[14]}.${ipPacket[15]}`;
|
package/dist/index.d.ts
CHANGED
|
@@ -20,7 +20,8 @@ export { FishNetMonsterDirectory, decodeMonsterSpawn, } from "./fishnet/monster-
|
|
|
20
20
|
export type { FishNetMonsterDirectoryChange, FishNetMonsterLevels, FishNetMonsterSpawn, } from "./fishnet/monster-directory.ts";
|
|
21
21
|
export { decodeBossGravestone } from "./fishnet/boss-gravestone.ts";
|
|
22
22
|
export type { BossGravestone } from "./fishnet/boss-gravestone.ts";
|
|
23
|
-
export type {
|
|
23
|
+
export type { DroppedFlow } from "./capture/drop-diagnostics.ts";
|
|
24
|
+
export type { CaptureConfig, CaptureConnectionEvent, CaptureProtocol, CaptureState, CaptureTargetStatus, CapturedTcpPacket, CapturedTransportPacket, CapturedUdpPacket, } from "./types.ts";
|
|
24
25
|
export type { CapturedLiteNetLibPacket, DecodedLiteNetLibPacket, LiteNetLibAckPacket, LiteNetLibChanneledPacket, LiteNetLibControlPacket, LiteNetLibFragment, LiteNetLibPacket, LiteNetLibPacketProperty, LiteNetLibPingPacket, LiteNetLibPongPacket, LiteNetLibUnreliablePacket, } from "./litenetlib/types.ts";
|
|
25
26
|
export type { CapturedFishNetPacket, DecodedFishNetPacket, FishNetDecodeOptions, FishNetDecodedField, FishNetDecodedValue, FishNetBehaviourDefinition, FishNetBroadcastDefinition, FishNetPrefabComponentDefinition, FishNetPrefabDefinition, FishNetPacketName, FishNetRpcMap, FishNetRpcPacketName, FishNetRpcDefinition, FishNetRpcLinkRegistration, FishNetRpcParameter, FishNetRpcResolution, FishNetSpawnSyncEntry, FishNetSyncEntry, FishNetSyncTypeDefinition, FishNetWireCodec, DecodedNetworkTransform, NetworkTransformAxes, } from "./fishnet/types.ts";
|
|
26
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC5F,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACjH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5D,YAAY,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAC1E,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,EACL,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,6BAA6B,EAC7B,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,YAAY,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,0BAA0B,EAC1B,0BAA0B,EAC1B,gCAAgC,EAChC,uBAAuB,EACvB,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,yBAAyB,EACzB,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC5F,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACjH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5D,YAAY,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAC1E,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,EACL,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,6BAA6B,EAC7B,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,YAAY,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,0BAA0B,EAC1B,0BAA0B,EAC1B,gCAAgC,EAChC,uBAAuB,EACvB,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,yBAAyB,EACzB,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,6 +9,13 @@ export interface CaptureConfig {
|
|
|
9
9
|
targetProcessName?: string;
|
|
10
10
|
/** Stable Npcap device name. Omit to select the default-route adapter automatically. */
|
|
11
11
|
deviceName?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Collapse the redundant copies a redirecting VPN puts on the wire. Defaults to true.
|
|
14
|
+
*
|
|
15
|
+
* Without this a relayed datagram is captured more than once and counted twice downstream.
|
|
16
|
+
* Disable only to inspect the wire exactly as observed.
|
|
17
|
+
*/
|
|
18
|
+
suppressDuplicates?: boolean;
|
|
12
19
|
/** Decode captured UDP payloads as LiteNetLib 1.x packets. Defaults to false. */
|
|
13
20
|
decodeLiteNetLib?: boolean;
|
|
14
21
|
/** Decode verified FishNet headers inside LiteNetLib data packets. Implies decodeLiteNetLib. */
|
|
@@ -49,5 +56,10 @@ export interface CaptureTargetStatus {
|
|
|
49
56
|
processIds: number[];
|
|
50
57
|
}
|
|
51
58
|
export type CaptureState = "stopped" | "starting" | "running" | "stopping";
|
|
59
|
+
/** A transport connection opening or closing, reported as LiteNetLib announces it. */
|
|
60
|
+
export interface CaptureConnectionEvent {
|
|
61
|
+
connectionId: string;
|
|
62
|
+
state: "opened" | "closed";
|
|
63
|
+
}
|
|
52
64
|
export {};
|
|
53
65
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACvC,sGAAsG;IACtG,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gGAAgG;IAChG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2FAA2F;IAC3F,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACvC,sGAAsG;IACtG,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gGAAgG;IAChG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2FAA2F;IAC3F,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;AAE3E,sFAAsF;AACtF,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC5B"}
|