@modelprofile.com/browser-runtime 1.0.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/.smartconfig.json +34 -0
- package/changelog.md +11 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/actions.d.ts +3 -0
- package/dist_ts/actions.js +215 -0
- package/dist_ts/classes.artifactstore.d.ts +38 -0
- package/dist_ts/classes.artifactstore.js +344 -0
- package/dist_ts/classes.egressproxy.d.ts +67 -0
- package/dist_ts/classes.egressproxy.js +830 -0
- package/dist_ts/classes.flexprovider.d.ts +9 -0
- package/dist_ts/classes.flexprovider.js +117 -0
- package/dist_ts/classes.framed.d.ts +52 -0
- package/dist_ts/classes.framed.js +557 -0
- package/dist_ts/classes.runtime.d.ts +202 -0
- package/dist_ts/classes.runtime.js +1667 -0
- package/dist_ts/confinement.d.ts +2 -0
- package/dist_ts/confinement.js +63 -0
- package/dist_ts/errors.d.ts +7 -0
- package/dist_ts/errors.js +40 -0
- package/dist_ts/index.d.ts +11 -0
- package/dist_ts/index.js +9 -0
- package/dist_ts/interfaces.d.ts +287 -0
- package/dist_ts/interfaces.js +2 -0
- package/dist_ts/internal.testing.d.ts +9 -0
- package/dist_ts/internal.testing.js +2 -0
- package/dist_ts/mcp.d.ts +4 -0
- package/dist_ts/mcp.js +196 -0
- package/dist_ts/plugins.d.ts +20 -0
- package/dist_ts/plugins.js +24 -0
- package/dist_ts/utils.d.ts +25 -0
- package/dist_ts/utils.js +143 -0
- package/license.md +21 -0
- package/package.json +59 -0
- package/readme.hints.md +35 -0
- package/readme.md +181 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/actions.ts +241 -0
- package/ts/classes.artifactstore.ts +432 -0
- package/ts/classes.egressproxy.ts +1005 -0
- package/ts/classes.flexprovider.ts +134 -0
- package/ts/classes.framed.ts +649 -0
- package/ts/classes.runtime.ts +2135 -0
- package/ts/confinement.ts +90 -0
- package/ts/errors.ts +63 -0
- package/ts/index.ts +52 -0
- package/ts/interfaces.ts +375 -0
- package/ts/internal.testing.ts +18 -0
- package/ts/mcp.ts +230 -0
- package/ts/plugins.ts +28 -0
- package/ts/utils.ts +188 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { BrowserRuntimeError } from './errors.js';
|
|
3
|
+
import { TransitionMutex, randomId, validateBoundedString, validateOptionalInteger, } from './utils.js';
|
|
4
|
+
export class BrowserArtifactStore {
|
|
5
|
+
rootDirectory;
|
|
6
|
+
maxFileBytes;
|
|
7
|
+
maxArtifactsPerProject;
|
|
8
|
+
maxProjectBytes;
|
|
9
|
+
maxProjects;
|
|
10
|
+
maxTotalArtifacts;
|
|
11
|
+
maxTotalBytes;
|
|
12
|
+
artifactTtlMs;
|
|
13
|
+
now;
|
|
14
|
+
directoryKey = plugins.crypto.randomBytes(32);
|
|
15
|
+
projects = new Map();
|
|
16
|
+
mutex = new TransitionMutex();
|
|
17
|
+
totalArtifacts = 0;
|
|
18
|
+
totalBytes = 0;
|
|
19
|
+
started = false;
|
|
20
|
+
startPromise;
|
|
21
|
+
stopPromise;
|
|
22
|
+
sweepTimer;
|
|
23
|
+
sweepRunning = false;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
if (!options || typeof options !== 'object' || !plugins.path.isAbsolute(options.rootDirectory)) {
|
|
26
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'rootDirectory must be absolute');
|
|
27
|
+
}
|
|
28
|
+
this.rootDirectory = options.rootDirectory;
|
|
29
|
+
this.maxFileBytes = validateOptionalInteger(options.maxFileBytes, 'maxFileBytes', 1024, 64 * 1024 * 1024, 8 * 1024 * 1024);
|
|
30
|
+
this.maxArtifactsPerProject = validateOptionalInteger(options.maxArtifactsPerProject, 'maxArtifactsPerProject', 1, 4096, 256);
|
|
31
|
+
this.maxProjectBytes = validateOptionalInteger(options.maxProjectBytes, 'maxProjectBytes', this.maxFileBytes, 1024 * 1024 * 1024, 64 * 1024 * 1024);
|
|
32
|
+
this.maxProjects = validateOptionalInteger(options.maxProjects, 'maxProjects', 1, 256, 32);
|
|
33
|
+
this.maxTotalArtifacts = validateOptionalInteger(options.maxTotalArtifacts, 'maxTotalArtifacts', this.maxArtifactsPerProject, 65_536, Math.max(4096, this.maxArtifactsPerProject));
|
|
34
|
+
this.maxTotalBytes = validateOptionalInteger(options.maxTotalBytes, 'maxTotalBytes', this.maxProjectBytes, 8 * 1024 * 1024 * 1024, Math.max(512 * 1024 * 1024, this.maxProjectBytes));
|
|
35
|
+
this.artifactTtlMs = validateOptionalInteger(options.artifactTtlMs, 'artifactTtlMs', 1000, 24 * 60 * 60 * 1000, 60 * 60 * 1000);
|
|
36
|
+
this.now = options.now ?? Date.now;
|
|
37
|
+
if (typeof this.now !== 'function')
|
|
38
|
+
throw new BrowserRuntimeError('INVALID_INPUT');
|
|
39
|
+
}
|
|
40
|
+
start() {
|
|
41
|
+
if (this.started)
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
if (this.startPromise)
|
|
44
|
+
return this.startPromise;
|
|
45
|
+
this.startPromise = this.startInternal().finally(() => {
|
|
46
|
+
this.startPromise = undefined;
|
|
47
|
+
});
|
|
48
|
+
return this.startPromise;
|
|
49
|
+
}
|
|
50
|
+
stop() {
|
|
51
|
+
if (this.stopPromise)
|
|
52
|
+
return this.stopPromise;
|
|
53
|
+
if (!this.started && !this.startPromise)
|
|
54
|
+
return Promise.resolve();
|
|
55
|
+
this.stopPromise = (async () => {
|
|
56
|
+
await this.startPromise?.catch(() => undefined);
|
|
57
|
+
if (this.sweepTimer)
|
|
58
|
+
clearInterval(this.sweepTimer);
|
|
59
|
+
this.sweepTimer = undefined;
|
|
60
|
+
const release = await this.mutex.acquire();
|
|
61
|
+
try {
|
|
62
|
+
await plugins.fsPromises.rm(this.rootDirectory, { recursive: true, force: true });
|
|
63
|
+
this.projects.clear();
|
|
64
|
+
this.totalArtifacts = 0;
|
|
65
|
+
this.totalBytes = 0;
|
|
66
|
+
this.started = false;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
release();
|
|
70
|
+
}
|
|
71
|
+
})().finally(() => {
|
|
72
|
+
this.stopPromise = undefined;
|
|
73
|
+
});
|
|
74
|
+
return this.stopPromise;
|
|
75
|
+
}
|
|
76
|
+
async store(projectIdArg, mimeTypeArg, data) {
|
|
77
|
+
this.requireStarted();
|
|
78
|
+
const projectId = validateBoundedString(projectIdArg, 'projectId', 1, 128);
|
|
79
|
+
const mimeType = validateBoundedString(mimeTypeArg, 'mimeType', 1, 128);
|
|
80
|
+
if (!(data instanceof Uint8Array)) {
|
|
81
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'data must be Uint8Array');
|
|
82
|
+
}
|
|
83
|
+
if (data.byteLength > this.maxFileBytes)
|
|
84
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
85
|
+
const bytes = plugins.Buffer.from(data);
|
|
86
|
+
const release = await this.mutex.acquire();
|
|
87
|
+
try {
|
|
88
|
+
this.requireStarted();
|
|
89
|
+
await this.purgeExpiredInternal(projectId);
|
|
90
|
+
const existingProject = this.projects.get(projectId);
|
|
91
|
+
if (!existingProject && this.projects.size >= this.maxProjects) {
|
|
92
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
93
|
+
}
|
|
94
|
+
if (this.totalArtifacts >= this.maxTotalArtifacts
|
|
95
|
+
|| this.totalBytes + bytes.byteLength > this.maxTotalBytes)
|
|
96
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
97
|
+
const project = existingProject ?? await this.createProject(projectId);
|
|
98
|
+
if (project.artifacts.size >= this.maxArtifactsPerProject
|
|
99
|
+
|| project.totalBytes + bytes.byteLength > this.maxProjectBytes)
|
|
100
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
101
|
+
const artifactId = randomId();
|
|
102
|
+
const createdAt = this.now();
|
|
103
|
+
const metadata = {
|
|
104
|
+
artifactId,
|
|
105
|
+
projectId,
|
|
106
|
+
mimeType,
|
|
107
|
+
size: bytes.byteLength,
|
|
108
|
+
createdAt,
|
|
109
|
+
expiresAt: createdAt + this.artifactTtlMs,
|
|
110
|
+
};
|
|
111
|
+
const stored = {
|
|
112
|
+
metadata,
|
|
113
|
+
digest: plugins.crypto.createHash('sha256').update(bytes).digest('hex'),
|
|
114
|
+
};
|
|
115
|
+
const projectDirectory = plugins.path.join(this.rootDirectory, project.directoryName);
|
|
116
|
+
const finalPath = plugins.path.join(projectDirectory, artifactId);
|
|
117
|
+
const temporaryPath = plugins.path.join(projectDirectory, `.${randomId(12)}.tmp`);
|
|
118
|
+
let handle;
|
|
119
|
+
let renamed = false;
|
|
120
|
+
try {
|
|
121
|
+
handle = await plugins.fsPromises.open(temporaryPath, 'wx', 0o600);
|
|
122
|
+
await handle.writeFile(bytes);
|
|
123
|
+
await handle.sync();
|
|
124
|
+
await handle.close();
|
|
125
|
+
handle = undefined;
|
|
126
|
+
await plugins.fsPromises.rename(temporaryPath, finalPath);
|
|
127
|
+
renamed = true;
|
|
128
|
+
await plugins.fsPromises.chmod(finalPath, 0o600);
|
|
129
|
+
project.artifacts.set(artifactId, stored);
|
|
130
|
+
project.totalBytes += bytes.byteLength;
|
|
131
|
+
this.totalArtifacts += 1;
|
|
132
|
+
this.totalBytes += bytes.byteLength;
|
|
133
|
+
return { ...metadata };
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
await handle?.close().catch(() => undefined);
|
|
137
|
+
await plugins.fsPromises.rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
138
|
+
if (renamed)
|
|
139
|
+
await plugins.fsPromises.rm(finalPath, { force: true }).catch(() => undefined);
|
|
140
|
+
if (project.artifacts.size === 0)
|
|
141
|
+
await this.removeEmptyProject(projectId, project);
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
release();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async read(projectIdArg, artifactIdArg) {
|
|
150
|
+
this.requireStarted();
|
|
151
|
+
const projectId = validateBoundedString(projectIdArg, 'projectId', 1, 128);
|
|
152
|
+
const artifactId = validateBoundedString(artifactIdArg, 'artifactId', 1, 128);
|
|
153
|
+
const release = await this.mutex.acquire();
|
|
154
|
+
let handle;
|
|
155
|
+
try {
|
|
156
|
+
const { project, stored, filePath } = this.resolveArtifact(projectId, artifactId);
|
|
157
|
+
if (stored.metadata.expiresAt <= this.now()) {
|
|
158
|
+
await this.deleteArtifact(projectId, project, stored, filePath);
|
|
159
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'artifact is unavailable');
|
|
160
|
+
}
|
|
161
|
+
handle = await plugins.fsPromises.open(filePath, plugins.fs.constants.O_RDONLY | plugins.fs.constants.O_NOFOLLOW);
|
|
162
|
+
const stat = await handle.stat();
|
|
163
|
+
if (!stat.isFile() || stat.size !== stored.metadata.size || stat.size > this.maxFileBytes) {
|
|
164
|
+
await handle.close();
|
|
165
|
+
handle = undefined;
|
|
166
|
+
await this.deleteArtifact(projectId, project, stored, filePath);
|
|
167
|
+
throw new BrowserRuntimeError('FENCED', 'artifact integrity check failed');
|
|
168
|
+
}
|
|
169
|
+
const data = plugins.Buffer.allocUnsafe(stat.size);
|
|
170
|
+
const { bytesRead } = await handle.read(data, 0, stat.size, 0);
|
|
171
|
+
await handle.close();
|
|
172
|
+
handle = undefined;
|
|
173
|
+
const digest = plugins.crypto.createHash('sha256').update(data).digest('hex');
|
|
174
|
+
if (bytesRead !== stat.size || digest !== stored.digest) {
|
|
175
|
+
await this.deleteArtifact(projectId, project, stored, filePath);
|
|
176
|
+
throw new BrowserRuntimeError('FENCED', 'artifact integrity check failed');
|
|
177
|
+
}
|
|
178
|
+
return new Uint8Array(data);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await handle?.close().catch(() => undefined);
|
|
182
|
+
release();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async delete(projectIdArg, artifactIdArg) {
|
|
186
|
+
this.requireStarted();
|
|
187
|
+
const projectId = validateBoundedString(projectIdArg, 'projectId', 1, 128);
|
|
188
|
+
const artifactId = validateBoundedString(artifactIdArg, 'artifactId', 1, 128);
|
|
189
|
+
const release = await this.mutex.acquire();
|
|
190
|
+
try {
|
|
191
|
+
const { project, stored, filePath } = this.resolveArtifact(projectId, artifactId);
|
|
192
|
+
await this.deleteArtifact(projectId, project, stored, filePath);
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
release();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async purgeExpired(projectIdArg) {
|
|
199
|
+
this.requireStarted();
|
|
200
|
+
const projectId = projectIdArg === undefined
|
|
201
|
+
? undefined
|
|
202
|
+
: validateBoundedString(projectIdArg, 'projectId', 1, 128);
|
|
203
|
+
const release = await this.mutex.acquire();
|
|
204
|
+
try {
|
|
205
|
+
return await this.purgeExpiredInternal(projectId);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
release();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async purgeProject(projectIdArg) {
|
|
212
|
+
this.requireStarted();
|
|
213
|
+
const projectId = validateBoundedString(projectIdArg, 'projectId', 1, 128);
|
|
214
|
+
const release = await this.mutex.acquire();
|
|
215
|
+
try {
|
|
216
|
+
const project = this.projects.get(projectId);
|
|
217
|
+
if (!project)
|
|
218
|
+
return;
|
|
219
|
+
await plugins.fsPromises.rm(plugins.path.join(this.rootDirectory, project.directoryName), { recursive: true, force: true });
|
|
220
|
+
this.totalArtifacts -= project.artifacts.size;
|
|
221
|
+
this.totalBytes -= project.totalBytes;
|
|
222
|
+
this.projects.delete(projectId);
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
release();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
getMetadata(projectIdArg, artifactIdArg) {
|
|
229
|
+
this.requireStarted();
|
|
230
|
+
const projectId = validateBoundedString(projectIdArg, 'projectId', 1, 128);
|
|
231
|
+
const artifactId = validateBoundedString(artifactIdArg, 'artifactId', 1, 128);
|
|
232
|
+
const project = this.projects.get(projectId);
|
|
233
|
+
const stored = project?.artifacts.get(artifactId);
|
|
234
|
+
if (!stored || stored.metadata.expiresAt <= this.now()) {
|
|
235
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'artifact is unavailable');
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const stat = plugins.fs.lstatSync(plugins.path.join(this.rootDirectory, project.directoryName, artifactId));
|
|
239
|
+
if (stat.isSymbolicLink() || !stat.isFile() || stat.size !== stored.metadata.size) {
|
|
240
|
+
throw new BrowserRuntimeError('FENCED', 'artifact integrity check failed');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
if (error instanceof BrowserRuntimeError)
|
|
245
|
+
throw error;
|
|
246
|
+
throw new BrowserRuntimeError('FENCED', 'artifact integrity check failed');
|
|
247
|
+
}
|
|
248
|
+
return { ...stored.metadata };
|
|
249
|
+
}
|
|
250
|
+
async startInternal() {
|
|
251
|
+
try {
|
|
252
|
+
await plugins.fsPromises.mkdir(this.rootDirectory, { recursive: false, mode: 0o700 });
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
if (error.code === 'EEXIST') {
|
|
256
|
+
const entries = await plugins.fsPromises.readdir(this.rootDirectory).catch(() => []);
|
|
257
|
+
throw new BrowserRuntimeError('FENCED', entries.length > 0 ? 'artifact root is not empty' : 'artifact root must not exist');
|
|
258
|
+
}
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
const stat = await plugins.fsPromises.lstat(this.rootDirectory);
|
|
262
|
+
const uid = process.getuid?.();
|
|
263
|
+
if (!stat.isDirectory()
|
|
264
|
+
|| stat.isSymbolicLink()
|
|
265
|
+
|| (uid !== undefined && stat.uid !== uid)
|
|
266
|
+
|| (stat.mode & 0o777) !== 0o700)
|
|
267
|
+
throw new BrowserRuntimeError('FENCED', 'artifact root is not private');
|
|
268
|
+
const entries = await plugins.fsPromises.readdir(this.rootDirectory);
|
|
269
|
+
if (entries.length > 0)
|
|
270
|
+
throw new BrowserRuntimeError('FENCED', 'artifact root is not empty');
|
|
271
|
+
await plugins.fsPromises.chmod(this.rootDirectory, 0o700);
|
|
272
|
+
this.started = true;
|
|
273
|
+
const sweepIntervalMs = Math.min(60_000, Math.max(1000, Math.floor(this.artifactTtlMs / 2)));
|
|
274
|
+
this.sweepTimer = setInterval(() => {
|
|
275
|
+
if (this.sweepRunning)
|
|
276
|
+
return;
|
|
277
|
+
this.sweepRunning = true;
|
|
278
|
+
void this.purgeExpired().catch(() => undefined).finally(() => {
|
|
279
|
+
this.sweepRunning = false;
|
|
280
|
+
});
|
|
281
|
+
}, sweepIntervalMs);
|
|
282
|
+
this.sweepTimer.unref();
|
|
283
|
+
}
|
|
284
|
+
requireStarted() {
|
|
285
|
+
if (!this.started)
|
|
286
|
+
throw new BrowserRuntimeError('NOT_RUNNING');
|
|
287
|
+
}
|
|
288
|
+
async createProject(projectId) {
|
|
289
|
+
const directoryName = plugins.crypto
|
|
290
|
+
.createHmac('sha256', this.directoryKey)
|
|
291
|
+
.update(projectId, 'utf8')
|
|
292
|
+
.digest('hex');
|
|
293
|
+
const projectDirectory = plugins.path.join(this.rootDirectory, directoryName);
|
|
294
|
+
await plugins.fsPromises.mkdir(projectDirectory, { recursive: false, mode: 0o700 });
|
|
295
|
+
const project = { directoryName, totalBytes: 0, artifacts: new Map() };
|
|
296
|
+
this.projects.set(projectId, project);
|
|
297
|
+
return project;
|
|
298
|
+
}
|
|
299
|
+
async purgeExpiredInternal(projectId) {
|
|
300
|
+
const projectIds = projectId === undefined ? [...this.projects.keys()] : [projectId];
|
|
301
|
+
let purged = 0;
|
|
302
|
+
for (const currentProjectId of projectIds) {
|
|
303
|
+
const project = this.projects.get(currentProjectId);
|
|
304
|
+
if (!project)
|
|
305
|
+
continue;
|
|
306
|
+
for (const stored of [...project.artifacts.values()]) {
|
|
307
|
+
if (stored.metadata.expiresAt <= this.now()) {
|
|
308
|
+
const filePath = plugins.path.join(this.rootDirectory, project.directoryName, stored.metadata.artifactId);
|
|
309
|
+
await this.deleteArtifact(currentProjectId, project, stored, filePath);
|
|
310
|
+
purged += 1;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return purged;
|
|
315
|
+
}
|
|
316
|
+
async deleteArtifact(projectId, project, stored, filePath) {
|
|
317
|
+
await plugins.fsPromises.rm(filePath, { force: true });
|
|
318
|
+
if (project.artifacts.delete(stored.metadata.artifactId)) {
|
|
319
|
+
project.totalBytes = Math.max(0, project.totalBytes - stored.metadata.size);
|
|
320
|
+
this.totalArtifacts = Math.max(0, this.totalArtifacts - 1);
|
|
321
|
+
this.totalBytes = Math.max(0, this.totalBytes - stored.metadata.size);
|
|
322
|
+
}
|
|
323
|
+
await this.removeEmptyProject(projectId, project);
|
|
324
|
+
}
|
|
325
|
+
async removeEmptyProject(projectId, project) {
|
|
326
|
+
if (project.artifacts.size > 0 || this.projects.get(projectId) !== project)
|
|
327
|
+
return;
|
|
328
|
+
await plugins.fsPromises.rm(plugins.path.join(this.rootDirectory, project.directoryName), { recursive: true, force: true });
|
|
329
|
+
this.projects.delete(projectId);
|
|
330
|
+
}
|
|
331
|
+
resolveArtifact(projectId, artifactId) {
|
|
332
|
+
const project = this.projects.get(projectId);
|
|
333
|
+
const stored = project?.artifacts.get(artifactId);
|
|
334
|
+
if (!project || !stored) {
|
|
335
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'artifact is unavailable');
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
project,
|
|
339
|
+
stored,
|
|
340
|
+
filePath: plugins.path.join(this.rootDirectory, project.directoryName, artifactId),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hcnRpZmFjdHN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5hcnRpZmFjdHN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBS3hDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsRCxPQUFPLEVBQ0wsZUFBZSxFQUNmLFFBQVEsRUFDUixxQkFBcUIsRUFDckIsdUJBQXVCLEdBQ3hCLE1BQU0sWUFBWSxDQUFDO0FBYXBCLE1BQU0sT0FBTyxvQkFBb0I7SUFDZCxhQUFhLENBQVM7SUFDdEIsWUFBWSxDQUFTO0lBQ3JCLHNCQUFzQixDQUFTO0lBQy9CLGVBQWUsQ0FBUztJQUN4QixXQUFXLENBQVM7SUFDcEIsaUJBQWlCLENBQVM7SUFDMUIsYUFBYSxDQUFTO0lBQ3RCLGFBQWEsQ0FBUztJQUN0QixHQUFHLENBQWU7SUFDbEIsWUFBWSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBNkIsQ0FBQztJQUNoRCxLQUFLLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztJQUN2QyxjQUFjLEdBQUcsQ0FBQyxDQUFDO0lBQ25CLFVBQVUsR0FBRyxDQUFDLENBQUM7SUFDZixPQUFPLEdBQUcsS0FBSyxDQUFDO0lBQ2hCLFlBQVksQ0FBaUI7SUFDN0IsV0FBVyxDQUFpQjtJQUM1QixVQUFVLENBQWtDO0lBQzVDLFlBQVksR0FBRyxLQUFLLENBQUM7SUFFN0IsWUFBWSxPQUFxQztRQUMvQyxJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1lBQy9GLE1BQU0sSUFBSSxtQkFBbUIs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
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { IBrowserEgressProxyOptions, IBrowserEgressProxyStats } from './interfaces.js';
|
|
2
|
+
export declare class BrowserEgressProxy {
|
|
3
|
+
private readonly projectId;
|
|
4
|
+
private readonly allowedPorts;
|
|
5
|
+
private readonly maxConnections;
|
|
6
|
+
private readonly maxActiveRequests;
|
|
7
|
+
private readonly maxHeaderBytes;
|
|
8
|
+
private readonly connectTimeoutMs;
|
|
9
|
+
private readonly idleTimeoutMs;
|
|
10
|
+
private readonly tunnelLifetimeMs;
|
|
11
|
+
private readonly requestTimeoutMs;
|
|
12
|
+
private readonly maxRequestBytes;
|
|
13
|
+
private readonly maxResponseBytes;
|
|
14
|
+
private readonly maxTunnelBytes;
|
|
15
|
+
private readonly resolver;
|
|
16
|
+
private readonly connector;
|
|
17
|
+
private readonly username;
|
|
18
|
+
private readonly password;
|
|
19
|
+
private readonly expectedAuthorization;
|
|
20
|
+
private readonly clientSockets;
|
|
21
|
+
private readonly upstreamSockets;
|
|
22
|
+
private readonly activeOperations;
|
|
23
|
+
private server?;
|
|
24
|
+
private listenPort?;
|
|
25
|
+
private startPromise?;
|
|
26
|
+
private stopPromise?;
|
|
27
|
+
private lifecycleState;
|
|
28
|
+
private lifecycleController;
|
|
29
|
+
private ordinaryRequests;
|
|
30
|
+
private upgradeRequests;
|
|
31
|
+
private connectRequests;
|
|
32
|
+
private rejectedRequests;
|
|
33
|
+
constructor(options: IBrowserEgressProxyOptions);
|
|
34
|
+
get credentials(): {
|
|
35
|
+
username: string;
|
|
36
|
+
password: string;
|
|
37
|
+
};
|
|
38
|
+
get port(): number;
|
|
39
|
+
get project(): string;
|
|
40
|
+
get allowedTargetPorts(): number[];
|
|
41
|
+
getStats(): IBrowserEgressProxyStats;
|
|
42
|
+
start(): Promise<void>;
|
|
43
|
+
stop(): Promise<void>;
|
|
44
|
+
private startInternal;
|
|
45
|
+
private stopInternal;
|
|
46
|
+
private track;
|
|
47
|
+
private admit;
|
|
48
|
+
private handleHttpRequest;
|
|
49
|
+
private handleConnect;
|
|
50
|
+
private handleUpgrade;
|
|
51
|
+
private authorize;
|
|
52
|
+
private sendProxyAuthenticationRequired;
|
|
53
|
+
private sendSafeFailure;
|
|
54
|
+
private rejectRawSocket;
|
|
55
|
+
private sanitizeHeaders;
|
|
56
|
+
private resolveAbsoluteTarget;
|
|
57
|
+
private resolveAuthority;
|
|
58
|
+
private canonicalizeHostname;
|
|
59
|
+
private resolveHost;
|
|
60
|
+
private openUpstream;
|
|
61
|
+
private waitForConnect;
|
|
62
|
+
private pipeTunnel;
|
|
63
|
+
private readWebSocketHandshake;
|
|
64
|
+
private createOperationSignal;
|
|
65
|
+
private raceAbort;
|
|
66
|
+
private waitForResponseCompletion;
|
|
67
|
+
}
|