import type { InstalledApp } from "./types";
/**
* Automatically discovers and loads dev tool presets from installed packages.
*
* This function attempts to import presets from known dev tool packages.
* If a package is installed, its preset will be automatically loaded.
* If a package is not installed, it will be silently skipped.
*
* This enables zero-config setup - just install the packages you want
* and they'll automatically appear in your dev tools!
*
* @returns Array of automatically discovered preset configurations
*
* @example
* ```tsx
* import { FloatingDevTools, autoDiscoverPresets } from '@react-buoy/core';
*
* // Automatically discover and load all installed dev tool presets
* const autoPresets = autoDiscoverPresets();
*
* function App() {
* return (
*
* );
* }
* ```
*
* @example
* ```tsx
* // Combine auto-discovery with custom tools
* const autoPresets = autoDiscoverPresets();
* const customTools = [
* {
* id: "my-custom-tool",
* name: "CUSTOM",
* // ... custom config
* },
* ];
*
* const allTools = [...autoPresets, ...customTools];
*
*
* ```
*/
export function autoDiscoverPresets(): InstalledApp[] {
const discoveredPresets: InstalledApp[] = [];
// Try to load each known preset
// These will only succeed if the package is actually installed
const presetLoaders = [
// ENV Tools
{
name: "@react-buoy/env",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const { envToolPreset } = require("@react-buoy/env");
return envToolPreset;
} catch {
return null;
}
},
},
// Network Tools
{
name: "@react-buoy/network",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const { networkToolPreset } = require("@react-buoy/network");
return networkToolPreset;
} catch {
return null;
}
},
},
// Storage Tools
{
name: "@react-buoy/storage",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const { storageToolPreset } = require("@react-buoy/storage");
return storageToolPreset;
} catch {
return null;
}
},
},
// React Query Tools
{
name: "@react-buoy/react-query",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const {
reactQueryToolPreset,
wifiTogglePreset,
} = require("@react-buoy/react-query");
return [reactQueryToolPreset, wifiTogglePreset];
} catch {
return null;
}
},
},
// Route Events
{
name: "@react-buoy/route-events",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const { routeEventsToolPreset } = require("@react-buoy/route-events");
return routeEventsToolPreset;
} catch {
return null;
}
},
},
// Debug Borders
{
name: "@react-buoy/debug-borders",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const {
debugBordersToolPreset,
} = require("@react-buoy/debug-borders");
return debugBordersToolPreset;
} catch {
return null;
}
},
},
// Highlight Updates (both toggle and modal presets)
{
name: "@react-buoy/highlight-updates",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const {
highlightUpdatesPreset,
highlightUpdatesModalPreset,
} = require("@react-buoy/highlight-updates");
return [highlightUpdatesModalPreset, highlightUpdatesPreset];
} catch {
return null;
}
},
},
// Benchmark Tools
{
name: "@react-buoy/benchmark",
loader: () => {
try {
// @ts-ignore - Dynamic import that may not exist
const { benchmarkPreset } = require("@react-buoy/benchmark");
return benchmarkPreset;
} catch {
return null;
}
},
},
];
// Attempt to load each preset
for (const { name, loader } of presetLoaders) {
try {
const preset = loader();
if (preset) {
if (Array.isArray(preset)) {
discoveredPresets.push(...preset);
} else {
discoveredPresets.push(preset);
}
}
} catch (error) {
// Silently skip packages that aren't installed
// This is expected behavior - not all packages will be installed
}
}
return discoveredPresets;
}
/**
* Merges auto-discovered presets with custom tools, ensuring no duplicates.
* Custom tools take precedence over auto-discovered ones with the same ID.
*
* @param customTools - Array of custom tool configurations
* @returns Combined array of tools with custom tools taking precedence
*
* @example
* ```tsx
* import { FloatingDevTools, autoDiscoverPresetsWithCustom } from '@react-buoy/core';
* import { createEnvTool } from '@react-buoy/env';
*
* const customTools = [
* // Override the env preset with custom config
* createEnvTool({
* requiredEnvVars: myRequiredVars,
* }),
* ];
*
* const allTools = autoDiscoverPresetsWithCustom(customTools);
*
*
* ```
*/
export function autoDiscoverPresetsWithCustom(
customTools: InstalledApp[]
): InstalledApp[] {
const autoPresets = autoDiscoverPresets();
// Create a map of custom tool IDs for quick lookup
const customToolIds = new Set(customTools.map((tool) => tool.id));
// Filter out auto-discovered presets that have custom overrides
const filteredAutoPresets = autoPresets.filter(
(preset) => !customToolIds.has(preset.id)
);
// Custom tools first (higher priority), then auto-discovered
return [...customTools, ...filteredAutoPresets];
}