UNPKG

guardz-event

Version:

Type-safe event handling with runtime validation using guardz for unsafe data from 3rd parties

320 lines 14 kB
"use strict"; // =============================== // Modern, Simplified API // =============================== var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Status = exports.safeStorageEventListener = exports.safeCustomEventListener = exports.safeEventSourceListener = exports.safeDOMEventListener = exports.safeWebSocketListener = exports.safePostMessageListener = exports.createTypedSafeStorageEvent = exports.createTypedSafeCustomEvent = exports.createTypedSafeEventSource = exports.createTypedSafeWebSocket = exports.createTypedSafePostMessage = exports.createTypedSafeDOMEvent = exports.createSafeEventContext = exports.safe = exports.SafeEventBuilder = exports.safeEvent = exports.safeEventSource = exports.safeWebSocket = exports.safeDOMEvent = exports.EventGuard = void 0; exports.onEvent = onEvent; exports.onMessage = onMessage; exports.onClick = onClick; exports.onCustom = onCustom; exports.onStorage = onStorage; exports.eventGuard = eventGuard; exports.useEvent = useEvent; exports.safeHandler = safeHandler; exports.safeTolerant = safeTolerant; exports.createTypedHandler = createTypedHandler; const Status_1 = require("./domain/event/Status"); // =============================== // 1. Simple onEvent API (Primary) // =============================== /** * Create a safe event handler for any event type * Usage: window.addEventListener('message', onEvent('message', isChatMessage, { onSuccess: handleData })) */ function onEvent(eventType, guard, options) { const config = { guard, tolerance: options.tolerance, identifier: options.identifier || eventType, allowedOrigins: options.allowedOrigins, allowedSources: options.allowedSources, onError: (error, context) => { if (context.type === 'security' && options.onSecurityViolation) { options.onSecurityViolation(context.origin || 'null', error); } else if (context.type === 'validation' && options.onTypeMismatch) { options.onTypeMismatch(error); } else if (options.onError) { options.onError(error); } }, }; return (event) => { let result; if (event instanceof MessageEvent) { result = (0, safe_event_never_throws_2.safePostMessage)(config)(event); } else if (event instanceof CustomEvent) { result = (0, safe_event_never_throws_2.safeCustomEvent)(config)(event); } else if (event instanceof StorageEvent) { result = (0, safe_event_never_throws_2.safeStorageEvent)(config)(event); } else { result = (0, safe_event_never_throws_2.safeDOMEvent)(config)(event); } if (result.status === Status_1.Status.SUCCESS) { options.onSuccess(result.data); } else if (result.code === 500 && options.onTypeMismatch) { options.onTypeMismatch(result.message); } else if (options.onError) { options.onError(result.message); } }; } // =============================== // 2. Auto-inferred Event Handlers // =============================== /** * Create a safe message event handler * Usage: window.addEventListener('message', onMessage(isChatMessage, { onSuccess: handleData })) */ function onMessage(guard, options) { return onEvent('message', guard, options); } /** * Create a safe DOM event handler * Usage: element.addEventListener('click', onClick(isClickData, { onSuccess: handleClick })) */ function onClick(guard, options) { return onEvent('click', guard, options); } /** * Create a safe custom event handler * Usage: element.addEventListener('custom-event', onCustom('custom-event', isCustomData, { onSuccess: handleData })) */ function onCustom(eventType, guard, options) { return onEvent(eventType, guard, options); } /** * Create a safe storage event handler * Usage: window.addEventListener('storage', onStorage(isStorageData, { onSuccess: handleStorage })) */ function onStorage(guard, options) { return onEvent('storage', guard, options); } // =============================== // 3. Fluent Builder API (Advanced) // =============================== class EventGuard { constructor() { this.eventType = ''; this.options = {}; } type(eventType) { this.eventType = eventType; return this; } validate(guard) { const newGuard = new EventGuard(); newGuard.eventType = this.eventType; newGuard.guard = guard; // Reset options for the new type newGuard.options = {}; return newGuard; } onSuccess(callback) { this.options.onSuccess = callback; return this; } onError(callback) { this.options.onError = callback; return this; } onTypeMismatch(callback) { this.options.onTypeMismatch = callback; return this; } onSecurityViolation(callback) { this.options.onSecurityViolation = callback; return this; } tolerance(enabled = true) { this.options.tolerance = enabled; return this; } allowedOrigins(origins) { this.options.allowedOrigins = origins; return this; } allowedSources(sources) { this.options.allowedSources = sources; return this; } identifier(id) { this.options.identifier = id; return this; } build() { if (!this.guard) { throw new Error('Guard function is required. Call .validate(guard) first.'); } if (!this.options.onSuccess) { throw new Error('Success callback is required. Call .onSuccess(callback) first.'); } return onEvent(this.eventType, this.guard, this.options); } } exports.EventGuard = EventGuard; /** * Create a fluent event guard builder * Usage: eventGuard().type('message').validate(isChatMessage).onSuccess(handleData).build() */ function eventGuard() { return new EventGuard(); } /** * React hook for safe event handling * Usage: const { data, error } = useEvent('message', isChatMessage, { tolerance: true }) * * Note: This is a framework-agnostic implementation. For React integration, * you would need to wrap this with React's useEffect and useState hooks. * * Example React implementation: * ```tsx * function useSafeEvent<T>(eventType: string, guard: TypeGuardFn<T>, options: UseEventOptions<T> = {}) { * const [data, setData] = useState<T | null>(null); * const [error, setError] = useState<string | null>(null); * const [isLoading, setIsLoading] = useState(false); * * useEffect(() => { * const handler = onEvent(eventType, guard, { * onSuccess: (data) => { * setData(data); * setError(null); * setIsLoading(false); * options.onSuccess?.(data); * }, * onError: (message) => { * setError(message); * setIsLoading(false); * options.onError?.(message); * }, * onTypeMismatch: options.onTypeMismatch, * onSecurityViolation: options.onSecurityViolation, * tolerance: options.tolerance, * allowedOrigins: options.allowedOrigins, * allowedSources: options.allowedSources, * identifier: options.identifier, * }); * * // Add event listener * window.addEventListener(eventType, handler); * * // Cleanup * return () => window.removeEventListener(eventType, handler); * }, [eventType, guard, options]); * * return { data, error, isLoading, refetch: () => setIsLoading(true) }; * } * ``` */ function useEvent(eventType, guard, options = {}) { // Framework-agnostic implementation // In a real React implementation, you would use: // const [data, setData] = useState<T | null>(null); // const [error, setError] = useState<string | null>(null); // const [isLoading, setIsLoading] = useState(false); const handler = onEvent(eventType, guard, { onSuccess: (data) => { if (options.onSuccess) { options.onSuccess(data); } }, onError: (message) => { if (options.onError) { options.onError(message); } }, onTypeMismatch: options.onTypeMismatch, onSecurityViolation: options.onSecurityViolation, tolerance: options.tolerance, allowedOrigins: options.allowedOrigins, allowedSources: options.allowedSources, identifier: options.identifier, }); return { data: null, error: null, isLoading: false, refetch: () => { // In a real implementation, this would trigger a re-fetch // For now, it's a no-op }, }; } // =============================== // 5. Utility Functions // =============================== /** * Create a safe event handler with minimal configuration * Usage: window.addEventListener('message', safeHandler(isChatMessage, handleData)) */ function safeHandler(guard, onSuccess, onError) { return onEvent('message', guard, { onSuccess, onError }); } /** * Create a safe event handler with tolerance mode * Usage: window.addEventListener('message', safeTolerant(isChatMessage, handleData, handleError)) */ function safeTolerant(guard, onSuccess, onError) { return onEvent('message', guard, { onSuccess, onError, tolerance: true }); } /** * Create a typed event handler factory */ function createTypedHandler(guard) { return (options) => onEvent('message', guard, options); } // =============================== // 7. Backward Compatibility // =============================== // Re-export existing APIs for backward compatibility (excluding EventResult to avoid conflicts) var safe_event_never_throws_1 = require("./utils/safe-event-never-throws"); // Legacy API functions Object.defineProperty(exports, "safeDOMEvent", { enumerable: true, get: function () { return safe_event_never_throws_1.safeDOMEvent; } }); Object.defineProperty(exports, "safeWebSocket", { enumerable: true, get: function () { return safe_event_never_throws_1.safeWebSocket; } }); Object.defineProperty(exports, "safeEventSource", { enumerable: true, get: function () { return safe_event_never_throws_1.safeEventSource; } }); Object.defineProperty(exports, "safeEvent", { enumerable: true, get: function () { return safe_event_never_throws_1.safeEvent; } }); // Builder API Object.defineProperty(exports, "SafeEventBuilder", { enumerable: true, get: function () { return safe_event_never_throws_1.SafeEventBuilder; } }); Object.defineProperty(exports, "safe", { enumerable: true, get: function () { return safe_event_never_throws_1.safe; } }); // Context API Object.defineProperty(exports, "createSafeEventContext", { enumerable: true, get: function () { return safe_event_never_throws_1.createSafeEventContext; } }); Object.defineProperty(exports, "createTypedSafeDOMEvent", { enumerable: true, get: function () { return safe_event_never_throws_1.createTypedSafeDOMEvent; } }); Object.defineProperty(exports, "createTypedSafePostMessage", { enumerable: true, get: function () { return safe_event_never_throws_1.createTypedSafePostMessage; } }); Object.defineProperty(exports, "createTypedSafeWebSocket", { enumerable: true, get: function () { return safe_event_never_throws_1.createTypedSafeWebSocket; } }); Object.defineProperty(exports, "createTypedSafeEventSource", { enumerable: true, get: function () { return safe_event_never_throws_1.createTypedSafeEventSource; } }); Object.defineProperty(exports, "createTypedSafeCustomEvent", { enumerable: true, get: function () { return safe_event_never_throws_1.createTypedSafeCustomEvent; } }); Object.defineProperty(exports, "createTypedSafeStorageEvent", { enumerable: true, get: function () { return safe_event_never_throws_1.createTypedSafeStorageEvent; } }); // Ergonomic API functions (legacy) Object.defineProperty(exports, "safePostMessageListener", { enumerable: true, get: function () { return safe_event_never_throws_1.safePostMessageListener; } }); Object.defineProperty(exports, "safeWebSocketListener", { enumerable: true, get: function () { return safe_event_never_throws_1.safeWebSocketListener; } }); Object.defineProperty(exports, "safeDOMEventListener", { enumerable: true, get: function () { return safe_event_never_throws_1.safeDOMEventListener; } }); Object.defineProperty(exports, "safeEventSourceListener", { enumerable: true, get: function () { return safe_event_never_throws_1.safeEventSourceListener; } }); Object.defineProperty(exports, "safeCustomEventListener", { enumerable: true, get: function () { return safe_event_never_throws_1.safeCustomEventListener; } }); Object.defineProperty(exports, "safeStorageEventListener", { enumerable: true, get: function () { return safe_event_never_throws_1.safeStorageEventListener; } }); __exportStar(require("./utils/additional-sources"), exports); var Status_2 = require("./domain/event/Status"); Object.defineProperty(exports, "Status", { enumerable: true, get: function () { return Status_2.Status; } }); // Import the functions we need const safe_event_never_throws_2 = require("./utils/safe-event-never-throws"); //# sourceMappingURL=index.js.map