@decaf-ts/for-http 0.3.50 → 0.3.52
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/for-http.cjs +1 -1
- package/dist/for-http.cjs.map +1 -1
- package/dist/for-http.js +1 -1
- package/dist/for-http.js.map +1 -1
- package/lib/HttpDispatcher.cjs +3 -9
- package/lib/HttpDispatcher.d.ts +1 -0
- package/lib/HttpDispatcher.js.map +1 -1
- package/lib/esm/HttpDispatcher.d.ts +1 -0
- package/lib/esm/HttpDispatcher.js +3 -9
- package/lib/esm/HttpDispatcher.js.map +1 -1
- package/lib/esm/event/ServerEventConnector.d.ts +8 -6
- package/lib/esm/event/ServerEventConnector.js +69 -31
- package/lib/esm/event/ServerEventConnector.js.map +1 -1
- package/lib/esm/event/types.d.ts +19 -4
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/event/ServerEventConnector.cjs +69 -31
- package/lib/event/ServerEventConnector.d.ts +8 -6
- package/lib/event/ServerEventConnector.js.map +1 -1
- package/lib/event/types.d.ts +19 -4
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { Adapter, Context, ContextualArgs, Dispatch, MaybeContextualArg, Prepare
|
|
|
2
2
|
import { HttpConfig, HttpFlags } from "./types";
|
|
3
3
|
export declare class HttpDispatcher extends Dispatch<Adapter<HttpConfig, any, PreparedStatement<any>, Context<HttpFlags>>> {
|
|
4
4
|
private connector?;
|
|
5
|
+
protected initialized: boolean;
|
|
5
6
|
private listening;
|
|
6
7
|
/**
|
|
7
8
|
* Called by the base Dispatch after observe(adapter).
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Dispatch, PersistenceKeys, } from "@decaf-ts/core";
|
|
2
2
|
import { ServerEventConnector } from "./event/index.js";
|
|
3
|
-
import { KeepAliveOperation } from "./constants.js";
|
|
4
3
|
export class HttpDispatcher extends Dispatch {
|
|
5
4
|
constructor() {
|
|
6
5
|
super(...arguments);
|
|
6
|
+
this.initialized = false;
|
|
7
7
|
this.listening = false;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
@@ -54,14 +54,10 @@ export class HttpDispatcher extends Dispatch {
|
|
|
54
54
|
log.info(`Opening ServerEventConnector for url: ${listeningUrl}`);
|
|
55
55
|
this.connector = ServerEventConnector.open(listeningUrl);
|
|
56
56
|
log.debug(`ServerEventConnector opened successfully for url: ${listeningUrl}`);
|
|
57
|
-
this.connector.
|
|
57
|
+
this.connector.addListener({
|
|
58
58
|
onEvent: async (event) => {
|
|
59
59
|
const [tableName, operation, id, ...args] = event;
|
|
60
60
|
const { log, ctxArgs } = (await this.logCtx(args, operation, true)).for("onEvent");
|
|
61
|
-
if (operation === KeepAliveOperation) {
|
|
62
|
-
log.debug(`keep alive received - discarding`);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
61
|
super
|
|
66
62
|
.updateObservers(tableName, operation, id, ...ctxArgs)
|
|
67
63
|
.catch((e) => log.error(`ServerEventConnector failed to updateObservers`, e));
|
|
@@ -77,9 +73,7 @@ export class HttpDispatcher extends Dispatch {
|
|
|
77
73
|
this.listening = true;
|
|
78
74
|
log.info(`HttpDispatcher is now listening at ${listeningUrl}.`);
|
|
79
75
|
}
|
|
80
|
-
async close(
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
82
|
-
...args) {
|
|
76
|
+
async close(...args) {
|
|
83
77
|
// const { log } = this.logCtx(args, this.close);
|
|
84
78
|
//
|
|
85
79
|
// log.debug(`Closing HttpDispatcher`, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpDispatcher.js","sourceRoot":"","sources":["../../src/HttpDispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,QAAQ,EAER,eAAe,GAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAe,oBAAoB,EAAE,yBAAgB;
|
|
1
|
+
{"version":3,"file":"HttpDispatcher.js","sourceRoot":"","sources":["../../src/HttpDispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import { EventHandlers } from "./types";
|
|
2
2
|
import { Context, ContextualLoggedClass } from "@decaf-ts/core";
|
|
3
|
+
export type ServerEventConnectorHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
3
4
|
export declare class ServerEventConnector extends ContextualLoggedClass<Context<any>> {
|
|
4
5
|
private readonly url;
|
|
6
|
+
private readonly headers?;
|
|
5
7
|
private static readonly cache;
|
|
6
8
|
static get(url: string): ServerEventConnector;
|
|
7
|
-
static open(url: string): ServerEventConnector;
|
|
9
|
+
static open(url: string, headers?: ServerEventConnectorHeaders): ServerEventConnector;
|
|
8
10
|
static close(url: string): void;
|
|
9
11
|
private static parseReceivedEvent;
|
|
10
12
|
/** Shared connection state (cached singleton instance). */
|
|
11
13
|
private es?;
|
|
12
14
|
private controller?;
|
|
13
15
|
private listeners;
|
|
14
|
-
constructor(url: string);
|
|
16
|
+
constructor(url: string, headers?: ServerEventConnectorHeaders | undefined);
|
|
15
17
|
isOpen(): boolean;
|
|
16
|
-
close(): void;
|
|
18
|
+
close(force?: boolean): void;
|
|
17
19
|
/**
|
|
18
20
|
* Increments refCount and ensures EventSource is created.
|
|
19
21
|
* This method must be called only on the shared singleton instance.
|
|
20
22
|
*/
|
|
21
|
-
startListening
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
private startListening;
|
|
24
|
+
addListener(handlers: EventHandlers): () => void;
|
|
25
|
+
removeListener(handlers: EventHandlers): void;
|
|
24
26
|
}
|
|
@@ -8,10 +8,10 @@ export class ServerEventConnector extends ContextualLoggedClass {
|
|
|
8
8
|
return this.cache.get(url);
|
|
9
9
|
throw new Error(`Server event connector not found for URL '${url}'. Did you forget to call open()?`);
|
|
10
10
|
}
|
|
11
|
-
static open(url) {
|
|
11
|
+
static open(url, headers) {
|
|
12
12
|
if (this.cache.has(url))
|
|
13
13
|
return this.cache.get(url);
|
|
14
|
-
const connector = new ServerEventConnector(url);
|
|
14
|
+
const connector = new ServerEventConnector(url, headers);
|
|
15
15
|
this.cache.set(url, connector);
|
|
16
16
|
return this.cache.get(url);
|
|
17
17
|
}
|
|
@@ -29,39 +29,44 @@ export class ServerEventConnector extends ContextualLoggedClass {
|
|
|
29
29
|
const [eventName, operationKey, objectId, rawPayload] = data;
|
|
30
30
|
if (typeof eventName !== "string")
|
|
31
31
|
return null;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
:
|
|
32
|
+
let payload;
|
|
33
|
+
if (Array.isArray(rawPayload)) {
|
|
34
|
+
payload = rawPayload.map((item) => typeof item === "string" ? Serialization.deserialize(item) : item);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
payload =
|
|
38
|
+
typeof rawPayload === "string"
|
|
39
|
+
? Serialization.deserialize(rawPayload)
|
|
40
|
+
: rawPayload;
|
|
41
|
+
}
|
|
35
42
|
return [eventName, String(operationKey), objectId, payload];
|
|
36
43
|
}
|
|
37
44
|
catch {
|
|
38
45
|
return null;
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
|
-
constructor(url) {
|
|
48
|
+
constructor(url, headers) {
|
|
42
49
|
super();
|
|
43
50
|
this.url = url;
|
|
51
|
+
this.headers = headers;
|
|
44
52
|
this.listeners = new Set();
|
|
45
53
|
}
|
|
46
54
|
isOpen() {
|
|
47
55
|
return this.es !== undefined;
|
|
48
56
|
}
|
|
49
|
-
close() {
|
|
57
|
+
close(force = false) {
|
|
50
58
|
const log = this.log.for(this.close);
|
|
51
59
|
if (!this.es) {
|
|
52
|
-
log.debug(`Skipping
|
|
60
|
+
log.debug(`Skipping EventSource close — no open connection to ${this.url}`);
|
|
53
61
|
return;
|
|
54
62
|
}
|
|
55
|
-
if (this.listeners.size > 0) {
|
|
56
|
-
log.warn(`Skipping
|
|
57
|
-
url: this.url,
|
|
58
|
-
listeners: this.listeners.size,
|
|
59
|
-
});
|
|
63
|
+
if (this.listeners.size > 0 && !force) {
|
|
64
|
+
log.warn(`Skipping EventSource connection close ${this.url} — ${this.listeners.size} active listener(s) remaining.`);
|
|
60
65
|
return;
|
|
61
66
|
}
|
|
62
67
|
// Close and drop from cache.
|
|
63
68
|
try {
|
|
64
|
-
log.info(`
|
|
69
|
+
log.info(`Closing EventSource connection for listening URL ${this.url}`);
|
|
65
70
|
this.controller?.abort();
|
|
66
71
|
}
|
|
67
72
|
finally {
|
|
@@ -69,47 +74,53 @@ export class ServerEventConnector extends ContextualLoggedClass {
|
|
|
69
74
|
this.es = undefined;
|
|
70
75
|
this.listeners.clear();
|
|
71
76
|
ServerEventConnector.cache.delete(this.url);
|
|
72
|
-
log.info(`
|
|
77
|
+
log.info(`EventSource connection ${this.url} closed and removed from pool`);
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
/**
|
|
76
81
|
* Increments refCount and ensures EventSource is created.
|
|
77
82
|
* This method must be called only on the shared singleton instance.
|
|
78
83
|
*/
|
|
79
|
-
startListening(
|
|
84
|
+
startListening() {
|
|
80
85
|
const log = this.log.for(this.startListening);
|
|
81
86
|
if (this.es) {
|
|
82
|
-
log.info(`
|
|
83
|
-
url: this.url,
|
|
84
|
-
listeners: this.listeners.size,
|
|
85
|
-
});
|
|
87
|
+
log.info(`Listening address ${this.url} is already in the pool and listening. Skipping opening a new connection.`, { url: this.url, listeners: this.listeners.size });
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
|
-
log.info(`Opening
|
|
90
|
+
log.info(`Opening EventSource connection to ${this.url}`);
|
|
89
91
|
this.es = new EventSourcePlus(this.url, {
|
|
90
|
-
headers,
|
|
92
|
+
...(this.headers && { headers: this.headers }),
|
|
91
93
|
credentials: "include",
|
|
92
94
|
});
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
96
|
+
const self = this;
|
|
93
97
|
this.controller = this.es.listen({
|
|
94
98
|
onResponse: () => {
|
|
95
|
-
log.info(`
|
|
99
|
+
log.info(`Connected to ${this.url}. Ready to receive events`);
|
|
96
100
|
},
|
|
97
101
|
onRequestError: ({ error }) => {
|
|
98
|
-
log.error(
|
|
102
|
+
log.error("Failed to establish EventSource connection", {
|
|
99
103
|
url: this.url,
|
|
100
104
|
error,
|
|
101
105
|
});
|
|
102
|
-
|
|
106
|
+
self.listeners.forEach((handler) => handler.onError(String(error?.message ?? error)));
|
|
103
107
|
},
|
|
104
108
|
onResponseError: ({ response }) => {
|
|
105
|
-
|
|
109
|
+
const status = response?.status;
|
|
110
|
+
const statusText = response?.statusText;
|
|
111
|
+
log.error("Listening failed with HTTP error response", {
|
|
106
112
|
url: this.url,
|
|
107
|
-
status
|
|
108
|
-
statusText
|
|
113
|
+
status,
|
|
114
|
+
statusText,
|
|
109
115
|
});
|
|
110
|
-
|
|
116
|
+
const err = new Error(`HTTP ${status ?? "unknown"} ${statusText ?? "error"}`);
|
|
117
|
+
self.listeners.forEach((handler) => handler.onError(err));
|
|
111
118
|
},
|
|
112
119
|
onMessage: (message) => {
|
|
120
|
+
if (message.event === "heartbeat") {
|
|
121
|
+
log.debug(`Refresh connection. Heartbeat received.`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
113
124
|
const raw = message && typeof message === "object" && "data" in message
|
|
114
125
|
? message.data
|
|
115
126
|
: message;
|
|
@@ -121,15 +132,42 @@ export class ServerEventConnector extends ContextualLoggedClass {
|
|
|
121
132
|
});
|
|
122
133
|
return;
|
|
123
134
|
}
|
|
124
|
-
|
|
135
|
+
for (const handler of self.listeners) {
|
|
136
|
+
try {
|
|
137
|
+
handler.onEvent(event);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
log.error("Listener handler failed on event", { err });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
125
143
|
},
|
|
126
144
|
});
|
|
127
145
|
}
|
|
128
146
|
addListener(handlers) {
|
|
147
|
+
const log = this.log.for(this.addListener);
|
|
148
|
+
log.info(`Registering listener for connection ${this.url} — ${this.listeners.size} active listener(s)`);
|
|
149
|
+
this.startListening();
|
|
129
150
|
this.listeners.add(handlers);
|
|
151
|
+
log.info(`Listener registered for connection ${this.url} — total listener(s): ${this.listeners.size}`);
|
|
152
|
+
return () => this.removeListener(handlers);
|
|
130
153
|
}
|
|
131
154
|
removeListener(handlers) {
|
|
132
|
-
this.
|
|
155
|
+
const log = this.log.for(this.removeListener);
|
|
156
|
+
const existed = this.listeners.has(handlers);
|
|
157
|
+
log.info(`Unregistering listener for connection ${this.url}. Current active listeners: ${this.listeners.size}`, {
|
|
158
|
+
listenerFound: existed,
|
|
159
|
+
});
|
|
160
|
+
if (existed) {
|
|
161
|
+
this.listeners.delete(handlers);
|
|
162
|
+
log.debug(`Listener unregistered for connection ${this.url} — total listener(s): ${this.listeners.size}`);
|
|
163
|
+
}
|
|
164
|
+
if (this.listeners.size === 0) {
|
|
165
|
+
log.info(`No listeners remaining. Closing EventSource connection ${this.url}.`, {
|
|
166
|
+
url: this.url,
|
|
167
|
+
listeners: this.listeners.size,
|
|
168
|
+
});
|
|
169
|
+
this.close();
|
|
170
|
+
}
|
|
133
171
|
}
|
|
134
172
|
}
|
|
135
173
|
//# sourceMappingURL=ServerEventConnector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerEventConnector.js","sourceRoot":"","sources":["../../../src/event/ServerEventConnector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAW,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"ServerEventConnector.js","sourceRoot":"","sources":["../../../src/event/ServerEventConnector.ts"],"names":[],"mappings":"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"}
|
package/lib/esm/event/types.d.ts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { BulkCrudOperationKeys, OperationKeys } from "@decaf-ts/db-decorators";
|
|
2
|
-
|
|
2
|
+
import { SseMessage } from "event-source-plus";
|
|
3
|
+
export type ServerEventType = "message" | "heartbeat" | string;
|
|
4
|
+
export type ServerRawMessage = SseMessage & {
|
|
5
|
+
id?: string;
|
|
6
|
+
event: ServerEventType;
|
|
7
|
+
data: string;
|
|
8
|
+
retry?: number;
|
|
9
|
+
};
|
|
10
|
+
export type SingleServerEvent<T> = readonly [
|
|
3
11
|
modelName: string,
|
|
4
|
-
operation: OperationKeys |
|
|
12
|
+
operation: OperationKeys | string,
|
|
5
13
|
id: string,
|
|
6
|
-
payload:
|
|
14
|
+
payload: T
|
|
15
|
+
];
|
|
16
|
+
export type BulkServerEvent<T> = readonly [
|
|
17
|
+
modelName: string,
|
|
18
|
+
operation: BulkCrudOperationKeys,
|
|
19
|
+
id: string[],
|
|
20
|
+
payload: T[]
|
|
7
21
|
];
|
|
22
|
+
export type ServerEvent<T> = SingleServerEvent<T> | BulkServerEvent<T>;
|
|
8
23
|
export type EventHandlers = {
|
|
9
|
-
onEvent: ([tableName, operation, id]: ServerEvent) => void;
|
|
24
|
+
onEvent: ([tableName, operation, id]: ServerEvent<any>) => void;
|
|
10
25
|
onError: (err: unknown) => void;
|
|
11
26
|
};
|
package/lib/esm/index.d.ts
CHANGED
package/lib/esm/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export * from "./event/index.js";
|
|
|
22
22
|
* @summary Version identifier for the module
|
|
23
23
|
* @const VERSION
|
|
24
24
|
*/
|
|
25
|
-
export const VERSION = "0.3.
|
|
25
|
+
export const VERSION = "0.3.52";
|
|
26
26
|
export const PACKAGE_NAME = "@decaf-ts/for-http";
|
|
27
27
|
Metadata.registerLibrary(PACKAGE_NAME, VERSION);
|
|
28
28
|
//# sourceMappingURL=index.js.map
|
|
@@ -11,10 +11,10 @@ class ServerEventConnector extends core_1.ContextualLoggedClass {
|
|
|
11
11
|
return this.cache.get(url);
|
|
12
12
|
throw new Error(`Server event connector not found for URL '${url}'. Did you forget to call open()?`);
|
|
13
13
|
}
|
|
14
|
-
static open(url) {
|
|
14
|
+
static open(url, headers) {
|
|
15
15
|
if (this.cache.has(url))
|
|
16
16
|
return this.cache.get(url);
|
|
17
|
-
const connector = new ServerEventConnector(url);
|
|
17
|
+
const connector = new ServerEventConnector(url, headers);
|
|
18
18
|
this.cache.set(url, connector);
|
|
19
19
|
return this.cache.get(url);
|
|
20
20
|
}
|
|
@@ -32,39 +32,44 @@ class ServerEventConnector extends core_1.ContextualLoggedClass {
|
|
|
32
32
|
const [eventName, operationKey, objectId, rawPayload] = data;
|
|
33
33
|
if (typeof eventName !== "string")
|
|
34
34
|
return null;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
:
|
|
35
|
+
let payload;
|
|
36
|
+
if (Array.isArray(rawPayload)) {
|
|
37
|
+
payload = rawPayload.map((item) => typeof item === "string" ? decorator_validation_1.Serialization.deserialize(item) : item);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
payload =
|
|
41
|
+
typeof rawPayload === "string"
|
|
42
|
+
? decorator_validation_1.Serialization.deserialize(rawPayload)
|
|
43
|
+
: rawPayload;
|
|
44
|
+
}
|
|
38
45
|
return [eventName, String(operationKey), objectId, payload];
|
|
39
46
|
}
|
|
40
47
|
catch {
|
|
41
48
|
return null;
|
|
42
49
|
}
|
|
43
50
|
}
|
|
44
|
-
constructor(url) {
|
|
51
|
+
constructor(url, headers) {
|
|
45
52
|
super();
|
|
46
53
|
this.url = url;
|
|
54
|
+
this.headers = headers;
|
|
47
55
|
this.listeners = new Set();
|
|
48
56
|
}
|
|
49
57
|
isOpen() {
|
|
50
58
|
return this.es !== undefined;
|
|
51
59
|
}
|
|
52
|
-
close() {
|
|
60
|
+
close(force = false) {
|
|
53
61
|
const log = this.log.for(this.close);
|
|
54
62
|
if (!this.es) {
|
|
55
|
-
log.debug(`Skipping
|
|
63
|
+
log.debug(`Skipping EventSource close — no open connection to ${this.url}`);
|
|
56
64
|
return;
|
|
57
65
|
}
|
|
58
|
-
if (this.listeners.size > 0) {
|
|
59
|
-
log.warn(`Skipping
|
|
60
|
-
url: this.url,
|
|
61
|
-
listeners: this.listeners.size,
|
|
62
|
-
});
|
|
66
|
+
if (this.listeners.size > 0 && !force) {
|
|
67
|
+
log.warn(`Skipping EventSource connection close ${this.url} — ${this.listeners.size} active listener(s) remaining.`);
|
|
63
68
|
return;
|
|
64
69
|
}
|
|
65
70
|
// Close and drop from cache.
|
|
66
71
|
try {
|
|
67
|
-
log.info(`
|
|
72
|
+
log.info(`Closing EventSource connection for listening URL ${this.url}`);
|
|
68
73
|
this.controller?.abort();
|
|
69
74
|
}
|
|
70
75
|
finally {
|
|
@@ -72,47 +77,53 @@ class ServerEventConnector extends core_1.ContextualLoggedClass {
|
|
|
72
77
|
this.es = undefined;
|
|
73
78
|
this.listeners.clear();
|
|
74
79
|
ServerEventConnector.cache.delete(this.url);
|
|
75
|
-
log.info(`
|
|
80
|
+
log.info(`EventSource connection ${this.url} closed and removed from pool`);
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
83
|
/**
|
|
79
84
|
* Increments refCount and ensures EventSource is created.
|
|
80
85
|
* This method must be called only on the shared singleton instance.
|
|
81
86
|
*/
|
|
82
|
-
startListening(
|
|
87
|
+
startListening() {
|
|
83
88
|
const log = this.log.for(this.startListening);
|
|
84
89
|
if (this.es) {
|
|
85
|
-
log.info(`
|
|
86
|
-
url: this.url,
|
|
87
|
-
listeners: this.listeners.size,
|
|
88
|
-
});
|
|
90
|
+
log.info(`Listening address ${this.url} is already in the pool and listening. Skipping opening a new connection.`, { url: this.url, listeners: this.listeners.size });
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
91
|
-
log.info(`Opening
|
|
93
|
+
log.info(`Opening EventSource connection to ${this.url}`);
|
|
92
94
|
this.es = new event_source_plus_1.EventSourcePlus(this.url, {
|
|
93
|
-
headers,
|
|
95
|
+
...(this.headers && { headers: this.headers }),
|
|
94
96
|
credentials: "include",
|
|
95
97
|
});
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
99
|
+
const self = this;
|
|
96
100
|
this.controller = this.es.listen({
|
|
97
101
|
onResponse: () => {
|
|
98
|
-
log.info(`
|
|
102
|
+
log.info(`Connected to ${this.url}. Ready to receive events`);
|
|
99
103
|
},
|
|
100
104
|
onRequestError: ({ error }) => {
|
|
101
|
-
log.error(
|
|
105
|
+
log.error("Failed to establish EventSource connection", {
|
|
102
106
|
url: this.url,
|
|
103
107
|
error,
|
|
104
108
|
});
|
|
105
|
-
|
|
109
|
+
self.listeners.forEach((handler) => handler.onError(String(error?.message ?? error)));
|
|
106
110
|
},
|
|
107
111
|
onResponseError: ({ response }) => {
|
|
108
|
-
|
|
112
|
+
const status = response?.status;
|
|
113
|
+
const statusText = response?.statusText;
|
|
114
|
+
log.error("Listening failed with HTTP error response", {
|
|
109
115
|
url: this.url,
|
|
110
|
-
status
|
|
111
|
-
statusText
|
|
116
|
+
status,
|
|
117
|
+
statusText,
|
|
112
118
|
});
|
|
113
|
-
|
|
119
|
+
const err = new Error(`HTTP ${status ?? "unknown"} ${statusText ?? "error"}`);
|
|
120
|
+
self.listeners.forEach((handler) => handler.onError(err));
|
|
114
121
|
},
|
|
115
122
|
onMessage: (message) => {
|
|
123
|
+
if (message.event === "heartbeat") {
|
|
124
|
+
log.debug(`Refresh connection. Heartbeat received.`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
116
127
|
const raw = message && typeof message === "object" && "data" in message
|
|
117
128
|
? message.data
|
|
118
129
|
: message;
|
|
@@ -124,15 +135,42 @@ class ServerEventConnector extends core_1.ContextualLoggedClass {
|
|
|
124
135
|
});
|
|
125
136
|
return;
|
|
126
137
|
}
|
|
127
|
-
|
|
138
|
+
for (const handler of self.listeners) {
|
|
139
|
+
try {
|
|
140
|
+
handler.onEvent(event);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
log.error("Listener handler failed on event", { err });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
128
146
|
},
|
|
129
147
|
});
|
|
130
148
|
}
|
|
131
149
|
addListener(handlers) {
|
|
150
|
+
const log = this.log.for(this.addListener);
|
|
151
|
+
log.info(`Registering listener for connection ${this.url} — ${this.listeners.size} active listener(s)`);
|
|
152
|
+
this.startListening();
|
|
132
153
|
this.listeners.add(handlers);
|
|
154
|
+
log.info(`Listener registered for connection ${this.url} — total listener(s): ${this.listeners.size}`);
|
|
155
|
+
return () => this.removeListener(handlers);
|
|
133
156
|
}
|
|
134
157
|
removeListener(handlers) {
|
|
135
|
-
this.
|
|
158
|
+
const log = this.log.for(this.removeListener);
|
|
159
|
+
const existed = this.listeners.has(handlers);
|
|
160
|
+
log.info(`Unregistering listener for connection ${this.url}. Current active listeners: ${this.listeners.size}`, {
|
|
161
|
+
listenerFound: existed,
|
|
162
|
+
});
|
|
163
|
+
if (existed) {
|
|
164
|
+
this.listeners.delete(handlers);
|
|
165
|
+
log.debug(`Listener unregistered for connection ${this.url} — total listener(s): ${this.listeners.size}`);
|
|
166
|
+
}
|
|
167
|
+
if (this.listeners.size === 0) {
|
|
168
|
+
log.info(`No listeners remaining. Closing EventSource connection ${this.url}.`, {
|
|
169
|
+
url: this.url,
|
|
170
|
+
listeners: this.listeners.size,
|
|
171
|
+
});
|
|
172
|
+
this.close();
|
|
173
|
+
}
|
|
136
174
|
}
|
|
137
175
|
}
|
|
138
176
|
exports.ServerEventConnector = ServerEventConnector;
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import { EventHandlers } from "./types";
|
|
2
2
|
import { Context, ContextualLoggedClass } from "@decaf-ts/core";
|
|
3
|
+
export type ServerEventConnectorHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
3
4
|
export declare class ServerEventConnector extends ContextualLoggedClass<Context<any>> {
|
|
4
5
|
private readonly url;
|
|
6
|
+
private readonly headers?;
|
|
5
7
|
private static readonly cache;
|
|
6
8
|
static get(url: string): ServerEventConnector;
|
|
7
|
-
static open(url: string): ServerEventConnector;
|
|
9
|
+
static open(url: string, headers?: ServerEventConnectorHeaders): ServerEventConnector;
|
|
8
10
|
static close(url: string): void;
|
|
9
11
|
private static parseReceivedEvent;
|
|
10
12
|
/** Shared connection state (cached singleton instance). */
|
|
11
13
|
private es?;
|
|
12
14
|
private controller?;
|
|
13
15
|
private listeners;
|
|
14
|
-
constructor(url: string);
|
|
16
|
+
constructor(url: string, headers?: ServerEventConnectorHeaders | undefined);
|
|
15
17
|
isOpen(): boolean;
|
|
16
|
-
close(): void;
|
|
18
|
+
close(force?: boolean): void;
|
|
17
19
|
/**
|
|
18
20
|
* Increments refCount and ensures EventSource is created.
|
|
19
21
|
* This method must be called only on the shared singleton instance.
|
|
20
22
|
*/
|
|
21
|
-
startListening
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
private startListening;
|
|
24
|
+
addListener(handlers: EventHandlers): () => void;
|
|
25
|
+
removeListener(handlers: EventHandlers): void;
|
|
24
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerEventConnector.js","sourceRoot":"","sources":["../../src/event/ServerEventConnector.ts"],"names":[],"mappings":";;;AACA,yDAAoD;AACpD,yEAA+D;AAC/D,yCAAgE;
|
|
1
|
+
{"version":3,"file":"ServerEventConnector.js","sourceRoot":"","sources":["../../src/event/ServerEventConnector.ts"],"names":[],"mappings":"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"}
|
package/lib/event/types.d.ts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { BulkCrudOperationKeys, OperationKeys } from "@decaf-ts/db-decorators";
|
|
2
|
-
|
|
2
|
+
import { SseMessage } from "event-source-plus";
|
|
3
|
+
export type ServerEventType = "message" | "heartbeat" | string;
|
|
4
|
+
export type ServerRawMessage = SseMessage & {
|
|
5
|
+
id?: string;
|
|
6
|
+
event: ServerEventType;
|
|
7
|
+
data: string;
|
|
8
|
+
retry?: number;
|
|
9
|
+
};
|
|
10
|
+
export type SingleServerEvent<T> = readonly [
|
|
3
11
|
modelName: string,
|
|
4
|
-
operation: OperationKeys |
|
|
12
|
+
operation: OperationKeys | string,
|
|
5
13
|
id: string,
|
|
6
|
-
payload:
|
|
14
|
+
payload: T
|
|
15
|
+
];
|
|
16
|
+
export type BulkServerEvent<T> = readonly [
|
|
17
|
+
modelName: string,
|
|
18
|
+
operation: BulkCrudOperationKeys,
|
|
19
|
+
id: string[],
|
|
20
|
+
payload: T[]
|
|
7
21
|
];
|
|
22
|
+
export type ServerEvent<T> = SingleServerEvent<T> | BulkServerEvent<T>;
|
|
8
23
|
export type EventHandlers = {
|
|
9
|
-
onEvent: ([tableName, operation, id]: ServerEvent) => void;
|
|
24
|
+
onEvent: ([tableName, operation, id]: ServerEvent<any>) => void;
|
|
10
25
|
onError: (err: unknown) => void;
|
|
11
26
|
};
|