@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.
Files changed (51) hide show
  1. package/.smartconfig.json +34 -0
  2. package/changelog.md +11 -0
  3. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  4. package/dist_ts/00_commitinfo_data.js +9 -0
  5. package/dist_ts/actions.d.ts +3 -0
  6. package/dist_ts/actions.js +215 -0
  7. package/dist_ts/classes.artifactstore.d.ts +38 -0
  8. package/dist_ts/classes.artifactstore.js +344 -0
  9. package/dist_ts/classes.egressproxy.d.ts +67 -0
  10. package/dist_ts/classes.egressproxy.js +830 -0
  11. package/dist_ts/classes.flexprovider.d.ts +9 -0
  12. package/dist_ts/classes.flexprovider.js +117 -0
  13. package/dist_ts/classes.framed.d.ts +52 -0
  14. package/dist_ts/classes.framed.js +557 -0
  15. package/dist_ts/classes.runtime.d.ts +202 -0
  16. package/dist_ts/classes.runtime.js +1667 -0
  17. package/dist_ts/confinement.d.ts +2 -0
  18. package/dist_ts/confinement.js +63 -0
  19. package/dist_ts/errors.d.ts +7 -0
  20. package/dist_ts/errors.js +40 -0
  21. package/dist_ts/index.d.ts +11 -0
  22. package/dist_ts/index.js +9 -0
  23. package/dist_ts/interfaces.d.ts +287 -0
  24. package/dist_ts/interfaces.js +2 -0
  25. package/dist_ts/internal.testing.d.ts +9 -0
  26. package/dist_ts/internal.testing.js +2 -0
  27. package/dist_ts/mcp.d.ts +4 -0
  28. package/dist_ts/mcp.js +196 -0
  29. package/dist_ts/plugins.d.ts +20 -0
  30. package/dist_ts/plugins.js +24 -0
  31. package/dist_ts/utils.d.ts +25 -0
  32. package/dist_ts/utils.js +143 -0
  33. package/license.md +21 -0
  34. package/package.json +59 -0
  35. package/readme.hints.md +35 -0
  36. package/readme.md +181 -0
  37. package/ts/00_commitinfo_data.ts +8 -0
  38. package/ts/actions.ts +241 -0
  39. package/ts/classes.artifactstore.ts +432 -0
  40. package/ts/classes.egressproxy.ts +1005 -0
  41. package/ts/classes.flexprovider.ts +134 -0
  42. package/ts/classes.framed.ts +649 -0
  43. package/ts/classes.runtime.ts +2135 -0
  44. package/ts/confinement.ts +90 -0
  45. package/ts/errors.ts +63 -0
  46. package/ts/index.ts +52 -0
  47. package/ts/interfaces.ts +375 -0
  48. package/ts/internal.testing.ts +18 -0
  49. package/ts/mcp.ts +230 -0
  50. package/ts/plugins.ts +28 -0
  51. package/ts/utils.ts +188 -0
package/dist_ts/mcp.js ADDED
@@ -0,0 +1,196 @@
1
+ import * as plugins from './plugins.js';
2
+ import { BrowserRuntimeError } from './errors.js';
3
+ import { commitinfo } from './00_commitinfo_data.js';
4
+ import { validateAgentActionResult } from './actions.js';
5
+ import { validateBoundedString, validateInteger, } from './utils.js';
6
+ const parseBearerToken = (request) => {
7
+ const authorization = request.headers.get('authorization');
8
+ if (!authorization?.startsWith('Bearer ') || authorization.includes(',')) {
9
+ throw new BrowserRuntimeError('CAPABILITY_INVALID');
10
+ }
11
+ return validateBoundedString(authorization.slice('Bearer '.length), 'bearer capability', 16, 512);
12
+ };
13
+ const validateStringList = (value, name) => {
14
+ if (value === undefined)
15
+ return undefined;
16
+ if (!Array.isArray(value) || value.length > 64)
17
+ throw new BrowserRuntimeError('INVALID_INPUT');
18
+ return value.map((entry) => validateBoundedString(entry, name, 1, 2048));
19
+ };
20
+ export const createBrowserRuntimeMcpHttpHandler = (runtime, options) => {
21
+ if (!runtime || !options || typeof options.authenticateMcpRequest !== 'function') {
22
+ throw new BrowserRuntimeError('INVALID_INPUT');
23
+ }
24
+ const trustedOrigins = validateStringList(options.trustedOrigins, 'trustedOrigin');
25
+ const allowedHosts = validateStringList(options.allowedHosts, 'allowedHost');
26
+ if (options.allowMissingOrigin !== undefined && typeof options.allowMissingOrigin !== 'boolean') {
27
+ throw new BrowserRuntimeError('INVALID_INPUT');
28
+ }
29
+ const maxRequestBytes = options.maxRequestBytes === undefined
30
+ ? 256 * 1024
31
+ : validateInteger(options.maxRequestBytes, 'maxRequestBytes', 1024, 1024 * 1024);
32
+ const maxToolResultBytes = options.maxToolResultBytes === undefined
33
+ ? 256 * 1024
34
+ : validateInteger(options.maxToolResultBytes, 'maxToolResultBytes', 1024, 256 * 1024);
35
+ const withLease = async (context, action) => {
36
+ const peerId = validateBoundedString(context.authInfo?.clientId, 'peerId', 1, 128);
37
+ const capabilityToken = parseBearerToken(context.request);
38
+ const signal = AbortSignal.any([context.extra.signal, context.request.signal]);
39
+ signal.throwIfAborted();
40
+ const descriptor = runtime.authorizeCapability(capabilityToken, peerId, 'agent', 'mcp');
41
+ if (descriptor.capabilityId !== context.authInfo?.token) {
42
+ throw new BrowserRuntimeError('CAPABILITY_INVALID');
43
+ }
44
+ const lease = await runtime.acquireLease({
45
+ capabilityToken,
46
+ peerId,
47
+ expectedRole: 'agent',
48
+ expectedSource: 'mcp',
49
+ signal,
50
+ });
51
+ try {
52
+ signal.throwIfAborted();
53
+ return await action(lease, signal);
54
+ }
55
+ finally {
56
+ await lease.release();
57
+ }
58
+ };
59
+ const tabIdSchema = plugins.smartmcp.z.string().min(1).max(128).optional();
60
+ const timeoutSchema = plugins.smartmcp.z.number().int().min(100).max(120_000).optional();
61
+ const tools = [
62
+ {
63
+ name: 'browser_snapshot',
64
+ description: 'Read bounded accessibility text from a browser tab.',
65
+ inputSchema: plugins.smartmcp.z.object({
66
+ tabId: tabIdSchema,
67
+ maxCharacters: plugins.smartmcp.z.number().int().min(256).max(50_000).optional(),
68
+ }).strict(),
69
+ annotations: { readOnlyHint: true, openWorldHint: false },
70
+ handler: async (args, context) => withLease(context, async (lease, signal) => (validateAgentActionResult(await lease.executeAgentAction({
71
+ action: 'snapshot',
72
+ ...(typeof args.tabId === 'string' ? { tabId: args.tabId } : {}),
73
+ ...(typeof args.maxCharacters === 'number'
74
+ ? { maxCharacters: args.maxCharacters }
75
+ : {}),
76
+ }, { signal })))),
77
+ },
78
+ {
79
+ name: 'browser_navigate',
80
+ description: 'Navigate a browser tab to an HTTP or HTTPS URL.',
81
+ inputSchema: plugins.smartmcp.z.object({
82
+ url: plugins.smartmcp.z.string().min(1).max(8192),
83
+ tabId: tabIdSchema,
84
+ timeoutMs: timeoutSchema,
85
+ }).strict(),
86
+ annotations: { readOnlyHint: false, openWorldHint: true },
87
+ handler: async (args, context) => withLease(context, async (lease, signal) => (validateAgentActionResult(await lease.executeAgentAction({
88
+ action: 'navigate',
89
+ url: String(args.url),
90
+ ...(typeof args.tabId === 'string' ? { tabId: args.tabId } : {}),
91
+ ...(typeof args.timeoutMs === 'number' ? { timeoutMs: args.timeoutMs } : {}),
92
+ }, { signal })))),
93
+ },
94
+ {
95
+ name: 'browser_click',
96
+ description: 'Click an element selected from the observed page.',
97
+ inputSchema: plugins.smartmcp.z.object({
98
+ selector: plugins.smartmcp.z.string().min(1).max(4096),
99
+ tabId: tabIdSchema,
100
+ timeoutMs: timeoutSchema,
101
+ }).strict(),
102
+ annotations: { readOnlyHint: false, openWorldHint: true },
103
+ handler: async (args, context) => withLease(context, async (lease, signal) => (validateAgentActionResult(await lease.executeAgentAction({
104
+ action: 'click',
105
+ selector: String(args.selector),
106
+ ...(typeof args.tabId === 'string' ? { tabId: args.tabId } : {}),
107
+ ...(typeof args.timeoutMs === 'number' ? { timeoutMs: args.timeoutMs } : {}),
108
+ }, { signal })))),
109
+ },
110
+ {
111
+ name: 'browser_fill',
112
+ description: 'Fill an element selected from the observed page.',
113
+ inputSchema: plugins.smartmcp.z.object({
114
+ selector: plugins.smartmcp.z.string().min(1).max(4096),
115
+ text: plugins.smartmcp.z.string().max(100_000),
116
+ tabId: tabIdSchema,
117
+ timeoutMs: timeoutSchema,
118
+ }).strict(),
119
+ annotations: { readOnlyHint: false, openWorldHint: true },
120
+ handler: async (args, context) => withLease(context, async (lease, signal) => (validateAgentActionResult(await lease.executeAgentAction({
121
+ action: 'fill',
122
+ selector: String(args.selector),
123
+ text: String(args.text),
124
+ ...(typeof args.tabId === 'string' ? { tabId: args.tabId } : {}),
125
+ ...(typeof args.timeoutMs === 'number' ? { timeoutMs: args.timeoutMs } : {}),
126
+ }, { signal })))),
127
+ },
128
+ {
129
+ name: 'browser_press',
130
+ description: 'Press a key on an element selected from the observed page.',
131
+ inputSchema: plugins.smartmcp.z.object({
132
+ selector: plugins.smartmcp.z.string().min(1).max(4096),
133
+ key: plugins.smartmcp.z.string().min(1).max(64),
134
+ tabId: tabIdSchema,
135
+ timeoutMs: timeoutSchema,
136
+ }).strict(),
137
+ annotations: { readOnlyHint: false, openWorldHint: true },
138
+ handler: async (args, context) => withLease(context, async (lease, signal) => (validateAgentActionResult(await lease.executeAgentAction({
139
+ action: 'press',
140
+ selector: String(args.selector),
141
+ key: String(args.key),
142
+ ...(typeof args.tabId === 'string' ? { tabId: args.tabId } : {}),
143
+ ...(typeof args.timeoutMs === 'number' ? { timeoutMs: args.timeoutMs } : {}),
144
+ }, { signal })))),
145
+ },
146
+ {
147
+ name: 'browser_screenshot',
148
+ description: 'Capture a screenshot as bounded artifact metadata.',
149
+ inputSchema: plugins.smartmcp.z.object({
150
+ tabId: tabIdSchema,
151
+ format: plugins.smartmcp.z.enum(['jpeg', 'png']).optional(),
152
+ quality: plugins.smartmcp.z.number().int().min(0).max(100).optional(),
153
+ }).strict(),
154
+ annotations: { readOnlyHint: true, openWorldHint: false },
155
+ handler: async (args, context) => withLease(context, async (lease, signal) => (validateAgentActionResult(await lease.executeAgentAction({
156
+ action: 'screenshot',
157
+ ...(typeof args.tabId === 'string' ? { tabId: args.tabId } : {}),
158
+ ...(args.format === 'jpeg' || args.format === 'png' ? { format: args.format } : {}),
159
+ ...(typeof args.quality === 'number' ? { quality: args.quality } : {}),
160
+ }, { signal })))),
161
+ },
162
+ ];
163
+ return plugins.smartmcp.createSmartMcpHttpHandler({
164
+ name: '@modelprofile.com/browser-runtime',
165
+ version: commitinfo.version,
166
+ ...(trustedOrigins ? { trustedOrigins } : {}),
167
+ ...(allowedHosts ? { allowedHosts } : {}),
168
+ ...(options.allowMissingOrigin !== undefined
169
+ ? { allowMissingOrigin: options.allowMissingOrigin }
170
+ : {}),
171
+ maxRequestBytes,
172
+ maxToolResultBytes,
173
+ redactError: () => 'Browser tool execution failed.',
174
+ authorize: async ({ request }) => {
175
+ let peerId;
176
+ let capabilityToken;
177
+ try {
178
+ const authentication = await options.authenticateMcpRequest(request);
179
+ peerId = validateBoundedString(authentication?.peerId, 'peerId', 1, 128);
180
+ capabilityToken = parseBearerToken(request);
181
+ const descriptor = runtime.authorizeCapability(capabilityToken, peerId, 'agent', 'mcp');
182
+ return {
183
+ token: descriptor.capabilityId,
184
+ clientId: peerId,
185
+ scopes: ['browser'],
186
+ expiresAt: descriptor.expiresAt,
187
+ };
188
+ }
189
+ catch {
190
+ return new Response('Unauthorized', { status: 401 });
191
+ }
192
+ },
193
+ tools,
194
+ });
195
+ };
196
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWNwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbWNwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFckQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3pELE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsZUFBZSxHQUNoQixNQUFNLFlBQVksQ0FBQztBQUVwQixNQUFNLGdCQUFnQixHQUFHLENBQUMsT0FBZ0IsRUFBVSxFQUFFO0lBQ3BELE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzNELElBQUksQ0FBQyxhQUFhLEVBQUUsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJLGFBQWEsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN6RSxNQUFNLElBQUksbUJBQW1CLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBQ0QsT0FBTyxxQkFBcUIsQ0FDMUIsYUFBYSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEVBQ3JDLG1CQUFtQixFQUNuQixFQUFFLEVBQ0YsR0FBRyxDQUNKLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLGtCQUFrQixHQUFHLENBQUMsS0FBYyxFQUFFLElBQVksRUFBd0IsRUFBRTtJQUNoRixJQUFJLEtBQUssS0FBSyxTQUFTO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDMUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxFQUFFO1FBQUUsTUFBTSxJQUFJLG1CQUFtQixDQUFDLGVBQWUs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
@@ -0,0 +1,20 @@
1
+ import { Buffer } from 'node:buffer';
2
+ import * as crypto from 'node:crypto';
3
+ import * as dns from 'node:dns';
4
+ import * as fs from 'node:fs';
5
+ import * as fsPromises from 'node:fs/promises';
6
+ import * as http from 'node:http';
7
+ import * as net from 'node:net';
8
+ import * as os from 'node:os';
9
+ import * as path from 'node:path';
10
+ import * as stream from 'node:stream';
11
+ import * as tls from 'node:tls';
12
+ import * as url from 'node:url';
13
+ export { Buffer, crypto, dns, fs, fsPromises, http, net, os, path, stream, tls, url };
14
+ import * as flexharness from '@modelprofile.com/flexharness';
15
+ import * as smartagent from '@push.rocks/smartagent';
16
+ import * as smartmcp from '@push.rocks/smartmcp';
17
+ import * as smartpuppeteer from '@push.rocks/smartpuppeteer';
18
+ export { flexharness, smartagent, smartmcp, smartpuppeteer };
19
+ import ipaddr from 'ipaddr.js';
20
+ export { ipaddr };
@@ -0,0 +1,24 @@
1
+ // node native scope
2
+ import { Buffer } from 'node:buffer';
3
+ import * as crypto from 'node:crypto';
4
+ import * as dns from 'node:dns';
5
+ import * as fs from 'node:fs';
6
+ import * as fsPromises from 'node:fs/promises';
7
+ import * as http from 'node:http';
8
+ import * as net from 'node:net';
9
+ import * as os from 'node:os';
10
+ import * as path from 'node:path';
11
+ import * as stream from 'node:stream';
12
+ import * as tls from 'node:tls';
13
+ import * as url from 'node:url';
14
+ export { Buffer, crypto, dns, fs, fsPromises, http, net, os, path, stream, tls, url };
15
+ // foss.global scopes
16
+ import * as flexharness from '@modelprofile.com/flexharness';
17
+ import * as smartagent from '@push.rocks/smartagent';
18
+ import * as smartmcp from '@push.rocks/smartmcp';
19
+ import * as smartpuppeteer from '@push.rocks/smartpuppeteer';
20
+ export { flexharness, smartagent, smartmcp, smartpuppeteer };
21
+ // third-party scope
22
+ import ipaddr from 'ipaddr.js';
23
+ export { ipaddr };
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxLQUFLLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDdEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDOUIsT0FBTyxLQUFLLFVBQVUsTUFBTSxrQkFBa0IsQ0FBQztBQUMvQyxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLEtBQUssR0FBRyxNQUFNLFVBQVUsQ0FBQztBQUNoQyxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUM5QixPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLEtBQUssTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUN0QyxPQUFPLEtBQUssR0FBRyxNQUFNLFVBQVUsQ0FBQztBQUNoQyxPQUFPLEtBQUssR0FBRyxNQUFNLFVBQVUsQ0FBQztBQUVoQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztBQUV0RixxQkFBcUI7QUFDckIsT0FBTyxLQUFLLFdBQVcsTUFBTSwrQkFBK0IsQ0FBQztBQUM3RCxPQUFPLEtBQUssVUFBVSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sS0FBSyxRQUFRLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxLQUFLLGNBQWMsTUFBTSw0QkFBNEIsQ0FBQztBQUU3RCxPQUFPLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsY0FBYyxFQUFFLENBQUM7QUFFN0Qsb0JBQW9CO0FBQ3BCLE9BQU8sTUFBTSxNQUFNLFdBQVcsQ0FBQztBQUUvQixPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMifQ==
@@ -0,0 +1,25 @@
1
+ import * as plugins from './plugins.js';
2
+ export declare const validateBoundedString: (value: unknown, name: string, minimum: number, maximum: number) => string;
3
+ export declare const validateInteger: (value: unknown, name: string, minimum: number, maximum: number) => number;
4
+ export declare const validateOptionalInteger: (value: unknown, name: string, minimum: number, maximum: number, defaultValue: number) => number;
5
+ export declare const validateExactKeys: (value: unknown, allowedKeys: readonly string[], name: string) => Record<string, unknown>;
6
+ export declare const randomId: (bytes?: number) => string;
7
+ export declare const digestToken: (token: string) => plugins.Buffer;
8
+ export declare const digestsEqual: (left: plugins.Buffer, right: plugins.Buffer) => boolean;
9
+ export declare const delay: (milliseconds: number) => Promise<void>;
10
+ export declare const waitBounded: <T>(promise: Promise<T>, timeoutMs: number) => Promise<{
11
+ settled: true;
12
+ value: T;
13
+ } | {
14
+ settled: false;
15
+ }>;
16
+ export declare const truncateString: (value: string, maximum?: number) => string;
17
+ export declare const assertJsonWithoutBytes: (value: unknown, maxBytes?: number) => void;
18
+ export declare class TransitionMutex {
19
+ private locked;
20
+ private waiters;
21
+ tryAcquire(): (() => void) | undefined;
22
+ acquire(): Promise<() => void>;
23
+ get busy(): boolean;
24
+ private createRelease;
25
+ }
@@ -0,0 +1,143 @@
1
+ import * as plugins from './plugins.js';
2
+ import { BrowserRuntimeError } from './errors.js';
3
+ export const validateBoundedString = (value, name, minimum, maximum) => {
4
+ if (typeof value !== 'string') {
5
+ throw new BrowserRuntimeError('INVALID_INPUT', `${name} must be a string`);
6
+ }
7
+ const normalized = value.trim();
8
+ if (normalized.length < minimum || normalized.length > maximum) {
9
+ throw new BrowserRuntimeError('INVALID_INPUT', `${name} must contain between ${minimum} and ${maximum} characters`);
10
+ }
11
+ return normalized;
12
+ };
13
+ export const validateInteger = (value, name, minimum, maximum) => {
14
+ if (!Number.isInteger(value) || value < minimum || value > maximum) {
15
+ throw new BrowserRuntimeError('INVALID_INPUT', `${name} must be an integer between ${minimum} and ${maximum}`);
16
+ }
17
+ return value;
18
+ };
19
+ export const validateOptionalInteger = (value, name, minimum, maximum, defaultValue) => value === undefined
20
+ ? defaultValue
21
+ : validateInteger(value, name, minimum, maximum);
22
+ export const validateExactKeys = (value, allowedKeys, name) => {
23
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
24
+ throw new BrowserRuntimeError('INVALID_INPUT', `${name} must be an object`);
25
+ }
26
+ const record = value;
27
+ const allowed = new Set(allowedKeys);
28
+ for (const key of Object.keys(record)) {
29
+ if (!allowed.has(key)) {
30
+ throw new BrowserRuntimeError('INVALID_INPUT', `${name} contains an unsupported field`);
31
+ }
32
+ }
33
+ return record;
34
+ };
35
+ export const randomId = (bytes = 24) => plugins.crypto.randomBytes(bytes).toString('base64url');
36
+ export const digestToken = (token) => plugins.crypto
37
+ .createHash('sha256')
38
+ .update(token, 'utf8')
39
+ .digest();
40
+ export const digestsEqual = (left, right) => (left.byteLength === right.byteLength && plugins.crypto.timingSafeEqual(left, right));
41
+ export const delay = (milliseconds) => new Promise((resolve) => {
42
+ const timer = setTimeout(resolve, milliseconds);
43
+ timer.unref();
44
+ });
45
+ export const waitBounded = async (promise, timeoutMs) => {
46
+ const timeout = Symbol('timeout');
47
+ let timer;
48
+ const timeoutPromise = new Promise((resolve) => {
49
+ timer = setTimeout(() => resolve(timeout), timeoutMs);
50
+ timer.unref();
51
+ });
52
+ try {
53
+ const result = await Promise.race([promise, timeoutPromise]);
54
+ return result === timeout
55
+ ? { settled: false }
56
+ : { settled: true, value: result };
57
+ }
58
+ finally {
59
+ if (timer)
60
+ clearTimeout(timer);
61
+ }
62
+ };
63
+ export const truncateString = (value, maximum = 2048) => (value.length <= maximum ? value : value.slice(0, maximum));
64
+ export const assertJsonWithoutBytes = (value, maxBytes = 256 * 1024) => {
65
+ const seen = new WeakSet();
66
+ const visit = (current, depth) => {
67
+ if (depth > 24) {
68
+ throw new BrowserRuntimeError('PROTOCOL_ERROR');
69
+ }
70
+ if (current instanceof Uint8Array
71
+ || current instanceof ArrayBuffer
72
+ || ArrayBuffer.isView(current)) {
73
+ throw new BrowserRuntimeError('PROTOCOL_ERROR');
74
+ }
75
+ if (!current || typeof current !== 'object') {
76
+ if (typeof current === 'bigint'
77
+ || typeof current === 'function'
78
+ || typeof current === 'symbol'
79
+ || typeof current === 'undefined'
80
+ || (typeof current === 'number' && !Number.isFinite(current))) {
81
+ throw new BrowserRuntimeError('PROTOCOL_ERROR');
82
+ }
83
+ return;
84
+ }
85
+ if (seen.has(current)) {
86
+ throw new BrowserRuntimeError('PROTOCOL_ERROR');
87
+ }
88
+ seen.add(current);
89
+ if (Array.isArray(current)) {
90
+ for (const entry of current)
91
+ visit(entry, depth + 1);
92
+ return;
93
+ }
94
+ const prototype = Object.getPrototypeOf(current);
95
+ if (prototype !== Object.prototype && prototype !== null) {
96
+ throw new BrowserRuntimeError('PROTOCOL_ERROR');
97
+ }
98
+ for (const entry of Object.values(current)) {
99
+ visit(entry, depth + 1);
100
+ }
101
+ };
102
+ visit(value, 0);
103
+ const serialized = JSON.stringify(value);
104
+ if (plugins.Buffer.byteLength(serialized, 'utf8') > maxBytes) {
105
+ throw new BrowserRuntimeError('PROTOCOL_ERROR');
106
+ }
107
+ };
108
+ export class TransitionMutex {
109
+ locked = false;
110
+ waiters = [];
111
+ tryAcquire() {
112
+ if (this.locked)
113
+ return undefined;
114
+ this.locked = true;
115
+ return this.createRelease();
116
+ }
117
+ async acquire() {
118
+ const immediate = this.tryAcquire();
119
+ if (immediate)
120
+ return immediate;
121
+ await new Promise((resolve) => this.waiters.push(resolve));
122
+ return this.createRelease();
123
+ }
124
+ get busy() {
125
+ return this.locked;
126
+ }
127
+ createRelease() {
128
+ let released = false;
129
+ return () => {
130
+ if (released)
131
+ return;
132
+ released = true;
133
+ const next = this.waiters.shift();
134
+ if (next) {
135
+ next();
136
+ }
137
+ else {
138
+ this.locked = false;
139
+ }
140
+ };
141
+ }
142
+ }
143
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFbEQsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsQ0FDbkMsS0FBYyxFQUNkLElBQVksRUFDWixPQUFlLEVBQ2YsT0FBZSxFQUNQLEVBQUU7SUFDVixJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxtQkFBbUIsQ0FBQyxlQUFlLEVBQUUsR0FBRyxJQUFJLG1CQUFtQixDQUFDLENBQUM7SUFDN0UsQ0FBQztJQUNELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUcsT0FBTyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUcsT0FBTyxFQUFFLENBQUM7UUFDL0QsTUFBTSxJQUFJLG1CQUFtQixDQUMzQixlQUFlLEVBQ2YsR0FBRyxJQUFJLHlCQUF5QixPQUFPLFFBQVEsT0FBTyxhQUFhLENBQ3BFLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxVQUFVLENBQUM7QUFDcEIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLENBQzdCLEtBQWMsRUFDZCxJQUFZLEVBQ1osT0FBZSxFQUNmLE9BQWUsRUFDUCxFQUFFO0lBQ1YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUssS0FBZ0IsR0FBRyxPQUFPLElBQUssS0FBZ0IsR0FBRyxPQUFPLEVBQUUsQ0FBQztRQUMzRixNQUFNLElBQUksbUJBQW1CLENBQzNCLGVBQWUsRUFDZixHQUFHLElBQUksK0JBQStCLE9BQU8sUUFBUSxPQUFPLEVBQUUsQ0FDL0QsQ0FBQztJQUNK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
package/license.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Task Venture Capital GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@modelprofile.com/browser-runtime",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "description": "Parent-owned, project-scoped Chromium runtime with authenticated human and agent control, fail-closed egress, bounded artifacts, and Flex/MCP adapters.",
6
+ "main": "dist_ts/index.js",
7
+ "typings": "dist_ts/index.d.ts",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist_ts/index.d.ts",
12
+ "import": "./dist_ts/index.js"
13
+ }
14
+ },
15
+ "author": "Task Venture Capital GmbH",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://code.foss.global/modelprofile.com/browser-runtime.git"
20
+ },
21
+ "homepage": "https://code.foss.global/modelprofile.com/browser-runtime",
22
+ "bugs": {
23
+ "url": "https://community.foss.global/"
24
+ },
25
+ "os": [
26
+ "linux"
27
+ ],
28
+ "engines": {
29
+ "node": ">=24"
30
+ },
31
+ "dependencies": {
32
+ "@modelprofile.com/flexharness": "^3.1.0",
33
+ "@push.rocks/smartagent": "^4.8.0",
34
+ "@push.rocks/smartmcp": "^0.3.0",
35
+ "@push.rocks/smartpuppeteer": "^2.3.0",
36
+ "ipaddr.js": "^2.5.0"
37
+ },
38
+ "devDependencies": {
39
+ "@git.zone/tsbuild": "4.4.2",
40
+ "@git.zone/tsrun": "2.0.6",
41
+ "@git.zone/tstest": "4.0.0",
42
+ "@types/node": "26.2.0"
43
+ },
44
+ "files": [
45
+ "ts/**/*",
46
+ "dist_ts/**/*",
47
+ ".smartconfig.json",
48
+ "readme.md",
49
+ "readme.hints.md",
50
+ "changelog.md",
51
+ "license.md"
52
+ ],
53
+ "scripts": {
54
+ "build": "tsbuild",
55
+ "test": "pnpm run build && tstest test/ --verbose --logfile",
56
+ "check:test": "tsbuild check 'test/**/*'",
57
+ "test:real-chrome": "BROWSER_RUNTIME_REAL_CHROME=1 tstest test/test.realchrome.node.ts --verbose --logfile --timeout 180"
58
+ }
59
+ }
@@ -0,0 +1,35 @@
1
+ # readme.hints.md
2
+
3
+ Durable implementation findings for `@modelprofile.com/browser-runtime`.
4
+
5
+ ## Ownership and lifecycle
6
+
7
+ - Capability authorization uses bounded pending reservations. A project slot is inserted only after host authorization succeeds, so denied project IDs cannot consume slot quota. Its transition mutex, generation, lease, active operation, frame subscriber, browser session, proxy, profile, and idle timer form one ownership domain.
8
+ - Agent lease admission and every agent operation use try-lock semantics. A transition, lease, or operation returns `BUSY`; work is never queued behind another agent operation.
9
+ - Human admission marks a fencing generation, aborts an agent lease and operation, releases the mutex while waiting, and verifies the same generation before publishing the human lease. Work that does not quiesce is escalated through `LiveBrowserSession.terminate()`.
10
+ - Profiles are deleted or reused only after confirmed process-group death. An unconfirmed termination permanently fences the slot and leaves the session/profile ownership reachable for a later retirement or `stop()` retry.
11
+ - The runtime lock is created with `open(..., 'wx')` and is never treated as stale. A failed start after lock acquisition retains lock ownership so the same runtime object can retry or stop cleanly.
12
+
13
+ ## Capability boundary
14
+
15
+ - Capability tokens are returned once. Runtime records retain only SHA-256 digests and compare exact digests with `timingSafeEqual`; project, actor, role, peer, source, optional Flex scope/session, and expiry are immutable server-owned bindings.
16
+ - Expiry and revocation abort work, close frame state, release the lease, and invoke the host disconnect callback or close the exact trusted framed peer. Cleanup remains tracked and `stop()` drains it.
17
+ - Operation IDs are generated independently from capability, lease, framed request, tab, and artifact IDs. Audit callbacks receive bounded metadata and are time-bounded.
18
+
19
+ ## Browser confinement
20
+
21
+ - Production session options are assembled only inside `BrowserRuntime`: sandbox required, random private user data directory, authenticated project proxy, fixed network-reduction arguments, external browser DNS failure rules, denied downloads/file choosers/permissions, and HTTP(S)-only public navigation. Deterministic injection uses a non-root-exported test symbol and is not part of the package API.
22
+ - `allowEvaluation` exists only to run the private confinement probe. No runtime lease, framed message, Flex tool, or MCP tool projects evaluation.
23
+ - The production probe owns a random loopback origin on a port outside the project allowlist, checks proxy traversal plus zero origin hits, checks synthetic `.invalid` traversal, and checks forced WebRTC policy by observing ICE candidates.
24
+
25
+ ## Egress and artifacts
26
+
27
+ - HTTP absolute-form, WebSocket Upgrade, and CONNECT all use the same canonical target resolver. Every DNS answer must be public unicast; one bad answer rejects the entire set. The selected answer is dialed numerically through the connector seam.
28
+ - Origin host semantics remain in `Host`; CONNECT leaves end-to-end TLS/SNI untouched. Proxy authorization and inherited hop-by-hop headers never reach upstreams.
29
+ - Artifact path components are generated or keyed digests, never caller IDs. The store exclusively owns its root; serialized admission enforces project and aggregate quotas. Writes are private, temporary, synced, and atomically renamed; reads use no-follow handles and verify size plus SHA-256.
30
+
31
+ ## Adapter boundary
32
+
33
+ - Framed messages contain no project, actor, role, source, scope, session, or peer selectors. The parent supplies peer, Flex scope, and Flex session out of band, and only one attached framed peer may own a peer ID.
34
+ - Flex resolves only a token; framed acquisition validates its immutable server-side `flex` source and scope/session bindings. SmartAgent's browser tool is configured with exactly navigate, snapshot, screenshot, click, fill, and press.
35
+ - MCP performs independent request authentication before bearer validation. Its tool list contains exactly the same six actions. Every call verifies the immutable authorization identity, acquires and releases an MCP-source agent lease, and combines SmartMCP's tool signal with the Web request signal.