@interzept/interzept-environment-selector
v1.1.0
Published
Multi-environment data source selector with feature flags and production safety
Maintainers
Readme
interzept-environment-selector
Multi-environment data source selector with feature flags and production safety. Perfect for testing and debugging across multiple environments simultaneously.
Environment Selector vs Data Source Selector
Environment Selector: Lets you choose which app environment to use (e.g., development, staging, production). Useful for testing how your app behaves in different deployment contexts.
Data Source Selector: Lets you choose where your app gets its data (e.g., mock data, local database, remote API). Useful for switching between test data and real data sources.
This package combines both!
- Select environments (dev, UAT, prod) and data sources (mock, local, API) in one UI.
- Multi-select and merge data from several sources/environments for advanced testing and debugging.
This flexibility makes it a powerful tool for development, QA, and debugging.
Features
✨ Multi-Select - Select and merge data from multiple environments simultaneously
🔒 Production Safe - Automatically hidden in production deployments
🎯 Feature Flag - Company-only internal tool with "Internal" badge
💾 Persistent - Selection saved to localStorage
🚀 Zero Config - Works out of the box in development
⚡ Parallel Fetching - Fetch from multiple sources in parallel
Installation
npm install @interzept/interzept-environment-selector
# or
pnpm add @interzept/interzept-environment-selector
# or
yarn add @interzept/interzept-environment-selectorQuick Start
1. Wrap your app with the provider
// app/layout.tsx
import { DataSourceProvider } from '@interzept/interzept-environment-selector'
export default function RootLayout({ children }) {
return (
<html>
<body>
<DataSourceProvider>
{children}
</DataSourceProvider>
</body>
</html>
)
}Using Wrappers for Customization
You can create thin wrapper files in your app or in this package to customize, feature-flag, or style the exports from @interzept/interzept-environment-selector. Wrappers help keep your import paths stable and allow you to add app-specific logic.
Example: Custom Wrapper for DataSourceToggle
// src/data-source-toggle-wrapper.tsx
// Add feature flags, custom props, or styling here if needed
export { DataSourceToggle } from '@interzept/interzept-environment-selector'Why use wrappers?
- Add feature flags or environment checks
- Apply custom styling or theming
- Set default props or behaviors
- Add logging, analytics, or permission checks
- Keep your app's import paths stable
Other developers can import from your wrapper instead of the package directly if they need custom logic. For most use cases, importing directly from the package is fine.
2. Add the toggle to your sidebar
Choose the version that fits your project:
Option A: With Tailwind CSS
// components/sidebar.tsx
import { DataSourceToggle } from '@interzept/interzept-environment-selector'
export function Sidebar() {
return (
<nav>
<DataSourceToggle />
</nav>
)
}Then configure Tailwind to scan the package:
// tailwind.config.js
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./node_modules/@interzept/interzept-environment-selector/dist/**/*.{js,mjs}'
],
}Option B: Without Tailwind (Plain CSS)
// components/sidebar.tsx
import { DataSourceToggleUnstyled } from '@interzept/interzept-environment-selector/unstyled'
import '@interzept/interzept-environment-selector/styles.css'
export function Sidebar() {
return (
<nav>
<DataSourceToggleUnstyled />
</nav>
)
}No configuration needed! Works in any React project.
3. Use in your components
// components/my-component.tsx
import { useDataSource, useMockData } from '@interzept/interzept-environment-selector'
export function MyComponent() {
const isMockMode = useMockData()
const { getApiBaseUrls } = useDataSource()
useEffect(() => {
if (isMockMode) {
setData(MOCK_DATA)
return
}
// Fetch from all selected sources in parallel
const urls = getApiBaseUrls()
const results = await Promise.allSettled(
urls.map(url => fetch(`${url}/api/endpoint?tenantId=${tenantId}`))
)
// Merge all successful results
const allData = []
results.forEach((result) => {
if (result.status === 'fulfilled') {
allData.push(...result.value.data)
}
})
setData(allData)
}, [isMockMode, getApiBaseUrls])
return <div>{/* Your UI */}</div>
}Environment Configuration
Create a .env.local file:
# Data source configuration
NEXT_PUBLIC_DATA_SOURCE=local
# Feature flag (optional - enabled by default in dev)
# NEXT_PUBLIC_ENABLE_DATA_SOURCE_TOGGLE=false
# Production safety (optional - recommended)
NEXT_PUBLIC_PRODUCTION_READ_ONLY=true
# Environment-specific API URLs
NEXT_PUBLIC_DEV_API_URL=https://dev-api.yourapp.com
NEXT_PUBLIC_UAT_API_URL=https://uat-api.yourapp.com
NEXT_PUBLIC_PROD_API_URL=https://api.yourapp.comData Sources
| Source | Description | Icon | Use Case | |--------|-------------|------|----------| | Mock | Static test data | 🧪 | UI development without backend | | Local | Local Supabase/DB | 💾 | Feature development | | Dev | Preview environment | 🖥️ | Testing commits/PRs | | UAT | Main branch | 🏢 | Pre-production testing | | Production | Release branch | 🌐 | Live data (read-only by default) |
API Reference
DataSourceProvider
Wraps your app to provide data source context.
<DataSourceProvider>
{children}
</DataSourceProvider>useDataSource()
Access data source state and methods.
const {
selectedSources, // DataSourceMode[] - Currently selected sources
toggleSource, // (mode: DataSourceMode) => void - Toggle a source
setSelectedSources, // (modes: DataSourceMode[]) => void - Set sources
useMockData, // () => boolean - Is mock mode active?
getApiBaseUrls, // () => string[] - Get all selected API URLs
primarySource, // DataSourceMode - First selected source
isProductionReadOnly, // boolean - Is production read-only?
canShowToggle, // boolean - Should toggle be visible?
} = useDataSource()useMockData()
Shorthand to check if mock mode is active.
const isMockMode = useMockData()useApiData()
Check if any real API source is selected.
const hasApiData = useApiData()DataSourceToggle / DataSourceToggleUnstyled
UI component for source selection. Choose based on your styling preference:
// Tailwind version (requires Tailwind CSS setup)
import { DataSourceToggle } from '@interzept/interzept-environment-selector'
<DataSourceToggle />
// Plain CSS version (works everywhere)
import { DataSourceToggleUnstyled } from '@interzept/interzept-environment-selector/unstyled'
import '@interzept/interzept-environment-selector/styles.css'
<DataSourceToggleUnstyled />Styling & Customization
Tailwind Version
Uses Tailwind utility classes. Requires:
- Tailwind CSS configured in your project
- Package path added to Tailwind content config
lucide-reactinstalled
Plain CSS Version
Uses standalone CSS with class prefix dst-*. To customize:
/* Override in your own CSS file */
.dst-container {
margin-bottom: 2rem !important;
}
.dst-header {
color: #your-color !important;
}
.dst-item-button:hover {
background-color: #your-hover-color !important;
}Available CSS Classes:
.dst-container- Main wrapper.dst-header- Collapsible header button.dst-badge- "Internal" badge.dst-item-button- Each data source button.dst-icon-purple,.dst-icon-blue,.dst-icon-green,.dst-icon-amber,.dst-icon-red- Icon colors.dst-footer- Footer with selection count
Comparison
| Feature | Tailwind (DataSourceToggle) | Plain CSS (DataSourceToggleUnstyled) |
|---------|-------------------------------|----------------------------------------|
| Setup | Requires Tailwind config | Import CSS once |
| Customization | Tailwind classes or wrapper | CSS overrides with !important |
| Bundle Size | Smaller (utility classes) | Includes compiled CSS (~3KB) |
| Best For | Tailwind projects | Any React project |
Production Deployment
The toggle automatically hides in production when:
NODE_ENV === 'production'ANDNEXT_PUBLIC_VERCEL_ENV === 'production'
Deployment Visibility Matrix
| Environment | Toggle Visible? | Production Selectable? | |-------------|-----------------|------------------------| | Local dev | ✅ Always | 🔒 No (if read-only enabled) | | Vercel Preview | ✅ Always | 🔒 No (if read-only enabled) | | Vercel Production | ❌ Never | ❌ Never |
Advanced Usage
Custom Environment URLs
const API_URLS = {
local: process.env.NEXT_PUBLIC_LOCAL_URL || 'http://localhost:55321',
dev: process.env.NEXT_PUBLIC_DEV_API_URL || 'https://dev.api.com',
// ...
}Fetching from Multiple Sources
async function fetchMultiSource(endpoint: string) {
const { getApiBaseUrls } = useDataSource()
const urls = getApiBaseUrls()
const results = await Promise.allSettled(
urls.map(baseUrl =>
fetch(`${baseUrl}${endpoint}`)
.then(res => res.json())
)
)
// Handle results
const allData = results
.filter(r => r.status === 'fulfilled')
.flatMap(r => r.value.data)
return allData
}Conditional Rendering
const { canShowToggle } = useDataSource()
return (
<nav>
{canShowToggle && <DataSourceToggle />}
</nav>
)TypeScript
Full TypeScript support included:
import type { DataSourceMode } from '@interzept/interzept-environment-selector'
type DataSourceMode = 'mock' | 'local' | 'dev' | 'uat' | 'production'Contributing
Contributions welcome!
License
MIT
Credits
Built with ❤️ for developers who need to test across multiple environments simultaneously.
Check out other Interzept projects:
- Interzept Browser Extension - Browser extension for enhanced development workflows
Need help? Open an issue on GitHub
