
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@context-action/core
Advanced tools
Type-safe action pipeline management library for JavaScript/TypeScript
Type-safe action pipeline management library for vanilla JavaScript/TypeScript applications with advanced filtering, performance optimizations, and optional React integration support.
✨ Framework-Agnostic: Works with vanilla JavaScript, React, Vue, Svelte, or any JavaScript environment. No framework dependencies required!
npm install @context-action/core
# or
pnpm install @context-action/core
<script type="module">
import { ActionRegister } from 'https://esm.sh/@context-action/core@latest';
// Your code here
</script>
import { ActionRegister } from '@context-action/core';
// Define your action types
interface MyActions {
increment: void;
setCount: number;
updateUser: { id: string; name: string };
}
// Create action register
const actions = new ActionRegister<MyActions>({
name: 'MyApp',
registry: { debug: true }
});
// Register handlers with priorities
actions.register('increment', () => {
console.log('Increment called');
}, { priority: 10 });
actions.register('setCount', (count) => {
console.log(`Setting count to: ${count}`);
}, { priority: 5 });
// Dispatch actions
await actions.dispatch('increment');
await actions.dispatch('setCount', 42);
@context-action/core works perfectly with vanilla JavaScript! No React, Vue, or any framework required.
<!DOCTYPE html>
<html>
<head>
<title>Context-Action Example</title>
</head>
<body>
<div id="counter">0</div>
<button id="increment">Increment</button>
<script type="module">
import { ActionRegister } from 'https://esm.sh/@context-action/core@latest';
// Simple store
class Store {
constructor(initialState) {
this.state = initialState;
this.listeners = new Set();
}
getValue() { return this.state; }
setValue(newState) {
this.state = newState;
this.listeners.forEach(fn => fn(this.state));
}
subscribe(listener) {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
}
// Create store and actions
const counterStore = new Store({ count: 0 });
const actions = new ActionRegister({ name: 'Counter' });
// Register handler
actions.register('increment', () => {
const current = counterStore.getValue();
counterStore.setValue({ count: current.count + 1 });
});
// Subscribe to updates
counterStore.subscribe(state => {
document.getElementById('counter').textContent = state.count;
});
// Wire up button
document.getElementById('increment').onclick = () => {
actions.dispatch('increment');
};
</script>
</body>
</html>
import { ActionRegister } from '@context-action/core';
const actions = new ActionRegister({ name: 'MyApp' });
actions.register('processData', async (data, controller) => {
console.log('Processing:', data);
// Business logic here
const result = await someAsyncOperation(data);
controller.setResult(result);
}, { priority: 100 });
// Dispatch action
const result = await actions.dispatchWithResult('processData', {
input: 'example'
});
console.log('Result:', result.successResults);
📚 Learn More:
// Configure handler limits for memory safety (v0.4.1+)
const actions = new ActionRegister<MyActions>({
registry: {
maxHandlersPerAction: 1000 // Default: 1000, prevents memory issues
// maxHandlersPerAction: 5000 // Higher limit for complex applications
// maxHandlersPerAction: Infinity // Disable limit (use with caution)
}
});
// Use cases for different limits:
// - 1000 (default): Most applications
// - 5000-10000: Large enterprise applications
// - Infinity: Only for controlled environments with trusted code
Filter handlers by priority, ID, or custom conditions:
// Filter by priority range
await actions.dispatch('updateUser', userData, {
filter: {
priority: { min: 10, max: 50 } // Only handlers with priority 10-50
}
});
// Filter by specific handler IDs
await actions.dispatch('processData', data, {
filter: {
handlerIds: ['validation', 'logging'], // Only these handlers
excludeHandlerIds: ['analytics'] // Exclude analytics handler
}
});
// Custom filtering logic
await actions.dispatch('secureAction', data, {
filter: {
custom: (config) => config.blocking === true // Only blocking handlers
}
});
// Combined filtering
await actions.dispatch('complexAction', data, {
filter: {
priority: { min: 20 },
excludeHandlerIds: ['debug'],
custom: (config) => !config.id.includes('test')
}
});
actions.register('myAction', handler, {
priority: 10,
id: 'my-handler',
blocking: true,
once: false,
debounce: 300,
throttle: 1000,
replaceExisting: true // 🆕 Replace handler with same ID (great for React HMR)
});
// Bypass queue for immediate execution
await actions.dispatch('urgentAction', data, {
immediate: true
});
// Queue with custom priority
await actions.dispatch('backgroundTask', data, {
queuePriority: 5
});
// Execution timeout
await actions.dispatch('timedAction', data, {
timeout: 5000
});
const result = await actions.dispatchWithResult('processData', data, {
result: {
collect: true,
strategy: 'all', // 'first' | 'last' | 'all' | 'merge' | 'custom'
maxResults: 10,
includeErrors: true
}
});
console.log('Results:', result.results);
console.log('Execution time:', result.execution.duration);
console.log('Success:', result.success);
import {
useActionHandler,
ReactDevUtils
} from '@context-action/core';
// React hook pattern
function MyComponent() {
const registry = useActionRegister();
// Auto-cleanup on unmount, HMR support
const handlerConfig = useActionHandler(
registry,
'userAction',
async (payload) => {
// Handler logic
},
{ priority: 10 },
[] // dependencies
);
// Direct registry dispatch with error handling
const handleDispatch = useCallback(async (action, payload) => {
try {
await registry.dispatch(action, payload);
} catch (error) {
console.error(`Failed to dispatch ${action}:`, error);
}
}, [registry]);
}
// Development utilities
ReactDevUtils.enableDebugMode();
const stats = ReactDevUtils.getStats(registry);
const registry = new ActionRegister<MyActions>({
name: 'MyApp',
registry: {
debug: true,
autoCleanup: true,
defaultExecutionMode: 'sequential',
useConcurrencyQueue: true,
errorHandler: (error, context) => {
console.error('Unhandled action error:', error);
}
}
});
Full control over pipeline execution:
actions.register('validate', (data, controller) => {
// Abort pipeline
if (!data.isValid) {
controller.abort('Validation failed');
return;
}
// Modify payload for next handlers
controller.modifyPayload(data => ({
...data,
validated: true,
timestamp: Date.now()
}));
// Jump to high-priority handlers
if (data.urgent) {
controller.jumpToPriority(100);
}
// Set result for collection
controller.setResult({ validation: 'passed' });
// Early return with result
if (data.fastPath) {
controller.return({ fastPath: true });
}
});
// Built-in debounce/throttle support
actions.register('searchUsers', searchHandler, {
debounce: 300 // Wait 300ms after last call
});
actions.register('scrollHandler', updateUI, {
throttle: 100 // Max once per 100ms
});
// Via dispatch options
await actions.dispatch('search', query, {
debounce: 500
});
// Set execution mode per action
actions.setActionExecutionMode('logEvent', 'parallel');
actions.setActionExecutionMode('fetchData', 'race');
// Override via dispatch options
await actions.dispatch('processFiles', files, {
executionMode: 'parallel'
});
actions.register('riskyOperation', async (data, controller) => {
try {
const result = await riskyAPI(data);
return result;
} catch (error) {
if (error.retryable) {
// Let other handlers try
return undefined;
} else {
// Abort pipeline for critical errors
controller.abort(`Critical error: ${error.message}`);
}
}
});
// With retry configuration
await actions.dispatch('apiCall', data, {
retryOnError: {
maxAttempts: 3,
delay: 1000
}
});
// Registry information
const info = actions.getRegistryInfo();
console.log(`Total actions: ${info.totalActions}`);
console.log(`Total handlers: ${info.totalHandlers}`);
// Action-specific statistics
const stats = actions.getActionStats('updateUser');
if (stats) {
console.log(`Handler count: ${stats.handlerCount}`);
console.log(`Success rate: ${stats.executionStats?.successRate}%`);
console.log(`Average duration: ${stats.executionStats?.averageDuration}ms`);
}
// Clear statistics
actions.clearExecutionStats();
// Explicit cleanup when done
const registry = new ActionRegister({ name: 'MyApp' });
// Use the registry...
// Clean up all resources
registry.destroy(); // Cleans up pipelines, guards, queues, stats
register<K>(action, handler, config?) - Register action handlerclearAction(action) - Remove all handlers for actionclearAll() - Remove all handlersdispatch<K>(action, payload?, options?) - Dispatch actiondispatchWithResult<K>(action, payload?, options?) - Dispatch with detailed resultsgetHandlerCount(action) - Get handler count for actionhasHandlers(action) - Check if action has handlersgetRegisteredActions() - Get all registered action namesgetRegistryInfo() - Get comprehensive registry informationgetActionStats(action) - Get detailed action statisticssetActionExecutionMode(action, mode) - Set execution mode for actiongetActionExecutionMode(action) - Get execution mode for actionremoveActionExecutionMode(action) - Reset to default execution modegetName() - Get registry nameisDebugEnabled() - Check if debug mode is enableddestroy() - Clean up all resourcesinterface HandlerConfig {
priority?: number; // Handler priority (higher = first)
id?: string; // Unique handler identifier
blocking?: boolean; // Wait for async completion
once?: boolean; // Remove after first execution
debounce?: number; // Debounce delay in ms
throttle?: number; // Throttle delay in ms
replaceExisting?: boolean; // Replace handler with same ID
}
interface DispatchOptions {
debounce?: number;
throttle?: number;
executionMode?: 'sequential' | 'parallel' | 'race';
signal?: AbortSignal;
immediate?: boolean; // Bypass queue
queuePriority?: number; // Queue priority
timeout?: number; // Execution timeout
retryOnError?: {
maxAttempts: number;
delay: number;
};
filter?: {
handlerIds?: string[];
excludeHandlerIds?: string[];
priority?: { min?: number; max?: number };
custom?: (config: HandlerConfig) => boolean;
};
result?: {
strategy?: 'first' | 'last' | 'all' | 'merge' | 'custom';
merger?: <R>(results: R[]) => R;
collect?: boolean;
maxResults?: number;
includeErrors?: boolean;
};
}
Full type safety with excellent IntelliSense support:
interface AppActions {
// Void actions
reset: void;
logout: void;
// Actions with payloads
setUser: { id: string; name: string; email: string };
updatePreferences: { theme: 'light' | 'dark'; language: string };
// Union type payloads
navigate: { route: string } | { url: URL };
}
const actions = new ActionRegister<AppActions>();
// ✅ Type-safe - all good
await actions.dispatch('reset');
await actions.dispatch('setUser', { id: '1', name: 'John', email: 'john@example.com' });
// ❌ TypeScript errors
await actions.dispatch('setUser'); // Missing required payload
await actions.dispatch('setUser', { id: '1' }); // Missing required fields
await actions.dispatch('invalidAction'); // Unknown action
Most existing code works without changes. New features are opt-in:
// v0.3.x code - still works
const actions = new ActionRegister();
actions.register('myAction', handler);
await actions.dispatch('myAction', payload);
// v0.4.x - new features available
actions.register('myAction', handler, {
replaceExisting: true // New option
});
await actions.dispatch('myAction', payload, {
filter: { priority: { min: 10 } } // New filtering
});
// Clean up when done (recommended)
actions.destroy();
Apache-2.0
FAQs
Type-safe action pipeline management library for JavaScript/TypeScript
We found that @context-action/core 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.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.