@kritchoff/agent-browser 0.9.2
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/LICENSE +201 -0
- package/README.md +903 -0
- package/README.sdk.md +77 -0
- package/bin/agent-browser-linux-x64 +0 -0
- package/bin/agent-browser.js +109 -0
- package/dist/actions.d.ts +17 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +1427 -0
- package/dist/actions.js.map +1 -0
- package/dist/browser.d.ts +474 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +1566 -0
- package/dist/browser.js.map +1 -0
- package/dist/cdp-client.d.ts +103 -0
- package/dist/cdp-client.d.ts.map +1 -0
- package/dist/cdp-client.js +223 -0
- package/dist/cdp-client.js.map +1 -0
- package/dist/daemon.d.ts +60 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +401 -0
- package/dist/daemon.js.map +1 -0
- package/dist/dualmode-config.d.ts +37 -0
- package/dist/dualmode-config.d.ts.map +1 -0
- package/dist/dualmode-config.js +44 -0
- package/dist/dualmode-config.js.map +1 -0
- package/dist/dualmode-fetcher.d.ts +60 -0
- package/dist/dualmode-fetcher.d.ts.map +1 -0
- package/dist/dualmode-fetcher.js +449 -0
- package/dist/dualmode-fetcher.js.map +1 -0
- package/dist/dualmode-types.d.ts +183 -0
- package/dist/dualmode-types.d.ts.map +1 -0
- package/dist/dualmode-types.js +8 -0
- package/dist/dualmode-types.js.map +1 -0
- package/dist/ios-actions.d.ts +11 -0
- package/dist/ios-actions.d.ts.map +1 -0
- package/dist/ios-actions.js +228 -0
- package/dist/ios-actions.js.map +1 -0
- package/dist/ios-manager.d.ts +266 -0
- package/dist/ios-manager.d.ts.map +1 -0
- package/dist/ios-manager.js +1073 -0
- package/dist/ios-manager.js.map +1 -0
- package/dist/protocol.d.ts +26 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +832 -0
- package/dist/protocol.js.map +1 -0
- package/dist/snapshot.d.ts +83 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +653 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/stream-server.d.ts +117 -0
- package/dist/stream-server.d.ts.map +1 -0
- package/dist/stream-server.js +305 -0
- package/dist/stream-server.js.map +1 -0
- package/dist/types.d.ts +742 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docker-compose.sdk.yml +45 -0
- package/package.json +85 -0
- package/scripts/benchmark.sh +80 -0
- package/scripts/build-all-platforms.sh +68 -0
- package/scripts/check-version-sync.js +39 -0
- package/scripts/copy-native.js +36 -0
- package/scripts/fast_reset.sh +108 -0
- package/scripts/postinstall.js +235 -0
- package/scripts/publish_images.sh +55 -0
- package/scripts/snapshot_manager.sh +293 -0
- package/scripts/start-android-agent.sh +49 -0
- package/scripts/sync-version.js +69 -0
- package/scripts/vaccine-run +26 -0
- package/sdk.sh +153 -0
- package/skills/agent-browser/SKILL.md +217 -0
- package/skills/agent-browser/references/authentication.md +202 -0
- package/skills/agent-browser/references/commands.md +259 -0
- package/skills/agent-browser/references/proxy-support.md +188 -0
- package/skills/agent-browser/references/session-management.md +193 -0
- package/skills/agent-browser/references/snapshot-refs.md +194 -0
- package/skills/agent-browser/references/video-recording.md +173 -0
- package/skills/agent-browser/templates/authenticated-session.sh +97 -0
- package/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/skills/agent-browser/templates/form-automation.sh +62 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +356 -0
- package/skills/skill-creator/references/output-patterns.md +82 -0
- package/skills/skill-creator/references/workflows.md +28 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/package_skill.py +113 -0
- package/skills/skill-creator/scripts/quick_validate.py +95 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { BrowserManager } from './browser.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check whether a WebSocket connection origin should be allowed.
|
|
4
|
+
* Allows: no origin (CLI tools), file:// origins, and localhost/loopback origins.
|
|
5
|
+
* Rejects: all other origins (prevents malicious web pages from connecting).
|
|
6
|
+
*/
|
|
7
|
+
export declare function isAllowedOrigin(origin: string | undefined): boolean;
|
|
8
|
+
export interface FrameMessage {
|
|
9
|
+
type: 'frame';
|
|
10
|
+
data: string;
|
|
11
|
+
metadata: {
|
|
12
|
+
offsetTop: number;
|
|
13
|
+
pageScaleFactor: number;
|
|
14
|
+
deviceWidth: number;
|
|
15
|
+
deviceHeight: number;
|
|
16
|
+
scrollOffsetX: number;
|
|
17
|
+
scrollOffsetY: number;
|
|
18
|
+
timestamp?: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface InputMouseMessage {
|
|
22
|
+
type: 'input_mouse';
|
|
23
|
+
eventType: 'mousePressed' | 'mouseReleased' | 'mouseMoved' | 'mouseWheel';
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
button?: 'left' | 'right' | 'middle' | 'none';
|
|
27
|
+
clickCount?: number;
|
|
28
|
+
deltaX?: number;
|
|
29
|
+
deltaY?: number;
|
|
30
|
+
modifiers?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface InputKeyboardMessage {
|
|
33
|
+
type: 'input_keyboard';
|
|
34
|
+
eventType: 'keyDown' | 'keyUp' | 'char';
|
|
35
|
+
key?: string;
|
|
36
|
+
code?: string;
|
|
37
|
+
text?: string;
|
|
38
|
+
modifiers?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface InputTouchMessage {
|
|
41
|
+
type: 'input_touch';
|
|
42
|
+
eventType: 'touchStart' | 'touchEnd' | 'touchMove' | 'touchCancel';
|
|
43
|
+
touchPoints: Array<{
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
id?: number;
|
|
47
|
+
}>;
|
|
48
|
+
modifiers?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface StatusMessage {
|
|
51
|
+
type: 'status';
|
|
52
|
+
connected: boolean;
|
|
53
|
+
screencasting: boolean;
|
|
54
|
+
viewportWidth?: number;
|
|
55
|
+
viewportHeight?: number;
|
|
56
|
+
}
|
|
57
|
+
export interface ErrorMessage {
|
|
58
|
+
type: 'error';
|
|
59
|
+
message: string;
|
|
60
|
+
}
|
|
61
|
+
export type StreamMessage = FrameMessage | InputMouseMessage | InputKeyboardMessage | InputTouchMessage | StatusMessage | ErrorMessage;
|
|
62
|
+
/**
|
|
63
|
+
* WebSocket server for streaming browser viewport and receiving input
|
|
64
|
+
*/
|
|
65
|
+
export declare class StreamServer {
|
|
66
|
+
private wss;
|
|
67
|
+
private clients;
|
|
68
|
+
private browser;
|
|
69
|
+
private port;
|
|
70
|
+
private isScreencasting;
|
|
71
|
+
constructor(browser: BrowserManager, port?: number);
|
|
72
|
+
/**
|
|
73
|
+
* Start the WebSocket server
|
|
74
|
+
*/
|
|
75
|
+
start(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Stop the WebSocket server
|
|
78
|
+
*/
|
|
79
|
+
stop(): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Handle a new WebSocket connection
|
|
82
|
+
*/
|
|
83
|
+
private handleConnection;
|
|
84
|
+
/**
|
|
85
|
+
* Handle incoming messages from clients
|
|
86
|
+
*/
|
|
87
|
+
private handleMessage;
|
|
88
|
+
/**
|
|
89
|
+
* Broadcast a frame to all connected clients
|
|
90
|
+
*/
|
|
91
|
+
private broadcastFrame;
|
|
92
|
+
/**
|
|
93
|
+
* Send status to a client
|
|
94
|
+
*/
|
|
95
|
+
private sendStatus;
|
|
96
|
+
/**
|
|
97
|
+
* Send an error to a client
|
|
98
|
+
*/
|
|
99
|
+
private sendError;
|
|
100
|
+
/**
|
|
101
|
+
* Start screencasting
|
|
102
|
+
*/
|
|
103
|
+
private startScreencast;
|
|
104
|
+
/**
|
|
105
|
+
* Stop screencasting
|
|
106
|
+
*/
|
|
107
|
+
private stopScreencast;
|
|
108
|
+
/**
|
|
109
|
+
* Get the port the server is running on
|
|
110
|
+
*/
|
|
111
|
+
getPort(): number;
|
|
112
|
+
/**
|
|
113
|
+
* Get the number of connected clients
|
|
114
|
+
*/
|
|
115
|
+
getClientCount(): number;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=stream-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-server.d.ts","sourceRoot":"","sources":["../src/stream-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
|
+
import { setScreencastFrameCallback } from './actions.js';
|
|
3
|
+
/**
|
|
4
|
+
* Check whether a WebSocket connection origin should be allowed.
|
|
5
|
+
* Allows: no origin (CLI tools), file:// origins, and localhost/loopback origins.
|
|
6
|
+
* Rejects: all other origins (prevents malicious web pages from connecting).
|
|
7
|
+
*/
|
|
8
|
+
export function isAllowedOrigin(origin) {
|
|
9
|
+
// Allow connections with no origin (non-browser clients like CLI tools)
|
|
10
|
+
if (!origin) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
// Allow file:// origins (local HTML files)
|
|
14
|
+
if (origin.startsWith('file://')) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
// Allow localhost/loopback origins (browser-based stream viewers)
|
|
18
|
+
try {
|
|
19
|
+
const url = new URL(origin);
|
|
20
|
+
const host = url.hostname;
|
|
21
|
+
if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '[::1]') {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Invalid origin URL - reject
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* WebSocket server for streaming browser viewport and receiving input
|
|
32
|
+
*/
|
|
33
|
+
export class StreamServer {
|
|
34
|
+
wss = null;
|
|
35
|
+
clients = new Set();
|
|
36
|
+
browser;
|
|
37
|
+
port;
|
|
38
|
+
isScreencasting = false;
|
|
39
|
+
constructor(browser, port = 9223) {
|
|
40
|
+
this.browser = browser;
|
|
41
|
+
this.port = port;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Start the WebSocket server
|
|
45
|
+
*/
|
|
46
|
+
start() {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
try {
|
|
49
|
+
this.wss = new WebSocketServer({
|
|
50
|
+
port: this.port,
|
|
51
|
+
// Security: Reject cross-origin WebSocket connections from untrusted origins.
|
|
52
|
+
// This prevents malicious web pages from connecting and injecting input events.
|
|
53
|
+
// Localhost origins are allowed so browser-based stream viewers can connect.
|
|
54
|
+
verifyClient: (info) => {
|
|
55
|
+
if (isAllowedOrigin(info.origin)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
console.log(`[StreamServer] Rejected connection from origin: ${info.origin}`);
|
|
59
|
+
return false;
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
this.wss.on('connection', (ws) => {
|
|
63
|
+
this.handleConnection(ws);
|
|
64
|
+
});
|
|
65
|
+
this.wss.on('error', (error) => {
|
|
66
|
+
console.error('[StreamServer] WebSocket error:', error);
|
|
67
|
+
reject(error);
|
|
68
|
+
});
|
|
69
|
+
this.wss.on('listening', () => {
|
|
70
|
+
console.log(`[StreamServer] Listening on port ${this.port}`);
|
|
71
|
+
// Set up the screencast frame callback
|
|
72
|
+
setScreencastFrameCallback((frame) => {
|
|
73
|
+
this.broadcastFrame(frame);
|
|
74
|
+
});
|
|
75
|
+
resolve();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
reject(error);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Stop the WebSocket server
|
|
85
|
+
*/
|
|
86
|
+
async stop() {
|
|
87
|
+
// Stop screencasting
|
|
88
|
+
if (this.isScreencasting) {
|
|
89
|
+
await this.stopScreencast();
|
|
90
|
+
}
|
|
91
|
+
// Clear the callback
|
|
92
|
+
setScreencastFrameCallback(null);
|
|
93
|
+
// Close all clients
|
|
94
|
+
for (const client of this.clients) {
|
|
95
|
+
client.close();
|
|
96
|
+
}
|
|
97
|
+
this.clients.clear();
|
|
98
|
+
// Close the server
|
|
99
|
+
if (this.wss) {
|
|
100
|
+
return new Promise((resolve) => {
|
|
101
|
+
this.wss.close(() => {
|
|
102
|
+
this.wss = null;
|
|
103
|
+
resolve();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Handle a new WebSocket connection
|
|
110
|
+
*/
|
|
111
|
+
handleConnection(ws) {
|
|
112
|
+
console.log('[StreamServer] Client connected');
|
|
113
|
+
this.clients.add(ws);
|
|
114
|
+
// Send initial status
|
|
115
|
+
this.sendStatus(ws);
|
|
116
|
+
// Start screencasting if this is the first client
|
|
117
|
+
if (this.clients.size === 1 && !this.isScreencasting) {
|
|
118
|
+
this.startScreencast().catch((error) => {
|
|
119
|
+
console.error('[StreamServer] Failed to start screencast:', error);
|
|
120
|
+
this.sendError(ws, error.message);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// Handle messages from client
|
|
124
|
+
ws.on('message', (data) => {
|
|
125
|
+
try {
|
|
126
|
+
const message = JSON.parse(data.toString());
|
|
127
|
+
this.handleMessage(message, ws);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error('[StreamServer] Failed to parse message:', error);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
// Handle client disconnect
|
|
134
|
+
ws.on('close', () => {
|
|
135
|
+
console.log('[StreamServer] Client disconnected');
|
|
136
|
+
this.clients.delete(ws);
|
|
137
|
+
// Stop screencasting if no more clients
|
|
138
|
+
if (this.clients.size === 0 && this.isScreencasting) {
|
|
139
|
+
this.stopScreencast().catch((error) => {
|
|
140
|
+
console.error('[StreamServer] Failed to stop screencast:', error);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
ws.on('error', (error) => {
|
|
145
|
+
console.error('[StreamServer] Client error:', error);
|
|
146
|
+
this.clients.delete(ws);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Handle incoming messages from clients
|
|
151
|
+
*/
|
|
152
|
+
async handleMessage(message, ws) {
|
|
153
|
+
try {
|
|
154
|
+
switch (message.type) {
|
|
155
|
+
case 'input_mouse':
|
|
156
|
+
await this.browser.injectMouseEvent({
|
|
157
|
+
type: message.eventType,
|
|
158
|
+
x: message.x,
|
|
159
|
+
y: message.y,
|
|
160
|
+
button: message.button,
|
|
161
|
+
clickCount: message.clickCount,
|
|
162
|
+
deltaX: message.deltaX,
|
|
163
|
+
deltaY: message.deltaY,
|
|
164
|
+
modifiers: message.modifiers,
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
case 'input_keyboard':
|
|
168
|
+
await this.browser.injectKeyboardEvent({
|
|
169
|
+
type: message.eventType,
|
|
170
|
+
key: message.key,
|
|
171
|
+
code: message.code,
|
|
172
|
+
text: message.text,
|
|
173
|
+
modifiers: message.modifiers,
|
|
174
|
+
});
|
|
175
|
+
break;
|
|
176
|
+
case 'input_touch':
|
|
177
|
+
await this.browser.injectTouchEvent({
|
|
178
|
+
type: message.eventType,
|
|
179
|
+
touchPoints: message.touchPoints,
|
|
180
|
+
modifiers: message.modifiers,
|
|
181
|
+
});
|
|
182
|
+
break;
|
|
183
|
+
case 'status':
|
|
184
|
+
// Client is requesting status
|
|
185
|
+
this.sendStatus(ws);
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
191
|
+
this.sendError(ws, errorMessage);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Broadcast a frame to all connected clients
|
|
196
|
+
*/
|
|
197
|
+
broadcastFrame(frame) {
|
|
198
|
+
const message = {
|
|
199
|
+
type: 'frame',
|
|
200
|
+
data: frame.data,
|
|
201
|
+
metadata: frame.metadata,
|
|
202
|
+
};
|
|
203
|
+
const payload = JSON.stringify(message);
|
|
204
|
+
for (const client of this.clients) {
|
|
205
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
206
|
+
client.send(payload);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Send status to a client
|
|
212
|
+
*/
|
|
213
|
+
sendStatus(ws) {
|
|
214
|
+
let viewportWidth;
|
|
215
|
+
let viewportHeight;
|
|
216
|
+
try {
|
|
217
|
+
const page = this.browser.getPage();
|
|
218
|
+
const viewport = page.viewportSize();
|
|
219
|
+
viewportWidth = viewport?.width;
|
|
220
|
+
viewportHeight = viewport?.height;
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Browser not launched yet
|
|
224
|
+
}
|
|
225
|
+
const message = {
|
|
226
|
+
type: 'status',
|
|
227
|
+
connected: true,
|
|
228
|
+
screencasting: this.isScreencasting,
|
|
229
|
+
viewportWidth,
|
|
230
|
+
viewportHeight,
|
|
231
|
+
};
|
|
232
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
233
|
+
ws.send(JSON.stringify(message));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Send an error to a client
|
|
238
|
+
*/
|
|
239
|
+
sendError(ws, errorMessage) {
|
|
240
|
+
const message = {
|
|
241
|
+
type: 'error',
|
|
242
|
+
message: errorMessage,
|
|
243
|
+
};
|
|
244
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
245
|
+
ws.send(JSON.stringify(message));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Start screencasting
|
|
250
|
+
*/
|
|
251
|
+
async startScreencast() {
|
|
252
|
+
// Set flag immediately to prevent race conditions with concurrent calls
|
|
253
|
+
if (this.isScreencasting)
|
|
254
|
+
return;
|
|
255
|
+
this.isScreencasting = true;
|
|
256
|
+
try {
|
|
257
|
+
// Check if browser is launched
|
|
258
|
+
if (!this.browser.isLaunched()) {
|
|
259
|
+
throw new Error('Browser not launched');
|
|
260
|
+
}
|
|
261
|
+
await this.browser.startScreencast((frame) => this.broadcastFrame(frame), {
|
|
262
|
+
format: 'jpeg',
|
|
263
|
+
quality: 80,
|
|
264
|
+
maxWidth: 1280,
|
|
265
|
+
maxHeight: 720,
|
|
266
|
+
everyNthFrame: 1,
|
|
267
|
+
});
|
|
268
|
+
// Notify all clients
|
|
269
|
+
for (const client of this.clients) {
|
|
270
|
+
this.sendStatus(client);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
// Reset flag on failure so caller can retry
|
|
275
|
+
this.isScreencasting = false;
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Stop screencasting
|
|
281
|
+
*/
|
|
282
|
+
async stopScreencast() {
|
|
283
|
+
if (!this.isScreencasting)
|
|
284
|
+
return;
|
|
285
|
+
await this.browser.stopScreencast();
|
|
286
|
+
this.isScreencasting = false;
|
|
287
|
+
// Notify all clients
|
|
288
|
+
for (const client of this.clients) {
|
|
289
|
+
this.sendStatus(client);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get the port the server is running on
|
|
294
|
+
*/
|
|
295
|
+
getPort() {
|
|
296
|
+
return this.port;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get the number of connected clients
|
|
300
|
+
*/
|
|
301
|
+
getClientCount() {
|
|
302
|
+
return this.clients.size;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=stream-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-server.js","sourceRoot":"","sources":["../src/stream-server.ts"],"names":[],"mappings":"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"}
|