@buoy-gg/network 7.0.10 → 7.0.11

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.
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NetworkDetailStepper = void 0;
7
+ var _react = require("react");
8
+ var _sharedUi = require("@buoy-gg/shared-ui");
9
+ var _useNetworkEventList = require("../hooks/useNetworkEventList");
10
+ var _useNetworkSaved = require("../hooks/useNetworkSaved");
11
+ var _withPinnedFirst = require("../utils/withPinnedFirst");
12
+ var _selectSavedEvents = require("../utils/selectSavedEvents");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ /**
15
+ * Previous/Next footer for the request DETAIL screen — step through requests
16
+ * without bouncing back to the list.
17
+ *
18
+ * It is its OWN leaf (rule3) because it is the only part of the detail screen
19
+ * that needs the event LIST. Subscribing here keeps the request stream out of
20
+ * the detail body's render path, which is the expensive subtree (headers,
21
+ * bodies, JSON viewers, diff views): a request arriving re-renders this
22
+ * ~30-node footer and nothing else.
23
+ *
24
+ * The order it steps through is EXACTLY what the list screen renders —
25
+ * `[...pinned, ...rest]` off the same `useNetworkEventList` + `splitPinned`
26
+ * derivation — so "Next" always lands on the row below the one the user
27
+ * tapped. Because the live filter is an input, typing in the search box or
28
+ * flipping a status chip re-scopes the stepper in place; the counter is
29
+ * "request N of <what the list is showing>", never "N of everything ever
30
+ * captured". Detail opened from the Saved screen steps through the SAVED
31
+ * list instead (with its own search applied), for the same reason.
32
+ */
33
+
34
+ const NetworkDetailStepper = exports.NetworkDetailStepper = /*#__PURE__*/(0, _react.memo)(function NetworkDetailStepper({
35
+ eventId,
36
+ paused,
37
+ filter,
38
+ ignoredPatterns,
39
+ isPro,
40
+ fromSaved,
41
+ savedSearch,
42
+ onSelect
43
+ }) {
44
+ const {
45
+ visibleEvents
46
+ } = (0, _useNetworkEventList.useNetworkEventList)({
47
+ filter,
48
+ ignoredPatterns,
49
+ paused,
50
+ isPro
51
+ });
52
+ const {
53
+ pinnedEvents,
54
+ pinnedLiveIds,
55
+ savedRecords
56
+ } = (0, _useNetworkSaved.useNetworkSaved)();
57
+ const ordered = (0, _react.useMemo)(() => {
58
+ if (fromSaved) {
59
+ return (0, _selectSavedEvents.selectSavedEvents)(savedRecords, isPro, savedSearch).events;
60
+ }
61
+ // Same split the list screen does — pins render above the FlatList, so
62
+ // they come first here too.
63
+ const {
64
+ pinned,
65
+ rest
66
+ } = (0, _withPinnedFirst.splitPinned)(visibleEvents, pinnedEvents, pinnedLiveIds);
67
+ return pinned.length === 0 ? rest : [...pinned, ...rest];
68
+ }, [fromSaved, savedRecords, savedSearch, isPro, visibleEvents, pinnedEvents, pinnedLiveIds]);
69
+ const index = ordered.findIndex(event => event.id === eventId);
70
+
71
+ // Not in the list at all: the filter changed under it while it was open, it
72
+ // aged past the 500-request cap, or it is a saved snapshot with no live twin.
73
+ // There is no coherent "next" in that state, so show no footer rather than a
74
+ // counter that lies.
75
+ if (index < 0) return null;
76
+
77
+ // Both lists are newest-first, so "Previous" walks toward the NEWER request —
78
+ // the same direction as scrolling up, which is what the arrow means here.
79
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
80
+ currentIndex: index,
81
+ totalItems: ordered.length,
82
+ itemLabel: "Request",
83
+ onPrevious: () => {
84
+ const target = ordered[index - 1];
85
+ if (target) onSelect(target.id);
86
+ },
87
+ onNext: () => {
88
+ const target = ordered[index + 1];
89
+ if (target) onSelect(target.id);
90
+ }
91
+ });
92
+ });
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.selectSavedEvents = selectSavedEvents;
7
+ var _filterNetworkEvents = require("./filterNetworkEvents");
8
+ var _networkSavedStore = require("./networkSavedStore");
9
+ /**
10
+ * The SAVED screen's visible list, as a pure function.
11
+ *
12
+ * Two places need the exact same list: the screen that renders it
13
+ * (`NetworkSavedScreen`) and the detail footer that steps through it
14
+ * (`NetworkDetailStepper`). If they derived it independently, "Next" would
15
+ * eventually disagree with the row below — the same drift `withPinnedFirst`
16
+ * exists to prevent for the live list.
17
+ */
18
+
19
+ function selectSavedEvents(savedRecords, isPro, search) {
20
+ /**
21
+ * A downgrade (or a limit change) can leave a free user holding more saves
22
+ * than the free tier allows. Rather than deleting their data, the overflow
23
+ * is LOCKED — oldest first, so the newest saves stay reachable.
24
+ */
25
+ const limit = isPro ? _networkSavedStore.MAX_SAVED : _networkSavedStore.FREE_TIER_SAVED_LIMIT;
26
+ const unlocked = savedRecords.slice(0, limit);
27
+ const events = unlocked.map(record => record.event);
28
+ return {
29
+ events: search ? (0, _filterNetworkEvents.filterNetworkEvents)(events, {
30
+ searchText: search
31
+ }) : events,
32
+ lockedCount: savedRecords.length - unlocked.length
33
+ };
34
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Previous/Next footer for the request DETAIL screen — step through requests
5
+ * without bouncing back to the list.
6
+ *
7
+ * It is its OWN leaf (rule3) because it is the only part of the detail screen
8
+ * that needs the event LIST. Subscribing here keeps the request stream out of
9
+ * the detail body's render path, which is the expensive subtree (headers,
10
+ * bodies, JSON viewers, diff views): a request arriving re-renders this
11
+ * ~30-node footer and nothing else.
12
+ *
13
+ * The order it steps through is EXACTLY what the list screen renders —
14
+ * `[...pinned, ...rest]` off the same `useNetworkEventList` + `splitPinned`
15
+ * derivation — so "Next" always lands on the row below the one the user
16
+ * tapped. Because the live filter is an input, typing in the search box or
17
+ * flipping a status chip re-scopes the stepper in place; the counter is
18
+ * "request N of <what the list is showing>", never "N of everything ever
19
+ * captured". Detail opened from the Saved screen steps through the SAVED
20
+ * list instead (with its own search applied), for the same reason.
21
+ */
22
+
23
+ import { memo, useMemo } from "react";
24
+ import { EventStepperFooter } from "@buoy-gg/shared-ui";
25
+ import { useNetworkEventList } from "../hooks/useNetworkEventList";
26
+ import { useNetworkSaved } from "../hooks/useNetworkSaved";
27
+ import { splitPinned } from "../utils/withPinnedFirst";
28
+ import { selectSavedEvents } from "../utils/selectSavedEvents";
29
+ import { jsx as _jsx } from "react/jsx-runtime";
30
+ export const NetworkDetailStepper = /*#__PURE__*/memo(function NetworkDetailStepper({
31
+ eventId,
32
+ paused,
33
+ filter,
34
+ ignoredPatterns,
35
+ isPro,
36
+ fromSaved,
37
+ savedSearch,
38
+ onSelect
39
+ }) {
40
+ const {
41
+ visibleEvents
42
+ } = useNetworkEventList({
43
+ filter,
44
+ ignoredPatterns,
45
+ paused,
46
+ isPro
47
+ });
48
+ const {
49
+ pinnedEvents,
50
+ pinnedLiveIds,
51
+ savedRecords
52
+ } = useNetworkSaved();
53
+ const ordered = useMemo(() => {
54
+ if (fromSaved) {
55
+ return selectSavedEvents(savedRecords, isPro, savedSearch).events;
56
+ }
57
+ // Same split the list screen does — pins render above the FlatList, so
58
+ // they come first here too.
59
+ const {
60
+ pinned,
61
+ rest
62
+ } = splitPinned(visibleEvents, pinnedEvents, pinnedLiveIds);
63
+ return pinned.length === 0 ? rest : [...pinned, ...rest];
64
+ }, [fromSaved, savedRecords, savedSearch, isPro, visibleEvents, pinnedEvents, pinnedLiveIds]);
65
+ const index = ordered.findIndex(event => event.id === eventId);
66
+
67
+ // Not in the list at all: the filter changed under it while it was open, it
68
+ // aged past the 500-request cap, or it is a saved snapshot with no live twin.
69
+ // There is no coherent "next" in that state, so show no footer rather than a
70
+ // counter that lies.
71
+ if (index < 0) return null;
72
+
73
+ // Both lists are newest-first, so "Previous" walks toward the NEWER request —
74
+ // the same direction as scrolling up, which is what the arrow means here.
75
+ return /*#__PURE__*/_jsx(EventStepperFooter, {
76
+ currentIndex: index,
77
+ totalItems: ordered.length,
78
+ itemLabel: "Request",
79
+ onPrevious: () => {
80
+ const target = ordered[index - 1];
81
+ if (target) onSelect(target.id);
82
+ },
83
+ onNext: () => {
84
+ const target = ordered[index + 1];
85
+ if (target) onSelect(target.id);
86
+ }
87
+ });
88
+ });
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * The SAVED screen's visible list, as a pure function.
5
+ *
6
+ * Two places need the exact same list: the screen that renders it
7
+ * (`NetworkSavedScreen`) and the detail footer that steps through it
8
+ * (`NetworkDetailStepper`). If they derived it independently, "Next" would
9
+ * eventually disagree with the row below — the same drift `withPinnedFirst`
10
+ * exists to prevent for the live list.
11
+ */
12
+
13
+ import { filterNetworkEvents } from "./filterNetworkEvents";
14
+ import { FREE_TIER_SAVED_LIMIT, MAX_SAVED } from "./networkSavedStore";
15
+ export function selectSavedEvents(savedRecords, isPro, search) {
16
+ /**
17
+ * A downgrade (or a limit change) can leave a free user holding more saves
18
+ * than the free tier allows. Rather than deleting their data, the overflow
19
+ * is LOCKED — oldest first, so the newest saves stay reachable.
20
+ */
21
+ const limit = isPro ? MAX_SAVED : FREE_TIER_SAVED_LIMIT;
22
+ const unlocked = savedRecords.slice(0, limit);
23
+ const events = unlocked.map(record => record.event);
24
+ return {
25
+ events: search ? filterNetworkEvents(events, {
26
+ searchText: search
27
+ }) : events,
28
+ lockedCount: savedRecords.length - unlocked.length
29
+ };
30
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Previous/Next footer for the request DETAIL screen — step through requests
3
+ * without bouncing back to the list.
4
+ *
5
+ * It is its OWN leaf (rule3) because it is the only part of the detail screen
6
+ * that needs the event LIST. Subscribing here keeps the request stream out of
7
+ * the detail body's render path, which is the expensive subtree (headers,
8
+ * bodies, JSON viewers, diff views): a request arriving re-renders this
9
+ * ~30-node footer and nothing else.
10
+ *
11
+ * The order it steps through is EXACTLY what the list screen renders —
12
+ * `[...pinned, ...rest]` off the same `useNetworkEventList` + `splitPinned`
13
+ * derivation — so "Next" always lands on the row below the one the user
14
+ * tapped. Because the live filter is an input, typing in the search box or
15
+ * flipping a status chip re-scopes the stepper in place; the counter is
16
+ * "request N of <what the list is showing>", never "N of everything ever
17
+ * captured". Detail opened from the Saved screen steps through the SAVED
18
+ * list instead (with its own search applied), for the same reason.
19
+ */
20
+ import { type IgnoredPattern } from "@buoy-gg/shared-ui";
21
+ import type { NetworkFilter } from "../types";
22
+ interface NetworkDetailStepperProps {
23
+ /** The request currently on screen. */
24
+ eventId: string;
25
+ paused: boolean;
26
+ filter: NetworkFilter;
27
+ ignoredPatterns: readonly IgnoredPattern[];
28
+ isPro: boolean;
29
+ /** Detail was opened from the Saved screen — step through THAT list. */
30
+ fromSaved: boolean;
31
+ /** The Saved screen's search box (lifted to the modal root so both agree). */
32
+ savedSearch: string;
33
+ onSelect: (eventId: string) => void;
34
+ }
35
+ export declare const NetworkDetailStepper: import("react").NamedExoticComponent<NetworkDetailStepperProps>;
36
+ export {};
37
+ //# sourceMappingURL=NetworkDetailStepper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkDetailStepper.d.ts","sourceRoot":"","sources":["../../../../src/network/components/NetworkDetailStepper.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,UAAU,CAAC;AAM5D,UAAU,yBAAyB;IACjC,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,eAAe,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,KAAK,EAAE,OAAO,CAAC;IACf,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,eAAO,MAAM,oBAAoB,iEAiE/B,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The SAVED screen's visible list, as a pure function.
3
+ *
4
+ * Two places need the exact same list: the screen that renders it
5
+ * (`NetworkSavedScreen`) and the detail footer that steps through it
6
+ * (`NetworkDetailStepper`). If they derived it independently, "Next" would
7
+ * eventually disagree with the row below — the same drift `withPinnedFirst`
8
+ * exists to prevent for the live list.
9
+ */
10
+ import type { NetworkEvent } from "../types";
11
+ import { type SavedNetworkRecord } from "./networkSavedStore";
12
+ export interface SavedEventSelection {
13
+ /** Unlocked saves, minus anything the search box excludes. */
14
+ events: NetworkEvent[];
15
+ /** Saves past the tier ceiling — rendered as the upgrade banner, not rows. */
16
+ lockedCount: number;
17
+ }
18
+ export declare function selectSavedEvents(savedRecords: readonly SavedNetworkRecord[], isPro: boolean, search: string): SavedEventSelection;
19
+ //# sourceMappingURL=selectSavedEvents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectSavedEvents.d.ts","sourceRoot":"","sources":["../../../../src/network/utils/selectSavedEvents.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,SAAS,kBAAkB,EAAE,EAC3C,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,mBAAmB,CAarB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/network",
3
- "version": "7.0.10",
3
+ "version": "7.0.11",
4
4
  "description": "In-app network inspector for React Native — requests, responses, timing & errors live, with GraphQL operation parsing. Part of Buoy devtools.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -26,7 +26,7 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
- "@buoy-gg/shared-ui": "^7.0.10"
29
+ "@buoy-gg/shared-ui": "^7.0.11"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "react": "*",