@buoy-gg/network 7.0.13 → 7.0.14

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.
Files changed (123) hide show
  1. package/lib/commonjs/index.js +39 -0
  2. package/lib/commonjs/network/components/NetworkEventDetailView.js +30 -3
  3. package/lib/commonjs/network/components/NetworkEventItemCompact.js +4 -0
  4. package/lib/commonjs/network/components/NetworkHeaderLive.js +26 -6
  5. package/lib/commonjs/network/components/NetworkHeaderMenu.js +183 -0
  6. package/lib/commonjs/network/components/NetworkListScreen.js +126 -5
  7. package/lib/commonjs/network/components/NetworkModal.js +136 -29
  8. package/lib/commonjs/network/components/NetworkNumberPrompt.js +178 -0
  9. package/lib/commonjs/network/components/NetworkOverrideEditor.js +797 -0
  10. package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +102 -0
  11. package/lib/commonjs/network/components/NetworkOverridesButton.js +88 -0
  12. package/lib/commonjs/network/components/NetworkOverridesScreen.js +489 -0
  13. package/lib/commonjs/network/components/response-editor/Explorer.js +973 -0
  14. package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +56 -0
  15. package/lib/commonjs/network/components/response-editor/editorContext.js +33 -0
  16. package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +61 -0
  17. package/lib/commonjs/network/hooks/useOverrideRules.js +36 -0
  18. package/lib/commonjs/network/overrides/applyToFetch.js +80 -0
  19. package/lib/commonjs/network/overrides/applyToXhr.js +190 -0
  20. package/lib/commonjs/network/overrides/engine.js +70 -0
  21. package/lib/commonjs/network/overrides/matchRule.js +81 -0
  22. package/lib/commonjs/network/overrides/overrideRulesStore.js +550 -0
  23. package/lib/commonjs/network/overrides/presets.js +70 -0
  24. package/lib/commonjs/network/overrides/resolveOverride.js +158 -0
  25. package/lib/commonjs/network/overrides/types.js +85 -0
  26. package/lib/commonjs/network/sync/networkSyncAdapter.js +230 -1
  27. package/lib/commonjs/network/types/index.js +5 -1
  28. package/lib/commonjs/network/utils/networkEventStore.js +52 -6
  29. package/lib/commonjs/network/utils/networkListener.js +90 -10
  30. package/lib/commonjs/preset.js +11 -0
  31. package/lib/module/index.js +15 -0
  32. package/lib/module/network/components/NetworkEventDetailView.js +31 -4
  33. package/lib/module/network/components/NetworkEventItemCompact.js +5 -1
  34. package/lib/module/network/components/NetworkHeaderLive.js +26 -6
  35. package/lib/module/network/components/NetworkHeaderMenu.js +177 -0
  36. package/lib/module/network/components/NetworkListScreen.js +127 -6
  37. package/lib/module/network/components/NetworkModal.js +138 -31
  38. package/lib/module/network/components/NetworkNumberPrompt.js +174 -0
  39. package/lib/module/network/components/NetworkOverrideEditor.js +794 -0
  40. package/lib/module/network/components/NetworkOverrideHeaderButton.js +99 -0
  41. package/lib/module/network/components/NetworkOverridesButton.js +85 -0
  42. package/lib/module/network/components/NetworkOverridesScreen.js +485 -0
  43. package/lib/module/network/components/response-editor/Explorer.js +972 -0
  44. package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +51 -0
  45. package/lib/module/network/components/response-editor/editorContext.js +29 -0
  46. package/lib/module/network/components/response-editor/updateNestedDataByPath.js +56 -0
  47. package/lib/module/network/hooks/useOverrideRules.js +32 -0
  48. package/lib/module/network/overrides/applyToFetch.js +72 -0
  49. package/lib/module/network/overrides/applyToXhr.js +185 -0
  50. package/lib/module/network/overrides/engine.js +64 -0
  51. package/lib/module/network/overrides/matchRule.js +75 -0
  52. package/lib/module/network/overrides/overrideRulesStore.js +547 -0
  53. package/lib/module/network/overrides/presets.js +65 -0
  54. package/lib/module/network/overrides/resolveOverride.js +152 -0
  55. package/lib/module/network/overrides/types.js +80 -0
  56. package/lib/module/network/sync/networkSyncAdapter.js +230 -1
  57. package/lib/module/network/types/index.js +3 -1
  58. package/lib/module/network/utils/networkEventStore.js +52 -6
  59. package/lib/module/network/utils/networkListener.js +91 -10
  60. package/lib/module/preset.js +13 -1
  61. package/lib/typescript/index.d.ts +8 -0
  62. package/lib/typescript/index.d.ts.map +1 -1
  63. package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -1
  64. package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +6 -0
  65. package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
  66. package/lib/typescript/network/components/NetworkHeaderLive.d.ts +8 -1
  67. package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -1
  68. package/lib/typescript/network/components/NetworkHeaderMenu.d.ts +46 -0
  69. package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +1 -0
  70. package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
  71. package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
  72. package/lib/typescript/network/components/NetworkNumberPrompt.d.ts +33 -0
  73. package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +1 -0
  74. package/lib/typescript/network/components/NetworkOverrideEditor.d.ts +17 -0
  75. package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +1 -0
  76. package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts +27 -0
  77. package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +1 -0
  78. package/lib/typescript/network/components/NetworkOverridesButton.d.ts +17 -0
  79. package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +1 -0
  80. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +29 -0
  81. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -0
  82. package/lib/typescript/network/components/response-editor/Explorer.d.ts +17 -0
  83. package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +1 -0
  84. package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts +9 -0
  85. package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +1 -0
  86. package/lib/typescript/network/components/response-editor/editorContext.d.ts +29 -0
  87. package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +1 -0
  88. package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts +10 -0
  89. package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +1 -0
  90. package/lib/typescript/network/hooks/useOverrideRules.d.ts +29 -0
  91. package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +1 -0
  92. package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts +16 -0
  93. package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts.map +1 -0
  94. package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts +19 -0
  95. package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -0
  96. package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts +22 -0
  97. package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts.map +1 -0
  98. package/lib/typescript/network/overrides/applyToFetch.d.ts +50 -0
  99. package/lib/typescript/network/overrides/applyToFetch.d.ts.map +1 -0
  100. package/lib/typescript/network/overrides/applyToXhr.d.ts +43 -0
  101. package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -0
  102. package/lib/typescript/network/overrides/engine.d.ts +47 -0
  103. package/lib/typescript/network/overrides/engine.d.ts.map +1 -0
  104. package/lib/typescript/network/overrides/matchRule.d.ts +22 -0
  105. package/lib/typescript/network/overrides/matchRule.d.ts.map +1 -0
  106. package/lib/typescript/network/overrides/overrideRulesStore.d.ts +205 -0
  107. package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +1 -0
  108. package/lib/typescript/network/overrides/presets.d.ts +38 -0
  109. package/lib/typescript/network/overrides/presets.d.ts.map +1 -0
  110. package/lib/typescript/network/overrides/resolveOverride.d.ts +46 -0
  111. package/lib/typescript/network/overrides/resolveOverride.d.ts.map +1 -0
  112. package/lib/typescript/network/overrides/types.d.ts +169 -0
  113. package/lib/typescript/network/overrides/types.d.ts.map +1 -0
  114. package/lib/typescript/network/sync/networkSyncAdapter.d.ts +73 -0
  115. package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +1 -1
  116. package/lib/typescript/network/types/index.d.ts +10 -0
  117. package/lib/typescript/network/types/index.d.ts.map +1 -1
  118. package/lib/typescript/network/utils/networkEventStore.d.ts +14 -0
  119. package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
  120. package/lib/typescript/network/utils/networkListener.d.ts +3 -0
  121. package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
  122. package/lib/typescript/preset.d.ts.map +1 -1
  123. package/package.json +2 -2
@@ -15,12 +15,17 @@ var _NetworkCopySettingsView = require("./NetworkCopySettingsView");
15
15
  var _NetworkHeaderLive = require("./NetworkHeaderLive");
16
16
  var _NetworkListScreen = require("./NetworkListScreen");
17
17
  var _NetworkSavedScreen = require("./NetworkSavedScreen");
18
+ var _NetworkOverridesScreen = require("./NetworkOverridesScreen");
19
+ var _NetworkOverridesButton = require("./NetworkOverridesButton");
20
+ var _NetworkOverrideHeaderButton = require("./NetworkOverrideHeaderButton");
21
+ var _NetworkHeaderMenu = require("./NetworkHeaderMenu");
18
22
  var _NetworkDetailStepper = require("./NetworkDetailStepper");
19
23
  var _useNetworkEventList = require("../hooks/useNetworkEventList");
20
24
  var _useLiveNetworkEvent = require("../hooks/useLiveNetworkEvent");
21
25
  var _useNetworkSelection = require("../hooks/useNetworkSelection");
22
26
  var _networkSelectionStore = require("../utils/networkSelectionStore");
23
27
  var _networkSavedStore = require("../utils/networkSavedStore");
28
+ var _types = require("../overrides/types");
24
29
  var _jsxRuntime = require("react/jsx-runtime");
25
30
  // ============================================================================
26
31
  // Screens (rule4 stable router: each gates itself with `return null`; the
@@ -204,6 +209,27 @@ function NetworkModalInner({
204
209
  const hasSelection = (0, _useNetworkSelection.useHasNetworkSelection)();
205
210
  const [showFilterView, setShowFilterView] = (0, _react.useState)(false);
206
211
  const [showSavedView, setShowSavedView] = (0, _react.useState)(false);
212
+ const [showOverridesView, setShowOverridesView] = (0, _react.useState)(false);
213
+ const [showHeaderMenu, setShowHeaderMenu] = (0, _react.useState)(false);
214
+ /**
215
+ * Overrides are a DEVICE capability — a rule runs inside the app's own
216
+ * `fetch`/`XMLHttpRequest`, which the dashboard doesn't have.
217
+ *
218
+ * That doesn't mean the dashboard can't AUTHOR them: in `inline` mode the
219
+ * rule store runs as a mirror of the connected device (see
220
+ * `overrideRulesStore.enableRemoteMode`), so the screens below are the same
221
+ * ones the phone renders and every edit is forwarded. The one thing the
222
+ * dashboard never does is apply a rule to its own traffic —
223
+ * `disableEngine()` guarantees that.
224
+ */
225
+ const overridesAvailable = true;
226
+ /**
227
+ * A rule prefilled from a request the user was looking at, handed to the
228
+ * Overrides screen when it mounts. Lives here rather than in that screen
229
+ * because the request that seeds it is on a DIFFERENT screen — this is the
230
+ * one place both are in scope.
231
+ */
232
+ const [pendingOverrideDraft, setPendingOverrideDraft] = (0, _react.useState)(null);
207
233
  const [activeTab, setActiveTab] = (0, _react.useState)("filters");
208
234
  const [searchText, setSearchText] = (0, _react.useState)("");
209
235
  const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
@@ -282,6 +308,25 @@ function NetworkModalInner({
282
308
  const handleEventPress = (0, _react.useCallback)(event => {
283
309
  _networkSelectionStore.networkSelectionStore.select(event.id);
284
310
  }, []);
311
+
312
+ /**
313
+ * "Custom…" in a request's Override section. Stable identity because the
314
+ * detail view is memoized on its props and an unstable callback would defeat
315
+ * the bail-out that keeps prev/next stepping cheap.
316
+ */
317
+ const handleOverridePress = (0, _react.useCallback)((draft, ruleId) => {
318
+ setPendingOverrideDraft(ruleId ? {
319
+ ...draft,
320
+ id: ruleId
321
+ } : draft);
322
+ setShowOverridesView(true);
323
+ // Leave the detail view, or its header would sit on top of the editor.
324
+ _networkSelectionStore.networkSelectionStore.clear();
325
+ }, []);
326
+
327
+ // Stable identity: the Overrides screen adopts the draft in an effect keyed
328
+ // on both, so an unstable callback would re-run it every render.
329
+ const handlePendingOverrideConsumed = (0, _react.useCallback)(() => setPendingOverrideDraft(null), []);
285
330
  const handleSearch = text => {
286
331
  setSearchText(text);
287
332
  setFilter(prev => ({
@@ -345,11 +390,28 @@ function NetworkModalInner({
345
390
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
346
391
  title: "Request Details",
347
392
  centered: true
348
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Actions, {
349
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkDetailPinActions, {
393
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
394
+ children: [overridesAvailable ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverrideHeaderButton.NetworkOverrideHeaderButton, {
395
+ onOpen: handleOverridePress
396
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkDetailPinActions, {
350
397
  isPro: isPro,
351
398
  onUpgradePress: () => showUpgrade("saved")
352
- })
399
+ })]
400
+ })]
401
+ });
402
+ }
403
+
404
+ // Overrides manager header.
405
+ if (showOverridesView && overridesAvailable) {
406
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
407
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
408
+ onBack: () => {
409
+ setShowOverridesView(false);
410
+ setPendingOverrideDraft(null);
411
+ }
412
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
413
+ title: "Response Overrides",
414
+ centered: true
353
415
  })]
354
416
  });
355
417
  }
@@ -421,35 +483,26 @@ function NetworkModalInner({
421
483
  size: 14,
422
484
  color: _sharedUi.macOSColors.text.secondary
423
485
  })
424
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
425
- "sentry-label": "ignore filter",
426
- onPress: () => {
427
- setShowFilterView(true);
428
- },
429
- style: [styles.headerActionButton, (filter.status || filter.method || filter.contentType) && styles.activeFilterButton],
430
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
431
- size: 14,
432
- color: filter.status || filter.method || filter.contentType ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.muted
433
- })
434
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkSavedButton, {
435
- onPress: () => setShowSavedView(true)
436
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton, {
437
- isPro: isPro,
438
- filter: filter,
439
- ignoredPatterns: ignoredPatterns,
440
- copySettings: copySettings,
441
- paused: paused,
442
- onUpgradePress: () => showUpgrade("export")
443
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
486
+ }), overridesAvailable ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverridesButton.NetworkOverridesButton, {
487
+ onPress: () => setShowOverridesView(true)
488
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
444
489
  isEnabled: !paused,
445
490
  onToggle: () => setPaused(prev => !prev),
446
491
  accessibilityLabel: "Toggle network interception"
447
492
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkClearButton, {
448
493
  paused: paused
494
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuButton, {
495
+ onPress: () => setShowHeaderMenu(prev => !prev),
496
+ isOpen: showHeaderMenu,
497
+ hasIndicator: hasActiveFilter
449
498
  })]
450
499
  })]
451
500
  });
452
501
  };
502
+
503
+ // Surfaced on the ⋯ so moving Filters into the menu doesn't hide the one
504
+ // thing that button was communicating.
505
+ const hasActiveFilter = !!(filter.status || filter.method || filter.contentType);
453
506
  const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.network.modal();
454
507
  if (!visible) return null;
455
508
 
@@ -498,8 +551,20 @@ function NetworkModalInner({
498
551
  ignoredPatterns: ignoredPatterns,
499
552
  settings: copySettings,
500
553
  onSettingsChange: setCopySettings
554
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverridesScreen.NetworkOverridesScreen, {
555
+ visible: overridesAvailable && showOverridesView && !hasSelection && !showFilterView,
556
+ isPro: isPro,
557
+ onUpgradePress: () => showUpgrade("overrides"),
558
+ pendingDraft: pendingOverrideDraft,
559
+ onPendingConsumed: handlePendingOverrideConsumed
560
+ // Inline (desktop panel) has no home indicator to clear.
561
+ ,
562
+ applySafeAreaInset: !inline && modalMode === "bottomSheet"
501
563
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkSavedScreen.NetworkSavedScreen, {
502
- visible: showSavedView && !hasSelection && !showFilterView,
564
+ visible: showSavedView && !hasSelection && !showFilterView &&
565
+ // Overrides wins in the header branch too — the two must agree, or
566
+ // one screen renders under the other's header.
567
+ !(showOverridesView && overridesAvailable),
503
568
  isPro: isPro,
504
569
  copySettings: copySettings,
505
570
  search: savedSearch,
@@ -507,7 +572,7 @@ function NetworkModalInner({
507
572
  onEventPress: handleEventPress,
508
573
  onUpgradePress: () => showUpgrade("saved")
509
574
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkListScreen.NetworkListScreen, {
510
- visible: !hasSelection && !showFilterView && !showSavedView,
575
+ visible: !hasSelection && !showFilterView && !showSavedView && !(showOverridesView && overridesAvailable),
511
576
  paused: paused,
512
577
  filter: filter,
513
578
  ignoredPatterns: ignoredPatterns,
@@ -516,12 +581,51 @@ function NetworkModalInner({
516
581
  onEventPress: handleEventPress,
517
582
  onUpgradePress: () => showUpgrade("export")
518
583
  })]
519
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.UpgradeModal, {
584
+ }), showHeaderMenu ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_NetworkHeaderMenu.NetworkHeaderMenu, {
585
+ onClose: () => setShowHeaderMenu(false),
586
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem, {
587
+ icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
588
+ size: 14,
589
+ color: hasActiveFilter ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.secondary
590
+ }),
591
+ label: "Filters",
592
+ detail: hasActiveFilter ? "Active" : undefined,
593
+ onPress: () => {
594
+ setShowHeaderMenu(false);
595
+ setActiveTab("filters");
596
+ setShowFilterView(true);
597
+ }
598
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem, {
599
+ icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Bookmark, {
600
+ size: 14,
601
+ color: _sharedUi.macOSColors.text.secondary
602
+ }),
603
+ label: "Saved requests",
604
+ onPress: () => {
605
+ setShowHeaderMenu(false);
606
+ setShowSavedView(true);
607
+ }
608
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
609
+ style: styles.menuCopyRow,
610
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton, {
611
+ isPro: isPro,
612
+ filter: filter,
613
+ ignoredPatterns: ignoredPatterns,
614
+ copySettings: copySettings,
615
+ paused: paused,
616
+ onUpgradePress: () => {
617
+ setShowHeaderMenu(false);
618
+ showUpgrade("export");
619
+ },
620
+ label: "Copy requests"
621
+ })
622
+ })]
623
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.UpgradeModal, {
520
624
  visible: showUpgradeModal,
521
625
  onClose: () => setShowUpgradeModal(false),
522
- featureName: upgradeReason === "saved" ? "Saved Requests" : "Network Export",
523
- description: upgradeReason === "saved" ? "Keep the requests that matter. Saved requests survive Clear, app restarts, and the 500-request history cap." : "Export network requests to share with your team, debug APIs, or feed into AI tools.",
524
- benefits: upgradeReason === "saved" ? [`Save up to ${_networkSavedStore.MAX_SAVED} requests (free keeps ${_networkSavedStore.FREE_TIER_SAVED_LIMIT})`, "Failed requests stay put through a Clear", "Snapshots survive an app restart", "Export saved requests to teammates or AI assistants"] : ["Export to JSON, Markdown, or plain text", "Customizable copy presets (URLs only, LLM-ready, full data)", "Share request details with teammates", "Feed network data directly to AI assistants"]
626
+ featureName: upgradeReason === "saved" ? "Saved Requests" : upgradeReason === "overrides" ? "Response Overrides" : "Network Export",
627
+ description: upgradeReason === "saved" ? "Keep the requests that matter. Saved requests survive Clear, app restarts, and the 500-request history cap." : upgradeReason === "overrides" ? "Force any endpoint to fail, stall or return something else — no backend changes, no code changes. Free keeps one active rule." : "Export network requests to share with your team, debug APIs, or feed into AI tools.",
628
+ benefits: upgradeReason === "overrides" ? [`Run ${_types.MAX_RULES} rules at once (free keeps ${_types.FREE_TIER_RULE_LIMIT})`, "Force a 500, a 401 or an empty list in one tap", "Simulate offline, timeouts and slow connections", "Rules survive an app reload, so you can test the boot path"] : upgradeReason === "saved" ? [`Save up to ${_networkSavedStore.MAX_SAVED} requests (free keeps ${_networkSavedStore.FREE_TIER_SAVED_LIMIT})`, "Failed requests stay put through a Clear", "Snapshots survive an app restart", "Export saved requests to teammates or AI assistants"] : ["Export to JSON, Markdown, or plain text", "Customizable copy presets (URLs only, LLM-ready, full data)", "Share request details with teammates", "Feed network data directly to AI assistants"]
525
629
  })]
526
630
  });
527
631
 
@@ -604,6 +708,9 @@ const styles = _reactNative.StyleSheet.create({
604
708
  marginLeft: 6,
605
709
  padding: 4
606
710
  },
711
+ menuCopyRow: {
712
+ paddingHorizontal: 6
713
+ },
607
714
  headerActionButton: {
608
715
  width: 32,
609
716
  height: 32,
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NetworkNumberPrompt = NetworkNumberPrompt;
7
+ var _react = require("react");
8
+ var _reactNative = require("react-native");
9
+ var _sharedUi = require("@buoy-gg/shared-ui");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ /**
12
+ * Entering one number, without the keyboard eating the screen.
13
+ *
14
+ * The custom status / delay / times fields used to be inline inputs sitting
15
+ * mid-form. Focusing one raises the keyboard, which on a phone covers roughly
16
+ * the bottom half of the tool — including, depending on where you'd scrolled,
17
+ * the field you were typing into and the Save button you needed next.
18
+ *
19
+ * Pinning the panel to the TOP is the fix, and it's the same one
20
+ * `StorageValueEditModal` reached for: a centred panel gets shoved up or
21
+ * covered the moment the field focuses, and a bottom sheet is simply
22
+ * underneath it. At the top it stays put and stays readable.
23
+ *
24
+ * Deliberately not a reuse of that component — this asks for a number and
25
+ * nothing else. It has no type inference, no raw-JSON escape hatch and no
26
+ * shape-preservation rules, so borrowing 400 lines to avoid writing 100 would
27
+ * be the wrong trade.
28
+ */
29
+
30
+ function NetworkNumberPrompt({
31
+ title,
32
+ hint,
33
+ value,
34
+ placeholder = "Number",
35
+ min,
36
+ max,
37
+ onSubmit,
38
+ onCancel
39
+ }) {
40
+ const [text, setText] = (0, _react.useState)(value != null ? String(value) : "");
41
+ const submit = () => {
42
+ const trimmed = text.trim();
43
+ if (!trimmed) {
44
+ onSubmit(null);
45
+ return;
46
+ }
47
+ const parsed = Number(trimmed);
48
+ if (!Number.isFinite(parsed)) {
49
+ onSubmit(null);
50
+ return;
51
+ }
52
+ // Clamped here rather than accepted-then-silently-changed: a field that
53
+ // takes 999 and stores 599 is a field that lies.
54
+ let next = parsed;
55
+ if (min != null) next = Math.max(min, next);
56
+ if (max != null) next = Math.min(max, next);
57
+ onSubmit(next);
58
+ };
59
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
60
+ style: styles.overlay,
61
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
62
+ style: styles.backdrop,
63
+ activeOpacity: 1,
64
+ onPress: onCancel,
65
+ "sentry-label": "ignore dismiss number prompt"
66
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
67
+ style: styles.panel,
68
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
69
+ style: styles.title,
70
+ children: title
71
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
72
+ style: styles.input,
73
+ value: text,
74
+ onChangeText: setText,
75
+ placeholder: placeholder,
76
+ placeholderTextColor: _sharedUi.macOSColors.text.muted,
77
+ keyboardType: "number-pad",
78
+ autoFocus: true,
79
+ selectTextOnFocus: true,
80
+ onSubmitEditing: submit,
81
+ returnKeyType: "done",
82
+ "sentry-label": "ignore number prompt input",
83
+ accessibilityLabel: title
84
+ }), hint ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
85
+ style: styles.hint,
86
+ children: hint
87
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
88
+ style: styles.actions,
89
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
90
+ onPress: onCancel,
91
+ "sentry-label": "ignore cancel number prompt",
92
+ style: [styles.button, styles.cancelButton],
93
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
94
+ style: styles.cancelText,
95
+ children: "Cancel"
96
+ })
97
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
98
+ onPress: submit,
99
+ "sentry-label": "ignore save number prompt",
100
+ style: [styles.button, styles.saveButton],
101
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
102
+ style: styles.saveText,
103
+ children: "Set"
104
+ })
105
+ })]
106
+ })]
107
+ })]
108
+ });
109
+ }
110
+ const styles = _reactNative.StyleSheet.create({
111
+ overlay: {
112
+ ..._sharedUi.absoluteFill,
113
+ zIndex: 40
114
+ },
115
+ backdrop: {
116
+ ..._sharedUi.absoluteFill,
117
+ backgroundColor: "rgba(0,0,0,0.6)"
118
+ },
119
+ panel: {
120
+ marginHorizontal: 12,
121
+ marginTop: 12,
122
+ padding: 14,
123
+ borderRadius: 10,
124
+ borderWidth: 1,
125
+ borderColor: _sharedUi.macOSColors.border.hover,
126
+ backgroundColor: _sharedUi.macOSColors.background.card,
127
+ gap: 10
128
+ },
129
+ title: {
130
+ fontSize: 13,
131
+ fontWeight: "700",
132
+ color: _sharedUi.macOSColors.text.primary
133
+ },
134
+ input: {
135
+ backgroundColor: _sharedUi.macOSColors.background.input,
136
+ borderWidth: 1,
137
+ borderColor: _sharedUi.macOSColors.border.input,
138
+ borderRadius: 6,
139
+ paddingHorizontal: 12,
140
+ paddingVertical: 10,
141
+ fontSize: 16,
142
+ fontWeight: "700",
143
+ color: _sharedUi.macOSColors.text.primary
144
+ },
145
+ hint: {
146
+ fontSize: 10,
147
+ color: _sharedUi.macOSColors.text.muted
148
+ },
149
+ actions: {
150
+ flexDirection: "row",
151
+ gap: 8
152
+ },
153
+ button: {
154
+ flex: 1,
155
+ paddingVertical: 10,
156
+ borderRadius: 6,
157
+ alignItems: "center",
158
+ borderWidth: 1
159
+ },
160
+ cancelButton: {
161
+ borderColor: _sharedUi.macOSColors.border.default,
162
+ backgroundColor: _sharedUi.macOSColors.background.base
163
+ },
164
+ cancelText: {
165
+ fontSize: 12,
166
+ fontWeight: "600",
167
+ color: _sharedUi.macOSColors.text.secondary
168
+ },
169
+ saveButton: {
170
+ borderColor: _sharedUi.macOSColors.semantic.info,
171
+ backgroundColor: `${_sharedUi.macOSColors.semantic.info}22`
172
+ },
173
+ saveText: {
174
+ fontSize: 12,
175
+ fontWeight: "700",
176
+ color: _sharedUi.macOSColors.semantic.info
177
+ }
178
+ });