@kar-mi/spirit-vale-tools-capture 2.4.2 → 2.5.1

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.
@@ -5,5 +5,5 @@ export interface AdapterResolution {
5
5
  detail?: string;
6
6
  }
7
7
  export declare function resolveCaptureDevice(devices: readonly NpcapDevice[], requestedName?: string): Promise<AdapterResolution>;
8
- export declare function chooseDeviceByRouteOutput(devices: readonly NpcapDevice[], output: string): NpcapDevice | undefined;
8
+ export declare function chooseDeviceByRouteAddress(devices: readonly NpcapDevice[], address: string): NpcapDevice | undefined;
9
9
  //# sourceMappingURL=adapter-selection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-selection.d.ts","sourceRoot":"","sources":["../../src/capture/adapter-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAYlH"}
1
+ {"version":3,"file":"adapter-selection.d.ts","sourceRoot":"","sources":["../../src/capture/adapter-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,OAAO,EAAE,MAAM,GACd,WAAW,GAAG,SAAS,CAEzB"}
@@ -1,4 +1,4 @@
1
- export type NpcapAvailability = "ready" | "missing" | "admin-only" | "error";
1
+ export type NpcapAvailability = "ready" | "missing" | "error";
2
2
  export interface NpcapStatus {
3
3
  availability: NpcapAvailability;
4
4
  detail: string;
@@ -32,6 +32,7 @@ export declare class SystemNpcapRuntime implements NpcapRuntime {
32
32
  private readyStatus?;
33
33
  status(): Promise<NpcapStatus>;
34
34
  listDevices(): Promise<NpcapDevice[]>;
35
+ private enumerateDevices;
35
36
  open(device: NpcapDevice, filter: string): Promise<NpcapSession>;
36
37
  private load;
37
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"npcap.d.ts","sourceRoot":"","sources":["../../src/capture/npcap.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,iBAAiB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,UAAU,IAAI,WAAW,GAAG,SAAS,CAAC;IACtC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAClE;AAID,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,GAAG,CAAC,CAAc;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAc;IAE5B,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CA0BnC;IAEK,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAiC1C;IAEK,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAiCrE;IAED,OAAO,CAAC,IAAI;CAyBb"}
1
+ {"version":3,"file":"npcap.d.ts","sourceRoot":"","sources":["../../src/capture/npcap.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,iBAAiB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,UAAU,IAAI,WAAW,GAAG,SAAS,CAAC;IACtC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAClE;AAKD,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,GAAG,CAAC,CAAc;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAc;IAE5B,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CA4BnC;IAEK,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAI1C;IAED,OAAO,CAAC,gBAAgB;IAgClB,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAsCrE;IAED,OAAO,CAAC,IAAI;CAyBb"}
@@ -24,6 +24,8 @@ export declare class PacketCapture extends EventEmitter {
24
24
  private decodeFishNet;
25
25
  private fishNetRpcMap;
26
26
  private fishNetSessionDecoder;
27
+ private droppedPending;
28
+ private droppedReportedAtMs;
27
29
  private _state;
28
30
  constructor(dependencies?: PacketCaptureDependencies);
29
31
  get state(): CaptureState;
@@ -41,6 +43,8 @@ export declare class PacketCapture extends EventEmitter {
41
43
  stop(): Promise<void>;
42
44
  private poll;
43
45
  private flushPending;
46
+ /** Reports packets given up on unattributed, which is how a connection loses its opening. */
47
+ private reportDroppedPending;
44
48
  private emitTransportPacket;
45
49
  private emitLiteNetLibPackets;
46
50
  private emitFishNetPacket;
@@ -1 +1 @@
1
- {"version":3,"file":"packet-capture.d.ts","sourceRoot":"","sources":["../../src/capture/packet-capture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"packet-capture.d.ts","sourceRoot":"","sources":["../../src/capture/packet-capture.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,7 @@
1
1
  import type { CaptureProtocol, CapturedTransportPacket, CaptureTargetStatus } from "../types.ts";
2
- interface OwnedEndpoint {
3
- protocol: CaptureProtocol;
4
- address: string;
5
- port: number;
6
- processId: number;
7
- }
2
+ import type { WindowsOwnedEndpoint } from "./win32-system.ts";
3
+ type OwnedEndpoint = WindowsOwnedEndpoint;
4
+ export declare const TARGET_REFRESH_INTERVAL_MS = 1000;
8
5
  export interface TargetSnapshotProvider {
9
6
  snapshot(processName: string, protocols: readonly CaptureProtocol[]): Promise<{
10
7
  processIds: number[];
@@ -31,7 +28,5 @@ export declare class WindowsTargetTracker {
31
28
  private matches;
32
29
  private refresh;
33
30
  }
34
- export declare function parseTaskList(output: string): number[];
35
- export declare function parseNetstat(output: string, protocol: CaptureProtocol): OwnedEndpoint[];
36
31
  export {};
37
32
  //# sourceMappingURL=target-tracker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"target-tracker.d.ts","sourceRoot":"","sources":["../../src/capture/target-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEjG,UAAU,aAAa;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC;QAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,SAAS,EAAE,aAAa,EAAE,CAAC;KAC5B,CAAC,CAAC;CACJ;AAED,qBAAa,oBAAoB;IAS7B,QAAQ,CAAC,WAAW,EAAE,MAAM;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAbpC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,KAAK,CAAC,CAAiC;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,YACW,WAAW,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,eAAe,EAAE,EACrC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,EAC/C,QAAQ,GAAE,sBAA4D,EACtE,SAAS,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,EAC/C,iBAAiB,SAA6B,EAC7D;IAEE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;IAED,IAAI,IAAI,IAAI,CAGX;IAED,QAAQ,CAAC,MAAM,EAAE,uBAAuB,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAM5E;IAED,OAAO,CAAC,OAAO;YAMD,OAAO;CAgCtB;AA+BD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAKtD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,aAAa,EAAE,CAQvF"}
1
+ {"version":3,"file":"target-tracker.d.ts","sourceRoot":"","sources":["../../src/capture/target-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEjG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,KAAK,aAAa,GAAG,oBAAoB,CAAC;AAE1C,eAAO,MAAM,0BAA0B,OAAQ,CAAC;AAEhD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC;QAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,SAAS,EAAE,aAAa,EAAE,CAAC;KAC5B,CAAC,CAAC;CACJ;AAED,qBAAa,oBAAoB;IAS7B,QAAQ,CAAC,WAAW,EAAE,MAAM;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAbpC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,KAAK,CAAC,CAAiC;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,YACW,WAAW,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,eAAe,EAAE,EACrC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,EAC/C,QAAQ,GAAE,sBAA4D,EACtE,SAAS,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,EAC/C,iBAAiB,SAA6B,EAC7D;IAEE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;IAED,IAAI,IAAI,IAAI,CAGX;IAED,QAAQ,CAAC,MAAM,EAAE,uBAAuB,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAM5E;IAED,OAAO,CAAC,OAAO;YAMD,OAAO;CAgCtB"}
@@ -0,0 +1,11 @@
1
+ import type { CaptureProtocol } from "../types.ts";
2
+ export interface WindowsOwnedEndpoint {
3
+ protocol: CaptureProtocol;
4
+ address: string;
5
+ port: number;
6
+ processId: number;
7
+ }
8
+ export declare function findProcessIdsByName(processName: string): number[];
9
+ export declare function listOwnedEndpoints(protocols: readonly CaptureProtocol[]): WindowsOwnedEndpoint[];
10
+ export declare function defaultRouteIpv4Address(): string | undefined;
11
+ //# sourceMappingURL=win32-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"win32-system.d.ts","sourceRoot":"","sources":["../../src/capture/win32-system.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAmDD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBlE;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,GAAG,oBAAoB,EAAE,CAIhG;AAED,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAe5D"}
package/dist/capture.js CHANGED
@@ -15235,53 +15235,8 @@ function decodeFishNetBundle(payload, options = { reliable: false }) {
15235
15235
  return new FishNetSessionDecoder(options.rpcMap).decode(payload, options);
15236
15236
  }
15237
15237
 
15238
- // src/capture/adapter-selection.ts
15239
- async function resolveCaptureDevice(devices, requestedName) {
15240
- if (requestedName) {
15241
- const requested = devices.find((device) => device.name === requestedName);
15242
- if (requested)
15243
- return { device: requested, usedFallback: false };
15244
- }
15245
- const automatic = await defaultRouteDevice(devices) ?? devices.find(isUsable) ?? devices[0];
15246
- return {
15247
- device: automatic,
15248
- usedFallback: Boolean(requestedName),
15249
- ...requestedName && automatic ? { detail: "The saved adapter is unavailable; capture is using the automatically selected adapter" } : {}
15250
- };
15251
- }
15252
- function chooseDeviceByRouteOutput(devices, output) {
15253
- const routes = output.split(/\r?\n/).flatMap((line) => {
15254
- const columns = line.trim().split(/\s+/);
15255
- if (columns[0] !== "0.0.0.0" || columns[1] !== "0.0.0.0" || columns.length < 5)
15256
- return [];
15257
- const metric = Number(columns[4]);
15258
- return [{ address: columns[3], metric: Number.isFinite(metric) ? metric : Number.MAX_SAFE_INTEGER }];
15259
- }).sort((left, right) => left.metric - right.metric);
15260
- for (const route of routes) {
15261
- const match = devices.find((device) => device.addresses.includes(route.address));
15262
- if (match)
15263
- return match;
15264
- }
15265
- return;
15266
- }
15267
- async function defaultRouteDevice(devices) {
15268
- try {
15269
- const child = Bun.spawn({
15270
- cmd: ["route.exe", "PRINT", "0.0.0.0"],
15271
- stdout: "pipe",
15272
- stderr: "ignore",
15273
- windowsHide: true
15274
- });
15275
- const output = await new Response(child.stdout).text();
15276
- return await child.exited === 0 ? chooseDeviceByRouteOutput(devices, output) : undefined;
15277
- } catch {
15278
- return;
15279
- }
15280
- }
15281
- function isUsable(device) {
15282
- const label = `${device.name} ${device.description}`.toLowerCase();
15283
- return !device.loopback && device.addresses.length > 0 && !["bluetooth", "wan miniport", "vmware", "hyper-v", "zerotier"].some((value) => label.includes(value));
15284
- }
15238
+ // src/capture/win32-system.ts
15239
+ import { dlopen, FFIType } from "bun:ffi";
15285
15240
 
15286
15241
  // src/capture/ip-address.ts
15287
15242
  function formatIpv6(data) {
@@ -15309,6 +15264,194 @@ function formatIpv6(data) {
15309
15264
  return `${before}::${after}`;
15310
15265
  }
15311
15266
 
15267
+ // src/capture/win32-system.ts
15268
+ var ERROR_SUCCESS = 0;
15269
+ var ERROR_INSUFFICIENT_BUFFER = 122;
15270
+ var TH32CS_SNAPPROCESS = 2;
15271
+ var AF_INET = 2;
15272
+ var AF_INET6 = 23;
15273
+ var TCP_TABLE_OWNER_PID_ALL = 5;
15274
+ var UDP_TABLE_OWNER_PID = 1;
15275
+ var ENDPOINT_LAYOUTS = [
15276
+ { protocol: "tcp", family: AF_INET, rowSize: 24, addressOffset: 4, portOffset: 8, processIdOffset: 20 },
15277
+ { protocol: "tcp", family: AF_INET6, rowSize: 56, addressOffset: 0, portOffset: 20, processIdOffset: 52 },
15278
+ { protocol: "udp", family: AF_INET, rowSize: 12, addressOffset: 0, portOffset: 4, processIdOffset: 8 },
15279
+ { protocol: "udp", family: AF_INET6, rowSize: 28, addressOffset: 0, portOffset: 20, processIdOffset: 24 }
15280
+ ];
15281
+ var ROUTE_SIZE = 56;
15282
+ var ROUTE_INTERFACE_INDEX_OFFSET = 16;
15283
+ var ADDRESS_ROW_SIZE = 24;
15284
+ var ADDRESS_ROW_INTERFACE_INDEX_OFFSET = 4;
15285
+ var PROCESS_ENTRY_SIZE = process.arch === "ia32" ? 556 : 568;
15286
+ var PROCESS_ENTRY_ID_OFFSET = 8;
15287
+ var PROCESS_ENTRY_NAME_OFFSET = process.arch === "ia32" ? 36 : 44;
15288
+ var kernel32;
15289
+ var ipHelper;
15290
+ function findProcessIdsByName(processName) {
15291
+ requireWindows();
15292
+ const api = loadKernel32();
15293
+ const snapshot = api.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
15294
+ if (snapshot === null || snapshot === -1)
15295
+ throw new Error("Windows could not create a process snapshot");
15296
+ const entry = new Uint8Array(PROCESS_ENTRY_SIZE);
15297
+ const view = new DataView(entry.buffer);
15298
+ view.setUint32(0, PROCESS_ENTRY_SIZE, true);
15299
+ const expected = processName.toLowerCase();
15300
+ const processIds = [];
15301
+ try {
15302
+ let hasEntry = api.Process32FirstW(snapshot, entry) !== 0;
15303
+ while (hasEntry) {
15304
+ if (decodeWideString(entry, PROCESS_ENTRY_NAME_OFFSET).toLowerCase() === expected) {
15305
+ processIds.push(view.getUint32(PROCESS_ENTRY_ID_OFFSET, true));
15306
+ }
15307
+ hasEntry = api.Process32NextW(snapshot, entry) !== 0;
15308
+ }
15309
+ } finally {
15310
+ api.CloseHandle(snapshot);
15311
+ }
15312
+ return processIds.sort((left, right) => left - right);
15313
+ }
15314
+ function listOwnedEndpoints(protocols) {
15315
+ requireWindows();
15316
+ const selected = new Set(protocols);
15317
+ return ENDPOINT_LAYOUTS.filter((layout) => selected.has(layout.protocol)).flatMap(readEndpoints);
15318
+ }
15319
+ function defaultRouteIpv4Address() {
15320
+ requireWindows();
15321
+ const api = loadIpHelper();
15322
+ const route = new Uint8Array(ROUTE_SIZE);
15323
+ if (api.GetBestRoute(0, 0, route) !== ERROR_SUCCESS)
15324
+ return;
15325
+ const interfaceIndex = new DataView(route.buffer).getUint32(ROUTE_INTERFACE_INDEX_OFFSET, true);
15326
+ const table = readVariableTable((buffer, size) => api.GetIpAddrTable(buffer, size, 0));
15327
+ const view = tableView(table, ADDRESS_ROW_SIZE);
15328
+ for (let index = 0;index < view.count; index += 1) {
15329
+ const offset = 4 + index * ADDRESS_ROW_SIZE;
15330
+ if (view.data.getUint32(offset + ADDRESS_ROW_INTERFACE_INDEX_OFFSET, true) === interfaceIndex) {
15331
+ return formatIpv4(table, offset);
15332
+ }
15333
+ }
15334
+ return;
15335
+ }
15336
+ function readEndpoints(layout) {
15337
+ const api = loadIpHelper();
15338
+ const table = readVariableTable((buffer, size) => layout.protocol === "tcp" ? api.GetExtendedTcpTable(buffer, size, 0, layout.family, TCP_TABLE_OWNER_PID_ALL, 0) : api.GetExtendedUdpTable(buffer, size, 0, layout.family, UDP_TABLE_OWNER_PID, 0));
15339
+ const view = tableView(table, layout.rowSize);
15340
+ const endpoints = [];
15341
+ for (let index = 0;index < view.count; index += 1) {
15342
+ const offset = 4 + index * layout.rowSize;
15343
+ endpoints.push({
15344
+ protocol: layout.protocol,
15345
+ address: readAddress(table, offset + layout.addressOffset, layout.family),
15346
+ port: view.data.getUint16(offset + layout.portOffset, false),
15347
+ processId: view.data.getUint32(offset + layout.processIdOffset, true)
15348
+ });
15349
+ }
15350
+ return endpoints;
15351
+ }
15352
+ function readVariableTable(call) {
15353
+ const size = new Uint32Array(1);
15354
+ const initialResult = call(null, size);
15355
+ if (initialResult !== ERROR_INSUFFICIENT_BUFFER || !size[0]) {
15356
+ throw new Error(`Windows table size query failed with error ${initialResult}`);
15357
+ }
15358
+ for (let attempt = 0;attempt < 3; attempt += 1) {
15359
+ const capacity = size[0] ?? 0;
15360
+ const buffer = new Uint8Array(capacity);
15361
+ size[0] = buffer.byteLength;
15362
+ const result = call(buffer, size);
15363
+ if (result === ERROR_SUCCESS)
15364
+ return buffer.subarray(0, size[0]);
15365
+ if (result !== ERROR_INSUFFICIENT_BUFFER || size[0] === 0) {
15366
+ throw new Error(`Windows table query failed with error ${result}`);
15367
+ }
15368
+ }
15369
+ throw new Error("Windows table changed too frequently to read consistently");
15370
+ }
15371
+ function tableView(table, rowSize) {
15372
+ if (table.byteLength < 4)
15373
+ throw new Error("Windows returned a truncated table");
15374
+ const data = new DataView(table.buffer, table.byteOffset, table.byteLength);
15375
+ const count = data.getUint32(0, true);
15376
+ if (4 + count * rowSize > table.byteLength)
15377
+ throw new Error("Windows returned an invalid table size");
15378
+ return { count, data };
15379
+ }
15380
+ function readAddress(buffer, offset, family) {
15381
+ return family === AF_INET ? formatIpv4(buffer, offset) : formatIpv6(Buffer.from(buffer.subarray(offset, offset + 16)));
15382
+ }
15383
+ function formatIpv4(buffer, offset) {
15384
+ return `${buffer[offset]}.${buffer[offset + 1]}.${buffer[offset + 2]}.${buffer[offset + 3]}`;
15385
+ }
15386
+ function decodeWideString(buffer, offset) {
15387
+ let end = offset;
15388
+ while (end + 1 < buffer.byteLength && (buffer[end] !== 0 || buffer[end + 1] !== 0))
15389
+ end += 2;
15390
+ return new TextDecoder("utf-16le").decode(buffer.subarray(offset, end));
15391
+ }
15392
+ function requireWindows() {
15393
+ if (process.platform !== "win32")
15394
+ throw new Error("Windows system APIs are unavailable on this platform");
15395
+ }
15396
+ function loadKernel32() {
15397
+ if (kernel32)
15398
+ return kernel32;
15399
+ kernel32 = dlopen("kernel32.dll", {
15400
+ CreateToolhelp32Snapshot: { args: [FFIType.u32, FFIType.u32], returns: FFIType.ptr },
15401
+ Process32FirstW: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
15402
+ Process32NextW: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
15403
+ CloseHandle: { args: [FFIType.ptr], returns: FFIType.i32 }
15404
+ }).symbols;
15405
+ return kernel32;
15406
+ }
15407
+ function loadIpHelper() {
15408
+ if (ipHelper)
15409
+ return ipHelper;
15410
+ ipHelper = dlopen("iphlpapi.dll", {
15411
+ GetBestRoute: { args: [FFIType.u32, FFIType.u32, FFIType.ptr], returns: FFIType.u32 },
15412
+ GetIpAddrTable: { args: [FFIType.ptr, FFIType.ptr, FFIType.i32], returns: FFIType.u32 },
15413
+ GetExtendedTcpTable: {
15414
+ args: [FFIType.ptr, FFIType.ptr, FFIType.i32, FFIType.u32, FFIType.u32, FFIType.u32],
15415
+ returns: FFIType.u32
15416
+ },
15417
+ GetExtendedUdpTable: {
15418
+ args: [FFIType.ptr, FFIType.ptr, FFIType.i32, FFIType.u32, FFIType.u32, FFIType.u32],
15419
+ returns: FFIType.u32
15420
+ }
15421
+ }).symbols;
15422
+ return ipHelper;
15423
+ }
15424
+
15425
+ // src/capture/adapter-selection.ts
15426
+ async function resolveCaptureDevice(devices, requestedName) {
15427
+ if (requestedName) {
15428
+ const requested = devices.find((device) => device.name === requestedName);
15429
+ if (requested)
15430
+ return { device: requested, usedFallback: false };
15431
+ }
15432
+ const automatic = defaultRouteDevice(devices) ?? devices.find(isUsable) ?? devices[0];
15433
+ return {
15434
+ device: automatic,
15435
+ usedFallback: Boolean(requestedName),
15436
+ ...requestedName && automatic ? { detail: "The saved adapter is unavailable; capture is using the automatically selected adapter" } : {}
15437
+ };
15438
+ }
15439
+ function chooseDeviceByRouteAddress(devices, address) {
15440
+ return devices.find((device) => device.addresses.includes(address));
15441
+ }
15442
+ function defaultRouteDevice(devices) {
15443
+ try {
15444
+ const address = defaultRouteIpv4Address();
15445
+ return address ? chooseDeviceByRouteAddress(devices, address) : undefined;
15446
+ } catch {
15447
+ return;
15448
+ }
15449
+ }
15450
+ function isUsable(device) {
15451
+ const label = `${device.name} ${device.description}`.toLowerCase();
15452
+ return !device.loopback && device.addresses.length > 0 && !["bluetooth", "wan miniport", "vmware", "hyper-v", "zerotier"].some((value) => label.includes(value));
15453
+ }
15454
+
15312
15455
  // src/capture/link-layer.ts
15313
15456
  var DATA_LINK = {
15314
15457
  NULL: 0,
@@ -15352,8 +15495,9 @@ function ipVersion(data) {
15352
15495
  // src/capture/npcap.ts
15353
15496
  import { existsSync } from "fs";
15354
15497
  import path from "path";
15355
- import { CString, dlopen, FFIType, read, toArrayBuffer } from "bun:ffi";
15498
+ import { CString, dlopen as dlopen2, FFIType as FFIType2, read, toArrayBuffer } from "bun:ffi";
15356
15499
  var ERROR_BUFFER_SIZE = 512;
15500
+ var PCAP_ERROR_PERM_DENIED = -8;
15357
15501
 
15358
15502
  class SystemNpcapRuntime {
15359
15503
  api;
@@ -15368,18 +15512,20 @@ class SystemNpcapRuntime {
15368
15512
  if (!existsSync(dllPath)) {
15369
15513
  return { availability: "missing", detail: "Npcap is not installed" };
15370
15514
  }
15371
- if (await isAdminOnlyInstall()) {
15372
- return {
15373
- availability: "admin-only",
15374
- detail: "Npcap is installed for administrators only; reinstall it with that restriction unchecked"
15375
- };
15376
- }
15377
15515
  try {
15378
15516
  const api = this.load();
15379
15517
  const version = String(api.symbols.pcap_lib_version());
15380
15518
  if (!version.toLowerCase().includes("npcap")) {
15381
15519
  return { availability: "error", detail: "The loaded packet capture library is not Npcap" };
15382
15520
  }
15521
+ const devices = this.enumerateDevices(api);
15522
+ if (devices.length === 0) {
15523
+ return {
15524
+ availability: "error",
15525
+ detail: "Npcap reported no captureable network adapters; access may require elevation",
15526
+ version
15527
+ };
15528
+ }
15383
15529
  this.readyStatus = { availability: "ready", detail: "Npcap is ready", version };
15384
15530
  return this.readyStatus;
15385
15531
  } catch (error) {
@@ -15390,7 +15536,9 @@ class SystemNpcapRuntime {
15390
15536
  const status = await this.status();
15391
15537
  if (status.availability !== "ready")
15392
15538
  throw new Error(status.detail);
15393
- const api = this.load();
15539
+ return this.enumerateDevices(this.load());
15540
+ }
15541
+ enumerateDevices(api) {
15394
15542
  const resultPointer = new Uint8Array(8);
15395
15543
  const errorBuffer = new Uint8Array(ERROR_BUFFER_SIZE);
15396
15544
  const result = api.symbols.pcap_findalldevs(resultPointer, errorBuffer);
@@ -15440,6 +15588,9 @@ class SystemNpcapRuntime {
15440
15588
  check(api.symbols.pcap_set_buffer_size(handle, 10 * 1024 * 1024), handle, api, "set capture buffer size");
15441
15589
  check(api.symbols.pcap_set_immediate_mode(handle, 1), handle, api, "enable immediate mode");
15442
15590
  const activated = api.symbols.pcap_activate(handle);
15591
+ if (activated === PCAP_ERROR_PERM_DENIED) {
15592
+ throw new Error(`Npcap denied access to ${device.description}; run elevated or reinstall Npcap without administrator-only access: ${pcapError(api, handle)}`);
15593
+ }
15443
15594
  if (activated < 0)
15444
15595
  throw new Error(`Npcap could not activate ${device.description}: ${pcapError(api, handle)}`);
15445
15596
  const dataLink = api.symbols.pcap_datalink(handle);
@@ -15463,25 +15614,25 @@ class SystemNpcapRuntime {
15463
15614
  load() {
15464
15615
  if (this.api)
15465
15616
  return this.api;
15466
- const library = dlopen(npcapDllPath(), {
15467
- pcap_lib_version: { args: [], returns: FFIType.cstring },
15468
- pcap_findalldevs: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
15469
- pcap_freealldevs: { args: [FFIType.ptr], returns: FFIType.void },
15470
- pcap_create: { args: [FFIType.cstring, FFIType.ptr], returns: FFIType.ptr },
15471
- pcap_set_snaplen: { args: [FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
15472
- pcap_set_promisc: { args: [FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
15473
- pcap_set_timeout: { args: [FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
15474
- pcap_set_buffer_size: { args: [FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
15475
- pcap_set_immediate_mode: { args: [FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
15476
- pcap_activate: { args: [FFIType.ptr], returns: FFIType.i32 },
15477
- pcap_datalink: { args: [FFIType.ptr], returns: FFIType.i32 },
15478
- pcap_compile: { args: [FFIType.ptr, FFIType.ptr, FFIType.cstring, FFIType.i32, FFIType.u32], returns: FFIType.i32 },
15479
- pcap_setfilter: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
15480
- pcap_freecode: { args: [FFIType.ptr], returns: FFIType.void },
15481
- pcap_setnonblock: { args: [FFIType.ptr, FFIType.i32, FFIType.ptr], returns: FFIType.i32 },
15482
- pcap_next_ex: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
15483
- pcap_geterr: { args: [FFIType.ptr], returns: FFIType.cstring },
15484
- pcap_close: { args: [FFIType.ptr], returns: FFIType.void }
15617
+ const library = dlopen2(npcapDllPath(), {
15618
+ pcap_lib_version: { args: [], returns: FFIType2.cstring },
15619
+ pcap_findalldevs: { args: [FFIType2.ptr, FFIType2.ptr], returns: FFIType2.i32 },
15620
+ pcap_freealldevs: { args: [FFIType2.ptr], returns: FFIType2.void },
15621
+ pcap_create: { args: [FFIType2.cstring, FFIType2.ptr], returns: FFIType2.ptr },
15622
+ pcap_set_snaplen: { args: [FFIType2.ptr, FFIType2.i32], returns: FFIType2.i32 },
15623
+ pcap_set_promisc: { args: [FFIType2.ptr, FFIType2.i32], returns: FFIType2.i32 },
15624
+ pcap_set_timeout: { args: [FFIType2.ptr, FFIType2.i32], returns: FFIType2.i32 },
15625
+ pcap_set_buffer_size: { args: [FFIType2.ptr, FFIType2.i32], returns: FFIType2.i32 },
15626
+ pcap_set_immediate_mode: { args: [FFIType2.ptr, FFIType2.i32], returns: FFIType2.i32 },
15627
+ pcap_activate: { args: [FFIType2.ptr], returns: FFIType2.i32 },
15628
+ pcap_datalink: { args: [FFIType2.ptr], returns: FFIType2.i32 },
15629
+ pcap_compile: { args: [FFIType2.ptr, FFIType2.ptr, FFIType2.cstring, FFIType2.i32, FFIType2.u32], returns: FFIType2.i32 },
15630
+ pcap_setfilter: { args: [FFIType2.ptr, FFIType2.ptr], returns: FFIType2.i32 },
15631
+ pcap_freecode: { args: [FFIType2.ptr], returns: FFIType2.void },
15632
+ pcap_setnonblock: { args: [FFIType2.ptr, FFIType2.i32, FFIType2.ptr], returns: FFIType2.i32 },
15633
+ pcap_next_ex: { args: [FFIType2.ptr, FFIType2.ptr, FFIType2.ptr], returns: FFIType2.i32 },
15634
+ pcap_geterr: { args: [FFIType2.ptr], returns: FFIType2.cstring },
15635
+ pcap_close: { args: [FFIType2.ptr], returns: FFIType2.void }
15485
15636
  });
15486
15637
  this.api = library;
15487
15638
  return this.api;
@@ -15575,20 +15726,6 @@ function readCStringBuffer(buffer) {
15575
15726
  function npcapDllPath() {
15576
15727
  return path.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "Npcap", "wpcap.dll");
15577
15728
  }
15578
- async function isAdminOnlyInstall() {
15579
- try {
15580
- const child = Bun.spawn({
15581
- cmd: ["reg.exe", "query", "HKLM\\SYSTEM\\CurrentControlSet\\Services\\npcap\\Parameters", "/v", "AdminOnly"],
15582
- stdout: "pipe",
15583
- stderr: "ignore",
15584
- windowsHide: true
15585
- });
15586
- const output = await new Response(child.stdout).text();
15587
- return await child.exited === 0 && /AdminOnly\s+REG_DWORD\s+0x1\b/i.test(output);
15588
- } catch {
15589
- return false;
15590
- }
15591
- }
15592
15729
  function errorMessage(error) {
15593
15730
  return error instanceof Error ? error.message : String(error);
15594
15731
  }
@@ -15614,7 +15751,7 @@ function parseIpv4(data, context) {
15614
15751
  const declaredLength = data.readUInt16BE(2);
15615
15752
  if (declaredLength < headerLength)
15616
15753
  return;
15617
- return parseTransport(data, headerLength, Math.min(declaredLength, data.length), declaredLength > data.length, data[9], 4, formatIpv4(data, 12), formatIpv4(data, 16), context);
15754
+ return parseTransport(data, headerLength, Math.min(declaredLength, data.length), declaredLength > data.length, data[9], 4, formatIpv42(data, 12), formatIpv42(data, 16), context);
15618
15755
  }
15619
15756
  function parseIpv6(data, context) {
15620
15757
  if (data.length < 40)
@@ -15685,7 +15822,7 @@ function parseTransport(data, offset, packetEnd, truncated, protocol, ipVersion2
15685
15822
  }
15686
15823
  return;
15687
15824
  }
15688
- function formatIpv4(data, offset) {
15825
+ function formatIpv42(data, offset) {
15689
15826
  return `${data[offset]}.${data[offset + 1]}.${data[offset + 2]}.${data[offset + 3]}`;
15690
15827
  }
15691
15828
 
@@ -15705,7 +15842,7 @@ class WindowsTargetTracker {
15705
15842
  refreshing = false;
15706
15843
  published = false;
15707
15844
  lastRefreshError;
15708
- constructor(processName, protocols, onStatus, provider = new CommandTargetSnapshotProvider, onWarning = () => {}, refreshIntervalMs = TARGET_REFRESH_INTERVAL_MS) {
15845
+ constructor(processName, protocols, onStatus, provider = new WindowsTargetSnapshotProvider, onWarning = () => {}, refreshIntervalMs = TARGET_REFRESH_INTERVAL_MS) {
15709
15846
  this.processName = processName;
15710
15847
  this.protocols = protocols;
15711
15848
  this.onStatus = onStatus;
@@ -15766,58 +15903,18 @@ class WindowsTargetTracker {
15766
15903
  }
15767
15904
  }
15768
15905
 
15769
- class CommandTargetSnapshotProvider {
15906
+ class WindowsTargetSnapshotProvider {
15770
15907
  async snapshot(processName, protocols) {
15771
- const process2 = Bun.spawn({
15772
- cmd: ["tasklist.exe", "/FI", `IMAGENAME eq ${processName}`, "/FO", "CSV", "/NH"],
15773
- stdout: "pipe",
15774
- stderr: "ignore",
15775
- windowsHide: true
15776
- });
15777
- const processOutput = await new Response(process2.stdout).text();
15778
- const processIds = await process2.exited === 0 ? parseTaskList(processOutput) : [];
15908
+ const processIds = findProcessIdsByName(processName);
15779
15909
  if (processIds.length === 0)
15780
15910
  return { processIds, endpoints: [] };
15781
- const outputs = await Promise.all(protocols.map(async (protocol) => {
15782
- const child = Bun.spawn({
15783
- cmd: ["netstat.exe", "-ano", "-p", protocol.toUpperCase()],
15784
- stdout: "pipe",
15785
- stderr: "ignore",
15786
- windowsHide: true
15787
- });
15788
- const output = await new Response(child.stdout).text();
15789
- return await child.exited === 0 ? parseNetstat(output, protocol) : [];
15790
- }));
15791
15911
  const selected = new Set(processIds);
15792
- return { processIds, endpoints: outputs.flat().filter((endpoint) => selected.has(endpoint.processId)) };
15912
+ return {
15913
+ processIds,
15914
+ endpoints: listOwnedEndpoints(protocols).filter((endpoint) => selected.has(endpoint.processId))
15915
+ };
15793
15916
  }
15794
15917
  }
15795
- function parseTaskList(output) {
15796
- return output.split(/\r?\n/).flatMap((line) => {
15797
- const match = line.match(/^"(?:[^"]|"")*","(\d+)"/);
15798
- return match ? [Number(match[1])] : [];
15799
- }).sort((left, right) => left - right);
15800
- }
15801
- function parseNetstat(output, protocol) {
15802
- return output.split(/\r?\n/).flatMap((line) => {
15803
- const columns = line.trim().split(/\s+/);
15804
- if (columns[0]?.toLowerCase() !== protocol || columns.length < (protocol === "tcp" ? 5 : 4))
15805
- return [];
15806
- const local = parseEndpoint(columns[1]);
15807
- const processId = Number(columns[protocol === "tcp" ? 4 : 3]);
15808
- return local && Number.isInteger(processId) ? [{ protocol, ...local, processId }] : [];
15809
- });
15810
- }
15811
- function parseEndpoint(value) {
15812
- const bracketed = value.match(/^\[(.*)]:(\d+)$/);
15813
- if (bracketed)
15814
- return { address: bracketed[1], port: Number(bracketed[2]) };
15815
- const split = value.lastIndexOf(":");
15816
- if (split < 0)
15817
- return;
15818
- const port = Number(value.slice(split + 1));
15819
- return Number.isInteger(port) ? { address: value.slice(0, split), port } : undefined;
15820
- }
15821
15918
  function endpointKey(protocol, address, port) {
15822
15919
  return `${protocol}|${address}|${port}`;
15823
15920
  }
@@ -15828,8 +15925,9 @@ function errorMessage2(error) {
15828
15925
  // src/capture/packet-capture.ts
15829
15926
  var POLL_INTERVAL_MS = 2;
15830
15927
  var MAX_POLL_BATCH = 128;
15831
- var PENDING_PACKET_LIMIT = 4096;
15832
- var PENDING_PACKET_MAX_AGE_MS = 1000;
15928
+ var PENDING_PACKET_LIMIT = 16384;
15929
+ var PENDING_PACKET_MAX_AGE_MS = TARGET_REFRESH_INTERVAL_MS * 5;
15930
+ var PENDING_DROP_REPORT_MS = 1e4;
15833
15931
  var systemRuntime = new SystemNpcapRuntime;
15834
15932
  async function getNpcapStatus() {
15835
15933
  return systemRuntime.status();
@@ -15851,6 +15949,8 @@ class PacketCapture extends EventEmitter {
15851
15949
  decodeFishNet = false;
15852
15950
  fishNetRpcMap;
15853
15951
  fishNetSessionDecoder = null;
15952
+ droppedPending = 0;
15953
+ droppedReportedAtMs = 0;
15854
15954
  _state = "stopped";
15855
15955
  constructor(dependencies = {}) {
15856
15956
  super();
@@ -15949,9 +16049,10 @@ class PacketCapture extends EventEmitter {
15949
16049
  packet.direction = direction;
15950
16050
  this.emitTransportPacket(packet);
15951
16051
  } else {
15952
- this.pending.push({ packet, observedAt: Date.now() });
15953
- if (this.pending.length > PENDING_PACKET_LIMIT)
15954
- this.pending.splice(0, this.pending.length - PENDING_PACKET_LIMIT);
16052
+ if (this.pending.length >= PENDING_PACKET_LIMIT)
16053
+ this.droppedPending += 1;
16054
+ else
16055
+ this.pending.push({ packet, observedAt: Date.now() });
15955
16056
  }
15956
16057
  }
15957
16058
  }
@@ -15967,13 +16068,19 @@ class PacketCapture extends EventEmitter {
15967
16068
  }
15968
16069
  }
15969
16070
  flushPending() {
15970
- if (!this.target || this.pending.length === 0)
16071
+ if (!this.target)
15971
16072
  return;
16073
+ if (this.pending.length === 0) {
16074
+ this.reportDroppedPending();
16075
+ return;
16076
+ }
15972
16077
  const cutoff = Date.now() - PENDING_PACKET_MAX_AGE_MS;
15973
16078
  const remaining = [];
15974
16079
  for (const candidate of this.pending) {
15975
- if (candidate.observedAt < cutoff)
16080
+ if (candidate.observedAt < cutoff) {
16081
+ this.droppedPending += 1;
15976
16082
  continue;
16083
+ }
15977
16084
  const direction = this.target.classify(candidate.packet);
15978
16085
  if (!direction)
15979
16086
  remaining.push(candidate);
@@ -15983,6 +16090,18 @@ class PacketCapture extends EventEmitter {
15983
16090
  }
15984
16091
  }
15985
16092
  this.pending = remaining;
16093
+ this.reportDroppedPending();
16094
+ }
16095
+ reportDroppedPending() {
16096
+ if (this.droppedPending === 0)
16097
+ return;
16098
+ const now = Date.now();
16099
+ this.droppedReportedAtMs ||= now;
16100
+ if (now - this.droppedReportedAtMs < PENDING_DROP_REPORT_MS)
16101
+ return;
16102
+ this.emitSafely("warning", `gave up on ${this.droppedPending} packets that could not be attributed to the target process`);
16103
+ this.droppedPending = 0;
16104
+ this.droppedReportedAtMs = now;
15986
16105
  }
15987
16106
  emitTransportPacket(packet) {
15988
16107
  if (packet.protocol === "tcp")
@@ -16065,6 +16184,8 @@ class PacketCapture extends EventEmitter {
16065
16184
  this.fishNetRpcMap = undefined;
16066
16185
  this.fishNetSessionDecoder?.reset();
16067
16186
  this.fishNetSessionDecoder = null;
16187
+ this.droppedPending = 0;
16188
+ this.droppedReportedAtMs = 0;
16068
16189
  }
16069
16190
  }
16070
16191
  function inferDirection(ipPacket, device) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kar-mi/spirit-vale-tools-capture",
3
- "version": "2.4.2",
3
+ "version": "2.5.1",
4
4
  "description": "Passive Windows packet capture and Spirit Vale protocol decoding for Bun.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {