@buoy-gg/shared-ui 7.0.33 → 7.0.35
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/lib/commonjs/JsModal.js +57 -22
- package/lib/commonjs/dataViewer/CyberpunkInput.js +3 -2
- package/lib/commonjs/dataViewer/DataTreeActionBar.js +3 -2
- package/lib/commonjs/dataViewer/DataTreeActionDock.js +2 -1
- package/lib/commonjs/dataViewer/DiffSummary.js +4 -3
- package/lib/commonjs/dataViewer/LiveExplorer.js +11 -10
- package/lib/commonjs/dataViewer/SplitDiffViewer.js +10 -9
- package/lib/commonjs/dataViewer/ThemedSplitView.js +12 -11
- package/lib/commonjs/dataViewer/ValueEditModal.js +6 -5
- package/lib/commonjs/dataViewer/VirtualizedDataExplorer.js +4 -3
- package/lib/commonjs/dataViewer/tree/TreeDiffViewer.js +15 -14
- package/lib/commonjs/hooks/index.js +26 -0
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/hooks/useChangeLog.js +55 -0
- package/lib/commonjs/hooks/useEventStoreEvents.js +65 -0
- package/lib/commonjs/hooks/usePersistedState.js +45 -10
- package/lib/commonjs/icons/index.js +533 -1
- package/lib/commonjs/index.js +143 -0
- package/lib/commonjs/license/FreeAccountPrompt.js +2 -1
- package/lib/commonjs/license/LicenseEntryModal.js +2 -1
- package/lib/commonjs/storage/definePersistedSetting.js +67 -0
- package/lib/commonjs/storage/index.js +8 -1
- package/lib/commonjs/stores/ChangeLog.js +197 -0
- package/lib/commonjs/stores/createToolStore.js +175 -0
- package/lib/commonjs/stores/index.js +15 -1
- package/lib/commonjs/sync/toolSyncAdapter.js +63 -0
- package/lib/commonjs/sync/wireForm.js +172 -0
- package/lib/commonjs/tools/defineTool.js +79 -0
- package/lib/commonjs/ui/components/ChangeRow.js +111 -0
- package/lib/commonjs/ui/components/ChipStrip.js +94 -0
- package/lib/commonjs/ui/components/ClipboardHintBanner.js +2 -1
- package/lib/commonjs/ui/components/CompactRow.js +3 -2
- package/lib/commonjs/ui/components/DataInspector.js +3 -2
- package/lib/commonjs/ui/components/DetailView.js +2 -1
- package/lib/commonjs/ui/components/DetailViewToggle.js +130 -0
- package/lib/commonjs/ui/components/DevToolsCard.js +3 -1
- package/lib/commonjs/ui/components/DynamicFilterView.js +8 -7
- package/lib/commonjs/ui/components/EntityFilterView.js +355 -0
- package/lib/commonjs/ui/components/EventHistoryViewer/CompareBar.js +5 -4
- package/lib/commonjs/ui/components/EventHistoryViewer/DiffModeTabs.js +2 -1
- package/lib/commonjs/ui/components/EventHistoryViewer/EventPickerModal.js +5 -4
- package/lib/commonjs/ui/components/EventStepperFooter.js +4 -3
- package/lib/commonjs/ui/components/ExpandablePopover.js +12 -4
- package/lib/commonjs/ui/components/ExpandedInfoRow.js +3 -2
- package/lib/commonjs/ui/components/ExportPreview.js +174 -0
- package/lib/commonjs/ui/components/FilterComponents.js +2 -1
- package/lib/commonjs/ui/components/InfoRow.js +91 -0
- package/lib/commonjs/ui/components/ModalHeader.js +40 -7
- package/lib/commonjs/ui/components/Pill.js +115 -0
- package/lib/commonjs/ui/components/ToggleRow.js +116 -0
- package/lib/commonjs/ui/components/ToolFooter.js +205 -0
- package/lib/commonjs/ui/components/index.js +100 -1
- package/lib/commonjs/ui/console/CyberpunkSectionButton.js +3 -2
- package/lib/commonjs/ui/fonts.js +12 -0
- package/lib/commonjs/ui/gameUI/components/GameUICollapsibleSection.js +4 -3
- package/lib/commonjs/ui/gameUI/components/GameUICompactStats.js +12 -11
- package/lib/commonjs/ui/gameUI/components/GameUIIssuesList.js +9 -8
- package/lib/commonjs/ui/gameUI/components/GameUIStatusHeader.js +4 -3
- package/lib/commonjs/ui/index.js +32 -2
- package/lib/commonjs/ui/listPresets.js +43 -0
- package/lib/commonjs/ui/night/primitives.js +3 -1
- package/lib/commonjs/ui/toolTheme.js +4 -3
- package/lib/commonjs/utils/snapshotProviderKit.js +167 -0
- package/lib/commonjs/utils/stateTools.js +160 -0
- package/lib/module/JsModal.js +57 -22
- package/lib/module/dataViewer/CyberpunkInput.js +3 -2
- package/lib/module/dataViewer/DataTreeActionBar.js +3 -2
- package/lib/module/dataViewer/DataTreeActionDock.js +2 -1
- package/lib/module/dataViewer/DiffSummary.js +4 -3
- package/lib/module/dataViewer/LiveExplorer.js +11 -11
- package/lib/module/dataViewer/SplitDiffViewer.js +10 -9
- package/lib/module/dataViewer/ThemedSplitView.js +12 -11
- package/lib/module/dataViewer/ValueEditModal.js +6 -5
- package/lib/module/dataViewer/VirtualizedDataExplorer.js +5 -4
- package/lib/module/dataViewer/tree/TreeDiffViewer.js +15 -15
- package/lib/module/hooks/index.js +3 -1
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/hooks/useChangeLog.js +50 -0
- package/lib/module/hooks/useEventStoreEvents.js +61 -0
- package/lib/module/hooks/usePersistedState.js +44 -10
- package/lib/module/icons/index.js +27 -2
- package/lib/module/index.js +11 -1
- package/lib/module/license/FreeAccountPrompt.js +2 -2
- package/lib/module/license/LicenseEntryModal.js +3 -3
- package/lib/module/storage/definePersistedSetting.js +63 -0
- package/lib/module/storage/index.js +2 -1
- package/lib/module/stores/ChangeLog.js +192 -0
- package/lib/module/stores/createToolStore.js +171 -0
- package/lib/module/stores/index.js +3 -1
- package/lib/module/sync/toolSyncAdapter.js +58 -0
- package/lib/module/sync/wireForm.js +159 -0
- package/lib/module/tools/defineTool.js +74 -0
- package/lib/module/ui/components/ChangeRow.js +106 -0
- package/lib/module/ui/components/ChipStrip.js +91 -0
- package/lib/module/ui/components/ClipboardHintBanner.js +2 -1
- package/lib/module/ui/components/CompactRow.js +3 -2
- package/lib/module/ui/components/DataInspector.js +3 -2
- package/lib/module/ui/components/DetailView.js +2 -1
- package/lib/module/ui/components/DetailViewToggle.js +125 -0
- package/lib/module/ui/components/DevToolsCard.js +3 -1
- package/lib/module/ui/components/DynamicFilterView.js +8 -7
- package/lib/module/ui/components/EntityFilterView.js +351 -0
- package/lib/module/ui/components/EventHistoryViewer/CompareBar.js +6 -5
- package/lib/module/ui/components/EventHistoryViewer/DiffModeTabs.js +3 -2
- package/lib/module/ui/components/EventHistoryViewer/EventPickerModal.js +6 -5
- package/lib/module/ui/components/EventStepperFooter.js +4 -3
- package/lib/module/ui/components/ExpandablePopover.js +12 -4
- package/lib/module/ui/components/ExpandedInfoRow.js +3 -2
- package/lib/module/ui/components/ExportPreview.js +169 -0
- package/lib/module/ui/components/FilterComponents.js +2 -2
- package/lib/module/ui/components/InfoRow.js +87 -0
- package/lib/module/ui/components/ModalHeader.js +40 -7
- package/lib/module/ui/components/Pill.js +111 -0
- package/lib/module/ui/components/ToggleRow.js +112 -0
- package/lib/module/ui/components/ToolFooter.js +197 -0
- package/lib/module/ui/components/index.js +10 -1
- package/lib/module/ui/console/CyberpunkSectionButton.js +3 -2
- package/lib/module/ui/fonts.js +8 -0
- package/lib/module/ui/gameUI/components/GameUICollapsibleSection.js +4 -3
- package/lib/module/ui/gameUI/components/GameUICompactStats.js +12 -11
- package/lib/module/ui/gameUI/components/GameUIIssuesList.js +9 -8
- package/lib/module/ui/gameUI/components/GameUIStatusHeader.js +4 -3
- package/lib/module/ui/index.js +7 -1
- package/lib/module/ui/listPresets.js +39 -0
- package/lib/module/ui/night/primitives.js +3 -1
- package/lib/module/ui/toolTheme.js +4 -4
- package/lib/module/utils/snapshotProviderKit.js +156 -0
- package/lib/module/utils/stateTools.js +154 -0
- package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/CyberpunkInput.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/DataTreeActionBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/DiffSummary.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/LiveExplorer.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/SplitDiffViewer.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/ThemedSplitView.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/ValueEditModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/VirtualizedDataExplorer.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/tree/TreeDiffViewer.d.ts.map +1 -1
- package/lib/typescript/commonjs/hooks/index.d.ts +3 -1
- package/lib/typescript/commonjs/hooks/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/hooks/useChangeLog.d.ts +38 -0
- package/lib/typescript/commonjs/hooks/useChangeLog.d.ts.map +1 -0
- package/lib/typescript/commonjs/hooks/useEventStoreEvents.d.ts +25 -0
- package/lib/typescript/commonjs/hooks/useEventStoreEvents.d.ts.map +1 -0
- package/lib/typescript/commonjs/hooks/usePersistedState.d.ts +34 -5
- package/lib/typescript/commonjs/hooks/usePersistedState.d.ts.map +1 -1
- package/lib/typescript/commonjs/icons/index.d.ts +4 -1
- package/lib/typescript/commonjs/icons/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +6 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/LicenseEntryModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/storage/definePersistedSetting.d.ts +39 -0
- package/lib/typescript/commonjs/storage/definePersistedSetting.d.ts.map +1 -0
- package/lib/typescript/commonjs/storage/index.d.ts +1 -0
- package/lib/typescript/commonjs/storage/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/stores/ChangeLog.d.ts +100 -0
- package/lib/typescript/commonjs/stores/ChangeLog.d.ts.map +1 -0
- package/lib/typescript/commonjs/stores/createToolStore.d.ts +92 -0
- package/lib/typescript/commonjs/stores/createToolStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/stores/index.d.ts +2 -0
- package/lib/typescript/commonjs/stores/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/sync/toolSyncAdapter.d.ts +66 -0
- package/lib/typescript/commonjs/sync/toolSyncAdapter.d.ts.map +1 -0
- package/lib/typescript/commonjs/sync/wireForm.d.ts +100 -0
- package/lib/typescript/commonjs/sync/wireForm.d.ts.map +1 -0
- package/lib/typescript/commonjs/tools/defineTool.d.ts +100 -0
- package/lib/typescript/commonjs/tools/defineTool.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ChangeRow.d.ts +52 -0
- package/lib/typescript/commonjs/ui/components/ChangeRow.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ChipStrip.d.ts +41 -0
- package/lib/typescript/commonjs/ui/components/ChipStrip.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ClipboardHintBanner.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/CompactRow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/DataInspector.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/DetailView.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/DetailViewToggle.d.ts +36 -0
- package/lib/typescript/commonjs/ui/components/DetailViewToggle.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/DevToolsCard.d.ts +8 -1
- package/lib/typescript/commonjs/ui/components/DevToolsCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/DynamicFilterView.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EntityFilterView.d.ts +51 -0
- package/lib/typescript/commonjs/ui/components/EntityFilterView.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/CompareBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/DiffModeTabs.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/EventPickerModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventStepperFooter.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ExpandablePopover.d.ts +5 -1
- package/lib/typescript/commonjs/ui/components/ExpandablePopover.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ExpandedInfoRow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ExportPreview.d.ts +48 -0
- package/lib/typescript/commonjs/ui/components/ExportPreview.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/FilterComponents.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/InfoRow.d.ts +33 -0
- package/lib/typescript/commonjs/ui/components/InfoRow.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts +31 -1
- package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/Pill.d.ts +38 -0
- package/lib/typescript/commonjs/ui/components/Pill.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ToggleRow.d.ts +33 -0
- package/lib/typescript/commonjs/ui/components/ToggleRow.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ToolFooter.d.ts +69 -0
- package/lib/typescript/commonjs/ui/components/ToolFooter.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/index.d.ts +9 -0
- package/lib/typescript/commonjs/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/console/CyberpunkSectionButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/fonts.d.ts +7 -0
- package/lib/typescript/commonjs/ui/fonts.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/gameUI/components/GameUICollapsibleSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/gameUI/components/GameUICompactStats.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/gameUI/components/GameUIIssuesList.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/gameUI/components/GameUIStatusHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +2 -0
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/listPresets.d.ts +28 -0
- package/lib/typescript/commonjs/ui/listPresets.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/night/primitives.d.ts +3 -1
- package/lib/typescript/commonjs/ui/night/primitives.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/toolTheme.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/snapshotProviderKit.d.ts +81 -0
- package/lib/typescript/commonjs/utils/snapshotProviderKit.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/stateTools.d.ts +44 -0
- package/lib/typescript/commonjs/utils/stateTools.d.ts.map +1 -0
- package/lib/typescript/module/JsModal.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/CyberpunkInput.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/DataTreeActionBar.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/DiffSummary.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/LiveExplorer.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/SplitDiffViewer.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/ThemedSplitView.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/ValueEditModal.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/VirtualizedDataExplorer.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/tree/TreeDiffViewer.d.ts.map +1 -1
- package/lib/typescript/module/hooks/index.d.ts +3 -1
- package/lib/typescript/module/hooks/index.d.ts.map +1 -1
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/hooks/useChangeLog.d.ts +38 -0
- package/lib/typescript/module/hooks/useChangeLog.d.ts.map +1 -0
- package/lib/typescript/module/hooks/useEventStoreEvents.d.ts +25 -0
- package/lib/typescript/module/hooks/useEventStoreEvents.d.ts.map +1 -0
- package/lib/typescript/module/hooks/usePersistedState.d.ts +34 -5
- package/lib/typescript/module/hooks/usePersistedState.d.ts.map +1 -1
- package/lib/typescript/module/icons/index.d.ts +4 -1
- package/lib/typescript/module/icons/index.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +6 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/license/FreeAccountPrompt.d.ts.map +1 -1
- package/lib/typescript/module/license/LicenseEntryModal.d.ts.map +1 -1
- package/lib/typescript/module/storage/definePersistedSetting.d.ts +39 -0
- package/lib/typescript/module/storage/definePersistedSetting.d.ts.map +1 -0
- package/lib/typescript/module/storage/index.d.ts +1 -0
- package/lib/typescript/module/storage/index.d.ts.map +1 -1
- package/lib/typescript/module/stores/ChangeLog.d.ts +100 -0
- package/lib/typescript/module/stores/ChangeLog.d.ts.map +1 -0
- package/lib/typescript/module/stores/createToolStore.d.ts +92 -0
- package/lib/typescript/module/stores/createToolStore.d.ts.map +1 -0
- package/lib/typescript/module/stores/index.d.ts +2 -0
- package/lib/typescript/module/stores/index.d.ts.map +1 -1
- package/lib/typescript/module/sync/toolSyncAdapter.d.ts +66 -0
- package/lib/typescript/module/sync/toolSyncAdapter.d.ts.map +1 -0
- package/lib/typescript/module/sync/wireForm.d.ts +100 -0
- package/lib/typescript/module/sync/wireForm.d.ts.map +1 -0
- package/lib/typescript/module/tools/defineTool.d.ts +100 -0
- package/lib/typescript/module/tools/defineTool.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ChangeRow.d.ts +52 -0
- package/lib/typescript/module/ui/components/ChangeRow.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ChipStrip.d.ts +41 -0
- package/lib/typescript/module/ui/components/ChipStrip.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ClipboardHintBanner.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/CompactRow.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/DataInspector.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/DetailView.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/DetailViewToggle.d.ts +36 -0
- package/lib/typescript/module/ui/components/DetailViewToggle.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/DevToolsCard.d.ts +8 -1
- package/lib/typescript/module/ui/components/DevToolsCard.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/DynamicFilterView.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EntityFilterView.d.ts +51 -0
- package/lib/typescript/module/ui/components/EntityFilterView.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/EventHistoryViewer/CompareBar.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/DiffModeTabs.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/EventPickerModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventStepperFooter.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ExpandablePopover.d.ts +5 -1
- package/lib/typescript/module/ui/components/ExpandablePopover.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ExpandedInfoRow.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ExportPreview.d.ts +48 -0
- package/lib/typescript/module/ui/components/ExportPreview.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/FilterComponents.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/InfoRow.d.ts +33 -0
- package/lib/typescript/module/ui/components/InfoRow.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ModalHeader.d.ts +31 -1
- package/lib/typescript/module/ui/components/ModalHeader.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/Pill.d.ts +38 -0
- package/lib/typescript/module/ui/components/Pill.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ToggleRow.d.ts +33 -0
- package/lib/typescript/module/ui/components/ToggleRow.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ToolFooter.d.ts +69 -0
- package/lib/typescript/module/ui/components/ToolFooter.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/index.d.ts +9 -0
- package/lib/typescript/module/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/console/CyberpunkSectionButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/fonts.d.ts +7 -0
- package/lib/typescript/module/ui/fonts.d.ts.map +1 -0
- package/lib/typescript/module/ui/gameUI/components/GameUICollapsibleSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/gameUI/components/GameUICompactStats.d.ts.map +1 -1
- package/lib/typescript/module/ui/gameUI/components/GameUIIssuesList.d.ts.map +1 -1
- package/lib/typescript/module/ui/gameUI/components/GameUIStatusHeader.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +2 -0
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/listPresets.d.ts +28 -0
- package/lib/typescript/module/ui/listPresets.d.ts.map +1 -0
- package/lib/typescript/module/ui/night/primitives.d.ts +3 -1
- package/lib/typescript/module/ui/night/primitives.d.ts.map +1 -1
- package/lib/typescript/module/ui/toolTheme.d.ts.map +1 -1
- package/lib/typescript/module/utils/snapshotProviderKit.d.ts +81 -0
- package/lib/typescript/module/utils/snapshotProviderKit.d.ts.map +1 -0
- package/lib/typescript/module/utils/stateTools.d.ts +44 -0
- package/lib/typescript/module/utils/stateTools.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -10,25 +10,43 @@ import { persistentStorage } from "../utils/persistentStorage.js";
|
|
|
10
10
|
*/
|
|
11
11
|
const hydratedCache = new Map();
|
|
12
12
|
|
|
13
|
+
/** The two calls a backend needs. `persistentStorage` and AsyncStorage both fit. */
|
|
14
|
+
|
|
15
|
+
function defaultParse(raw) {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(raw);
|
|
18
|
+
} catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
/**
|
|
14
24
|
* `useState` persisted through `persistentStorage` (FileSystem → AsyncStorage
|
|
15
25
|
* → memory). Replaces the load-then-`hasLoaded`-guard `useEffect` pattern
|
|
16
26
|
* every tool used to hand-roll.
|
|
17
27
|
*
|
|
18
|
-
* Values are JSON-serialized; the default is returned until
|
|
19
|
-
* completes (subsequent mounts of the same key hydrate synchronously
|
|
20
|
-
* in-memory cache). The third tuple element reports hydration so
|
|
21
|
-
* defer writes that must not clobber a not-yet-loaded value.
|
|
28
|
+
* Values are JSON-serialized by default; the default is returned until
|
|
29
|
+
* hydration completes (subsequent mounts of the same key hydrate synchronously
|
|
30
|
+
* from an in-memory cache). The third tuple element reports hydration so
|
|
31
|
+
* callers can defer writes that must not clobber a not-yet-loaded value.
|
|
22
32
|
*
|
|
23
33
|
* ```tsx
|
|
24
34
|
* const [tab, setTab, tabHydrated] = usePersistedState("@react_buoy_custom_flags_tab", "flags");
|
|
35
|
+
*
|
|
36
|
+
* // A Set, stored as an array:
|
|
37
|
+
* const [pins, setPins] = usePersistedState(key, new Set<string>(), {
|
|
38
|
+
* parse: (raw) => new Set(JSON.parse(raw) as string[]),
|
|
39
|
+
* serialize: (set) => JSON.stringify([...set]),
|
|
40
|
+
* });
|
|
25
41
|
* ```
|
|
26
42
|
*/
|
|
27
|
-
export function usePersistedState(key, defaultValue) {
|
|
43
|
+
export function usePersistedState(key, defaultValue, options = {}) {
|
|
28
44
|
const [value, setValue] = useState(() => hydratedCache.has(key) ? hydratedCache.get(key) : defaultValue);
|
|
29
45
|
const [hydrated, setHydrated] = useState(() => hydratedCache.has(key));
|
|
30
46
|
const keyRef = useRef(key);
|
|
31
47
|
keyRef.current = key;
|
|
48
|
+
const optionsRef = useRef(options);
|
|
49
|
+
optionsRef.current = options;
|
|
32
50
|
useEffect(() => {
|
|
33
51
|
if (hydratedCache.has(key)) {
|
|
34
52
|
setValue(hydratedCache.get(key));
|
|
@@ -36,17 +54,22 @@ export function usePersistedState(key, defaultValue) {
|
|
|
36
54
|
return;
|
|
37
55
|
}
|
|
38
56
|
let cancelled = false;
|
|
39
|
-
|
|
57
|
+
const storage = optionsRef.current.storage ?? persistentStorage;
|
|
58
|
+
const parse = optionsRef.current.parse ?? defaultParse;
|
|
59
|
+
storage.getItem(key).then(raw => {
|
|
40
60
|
if (cancelled) return;
|
|
41
61
|
if (raw != null) {
|
|
62
|
+
let parsed;
|
|
42
63
|
try {
|
|
43
|
-
|
|
44
|
-
hydratedCache.set(key, parsed);
|
|
45
|
-
setValue(parsed);
|
|
64
|
+
parsed = parse(raw);
|
|
46
65
|
} catch {
|
|
47
66
|
// Corrupt payload — fall back to the default and let the next
|
|
48
67
|
// write repair it.
|
|
49
68
|
}
|
|
69
|
+
if (parsed !== undefined) {
|
|
70
|
+
hydratedCache.set(key, parsed);
|
|
71
|
+
setValue(parsed);
|
|
72
|
+
}
|
|
50
73
|
}
|
|
51
74
|
setHydrated(true);
|
|
52
75
|
}).catch(() => {
|
|
@@ -60,9 +83,20 @@ export function usePersistedState(key, defaultValue) {
|
|
|
60
83
|
setValue(prev => {
|
|
61
84
|
const resolved = typeof next === "function" ? next(prev) : next;
|
|
62
85
|
hydratedCache.set(keyRef.current, resolved);
|
|
63
|
-
|
|
86
|
+
const storage = optionsRef.current.storage ?? persistentStorage;
|
|
87
|
+
const serialize = optionsRef.current.serialize ?? JSON.stringify;
|
|
88
|
+
try {
|
|
89
|
+
storage.setItem(keyRef.current, serialize(resolved)).catch(() => {});
|
|
90
|
+
} catch {
|
|
91
|
+
// Unserializable value — keep it in memory, skip the write.
|
|
92
|
+
}
|
|
64
93
|
return resolved;
|
|
65
94
|
});
|
|
66
95
|
}, []);
|
|
67
96
|
return [value, set, hydrated];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Test seam: forget every hydrated value. */
|
|
100
|
+
export function resetPersistedStateCache() {
|
|
101
|
+
hydratedCache.clear();
|
|
68
102
|
}
|
|
@@ -28,8 +28,33 @@ export { WifiCircuitIcon } from "./WifiCircuitIcon.js";
|
|
|
28
28
|
export { RouteMapIcon, RouteIcon, NavigationIcon } from "./RouteMapIcon.js";
|
|
29
29
|
export { StackPulseIcon, RenderPulseIcon, HighlightUpdatesIcon } from "./StackPulseIcon.js";
|
|
30
30
|
export { RenderCountIcon } from "./RenderCountIcon.js";
|
|
31
|
-
|
|
31
|
+
// The hand-drawn stopwatch is legacy; `BenchmarkIcon` is the BIF artwork (same on every port).
|
|
32
|
+
export { BenchmarkIcon as BenchmarkLegacyIcon } from "./BenchmarkIcon.js";
|
|
32
33
|
export { IconBackground } from "./IconBackground.js";
|
|
33
34
|
|
|
34
35
|
// Export lucide icons
|
|
35
|
-
export * from "./lucide-icons.js";
|
|
36
|
+
export * from "./lucide-icons.js";
|
|
37
|
+
|
|
38
|
+
// The lucide glyph tier, drawn from shared/icons/glyphs/*.json — the SAME data
|
|
39
|
+
// the Flutter and Swift renderers read. React Native used to carry a second,
|
|
40
|
+
// hand-drawn copy of these icons (`./lucide-icons`), so `Globe` was one drawing
|
|
41
|
+
// on RN and another on every port; the cross-framework parity sheet measured
|
|
42
|
+
// `icons/globe-24` 10.8 % apart on both. These explicit exports shadow the
|
|
43
|
+
// `export * from "./lucide-icons"` above (the same trick `WifiBifIcon` uses),
|
|
44
|
+
// so one edit to a JSON now moves all three frameworks. The hand-drawn
|
|
45
|
+
// originals stay reachable as `<Name>Icon` from `./lucide-icons`.
|
|
46
|
+
//
|
|
47
|
+
// `Pin` is deliberately NOT here: RN's pin carries an extra `active` prop that
|
|
48
|
+
// stands it upright, which the glyph data has no way to express (the ports draw
|
|
49
|
+
// the resting pose only). `WifiIcon` stays lucide for the same kind of reason —
|
|
50
|
+
// see the `WifiBifIcon` note below.
|
|
51
|
+
export { ActivityGlyph as Activity, AlertCircleGlyph as AlertCircle, AlertTriangleGlyph as AlertTriangle, BookmarkGlyph as Bookmark, BoxGlyph as Box, BugGlyph as Bug, CheckCircleGlyph as CheckCircle, CheckGlyph as Check, ChevronDownGlyph as ChevronDown, ChevronLeftGlyph as ChevronLeft, ChevronRightGlyph as ChevronRight, ChevronUpGlyph as ChevronUp, ClockGlyph as Clock, CopyGlyph as Copy, DatabaseGlyph as Database, DockBottomGlyph as DockBottom, DownloadGlyph as Download, Edit3Glyph as Edit3, EyeOffGlyph as EyeOff, EyeGlyph as Eye, FileJsonGlyph as FileJson, FileTextGlyph as FileText, FilmGlyph as Film, FilterGlyph as Filter, FlaskConicalGlyph as FlaskConical, FloatWindowGlyph as FloatWindow, GitBranchGlyph as GitBranch, GlobeGlyph as Globe, HashGlyph as Hash, HomeGlyph as Home, ImageGlyph as Image, InfoGlyph as Info, KeyGlyph as Key, LayersGlyph as Layers, LinkGlyph as Link, LockGlyph as Lock, MinusGlyph as Minus, MusicGlyph as Music, NavigationGlyph as Navigation, PaletteGlyph as Palette, PauseGlyph as Pause, PlayGlyph as Play, PlusGlyph as Plus, PowerGlyph as Power, RefreshCwGlyph as RefreshCw, SearchGlyph as Search, ServerGlyph as Server, SettingsGlyph as Settings, ShieldGlyph as Shield, Trash2Glyph as Trash2,
|
|
52
|
+
// RN aliases `Trash` onto `Trash2Icon`; the glyph has to shadow both.
|
|
53
|
+
Trash2Glyph as Trash, UnlockGlyph as Unlock, UploadGlyph as Upload, UserGlyph as User, WifiGlyph as Wifi, XCircleGlyph as XCircle, XGlyph as X, ZapGlyph as Zap } from "@buoy-gg/floating-tools-core";
|
|
54
|
+
|
|
55
|
+
// Every BIF brand icon the dial can show, re-exported so the parity sheet (and tools) render
|
|
56
|
+
// the same artwork by name — see shared/parity/specimens.json `icons/bif-*`.
|
|
57
|
+
export { SentryIcon, EventsIcon, RoutesIcon, RoutePinIcon, RoutePathIcon, RouteDotIcon, RouteTwoPinsIcon, CameraIcon, HighlightIcon, ReduxIcon, StorageIcon, AskBuoyIcon, HighlighterIcon, QueryIcon, ScenariosIcon } from "@buoy-gg/floating-tools-core";
|
|
58
|
+
// `WifiIcon` here stays the lucide glyph (react-query's online toggle); the BIF wifi ships as
|
|
59
|
+
// `WifiBifIcon`. `BenchmarkIcon` IS the BIF stopwatch since 2026-09-04 (perf-monitor's dial icon).
|
|
60
|
+
export { WifiIcon as WifiBifIcon, BenchmarkIcon, BENCHMARK_ICON_COLOR } from "@buoy-gg/floating-tools-core";
|
package/lib/module/index.js
CHANGED
|
@@ -6,6 +6,10 @@ export * from "./ui/index.js";
|
|
|
6
6
|
// Store base classes
|
|
7
7
|
export * from "./stores/index.js";
|
|
8
8
|
export * from "./sync/wireBudget.js";
|
|
9
|
+
export * from "./sync/wireForm.js";
|
|
10
|
+
export * from "./sync/toolSyncAdapter.js";
|
|
11
|
+
// Typed tool presets + derived createXTool factories (structurally InstalledApp)
|
|
12
|
+
export * from "./tools/defineTool.js";
|
|
9
13
|
export * from "./sync/toolActionRegistry.js";
|
|
10
14
|
export * from "./sync/toolUiBridge.js";
|
|
11
15
|
|
|
@@ -44,6 +48,12 @@ Subscribable,
|
|
|
44
48
|
subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange,
|
|
45
49
|
// Safe expo-router wrappers (falls back to no-ops on RN CLI)
|
|
46
50
|
useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, getSafeCurrentPathname, getSafeCurrentRoute, isExpoRouterAvailable } from "./utils/index.js";
|
|
51
|
+
// Time Machine snapshot-provider kit (restore scope, verdict ladder, result shapes)
|
|
52
|
+
export { PREVIEW_ITEM_RENDER_BYTE_LIMIT, createRestoreScope, emptyRestoreResult, failedRestore, skippedRestore, classifyPreviewItem, wontApply, unionKeys } from "./utils/snapshotProviderKit.js";
|
|
53
|
+
|
|
54
|
+
// State-tool helpers (entity colors, value previews, shallow diff summaries)
|
|
55
|
+
export { entityColor, formatValuePreview, shallowDiffSummary } from "./utils/stateTools.js";
|
|
56
|
+
|
|
47
57
|
// Also export formatting utils
|
|
48
58
|
export * from "./utils/formatting/index.js";
|
|
49
59
|
export * from "./utils/time/index.js";
|
|
@@ -59,7 +69,7 @@ export * from "./clipboard/index.js";
|
|
|
59
69
|
export * from "./logger/index.js";
|
|
60
70
|
export * from "./settings/index.js";
|
|
61
71
|
export * from "./storage/index.js";
|
|
62
|
-
export { useSafeAreaInsets, useFilterManager, usePersistedState, useDeviceInfo, getDeviceInfo, logDeviceInfo } from "./hooks/index.js";
|
|
72
|
+
export { useSafeAreaInsets, useFilterManager, usePersistedState, resetPersistedStateCache, useChangeLog, useSubscribedValue, useEventStoreEvents, useDeviceInfo, getDeviceInfo, logDeviceInfo } from "./hooks/index.js";
|
|
63
73
|
|
|
64
74
|
// JsModal
|
|
65
75
|
export { JsModal } from "./JsModal";
|
|
@@ -19,7 +19,7 @@ import { buoyColors } from "../ui/gameUI/constants/gameUIColors.js";
|
|
|
19
19
|
import { Check, Copy, X } from "../icons/lucide-icons.js";
|
|
20
20
|
import { copyToClipboard } from "../clipboard/index.js";
|
|
21
21
|
import { openPricing } from "./openPricing.js";
|
|
22
|
-
|
|
22
|
+
import { monoFont } from "../ui/fonts.js";
|
|
23
23
|
/** The one thing a reader has to be able to act on. */
|
|
24
24
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
25
25
|
export const LOGIN_COMMAND = "npx buoy login";
|
|
@@ -155,7 +155,7 @@ const styles = StyleSheet.create({
|
|
|
155
155
|
fontSize: 14,
|
|
156
156
|
fontWeight: "600",
|
|
157
157
|
color: buoyColors.text,
|
|
158
|
-
fontFamily:
|
|
158
|
+
fontFamily: monoFont
|
|
159
159
|
},
|
|
160
160
|
reassure: {
|
|
161
161
|
fontSize: 12,
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import React, { useCallback } from "react";
|
|
12
|
-
import { View, Text, TouchableOpacity, StyleSheet, Modal
|
|
12
|
+
import { View, Text, TouchableOpacity, StyleSheet, Modal } from "react-native";
|
|
13
13
|
import { absoluteFill } from "../utils/absoluteFill.js";
|
|
14
14
|
import { macOSColors } from "../ui/gameUI/constants/macOSDesignSystemColors.js";
|
|
15
15
|
import { openPricing, isWeb } from "./openPricing.js";
|
|
16
16
|
import { X, Key, Link, FileCode, Copy } from "../icons/lucide-icons.js";
|
|
17
|
-
|
|
17
|
+
import { monoFont } from "../ui/fonts.js";
|
|
18
18
|
// For clipboard functionality
|
|
19
19
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
20
20
|
let Clipboard = null;
|
|
@@ -339,7 +339,7 @@ const styles = StyleSheet.create({
|
|
|
339
339
|
},
|
|
340
340
|
codeText: {
|
|
341
341
|
fontSize: 11,
|
|
342
|
-
fontFamily:
|
|
342
|
+
fontFamily: monoFont,
|
|
343
343
|
lineHeight: 18,
|
|
344
344
|
color: macOSColors.text.primary
|
|
345
345
|
},
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* definePersistedSetting — the `load / save / clear` triple every tool wrote
|
|
5
|
+
* for its module-level settings (copy settings, HUD prefs, JS TOP prefs, …).
|
|
6
|
+
*
|
|
7
|
+
* Contract, the same one all of them followed:
|
|
8
|
+
* - `load()` never throws and never returns a partial object: the stored
|
|
9
|
+
* value is merged OVER the defaults so fields added in a later release
|
|
10
|
+
* get their default instead of `undefined`, then `sanitize` gets the last
|
|
11
|
+
* word (drop values the UI no longer offers, coerce types).
|
|
12
|
+
* - `save()` and `clear()` are best-effort; persistence is optional.
|
|
13
|
+
* - `loadOrNull()` distinguishes "nothing saved yet" from the defaults, for
|
|
14
|
+
* callers that treat first launch differently.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { persistentStorage } from "../utils/persistentStorage.js";
|
|
18
|
+
function isPlainObject(value) {
|
|
19
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
export function definePersistedSetting(key, defaults, options = {}) {
|
|
22
|
+
const storage = options.storage ?? persistentStorage;
|
|
23
|
+
const parse = options.parse ?? (raw => JSON.parse(raw));
|
|
24
|
+
const serialize = options.serialize ?? (value => JSON.stringify(value));
|
|
25
|
+
function resolve(stored) {
|
|
26
|
+
const merged = isPlainObject(defaults) && isPlainObject(stored) ? {
|
|
27
|
+
...defaults,
|
|
28
|
+
...stored
|
|
29
|
+
} : stored;
|
|
30
|
+
return options.sanitize ? options.sanitize(merged, stored) : merged;
|
|
31
|
+
}
|
|
32
|
+
async function loadOrNull() {
|
|
33
|
+
try {
|
|
34
|
+
const raw = await storage.getItem(key);
|
|
35
|
+
if (raw == null || raw === "") return null;
|
|
36
|
+
return resolve(parse(raw));
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
key,
|
|
43
|
+
defaults,
|
|
44
|
+
loadOrNull,
|
|
45
|
+
async load() {
|
|
46
|
+
return (await loadOrNull()) ?? defaults;
|
|
47
|
+
},
|
|
48
|
+
async save(value) {
|
|
49
|
+
try {
|
|
50
|
+
await storage.setItem(key, serialize(value));
|
|
51
|
+
} catch {
|
|
52
|
+
// Persistence is best-effort.
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
async clear() {
|
|
56
|
+
try {
|
|
57
|
+
await storage.removeItem(key);
|
|
58
|
+
} catch {
|
|
59
|
+
// Persistence is best-effort.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ChangeLog — the class-shaped event log the state tools share.
|
|
5
|
+
*
|
|
6
|
+
* redux (`ReduxActionStore`), zustand (`ZustandStateStore`), jotai
|
|
7
|
+
* (`JotaiStateStore`) and react-query (`ReactQueryEventStore`) each carried
|
|
8
|
+
* the same ~120 lines: a newest-first ring buffer, a `Set` of array listeners
|
|
9
|
+
* (`(items) => void`), a `Set` of clear listeners for the desktop's mirror
|
|
10
|
+
* mode, an `enabled` flag (the UI's pause button), a `captureSuppressed` flag
|
|
11
|
+
* (the dashboard must never record its own traffic), a monotonic id counter,
|
|
12
|
+
* `getById`, and hydrate-by-id for lazily fetched detail payloads.
|
|
13
|
+
*
|
|
14
|
+
* This is that core. Tool stores `extend` it and keep their public method
|
|
15
|
+
* names (`addStateChange`, `getActions`, `clearAtomChanges`, …) as thin
|
|
16
|
+
* wrappers, so no call site — including Buoy Desktop — has to change.
|
|
17
|
+
*
|
|
18
|
+
* Semantics preserved from the originals, deliberately:
|
|
19
|
+
* - `getAll()` returns a COPY (`[...items]`) — consumers seed React state
|
|
20
|
+
* from it and rely on a fresh identity per notification.
|
|
21
|
+
* - `clear()` always notifies, even when already empty, then fires the clear
|
|
22
|
+
* listeners (the dashboard forwards the clear to the device either way).
|
|
23
|
+
* - `replaceAll()` respects `enabled`: the pause button freezes a mirror.
|
|
24
|
+
* - `disableCapture()` is permanent for the store's lifetime.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export class ChangeLog {
|
|
28
|
+
/** Newest first. Subclasses may read; mutate only through the helpers. */
|
|
29
|
+
items = [];
|
|
30
|
+
itemListeners = new Set();
|
|
31
|
+
clearListeners = new Set();
|
|
32
|
+
idCounter = 0;
|
|
33
|
+
enabled = true;
|
|
34
|
+
captureSuppressed = false;
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
this.max = options.max ?? 200;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---- Recording ----
|
|
40
|
+
|
|
41
|
+
/** True when a new item should be recorded (not paused, not a mirror). */
|
|
42
|
+
canRecord() {
|
|
43
|
+
return this.enabled && !this.captureSuppressed;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** `${Date.now()}-${n}` — unique per store instance, sorts by time. */
|
|
47
|
+
nextId() {
|
|
48
|
+
return `${Date.now()}-${++this.idCounter}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Prepend one item and trim to `max`. Does NOT notify — subclasses often
|
|
53
|
+
* touch companion state (per-entity counters, raw-state eviction) before
|
|
54
|
+
* they notify. Call `notifyListeners()` when done, or use `record()`.
|
|
55
|
+
*/
|
|
56
|
+
push(item) {
|
|
57
|
+
this.items = [item, ...this.items].slice(0, this.max);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** `push()` + notify. The common case. */
|
|
61
|
+
record(item) {
|
|
62
|
+
this.push(item);
|
|
63
|
+
this.notifyListeners();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Replace the buffer wholesale (already merged/hydrated by the caller) and notify. */
|
|
67
|
+
setItems(next) {
|
|
68
|
+
this.items = next.slice(0, this.max);
|
|
69
|
+
this.notifyListeners();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---- Reading ----
|
|
73
|
+
|
|
74
|
+
/** All items, newest first. Fresh array each call. */
|
|
75
|
+
getAll() {
|
|
76
|
+
return [...this.items];
|
|
77
|
+
}
|
|
78
|
+
getById(id) {
|
|
79
|
+
return this.items.find(item => item.id === id);
|
|
80
|
+
}
|
|
81
|
+
get size() {
|
|
82
|
+
return this.items.length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ---- Clearing ----
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Empty the buffer, notify, then fire clear listeners. Always notifies —
|
|
89
|
+
* a clear is a user action and the list must repaint even if nothing was
|
|
90
|
+
* in it. Subclasses that keep companion counters reset them first.
|
|
91
|
+
*/
|
|
92
|
+
clear() {
|
|
93
|
+
this.items = [];
|
|
94
|
+
this.notifyListeners();
|
|
95
|
+
this.clearListeners.forEach(listener => {
|
|
96
|
+
try {
|
|
97
|
+
listener();
|
|
98
|
+
} catch {
|
|
99
|
+
// Ignore listener errors
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Listen for `clear()` calls. Used in remote mirror mode to forward a
|
|
106
|
+
* clear performed in the dashboard UI to the synced device.
|
|
107
|
+
*/
|
|
108
|
+
onClear(listener) {
|
|
109
|
+
this.clearListeners.add(listener);
|
|
110
|
+
return () => {
|
|
111
|
+
this.clearListeners.delete(listener);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ---- Remote mirror mode ----
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Permanently suppress local capture. Use when this store acts as a mirror
|
|
119
|
+
* of a remote device (the desktop dashboard): data arrives via
|
|
120
|
+
* `replaceAll()` / a subclass snapshot method and local instrumentation
|
|
121
|
+
* must never record.
|
|
122
|
+
*/
|
|
123
|
+
disableCapture() {
|
|
124
|
+
this.captureSuppressed = true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Whether the store is in remote mirror mode (capture suppressed). */
|
|
128
|
+
isCaptureSuppressed() {
|
|
129
|
+
return this.captureSuppressed;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Replace the whole list from a remote snapshot and notify. Respects the
|
|
134
|
+
* enabled flag so the UI's pause button freezes the mirror. Returns false
|
|
135
|
+
* when skipped. Subclasses with hydration-preserving merges compute the
|
|
136
|
+
* merged list themselves and call `setItems()`.
|
|
137
|
+
*/
|
|
138
|
+
replaceAll(next) {
|
|
139
|
+
if (!this.enabled) return false;
|
|
140
|
+
this.setItems(next);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Patch one item in place (by id) and notify. Used to hydrate a mirrored
|
|
146
|
+
* item with detail payloads fetched on demand from the device.
|
|
147
|
+
*/
|
|
148
|
+
hydrateById(id, patch) {
|
|
149
|
+
const index = this.items.findIndex(item => item.id === id);
|
|
150
|
+
if (index === -1) return;
|
|
151
|
+
this.items = [...this.items.slice(0, index), {
|
|
152
|
+
...this.items[index],
|
|
153
|
+
...patch
|
|
154
|
+
}, ...this.items.slice(index + 1)];
|
|
155
|
+
this.notifyListeners();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---- Enable / disable ----
|
|
159
|
+
|
|
160
|
+
setEnabled(enabled) {
|
|
161
|
+
this.enabled = enabled;
|
|
162
|
+
}
|
|
163
|
+
getEnabled() {
|
|
164
|
+
return this.enabled;
|
|
165
|
+
}
|
|
166
|
+
setMax(max) {
|
|
167
|
+
this.max = max;
|
|
168
|
+
if (this.items.length > max) {
|
|
169
|
+
this.items = this.items.slice(0, max);
|
|
170
|
+
this.notifyListeners();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
getMax() {
|
|
174
|
+
return this.max;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ---- Subscriptions ----
|
|
178
|
+
|
|
179
|
+
subscribe(listener) {
|
|
180
|
+
this.itemListeners.add(listener);
|
|
181
|
+
return () => {
|
|
182
|
+
this.itemListeners.delete(listener);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
notifyListeners() {
|
|
186
|
+
const items = this.getAll();
|
|
187
|
+
this.itemListeners.forEach(listener => listener(items));
|
|
188
|
+
}
|
|
189
|
+
get listenerCount() {
|
|
190
|
+
return this.itemListeners.size;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* createToolStore — the one bounded, subscribable buffer every tool used to
|
|
5
|
+
* hand-roll.
|
|
6
|
+
*
|
|
7
|
+
* Before this existed, console, sentry, images, assets, focus-inspector,
|
|
8
|
+
* tv-remote, redux, zustand, jotai and react-query each carried their own copy
|
|
9
|
+
* of the same ~100 lines: a `Set` of listeners, a `Set` of clear listeners
|
|
10
|
+
* (so the desktop dashboard can forward a clear to the device in mirror
|
|
11
|
+
* mode), a ring buffer with a max, an optional frame-coalesced emit, and the
|
|
12
|
+
* `__buoyFlushToolSync` escape hatch that pushes a tool's snapshot to the
|
|
13
|
+
* dashboard NOW (a crash's last words must not wait on the sync throttle).
|
|
14
|
+
*
|
|
15
|
+
* This is a plain function, not a class, on purpose: every consumer exposes a
|
|
16
|
+
* module-level functional API (`subscribe`, `getSnapshot`, `clearX`) and
|
|
17
|
+
* feeds `useSyncExternalStore`, so the store is a value the module wraps
|
|
18
|
+
* rather than something it extends. `BaseEventStore` stays for the
|
|
19
|
+
* class-based, auto-start/stop capture stores (network, storage, routes).
|
|
20
|
+
*
|
|
21
|
+
* Contract:
|
|
22
|
+
* - `getSnapshot()` returns the SAME array reference until the next
|
|
23
|
+
* mutation, so `useSyncExternalStore` never re-renders for nothing.
|
|
24
|
+
* - `order: "append"` keeps the newest item LAST (console-style scrollback);
|
|
25
|
+
* `order: "prepend"` keeps it FIRST (event-log style). Trimming drops from
|
|
26
|
+
* the opposite end. Consumers never have to `.reverse()`.
|
|
27
|
+
* - `clear()` fires `onClear` listeners even when the buffer is already
|
|
28
|
+
* empty — the dashboard's forwarded clear must reach the device regardless.
|
|
29
|
+
* - `set()` (mirror mode) never fires clear listeners; it is a replacement.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** Listener signature: change-only, read the snapshot yourself. */
|
|
33
|
+
|
|
34
|
+
function scheduleFrame(cb) {
|
|
35
|
+
if (typeof requestAnimationFrame === "function") {
|
|
36
|
+
requestAnimationFrame(() => cb());
|
|
37
|
+
} else {
|
|
38
|
+
setTimeout(cb, 0);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function createToolStore(options) {
|
|
42
|
+
const id = options.id;
|
|
43
|
+
const order = options.order ?? "append";
|
|
44
|
+
const coalesce = options.coalesce ?? "sync";
|
|
45
|
+
const flushMinIntervalMs = options.flushMinIntervalMs ?? 150;
|
|
46
|
+
let max = options.max;
|
|
47
|
+
let items = [];
|
|
48
|
+
let paused = false;
|
|
49
|
+
let nextId = options.firstId ?? 1;
|
|
50
|
+
let lastFlushAt = 0;
|
|
51
|
+
let emitScheduled = false;
|
|
52
|
+
const listeners = new Set();
|
|
53
|
+
const clearListeners = new Set();
|
|
54
|
+
function fire() {
|
|
55
|
+
for (const listener of listeners) {
|
|
56
|
+
try {
|
|
57
|
+
listener();
|
|
58
|
+
} catch {
|
|
59
|
+
// A broken subscriber must not take the store (or a crash path) down.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function emit() {
|
|
64
|
+
if (coalesce === "sync") {
|
|
65
|
+
fire();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (emitScheduled) return;
|
|
69
|
+
emitScheduled = true;
|
|
70
|
+
scheduleFrame(() => {
|
|
71
|
+
emitScheduled = false;
|
|
72
|
+
fire();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function trim(list) {
|
|
76
|
+
if (list.length <= max) return list;
|
|
77
|
+
return order === "append" ? list.slice(list.length - max) : list.slice(0, max);
|
|
78
|
+
}
|
|
79
|
+
const store = {
|
|
80
|
+
id,
|
|
81
|
+
subscribe(listener) {
|
|
82
|
+
listeners.add(listener);
|
|
83
|
+
return () => {
|
|
84
|
+
listeners.delete(listener);
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
getSnapshot() {
|
|
88
|
+
return items;
|
|
89
|
+
},
|
|
90
|
+
size() {
|
|
91
|
+
return items.length;
|
|
92
|
+
},
|
|
93
|
+
add(item) {
|
|
94
|
+
if (paused) return;
|
|
95
|
+
if (order === "append") {
|
|
96
|
+
items = items.length >= max ? [...items.slice(items.length - max + 1), item] : [...items, item];
|
|
97
|
+
} else {
|
|
98
|
+
items = items.length >= max ? [item, ...items.slice(0, max - 1)] : [item, ...items];
|
|
99
|
+
}
|
|
100
|
+
emit();
|
|
101
|
+
},
|
|
102
|
+
set(next) {
|
|
103
|
+
items = trim(next);
|
|
104
|
+
emit();
|
|
105
|
+
},
|
|
106
|
+
update(fn) {
|
|
107
|
+
items = trim(fn(items));
|
|
108
|
+
emit();
|
|
109
|
+
},
|
|
110
|
+
clear() {
|
|
111
|
+
for (const listener of clearListeners) {
|
|
112
|
+
try {
|
|
113
|
+
listener();
|
|
114
|
+
} catch {
|
|
115
|
+
// ignore
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (items.length === 0) return;
|
|
119
|
+
items = [];
|
|
120
|
+
emit();
|
|
121
|
+
},
|
|
122
|
+
onClear(listener) {
|
|
123
|
+
clearListeners.add(listener);
|
|
124
|
+
return () => {
|
|
125
|
+
clearListeners.delete(listener);
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
notify() {
|
|
129
|
+
emit();
|
|
130
|
+
},
|
|
131
|
+
flushSync(force = false) {
|
|
132
|
+
const now = Date.now();
|
|
133
|
+
if (!force && now - lastFlushAt < flushMinIntervalMs) return;
|
|
134
|
+
lastFlushAt = now;
|
|
135
|
+
try {
|
|
136
|
+
const set = globalThis.__buoyFlushToolSync;
|
|
137
|
+
if (!set) return;
|
|
138
|
+
for (const flush of set) flush(id);
|
|
139
|
+
} catch {
|
|
140
|
+
// Best-effort: a crash path must never crash.
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
setPaused(next) {
|
|
144
|
+
paused = next;
|
|
145
|
+
},
|
|
146
|
+
isPaused() {
|
|
147
|
+
return paused;
|
|
148
|
+
},
|
|
149
|
+
setMax(next) {
|
|
150
|
+
max = next;
|
|
151
|
+
const trimmed = trim(items);
|
|
152
|
+
if (trimmed !== items) {
|
|
153
|
+
items = trimmed;
|
|
154
|
+
emit();
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
getMax() {
|
|
158
|
+
return max;
|
|
159
|
+
},
|
|
160
|
+
allocId() {
|
|
161
|
+
return nextId++;
|
|
162
|
+
},
|
|
163
|
+
bumpIdAbove(idFloor) {
|
|
164
|
+
if (idFloor + 1 > nextId) nextId = idFloor + 1;
|
|
165
|
+
},
|
|
166
|
+
listenerCount() {
|
|
167
|
+
return listeners.size;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
return store;
|
|
171
|
+
}
|
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export { BaseEventStore } from "./BaseEventStore.js";
|
|
8
|
-
export { ignoredPatternsStore, useIgnoredPatterns, urlMatchesIgnoredPattern, isUrlIgnored } from "./ignoredPatternsStore";
|
|
8
|
+
export { ignoredPatternsStore, useIgnoredPatterns, urlMatchesIgnoredPattern, isUrlIgnored } from "./ignoredPatternsStore";
|
|
9
|
+
export { createToolStore } from "./createToolStore.js";
|
|
10
|
+
export { ChangeLog } from "./ChangeLog.js";
|