
Research
Malicious npm Package Brand-Squats TanStack to Exfiltrate Environment Variables
A brand-squatted TanStack npm package used postinstall scripts to steal .env files and exfiltrate developer secrets to an attacker-controlled endpoint.
@daturon/mapboxgl-layer-manager
Advanced tools
The Layer Manager for Mapbox GL is a versatile and user-friendly tool designed to streamline the management of map layers within the Mapbox GL environment. This tool simplifies the process of modifying layer order and adjusting and fine-tuning each layer'
The Layer Manager for Mapbox GL is a powerful utility that simplifies the management of layers and sources in the Mapbox GL environment. This package allows easy layer reordering, visibility toggling, opacity adjustments, and other modifications, making it an essential tool for developers working with interactive maps.
It supports dynamic management of multiple sources and layers, allowing developers to dynamically change active sources, reorder layers efficiently, and automatically free unused resources to optimize performance.
New in v1.3: built-in Performance Analyzer that surfaces per-layer GPU timing, source load times, frame stats, and actionable optimization suggestions β and a first-class React hook (useLayerManager) for seamless SPA integration.
Live demo (GitHub Pages): Try the interactive demo β layer controls, filters, and the performance analyzer in the browser. Your Mapbox public token stays in sessionStorage and is not sent to this projectβs servers.
useLayerManager for clean lifecycle management with automatic destroy on unmount.npm install @daturon/mapboxgl-layer-manager
mapbox-gl (>=3.0.0) is a required peer dependency. React (>=16.8.0) is optional β only needed if you use the React hook.
mapboxgl-layer-manager/
βββ demo/ # Vite app published to GitHub Pages (`demo:dev`, `demo:build`)
βββ src/
β βββ index.ts # package entry
β βββ LayerManager.ts
β βββ LayerAnalyzer.ts
β βββ utils.ts
β βββ interfaces.ts
β βββ react.ts # `useLayerManager`; separate bundle (see tsup.config.ts)
β βββ __tests__/
β βββ *.test.ts
β βββ helpers/
β βββ mockMap.ts
βββ tsup.config.ts # `index` + `react` (ESM, CJS, declarations)
βββ vitest.config.ts
Gitignored build output: dist/ (npm package), demo-dist/ (static demo build), coverage/ (after coverage run).
import { LayerManager } from '@daturon/mapboxgl-layer-manager';
const map = new mapboxgl.Map({ /* ... */ });
const sources = [
{ id: 'my-source', source: { type: 'geojson', data: myGeoJSONData } },
];
const layers = [
{
id: 'my-layer',
type: 'circle',
source: 'my-source',
paint: { 'circle-radius': 5, 'circle-color': '#ff0000' },
},
];
const manager = new LayerManager(map, sources, layers);
// Adds sources, removes unused ones, and renders layers in the given order.
// Call again whenever the active layer set changes.
await manager.renderOrderedLayers(['my-layer'], {
'my-layer': {
filter: ['==', ['get', 'type'], 'park'],
paint: { 'circle-color': '#00ff00' },
},
});
manager.setLayerOpacity('my-layer', 0.5);
manager.toggleLayerVisibility('my-layer');
manager.updateLayerPaint('my-layer', 'circle-color', '#0000ff');
manager.updateLayerLayout('my-layer', 'visibility', 'none');
// Filters are named, so multiple independent filters compose automatically.
manager.updateLayerFilter('my-layer', ['==', ['get', 'category'], 'park'], 'category-filter');
manager.updateLayerFilter('my-layer', ['>', ['get', 'area'], 500], 'area-filter');
// Remove one filter without affecting the other.
manager.removeLayerFilter('my-layer', 'area-filter');
manager.addSources([{ id: 'new-source', source: { type: 'geojson', data: newData } }]);
manager.addLayers([{ id: 'new-layer', type: 'fill', source: 'new-source', paint: {} }]);
manager.removeLayers(['new-layer']);
manager.removeSources(['new-source']);
manager.updateFeatureState('my-source', featureId, { hover: true });
// Removes all managed layers and sources from the map.
manager.destroy();
Enable the built-in analyzer to collect GPU timing, frame stats, and source load durations, then call getReport() or getSuggestions() for actionable insights.
import { LayerManager, LayerAnalyzer } from '@daturon/mapboxgl-layer-manager';
// Option A β enable via LayerManager option:
const manager = new LayerManager(map, sources, layers, { analyzer: true });
const report = manager.analyzer!.getReport();
// Option B β standalone (works without LayerManager):
const analyzer = new LayerAnalyzer(map);
analyzer.start();
// ... after some map interaction ...
const report = analyzer.getReport();
console.log(report.timeToIdleMs); // ms from load β first idle
console.log(report.frameStats); // { avg, p95, max, sampleCount }
console.log(report.layerTimes); // per-layer GPU time + share
console.log(report.sourceLoadTimes); // per-source load duration
console.log(report.unusedLayerIds); // layers with no GPU activity
console.log(report.suggestions); // ["Layer X uses 45% of GPU time..."]
analyzer.getSlowestLayers(3); // top 3 layers by GPU time
analyzer.getUnusedLayers(); // layers never rendered
analyzer.stop();
Import from the /react sub-path. The manager is created when map becomes non-null and destroyed automatically on unmount.
import { useLayerManager } from '@daturon/mapboxgl-layer-manager/react';
function MapLayers({ map }: { map: mapboxgl.Map | null }) {
const manager = useLayerManager(map, sources, layers, { analyzer: true });
useEffect(() => {
if (!manager) return;
manager.renderOrderedLayers(['my-layer']);
}, [manager]);
return null;
}
LayerManager| Method | Description |
|---|---|
new LayerManager(map, sources?, layers?, options?) | Create a manager. sources and layers are initial registrations. Pass { analyzer: true } to enable the analyzer. |
renderOrderedLayers(ids, configs?, beforeId?) | Render the given layers in order, auto-adding/removing sources and layers as needed. Returns a Promise that resolves after the next render. |
addSources(sources) | Register and add sources to the map. |
removeSources(ids) | Remove sources from the map and internal registry. |
addLayers(layers, beforeId?) | Add layers to the map. |
removeLayers(ids) | Remove layers from the map. |
setLayerOpacity(id, opacity) | Set a layer's opacity (0β1). Auto-detects the correct paint property by layer type. |
toggleLayerVisibility(id) | Toggle a layer between 'visible' and 'none'. |
updateLayerFilter(id, filter, name?) | Set or update a named filter. Multiple named filters compose with 'all'. |
removeLayerFilter(id, name) | Remove a named filter. |
updateLayerPaint(id, name, value, options?) | Update a paint property. |
updateLayerLayout(id, name, value, options?) | Update a layout property. |
updateFeatureState(sourceId, featureId, state) | Set feature state for hover/selection effects. |
getActiveCustomLayerIds() | Returns IDs of all currently active managed layers. |
getActiveCustomSourceIds() | Returns IDs of all currently active managed sources. |
getLayersFilters() | Returns the full filter map. |
getMapInstance() | Returns the underlying mapboxgl.Map. |
analyzer | The LayerAnalyzer instance (if { analyzer: true } was passed). |
destroy() | Remove all managed layers/sources and stop the analyzer. |
LayerAnalyzer| Method | Description |
|---|---|
new LayerAnalyzer(map) | Create a standalone analyzer for a map instance. |
start() | Begin collecting performance data. |
stop() | Detach all event listeners. |
setManagedLayerIds(ids) | Register layer IDs to track for unused-layer detection. |
getReport() | Full snapshot: frame stats, layer times, source load times, suggestions. |
getFrameStats() | { avg, p95, max, sampleCount } GPU frame times. |
getSlowestLayers(n?) | Top N layers by average GPU render time. |
getUnusedLayers() | Managed layers with no GPU activity recorded. |
getSourceLoadTimes() | Per-source load durations from sourcedataloading β loaded. |
getSuggestions() | Array of human-readable optimization tips. |
Tests run with Vitest. npm test runs the suite once (same command as CI). Use npm run test:watch for a watch mode while you work.
Coverage: npm run test:coverage prints a V8 summary in the terminal and writes an HTML report to coverage/index.html (the coverage/ directory is gitignored). Coverage is collected for src/**/*.ts except src/__tests__/** and src/react.ts, so the React hook module is intentionally excluded from coverage reports.
npm installnpm run buildnpm run lintnpm testMIT β see LICENSE.
FAQs
The Layer Manager for Mapbox GL is a versatile and user-friendly tool designed to streamline the management of map layers within the Mapbox GL environment. This tool simplifies the process of modifying layer order and adjusting and fine-tuning each layer'
The npm package @daturon/mapboxgl-layer-manager receives a total of 75 weekly downloads. As such, @daturon/mapboxgl-layer-manager popularity was classified as not popular.
We found that @daturon/mapboxgl-layer-manager demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A brand-squatted TanStack npm package used postinstall scripts to steal .env files and exfiltrate developer secrets to an attacker-controlled endpoint.

Research
Compromised SAP CAP npm packages download and execute unverified binaries, creating urgent supply chain risk for affected developers and CI/CD environments.

Company News
Socket has acquired Secure Annex to expand extension security across browsers, IDEs, and AI tools.