sonamu 0.8.20 → 0.8.21
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/stream/sse.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { z } from "zod";
|
|
|
3
3
|
export declare function createSSEFactory<T extends z.ZodObject>(socket: FastifyRequest["socket"], reply: FastifyReply, _events: T): SSEConnection<T>;
|
|
4
4
|
export declare function createMockSSEFactory<T extends z.ZodObject>(_events: T): SSEConnection<T>;
|
|
5
5
|
export interface SSEConnection<T extends z.ZodObject> {
|
|
6
|
+
get closed(): boolean;
|
|
7
|
+
onClose(callback: () => void): void;
|
|
6
8
|
publish<K extends keyof z.infer<T>>(event: K, data: z.infer<T>[K]): void;
|
|
7
9
|
end(): Promise<void>;
|
|
8
10
|
}
|
package/dist/stream/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/stream/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EACpD,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAChC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,CAAC,GACT,aAAa,CAAC,CAAC,CAAC,CAElB;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/stream/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EACpD,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAChC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,CAAC,GACT,aAAa,CAAC,CAAC,CAAC,CAElB;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CASxF;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;IAClD,IAAI,MAAM,IAAI,OAAO,CAAC;IACtB,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACzE,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB"}
|
package/dist/stream/sse.js
CHANGED
|
@@ -4,6 +4,10 @@ export function createSSEFactory(socket, reply, _events) {
|
|
|
4
4
|
}
|
|
5
5
|
export function createMockSSEFactory(_events) {
|
|
6
6
|
return {
|
|
7
|
+
get closed () {
|
|
8
|
+
return false;
|
|
9
|
+
},
|
|
10
|
+
onClose: (_callback)=>{},
|
|
7
11
|
publish: (_event, _data)=>{},
|
|
8
12
|
end: ()=>Promise.resolve()
|
|
9
13
|
};
|
|
@@ -12,9 +16,25 @@ class SSEConnectionImpl {
|
|
|
12
16
|
socket;
|
|
13
17
|
reply;
|
|
14
18
|
_closed = false;
|
|
19
|
+
_closeCallbacks = [];
|
|
15
20
|
markClosed = ()=>{
|
|
16
21
|
this._closed = true;
|
|
22
|
+
this.fireCloseCallbacks();
|
|
17
23
|
};
|
|
24
|
+
get closed() {
|
|
25
|
+
return this._closed;
|
|
26
|
+
}
|
|
27
|
+
onClose(callback) {
|
|
28
|
+
this._closeCallbacks.push(callback);
|
|
29
|
+
}
|
|
30
|
+
// 콜백을 한 번만 실행하고 배열을 비워 중복 호출을 방지
|
|
31
|
+
fireCloseCallbacks() {
|
|
32
|
+
const callbacks = this._closeCallbacks;
|
|
33
|
+
this._closeCallbacks = [];
|
|
34
|
+
for (const cb of callbacks){
|
|
35
|
+
cb();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
18
38
|
constructor(socket, reply){
|
|
19
39
|
this.socket = socket;
|
|
20
40
|
this.reply = reply;
|
|
@@ -37,6 +57,7 @@ class SSEConnectionImpl {
|
|
|
37
57
|
this._closed = true;
|
|
38
58
|
this.socket.off("close", this.markClosed);
|
|
39
59
|
this.socket.off("error", this.markClosed);
|
|
60
|
+
this.fireCloseCallbacks();
|
|
40
61
|
this.reply.sse({
|
|
41
62
|
event: "end",
|
|
42
63
|
data: "END"
|
|
@@ -46,4 +67,4 @@ class SSEConnectionImpl {
|
|
|
46
67
|
}
|
|
47
68
|
}
|
|
48
69
|
|
|
49
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdHJlYW0vc3NlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRmFzdGlmeVJlcGx5LCBGYXN0aWZ5UmVxdWVzdCB9IGZyb20gXCJmYXN0aWZ5XCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5cbi8vIE5PVEUoSGF6ZSwgMjUxMTA2KTogY29udGV4dCBwcm92aWRlcuyXkOyEnCDsnbjsnpDrpbwg7LGE7JuM7KO866m0IGNyZWF0ZVNTRShldmVudHMp66eM7Jy866GcIOyCrOyaqSDqsIDriqVcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTU0VGYWN0b3J5PFQgZXh0ZW5kcyB6LlpvZE9iamVjdD4oXG4gIHNvY2tldDogRmFzdGlmeVJlcXVlc3RbXCJzb2NrZXRcIl0sXG4gIHJlcGx5OiBGYXN0aWZ5UmVwbHksXG4gIF9ldmVudHM6IFQsXG4pOiBTU0VDb25uZWN0aW9uPFQ+
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdHJlYW0vc3NlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRmFzdGlmeVJlcGx5LCBGYXN0aWZ5UmVxdWVzdCB9IGZyb20gXCJmYXN0aWZ5XCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5cbi8vIE5PVEUoSGF6ZSwgMjUxMTA2KTogY29udGV4dCBwcm92aWRlcuyXkOyEnCDsnbjsnpDrpbwg7LGE7JuM7KO866m0IGNyZWF0ZVNTRShldmVudHMp66eM7Jy866GcIOyCrOyaqSDqsIDriqVcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTU0VGYWN0b3J5PFQgZXh0ZW5kcyB6LlpvZE9iamVjdD4oXG4gIHNvY2tldDogRmFzdGlmeVJlcXVlc3RbXCJzb2NrZXRcIl0sXG4gIHJlcGx5OiBGYXN0aWZ5UmVwbHksXG4gIF9ldmVudHM6IFQsXG4pOiBTU0VDb25uZWN0aW9uPFQ+IHtcbiAgcmV0dXJuIG5ldyBTU0VDb25uZWN0aW9uSW1wbDxUPihzb2NrZXQsIHJlcGx5KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU1vY2tTU0VGYWN0b3J5PFQgZXh0ZW5kcyB6LlpvZE9iamVjdD4oX2V2ZW50czogVCk6IFNTRUNvbm5lY3Rpb248VD4ge1xuICByZXR1cm4ge1xuICAgIGdldCBjbG9zZWQoKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSxcbiAgICBvbkNsb3NlOiAoX2NhbGxiYWNrKSA9PiB7fSxcbiAgICBwdWJsaXNoOiAoX2V2ZW50LCBfZGF0YSkgPT4ge30sXG4gICAgZW5kOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKSxcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTU0VDb25uZWN0aW9uPFQgZXh0ZW5kcyB6LlpvZE9iamVjdD4ge1xuICBnZXQgY2xvc2VkKCk6IGJvb2xlYW47XG4gIG9uQ2xvc2UoY2FsbGJhY2s6ICgpID0+IHZvaWQpOiB2b2lkO1xuICBwdWJsaXNoPEsgZXh0ZW5kcyBrZXlvZiB6LmluZmVyPFQ+PihldmVudDogSywgZGF0YTogei5pbmZlcjxUPltLXSk6IHZvaWQ7XG4gIGVuZCgpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG5jbGFzcyBTU0VDb25uZWN0aW9uSW1wbDxUIGV4dGVuZHMgei5ab2RPYmplY3Q+IGltcGxlbWVudHMgU1NFQ29ubmVjdGlvbjxUPiB7XG4gIHByaXZhdGUgX2Nsb3NlZCA9IGZhbHNlO1xuICBwcml2YXRlIF9jbG9zZUNhbGxiYWNrczogQXJyYXk8KCkgPT4gdm9pZD4gPSBbXTtcblxuICBwcml2YXRlIHJlYWRvbmx5IG1hcmtDbG9zZWQgPSAoKSA9PiB7XG4gICAgdGhpcy5fY2xvc2VkID0gdHJ1ZTtcbiAgICB0aGlzLmZpcmVDbG9zZUNhbGxiYWNrcygpO1xuICB9O1xuXG4gIGdldCBjbG9zZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2Nsb3NlZDtcbiAgfVxuXG4gIG9uQ2xvc2UoY2FsbGJhY2s6ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLl9jbG9zZUNhbGxiYWNrcy5wdXNoKGNhbGxiYWNrKTtcbiAgfVxuXG4gIC8vIOy9nOuwseydhCDtlZwg67KI66eMIOyLpO2Wie2VmOqzoCDrsLDsl7TsnYQg67mE7JuMIOykkeuztSDtmLjstpzsnYQg67Cp7KeAXG4gIHByaXZhdGUgZmlyZUNsb3NlQ2FsbGJhY2tzKCk6IHZvaWQge1xuICAgIGNvbnN0IGNhbGxiYWNrcyA9IHRoaXMuX2Nsb3NlQ2FsbGJhY2tzO1xuICAgIHRoaXMuX2Nsb3NlQ2FsbGJhY2tzID0gW107XG4gICAgZm9yIChjb25zdCBjYiBvZiBjYWxsYmFja3MpIHtcbiAgICAgIGNiKCk7XG4gICAgfVxuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBzb2NrZXQ6IEZhc3RpZnlSZXF1ZXN0W1wic29ja2V0XCJdLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcmVwbHk6IEZhc3RpZnlSZXBseSxcbiAgKSB7XG4gICAgdGhpcy5zb2NrZXQub24oXCJjbG9zZVwiLCB0aGlzLm1hcmtDbG9zZWQpO1xuICAgIHRoaXMuc29ja2V0Lm9uKFwiZXJyb3JcIiwgdGhpcy5tYXJrQ2xvc2VkKTtcbiAgfVxuXG4gIHB1Ymxpc2g8SyBleHRlbmRzIGtleW9mIHouaW5mZXI8VD4+KGV2ZW50OiBLLCBkYXRhOiB6LmluZmVyPFQ+W0tdKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2Nsb3NlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMucmVwbHkuc3NlKHtcbiAgICAgIGV2ZW50OiBldmVudCBhcyBzdHJpbmcsXG4gICAgICBkYXRhOiBKU09OLnN0cmluZ2lmeShkYXRhKSxcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGVuZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5fY2xvc2VkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fY2xvc2VkID0gdHJ1ZTtcbiAgICB0aGlzLnNvY2tldC5vZmYoXCJjbG9zZVwiLCB0aGlzLm1hcmtDbG9zZWQpO1xuICAgIHRoaXMuc29ja2V0Lm9mZihcImVycm9yXCIsIHRoaXMubWFya0Nsb3NlZCk7XG4gICAgdGhpcy5maXJlQ2xvc2VDYWxsYmFja3MoKTtcblxuICAgIHRoaXMucmVwbHkuc3NlKHtcbiAgICAgIGV2ZW50OiBcImVuZFwiLFxuICAgICAgZGF0YTogXCJFTkRcIixcbiAgICB9KTtcblxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDIwMCkpO1xuICAgIHRoaXMucmVwbHkucmF3LmVuZCgpO1xuICB9XG59XG4iXSwibmFtZXMiOlsiY3JlYXRlU1NFRmFjdG9yeSIsInNvY2tldCIsInJlcGx5IiwiX2V2ZW50cyIsIlNTRUNvbm5lY3Rpb25JbXBsIiwiY3JlYXRlTW9ja1NTRUZhY3RvcnkiLCJjbG9zZWQiLCJvbkNsb3NlIiwiX2NhbGxiYWNrIiwicHVibGlzaCIsIl9ldmVudCIsIl9kYXRhIiwiZW5kIiwiUHJvbWlzZSIsInJlc29sdmUiLCJfY2xvc2VkIiwiX2Nsb3NlQ2FsbGJhY2tzIiwibWFya0Nsb3NlZCIsImZpcmVDbG9zZUNhbGxiYWNrcyIsImNhbGxiYWNrIiwicHVzaCIsImNhbGxiYWNrcyIsImNiIiwib24iLCJldmVudCIsImRhdGEiLCJzc2UiLCJKU09OIiwic3RyaW5naWZ5Iiwib2ZmIiwic2V0VGltZW91dCIsInJhdyJdLCJtYXBwaW5ncyI6IkFBR0EsNkVBQTZFO0FBQzdFLE9BQU8sU0FBU0EsaUJBQ2RDLE1BQWdDLEVBQ2hDQyxLQUFtQixFQUNuQkMsT0FBVTtJQUVWLE9BQU8sSUFBSUMsa0JBQXFCSCxRQUFRQztBQUMxQztBQUVBLE9BQU8sU0FBU0cscUJBQTRDRixPQUFVO0lBQ3BFLE9BQU87UUFDTCxJQUFJRyxVQUFTO1lBQ1gsT0FBTztRQUNUO1FBQ0FDLFNBQVMsQ0FBQ0MsYUFBZTtRQUN6QkMsU0FBUyxDQUFDQyxRQUFRQyxTQUFXO1FBQzdCQyxLQUFLLElBQU1DLFFBQVFDLE9BQU87SUFDNUI7QUFDRjtBQVNBLE1BQU1WOzs7SUFDSVcsVUFBVSxNQUFNO0lBQ2hCQyxrQkFBcUMsRUFBRSxDQUFDO0lBRS9CQyxhQUFhO1FBQzVCLElBQUksQ0FBQ0YsT0FBTyxHQUFHO1FBQ2YsSUFBSSxDQUFDRyxrQkFBa0I7SUFDekIsRUFBRTtJQUVGLElBQUlaLFNBQWtCO1FBQ3BCLE9BQU8sSUFBSSxDQUFDUyxPQUFPO0lBQ3JCO0lBRUFSLFFBQVFZLFFBQW9CLEVBQVE7UUFDbEMsSUFBSSxDQUFDSCxlQUFlLENBQUNJLElBQUksQ0FBQ0Q7SUFDNUI7SUFFQSxpQ0FBaUM7SUFDekJELHFCQUEyQjtRQUNqQyxNQUFNRyxZQUFZLElBQUksQ0FBQ0wsZUFBZTtRQUN0QyxJQUFJLENBQUNBLGVBQWUsR0FBRyxFQUFFO1FBQ3pCLEtBQUssTUFBTU0sTUFBTUQsVUFBVztZQUMxQkM7UUFDRjtJQUNGO0lBRUEsWUFDRSxBQUFpQnJCLE1BQWdDLEVBQ2pELEFBQWlCQyxLQUFtQixDQUNwQzthQUZpQkQsU0FBQUE7YUFDQUMsUUFBQUE7UUFFakIsSUFBSSxDQUFDRCxNQUFNLENBQUNzQixFQUFFLENBQUMsU0FBUyxJQUFJLENBQUNOLFVBQVU7UUFDdkMsSUFBSSxDQUFDaEIsTUFBTSxDQUFDc0IsRUFBRSxDQUFDLFNBQVMsSUFBSSxDQUFDTixVQUFVO0lBQ3pDO0lBRUFSLFFBQW9DZSxLQUFRLEVBQUVDLElBQW1CLEVBQVE7UUFDdkUsSUFBSSxJQUFJLENBQUNWLE9BQU8sRUFBRTtZQUNoQjtRQUNGO1FBRUEsSUFBSSxDQUFDYixLQUFLLENBQUN3QixHQUFHLENBQUM7WUFDYkYsT0FBT0E7WUFDUEMsTUFBTUUsS0FBS0MsU0FBUyxDQUFDSDtRQUN2QjtJQUNGO0lBRUEsTUFBTWIsTUFBcUI7UUFDekIsSUFBSSxJQUFJLENBQUNHLE9BQU8sRUFBRTtZQUNoQjtRQUNGO1FBRUEsSUFBSSxDQUFDQSxPQUFPLEdBQUc7UUFDZixJQUFJLENBQUNkLE1BQU0sQ0FBQzRCLEdBQUcsQ0FBQyxTQUFTLElBQUksQ0FBQ1osVUFBVTtRQUN4QyxJQUFJLENBQUNoQixNQUFNLENBQUM0QixHQUFHLENBQUMsU0FBUyxJQUFJLENBQUNaLFVBQVU7UUFDeEMsSUFBSSxDQUFDQyxrQkFBa0I7UUFFdkIsSUFBSSxDQUFDaEIsS0FBSyxDQUFDd0IsR0FBRyxDQUFDO1lBQ2JGLE9BQU87WUFDUEMsTUFBTTtRQUNSO1FBRUEsTUFBTSxJQUFJWixRQUFRLENBQUNDLFVBQVlnQixXQUFXaEIsU0FBUztRQUNuRCxJQUFJLENBQUNaLEtBQUssQ0FBQzZCLEdBQUcsQ0FBQ25CLEdBQUc7SUFDcEI7QUFDRiJ9
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonamu",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.21",
|
|
4
4
|
"description": "Sonamu — TypeScript Fullstack API Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -124,9 +124,9 @@
|
|
|
124
124
|
"vite": "7.3.0",
|
|
125
125
|
"vitest": "^4.0.10",
|
|
126
126
|
"@sonamu-kit/hmr-hook": "^0.4.1",
|
|
127
|
-
"@sonamu-kit/
|
|
127
|
+
"@sonamu-kit/tasks": "^0.2.0",
|
|
128
128
|
"@sonamu-kit/ts-loader": "^2.1.3",
|
|
129
|
-
"@sonamu-kit/
|
|
129
|
+
"@sonamu-kit/hmr-runner": "^0.1.1"
|
|
130
130
|
},
|
|
131
131
|
"devDependencies": {
|
|
132
132
|
"@biomejs/biome": "^2.3.13",
|
|
@@ -86,7 +86,7 @@ export async function fetch(options: AxiosRequestConfig) {
|
|
|
86
86
|
});
|
|
87
87
|
return res.data;
|
|
88
88
|
} catch (e: unknown) {
|
|
89
|
-
if (axios.isAxiosError(e) && e.response
|
|
89
|
+
if (axios.isAxiosError(e) && e.response?.data) {
|
|
90
90
|
const d = e.response.data as {
|
|
91
91
|
message: string;
|
|
92
92
|
issues: core.$ZodIssue[];
|
|
@@ -61,7 +61,7 @@ export async function fetch(options: AxiosRequestConfig) {
|
|
|
61
61
|
});
|
|
62
62
|
return res.data;
|
|
63
63
|
} catch (e: unknown) {
|
|
64
|
-
if (axios.isAxiosError(e) && e.response
|
|
64
|
+
if (axios.isAxiosError(e) && e.response?.data) {
|
|
65
65
|
const d = e.response.data as {
|
|
66
66
|
message: string;
|
|
67
67
|
issues: core.$ZodIssue[];
|
package/src/stream/sse.ts
CHANGED
|
@@ -12,22 +12,48 @@ export function createSSEFactory<T extends z.ZodObject>(
|
|
|
12
12
|
|
|
13
13
|
export function createMockSSEFactory<T extends z.ZodObject>(_events: T): SSEConnection<T> {
|
|
14
14
|
return {
|
|
15
|
+
get closed() {
|
|
16
|
+
return false;
|
|
17
|
+
},
|
|
18
|
+
onClose: (_callback) => {},
|
|
15
19
|
publish: (_event, _data) => {},
|
|
16
20
|
end: () => Promise.resolve(),
|
|
17
21
|
};
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
export interface SSEConnection<T extends z.ZodObject> {
|
|
25
|
+
get closed(): boolean;
|
|
26
|
+
onClose(callback: () => void): void;
|
|
21
27
|
publish<K extends keyof z.infer<T>>(event: K, data: z.infer<T>[K]): void;
|
|
22
28
|
end(): Promise<void>;
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
class SSEConnectionImpl<T extends z.ZodObject> implements SSEConnection<T> {
|
|
26
32
|
private _closed = false;
|
|
33
|
+
private _closeCallbacks: Array<() => void> = [];
|
|
34
|
+
|
|
27
35
|
private readonly markClosed = () => {
|
|
28
36
|
this._closed = true;
|
|
37
|
+
this.fireCloseCallbacks();
|
|
29
38
|
};
|
|
30
39
|
|
|
40
|
+
get closed(): boolean {
|
|
41
|
+
return this._closed;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
onClose(callback: () => void): void {
|
|
45
|
+
this._closeCallbacks.push(callback);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 콜백을 한 번만 실행하고 배열을 비워 중복 호출을 방지
|
|
49
|
+
private fireCloseCallbacks(): void {
|
|
50
|
+
const callbacks = this._closeCallbacks;
|
|
51
|
+
this._closeCallbacks = [];
|
|
52
|
+
for (const cb of callbacks) {
|
|
53
|
+
cb();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
31
57
|
constructor(
|
|
32
58
|
private readonly socket: FastifyRequest["socket"],
|
|
33
59
|
private readonly reply: FastifyReply,
|
|
@@ -55,6 +81,7 @@ class SSEConnectionImpl<T extends z.ZodObject> implements SSEConnection<T> {
|
|
|
55
81
|
this._closed = true;
|
|
56
82
|
this.socket.off("close", this.markClosed);
|
|
57
83
|
this.socket.off("error", this.markClosed);
|
|
84
|
+
this.fireCloseCallbacks();
|
|
58
85
|
|
|
59
86
|
this.reply.sse({
|
|
60
87
|
event: "end",
|