guardz-event
Version:
Type-safe event handling with runtime validation using guardz for unsafe data from 3rd parties
783 lines • 30.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeIntersectionObserver = safeIntersectionObserver;
exports.safeResizeObserver = safeResizeObserver;
exports.safeMutationObserver = safeMutationObserver;
exports.safePerformanceObserver = safePerformanceObserver;
exports.safeGeolocation = safeGeolocation;
exports.safeDeviceOrientation = safeDeviceOrientation;
exports.safeDeviceMotion = safeDeviceMotion;
exports.safeServiceWorkerMessage = safeServiceWorkerMessage;
exports.safeBroadcastChannel = safeBroadcastChannel;
exports.safePaymentRequest = safePaymentRequest;
exports.safeBatteryStatus = safeBatteryStatus;
exports.safeNetworkInformation = safeNetworkInformation;
const guardz_1 = require("guardz");
const Status_1 = require("../domain/event/Status");
// ===============================
// Observer-based Event Sources
// ===============================
/**
* Safe Intersection Observer handler
* Usage: const safeIntersectionHandler = safeIntersectionObserver({ guard: isIntersectionData });
* observer.observe(element);
*/
function safeIntersectionObserver(config) {
return (entries) => {
return entries.map(entry => {
try {
const data = {
isIntersecting: entry.isIntersecting,
intersectionRatio: entry.intersectionRatio,
boundingClientRect: entry.boundingClientRect,
rootBounds: entry.rootBounds,
target: entry.target,
time: entry.time,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'intersection-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'intersection',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'intersection',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
});
};
}
/**
* Safe Resize Observer handler
* Usage: const safeResizeHandler = safeResizeObserver({ guard: isResizeData });
* observer.observe(element);
*/
function safeResizeObserver(config) {
return (entries) => {
return entries.map(entry => {
try {
const data = {
contentRect: entry.contentRect,
borderBoxSize: entry.borderBoxSize,
contentBoxSize: entry.contentBoxSize,
devicePixelContentBoxSize: entry.devicePixelContentBoxSize,
target: entry.target,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'resize-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'resize',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'resize',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
});
};
}
/**
* Safe Mutation Observer handler
* Usage: const safeMutationHandler = safeMutationObserver({ guard: isMutationData });
* observer.observe(target, config);
*/
function safeMutationObserver(config) {
return (mutations) => {
return mutations.map(mutation => {
try {
const data = {
type: mutation.type,
target: mutation.target,
addedNodes: mutation.addedNodes,
removedNodes: mutation.removedNodes,
previousSibling: mutation.previousSibling,
nextSibling: mutation.nextSibling,
attributeName: mutation.attributeName,
attributeNamespace: mutation.attributeNamespace,
oldValue: mutation.oldValue,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard);
const isValid = config.guard(result);
if (isValid) {
return { status: Status_1.Status.SUCCESS, data: result };
}
else {
const errorMessage = `Validation failed: Data does not match expected type`;
if (config.onError) {
config.onError(errorMessage, {
type: 'validation',
eventType: 'mutation',
originalError: errorMessage,
});
}
return { status: Status_1.Status.SUCCESS, data: result };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'mutation',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
});
};
}
/**
* Safe Performance Observer handler
* Usage: const safePerformanceHandler = safePerformanceObserver({ guard: isPerformanceData });
* observer.observe({ entryTypes: ['navigation'] });
*/
function safePerformanceObserver(config) {
return (list) => {
return list.getEntries().map(() => {
try {
const data = {
entries: list.getEntries(),
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'performance-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'performance',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'performance',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
});
};
}
// ===============================
// Device API Event Sources
// ===============================
/**
* Safe Geolocation handler
* Usage: const safeGeoHandler = safeGeolocation({ guard: isGeoData });
* navigator.geolocation.getCurrentPosition(safeGeoHandler);
*/
function safeGeolocation(config) {
return (position) => {
try {
const data = {
coords: position.coords,
timestamp: position.timestamp,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'geolocation-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'geolocation',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'geolocation',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
/**
* Safe Device Orientation handler
* Usage: const safeOrientationHandler = safeDeviceOrientation({ guard: isOrientationData });
* window.addEventListener('deviceorientation', safeOrientationHandler);
*/
function safeDeviceOrientation(config) {
return (event) => {
try {
const data = {
alpha: event.alpha,
beta: event.beta,
gamma: event.gamma,
absolute: event.absolute,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'deviceorientation-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'deviceorientation',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'deviceorientation',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
/**
* Safe Device Motion handler
* Usage: const safeMotionHandler = safeDeviceMotion({ guard: isMotionData });
* window.addEventListener('devicemotion', safeMotionHandler);
*/
function safeDeviceMotion(config) {
return (event) => {
try {
const data = {
acceleration: event.acceleration,
accelerationIncludingGravity: event.accelerationIncludingGravity,
rotationRate: event.rotationRate,
interval: event.interval,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'devicemotion-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'devicemotion',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'devicemotion',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
// ===============================
// Service Worker Event Sources
// ===============================
/**
* Safe Service Worker Message handler
* Usage: const safeSWHandler = safeServiceWorkerMessage({ guard: isSWMessageData });
* self.addEventListener('message', safeSWHandler);
*/
function safeServiceWorkerMessage(config) {
return (event) => {
try {
const data = {
data: event.data,
origin: event.origin,
source: event.source,
ports: event.ports,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'serviceworker-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'serviceworker',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'serviceworker',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
// ===============================
// Broadcast Channel Event Sources
// ===============================
/**
* Safe Broadcast Channel handler
* Usage: const safeBCHandler = safeBroadcastChannel({ guard: isBCData });
* channel.addEventListener('message', safeBCHandler);
*/
function safeBroadcastChannel(config) {
return (event) => {
try {
const data = {
data: event.data,
origin: event.origin,
source: event.source,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'broadcast-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'broadcast',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'broadcast',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
// ===============================
// Payment API Event Sources
// ===============================
/**
* Safe Payment Request handler
* Usage: const safePaymentHandler = safePaymentRequest({ guard: isPaymentData });
* paymentRequest.addEventListener('paymentmethodchange', safePaymentHandler);
*/
function safePaymentRequest(config) {
return (event) => {
try {
const data = {
methodName: event.methodName,
methodDetails: event.methodDetails,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'payment-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'payment',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'payment',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
// ===============================
// Battery API Event Sources
// ===============================
/**
* Safe Battery Status handler
* Usage: const safeBatteryHandler = safeBatteryStatus({ guard: isBatteryData });
* battery.addEventListener('levelchange', safeBatteryHandler);
*/
function safeBatteryStatus(config) {
return async () => {
try {
const batteryPromise = navigator.getBattery?.();
if (!batteryPromise) {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Battery API not supported',
};
}
const battery = await batteryPromise;
const data = {
level: battery.level,
charging: battery.charging,
chargingTime: battery.chargingTime,
dischargingTime: battery.dischargingTime,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'battery-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'battery',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'battery',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
// ===============================
// Network Information API Event Sources
// ===============================
/**
* Safe Network Information handler
* Usage: const safeNetworkHandler = safeNetworkInformation({ guard: isNetworkData });
* connection.addEventListener('change', safeNetworkHandler);
*/
function safeNetworkInformation(config) {
return () => {
try {
const connection = navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection;
if (!connection) {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Network Information API not supported',
};
}
const data = {
effectiveType: connection.effectiveType,
downlink: connection.downlink,
rtt: connection.rtt,
saveData: connection.saveData,
};
if (config.tolerance) {
const result = (0, guardz_1.guardWithTolerance)(data, config.guard, {
identifier: 'network-data',
callbackOnError: error => {
if (config.onError) {
config.onError(error, {
type: 'validation',
eventType: 'network',
originalError: error,
});
}
},
});
if (result) {
return { status: Status_1.Status.SUCCESS, data: data };
}
else {
return { status: Status_1.Status.SUCCESS, data: data };
}
}
else {
if (config.guard(data)) {
return { status: Status_1.Status.SUCCESS, data };
}
else {
return {
status: Status_1.Status.ERROR,
code: 500,
message: 'Validation failed: Data does not match expected type',
};
}
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
if (config.onError) {
config.onError(errorMessage, {
type: 'unknown',
eventType: 'network',
originalError: error,
});
}
return { status: Status_1.Status.ERROR, code: 500, message: errorMessage };
}
};
}
//# sourceMappingURL=additional-sources.js.map