
Security News
Free Certified Patch for Critical Rails Active Storage Vulnerability
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.
Tiny event emitter with strict TypeScript types, wildcard namespaces, and optional schema validation.
all, listener snapshots, predictable order)npm install eventify
import { createEmitter } from "eventify";
const emitter = createEmitter();
emitter.on("alert", (message) => {
console.log(message);
});
emitter.trigger("alert", "hello");
import { decorateWithEvents } from "eventify";
const target = decorateWithEvents({ name: "service" });
type Events = {
ready: void;
"change:title": string;
data: [string, number];
};
const emitter = createEmitter<Events>();
emitter.on("data", (name, count) => {
console.log(name, count);
});
emitter.trigger("data", "hello", 42);
emitter.on({
"change:title": () => console.log("title"),
"change:author": () => console.log("author"),
});
emitter.on("open close", () => console.log("toggled"));
Event names are split by namespaceDelimiter (default /). The wildcard token (default *) matches segments.
* in the middle matches one segment* matches remaining segments* alone matches any event (use "all" if you need the event name)const emitter = createEmitter({
namespaceDelimiter: "/",
wildcard: "*",
});
emitter.on("/product/foo/org/123/user/56/*", () => {
console.log("any account for that user");
});
emitter.on("/product/foo/org/123/*", () => {
console.log("any user in org 123");
});
emitter.on("/product/foo/*", () => {
console.log("any org in product foo");
});
emitter.trigger("/product/foo/org/123/user/56/account/abcd");
Middle-segment wildcards:
emitter.on("/product/foo/org/*/tracked-object/*/assesment", () => {
console.log("any tracked-object assesment within an org");
});
Colon namespaces:
const emitter = createEmitter({
namespaceDelimiter: ":",
wildcard: "*",
});
emitter.on("namespace:foo:*", () => {
console.log("any sub-event in namespace:foo");
});
Any schema with parse or safeParse works. Zod is supported via DI.
import { z } from "zod";
import { createEmitter, setDefaultSchemaValidator } from "eventify";
const schemas = {
data: z.tuple([z.string(), z.number()]),
ready: z.undefined(),
};
const emitter = createEmitter({
schemas,
validate: setDefaultSchemaValidator,
});
emitter.on("data", (name, count) => {
console.log(name, count);
});
emitter.trigger("data", "hello", 1);
Validation runs on trigger/emit/produce. If validation fails, the call throws and no listeners run.
Listener failures never crash by default. Errors are routed to onError.
const emitter = createEmitter({
onError: (error, meta) => {
console.error(meta.event, error);
},
});
emitter.on("boom", () => {
throw new Error("nope");
});
emitter.trigger("boom");
createEmitter and decorateWithEvents expose addEventListener, removeEventListener, and dispatchEvent.
trigger/emit/produce dispatch a CustomEvent with the payload in event.detail.
dispatchEvent only uses the EventTarget path (and matching on listeners). It does not run schemas, patterns, or "all".
detail is the single payload for 1-arg events, an array for multi-arg events, and undefined for no-arg events.
const emitter = createEmitter();
const iterator = emitter.iterate("data");
emitter.trigger("data", "a", 1);
const { value } = await iterator.next();
// value -> ["a", 1]
Iterate all events:
const all = emitter.iterate("all");
emitter.trigger("ready");
const { value } = await all.next();
// value -> ["ready"]
Abort with an AbortSignal:
const controller = new AbortController();
const iterator = emitter.iterate("data", { signal: controller.signal });
controller.abort();
for await with abort:
const controller = new AbortController();
(async () => {
for await (const value of emitter.iterate("data", {
signal: controller.signal,
})) {
console.log(value);
controller.abort();
}
})();
trigger/emit/produce throws and no listeners run (including wildcard and all).onError and do not stop other listeners.TypeError that is routed to onError.onError failures: errors thrown by the handler are swallowed to avoid crashing producers.iterate backpressure: if producers emit faster than you consume, the iterator queue grows. Use AbortSignal, return(), or stop iteration.listenTo/listenToOnce: the target must be an Eventify emitter (or another object with compatible on/once/off).Constraint tools:
schemas + validate enforce data shape at emit time.once / listenToOnce.off / stopListening / iterate + AbortSignal.namespaceDelimiter + wildcard.onError centralizes listener failures."all".context defaults to the emitter."all" is a compatibility feature (Backbone/Eventify style); it is not a standard EventTarget concept.createEmitter([options]);
decorateWithEvents([target], [options]);
setDefaultSchemaValidator(schema, payload, meta);
createEmitter returns a standalone emitter. decorateWithEvents mixes Eventify methods into an existing object.
setDefaultSchemaValidator is the default validator function (no global mutation).
Eventify.create([options]);
Eventify.enable([target], [options]);
Eventify.defaultSchemaValidator;
Eventify.version;
Eventify.proto;
The Eventify default export remains for compatibility.
type EventifyOptions = {
schemas?: Record<string, SchemaLike>;
validate?: SchemaValidator;
onError?: (
error: unknown,
meta: {
event: string;
args: unknown[];
listener?: (...args: unknown[]) => unknown;
emitter: object;
},
) => void;
namespaceDelimiter?: string; // default "/"
wildcard?: string; // default "*"
};
on(event, callback, [context])
on({ event: callback, ... }, [context])
on("a b c", callback, [context])
once(event, callback, [context])
once({ event: callback, ... }, [context])
once("a b c", callback, [context])
off()
off(event, [callback], [context])
off({ event: callback, ... }, [context])
trigger(event, ...args);
emit(event, ...args);
produce(event, ...args);
emit and produce are aliases of trigger.
addEventListener(type, listener, [options]);
removeEventListener(type, listener, [options]);
dispatchEvent(event);
listenTo(other, event, callback)
listenTo(other, { event: callback, ... })
listenToOnce(other, event, callback)
listenToOnce(other, { event: callback, ... })
stopListening([other], [event], [callback]);
iterate(event, [options]);
For "all", each value is [eventName, ...args]. For other events, a single argument is yielded as a value; multiple arguments are yielded as an array.
EventMap;
EventName;
EventHandler;
EventHandlerMap;
SchemaLike;
SchemaMap;
SchemaValidator;
EventsFromSchemas;
BENCHMARKS.mdCHANGELOG.mdbun install
bun run format
bun test --coverage
bun run build:all
bunx playwright install --with-deps chromium
bun run test:browser
bun run test:all
bun run ci:local
bun run publish
ci:local requires act installed locally.
MIT
FAQs
Tiny event emitter with strict TypeScript typings and optional schema validation.
The npm package eventify receives a total of 0 weekly downloads. As such, eventify popularity was classified as not popular.
We found that eventify demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.

Security News
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.

Security News
/Threat Research
A malicious Ruby gem runs a credential-stealing worm during installation, poisons AI coding tools, and can wipe files when a stolen GitHub token is revoked.

Security News
GitHub is tightening GitHub Actions security with new restrictions on privileged pull request workflows. Here's what changes and how maintainers are affected.