Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@xyo-network/module-events

Package Overview
Dependencies
Maintainers
7
Versions
611
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@xyo-network/module-events - npm Package Compare versions

Comparing version 2.53.3 to 2.53.4

160

dist/cjs/Events/Events.js

@@ -7,32 +7,15 @@ "use strict";

const forget_1 = require("@xylabs/forget");
const core_1 = require("@xyo-network/core");
const resolvedPromise = Promise.resolve();
let canEmitMetaEvents = false;
let isGlobalDebugEnabled = false;
function assertEventName(eventName) {
if (typeof eventName !== 'string' && typeof eventName !== 'symbol' && typeof eventName !== 'number') {
throw new TypeError('`eventName` must be a string, symbol, or number');
}
}
function assertListener(listener) {
if (typeof listener !== 'function') {
throw new TypeError('listener must be a function');
}
}
const isMetaEvent = (eventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved';
class Events {
constructor(options = {}) {
class Events extends core_1.Base {
constructor(params = {}) {
var _a;
//this is here to be able to query the type, not use
this.eventData = {};
Events.anyMap.set(this, new Set());
Events.eventsMap.set(this, new Map());
this.debug = options.debug;
if (this.debug) {
this.debug.enabled = !!this.debug.enabled;
this.debug.logger =
(_a = this.debug.logger) !== null && _a !== void 0 ? _a : ((type, debugName, eventName, eventData) => {
const mutatedParams = Object.assign({}, params);
if (mutatedParams.debug) {
mutatedParams.debug.logger =
(_a = mutatedParams.debug.logger) !== null && _a !== void 0 ? _a : ((type, debugName, eventName, eventData) => {
let eventDataString;
let eventNameString;
try {
// TODO: Use https://github.com/sindresorhus/safe-stringify when the package is more mature. Just copy-paste the code.
eventDataString = JSON.stringify(eventData);

@@ -51,5 +34,10 @@ }

const logTime = `${currentTime.getHours()}:${currentTime.getMinutes()}:${currentTime.getSeconds()}.${currentTime.getMilliseconds()}`;
console.log(`[${logTime}][events:${type}][${debugName}] Event Name: ${eventNameString}\n\tdata: ${eventDataString}`);
this.logger.log(`[${logTime}][events:${type}][${debugName}] Event Name: ${eventNameString}\n\tdata: ${eventDataString}`);
});
}
super(mutatedParams);
//this is here to be able to query the type, not use
this.eventData = {};
Events.anyMap.set(this, new Set());
Events.eventsMap.set(this, new Map());
}

@@ -61,10 +49,13 @@ static get isDebugEnabled() {

if (typeof ((_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env) !== 'object') {
return isGlobalDebugEnabled;
return Events.isGlobalDebugEnabled;
}
const { env } = (_b = globalThis.process) !== null && _b !== void 0 ? _b : { env: {} };
return env.DEBUG === 'emittery' || env.DEBUG === '*' || isGlobalDebugEnabled;
return env.DEBUG === 'events' || env.DEBUG === '*' || Events.isGlobalDebugEnabled;
}
static set isDebugEnabled(newValue) {
isGlobalDebugEnabled = newValue;
Events.isGlobalDebugEnabled = newValue;
}
get debug() {
return this.params.debug;
}
clearListeners(eventNames) {

@@ -99,7 +90,7 @@ var _a, _b;

try {
canEmitMetaEvents = true;
Events.canEmitMetaEvents = true;
yield this.emitMetaEventInternal(eventName, eventArgs);
}
finally {
canEmitMetaEvents = false;
Events.canEmitMetaEvents = false;
}

@@ -112,31 +103,34 @@ }

return tslib_1.__awaiter(this, void 0, void 0, function* () {
assertEventName(eventName);
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');
}
const filterMatch = (args, filter) => {
if (filter) {
switch (typeof filter) {
case 'object':
return Object.entries(args).reduce((prev, [key, value]) => (filter[key] === value ? true : prev), false);
default:
return args === filter;
}
}
return true;
};
this.logIfDebugEnabled('emitSerial', eventName, eventArgs);
const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set();
const filteredListeners = [...listeners.values()]
.filter((value) => (value.filter ? filterMatch(eventArgs, value.filter) : true))
.map((info) => info.listener);
const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this));
const staticListeners = [...listeners];
const staticListeners = [...filteredListeners];
const staticAnyListeners = [...anyListeners];
yield resolvedPromise;
for (const listener of staticListeners) {
if (listeners.has(listener)) {
yield listener(eventArgs);
}
yield this.safeCallListener(eventName, eventArgs, listener);
}
for (const listener of staticAnyListeners) {
if (anyListeners.has(listener)) {
yield listener(eventName, eventArgs);
}
yield this.safeCallAnyListener(eventName, eventArgs, listener);
}
});
}
getListeners(eventName) {
const events = (0, assert_1.assertEx)(Events.eventsMap.get(this));
if (!events.has(eventName)) {
return;
}
return events.get(eventName);
}
//TODO: Make test for this
listenerCount(eventNames) {

@@ -151,5 +145,2 @@ var _a, _b;

}
if (typeof eventName !== 'undefined') {
assertEventName(eventName);
}
count += (0, assert_1.assertEx)(Events.anyMap.get(this)).size;

@@ -169,6 +160,4 @@ for (const value of (0, assert_1.assertEx)(Events.eventsMap.get(this)).values()) {

off(eventNames, listener) {
assertListener(listener);
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNamesArray) {
assertEventName(eventName);
const set = this.getListeners(eventName);

@@ -189,3 +178,2 @@ if (set) {

offAny(listener) {
assertListener(listener);
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined);

@@ -196,7 +184,5 @@ const typedMap = Events.anyMap.get(this);

}
on(eventNames, listener) {
assertListener(listener);
on(eventNames, listener, filter) {
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNamesArray) {
assertEventName(eventName);
let set = this.getListeners(eventName);

@@ -208,3 +194,3 @@ if (!set) {

}
set.add(listener);
set.add({ filter, listener: listener });
this.logIfDebugEnabled('subscribe', eventName, undefined);

@@ -219,3 +205,2 @@ if (!isMetaEvent(eventName)) {

var _a;
assertListener(listener);
this.logIfDebugEnabled('subscribeAny', undefined, undefined);

@@ -229,3 +214,3 @@ (_a = Events.anyMap.get(this)) === null || _a === void 0 ? void 0 : _a.add(listener);

this.off(eventName, subListener);
yield listener(args);
yield this.safeCallListener(eventName, args, listener);
});

@@ -235,7 +220,6 @@ this.on(eventName, subListener);

}
emitInternal(eventName, eventArgs) {
emitInternal(eventName, eventArgs, filter) {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
assertEventName(eventName);
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');

@@ -245,4 +229,5 @@ }

const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set();
const filteredListeners = [...listeners.values()].filter((value) => (filter ? value.listener : true)).map((info) => info.listener);
const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this));
const staticListeners = [...listeners];
const staticListeners = [...filteredListeners];
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners];

@@ -252,9 +237,7 @@ yield resolvedPromise;

...staticListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (listeners.has(listener)) {
return yield listener(eventArgs);
}
yield this.safeCallListener(eventName, eventArgs, listener);
})),
...staticAnyListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (anyListeners.has(listener)) {
return yield listener(eventName, eventArgs);
yield this.safeCallAnyListener(eventName, eventArgs, listener);
}

@@ -268,4 +251,3 @@ })),

return tslib_1.__awaiter(this, void 0, void 0, function* () {
assertEventName(eventName);
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');

@@ -275,4 +257,5 @@ }

const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set();
const filteredListeners = [...listeners.values()].map((info) => info.listener);
const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this));
const staticListeners = [...listeners];
const staticListeners = [...filteredListeners];
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners];

@@ -282,9 +265,7 @@ yield resolvedPromise;

...staticListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (listeners.has(listener)) {
return yield listener(eventArgs);
}
yield this.safeCallListener(eventName, eventArgs, listener);
})),
...staticAnyListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (anyListeners.has(listener)) {
return yield listener(eventName, eventArgs);
yield this.safeCallAnyListener(eventName, eventArgs, listener);
}

@@ -295,2 +276,33 @@ })),

}
getListeners(eventName) {
const events = (0, assert_1.assertEx)(Events.eventsMap.get(this));
if (!events.has(eventName)) {
return;
}
return events.get(eventName);
}
safeCallAnyListener(eventName, eventArgs, listener) {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
return yield listener(eventName, eventArgs);
}
catch (ex) {
const error = ex;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`Listener[${String(eventName)}] Excepted: ${error.message}`);
}
});
}
safeCallListener(eventName, eventArgs, listener) {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
return yield listener(eventArgs);
}
catch (ex) {
const error = ex;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`Listener[${String(eventName)}] Excepted: ${error.message}`);
}
});
}
}

@@ -300,2 +312,4 @@ exports.Events = Events;

Events.eventsMap = new WeakMap();
Events.canEmitMetaEvents = false;
Events.isGlobalDebugEnabled = false;
//# sourceMappingURL=Events.js.map
import { assertEx } from '@xylabs/assert';
import { forget } from '@xylabs/forget';
import { Base } from '@xyo-network/core';
const resolvedPromise = Promise.resolve();
let canEmitMetaEvents = false;
let isGlobalDebugEnabled = false;
function assertEventName(eventName) {
if (typeof eventName !== 'string' && typeof eventName !== 'symbol' && typeof eventName !== 'number') {
throw new TypeError('`eventName` must be a string, symbol, or number');
}
}
function assertListener(listener) {
if (typeof listener !== 'function') {
throw new TypeError('listener must be a function');
}
}
const isMetaEvent = (eventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved';
export class Events {
export class Events extends Base {
static anyMap = new WeakMap();
static eventsMap = new WeakMap();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
debug;
static canEmitMetaEvents = false;
static isGlobalDebugEnabled = false;
//this is here to be able to query the type, not use
eventData = {};
constructor(options = {}) {
Events.anyMap.set(this, new Set());
Events.eventsMap.set(this, new Map());
this.debug = options.debug;
if (this.debug) {
this.debug.enabled = !!this.debug.enabled;
this.debug.logger =
this.debug.logger ??
constructor(params = {}) {
const mutatedParams = { ...params };
if (mutatedParams.debug) {
mutatedParams.debug.logger =
mutatedParams.debug.logger ??
((type, debugName, eventName, eventData) => {

@@ -36,3 +22,2 @@ let eventDataString;

try {
// TODO: Use https://github.com/sindresorhus/safe-stringify when the package is more mature. Just copy-paste the code.
eventDataString = JSON.stringify(eventData);

@@ -51,5 +36,8 @@ }

const logTime = `${currentTime.getHours()}:${currentTime.getMinutes()}:${currentTime.getSeconds()}.${currentTime.getMilliseconds()}`;
console.log(`[${logTime}][events:${type}][${debugName}] Event Name: ${eventNameString}\n\tdata: ${eventDataString}`);
this.logger.log(`[${logTime}][events:${type}][${debugName}] Event Name: ${eventNameString}\n\tdata: ${eventDataString}`);
});
}
super(mutatedParams);
Events.anyMap.set(this, new Set());
Events.eventsMap.set(this, new Map());
}

@@ -60,10 +48,13 @@ static get isDebugEnabled() {

if (typeof globalThis.process?.env !== 'object') {
return isGlobalDebugEnabled;
return Events.isGlobalDebugEnabled;
}
const { env } = globalThis.process ?? { env: {} };
return env.DEBUG === 'emittery' || env.DEBUG === '*' || isGlobalDebugEnabled;
return env.DEBUG === 'events' || env.DEBUG === '*' || Events.isGlobalDebugEnabled;
}
static set isDebugEnabled(newValue) {
isGlobalDebugEnabled = newValue;
Events.isGlobalDebugEnabled = newValue;
}
get debug() {
return this.params.debug;
}
clearListeners(eventNames) {

@@ -94,7 +85,7 @@ const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames];

try {
canEmitMetaEvents = true;
Events.canEmitMetaEvents = true;
await this.emitMetaEventInternal(eventName, eventArgs);
}
finally {
canEmitMetaEvents = false;
Events.canEmitMetaEvents = false;
}

@@ -104,30 +95,33 @@ }

async emitSerial(eventName, eventArgs) {
assertEventName(eventName);
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');
}
const filterMatch = (args, filter) => {
if (filter) {
switch (typeof filter) {
case 'object':
return Object.entries(args).reduce((prev, [key, value]) => (filter[key] === value ? true : prev), false);
default:
return args === filter;
}
}
return true;
};
this.logIfDebugEnabled('emitSerial', eventName, eventArgs);
const listeners = this.getListeners(eventName) ?? new Set();
const filteredListeners = [...listeners.values()]
.filter((value) => (value.filter ? filterMatch(eventArgs, value.filter) : true))
.map((info) => info.listener);
const anyListeners = assertEx(Events.anyMap.get(this));
const staticListeners = [...listeners];
const staticListeners = [...filteredListeners];
const staticAnyListeners = [...anyListeners];
await resolvedPromise;
for (const listener of staticListeners) {
if (listeners.has(listener)) {
await listener(eventArgs);
}
await this.safeCallListener(eventName, eventArgs, listener);
}
for (const listener of staticAnyListeners) {
if (anyListeners.has(listener)) {
await listener(eventName, eventArgs);
}
await this.safeCallAnyListener(eventName, eventArgs, listener);
}
}
getListeners(eventName) {
const events = assertEx(Events.eventsMap.get(this));
if (!events.has(eventName)) {
return;
}
return events.get(eventName);
}
//TODO: Make test for this
listenerCount(eventNames) {

@@ -141,5 +135,2 @@ const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames];

}
if (typeof eventName !== 'undefined') {
assertEventName(eventName);
}
count += assertEx(Events.anyMap.get(this)).size;

@@ -158,6 +149,4 @@ for (const value of assertEx(Events.eventsMap.get(this)).values()) {

off(eventNames, listener) {
assertListener(listener);
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNamesArray) {
assertEventName(eventName);
const set = this.getListeners(eventName);

@@ -178,3 +167,2 @@ if (set) {

offAny(listener) {
assertListener(listener);
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined);

@@ -185,7 +173,5 @@ const typedMap = Events.anyMap.get(this);

}
on(eventNames, listener) {
assertListener(listener);
on(eventNames, listener, filter) {
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNamesArray) {
assertEventName(eventName);
let set = this.getListeners(eventName);

@@ -197,3 +183,3 @@ if (!set) {

}
set.add(listener);
set.add({ filter, listener: listener });
this.logIfDebugEnabled('subscribe', eventName, undefined);

@@ -207,3 +193,2 @@ if (!isMetaEvent(eventName)) {

onAny(listener) {
assertListener(listener);
this.logIfDebugEnabled('subscribeAny', undefined, undefined);

@@ -217,3 +202,3 @@ Events.anyMap.get(this)?.add(listener);

this.off(eventName, subListener);
await listener(args);
await this.safeCallListener(eventName, args, listener);
};

@@ -223,5 +208,4 @@ this.on(eventName, subListener);

}
async emitInternal(eventName, eventArgs) {
assertEventName(eventName);
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
async emitInternal(eventName, eventArgs, filter) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');

@@ -231,4 +215,5 @@ }

const listeners = this.getListeners(eventName) ?? new Set();
const filteredListeners = [...listeners.values()].filter((value) => (filter ? value.listener : true)).map((info) => info.listener);
const anyListeners = assertEx(Events.anyMap.get(this));
const staticListeners = [...listeners];
const staticListeners = [...filteredListeners];
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners];

@@ -238,9 +223,7 @@ await resolvedPromise;

...staticListeners.map(async (listener) => {
if (listeners.has(listener)) {
return await listener(eventArgs);
}
await this.safeCallListener(eventName, eventArgs, listener);
}),
...staticAnyListeners.map(async (listener) => {
if (anyListeners.has(listener)) {
return await listener(eventName, eventArgs);
await this.safeCallAnyListener(eventName, eventArgs, listener);
}

@@ -251,4 +234,3 @@ }),

async emitMetaEventInternal(eventName, eventArgs) {
assertEventName(eventName);
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');

@@ -258,4 +240,5 @@ }

const listeners = this.getListeners(eventName) ?? new Set();
const filteredListeners = [...listeners.values()].map((info) => info.listener);
const anyListeners = assertEx(Events.anyMap.get(this));
const staticListeners = [...listeners];
const staticListeners = [...filteredListeners];
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners];

@@ -265,9 +248,7 @@ await resolvedPromise;

...staticListeners.map(async (listener) => {
if (listeners.has(listener)) {
return await listener(eventArgs);
}
await this.safeCallListener(eventName, eventArgs, listener);
}),
...staticAnyListeners.map(async (listener) => {
if (anyListeners.has(listener)) {
return await listener(eventName, eventArgs);
await this.safeCallAnyListener(eventName, eventArgs, listener);
}

@@ -277,3 +258,28 @@ }),

}
getListeners(eventName) {
const events = assertEx(Events.eventsMap.get(this));
if (!events.has(eventName)) {
return;
}
return events.get(eventName);
}
async safeCallAnyListener(eventName, eventArgs, listener) {
try {
return await listener(eventName, eventArgs);
}
catch (ex) {
const error = ex;
this.logger?.error(`Listener[${String(eventName)}] Excepted: ${error.message}`);
}
}
async safeCallListener(eventName, eventArgs, listener) {
try {
return await listener(eventArgs);
}
catch (ex) {
const error = ex;
this.logger?.error(`Listener[${String(eventName)}] Excepted: ${error.message}`);
}
}
}
//# sourceMappingURL=Events.js.map

@@ -0,1 +1,2 @@

import { Base, BaseParams } from '@xyo-network/core';
import { EventAnyListener, EventArgs, EventData, EventFunctions, EventListener, EventName } from '../model';

@@ -9,17 +10,15 @@ /**

*/
export type DebugLogger<TEventData extends EventData, TName extends keyof TEventData> = (type: string, debugName: string, eventName?: TName, eventData?: TEventData[TName]) => void;
export type DebugLogger = (type: string, debugName: string, eventName?: EventName, eventData?: EventArgs) => void;
type EventListenerInfo<TEventArgs extends EventArgs = EventArgs> = {
filter?: TEventArgs;
listener: EventListener<TEventArgs>;
};
/**
Configure debug options of an instance.
*/
export type DebugOptions<TEventData extends EventData> = {
export type DebugOptions = {
enabled?: boolean;
logger?: DebugLogger<TEventData, keyof TEventData>;
logger?: DebugLogger;
readonly name: string;
};
/**
Configuration options for Emittery.
*/
export type Options<TEventData extends EventData> = {
readonly debug?: DebugOptions<TEventData>;
};
export type MetaEventData<TEventData extends EventData> = {

@@ -35,10 +34,15 @@ listenerAdded: {

};
export declare class Events<TEventData extends EventData = EventData> implements EventFunctions<TEventData> {
static anyMap: WeakMap<object, Set<EventAnyListener<EventArgs>>>;
static eventsMap: WeakMap<object, Map<PropertyKey, Set<EventListener<EventArgs>>>>;
debug?: DebugOptions<any>;
export type EventsParams = BaseParams<{
readonly debug?: DebugOptions;
}>;
export declare class Events<TEventData extends EventData = EventData> extends Base<EventsParams> implements EventFunctions<TEventData> {
protected static anyMap: WeakMap<object, Set<EventAnyListener<EventArgs>>>;
protected static eventsMap: WeakMap<object, Map<PropertyKey, Set<EventListenerInfo<EventArgs>>>>;
private static canEmitMetaEvents;
private static isGlobalDebugEnabled;
eventData: TEventData;
constructor(options?: Options<TEventData>);
constructor(params?: EventsParams);
static get isDebugEnabled(): boolean;
static set isDebugEnabled(newValue: boolean);
get debug(): DebugOptions | undefined;
clearListeners(eventNames: keyof TEventData | (keyof TEventData)[]): void;

@@ -48,8 +52,7 @@ emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>;

emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>;
getListeners(eventName: keyof TEventData): Set<EventListener<EventArgs>> | undefined;
listenerCount(eventNames: keyof TEventData | (keyof TEventData)[]): number;
logIfDebugEnabled<TEventName extends EventName, TEventArgs extends EventArgs>(type: string, eventName?: TEventName, eventArgs?: TEventArgs): void;
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): void;
listenerCount(eventNames?: keyof TEventData | (keyof TEventData)[]): number;
logIfDebugEnabled<TEventName extends EventName>(type: string, eventName?: TEventName, eventArgs?: EventArgs): void;
off<TEventName extends keyof TEventData, TEventListener = EventListener<TEventData[TEventName]>>(eventNames: TEventName | TEventName[], listener: TEventListener): void;
offAny(listener: EventAnyListener): void;
on<TEventName extends keyof TEventData = keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): () => void;
on<TEventName extends keyof TEventData = keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>, filter?: TEventData[TEventName]): () => void;
onAny(listener: EventAnyListener): () => void;

@@ -59,3 +62,7 @@ once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>): () => void;

private emitMetaEventInternal;
private getListeners;
private safeCallAnyListener;
private safeCallListener;
}
export {};
//# sourceMappingURL=Events.d.ts.map

@@ -15,3 +15,4 @@ {

"@xylabs/forget": "^2.7.4",
"@xyo-network/promise": "^2.53.3"
"@xyo-network/core": "^2.53.4",
"@xyo-network/promise": "^2.53.4"
},

@@ -57,3 +58,3 @@ "devDependencies": {

"types": "dist/types/index.d.ts",
"version": "2.53.3"
"version": "2.53.4"
}
import { assertEx } from '@xylabs/assert'
import { forget } from '@xylabs/forget'
import { Base, BaseParams } from '@xyo-network/core'

@@ -13,25 +14,18 @@ import { EventAnyListener, EventArgs, EventData, EventFunctions, EventListener, EventName } from '../model'

*/
export type DebugLogger<TEventData extends EventData, TName extends keyof TEventData> = (
type: string,
debugName: string,
eventName?: TName,
eventData?: TEventData[TName],
) => void
export type DebugLogger = (type: string, debugName: string, eventName?: EventName, eventData?: EventArgs) => void
type EventListenerInfo<TEventArgs extends EventArgs = EventArgs> = {
filter?: TEventArgs
listener: EventListener<TEventArgs>
}
/**
Configure debug options of an instance.
*/
export type DebugOptions<TEventData extends EventData> = {
export type DebugOptions = {
enabled?: boolean
logger?: DebugLogger<TEventData, keyof TEventData>
logger?: DebugLogger
readonly name: string
}
/**
Configuration options for Emittery.
*/
export type Options<TEventData extends EventData> = {
readonly debug?: DebugOptions<TEventData>
}
const resolvedPromise = Promise.resolve()

@@ -50,45 +44,25 @@

let canEmitMetaEvents = false
let isGlobalDebugEnabled = false
const isMetaEvent = (eventName: EventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved'
function assertEventName(eventName: EventName) {
if (typeof eventName !== 'string' && typeof eventName !== 'symbol' && typeof eventName !== 'number') {
throw new TypeError('`eventName` must be a string, symbol, or number')
}
}
export type EventsParams = BaseParams<{ readonly debug?: DebugOptions }>
function assertListener(listener: object) {
if (typeof listener !== 'function') {
throw new TypeError('listener must be a function')
}
}
export class Events<TEventData extends EventData = EventData> extends Base<EventsParams> implements EventFunctions<TEventData> {
protected static anyMap = new WeakMap<object, Set<EventAnyListener>>()
protected static eventsMap = new WeakMap<object, Map<EventName, Set<EventListenerInfo>>>()
const isMetaEvent = (eventName: EventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved'
private static canEmitMetaEvents = false
private static isGlobalDebugEnabled = false
export class Events<TEventData extends EventData = EventData> implements EventFunctions<TEventData> {
static anyMap = new WeakMap<object, Set<EventAnyListener>>()
static eventsMap = new WeakMap<object, Map<EventName, Set<EventListener>>>()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
debug?: DebugOptions<any>
//this is here to be able to query the type, not use
eventData = {} as TEventData
constructor(options: Options<TEventData> = {}) {
Events.anyMap.set(this, new Set<EventAnyListener>())
Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListener>>())
this.debug = options.debug
if (this.debug) {
this.debug.enabled = !!this.debug.enabled
this.debug.logger =
this.debug.logger ??
((type: string, debugName: string, eventName?: keyof TEventData, eventData?: TEventData[keyof TEventData]) => {
constructor(params: EventsParams = {}) {
const mutatedParams = { ...params }
if (mutatedParams.debug) {
mutatedParams.debug.logger =
mutatedParams.debug.logger ??
((type: string, debugName: string, eventName?: EventName, eventData?: EventArgs) => {
let eventDataString: string
let eventNameString: string | undefined
try {
// TODO: Use https://github.com/sindresorhus/safe-stringify when the package is more mature. Just copy-paste the code.
eventDataString = JSON.stringify(eventData)

@@ -107,5 +81,8 @@ } catch {

const logTime = `${currentTime.getHours()}:${currentTime.getMinutes()}:${currentTime.getSeconds()}.${currentTime.getMilliseconds()}`
console.log(`[${logTime}][events:${type}][${debugName}] Event Name: ${eventNameString}\n\tdata: ${eventDataString}`)
this.logger.log(`[${logTime}][events:${type}][${debugName}] Event Name: ${eventNameString}\n\tdata: ${eventDataString}`)
})
}
super(mutatedParams)
Events.anyMap.set(this, new Set<EventAnyListener>())
Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListenerInfo>>())
}

@@ -118,13 +95,17 @@

if (typeof globalThis.process?.env !== 'object') {
return isGlobalDebugEnabled
return Events.isGlobalDebugEnabled
}
const { env } = globalThis.process ?? { env: {} }
return env.DEBUG === 'emittery' || env.DEBUG === '*' || isGlobalDebugEnabled
return env.DEBUG === 'events' || env.DEBUG === '*' || Events.isGlobalDebugEnabled
}
static set isDebugEnabled(newValue) {
isGlobalDebugEnabled = newValue
Events.isGlobalDebugEnabled = newValue
}
get debug() {
return this.params.debug
}
clearListeners(eventNames: keyof TEventData | (keyof TEventData)[]) {

@@ -159,6 +140,6 @@ const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames]

try {
canEmitMetaEvents = true
Events.canEmitMetaEvents = true
await this.emitMetaEventInternal(eventName, eventArgs)
} finally {
canEmitMetaEvents = false
Events.canEmitMetaEvents = false
}

@@ -169,13 +150,26 @@ }

async emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]) {
assertEventName(eventName)
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')
}
const filterMatch = (args: TEventData[TEventName], filter: TEventData[TEventName]) => {
if (filter) {
switch (typeof filter) {
case 'object':
return Object.entries(args).reduce((prev, [key, value]) => ((filter as Record<PropertyKey, unknown>)[key] === value ? true : prev), false)
default:
return args === filter
}
}
return true
}
this.logIfDebugEnabled('emitSerial', eventName, eventArgs)
const listeners = this.getListeners(eventName) ?? new Set()
const filteredListeners = [...listeners.values()]
.filter((value) => (value.filter ? filterMatch(eventArgs, value.filter as TEventData[TEventName]) : true))
.map((info) => info.listener)
const anyListeners = assertEx(Events.anyMap.get(this))
const staticListeners = [...listeners]
const staticListeners = [...filteredListeners]
const staticAnyListeners = [...anyListeners]

@@ -186,24 +180,12 @@

for (const listener of staticListeners) {
if (listeners.has(listener)) {
await listener(eventArgs)
}
await this.safeCallListener(eventName, eventArgs, listener)
}
for (const listener of staticAnyListeners) {
if (anyListeners.has(listener)) {
await listener(eventName, eventArgs)
}
await this.safeCallAnyListener(eventName, eventArgs, listener)
}
}
getListeners(eventName: keyof TEventData) {
const events = assertEx(Events.eventsMap.get(this))
if (!events.has(eventName)) {
return
}
return events.get(eventName)
}
listenerCount(eventNames: keyof TEventData | (keyof TEventData)[]) {
//TODO: Make test for this
listenerCount(eventNames?: keyof TEventData | (keyof TEventData)[]) {
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames]

@@ -219,6 +201,2 @@ let count = 0

if (typeof eventName !== 'undefined') {
assertEventName(eventName)
}
count += assertEx(Events.anyMap.get(this)).size

@@ -234,3 +212,3 @@

logIfDebugEnabled<TEventName extends EventName, TEventArgs extends EventArgs>(type: string, eventName?: TEventName, eventArgs?: TEventArgs) {
logIfDebugEnabled<TEventName extends EventName>(type: string, eventName?: TEventName, eventArgs?: EventArgs) {
if (Events.isDebugEnabled || this.debug?.enabled) {

@@ -241,9 +219,9 @@ this.debug?.logger?.(type, this.debug.name, eventName, eventArgs)

off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>) {
assertListener(listener)
off<TEventName extends keyof TEventData, TEventListener = EventListener<TEventData[TEventName]>>(
eventNames: TEventName | TEventName[],
listener: TEventListener,
) {
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames]
for (const eventName of eventNamesArray) {
assertEventName(eventName)
const set = this.getListeners(eventName) as Set<EventListener<TEventData[TEventName]>>
const set = this.getListeners(eventName) as Set<TEventListener>
if (set) {

@@ -266,4 +244,2 @@ set.delete(listener)

offAny(listener: EventAnyListener) {
assertListener(listener)
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined)

@@ -276,8 +252,9 @@

on<TEventName extends keyof TEventData = keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>) {
assertListener(listener)
on<TEventName extends keyof TEventData = keyof TEventData>(
eventNames: TEventName | TEventName[],
listener: EventListener<TEventData[TEventName]>,
filter?: TEventData[TEventName],
) {
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames]
for (const eventName of eventNamesArray) {
assertEventName(eventName)
let set = this.getListeners(eventName)

@@ -290,3 +267,3 @@ if (!set) {

set.add(listener as EventListener)
set.add({ filter, listener: listener as EventListener })

@@ -304,4 +281,2 @@ this.logIfDebugEnabled('subscribe', eventName, undefined)

onAny(listener: EventAnyListener) {
assertListener(listener)
this.logIfDebugEnabled('subscribeAny', undefined, undefined)

@@ -317,3 +292,3 @@

this.off(eventName, subListener)
await listener(args)
await this.safeCallListener(eventName, args, listener)
}

@@ -327,6 +302,5 @@ this.on(eventName, subListener)

eventArgs: TEventArgs,
filter?: TEventArgs,
) {
assertEventName(eventName)
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')

@@ -338,4 +312,5 @@ }

const listeners = this.getListeners(eventName) ?? new Set()
const filteredListeners = [...listeners.values()].filter((value) => (filter ? value.listener : true)).map((info) => info.listener)
const anyListeners = assertEx(Events.anyMap.get(this))
const staticListeners = [...listeners]
const staticListeners = [...filteredListeners]
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]

@@ -346,9 +321,7 @@

...staticListeners.map(async (listener) => {
if (listeners.has(listener)) {
return await listener(eventArgs)
}
await this.safeCallListener(eventName, eventArgs, listener)
}),
...staticAnyListeners.map(async (listener) => {
if (anyListeners.has(listener)) {
return await listener(eventName, eventArgs)
await this.safeCallAnyListener(eventName, eventArgs, listener)
}

@@ -363,5 +336,3 @@ }),

) {
assertEventName(eventName)
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
if (isMetaEvent(eventName) && !Events.canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')

@@ -373,4 +344,5 @@ }

const listeners = this.getListeners(eventName) ?? new Set()
const filteredListeners = [...listeners.values()].map((info) => info.listener)
const anyListeners = assertEx(Events.anyMap.get(this))
const staticListeners = [...listeners]
const staticListeners = [...filteredListeners]
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]

@@ -381,9 +353,7 @@

...staticListeners.map(async (listener) => {
if (listeners.has(listener)) {
return await listener(eventArgs)
}
await this.safeCallListener(eventName, eventArgs, listener)
}),
...staticAnyListeners.map(async (listener) => {
if (anyListeners.has(listener)) {
return await listener(eventName, eventArgs)
await this.safeCallAnyListener(eventName, eventArgs, listener)
}

@@ -393,2 +363,37 @@ }),

}
private getListeners<TEventName extends keyof TEventData>(eventName: TEventName) {
const events = assertEx(Events.eventsMap.get(this))
if (!events.has(eventName)) {
return
}
return events.get(eventName)
}
private async safeCallAnyListener<TEventData extends EventData, TEventName extends keyof EventData>(
eventName: TEventName,
eventArgs: TEventData[TEventName],
listener: EventAnyListener<TEventData[TEventName]>,
) {
try {
return await listener(eventName, eventArgs)
} catch (ex) {
const error = ex as Error
this.logger?.error(`Listener[${String(eventName)}] Excepted: ${error.message}`)
}
}
private async safeCallListener<TEventData extends EventData, TEventName extends keyof EventData>(
eventName: TEventName,
eventArgs: TEventData[TEventName],
listener: EventListener<TEventData[TEventName]>,
) {
try {
return await listener(eventArgs)
} catch (ex) {
const error = ex as Error
this.logger?.error(`Listener[${String(eventName)}] Excepted: ${error.message}`)
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc