@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
144 lines • 4.3 kB
JavaScript
import { uuidv7 } from "../utils/uuid";
function deepCloneAndFreeze(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (Array.isArray(obj)) {
const cloned = obj.map((item) => deepCloneAndFreeze(item));
return Object.freeze(cloned);
}
const cloned = {};
for (const key of Object.keys(obj)) {
cloned[key] = deepCloneAndFreeze(obj[key]);
}
return Object.freeze(cloned);
}
export class EventDispatcher {
handlers = [];
streamId;
_context;
highPerformance;
batchSize;
batchFlushMs;
eventBatch = [];
batchTimeout = null;
constructor(contextOrConfig = {}) {
this.streamId = uuidv7();
const isConfig = "highPerformance" in contextOrConfig ||
"batchSize" in contextOrConfig ||
"batchFlushMs" in contextOrConfig ||
"context" in contextOrConfig;
if (isConfig) {
const config = contextOrConfig;
this.highPerformance = config.highPerformance ?? false;
this.batchSize = config.batchSize ?? 10;
this.batchFlushMs = config.batchFlushMs ?? 5;
this._context = this.highPerformance
? Object.freeze(config.context ?? {})
: deepCloneAndFreeze(config.context ?? {});
}
else {
this.highPerformance = false;
this.batchSize = 10;
this.batchFlushMs = 5;
this._context = deepCloneAndFreeze(contextOrConfig);
}
}
onEvent(handler) {
this.handlers.push(handler);
}
offEvent(handler) {
const index = this.handlers.indexOf(handler);
if (index !== -1) {
this.handlers.splice(index, 1);
}
}
flush() {
if (this.batchTimeout) {
clearTimeout(this.batchTimeout);
this.batchTimeout = null;
}
if (this.eventBatch.length === 0)
return;
const batch = this.eventBatch;
this.eventBatch = [];
for (const event of batch) {
this.dispatchToHandlers(event);
}
}
dispatchToHandlers(event) {
for (const handler of [...this.handlers]) {
queueMicrotask(() => {
try {
const result = handler(event);
if (result && typeof result === "object" && "catch" in result) {
result.catch(() => {
});
}
}
catch {
}
});
}
}
emit(type, payload) {
if (this.handlers.length === 0)
return;
const event = {
type,
ts: Date.now(),
streamId: this.streamId,
context: this._context,
...payload,
};
if (this.highPerformance && this.batchSize > 1) {
this.eventBatch.push(event);
if (this.eventBatch.length >= this.batchSize) {
this.flush();
}
else if (!this.batchTimeout) {
this.batchTimeout = setTimeout(() => {
this.batchTimeout = null;
this.flush();
}, this.batchFlushMs);
}
return;
}
this.dispatchToHandlers(event);
}
emitSync(type, payload) {
if (this.handlers.length === 0)
return;
const event = {
type,
ts: Date.now(),
streamId: this.streamId,
context: this._context,
...payload,
};
for (const handler of [...this.handlers]) {
try {
const result = handler(event);
if (result && typeof result === "object" && "catch" in result) {
result.catch(() => {
});
}
}
catch {
}
}
}
getStreamId() {
return this.streamId;
}
getContext() {
return this._context;
}
getHandlerCount() {
return this.handlers.length;
}
}
export function createEventDispatcher(context = {}) {
return new EventDispatcher(context);
}
//# sourceMappingURL=event-dispatcher.js.map