@rsdoctor/components 1.5.12 → 2.0.0-alpha.0
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/components/Charts/done.mjs +2 -2
- package/dist/components/Charts/done.mjs.map +1 -1
- package/dist/components/Charts/minify.mjs +2 -2
- package/dist/components/Charts/minify.mjs.map +1 -1
- package/dist/components/Layout/menus.mjs +7 -7
- package/dist/components/Layout/menus.mjs.map +1 -1
- package/dist/components/Manifest/api.mjs +2 -2
- package/dist/components/Manifest/api.mjs.map +1 -1
- package/dist/components/Plugins/plugins.d.ts +18 -0
- package/dist/components/Plugins/{webpack.mjs → plugins.mjs} +4 -4
- package/dist/components/Plugins/plugins.mjs.map +1 -0
- package/dist/pages/{WebpackLoaders → Loaders}/Analysis/constants.d.ts +1 -1
- package/dist/pages/{WebpackLoaders → Loaders}/Analysis/constants.mjs +1 -1
- package/dist/pages/Loaders/Analysis/constants.mjs.map +1 -0
- package/dist/pages/Loaders/Analysis/index.mjs.map +1 -0
- package/dist/pages/{WebpackLoaders → Loaders}/Overall/constants.d.ts +1 -1
- package/dist/pages/{WebpackLoaders → Loaders}/Overall/constants.mjs +1 -1
- package/dist/pages/Loaders/Overall/constants.mjs.map +1 -0
- package/dist/pages/Loaders/Overall/index.mjs.map +1 -0
- package/dist/pages/Loaders/constants.d.ts +2 -0
- package/dist/pages/{WebpackLoaders → Loaders}/constants.mjs +1 -1
- package/dist/pages/Loaders/constants.mjs.map +1 -0
- package/dist/pages/{WebpackPlugins → Plugins}/constants.d.ts +1 -1
- package/dist/pages/{WebpackPlugins → Plugins}/constants.mjs +1 -1
- package/dist/pages/Plugins/constants.mjs.map +1 -0
- package/dist/pages/Plugins/index.css.map +1 -0
- package/dist/pages/{WebpackPlugins → Plugins}/index.mjs +2 -2
- package/dist/pages/Plugins/index.mjs.map +1 -0
- package/dist/pages/Resources/BundleDiff/DiffContainer/modules.mjs +2 -2
- package/dist/pages/Resources/BundleDiff/DiffContainer/modules.mjs.map +1 -1
- package/dist/pages/Resources/BundleDiff/DiffContainer/row.mjs +1 -1
- package/dist/pages/Resources/BundleDiff/DiffContainer/row.mjs.map +1 -1
- package/dist/pages/index.d.ts +3 -3
- package/dist/pages/index.mjs +4 -4
- package/dist/utils/data/base.d.ts +2 -2
- package/dist/utils/data/base.mjs.map +1 -1
- package/dist/utils/data/local.d.ts +10 -3
- package/dist/utils/data/local.mjs +37 -24
- package/dist/utils/data/local.mjs.map +1 -1
- package/dist/utils/data/local.test.d.ts +1 -0
- package/dist/utils/data/local.test.mjs +89 -0
- package/dist/utils/data/local.test.mjs.map +1 -0
- package/dist/utils/hooks.d.ts +1 -1
- package/dist/utils/request.mjs +4 -3
- package/dist/utils/request.mjs.map +1 -1
- package/dist/utils/request.test.mjs +23 -0
- package/dist/utils/request.test.mjs.map +1 -1
- package/dist/utils/routes.mjs +1 -1
- package/dist/utils/routes.mjs.map +1 -1
- package/dist/utils/socket.d.ts +12 -2
- package/dist/utils/socket.mjs +155 -23
- package/dist/utils/socket.mjs.map +1 -1
- package/dist/utils/socket.test.d.ts +1 -0
- package/dist/utils/socket.test.mjs +167 -0
- package/dist/utils/socket.test.mjs.map +1 -0
- package/package.json +5 -6
- package/dist/components/Plugins/webpack.d.ts +0 -18
- package/dist/components/Plugins/webpack.mjs.map +0 -1
- package/dist/pages/WebpackLoaders/Analysis/constants.mjs.map +0 -1
- package/dist/pages/WebpackLoaders/Analysis/index.mjs.map +0 -1
- package/dist/pages/WebpackLoaders/Overall/constants.mjs.map +0 -1
- package/dist/pages/WebpackLoaders/Overall/index.mjs.map +0 -1
- package/dist/pages/WebpackLoaders/constants.d.ts +0 -2
- package/dist/pages/WebpackLoaders/constants.mjs.map +0 -1
- package/dist/pages/WebpackPlugins/constants.mjs.map +0 -1
- package/dist/pages/WebpackPlugins/index.css.map +0 -1
- package/dist/pages/WebpackPlugins/index.mjs.map +0 -1
- /package/dist/pages/{WebpackLoaders → Loaders}/Analysis/index.d.ts +0 -0
- /package/dist/pages/{WebpackLoaders → Loaders}/Analysis/index.mjs +0 -0
- /package/dist/pages/{WebpackLoaders → Loaders}/Overall/index.d.ts +0 -0
- /package/dist/pages/{WebpackLoaders → Loaders}/Overall/index.mjs +0 -0
- /package/dist/pages/{WebpackPlugins → Plugins}/index.css +0 -0
- /package/dist/pages/{WebpackPlugins → Plugins}/index.d.ts +0 -0
package/dist/utils/socket.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { SDK } from '@rsdoctor/types';
|
|
2
|
+
type SocketAPI = SDK.ServerAPI.API | SDK.ServerAPI.APIExtends;
|
|
3
|
+
export interface ServerSocketMessage<T extends SocketAPI = SocketAPI> {
|
|
4
|
+
api: T;
|
|
5
|
+
payload: SDK.ServerAPI.SocketResponseType<T>;
|
|
6
|
+
}
|
|
7
|
+
type SocketListener<T extends SocketAPI = SocketAPI> = (payload: SDK.ServerAPI.SocketResponseType<T>) => void;
|
|
8
|
+
export declare function requestServerAPI<T extends SDK.ServerAPI.API, B extends SDK.ServerAPI.InferRequestBodyType<T> = SDK.ServerAPI.InferRequestBodyType<T>, R extends SDK.ServerAPI.InferResponseType<T> = SDK.ServerAPI.InferResponseType<T>>(api: T, body: B | null | undefined, socketPort?: string): Promise<R>;
|
|
9
|
+
export declare function subscribeServerAPI<T extends SocketAPI>(api: T, body: SDK.ServerAPI.InferRequestBodyType<T, null> | null, listener: SocketListener<T>, socketPort?: string): () => void;
|
|
10
|
+
export declare function unsubscribeServerAPI<T extends SocketAPI>(api: T, body: SDK.ServerAPI.InferRequestBodyType<T, null> | null, listener: SocketListener<T>, socketPort?: string): void;
|
|
11
|
+
export declare function publishServerSocketMessage(message: ServerSocketMessage, socketUrl?: string): void;
|
|
3
12
|
export declare function formatURL({ port, protocol, hostname, }: {
|
|
4
13
|
port?: string;
|
|
5
14
|
protocol: string;
|
|
6
15
|
hostname: string;
|
|
7
16
|
}): string;
|
|
17
|
+
export {};
|
package/dist/utils/socket.mjs
CHANGED
|
@@ -1,38 +1,170 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
1
|
+
const clients = new Map();
|
|
2
|
+
const defaultClientKey = '__default__';
|
|
3
|
+
const openState = 1;
|
|
4
|
+
let requestId = 0;
|
|
5
5
|
const ipv4Pattern = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
const socket = io(socketUrl, {});
|
|
9
|
-
socket.on('connect', ()=>{
|
|
10
|
-
console.log(`Socket Connect ${socketUrl}`);
|
|
11
|
-
});
|
|
12
|
-
map.set(socketUrl, socket);
|
|
13
|
-
}
|
|
14
|
-
return map.get(socketUrl);
|
|
6
|
+
function getSocketProtocol(protocol) {
|
|
7
|
+
return protocol.includes('https') ? 'wss' : 'ws';
|
|
15
8
|
}
|
|
16
|
-
function
|
|
17
|
-
|
|
9
|
+
function getDefaultSocketUrl() {
|
|
10
|
+
if ("u" < typeof location) return '';
|
|
11
|
+
const socketProtocol = getSocketProtocol(location.protocol);
|
|
12
|
+
return 'development' === process.env.NODE_ENV ? `${socketProtocol}://${location.hostname}:${process.env.LOCAL_CLI_PORT}` : `${socketProtocol}://${location.host}`;
|
|
13
|
+
}
|
|
14
|
+
function getSocketUrl(socketPort) {
|
|
15
|
+
if ("u" < typeof location) return socketPort ? `ws://localhost:${socketPort}` : '';
|
|
16
|
+
return socketPort ? formatURL({
|
|
18
17
|
port: socketPort,
|
|
19
18
|
hostname: location.hostname,
|
|
20
19
|
protocol: location.protocol
|
|
20
|
+
}) : getDefaultSocketUrl();
|
|
21
|
+
}
|
|
22
|
+
function getClient(socketUrl = getDefaultSocketUrl()) {
|
|
23
|
+
const key = socketUrl || defaultClientKey;
|
|
24
|
+
if (!clients.has(key)) clients.set(key, {
|
|
25
|
+
url: socketUrl,
|
|
26
|
+
listeners: new Map(),
|
|
27
|
+
subscriptions: new Map(),
|
|
28
|
+
requests: new Map()
|
|
29
|
+
});
|
|
30
|
+
return clients.get(key);
|
|
31
|
+
}
|
|
32
|
+
function getSubscriptionKey(api, body) {
|
|
33
|
+
return `${api}:${JSON.stringify(body ?? null)}`;
|
|
34
|
+
}
|
|
35
|
+
function sendSubscription(client, subscription) {
|
|
36
|
+
if (client.socket?.readyState !== openState) return;
|
|
37
|
+
client.socket.send(JSON.stringify({
|
|
38
|
+
type: 'subscribe',
|
|
39
|
+
api: subscription.api,
|
|
40
|
+
body: subscription.body ?? null
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
function sendUnsubscribe(client, subscription) {
|
|
44
|
+
if (client.socket?.readyState !== openState) return;
|
|
45
|
+
client.socket.send(JSON.stringify({
|
|
46
|
+
type: 'unsubscribe',
|
|
47
|
+
api: subscription.api,
|
|
48
|
+
body: subscription.body ?? null
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
function sendRequest(client, id) {
|
|
52
|
+
if (client.socket?.readyState !== openState) return;
|
|
53
|
+
const request = client.requests.get(id);
|
|
54
|
+
if (!request) return;
|
|
55
|
+
client.socket.send(request.message);
|
|
56
|
+
}
|
|
57
|
+
function handleResponseMessage(client, message) {
|
|
58
|
+
const request = client.requests.get(message.id);
|
|
59
|
+
if (!request) return;
|
|
60
|
+
client.requests.delete(message.id);
|
|
61
|
+
if (message.error) return void request.reject(new Error(message.error));
|
|
62
|
+
request.resolve(message.payload);
|
|
63
|
+
}
|
|
64
|
+
function connectSocket(client) {
|
|
65
|
+
if (!client.url || "u" < typeof WebSocket || client.socket) return;
|
|
66
|
+
const socket = new WebSocket(client.url);
|
|
67
|
+
socket.addEventListener('open', ()=>{
|
|
68
|
+
client.subscriptions.forEach((subscription)=>{
|
|
69
|
+
sendSubscription(client, subscription);
|
|
70
|
+
});
|
|
71
|
+
client.requests.forEach((_, id)=>{
|
|
72
|
+
sendRequest(client, id);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
socket.addEventListener('message', (event)=>{
|
|
76
|
+
if ('string' != typeof event.data) return;
|
|
77
|
+
try {
|
|
78
|
+
const message = JSON.parse(event.data);
|
|
79
|
+
if ('type' in message && 'response' === message.type) return void handleResponseMessage(client, message);
|
|
80
|
+
publishServerSocketMessage(message, client.url);
|
|
81
|
+
} catch {}
|
|
82
|
+
});
|
|
83
|
+
socket.addEventListener('close', ()=>{
|
|
84
|
+
client.socket = void 0;
|
|
85
|
+
client.requests.forEach((request)=>{
|
|
86
|
+
request.reject(new Error('WebSocket closed before the response arrived.'));
|
|
87
|
+
});
|
|
88
|
+
client.requests.clear();
|
|
89
|
+
});
|
|
90
|
+
client.socket = socket;
|
|
91
|
+
}
|
|
92
|
+
function requestServerAPI(api, body, socketPort) {
|
|
93
|
+
const socketUrl = getSocketUrl(socketPort);
|
|
94
|
+
if (!socketUrl) return Promise.reject(new Error('WebSocket URL is not available.'));
|
|
95
|
+
if ("u" < typeof WebSocket) return Promise.reject(new Error('WebSocket is not available.'));
|
|
96
|
+
const client = getClient(socketUrl);
|
|
97
|
+
const id = `${Date.now()}-${++requestId}`;
|
|
98
|
+
return new Promise((resolve, reject)=>{
|
|
99
|
+
client.requests.set(id, {
|
|
100
|
+
message: JSON.stringify({
|
|
101
|
+
type: 'request',
|
|
102
|
+
id,
|
|
103
|
+
api,
|
|
104
|
+
body: body ?? null
|
|
105
|
+
}),
|
|
106
|
+
resolve: resolve,
|
|
107
|
+
reject
|
|
108
|
+
});
|
|
109
|
+
connectSocket(client);
|
|
110
|
+
sendRequest(client, id);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function subscribeServerAPI(api, body, listener, socketPort) {
|
|
114
|
+
const client = getClient(getSocketUrl(socketPort));
|
|
115
|
+
const bodyValue = body ?? null;
|
|
116
|
+
const key = getSubscriptionKey(api, bodyValue);
|
|
117
|
+
if (!client.listeners.has(key)) client.listeners.set(key, new Set());
|
|
118
|
+
client.listeners.get(key).add(listener);
|
|
119
|
+
const subscription = {
|
|
120
|
+
api,
|
|
121
|
+
body: bodyValue
|
|
122
|
+
};
|
|
123
|
+
client.subscriptions.set(key, subscription);
|
|
124
|
+
connectSocket(client);
|
|
125
|
+
sendSubscription(client, subscription);
|
|
126
|
+
return ()=>{
|
|
127
|
+
unsubscribeServerAPI(api, bodyValue, listener, socketPort);
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function unsubscribeServerAPI(api, body, listener, socketPort) {
|
|
131
|
+
const client = getClient(getSocketUrl(socketPort));
|
|
132
|
+
const key = getSubscriptionKey(api, body);
|
|
133
|
+
const listeners = client.listeners.get(key);
|
|
134
|
+
listeners?.delete(listener);
|
|
135
|
+
if (listeners?.size === 0) {
|
|
136
|
+
const subscription = client.subscriptions.get(key);
|
|
137
|
+
if (subscription) sendUnsubscribe(client, subscription);
|
|
138
|
+
client.listeners.delete(key);
|
|
139
|
+
client.subscriptions.delete(key);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function publishServerSocketMessage(message, socketUrl) {
|
|
143
|
+
const targets = socketUrl ? [
|
|
144
|
+
getClient(socketUrl)
|
|
145
|
+
] : [
|
|
146
|
+
...clients.values()
|
|
147
|
+
];
|
|
148
|
+
targets.forEach((client)=>{
|
|
149
|
+
const key = getSubscriptionKey(message.api, message.payload.req.body);
|
|
150
|
+
client.listeners.get(key)?.forEach((listener)=>{
|
|
151
|
+
listener(message.payload);
|
|
152
|
+
});
|
|
21
153
|
});
|
|
22
|
-
const socket = ensureSocket(socketPort ? socketUrl : defaultSocketUrl);
|
|
23
|
-
return socket;
|
|
24
154
|
}
|
|
25
155
|
function formatURL({ port, protocol, hostname }) {
|
|
156
|
+
const socketProtocol = getSocketProtocol(protocol);
|
|
157
|
+
const shouldUsePort = ipv4Pattern.test(hostname) || hostname.includes('localhost');
|
|
26
158
|
if ("u" > typeof URL) {
|
|
27
159
|
const url = new URL('http://localhost');
|
|
28
|
-
url.port = String(port);
|
|
29
160
|
url.hostname = hostname;
|
|
30
|
-
url.protocol =
|
|
31
|
-
|
|
161
|
+
url.protocol = socketProtocol;
|
|
162
|
+
if (port && shouldUsePort) url.port = port;
|
|
163
|
+
return url.toString();
|
|
32
164
|
}
|
|
33
|
-
const
|
|
34
|
-
return `${
|
|
165
|
+
const portText = port && shouldUsePort ? `:${port}` : '';
|
|
166
|
+
return `${socketProtocol}://${hostname}${portText}`;
|
|
35
167
|
}
|
|
36
|
-
export { formatURL,
|
|
168
|
+
export { formatURL, publishServerSocketMessage, requestServerAPI, subscribeServerAPI, unsubscribeServerAPI };
|
|
37
169
|
|
|
38
170
|
//# sourceMappingURL=socket.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils/socket.mjs","sources":["../../src/utils/socket.ts"],"sourcesContent":["/* rslint-disable no-restricted-globals */\nimport { io, Socket } from 'socket.io-client';\n\nconst map = new Map<string, Socket>();\nconst socketProtocol = location.protocol.includes('https') ? 'wss' : 'ws';\nconst defaultSocketUrl =\n process.env.NODE_ENV === 'development'\n ? `${socketProtocol}://${location.hostname}:${process.env.LOCAL_CLI_PORT}`\n : `${socketProtocol}://${location.host}`;\n\nconst ipv4Pattern =\n /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\nfunction ensureSocket(socketUrl: string = defaultSocketUrl) {\n if (!map.has(socketUrl)) {\n const socket = io(socketUrl, {});\n socket.on('connect', () => {\n console.log(`Socket Connect ${socketUrl}`);\n });\n map.set(socketUrl, socket);\n }\n return map.get(socketUrl)!;\n}\n\nexport function getSocket(socketPort?: string): Socket {\n const socketUrl = formatURL({\n port: socketPort,\n hostname: location.hostname,\n protocol: location.protocol,\n });\n const socket = ensureSocket(socketPort ? socketUrl : defaultSocketUrl);\n return socket;\n}\n\nexport function formatURL({\n port,\n protocol,\n hostname,\n}: {\n port?: string;\n protocol: string;\n hostname: string;\n}) {\n if (typeof URL !== 'undefined') {\n const url = new URL('http://localhost');\n url.port = String(port);\n url.hostname = hostname;\n url.protocol = location.protocol.includes('https') ? 'wss' : 'ws';\n return ipv4Pattern.test(hostname) || hostname.includes('localhost')\n ? url.toString()\n : `${protocol}//${hostname}`;\n }\n\n // compatible with IE11\n const colon = protocol.indexOf(':') === -1 ? ':' : '';\n return `${protocol}${colon}//${hostname}:${port}`;\n}\n"],"names":["map","Map","socketProtocol","location","defaultSocketUrl","process","ipv4Pattern","ensureSocket","socketUrl","socket","io","console","getSocket","socketPort","formatURL","port","protocol","hostname","URL","url","String","colon"],"mappings":";AAGA,MAAMA,MAAM,IAAIC;AAChB,MAAMC,iBAAiBC,SAAS,QAAQ,CAAC,QAAQ,CAAC,WAAW,QAAQ;AACrE,MAAMC,mBACJC,AAAyB,kBAAzBA,QAAQ,GAAG,CAAC,QAAQ,GAChB,GAAGH,eAAe,GAAG,EAAEC,SAAS,QAAQ,CAAC,CAAC,EAAEE,QAAQ,GAAG,CAAC,cAAc,EAAE,GACxE,GAAGH,eAAe,GAAG,EAAEC,SAAS,IAAI,EAAE;AAE5C,MAAMG,cACJ;AAEF,SAASC,aAAaC,YAAoBJ,gBAAgB;IACxD,IAAI,CAACJ,IAAI,GAAG,CAACQ,YAAY;QACvB,MAAMC,SAASC,GAAGF,WAAW,CAAC;QAC9BC,OAAO,EAAE,CAAC,WAAW;YACnBE,QAAQ,GAAG,CAAC,CAAC,eAAe,EAAEH,WAAW;QAC3C;QACAR,IAAI,GAAG,CAACQ,WAAWC;IACrB;IACA,OAAOT,IAAI,GAAG,CAACQ;AACjB;AAEO,SAASI,UAAUC,UAAmB;IAC3C,MAAML,YAAYM,UAAU;QAC1B,MAAMD;QACN,UAAUV,SAAS,QAAQ;QAC3B,UAAUA,SAAS,QAAQ;IAC7B;IACA,MAAMM,SAASF,aAAaM,aAAaL,YAAYJ;IACrD,OAAOK;AACT;AAEO,SAASK,UAAU,EACxBC,IAAI,EACJC,QAAQ,EACRC,QAAQ,EAKT;IACC,IAAI,AAAe,MAAf,OAAOC,KAAqB;QAC9B,MAAMC,MAAM,IAAID,IAAI;QACpBC,IAAI,IAAI,GAAGC,OAAOL;QAClBI,IAAI,QAAQ,GAAGF;QACfE,IAAI,QAAQ,GAAGhB,SAAS,QAAQ,CAAC,QAAQ,CAAC,WAAW,QAAQ;QAC7D,OAAOG,YAAY,IAAI,CAACW,aAAaA,SAAS,QAAQ,CAAC,eACnDE,IAAI,QAAQ,KACZ,GAAGH,SAAS,EAAE,EAAEC,UAAU;IAChC;IAGA,MAAMI,QAAQL,AAA0B,OAA1BA,SAAS,OAAO,CAAC,OAAc,MAAM;IACnD,OAAO,GAAGA,WAAWK,MAAM,EAAE,EAAEJ,SAAS,CAAC,EAAEF,MAAM;AACnD"}
|
|
1
|
+
{"version":3,"file":"utils/socket.mjs","sources":["../../src/utils/socket.ts"],"sourcesContent":["/* rslint-disable no-restricted-globals */\nimport type { Common, SDK } from '@rsdoctor/types';\n\ntype SocketAPI = SDK.ServerAPI.API | SDK.ServerAPI.APIExtends;\n\nexport interface ServerSocketMessage<T extends SocketAPI = SocketAPI> {\n api: T;\n payload: SDK.ServerAPI.SocketResponseType<T>;\n}\n\ntype ServerSocketResponseMessage<\n T extends SDK.ServerAPI.API = SDK.ServerAPI.API,\n> = {\n type: 'response';\n id: string;\n payload?: SDK.ServerAPI.InferResponseType<T>;\n error?: string;\n};\n\ntype SocketListener<T extends SocketAPI = SocketAPI> = (\n payload: SDK.ServerAPI.SocketResponseType<T>,\n) => void;\n\ntype Subscription = {\n api: SocketAPI;\n body: Common.PlainObject | null | undefined;\n};\n\ntype PendingRequest = {\n message: string;\n resolve: (payload: unknown) => void;\n reject: (error: Error) => void;\n};\n\ntype SocketClient = {\n url: string;\n socket?: WebSocket;\n listeners: Map<string, Set<SocketListener>>;\n subscriptions: Map<string, Subscription>;\n requests: Map<string, PendingRequest>;\n};\n\nconst clients = new Map<string, SocketClient>();\nconst defaultClientKey = '__default__';\nconst openState = 1;\nlet requestId = 0;\n\nconst ipv4Pattern =\n /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\nfunction getSocketProtocol(protocol: string) {\n return protocol.includes('https') ? 'wss' : 'ws';\n}\n\nfunction getDefaultSocketUrl() {\n if (typeof location === 'undefined') {\n return '';\n }\n\n const socketProtocol = getSocketProtocol(location.protocol);\n return process.env.NODE_ENV === 'development'\n ? `${socketProtocol}://${location.hostname}:${process.env.LOCAL_CLI_PORT}`\n : `${socketProtocol}://${location.host}`;\n}\n\nfunction getSocketUrl(socketPort?: string) {\n if (typeof location === 'undefined') {\n return socketPort ? `ws://localhost:${socketPort}` : '';\n }\n\n return socketPort\n ? formatURL({\n port: socketPort,\n hostname: location.hostname,\n protocol: location.protocol,\n })\n : getDefaultSocketUrl();\n}\n\nfunction getClient(socketUrl = getDefaultSocketUrl()) {\n const key = socketUrl || defaultClientKey;\n if (!clients.has(key)) {\n clients.set(key, {\n url: socketUrl,\n listeners: new Map(),\n subscriptions: new Map(),\n requests: new Map(),\n });\n }\n return clients.get(key)!;\n}\n\nfunction getSubscriptionKey(api: SocketAPI, body: unknown) {\n return `${api}:${JSON.stringify(body ?? null)}`;\n}\n\nfunction sendSubscription(client: SocketClient, subscription: Subscription) {\n if (client.socket?.readyState !== openState) {\n return;\n }\n\n client.socket.send(\n JSON.stringify({\n type: 'subscribe',\n api: subscription.api,\n body: subscription.body ?? null,\n }),\n );\n}\n\nfunction sendUnsubscribe(client: SocketClient, subscription: Subscription) {\n if (client.socket?.readyState !== openState) {\n return;\n }\n\n client.socket.send(\n JSON.stringify({\n type: 'unsubscribe',\n api: subscription.api,\n body: subscription.body ?? null,\n }),\n );\n}\n\nfunction sendRequest(client: SocketClient, id: string) {\n if (client.socket?.readyState !== openState) {\n return;\n }\n\n const request = client.requests.get(id);\n if (!request) {\n return;\n }\n client.socket.send(request.message);\n}\n\nfunction handleResponseMessage(\n client: SocketClient,\n message: ServerSocketResponseMessage,\n) {\n const request = client.requests.get(message.id);\n if (!request) {\n return;\n }\n\n client.requests.delete(message.id);\n if (message.error) {\n request.reject(new Error(message.error));\n return;\n }\n request.resolve(message.payload);\n}\n\nfunction connectSocket(client: SocketClient) {\n if (!client.url || typeof WebSocket === 'undefined' || client.socket) {\n return;\n }\n\n const socket = new WebSocket(client.url);\n socket.addEventListener('open', () => {\n client.subscriptions.forEach((subscription) => {\n sendSubscription(client, subscription);\n });\n client.requests.forEach((_, id) => {\n sendRequest(client, id);\n });\n });\n socket.addEventListener('message', (event) => {\n if (typeof event.data !== 'string') {\n return;\n }\n\n try {\n const message = JSON.parse(event.data) as\n | ServerSocketMessage\n | ServerSocketResponseMessage;\n if ('type' in message && message.type === 'response') {\n handleResponseMessage(client, message);\n return;\n }\n publishServerSocketMessage(message as ServerSocketMessage, client.url);\n } catch {\n // Ignore malformed payloads and keep the transport alive.\n }\n });\n socket.addEventListener('close', () => {\n client.socket = undefined;\n client.requests.forEach((request) => {\n request.reject(\n new Error('WebSocket closed before the response arrived.'),\n );\n });\n client.requests.clear();\n });\n client.socket = socket;\n}\n\nexport function requestServerAPI<\n T extends SDK.ServerAPI.API,\n B extends SDK.ServerAPI.InferRequestBodyType<T> =\n SDK.ServerAPI.InferRequestBodyType<T>,\n R extends SDK.ServerAPI.InferResponseType<T> =\n SDK.ServerAPI.InferResponseType<T>,\n>(api: T, body: B | null | undefined, socketPort?: string): Promise<R> {\n const socketUrl = getSocketUrl(socketPort);\n if (!socketUrl) {\n return Promise.reject(new Error('WebSocket URL is not available.'));\n }\n\n if (typeof WebSocket === 'undefined') {\n return Promise.reject(new Error('WebSocket is not available.'));\n }\n\n const client = getClient(socketUrl);\n const id = `${Date.now()}-${++requestId}`;\n\n return new Promise<R>((resolve, reject) => {\n client.requests.set(id, {\n message: JSON.stringify({\n type: 'request',\n id,\n api,\n body: body ?? null,\n }),\n resolve: resolve as (payload: unknown) => void,\n reject,\n });\n connectSocket(client);\n sendRequest(client, id);\n });\n}\n\nexport function subscribeServerAPI<T extends SocketAPI>(\n api: T,\n body: SDK.ServerAPI.InferRequestBodyType<T, null> | null,\n listener: SocketListener<T>,\n socketPort?: string,\n) {\n const client = getClient(getSocketUrl(socketPort));\n const bodyValue = body ?? null;\n const key = getSubscriptionKey(api, bodyValue);\n if (!client.listeners.has(key)) {\n client.listeners.set(key, new Set());\n }\n client.listeners.get(key)!.add(listener as SocketListener);\n\n const subscription = {\n api,\n body: bodyValue,\n };\n client.subscriptions.set(key, subscription);\n connectSocket(client);\n sendSubscription(client, subscription);\n\n return () => {\n unsubscribeServerAPI(api, bodyValue, listener, socketPort);\n };\n}\n\nexport function unsubscribeServerAPI<T extends SocketAPI>(\n api: T,\n body: SDK.ServerAPI.InferRequestBodyType<T, null> | null,\n listener: SocketListener<T>,\n socketPort?: string,\n) {\n const client = getClient(getSocketUrl(socketPort));\n const key = getSubscriptionKey(api, body);\n const listeners = client.listeners.get(key);\n listeners?.delete(listener as SocketListener);\n\n if (listeners?.size === 0) {\n const subscription = client.subscriptions.get(key);\n if (subscription) {\n sendUnsubscribe(client, subscription);\n }\n client.listeners.delete(key);\n client.subscriptions.delete(key);\n }\n}\n\nexport function publishServerSocketMessage(\n message: ServerSocketMessage,\n socketUrl?: string,\n) {\n const targets = socketUrl ? [getClient(socketUrl)] : [...clients.values()];\n\n targets.forEach((client) => {\n const key = getSubscriptionKey(message.api, message.payload.req.body);\n client.listeners.get(key)?.forEach((listener) => {\n listener(message.payload);\n });\n });\n}\n\nexport function formatURL({\n port,\n protocol,\n hostname,\n}: {\n port?: string;\n protocol: string;\n hostname: string;\n}) {\n const socketProtocol = getSocketProtocol(protocol);\n const shouldUsePort =\n ipv4Pattern.test(hostname) || hostname.includes('localhost');\n\n if (typeof URL !== 'undefined') {\n const url = new URL('http://localhost');\n url.hostname = hostname;\n url.protocol = socketProtocol;\n if (port && shouldUsePort) {\n url.port = port;\n }\n return url.toString();\n }\n\n const portText = port && shouldUsePort ? `:${port}` : '';\n return `${socketProtocol}://${hostname}${portText}`;\n}\n"],"names":["clients","Map","defaultClientKey","openState","requestId","ipv4Pattern","getSocketProtocol","protocol","getDefaultSocketUrl","location","socketProtocol","process","getSocketUrl","socketPort","formatURL","getClient","socketUrl","key","getSubscriptionKey","api","body","JSON","sendSubscription","client","subscription","sendUnsubscribe","sendRequest","id","request","handleResponseMessage","message","Error","connectSocket","WebSocket","socket","_","event","publishServerSocketMessage","undefined","requestServerAPI","Promise","Date","resolve","reject","subscribeServerAPI","listener","bodyValue","Set","unsubscribeServerAPI","listeners","targets","port","hostname","shouldUsePort","URL","url","portText"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, rs } from "@rstest/core";
|
|
2
|
+
import { SDK } from "@rsdoctor/types";
|
|
3
|
+
import { formatURL, publishServerSocketMessage, requestServerAPI, subscribeServerAPI } from "./socket.mjs";
|
|
4
|
+
function _define_property(obj, key, value) {
|
|
5
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
6
|
+
value: value,
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
writable: true
|
|
10
|
+
});
|
|
11
|
+
else obj[key] = value;
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
class MockWebSocket {
|
|
15
|
+
addEventListener(event, listener) {
|
|
16
|
+
if (!this.listeners.has(event)) this.listeners.set(event, new Set());
|
|
17
|
+
this.listeners.get(event).add(listener);
|
|
18
|
+
}
|
|
19
|
+
send(message) {
|
|
20
|
+
this.sentMessages.push(message);
|
|
21
|
+
}
|
|
22
|
+
trigger(event, data) {
|
|
23
|
+
if ('open' === event) this.readyState = 1;
|
|
24
|
+
this.listeners.get(event)?.forEach((listener)=>listener(void 0 === data ? void 0 : {
|
|
25
|
+
data
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
constructor(url){
|
|
29
|
+
_define_property(this, "url", void 0);
|
|
30
|
+
_define_property(this, "readyState", void 0);
|
|
31
|
+
_define_property(this, "sentMessages", void 0);
|
|
32
|
+
_define_property(this, "listeners", void 0);
|
|
33
|
+
this.url = url;
|
|
34
|
+
this.readyState = 0;
|
|
35
|
+
this.sentMessages = [];
|
|
36
|
+
this.listeners = new Map();
|
|
37
|
+
MockWebSocket.instances.push(this);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
_define_property(MockWebSocket, "instances", []);
|
|
41
|
+
describe('websocket transport', ()=>{
|
|
42
|
+
const originalLocation = globalThis.location;
|
|
43
|
+
const originalWebSocket = globalThis.WebSocket;
|
|
44
|
+
afterEach(()=>{
|
|
45
|
+
rs.restoreAllMocks();
|
|
46
|
+
Object.defineProperty(globalThis, 'location', {
|
|
47
|
+
configurable: true,
|
|
48
|
+
value: originalLocation
|
|
49
|
+
});
|
|
50
|
+
globalThis.WebSocket = originalWebSocket;
|
|
51
|
+
MockWebSocket.instances = [];
|
|
52
|
+
});
|
|
53
|
+
it('dispatches server push payloads to subscribers by api', ()=>{
|
|
54
|
+
const callback = rs.fn();
|
|
55
|
+
const api = SDK.ServerAPI.APIExtends.GetCompileProgress;
|
|
56
|
+
const unsubscribe = subscribeServerAPI(api, null, callback);
|
|
57
|
+
publishServerSocketMessage({
|
|
58
|
+
api,
|
|
59
|
+
payload: {
|
|
60
|
+
req: {
|
|
61
|
+
api,
|
|
62
|
+
body: void 0
|
|
63
|
+
},
|
|
64
|
+
res: {
|
|
65
|
+
percentage: 50,
|
|
66
|
+
message: 'building'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
expect(callback).toHaveBeenCalledWith({
|
|
71
|
+
req: {
|
|
72
|
+
api,
|
|
73
|
+
body: void 0
|
|
74
|
+
},
|
|
75
|
+
res: {
|
|
76
|
+
percentage: 50,
|
|
77
|
+
message: 'building'
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
unsubscribe();
|
|
81
|
+
});
|
|
82
|
+
it('formats non-localhost socket urls with websocket protocol', ()=>{
|
|
83
|
+
expect(formatURL({
|
|
84
|
+
port: '3000',
|
|
85
|
+
protocol: 'https:',
|
|
86
|
+
hostname: 'example.com'
|
|
87
|
+
})).toBe('wss://example.com/');
|
|
88
|
+
});
|
|
89
|
+
it("removes subscriptions when the last listener unsubscribes", ()=>{
|
|
90
|
+
globalThis.WebSocket = MockWebSocket;
|
|
91
|
+
const api = SDK.ServerAPI.API.GetModuleByName;
|
|
92
|
+
const body = {
|
|
93
|
+
name: 'foo'
|
|
94
|
+
};
|
|
95
|
+
const unsubscribe = subscribeServerAPI(api, body, rs.fn(), '3081');
|
|
96
|
+
const staleSocket = MockWebSocket.instances[0];
|
|
97
|
+
unsubscribe();
|
|
98
|
+
staleSocket.trigger('close');
|
|
99
|
+
subscribeServerAPI(SDK.ServerAPI.API.GetProjectInfo, null, rs.fn(), '3081');
|
|
100
|
+
const reconnectedSocket = MockWebSocket.instances[1];
|
|
101
|
+
reconnectedSocket.trigger('open');
|
|
102
|
+
expect(reconnectedSocket.sentMessages.map((message)=>JSON.parse(message))).toStrictEqual([
|
|
103
|
+
{
|
|
104
|
+
type: 'subscribe',
|
|
105
|
+
api: SDK.ServerAPI.API.GetProjectInfo,
|
|
106
|
+
body: null
|
|
107
|
+
}
|
|
108
|
+
]);
|
|
109
|
+
});
|
|
110
|
+
it('sends unsubscribe messages when the last listener unsubscribes', ()=>{
|
|
111
|
+
globalThis.WebSocket = MockWebSocket;
|
|
112
|
+
const api = SDK.ServerAPI.API.GetModuleByName;
|
|
113
|
+
const body = {
|
|
114
|
+
name: 'foo'
|
|
115
|
+
};
|
|
116
|
+
const unsubscribe = subscribeServerAPI(api, body, rs.fn(), '3084');
|
|
117
|
+
const socket = MockWebSocket.instances[0];
|
|
118
|
+
socket.trigger('open');
|
|
119
|
+
unsubscribe();
|
|
120
|
+
expect(socket.sentMessages.map((message)=>JSON.parse(message))).toContainEqual({
|
|
121
|
+
type: 'unsubscribe',
|
|
122
|
+
api,
|
|
123
|
+
body
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
it('resolves request responses sent over websocket', async ()=>{
|
|
127
|
+
globalThis.WebSocket = MockWebSocket;
|
|
128
|
+
const request = requestServerAPI(SDK.ServerAPI.API.GetAllModuleGraph, {}, '3082');
|
|
129
|
+
const socket = MockWebSocket.instances[0];
|
|
130
|
+
socket.trigger('open');
|
|
131
|
+
const [message] = socket.sentMessages.map((item)=>JSON.parse(item));
|
|
132
|
+
expect(message).toMatchObject({
|
|
133
|
+
type: 'request',
|
|
134
|
+
api: SDK.ServerAPI.API.GetAllModuleGraph,
|
|
135
|
+
body: {}
|
|
136
|
+
});
|
|
137
|
+
expect(message.id).toBeTruthy();
|
|
138
|
+
socket.trigger('message', JSON.stringify({
|
|
139
|
+
type: 'response',
|
|
140
|
+
id: message.id,
|
|
141
|
+
payload: [
|
|
142
|
+
{
|
|
143
|
+
id: 1
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}));
|
|
147
|
+
await expect(request).resolves.toStrictEqual([
|
|
148
|
+
{
|
|
149
|
+
id: 1
|
|
150
|
+
}
|
|
151
|
+
]);
|
|
152
|
+
});
|
|
153
|
+
it('rejects websocket requests when no socket url is available', async ()=>{
|
|
154
|
+
Object.defineProperty(globalThis, 'location', {
|
|
155
|
+
configurable: true,
|
|
156
|
+
value: void 0
|
|
157
|
+
});
|
|
158
|
+
globalThis.WebSocket = MockWebSocket;
|
|
159
|
+
await expect(requestServerAPI(SDK.ServerAPI.API.GetAllModuleGraph, {})).rejects.toThrow('WebSocket URL is not available.');
|
|
160
|
+
});
|
|
161
|
+
it('rejects websocket requests when WebSocket is unavailable', async ()=>{
|
|
162
|
+
globalThis.WebSocket = void 0;
|
|
163
|
+
await expect(requestServerAPI(SDK.ServerAPI.API.GetAllModuleGraph, {}, '3085')).rejects.toThrow('WebSocket is not available.');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=socket.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils/socket.test.mjs","sources":["../../src/utils/socket.test.ts"],"sourcesContent":["import { afterEach, describe, expect, it, rs } from '@rstest/core';\nimport { SDK } from '@rsdoctor/types';\nimport {\n formatURL,\n publishServerSocketMessage,\n requestServerAPI,\n subscribeServerAPI,\n} from './socket';\n\nclass MockWebSocket {\n static instances: MockWebSocket[] = [];\n\n public readyState = 0;\n\n public sentMessages: string[] = [];\n\n private listeners = new Map<\n string,\n Set<(event?: { data: string }) => void>\n >();\n\n constructor(public url: string) {\n MockWebSocket.instances.push(this);\n }\n\n addEventListener(\n event: string,\n listener: (event?: { data: string }) => void,\n ) {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n send(message: string) {\n this.sentMessages.push(message);\n }\n\n trigger(event: string, data?: string) {\n if (event === 'open') {\n this.readyState = 1;\n }\n this.listeners\n .get(event)\n ?.forEach((listener) =>\n listener(data === undefined ? undefined : { data }),\n );\n }\n}\n\ndescribe('websocket transport', () => {\n const originalLocation = globalThis.location;\n const originalWebSocket = globalThis.WebSocket;\n\n afterEach(() => {\n rs.restoreAllMocks();\n Object.defineProperty(globalThis, 'location', {\n configurable: true,\n value: originalLocation,\n });\n globalThis.WebSocket = originalWebSocket;\n MockWebSocket.instances = [];\n });\n\n it('dispatches server push payloads to subscribers by api', () => {\n const callback = rs.fn();\n const api = SDK.ServerAPI.APIExtends.GetCompileProgress;\n const unsubscribe = subscribeServerAPI(api, null, callback);\n\n publishServerSocketMessage({\n api,\n payload: {\n req: { api, body: undefined },\n res: { percentage: 50, message: 'building' },\n },\n });\n\n expect(callback).toHaveBeenCalledWith({\n req: { api, body: undefined },\n res: { percentage: 50, message: 'building' },\n });\n\n unsubscribe();\n });\n\n it('formats non-localhost socket urls with websocket protocol', () => {\n expect(\n formatURL({\n port: '3000',\n protocol: 'https:',\n hostname: 'example.com',\n }),\n ).toBe('wss://example.com/');\n });\n\n it('removes subscriptions when the last listener unsubscribes', () => {\n globalThis.WebSocket = MockWebSocket as any;\n\n const api = SDK.ServerAPI.API.GetModuleByName;\n const body = { name: 'foo' };\n const unsubscribe = subscribeServerAPI(api, body as any, rs.fn(), '3081');\n const staleSocket = MockWebSocket.instances[0];\n\n unsubscribe();\n staleSocket.trigger('close');\n\n subscribeServerAPI(SDK.ServerAPI.API.GetProjectInfo, null, rs.fn(), '3081');\n const reconnectedSocket = MockWebSocket.instances[1];\n reconnectedSocket.trigger('open');\n\n expect(\n reconnectedSocket.sentMessages.map((message) => JSON.parse(message)),\n ).toStrictEqual([\n {\n type: 'subscribe',\n api: SDK.ServerAPI.API.GetProjectInfo,\n body: null,\n },\n ]);\n });\n\n it('sends unsubscribe messages when the last listener unsubscribes', () => {\n globalThis.WebSocket = MockWebSocket as any;\n\n const api = SDK.ServerAPI.API.GetModuleByName;\n const body = { name: 'foo' };\n const unsubscribe = subscribeServerAPI(api, body as any, rs.fn(), '3084');\n const socket = MockWebSocket.instances[0];\n socket.trigger('open');\n\n unsubscribe();\n\n expect(\n socket.sentMessages.map((message) => JSON.parse(message)),\n ).toContainEqual({\n type: 'unsubscribe',\n api,\n body,\n });\n });\n\n it('resolves request responses sent over websocket', async () => {\n globalThis.WebSocket = MockWebSocket as any;\n\n const request = requestServerAPI(\n SDK.ServerAPI.API.GetAllModuleGraph,\n {},\n '3082',\n );\n const socket = MockWebSocket.instances[0];\n socket.trigger('open');\n const [message] = socket.sentMessages.map((item) => JSON.parse(item));\n\n expect(message).toMatchObject({\n type: 'request',\n api: SDK.ServerAPI.API.GetAllModuleGraph,\n body: {},\n });\n expect(message.id).toBeTruthy();\n\n socket.trigger(\n 'message',\n JSON.stringify({\n type: 'response',\n id: message.id,\n payload: [{ id: 1 }],\n }),\n );\n\n await expect(request).resolves.toStrictEqual([{ id: 1 }]);\n });\n\n it('rejects websocket requests when no socket url is available', async () => {\n Object.defineProperty(globalThis, 'location', {\n configurable: true,\n value: undefined,\n });\n globalThis.WebSocket = MockWebSocket as any;\n\n await expect(\n requestServerAPI(SDK.ServerAPI.API.GetAllModuleGraph, {}),\n ).rejects.toThrow('WebSocket URL is not available.');\n });\n\n it('rejects websocket requests when WebSocket is unavailable', async () => {\n globalThis.WebSocket = undefined as any;\n\n await expect(\n requestServerAPI(SDK.ServerAPI.API.GetAllModuleGraph, {}, '3085'),\n ).rejects.toThrow('WebSocket is not available.');\n });\n});\n"],"names":["MockWebSocket","event","listener","Set","message","data","undefined","url","Map","describe","originalLocation","globalThis","originalWebSocket","afterEach","rs","Object","it","callback","api","SDK","unsubscribe","subscribeServerAPI","publishServerSocketMessage","expect","formatURL","body","staleSocket","reconnectedSocket","JSON","socket","request","requestServerAPI","item"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsdoctor/components",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"repository": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@rsbuild/plugin-svgr": "2.0.2",
|
|
45
45
|
"@types/node": "^24.12.3",
|
|
46
46
|
"@types/path-browserify": "1.0.3",
|
|
47
|
-
"@types/react": "^19.2.
|
|
47
|
+
"@types/react": "^19.2.15",
|
|
48
48
|
"@types/react-highlight-words": "^0.20.1",
|
|
49
49
|
"@types/url-parse": "1.4.11",
|
|
50
50
|
"react": "19.2.6",
|
|
@@ -71,11 +71,10 @@
|
|
|
71
71
|
"react-i18next": "12.0.0",
|
|
72
72
|
"react-json-view": "1.21.3",
|
|
73
73
|
"react-markdown": "^9.1.0",
|
|
74
|
-
"socket.io-client": "4.8.1",
|
|
75
74
|
"url-parse": "1.5.10",
|
|
76
|
-
"@rsdoctor/
|
|
77
|
-
"@rsdoctor/
|
|
78
|
-
"@rsdoctor/
|
|
75
|
+
"@rsdoctor/types": "2.0.0-alpha.0",
|
|
76
|
+
"@rsdoctor/utils": "2.0.0-alpha.0",
|
|
77
|
+
"@rsdoctor/graph": "2.0.0-alpha.0"
|
|
79
78
|
},
|
|
80
79
|
"peerDependencies": {
|
|
81
80
|
"react": ">=19",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { SDK } from '@rsdoctor/types';
|
|
3
|
-
interface WebpackPluginsTableDataItem {
|
|
4
|
-
tapName: string;
|
|
5
|
-
hook: string;
|
|
6
|
-
key: string;
|
|
7
|
-
hookData: SDK.PluginHookData[];
|
|
8
|
-
}
|
|
9
|
-
export interface WebpackPluginsDataTableProps {
|
|
10
|
-
dataSource: SDK.ServerAPI.InferResponseType<SDK.ServerAPI.API.GetPluginData>;
|
|
11
|
-
}
|
|
12
|
-
export declare function useWebpackPluginsDataSource(plugin: SDK.PluginData, selectedTapNames: string[], selectedHooks: string[]): {
|
|
13
|
-
dataSource: WebpackPluginsTableDataItem[];
|
|
14
|
-
tapNames: string[];
|
|
15
|
-
hooks: string[];
|
|
16
|
-
};
|
|
17
|
-
export declare const WebpackPluginsDataTable: React.FC<WebpackPluginsDataTableProps>;
|
|
18
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/Plugins/webpack.mjs","sources":["../../../src/components/Plugins/webpack.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { Table, Tooltip } from 'antd';\nimport { sumBy, uniq } from 'es-toolkit/compat';\nimport { SDK } from '@rsdoctor/types';\nimport { formatCosts } from '../../utils';\n\ninterface WebpackPluginsTableDataItem {\n tapName: string;\n hook: string;\n key: string;\n hookData: SDK.PluginHookData[];\n}\nexport interface WebpackPluginsDataTableProps {\n dataSource: SDK.ServerAPI.InferResponseType<SDK.ServerAPI.API.GetPluginData>;\n}\n\nexport function useWebpackPluginsDataSource(\n plugin: SDK.PluginData,\n selectedTapNames: string[],\n selectedHooks: string[],\n) {\n const tapNames = useMemo(\n () =>\n uniq(\n Object.values(plugin)\n .flat()\n .map((e) => e.tapName),\n ),\n [plugin],\n );\n\n const hooks = useMemo(() => Object.keys(plugin), [plugin]);\n\n const dataSource = useMemo(() => {\n if (!tapNames.length) return [];\n\n return tapNames.reduce((total, tapName) => {\n if (selectedTapNames.length && !selectedTapNames.includes(tapName)) {\n return total;\n }\n\n hooks.forEach((hook) => {\n if (selectedHooks.length && !selectedHooks.includes(hook)) {\n return;\n }\n\n const hookData = plugin[hook].filter((e) => e.tapName === tapName);\n if (hookData.length === 0) return;\n total.push({\n tapName,\n hook,\n key: `${tapName}${hook}`,\n hookData,\n });\n });\n\n return total;\n }, [] as WebpackPluginsTableDataItem[]);\n }, [plugin, selectedTapNames, selectedHooks]);\n\n return {\n dataSource,\n tapNames,\n hooks,\n };\n}\n\nexport const WebpackPluginsDataTable: React.FC<\n WebpackPluginsDataTableProps\n> = ({ dataSource }) => {\n return (\n <Table\n dataSource={dataSource}\n rowKey={(v) => `${v.tapName}_${v.hook}`}\n columns={[\n {\n title: `Plugin Tap Name`,\n render: (_v, r) => r.tapName,\n },\n {\n title: `Hook`,\n render: (_v, r) => r.hook,\n },\n {\n title: 'calls',\n render: (_v, r) => (\n <Tooltip\n title={`\"${r.hook}\" has been called ${r.data.length} times by \"${r.tapName}\"`}\n >\n {r.data.length}\n </Tooltip>\n ),\n sorter(a, b) {\n return a.data.length - b.data.length;\n },\n },\n {\n title: 'duration(total)',\n render: (_v, r) => formatCosts(sumBy(r.data, (e) => e.costs)),\n sorter(a, b) {\n return (\n sumBy(a.data, (e) => e.costs) - sumBy(b.data, (e) => e.costs)\n );\n },\n defaultSortOrder: 'descend',\n },\n ]}\n />\n );\n};\n"],"names":["useWebpackPluginsDataSource","plugin","selectedTapNames","selectedHooks","tapNames","useMemo","uniq","Object","e","hooks","dataSource","total","tapName","hook","hookData","WebpackPluginsDataTable","Table","v","_v","r","Tooltip","a","b","formatCosts","sumBy"],"mappings":";;;;;AAgBO,SAASA,4BACdC,MAAsB,EACtBC,gBAA0B,EAC1BC,aAAuB;IAEvB,MAAMC,WAAWC,QACf,IACEC,KACEC,OAAO,MAAM,CAACN,QACX,IAAI,GACJ,GAAG,CAAC,CAACO,IAAMA,EAAE,OAAO,IAE3B;QAACP;KAAO;IAGV,MAAMQ,QAAQJ,QAAQ,IAAME,OAAO,IAAI,CAACN,SAAS;QAACA;KAAO;IAEzD,MAAMS,aAAaL,QAAQ;QACzB,IAAI,CAACD,SAAS,MAAM,EAAE,OAAO,EAAE;QAE/B,OAAOA,SAAS,MAAM,CAAC,CAACO,OAAOC;YAC7B,IAAIV,iBAAiB,MAAM,IAAI,CAACA,iBAAiB,QAAQ,CAACU,UACxD,OAAOD;YAGTF,MAAM,OAAO,CAAC,CAACI;gBACb,IAAIV,cAAc,MAAM,IAAI,CAACA,cAAc,QAAQ,CAACU,OAClD;gBAGF,MAAMC,WAAWb,MAAM,CAACY,KAAK,CAAC,MAAM,CAAC,CAACL,IAAMA,EAAE,OAAO,KAAKI;gBAC1D,IAAIE,AAAoB,MAApBA,SAAS,MAAM,EAAQ;gBAC3BH,MAAM,IAAI,CAAC;oBACTC;oBACAC;oBACA,KAAK,GAAGD,UAAUC,MAAM;oBACxBC;gBACF;YACF;YAEA,OAAOH;QACT,GAAG,EAAE;IACP,GAAG;QAACV;QAAQC;QAAkBC;KAAc;IAE5C,OAAO;QACLO;QACAN;QACAK;IACF;AACF;AAEO,MAAMM,0BAET,CAAC,EAAEL,UAAU,EAAE,GACV,WAAP,GACE,IAACM,OAAKA;QACJ,YAAYN;QACZ,QAAQ,CAACO,IAAM,GAAGA,EAAE,OAAO,CAAC,CAAC,EAAEA,EAAE,IAAI,EAAE;QACvC,SAAS;YACP;gBACE,OAAO;gBACP,QAAQ,CAACC,IAAIC,IAAMA,EAAE,OAAO;YAC9B;YACA;gBACE,OAAO;gBACP,QAAQ,CAACD,IAAIC,IAAMA,EAAE,IAAI;YAC3B;YACA;gBACE,OAAO;gBACP,QAAQ,CAACD,IAAIC,IAAAA,WAAAA,GACX,IAACC,SAAOA;wBACN,OAAO,CAAC,CAAC,EAAED,EAAE,IAAI,CAAC,kBAAkB,EAAEA,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAEA,EAAE,OAAO,CAAC,CAAC,CAAC;kCAE5EA,EAAE,IAAI,CAAC,MAAM;;gBAGlB,QAAOE,CAAC,EAAEC,CAAC;oBACT,OAAOD,EAAE,IAAI,CAAC,MAAM,GAAGC,EAAE,IAAI,CAAC,MAAM;gBACtC;YACF;YACA;gBACE,OAAO;gBACP,QAAQ,CAACJ,IAAIC,IAAMI,YAAYC,MAAML,EAAE,IAAI,EAAE,CAACX,IAAMA,EAAE,KAAK;gBAC3D,QAAOa,CAAC,EAAEC,CAAC;oBACT,OACEE,MAAMH,EAAE,IAAI,EAAE,CAACb,IAAMA,EAAE,KAAK,IAAIgB,MAAMF,EAAE,IAAI,EAAE,CAACd,IAAMA,EAAE,KAAK;gBAEhE;gBACA,kBAAkB;YACpB;SACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackLoaders/Analysis/constants.mjs","sources":["../../../../src/pages/WebpackLoaders/Analysis/constants.ts"],"sourcesContent":["import { Client } from '@rsdoctor/types';\n\nexport const name = 'Loaders Analysis';\n\nexport const route = Client.RsdoctorClientRoutes.WebpackLoaderAnalysis;\n"],"names":["name","route","Client"],"mappings":";AAEO,MAAMA,iBAAO;AAEb,MAAMC,QAAQC,OAAO,oBAAoB,CAAC,qBAAqB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackLoaders/Analysis/index.mjs","sources":["../../../../src/pages/WebpackLoaders/Analysis/index.tsx"],"sourcesContent":["import React from 'react';\nimport { LoaderAnalysis } from '../../../components/Loader/Analysis';\nimport { WebpackConfigurationViewer } from '../../../components/Configuration';\nimport { Card } from '../../../components/Card';\nimport { Popover, Space, Tag, theme, Typography } from 'antd';\nimport { ExclamationCircleOutlined } from '@ant-design/icons';\nimport { t } from 'i18next';\nconst { useToken } = theme;\n\nexport const Page: React.FC = () => {\n const { token } = useToken();\n\n return (\n <Card\n title={\n <Space align=\"baseline\">\n <Typography.Title level={5} style={{ margin: 0 }}>\n Loader Analysis\n </Typography.Title>\n <Popover\n content={\n <div>\n {t('AsyncLoaderInfo')}\n <a\n href=\"https://rsdoctor.rs/guide/more/faq#cssextractrspackplugin-%E7%9A%84-loader-%E8%80%97%E6%97%B6%E8%BF%87%E9%95%BF%E9%97%AE%E9%A2%98\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t('Details')}\n </a>\n </div>\n }\n title=\"Info\"\n >\n <Tag icon={<ExclamationCircleOutlined />} color=\"warning\">\n Info\n </Tag>\n </Popover>\n </Space>\n }\n extra={<WebpackConfigurationViewer defaultKeys={['module', 'resolve']} />}\n bodyStyle={{ paddingTop: token.padding, height: 800 }}\n >\n <LoaderAnalysis />\n </Card>\n );\n};\n\nexport * from './constants';\n"],"names":["useToken","theme","Page","token","Card","Space","Typography","Popover","t","Tag","ExclamationCircleOutlined","WebpackConfigurationViewer","LoaderAnalysis"],"mappings":";;;;;;;;;AAOA,MAAM,EAAEA,UAAAA,QAAQ,EAAE,GAAGC;AAEd,MAAMC,OAAiB;IAC5B,MAAM,EAAEC,KAAK,EAAE,GAAGH;IAElB,OAAO,WAAP,GACE,IAACI,MAAIA;QACH,qBACE,KAACC,OAAKA;YAAC,OAAM;;8BACX,IAACC,WAAW,KAAK;oBAAC,OAAO;oBAAG,OAAO;wBAAE,QAAQ;oBAAE;8BAAG;;8BAGlD,IAACC,SAAOA;oBACN,uBACE,KAAC;;4BACEC,EAAE;0CACH,IAAC;gCACC,MAAK;gCACL,QAAO;gCACP,KAAI;0CAEHA,EAAE;;;;oBAIT,OAAM;8BAEN,kBAACC,KAAGA;wBAAC,oBAAM,IAACC,2BAAyBA,CAAAA;wBAAK,OAAM;kCAAU;;;;;QAMhE,qBAAO,IAACC,4BAA0BA;YAAC,aAAa;gBAAC;gBAAU;aAAU;;QACrE,WAAW;YAAE,YAAYR,MAAM,OAAO;YAAE,QAAQ;QAAI;kBAEpD,kBAACS,gBAAcA,CAAAA;;AAGrB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackLoaders/Overall/constants.mjs","sources":["../../../../src/pages/WebpackLoaders/Overall/constants.ts"],"sourcesContent":["import { Client } from '@rsdoctor/types';\n\nexport const name = 'Loaders Timeline';\n\nexport const route = Client.RsdoctorClientRoutes.WebpackLoaderOverall;\n"],"names":["name","route","Client"],"mappings":";AAEO,MAAMA,iBAAO;AAEb,MAAMC,QAAQC,OAAO,oBAAoB,CAAC,oBAAoB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackLoaders/Overall/index.mjs","sources":["../../../../src/pages/WebpackLoaders/Overall/index.tsx"],"sourcesContent":["import React from 'react';\nimport { WebpackConfigurationViewer } from '../../../components/Configuration';\nimport { Card } from '../../../components/Card';\nimport { LoaderChart } from 'src/components/Charts';\nimport { Popover, Space, Tag, Typography } from 'antd/lib';\nimport { ExclamationCircleOutlined } from '@ant-design/icons';\nimport { useTranslation } from 'react-i18next';\n\nexport const Page: React.FC = () => {\n const { t } = useTranslation();\n return (\n <Card\n title={\n <Space align=\"baseline\">\n <Typography.Title level={5} style={{ margin: 0 }}>\n Loader Timeline\n </Typography.Title>\n <Popover\n content={\n <div>\n {t('AsyncLoaderInfo')}\n <a\n href=\"https://rsdoctor.rs/guide/more/faq#cssextractrspackplugin-%E7%9A%84-loader-%E8%80%97%E6%97%B6%E8%BF%87%E9%95%BF%E9%97%AE%E9%A2%98\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t('Details')}\n </a>\n </div>\n }\n title=\"Info\"\n >\n <Tag icon={<ExclamationCircleOutlined />} color=\"warning\">\n Info\n </Tag>\n </Popover>\n </Space>\n }\n extra={<WebpackConfigurationViewer defaultKeys={['module']} />}\n >\n <LoaderChart />\n </Card>\n );\n};\n\nexport * from './constants';\n"],"names":["Page","t","useTranslation","Card","Space","Typography","Popover","Tag","ExclamationCircleOutlined","WebpackConfigurationViewer","LoaderChart"],"mappings":";;;;;;;;;AAQO,MAAMA,OAAiB;IAC5B,MAAM,EAAEC,CAAC,EAAE,GAAGC;IACd,OAAO,WAAP,GACE,IAACC,MAAIA;QACH,qBACE,KAACC,OAAKA;YAAC,OAAM;;8BACX,IAACC,WAAW,KAAK;oBAAC,OAAO;oBAAG,OAAO;wBAAE,QAAQ;oBAAE;8BAAG;;8BAGlD,IAACC,SAAOA;oBACN,uBACE,KAAC;;4BACEL,EAAE;0CACH,IAAC;gCACC,MAAK;gCACL,QAAO;gCACP,KAAI;0CAEHA,EAAE;;;;oBAIT,OAAM;8BAEN,kBAACM,KAAGA;wBAAC,oBAAM,IAACC,2BAAyBA,CAAAA;wBAAK,OAAM;kCAAU;;;;;QAMhE,qBAAO,IAACC,4BAA0BA;YAAC,aAAa;gBAAC;aAAS;;kBAE1D,kBAACC,aAAWA,CAAAA;;AAGlB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackLoaders/constants.mjs","sources":["../../../src/pages/WebpackLoaders/constants.ts"],"sourcesContent":["export const name = 'Loaders';\n\nexport const route = '/webpack/loaders';\n"],"names":["name","route"],"mappings":"AAAO,MAAMA,iBAAO;AAEb,MAAMC,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackPlugins/constants.mjs","sources":["../../../src/pages/WebpackPlugins/constants.ts"],"sourcesContent":["import { Client } from '@rsdoctor/types';\n\nexport const name = 'Plugins Analysis';\n\nexport const route = Client.RsdoctorClientRoutes.WebpackPlugins;\n"],"names":["name","route","Client"],"mappings":";AAEO,MAAMA,iBAAO;AAEb,MAAMC,QAAQC,OAAO,oBAAoB,CAAC,cAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["webpack://./src/pages/WebpackPlugins/index.scss"],"names":[],"mappings":"AAAA;EACE,YAAY;AACd","sourcesContent":[".plugin-select .ant-select-selector{width:300px}"],"sourceRoot":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pages/WebpackPlugins/index.mjs","sources":["../../../src/pages/WebpackPlugins/index.tsx"],"sourcesContent":["import { ApiOutlined, PartitionOutlined } from '@ant-design/icons';\nimport { SDK } from '@rsdoctor/types';\nimport { Button, Card, Input, Select, Space, Typography } from 'antd';\nimport React, { useState } from 'react';\nimport { WebpackConfigurationViewer } from '../../components/Configuration';\nimport { ServerAPIProvider } from '../../components/Manifest';\nimport { WebpackPluginsDataTable } from '../../components/Plugins/webpack';\nimport { Size } from '../../constants';\nimport './index.scss';\n\nexport const Page: React.FC = () => {\n const [selectedTapNames, setSelectedTapNames] = useState([]);\n const [selectedHooks, setSelectedHooks] = useState([]);\n\n return (\n <div>\n <Card\n title=\"Plugins Overall\"\n bodyStyle={{ paddingTop: Size.BasePadding / 3 }}\n extra={<WebpackConfigurationViewer defaultKeys={['plugins']} />}\n >\n <Space\n direction=\"vertical\"\n style={{ width: '100%', padding: '0 30px' }}\n >\n <ServerAPIProvider api={SDK.ServerAPI.API.GetPluginSummary}>\n {({ hooks, tapNames }) => (\n <Space style={{ marginBottom: Size.BasePadding / 2 }}>\n <Input.Group compact>\n <Button>\n <ApiOutlined />\n <Typography.Text>Plugin Tap Names</Typography.Text>\n </Button>\n <Select\n mode=\"multiple\"\n allowClear\n className=\"plugin-select\"\n style={{ width: 300 }}\n popupMatchSelectWidth\n onChange={(e) => {\n setSelectedTapNames(e);\n }}\n >\n {tapNames.map((e) => {\n return (\n <Select.Option key={e} label={e} value={e}>\n {e}\n </Select.Option>\n );\n })}\n </Select>\n </Input.Group>\n <Input.Group compact>\n <Button>\n <PartitionOutlined />\n <Typography.Text>Hooks</Typography.Text>\n </Button>\n <Select\n mode=\"multiple\"\n allowClear\n className=\"plugin-select\"\n style={{ width: 300 }}\n popupMatchSelectWidth\n onChange={(e) => {\n setSelectedHooks(e);\n }}\n >\n {hooks.map((e) => {\n return (\n <Select.Option key={e} label={e} value={e}>\n {e}\n </Select.Option>\n );\n })}\n </Select>\n </Input.Group>\n </Space>\n )}\n </ServerAPIProvider>\n <ServerAPIProvider\n api={SDK.ServerAPI.API.GetPluginData}\n body={{ hooks: selectedHooks, tapNames: selectedTapNames }}\n >\n {(res) => <WebpackPluginsDataTable dataSource={res} />}\n </ServerAPIProvider>\n </Space>\n </Card>\n </div>\n );\n};\n\nexport * from './constants';\n"],"names":["Page","selectedTapNames","setSelectedTapNames","useState","selectedHooks","setSelectedHooks","Card","Size","WebpackConfigurationViewer","Space","ServerAPIProvider","SDK","hooks","tapNames","Input","Button","ApiOutlined","Typography","Select","e","PartitionOutlined","res","WebpackPluginsDataTable"],"mappings":";;;;;;;;;;;AAUO,MAAMA,OAAiB;IAC5B,MAAM,CAACC,kBAAkBC,oBAAoB,GAAGC,SAAS,EAAE;IAC3D,MAAM,CAACC,eAAeC,iBAAiB,GAAGF,SAAS,EAAE;IAErD,OAAO,WAAP,GACE,IAAC;kBACC,kBAACG,MAAIA;YACH,OAAM;YACN,WAAW;gBAAE,YAAYC,KAAK,WAAW,GAAG;YAAE;YAC9C,qBAAO,IAACC,4BAA0BA;gBAAC,aAAa;oBAAC;iBAAU;;sBAE3D,mBAACC,OAAKA;gBACJ,WAAU;gBACV,OAAO;oBAAE,OAAO;oBAAQ,SAAS;gBAAS;;kCAE1C,IAACC,mBAAiBA;wBAAC,KAAKC,IAAI,SAAS,CAAC,GAAG,CAAC,gBAAgB;kCACvD,CAAC,EAAEC,KAAK,EAAEC,QAAQ,EAAE,iBACnB,KAACJ,OAAKA;gCAAC,OAAO;oCAAE,cAAcF,KAAK,WAAW,GAAG;gCAAE;;kDACjD,KAACO,MAAM,KAAK;wCAAC,SAAO;;0DAClB,KAACC,QAAMA;;kEACL,IAACC,aAAWA,CAAAA;kEACZ,IAACC,WAAW,IAAI;kEAAC;;;;0DAEnB,IAACC,QAAMA;gDACL,MAAK;gDACL,YAAU;gDACV,WAAU;gDACV,OAAO;oDAAE,OAAO;gDAAI;gDACpB,uBAAqB;gDACrB,UAAU,CAACC;oDACTjB,oBAAoBiB;gDACtB;0DAECN,SAAS,GAAG,CAAC,CAACM,IACN,WAAP,GACE,IAACD,OAAO,MAAM;wDAAS,OAAOC;wDAAG,OAAOA;kEACrCA;uDADiBA;;;;kDAO5B,KAACL,MAAM,KAAK;wCAAC,SAAO;;0DAClB,KAACC,QAAMA;;kEACL,IAACK,mBAAiBA,CAAAA;kEAClB,IAACH,WAAW,IAAI;kEAAC;;;;0DAEnB,IAACC,QAAMA;gDACL,MAAK;gDACL,YAAU;gDACV,WAAU;gDACV,OAAO;oDAAE,OAAO;gDAAI;gDACpB,uBAAqB;gDACrB,UAAU,CAACC;oDACTd,iBAAiBc;gDACnB;0DAECP,MAAM,GAAG,CAAC,CAACO,IACH,WAAP,GACE,IAACD,OAAO,MAAM;wDAAS,OAAOC;wDAAG,OAAOA;kEACrCA;uDADiBA;;;;;;;kCAUlC,IAACT,mBAAiBA;wBAChB,KAAKC,IAAI,SAAS,CAAC,GAAG,CAAC,aAAa;wBACpC,MAAM;4BAAE,OAAOP;4BAAe,UAAUH;wBAAiB;kCAExD,CAACoB,MAAAA,WAAAA,GAAQ,IAACC,yBAAuBA;gCAAC,YAAYD;;;;;;;AAM3D"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|