@shaper.org/core 1.0.3 → 1.0.4-prerelease
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/client/index.d.mts +15 -7
- package/dist/client/index.mjs +17 -4
- package/dist/node/index.d.mts +1 -0
- package/dist/node/index.mjs +2 -1
- package/dist/runtime/error-tracker.ts +54 -104
- package/dist/runtime/vite-hook.ts +112 -111
- package/package.json +1 -1
package/dist/client/index.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/client/iframe-post-message.d.ts
|
|
2
|
-
type PostMessageType = "server-ready" | "all-routes" | "route-change" | "route-refresh";
|
|
2
|
+
type PostMessageType = "server-ready" | "all-routes" | "route-change" | "route-refresh" | "error";
|
|
3
3
|
interface PostMessage {
|
|
4
4
|
message: any;
|
|
5
5
|
type: PostMessageType;
|
|
6
|
+
object: "shaper-post-message";
|
|
6
7
|
}
|
|
7
8
|
interface RouteInfo {
|
|
8
9
|
name: string;
|
|
@@ -23,15 +24,20 @@ interface AllRoutesMessage extends PostMessage {
|
|
|
23
24
|
}
|
|
24
25
|
interface RouteChangeMessage extends PostMessage {
|
|
25
26
|
type: "route-change";
|
|
26
|
-
message:
|
|
27
|
-
route: RouteInfo;
|
|
28
|
-
};
|
|
27
|
+
message: RouteInfo;
|
|
29
28
|
}
|
|
30
29
|
interface RouteRefreshMessage extends PostMessage {
|
|
31
30
|
type: "route-refresh";
|
|
32
|
-
message:
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
message: RouteInfo;
|
|
32
|
+
}
|
|
33
|
+
interface ErrorInfo {
|
|
34
|
+
errorType: string;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
lineno?: number;
|
|
37
|
+
colno?: number;
|
|
38
|
+
stack: string;
|
|
39
|
+
has_blank_screen: boolean;
|
|
40
|
+
filename?: string;
|
|
35
41
|
}
|
|
36
42
|
declare class IframePostMessageClient {
|
|
37
43
|
authHost: string;
|
|
@@ -48,6 +54,8 @@ declare class IframePostMessageClient {
|
|
|
48
54
|
sendAllRoutes(routes: RouteInfo[]): void;
|
|
49
55
|
sendRouteChange(route: RouteInfo): void;
|
|
50
56
|
sendRouteRefresh(route: RouteInfo): void;
|
|
57
|
+
sendError(errorInfo: ErrorInfo): void;
|
|
58
|
+
sendConsole(): void;
|
|
51
59
|
}
|
|
52
60
|
//#endregion
|
|
53
61
|
export { AllRoutesMessage, IframePostMessageClient, PostMessage, PostMessageType, RouteChangeMessage, RouteInfo, RouteRefreshMessage, ServerReadyMessage };
|
package/dist/client/index.mjs
CHANGED
|
@@ -33,14 +33,16 @@ var IframePostMessageClient = class {
|
|
|
33
33
|
sendServerReady() {
|
|
34
34
|
this._send({
|
|
35
35
|
type: "server-ready",
|
|
36
|
-
message: { satus: "ok" }
|
|
36
|
+
message: { satus: "ok" },
|
|
37
|
+
object: "shaper-post-message"
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
sendAllRoutes(routes) {
|
|
40
41
|
for (let route of routes) this._ensure_route_file(route);
|
|
41
42
|
const message = {
|
|
42
43
|
type: "all-routes",
|
|
43
|
-
message: { routes }
|
|
44
|
+
message: { routes },
|
|
45
|
+
object: "shaper-post-message"
|
|
44
46
|
};
|
|
45
47
|
this._send(message);
|
|
46
48
|
}
|
|
@@ -48,7 +50,8 @@ var IframePostMessageClient = class {
|
|
|
48
50
|
this._ensure_route_file(route);
|
|
49
51
|
const message = {
|
|
50
52
|
type: "route-change",
|
|
51
|
-
message: { route }
|
|
53
|
+
message: { ...route },
|
|
54
|
+
object: "shaper-post-message"
|
|
52
55
|
};
|
|
53
56
|
this._send(message);
|
|
54
57
|
}
|
|
@@ -56,10 +59,20 @@ var IframePostMessageClient = class {
|
|
|
56
59
|
this._ensure_route_file(route);
|
|
57
60
|
const message = {
|
|
58
61
|
type: "route-refresh",
|
|
59
|
-
message: { route }
|
|
62
|
+
message: { ...route },
|
|
63
|
+
object: "shaper-post-message"
|
|
60
64
|
};
|
|
61
65
|
this._send(message);
|
|
62
66
|
}
|
|
67
|
+
sendError(errorInfo) {
|
|
68
|
+
const message = {
|
|
69
|
+
type: "error",
|
|
70
|
+
message: errorInfo,
|
|
71
|
+
object: "shaper-post-message"
|
|
72
|
+
};
|
|
73
|
+
this._send(message);
|
|
74
|
+
}
|
|
75
|
+
sendConsole() {}
|
|
63
76
|
};
|
|
64
77
|
|
|
65
78
|
//#endregion
|
package/dist/node/index.d.mts
CHANGED
|
@@ -5,6 +5,7 @@ import { HmrContext, ViteDevServer } from "vite";
|
|
|
5
5
|
declare const HMREventsPlugin: () => {
|
|
6
6
|
name: string;
|
|
7
7
|
enforce: string;
|
|
8
|
+
apply: string;
|
|
8
9
|
resolveId(id: string): "virtual:hmr-events-plugin" | undefined;
|
|
9
10
|
load(id: string): string | undefined;
|
|
10
11
|
transformIndexHtml(html: string): {
|
package/dist/node/index.mjs
CHANGED
|
@@ -1,46 +1,22 @@
|
|
|
1
1
|
import { ViteHook } from "./vite-hook";
|
|
2
2
|
import { ViteMessage } from "./vite-message";
|
|
3
|
-
|
|
4
|
-
interface LogEvent {
|
|
5
|
-
type: "logEvent";
|
|
6
|
-
logLevel: string;
|
|
7
|
-
timestamp: number;
|
|
8
|
-
message: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface UnhandledrejectionEvent {
|
|
12
|
-
type: "unhandledrejectionEvent";
|
|
13
|
-
message: string;
|
|
14
|
-
timestamp: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface ErrorEvent {
|
|
18
|
-
type: "errorEvent";
|
|
19
|
-
lineno: number;
|
|
20
|
-
colno: number;
|
|
21
|
-
filename: string;
|
|
22
|
-
message: string;
|
|
23
|
-
timestamp: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type Event = LogEvent | UnhandledrejectionEvent | ErrorEvent;
|
|
3
|
+
import { IframePostMessageClient } from "../client";
|
|
27
4
|
|
|
28
5
|
class ErrorTracker {
|
|
29
|
-
eventsQueue: Event[];
|
|
30
|
-
|
|
31
6
|
public vHook: ViteHook;
|
|
32
7
|
public viteMessage: ViteMessage;
|
|
8
|
+
private iframeClient: IframePostMessageClient;
|
|
33
9
|
|
|
34
10
|
constructor() {
|
|
35
|
-
this.eventsQueue = [];
|
|
36
|
-
|
|
37
11
|
this.viteMessage = new ViteMessage();
|
|
38
12
|
|
|
39
13
|
this.vHook = new ViteHook();
|
|
14
|
+
|
|
15
|
+
this.iframeClient = new IframePostMessageClient();
|
|
40
16
|
}
|
|
41
17
|
|
|
42
18
|
isBlankScreen() {
|
|
43
|
-
const app = document.querySelector("div#
|
|
19
|
+
const app = document.querySelector("div#root");
|
|
44
20
|
return app ? app.childElementCount === 0 : false;
|
|
45
21
|
}
|
|
46
22
|
|
|
@@ -48,35 +24,29 @@ class ErrorTracker {
|
|
|
48
24
|
this.handleError();
|
|
49
25
|
this.handleUnhandledrejection();
|
|
50
26
|
this.consoleInterception();
|
|
27
|
+
}
|
|
51
28
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.vHook.onAfterUpdate((data, timestamp) => {
|
|
63
|
-
setTimeout(() => {
|
|
64
|
-
const endTimestamp = Date.now();
|
|
65
|
-
|
|
66
|
-
let events = this.eventsQueue.filter(
|
|
67
|
-
(event) =>
|
|
68
|
-
event.timestamp >= startTimestamp &&
|
|
69
|
-
event.timestamp <= endTimestamp,
|
|
70
|
-
);
|
|
29
|
+
formatConsoleMessage(args: unknown[]): string {
|
|
30
|
+
let error;
|
|
31
|
+
const texts = [];
|
|
32
|
+
for (let arg of args) {
|
|
33
|
+
if (arg instanceof Error) {
|
|
34
|
+
error = arg;
|
|
35
|
+
} else {
|
|
36
|
+
texts.push(arg);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
71
39
|
|
|
72
|
-
|
|
40
|
+
if (error) {
|
|
41
|
+
return error.stack || error.message;
|
|
42
|
+
}
|
|
73
43
|
|
|
74
|
-
|
|
75
|
-
}, 5);
|
|
76
|
-
});
|
|
44
|
+
return texts.map((text) => String(text)).join(" ");
|
|
77
45
|
}
|
|
78
46
|
|
|
79
47
|
consoleInterception() {
|
|
48
|
+
type LogLevel = keyof typeof originalConsole;
|
|
49
|
+
|
|
80
50
|
const originalConsole = {
|
|
81
51
|
log: console.log,
|
|
82
52
|
warn: console.warn,
|
|
@@ -84,83 +54,63 @@ class ErrorTracker {
|
|
|
84
54
|
trace: console.trace,
|
|
85
55
|
// debug: console.debug,
|
|
86
56
|
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return arg.toString();
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
this.eventsQueue.push({
|
|
97
|
-
type: "logEvent",
|
|
98
|
-
logLevel,
|
|
99
|
-
timestamp: Date.now(),
|
|
100
|
-
message: logArgumentsString.join(" "),
|
|
101
|
-
});
|
|
57
|
+
for (let logLevel of Object.keys(originalConsole) as LogLevel[]) {
|
|
58
|
+
console[logLevel] = function (
|
|
59
|
+
this: ErrorTracker,
|
|
60
|
+
...args: unknown[]
|
|
61
|
+
) {
|
|
102
62
|
originalConsole[logLevel].apply(this, args);
|
|
63
|
+
|
|
64
|
+
const message = this.formatConsoleMessage(args);
|
|
65
|
+
|
|
66
|
+
if (!message) return;
|
|
67
|
+
|
|
68
|
+
if (logLevel === "error") {
|
|
69
|
+
console.debug("console error", message);
|
|
70
|
+
this.iframeClient.sendError({
|
|
71
|
+
errorType: "RUNTIME_ERROR",
|
|
72
|
+
timestamp: Date.now(),
|
|
73
|
+
stack: message,
|
|
74
|
+
has_blank_screen: this.isBlankScreen(),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
103
77
|
}.bind(this);
|
|
104
78
|
}
|
|
105
79
|
}
|
|
106
80
|
|
|
107
81
|
handleUnhandledrejection() {
|
|
108
82
|
window.addEventListener("unhandledrejection", (evt) => {
|
|
109
|
-
console.debug(evt);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
message: evt.reason.stack || evt.reason.message,
|
|
83
|
+
console.debug("handleUnhandledrejection", evt);
|
|
84
|
+
this.iframeClient.sendError({
|
|
85
|
+
errorType: "RUNTIME_ERROR",
|
|
113
86
|
timestamp: Date.now(),
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
87
|
+
stack: evt.reason.stack || evt.reason.message,
|
|
88
|
+
has_blank_screen: this.isBlankScreen(),
|
|
89
|
+
});
|
|
117
90
|
});
|
|
118
91
|
}
|
|
119
92
|
|
|
120
93
|
handleError() {
|
|
121
94
|
window.addEventListener("error", (evt) => {
|
|
95
|
+
console.debug("handleError", evt);
|
|
122
96
|
let message;
|
|
123
97
|
if (evt.error) {
|
|
124
98
|
message = evt.error.stack || evt.error.message;
|
|
125
99
|
} else {
|
|
126
100
|
message = evt.message;
|
|
127
101
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
102
|
+
this.iframeClient.sendError({
|
|
103
|
+
errorType: "RUNTIME_ERROR",
|
|
104
|
+
timestamp: Date.now(),
|
|
105
|
+
stack: message,
|
|
106
|
+
has_blank_screen: this.isBlankScreen(),
|
|
132
107
|
lineno: evt.lineno,
|
|
133
108
|
colno: evt.colno,
|
|
134
109
|
filename: evt.filename,
|
|
135
|
-
|
|
136
|
-
timestamp: Date.now(),
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
this.eventsQueue.push(errorMessage);
|
|
110
|
+
});
|
|
140
111
|
});
|
|
141
|
-
|
|
142
|
-
// This handle the following kind of runtime error
|
|
143
|
-
// For now it's diffcult to know what to do because those errors are not sync with the HMR lifecyle
|
|
144
|
-
// Maybe use a queue
|
|
145
|
-
// <script setup lang="ts">
|
|
146
|
-
// import { onMounted } from 'vue';
|
|
147
|
-
|
|
148
|
-
// onMounted(() => {
|
|
149
|
-
// // This will trigger the error event because it happens at runtime
|
|
150
|
-
// setTimeout(() => {
|
|
151
|
-
// undefinedFunction(); // Runtime error - WILL trigger window.error
|
|
152
|
-
// }, 0);
|
|
153
|
-
// });
|
|
154
|
-
// </script>
|
|
155
112
|
}
|
|
156
113
|
}
|
|
157
114
|
|
|
158
115
|
const tracker = new ErrorTracker();
|
|
159
116
|
tracker.start();
|
|
160
|
-
|
|
161
|
-
// HMR listening
|
|
162
|
-
// const handleMessage = (event) => {
|
|
163
|
-
// console.log(event);
|
|
164
|
-
// };
|
|
165
|
-
|
|
166
|
-
// window.addEventListener("message", handleMessage);
|
|
@@ -1,133 +1,134 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
ErrorPayload,
|
|
3
|
+
FullReloadPayload,
|
|
4
|
+
PrunePayload,
|
|
5
|
+
UpdatePayload,
|
|
6
6
|
} from "vite/types/hmrPayload.js";
|
|
7
7
|
import { ViteHotContext } from "vite/types/hot.js";
|
|
8
8
|
|
|
9
9
|
type ViteUpdateCallback =
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
| ((data: UpdatePayload, timestamp: number) => void)
|
|
11
|
+
| null;
|
|
12
12
|
|
|
13
13
|
type VitePruneCallback =
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
| ((data: PrunePayload, timestamp: number) => void)
|
|
15
|
+
| null;
|
|
16
16
|
|
|
17
17
|
type VitFullReloadCallback =
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
| ((data: FullReloadPayload, timestamp: number) => void)
|
|
19
|
+
| null;
|
|
20
20
|
|
|
21
21
|
type ViteErrorCallback =
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
| ((data: ErrorPayload, timestamp: number) => void)
|
|
23
|
+
| null;
|
|
24
24
|
|
|
25
25
|
type ViteInvalidateCallback = ((data: any, timestamp: number) => void) | null;
|
|
26
26
|
|
|
27
27
|
type ViteWebSocketConnectCallback =
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
| ((data: any, timestamp: number) => void)
|
|
29
|
+
| null;
|
|
30
30
|
|
|
31
31
|
type ViteWebSocketDisconnectCallback =
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
| ((data: any, timestamp: number) => void)
|
|
33
|
+
| null;
|
|
34
34
|
|
|
35
35
|
class ViteHook {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
36
|
+
private hmr: ViteHotContext | undefined;
|
|
37
|
+
constructor() {
|
|
38
|
+
this.hmr = import.meta.hot;
|
|
39
|
+
}
|
|
40
|
+
hotExists(hmr: ViteHotContext | undefined): hmr is ViteHotContext {
|
|
41
|
+
if (hmr) return true;
|
|
42
|
+
console.error("HotContext does not exists");
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onBeforeUpdate(fn: ViteUpdateCallback = null) {
|
|
47
|
+
if (!this.hotExists(this.hmr)) return;
|
|
48
|
+
|
|
49
|
+
this.hmr.on("vite:beforeUpdate", (data: UpdatePayload) => {
|
|
50
|
+
const timestamp = Date.now();
|
|
51
|
+
console.debug("beforeUpdate");
|
|
52
|
+
fn && fn(data, timestamp);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onAfterUpdate(fn: ViteUpdateCallback = null) {
|
|
57
|
+
if (!this.hotExists(this.hmr)) return;
|
|
58
|
+
|
|
59
|
+
this.hmr.on("vite:afterUpdate", (data: UpdatePayload) => {
|
|
60
|
+
const timestamp = Date.now();
|
|
61
|
+
console.debug("afterUpdate");
|
|
62
|
+
fn && fn(data, timestamp);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
onBeforePrune(fn: VitePruneCallback = null) {
|
|
67
|
+
if (!this.hotExists(this.hmr)) return;
|
|
68
|
+
|
|
69
|
+
this.hmr.on("vite:beforePrune", (data: PrunePayload) => {
|
|
70
|
+
const timestamp = Date.now();
|
|
71
|
+
console.debug("beforePrune");
|
|
72
|
+
|
|
73
|
+
fn && fn(data, timestamp);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
onBeforeFullReload(fn: VitFullReloadCallback = null) {
|
|
78
|
+
if (!this.hotExists(this.hmr)) return;
|
|
79
|
+
|
|
80
|
+
this.hmr.on("vite:beforeFullReload", (data: FullReloadPayload) => {
|
|
81
|
+
const timestamp = Date.now();
|
|
82
|
+
console.debug("beforeFullReload");
|
|
83
|
+
|
|
84
|
+
fn && fn(data, timestamp);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onError(fn: ViteErrorCallback = null) {
|
|
89
|
+
if (!this.hotExists(this.hmr)) return;
|
|
90
|
+
|
|
91
|
+
this.hmr.on("vite:error", (data: ErrorPayload) => {
|
|
92
|
+
const timestamp = Date.now();
|
|
93
|
+
console.debug("error");
|
|
94
|
+
console.log(this.hmr);
|
|
95
|
+
|
|
96
|
+
fn && fn(data, timestamp);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onInvalidate(fn: ViteInvalidateCallback = null) {
|
|
101
|
+
if (!this.hotExists(this.hmr)) return;
|
|
102
|
+
|
|
103
|
+
this.hmr.on("vite:invalidate", (data: any) => {
|
|
104
|
+
const timestamp = Date.now();
|
|
105
|
+
console.debug("invalidate");
|
|
106
|
+
|
|
107
|
+
fn && fn(data, timestamp);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
onWsConnect(fn: ViteWebSocketConnectCallback = null) {
|
|
112
|
+
if (!this.hotExists(this.hmr)) return;
|
|
113
|
+
|
|
114
|
+
this.hmr.on("vite:ws:connect", (data: any) => {
|
|
115
|
+
const timestamp = Date.now();
|
|
116
|
+
console.debug("ws:connect");
|
|
117
|
+
|
|
118
|
+
fn && fn(data, timestamp);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
onWsDisconnect(fn: ViteWebSocketDisconnectCallback = null) {
|
|
123
|
+
if (!this.hotExists(this.hmr)) return;
|
|
124
|
+
|
|
125
|
+
this.hmr.on("vite:ws:disconnect", (data: any) => {
|
|
126
|
+
const timestamp = Date.now();
|
|
127
|
+
console.debug(":ws:disconnect");
|
|
128
|
+
|
|
129
|
+
fn && fn(data, timestamp);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
export { ViteHook };
|