abxbus 2.4.24 → 2.4.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/BaseEvent.d.ts +211 -0
- package/dist/cjs/{base_event.js → BaseEvent.js} +23 -23
- package/dist/cjs/BaseEvent.js.map +7 -0
- package/dist/cjs/EventBridge.d.ts +34 -0
- package/dist/cjs/EventBridge.js +295 -0
- package/dist/cjs/EventBridge.js.map +7 -0
- package/dist/cjs/EventBus.d.ts +125 -0
- package/dist/cjs/{event_bus.js → EventBus.js} +21 -21
- package/dist/cjs/EventBus.js.map +7 -0
- package/dist/cjs/EventBusMiddleware.d.ts +13 -0
- package/dist/cjs/EventBusMiddleware.js +17 -0
- package/dist/cjs/EventBusMiddleware.js.map +7 -0
- package/dist/cjs/EventHandler.d.ts +140 -0
- package/dist/cjs/{event_handler.js → EventHandler.js} +4 -4
- package/dist/cjs/EventHandler.js.map +7 -0
- package/dist/cjs/EventHistory.d.ts +45 -0
- package/dist/cjs/{event_history.js → EventHistory.js} +4 -4
- package/dist/cjs/EventHistory.js.map +7 -0
- package/dist/cjs/EventResult.d.ts +86 -0
- package/dist/cjs/{event_result.js → EventResult.js} +18 -16
- package/dist/cjs/EventResult.js.map +7 -0
- package/dist/cjs/HTTPEventBridge.d.ts +10 -0
- package/dist/cjs/HTTPEventBridge.js +37 -0
- package/dist/cjs/HTTPEventBridge.js.map +7 -0
- package/dist/cjs/JSONLEventBridge.d.ts +26 -0
- package/dist/cjs/{bridge_jsonl.js → JSONLEventBridge.js} +8 -8
- package/dist/cjs/JSONLEventBridge.js.map +7 -0
- package/dist/cjs/LockManager.d.ts +70 -0
- package/dist/cjs/{lock_manager.js → LockManager.js} +4 -4
- package/dist/cjs/LockManager.js.map +7 -0
- package/dist/cjs/NATSEventBridge.d.ts +20 -0
- package/dist/cjs/{bridge_nats.js → NATSEventBridge.js} +8 -8
- package/dist/cjs/NATSEventBridge.js.map +7 -0
- package/dist/cjs/OtelTracingMiddleware.d.ts +49 -0
- package/dist/cjs/{middleware_otel_tracing.js → OtelTracingMiddleware.js} +49 -26
- package/dist/cjs/OtelTracingMiddleware.js.map +7 -0
- package/dist/cjs/PostgresEventBridge.d.ts +31 -0
- package/dist/cjs/{bridge_postgres.js → PostgresEventBridge.js} +8 -8
- package/dist/cjs/PostgresEventBridge.js.map +7 -0
- package/dist/cjs/RedisEventBridge.d.ts +34 -0
- package/dist/cjs/{bridge_redis.js → RedisEventBridge.js} +8 -8
- package/dist/cjs/RedisEventBridge.js.map +7 -0
- package/dist/cjs/SQLiteEventBridge.d.ts +30 -0
- package/dist/cjs/{bridge_sqlite.js → SQLiteEventBridge.js} +8 -8
- package/dist/cjs/SQLiteEventBridge.js.map +7 -0
- package/dist/cjs/SocketEventBridge.d.ts +4 -0
- package/dist/cjs/SocketEventBridge.js +35 -0
- package/dist/cjs/SocketEventBridge.js.map +7 -0
- package/dist/cjs/bridge_ipc.d.ts +45 -0
- package/dist/cjs/bridges.d.ts +9 -49
- package/dist/cjs/bridges.js +16 -303
- package/dist/cjs/bridges.js.map +2 -2
- package/dist/cjs/events_suck.d.ts +2 -2
- package/dist/cjs/events_suck.js +4 -4
- package/dist/cjs/events_suck.js.map +2 -2
- package/dist/cjs/index.d.ts +15 -14
- package/dist/cjs/index.js +24 -24
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/logging.d.ts +2 -2
- package/dist/cjs/logging.js +7 -7
- package/dist/cjs/logging.js.map +2 -2
- package/dist/cjs/middleware_otel_tracing.d.ts +2 -2
- package/dist/cjs/middlewares.d.ts +1 -13
- package/dist/cjs/middlewares.js.map +1 -1
- package/dist/cjs/types.d.ts +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/{base_event.js → BaseEvent.js} +4 -4
- package/dist/esm/BaseEvent.js.map +7 -0
- package/dist/esm/EventBridge.js +275 -0
- package/dist/esm/EventBridge.js.map +7 -0
- package/dist/esm/{event_bus.js → EventBus.js} +5 -5
- package/dist/esm/EventBus.js.map +7 -0
- package/dist/esm/EventBusMiddleware.js +1 -0
- package/dist/esm/EventBusMiddleware.js.map +7 -0
- package/dist/esm/{event_handler.js → EventHandler.js} +1 -1
- package/dist/esm/EventHandler.js.map +7 -0
- package/dist/esm/{event_history.js → EventHistory.js} +1 -1
- package/dist/esm/EventHistory.js.map +7 -0
- package/dist/esm/{event_result.js → EventResult.js} +7 -5
- package/dist/esm/EventResult.js.map +7 -0
- package/dist/esm/HTTPEventBridge.js +17 -0
- package/dist/esm/HTTPEventBridge.js.map +7 -0
- package/dist/esm/{bridge_jsonl.js → JSONLEventBridge.js} +3 -3
- package/dist/esm/JSONLEventBridge.js.map +7 -0
- package/dist/esm/{lock_manager.js → LockManager.js} +1 -1
- package/dist/esm/LockManager.js.map +7 -0
- package/dist/esm/{bridge_nats.js → NATSEventBridge.js} +3 -3
- package/dist/esm/NATSEventBridge.js.map +7 -0
- package/dist/esm/{middleware_otel_tracing.js → OtelTracingMiddleware.js} +47 -24
- package/dist/esm/OtelTracingMiddleware.js.map +7 -0
- package/dist/esm/{bridge_postgres.js → PostgresEventBridge.js} +3 -3
- package/dist/esm/PostgresEventBridge.js.map +7 -0
- package/dist/esm/{bridge_redis.js → RedisEventBridge.js} +3 -3
- package/dist/esm/RedisEventBridge.js.map +7 -0
- package/dist/esm/{bridge_sqlite.js → SQLiteEventBridge.js} +3 -3
- package/dist/esm/SQLiteEventBridge.js.map +7 -0
- package/dist/esm/SocketEventBridge.js +15 -0
- package/dist/esm/SocketEventBridge.js.map +7 -0
- package/dist/esm/bridges.js +9 -296
- package/dist/esm/bridges.js.map +2 -2
- package/dist/esm/events_suck.js +2 -2
- package/dist/esm/events_suck.js.map +1 -1
- package/dist/esm/index.js +11 -19
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/logging.js +2 -2
- package/dist/esm/logging.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/types/BaseEvent.d.ts +211 -0
- package/dist/types/EventBridge.d.ts +34 -0
- package/dist/types/EventBus.d.ts +125 -0
- package/dist/types/EventBusMiddleware.d.ts +13 -0
- package/dist/types/EventHandler.d.ts +140 -0
- package/dist/types/EventHistory.d.ts +45 -0
- package/dist/types/EventResult.d.ts +86 -0
- package/dist/types/HTTPEventBridge.d.ts +10 -0
- package/dist/types/JSONLEventBridge.d.ts +26 -0
- package/dist/types/LockManager.d.ts +70 -0
- package/dist/types/NATSEventBridge.d.ts +20 -0
- package/dist/types/OtelTracingMiddleware.d.ts +49 -0
- package/dist/types/PostgresEventBridge.d.ts +31 -0
- package/dist/types/RedisEventBridge.d.ts +34 -0
- package/dist/types/SQLiteEventBridge.d.ts +30 -0
- package/dist/types/SocketEventBridge.d.ts +4 -0
- package/dist/types/bridge_ipc.d.ts +45 -0
- package/dist/types/bridges.d.ts +9 -49
- package/dist/types/events_suck.d.ts +2 -2
- package/dist/types/index.d.ts +15 -14
- package/dist/types/logging.d.ts +2 -2
- package/dist/types/middleware_otel_tracing.d.ts +2 -2
- package/dist/types/middlewares.d.ts +1 -13
- package/dist/types/types.d.ts +1 -1
- package/package.json +52 -10
- package/src/{base_event.ts → BaseEvent.ts} +5 -5
- package/src/EventBridge.ts +332 -0
- package/src/{event_bus.ts → EventBus.ts} +6 -6
- package/src/EventBusMiddleware.ts +16 -0
- package/src/{event_handler.ts → EventHandler.ts} +2 -2
- package/src/{event_history.ts → EventHistory.ts} +1 -1
- package/src/{event_result.ts → EventResult.ts} +8 -6
- package/src/HTTPEventBridge.ts +27 -0
- package/src/{bridge_jsonl.ts → JSONLEventBridge.ts} +2 -2
- package/src/{lock_manager.ts → LockManager.ts} +2 -2
- package/src/{bridge_nats.ts → NATSEventBridge.ts} +2 -2
- package/src/{middleware_otel_tracing.ts → OtelTracingMiddleware.ts} +55 -26
- package/src/{bridge_postgres.ts → PostgresEventBridge.ts} +2 -2
- package/src/{bridge_redis.ts → RedisEventBridge.ts} +2 -2
- package/src/{bridge_sqlite.ts → SQLiteEventBridge.ts} +2 -2
- package/src/SocketEventBridge.ts +13 -0
- package/src/bridges.ts +9 -376
- package/src/events_suck.ts +2 -2
- package/src/index.ts +15 -22
- package/src/logging.ts +3 -3
- package/src/middlewares.ts +1 -16
- package/src/types.ts +1 -1
- package/dist/cjs/base_event.js.map +0 -7
- package/dist/cjs/bridge_jsonl.js.map +0 -7
- package/dist/cjs/bridge_nats.js.map +0 -7
- package/dist/cjs/bridge_postgres.js.map +0 -7
- package/dist/cjs/bridge_redis.js.map +0 -7
- package/dist/cjs/bridge_sqlite.js.map +0 -7
- package/dist/cjs/event_bus.js.map +0 -7
- package/dist/cjs/event_handler.js.map +0 -7
- package/dist/cjs/event_history.js.map +0 -7
- package/dist/cjs/event_result.js.map +0 -7
- package/dist/cjs/lock_manager.js.map +0 -7
- package/dist/cjs/middleware_otel_tracing.js.map +0 -7
- package/dist/esm/base_event.js.map +0 -7
- package/dist/esm/bridge_jsonl.js.map +0 -7
- package/dist/esm/bridge_nats.js.map +0 -7
- package/dist/esm/bridge_postgres.js.map +0 -7
- package/dist/esm/bridge_redis.js.map +0 -7
- package/dist/esm/bridge_sqlite.js.map +0 -7
- package/dist/esm/event_bus.js.map +0 -7
- package/dist/esm/event_handler.js.map +0 -7
- package/dist/esm/event_history.js.map +0 -7
- package/dist/esm/event_result.js.map +0 -7
- package/dist/esm/lock_manager.js.map +0 -7
- package/dist/esm/middleware_otel_tracing.js.map +0 -7
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var EventBridge_exports = {};
|
|
20
|
+
__export(EventBridge_exports, {
|
|
21
|
+
EventBridge: () => EventBridge,
|
|
22
|
+
parseEndpoint: () => parseEndpoint,
|
|
23
|
+
randomSuffix: () => randomSuffix
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(EventBridge_exports);
|
|
26
|
+
var import_BaseEvent = require("./BaseEvent.js");
|
|
27
|
+
var import_EventBus = require("./EventBus.js");
|
|
28
|
+
const isNodeRuntime = () => {
|
|
29
|
+
const maybe_process = globalThis.process;
|
|
30
|
+
return typeof maybe_process?.versions?.node === "string";
|
|
31
|
+
};
|
|
32
|
+
const isBrowserRuntime = () => !isNodeRuntime() && typeof globalThis.window !== "undefined";
|
|
33
|
+
const randomSuffix = () => Math.random().toString(36).slice(2, 10);
|
|
34
|
+
const UNIX_SOCKET_MAX_PATH_CHARS = 90;
|
|
35
|
+
const parseEndpoint = (raw_endpoint) => {
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = new URL(raw_endpoint);
|
|
39
|
+
} catch {
|
|
40
|
+
throw new Error(`Invalid endpoint URL: ${raw_endpoint}`);
|
|
41
|
+
}
|
|
42
|
+
const protocol = parsed.protocol.replace(/:$/, "").toLowerCase();
|
|
43
|
+
if (protocol !== "unix" && protocol !== "http" && protocol !== "https") {
|
|
44
|
+
throw new Error(`Unsupported endpoint scheme: ${raw_endpoint}`);
|
|
45
|
+
}
|
|
46
|
+
if (protocol === "unix") {
|
|
47
|
+
const socket_path = decodeURIComponent(parsed.pathname || "");
|
|
48
|
+
if (!socket_path) {
|
|
49
|
+
throw new Error(`Invalid unix endpoint (missing socket path): ${raw_endpoint}`);
|
|
50
|
+
}
|
|
51
|
+
const socket_path_len = new TextEncoder().encode(socket_path).length;
|
|
52
|
+
if (socket_path_len > UNIX_SOCKET_MAX_PATH_CHARS) {
|
|
53
|
+
throw new Error(`Unix socket path is too long (${socket_path_len} chars), max is ${UNIX_SOCKET_MAX_PATH_CHARS}: ${socket_path}`);
|
|
54
|
+
}
|
|
55
|
+
return { raw: raw_endpoint, scheme: "unix", path: socket_path };
|
|
56
|
+
}
|
|
57
|
+
if (!parsed.hostname) {
|
|
58
|
+
throw new Error(`Invalid HTTP endpoint (missing hostname): ${raw_endpoint}`);
|
|
59
|
+
}
|
|
60
|
+
const default_port = protocol === "https" ? 443 : 80;
|
|
61
|
+
return {
|
|
62
|
+
raw: raw_endpoint,
|
|
63
|
+
scheme: protocol,
|
|
64
|
+
host: parsed.hostname,
|
|
65
|
+
port: parsed.port ? Number(parsed.port) : default_port,
|
|
66
|
+
path: `${parsed.pathname || "/"}${parsed.search || ""}`
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const importNodeModule = async (specifier) => {
|
|
70
|
+
const dynamic_import = Function("module_name", "return import(module_name)");
|
|
71
|
+
return dynamic_import(specifier);
|
|
72
|
+
};
|
|
73
|
+
class EventBridge {
|
|
74
|
+
send_to;
|
|
75
|
+
listen_on;
|
|
76
|
+
name;
|
|
77
|
+
inbound_bus;
|
|
78
|
+
start_promise;
|
|
79
|
+
node_server;
|
|
80
|
+
constructor(send_to, listen_on, name) {
|
|
81
|
+
this.send_to = send_to ? parseEndpoint(send_to) : null;
|
|
82
|
+
this.listen_on = listen_on ? parseEndpoint(listen_on) : null;
|
|
83
|
+
this.name = name ?? `EventBridge_${randomSuffix()}`;
|
|
84
|
+
this.inbound_bus = new import_EventBus.EventBus(this.name, { max_history_size: 0 });
|
|
85
|
+
this.start_promise = null;
|
|
86
|
+
this.node_server = null;
|
|
87
|
+
if (this.listen_on && isBrowserRuntime()) {
|
|
88
|
+
throw new Error(`${this.constructor.name} listen_on is not supported in browser runtimes`);
|
|
89
|
+
}
|
|
90
|
+
this.dispatch = this.dispatch.bind(this);
|
|
91
|
+
this.emit = this.emit.bind(this);
|
|
92
|
+
this.on = this.on.bind(this);
|
|
93
|
+
}
|
|
94
|
+
on(event_pattern, handler) {
|
|
95
|
+
this.ensureListenerStarted();
|
|
96
|
+
if (typeof event_pattern === "string") {
|
|
97
|
+
this.inbound_bus.on(event_pattern, handler);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this.inbound_bus.on(event_pattern, handler);
|
|
101
|
+
}
|
|
102
|
+
async emit(event) {
|
|
103
|
+
if (!this.send_to) {
|
|
104
|
+
throw new Error(`${this.constructor.name}.emit() requires send_to`);
|
|
105
|
+
}
|
|
106
|
+
const payload = event.toJSON();
|
|
107
|
+
if (this.send_to.scheme === "unix") {
|
|
108
|
+
await this.sendUnix(this.send_to, payload);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
await this.sendHttp(this.send_to, payload);
|
|
112
|
+
}
|
|
113
|
+
async dispatch(event) {
|
|
114
|
+
return this.emit(event);
|
|
115
|
+
}
|
|
116
|
+
async start() {
|
|
117
|
+
if (!this.listen_on) return;
|
|
118
|
+
if (this.node_server) return;
|
|
119
|
+
if (this.start_promise) {
|
|
120
|
+
await this.start_promise;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (!isNodeRuntime()) {
|
|
124
|
+
throw new Error(`${this.constructor.name} listen_on is only supported in Node.js runtimes`);
|
|
125
|
+
}
|
|
126
|
+
const launch = (async () => {
|
|
127
|
+
const endpoint = this.listen_on;
|
|
128
|
+
if (!endpoint) return;
|
|
129
|
+
if (endpoint.scheme === "unix") {
|
|
130
|
+
await this.startUnixListener(endpoint);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (endpoint.scheme !== "http") {
|
|
134
|
+
throw new Error(`listen_on only supports unix:// or http:// endpoints, got: ${endpoint.raw}`);
|
|
135
|
+
}
|
|
136
|
+
await this.startHttpListener(endpoint);
|
|
137
|
+
})();
|
|
138
|
+
this.start_promise = launch;
|
|
139
|
+
try {
|
|
140
|
+
await launch;
|
|
141
|
+
} finally {
|
|
142
|
+
if (this.start_promise === launch) {
|
|
143
|
+
this.start_promise = null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async close() {
|
|
148
|
+
if (this.start_promise) {
|
|
149
|
+
await Promise.allSettled([this.start_promise]);
|
|
150
|
+
this.start_promise = null;
|
|
151
|
+
}
|
|
152
|
+
if (this.node_server) {
|
|
153
|
+
const server = this.node_server;
|
|
154
|
+
await new Promise((resolve) => {
|
|
155
|
+
server.close(() => resolve());
|
|
156
|
+
});
|
|
157
|
+
this.node_server = null;
|
|
158
|
+
}
|
|
159
|
+
this.inbound_bus.destroy();
|
|
160
|
+
}
|
|
161
|
+
ensureListenerStarted() {
|
|
162
|
+
if (!this.listen_on || this.node_server || this.start_promise) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
void this.start().catch((error) => {
|
|
166
|
+
console.error("[abxbus] EventBridge failed to start listener", error);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async handleIncomingPayload(payload) {
|
|
170
|
+
const event = import_BaseEvent.BaseEvent.fromJSON(payload).eventReset();
|
|
171
|
+
this.inbound_bus.emit(event);
|
|
172
|
+
}
|
|
173
|
+
async sendHttp(endpoint, payload) {
|
|
174
|
+
const response = await fetch(endpoint.raw, {
|
|
175
|
+
method: "POST",
|
|
176
|
+
headers: { "content-type": "application/json" },
|
|
177
|
+
body: JSON.stringify(payload)
|
|
178
|
+
});
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
throw new Error(`IPC HTTP send failed with status ${response.status}: ${endpoint.raw}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async sendUnix(endpoint, payload) {
|
|
184
|
+
if (!isNodeRuntime()) {
|
|
185
|
+
throw new Error("unix:// send_to is only supported in Node.js runtimes");
|
|
186
|
+
}
|
|
187
|
+
const socket_path = endpoint.path;
|
|
188
|
+
if (!socket_path) {
|
|
189
|
+
throw new Error(`Invalid unix endpoint: ${endpoint.raw}`);
|
|
190
|
+
}
|
|
191
|
+
const node_net = await importNodeModule("node:net");
|
|
192
|
+
await new Promise((resolve, reject) => {
|
|
193
|
+
const socket = node_net.createConnection(socket_path, () => {
|
|
194
|
+
socket.end(`${JSON.stringify(payload)}
|
|
195
|
+
`);
|
|
196
|
+
});
|
|
197
|
+
socket.on("error", (error) => reject(error));
|
|
198
|
+
socket.on("close", () => resolve());
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
async startHttpListener(endpoint) {
|
|
202
|
+
const node_http = await importNodeModule("node:http");
|
|
203
|
+
const expected_path = endpoint.path || "/";
|
|
204
|
+
this.node_server = node_http.createServer((req, res) => {
|
|
205
|
+
const method = (req.method || "").toUpperCase();
|
|
206
|
+
const request_url = String(req.url || "/");
|
|
207
|
+
if (method !== "POST") {
|
|
208
|
+
res.statusCode = 405;
|
|
209
|
+
res.end("method not allowed");
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (request_url !== expected_path) {
|
|
213
|
+
res.statusCode = 404;
|
|
214
|
+
res.end("not found");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
let body = "";
|
|
218
|
+
req.setEncoding("utf8");
|
|
219
|
+
req.on("data", (chunk) => {
|
|
220
|
+
body += chunk;
|
|
221
|
+
});
|
|
222
|
+
req.on("end", () => {
|
|
223
|
+
let parsed_payload;
|
|
224
|
+
try {
|
|
225
|
+
parsed_payload = JSON.parse(body);
|
|
226
|
+
} catch {
|
|
227
|
+
res.statusCode = 400;
|
|
228
|
+
res.end("invalid json");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
void this.handleIncomingPayload(parsed_payload).then(() => {
|
|
232
|
+
res.statusCode = 202;
|
|
233
|
+
res.end("accepted");
|
|
234
|
+
}).catch((error) => {
|
|
235
|
+
res.statusCode = 500;
|
|
236
|
+
res.end("failed to process event");
|
|
237
|
+
console.error("[abxbus] EventBridge HTTP listener error", error);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
await new Promise((resolve, reject) => {
|
|
242
|
+
this.node_server.once("error", (error) => reject(error));
|
|
243
|
+
this.node_server.listen(endpoint.port, endpoint.host, () => resolve());
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async startUnixListener(endpoint) {
|
|
247
|
+
const socket_path = endpoint.path;
|
|
248
|
+
if (!socket_path) {
|
|
249
|
+
throw new Error(`Invalid unix endpoint: ${endpoint.raw}`);
|
|
250
|
+
}
|
|
251
|
+
const node_net = await importNodeModule("node:net");
|
|
252
|
+
const node_fs = await importNodeModule("node:fs");
|
|
253
|
+
try {
|
|
254
|
+
await node_fs.promises.unlink(socket_path);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
const code = error.code;
|
|
257
|
+
if (code !== "ENOENT") {
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
this.node_server = node_net.createServer((socket) => {
|
|
262
|
+
let buffer = "";
|
|
263
|
+
socket.setEncoding("utf8");
|
|
264
|
+
socket.on("data", (chunk) => {
|
|
265
|
+
buffer += chunk;
|
|
266
|
+
while (true) {
|
|
267
|
+
const newline_index = buffer.indexOf("\n");
|
|
268
|
+
if (newline_index < 0) break;
|
|
269
|
+
const line = buffer.slice(0, newline_index).trim();
|
|
270
|
+
buffer = buffer.slice(newline_index + 1);
|
|
271
|
+
if (!line) continue;
|
|
272
|
+
try {
|
|
273
|
+
const parsed_payload = JSON.parse(line);
|
|
274
|
+
void this.handleIncomingPayload(parsed_payload);
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
socket.on("end", () => {
|
|
280
|
+
const remainder = buffer.trim();
|
|
281
|
+
if (!remainder) return;
|
|
282
|
+
try {
|
|
283
|
+
const parsed_payload = JSON.parse(remainder);
|
|
284
|
+
void this.handleIncomingPayload(parsed_payload);
|
|
285
|
+
} catch {
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
await new Promise((resolve, reject) => {
|
|
290
|
+
this.node_server.once("error", (error) => reject(error));
|
|
291
|
+
this.node_server.listen(socket_path, () => resolve());
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=EventBridge.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/EventBridge.ts"],
|
|
4
|
+
"sourcesContent": ["import { BaseEvent } from './BaseEvent.js'\nimport { EventBus } from './EventBus.js'\nimport type { EventClass, EventHandlerCallable, EventPattern, UntypedEventHandlerFunction } from './types.js'\n\nexport type EndpointScheme = 'unix' | 'http' | 'https'\n\nexport type ParsedEndpoint = {\n raw: string\n scheme: EndpointScheme\n host?: string\n port?: number\n path?: string\n}\n\nconst isNodeRuntime = (): boolean => {\n const maybe_process = (globalThis as { process?: { versions?: { node?: string } } }).process\n return typeof maybe_process?.versions?.node === 'string'\n}\n\nconst isBrowserRuntime = (): boolean => !isNodeRuntime() && typeof globalThis.window !== 'undefined'\n\nexport const randomSuffix = (): string => Math.random().toString(36).slice(2, 10)\nconst UNIX_SOCKET_MAX_PATH_CHARS = 90\n\nexport const parseEndpoint = (raw_endpoint: string): ParsedEndpoint => {\n let parsed: URL\n try {\n parsed = new URL(raw_endpoint)\n } catch {\n throw new Error(`Invalid endpoint URL: ${raw_endpoint}`)\n }\n\n const protocol = parsed.protocol.replace(/:$/, '').toLowerCase()\n if (protocol !== 'unix' && protocol !== 'http' && protocol !== 'https') {\n throw new Error(`Unsupported endpoint scheme: ${raw_endpoint}`)\n }\n\n if (protocol === 'unix') {\n const socket_path = decodeURIComponent(parsed.pathname || '')\n if (!socket_path) {\n throw new Error(`Invalid unix endpoint (missing socket path): ${raw_endpoint}`)\n }\n const socket_path_len = new TextEncoder().encode(socket_path).length\n if (socket_path_len > UNIX_SOCKET_MAX_PATH_CHARS) {\n throw new Error(`Unix socket path is too long (${socket_path_len} chars), max is ${UNIX_SOCKET_MAX_PATH_CHARS}: ${socket_path}`)\n }\n return { raw: raw_endpoint, scheme: 'unix', path: socket_path }\n }\n\n if (!parsed.hostname) {\n throw new Error(`Invalid HTTP endpoint (missing hostname): ${raw_endpoint}`)\n }\n\n const default_port = protocol === 'https' ? 443 : 80\n return {\n raw: raw_endpoint,\n scheme: protocol,\n host: parsed.hostname,\n port: parsed.port ? Number(parsed.port) : default_port,\n path: `${parsed.pathname || '/'}${parsed.search || ''}`,\n }\n}\n\nconst importNodeModule = async (specifier: string): Promise<any> => {\n const dynamic_import = Function('module_name', 'return import(module_name)') as (module_name: string) => Promise<unknown>\n return dynamic_import(specifier) as Promise<any>\n}\n\nexport class EventBridge {\n readonly send_to: ParsedEndpoint | null\n readonly listen_on: ParsedEndpoint | null\n readonly name: string\n\n protected readonly inbound_bus: EventBus\n private start_promise: Promise<void> | null\n private node_server: any | null\n\n constructor(send_to?: string | null, listen_on?: string | null, name?: string) {\n this.send_to = send_to ? parseEndpoint(send_to) : null\n this.listen_on = listen_on ? parseEndpoint(listen_on) : null\n this.name = name ?? `EventBridge_${randomSuffix()}`\n this.inbound_bus = new EventBus(this.name, { max_history_size: 0 })\n this.start_promise = null\n this.node_server = null\n\n if (this.listen_on && isBrowserRuntime()) {\n throw new Error(`${this.constructor.name} listen_on is not supported in browser runtimes`)\n }\n\n this.dispatch = this.dispatch.bind(this)\n this.emit = this.emit.bind(this)\n this.on = this.on.bind(this)\n }\n\n on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void\n on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void\n on(event_pattern: EventPattern | '*', handler: EventHandlerCallable | UntypedEventHandlerFunction): void {\n this.ensureListenerStarted()\n if (typeof event_pattern === 'string') {\n this.inbound_bus.on(event_pattern, handler as UntypedEventHandlerFunction<BaseEvent>)\n return\n }\n this.inbound_bus.on(event_pattern as EventClass<BaseEvent>, handler as EventHandlerCallable<BaseEvent>)\n }\n\n async emit<T extends BaseEvent>(event: T): Promise<void> {\n if (!this.send_to) {\n throw new Error(`${this.constructor.name}.emit() requires send_to`)\n }\n\n const payload = event.toJSON()\n\n if (this.send_to.scheme === 'unix') {\n await this.sendUnix(this.send_to, payload)\n return\n }\n\n await this.sendHttp(this.send_to, payload)\n }\n\n async dispatch<T extends BaseEvent>(event: T): Promise<void> {\n return this.emit(event)\n }\n\n async start(): Promise<void> {\n if (!this.listen_on) return\n if (this.node_server) return\n if (this.start_promise) {\n await this.start_promise\n return\n }\n\n if (!isNodeRuntime()) {\n throw new Error(`${this.constructor.name} listen_on is only supported in Node.js runtimes`)\n }\n\n const launch = (async () => {\n const endpoint = this.listen_on\n if (!endpoint) return\n\n if (endpoint.scheme === 'unix') {\n await this.startUnixListener(endpoint)\n return\n }\n\n if (endpoint.scheme !== 'http') {\n throw new Error(`listen_on only supports unix:// or http:// endpoints, got: ${endpoint.raw}`)\n }\n\n await this.startHttpListener(endpoint)\n })()\n this.start_promise = launch\n\n try {\n await launch\n } finally {\n if (this.start_promise === launch) {\n this.start_promise = null\n }\n }\n }\n\n async close(): Promise<void> {\n if (this.start_promise) {\n await Promise.allSettled([this.start_promise])\n this.start_promise = null\n }\n\n if (this.node_server) {\n const server = this.node_server\n await new Promise<void>((resolve) => {\n server.close(() => resolve())\n })\n this.node_server = null\n }\n\n this.inbound_bus.destroy()\n }\n\n private ensureListenerStarted(): void {\n if (!this.listen_on || this.node_server || this.start_promise) {\n return\n }\n void this.start().catch((error: unknown) => {\n console.error('[abxbus] EventBridge failed to start listener', error)\n })\n }\n\n private async handleIncomingPayload(payload: unknown): Promise<void> {\n const event = BaseEvent.fromJSON(payload).eventReset()\n this.inbound_bus.emit(event)\n }\n\n private async sendHttp(endpoint: ParsedEndpoint, payload: unknown): Promise<void> {\n const response = await fetch(endpoint.raw, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!response.ok) {\n throw new Error(`IPC HTTP send failed with status ${response.status}: ${endpoint.raw}`)\n }\n }\n\n private async sendUnix(endpoint: ParsedEndpoint, payload: unknown): Promise<void> {\n if (!isNodeRuntime()) {\n throw new Error('unix:// send_to is only supported in Node.js runtimes')\n }\n\n const socket_path = endpoint.path\n if (!socket_path) {\n throw new Error(`Invalid unix endpoint: ${endpoint.raw}`)\n }\n\n const node_net = await importNodeModule('node:net')\n await new Promise<void>((resolve, reject) => {\n const socket = node_net.createConnection(socket_path, () => {\n socket.end(`${JSON.stringify(payload)}\\n`)\n })\n socket.on('error', (error: unknown) => reject(error))\n socket.on('close', () => resolve())\n })\n }\n\n private async startHttpListener(endpoint: ParsedEndpoint): Promise<void> {\n const node_http = await importNodeModule('node:http')\n const expected_path = endpoint.path || '/'\n\n this.node_server = node_http.createServer((req: any, res: any) => {\n const method = (req.method || '').toUpperCase()\n const request_url = String(req.url || '/')\n\n if (method !== 'POST') {\n res.statusCode = 405\n res.end('method not allowed')\n return\n }\n if (request_url !== expected_path) {\n res.statusCode = 404\n res.end('not found')\n return\n }\n\n let body = ''\n req.setEncoding('utf8')\n req.on('data', (chunk: string) => {\n body += chunk\n })\n req.on('end', () => {\n let parsed_payload: unknown\n try {\n parsed_payload = JSON.parse(body)\n } catch {\n res.statusCode = 400\n res.end('invalid json')\n return\n }\n\n void this.handleIncomingPayload(parsed_payload)\n .then(() => {\n res.statusCode = 202\n res.end('accepted')\n })\n .catch((error: unknown) => {\n res.statusCode = 500\n res.end('failed to process event')\n console.error('[abxbus] EventBridge HTTP listener error', error)\n })\n })\n })\n\n await new Promise<void>((resolve, reject) => {\n this.node_server.once('error', (error: unknown) => reject(error))\n this.node_server.listen(endpoint.port, endpoint.host, () => resolve())\n })\n }\n\n private async startUnixListener(endpoint: ParsedEndpoint): Promise<void> {\n const socket_path = endpoint.path\n if (!socket_path) {\n throw new Error(`Invalid unix endpoint: ${endpoint.raw}`)\n }\n\n const node_net = await importNodeModule('node:net')\n const node_fs = await importNodeModule('node:fs')\n\n try {\n await node_fs.promises.unlink(socket_path)\n } catch (error: unknown) {\n const code = (error as { code?: string }).code\n if (code !== 'ENOENT') {\n throw error\n }\n }\n\n this.node_server = node_net.createServer((socket: any) => {\n let buffer = ''\n socket.setEncoding('utf8')\n socket.on('data', (chunk: string) => {\n buffer += chunk\n while (true) {\n const newline_index = buffer.indexOf('\\n')\n if (newline_index < 0) break\n const line = buffer.slice(0, newline_index).trim()\n buffer = buffer.slice(newline_index + 1)\n if (!line) continue\n try {\n const parsed_payload = JSON.parse(line)\n void this.handleIncomingPayload(parsed_payload)\n } catch {\n // Ignore malformed lines and continue reading next frames.\n }\n }\n })\n socket.on('end', () => {\n const remainder = buffer.trim()\n if (!remainder) return\n try {\n const parsed_payload = JSON.parse(remainder)\n void this.handleIncomingPayload(parsed_payload)\n } catch {\n // Ignore malformed trailing frame.\n }\n })\n })\n\n await new Promise<void>((resolve, reject) => {\n this.node_server.once('error', (error: unknown) => reject(error))\n this.node_server.listen(socket_path, () => resolve())\n })\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { BaseEvent, type BaseEventJSON } from './BaseEvent.js';
|
|
2
|
+
import { EventHistory } from './EventHistory.js';
|
|
3
|
+
import { EventResult } from './EventResult.js';
|
|
4
|
+
import { AsyncLock, type EventConcurrencyMode, type EventHandlerConcurrencyMode, type EventHandlerCompletionMode, LockManager } from './LockManager.js';
|
|
5
|
+
import { EventHandler, type EphemeralFindEventHandler, type EventHandlerJSON } from './EventHandler.js';
|
|
6
|
+
import type { EventBusMiddleware, EventBusMiddlewareInput } from './EventBusMiddleware.js';
|
|
7
|
+
import type { EventClass, EventHandlerCallable, EventPattern, FindOptions, UntypedEventHandlerFunction } from './types.js';
|
|
8
|
+
export type EventBusOptions = {
|
|
9
|
+
id?: string;
|
|
10
|
+
max_history_size?: number | null;
|
|
11
|
+
max_history_drop?: boolean;
|
|
12
|
+
event_concurrency?: EventConcurrencyMode | null;
|
|
13
|
+
event_timeout?: number | null;
|
|
14
|
+
event_slow_timeout?: number | null;
|
|
15
|
+
event_handler_concurrency?: EventHandlerConcurrencyMode | null;
|
|
16
|
+
event_handler_completion?: EventHandlerCompletionMode;
|
|
17
|
+
event_handler_slow_timeout?: number | null;
|
|
18
|
+
event_handler_detect_file_paths?: boolean;
|
|
19
|
+
middlewares?: EventBusMiddlewareInput[];
|
|
20
|
+
};
|
|
21
|
+
export type EventBusJSON = {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
max_history_size: number | null;
|
|
25
|
+
max_history_drop: boolean;
|
|
26
|
+
event_concurrency: EventConcurrencyMode;
|
|
27
|
+
event_timeout: number | null;
|
|
28
|
+
event_slow_timeout: number | null;
|
|
29
|
+
event_handler_concurrency: EventHandlerConcurrencyMode;
|
|
30
|
+
event_handler_completion: EventHandlerCompletionMode;
|
|
31
|
+
event_handler_slow_timeout: number | null;
|
|
32
|
+
event_handler_detect_file_paths: boolean;
|
|
33
|
+
handlers: Record<string, EventHandlerJSON>;
|
|
34
|
+
handlers_by_key: Record<string, string[]>;
|
|
35
|
+
event_history: Record<string, BaseEventJSON>;
|
|
36
|
+
pending_event_queue: string[];
|
|
37
|
+
};
|
|
38
|
+
export declare class GlobalEventBusRegistry {
|
|
39
|
+
private _bus_refs;
|
|
40
|
+
add(bus: EventBus): void;
|
|
41
|
+
discard(bus: EventBus): void;
|
|
42
|
+
has(bus: EventBus): boolean;
|
|
43
|
+
get size(): number;
|
|
44
|
+
[Symbol.iterator](): IterableIterator<EventBus>;
|
|
45
|
+
findBusById(bus_id: string): EventBus | undefined;
|
|
46
|
+
findEventById(event_id: string): BaseEvent | null;
|
|
47
|
+
}
|
|
48
|
+
export declare class EventBus {
|
|
49
|
+
private static _registry_by_constructor;
|
|
50
|
+
private static _global_event_lock_by_constructor;
|
|
51
|
+
private static getRegistryForConstructor;
|
|
52
|
+
private static getGlobalEventLockForConstructor;
|
|
53
|
+
static get all_instances(): GlobalEventBusRegistry;
|
|
54
|
+
get all_instances(): GlobalEventBusRegistry;
|
|
55
|
+
get _lock_for_event_global_serial(): AsyncLock;
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
event_timeout: number | null;
|
|
59
|
+
event_concurrency: EventConcurrencyMode;
|
|
60
|
+
event_handler_concurrency: EventHandlerConcurrencyMode;
|
|
61
|
+
event_handler_completion: EventHandlerCompletionMode;
|
|
62
|
+
event_handler_detect_file_paths: boolean;
|
|
63
|
+
event_handler_slow_timeout: number | null;
|
|
64
|
+
event_slow_timeout: number | null;
|
|
65
|
+
handlers: Map<string, EventHandler>;
|
|
66
|
+
handlers_by_key: Map<string, string[]>;
|
|
67
|
+
event_history: EventHistory<BaseEvent>;
|
|
68
|
+
pending_event_queue: BaseEvent[];
|
|
69
|
+
in_flight_event_ids: Set<string>;
|
|
70
|
+
runloop_running: boolean;
|
|
71
|
+
locks: LockManager;
|
|
72
|
+
find_waiters: Set<EphemeralFindEventHandler>;
|
|
73
|
+
middlewares: EventBusMiddleware[];
|
|
74
|
+
private static normalizeMiddlewares;
|
|
75
|
+
constructor(name?: string, options?: EventBusOptions);
|
|
76
|
+
toString(): string;
|
|
77
|
+
scheduleMicrotask(fn: () => void): void;
|
|
78
|
+
private _runMiddlewareHook;
|
|
79
|
+
onEventChange(event: BaseEvent, status: 'pending' | 'started' | 'completed'): Promise<void>;
|
|
80
|
+
onEventResultChange(event: BaseEvent, result: EventResult, status: 'pending' | 'started' | 'completed'): Promise<void>;
|
|
81
|
+
private _onEventChange;
|
|
82
|
+
private _onEventResultChange;
|
|
83
|
+
private _onBusHandlersChange;
|
|
84
|
+
private _finalizeEventTimeout;
|
|
85
|
+
private _createEventTimeoutError;
|
|
86
|
+
private _runHandlersWithTimeout;
|
|
87
|
+
private _markEventCompletedIfNeeded;
|
|
88
|
+
toJSON(): EventBusJSON;
|
|
89
|
+
private static _stubHandlerFn;
|
|
90
|
+
private static _upsertHandlerIndex;
|
|
91
|
+
private static _linkEventResultHandlers;
|
|
92
|
+
static fromJSON(data: unknown): EventBus;
|
|
93
|
+
get label(): string;
|
|
94
|
+
removeEventFromPendingQueue(event: BaseEvent): number;
|
|
95
|
+
isEventInFlightOrQueued(event_id: string): boolean;
|
|
96
|
+
removeEventFromHistory(event_id: string): boolean;
|
|
97
|
+
destroy(): void;
|
|
98
|
+
on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>, options?: Partial<EventHandler>): EventHandler;
|
|
99
|
+
on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>, options?: Partial<EventHandler>): EventHandler;
|
|
100
|
+
off<T extends BaseEvent>(event_pattern: EventPattern<T> | '*', handler?: EventHandlerCallable<T> | string | EventHandler): void;
|
|
101
|
+
emit<T extends BaseEvent>(event: T): T;
|
|
102
|
+
dispatch<T extends BaseEvent>(event: T): T;
|
|
103
|
+
find(event_pattern: '*', options?: FindOptions<BaseEvent>): Promise<BaseEvent | null>;
|
|
104
|
+
find(event_pattern: '*', where: (event: BaseEvent) => boolean, options?: FindOptions<BaseEvent>): Promise<BaseEvent | null>;
|
|
105
|
+
find<T extends BaseEvent>(event_pattern: EventPattern<T>, options?: FindOptions<T>): Promise<T | null>;
|
|
106
|
+
find<T extends BaseEvent>(event_pattern: EventPattern<T>, where: (event: T) => boolean, options?: FindOptions<T>): Promise<T | null>;
|
|
107
|
+
private _waitForFutureMatch;
|
|
108
|
+
waitUntilIdle(timeout?: number | null): Promise<boolean>;
|
|
109
|
+
isIdle(): boolean;
|
|
110
|
+
isIdleAndQueueEmpty(): boolean;
|
|
111
|
+
eventIsChildOf(child_event: BaseEvent, parent_event: BaseEvent): boolean;
|
|
112
|
+
eventIsParentOf(parent_event: BaseEvent, child_event: BaseEvent): boolean;
|
|
113
|
+
logTree(): string;
|
|
114
|
+
findEventById(event_id: string): BaseEvent | null;
|
|
115
|
+
private _startRunloop;
|
|
116
|
+
private _processEvent;
|
|
117
|
+
_processEventImmediately<T extends BaseEvent>(event: T, handler_result?: EventResult): Promise<T>;
|
|
118
|
+
private _processEventImmediatelyAcrossBuses;
|
|
119
|
+
private _runloop;
|
|
120
|
+
_hasProcessedEvent(event: BaseEvent): boolean;
|
|
121
|
+
_getEventProxyScopedToThisBus<T extends BaseEvent>(event: T, handler_result?: EventResult): T;
|
|
122
|
+
private _resolveFindWaiters;
|
|
123
|
+
_getHandlersForEvent(event: BaseEvent): EventHandler[];
|
|
124
|
+
private _removeIndexedHandler;
|
|
125
|
+
}
|
|
@@ -16,18 +16,18 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var
|
|
20
|
-
__export(
|
|
19
|
+
var EventBus_exports = {};
|
|
20
|
+
__export(EventBus_exports, {
|
|
21
21
|
EventBus: () => EventBus,
|
|
22
22
|
GlobalEventBusRegistry: () => GlobalEventBusRegistry
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
25
|
-
var
|
|
26
|
-
var
|
|
24
|
+
module.exports = __toCommonJS(EventBus_exports);
|
|
25
|
+
var import_BaseEvent = require("./BaseEvent.js");
|
|
26
|
+
var import_EventHistory = require("./EventHistory.js");
|
|
27
27
|
var import_async_context = require("./async_context.js");
|
|
28
28
|
var import_timing = require("./timing.js");
|
|
29
|
-
var
|
|
30
|
-
var
|
|
29
|
+
var import_LockManager = require("./LockManager.js");
|
|
30
|
+
var import_EventHandler = require("./EventHandler.js");
|
|
31
31
|
var import_logging = require("./logging.js");
|
|
32
32
|
var import_uuid = require("uuid");
|
|
33
33
|
var import_helpers = require("./helpers.js");
|
|
@@ -114,7 +114,7 @@ class EventBus {
|
|
|
114
114
|
if (existing_lock) {
|
|
115
115
|
return existing_lock;
|
|
116
116
|
}
|
|
117
|
-
const created_lock = new
|
|
117
|
+
const created_lock = new import_LockManager.AsyncLock(1);
|
|
118
118
|
EventBus._global_event_lock_by_constructor.set(constructor_fn, created_lock);
|
|
119
119
|
return created_lock;
|
|
120
120
|
}
|
|
@@ -185,13 +185,13 @@ class EventBus {
|
|
|
185
185
|
this.handlers = /* @__PURE__ */ new Map();
|
|
186
186
|
this.handlers_by_key = /* @__PURE__ */ new Map();
|
|
187
187
|
this.find_waiters = /* @__PURE__ */ new Set();
|
|
188
|
-
this.event_history = new
|
|
188
|
+
this.event_history = new import_EventHistory.EventHistory({
|
|
189
189
|
max_history_size: options.max_history_size === void 0 ? 100 : options.max_history_size,
|
|
190
190
|
max_history_drop: options.max_history_drop ?? false
|
|
191
191
|
});
|
|
192
192
|
this.pending_event_queue = [];
|
|
193
193
|
this.in_flight_event_ids = /* @__PURE__ */ new Set();
|
|
194
|
-
this.locks = new
|
|
194
|
+
this.locks = new import_LockManager.LockManager(this);
|
|
195
195
|
this.middlewares = EventBus.normalizeMiddlewares(options.middlewares);
|
|
196
196
|
this.all_instances.add(this);
|
|
197
197
|
this.dispatch = this.dispatch.bind(this);
|
|
@@ -248,7 +248,7 @@ class EventBus {
|
|
|
248
248
|
if (result.status === "started") {
|
|
249
249
|
result._lock?.exitHandlerRun();
|
|
250
250
|
result._releaseQueueJumpPauses();
|
|
251
|
-
const aborted_error = new
|
|
251
|
+
const aborted_error = new import_EventHandler.EventHandlerAbortedError(`Aborted running handler due to event timeout`, {
|
|
252
252
|
event_result: result,
|
|
253
253
|
timeout_seconds,
|
|
254
254
|
cause: timeout_error
|
|
@@ -257,7 +257,7 @@ class EventBus {
|
|
|
257
257
|
result._signalAbort(aborted_error);
|
|
258
258
|
continue;
|
|
259
259
|
}
|
|
260
|
-
const cancelled_error = new
|
|
260
|
+
const cancelled_error = new import_EventHandler.EventHandlerCancelledError(`Cancelled pending handler due to event timeout`, {
|
|
261
261
|
event_result: result,
|
|
262
262
|
timeout_seconds,
|
|
263
263
|
cause: timeout_error
|
|
@@ -269,7 +269,7 @@ class EventBus {
|
|
|
269
269
|
}
|
|
270
270
|
_createEventTimeoutError(event, pending_entries, timeout_seconds) {
|
|
271
271
|
const timeout_anchor = pending_entries.find((entry) => entry.result.status === "started") ?? pending_entries.find((entry) => entry.result.status === "pending") ?? pending_entries[0];
|
|
272
|
-
return new
|
|
272
|
+
return new import_EventHandler.EventHandlerTimeoutError(
|
|
273
273
|
`${this.toString()}.on(${event.toString()}, ${timeout_anchor.result.handler.toString()}) timed out after ${timeout_seconds}s`,
|
|
274
274
|
{
|
|
275
275
|
event_result: timeout_anchor.result,
|
|
@@ -285,7 +285,7 @@ class EventBus {
|
|
|
285
285
|
await (0, import_timing._runWithTimeout)(event_timeout, () => this._createEventTimeoutError(event, pending_entries, event_timeout), fn);
|
|
286
286
|
}
|
|
287
287
|
} catch (error) {
|
|
288
|
-
if (error instanceof
|
|
288
|
+
if (error instanceof import_EventHandler.EventHandlerTimeoutError) {
|
|
289
289
|
this._finalizeEventTimeout(event, pending_entries, error);
|
|
290
290
|
return;
|
|
291
291
|
}
|
|
@@ -367,7 +367,7 @@ class EventBus {
|
|
|
367
367
|
result.handler = existing_handler;
|
|
368
368
|
} else {
|
|
369
369
|
const source = result.handler;
|
|
370
|
-
const handler_entry =
|
|
370
|
+
const handler_entry = import_EventHandler.EventHandler.fromJSON(
|
|
371
371
|
{
|
|
372
372
|
...source.toJSON(),
|
|
373
373
|
id: handler_id,
|
|
@@ -423,7 +423,7 @@ class EventBus {
|
|
|
423
423
|
if (!payload || typeof payload !== "object") {
|
|
424
424
|
continue;
|
|
425
425
|
}
|
|
426
|
-
const parsed =
|
|
426
|
+
const parsed = import_EventHandler.EventHandler.fromJSON(
|
|
427
427
|
{
|
|
428
428
|
...payload,
|
|
429
429
|
id: typeof payload.id === "string" ? payload.id : handler_id
|
|
@@ -450,7 +450,7 @@ class EventBus {
|
|
|
450
450
|
if (!payload || typeof payload !== "object") {
|
|
451
451
|
continue;
|
|
452
452
|
}
|
|
453
|
-
const event =
|
|
453
|
+
const event = import_BaseEvent.BaseEvent.fromJSON({
|
|
454
454
|
...payload,
|
|
455
455
|
event_id: typeof payload.event_id === "string" ? payload.event_id : event_id
|
|
456
456
|
});
|
|
@@ -525,8 +525,8 @@ class EventBus {
|
|
|
525
525
|
}
|
|
526
526
|
on(event_pattern, handler, options = {}) {
|
|
527
527
|
const normalized_key = (0, import_types.normalizeEventPattern)(event_pattern);
|
|
528
|
-
const handler_name =
|
|
529
|
-
const handler_entry = new
|
|
528
|
+
const handler_name = import_EventHandler.EventHandler.handlerNameFromCallable(handler);
|
|
529
|
+
const handler_entry = new import_EventHandler.EventHandler({
|
|
530
530
|
handler,
|
|
531
531
|
handler_name,
|
|
532
532
|
handler_registered_at: (0, import_helpers.monotonicDatetime)(),
|
|
@@ -549,7 +549,7 @@ class EventBus {
|
|
|
549
549
|
}
|
|
550
550
|
off(event_pattern, handler) {
|
|
551
551
|
const normalized_key = (0, import_types.normalizeEventPattern)(event_pattern);
|
|
552
|
-
if (typeof handler === "object" && handler instanceof
|
|
552
|
+
if (typeof handler === "object" && handler instanceof import_EventHandler.EventHandler && handler.id !== void 0) {
|
|
553
553
|
handler = handler.id;
|
|
554
554
|
}
|
|
555
555
|
const match_by_id = typeof handler === "string";
|
|
@@ -1022,4 +1022,4 @@ class EventBus {
|
|
|
1022
1022
|
if (ids.length === 0) this.handlers_by_key.delete(event_pattern);
|
|
1023
1023
|
}
|
|
1024
1024
|
}
|
|
1025
|
-
//# sourceMappingURL=
|
|
1025
|
+
//# sourceMappingURL=EventBus.js.map
|