@opengeni/runtime 3.1.3-canary.38890816741001 → 3.3.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.
@@ -9697,6 +9697,9 @@ async function transferEditorFile(input) {
9697
9697
  return { recovered: false };
9698
9698
  }
9699
9699
 
9700
+ // src/sandbox/browser-control-http.ts
9701
+ var BROWSER_CONTROL_HTTP_REPLY_GRACE_MS = 5e3;
9702
+
9700
9703
  // src/sandbox/selfhosted/retry-policy.ts
9701
9704
  var SELFHOSTED_IDEMPOTENT_READONLY_OPS = /* @__PURE__ */ new Set([
9702
9705
  "ping",
@@ -10920,6 +10923,7 @@ var SelfhostedSession = class {
10920
10923
  resourcePolicySupported;
10921
10924
  operationCpuQuotaSupported;
10922
10925
  transactionalFsWriteSupported;
10926
+ browserControlHttpSupported;
10923
10927
  defaultOpStream;
10924
10928
  connectionInstanceId;
10925
10929
  resolveOperationAdmission;
@@ -10980,6 +10984,7 @@ var SelfhostedSession = class {
10980
10984
  this.resourcePolicySupported = deps.operationResourcePolicySupported === true;
10981
10985
  this.operationCpuQuotaSupported = deps.operationCpuQuotaSupported === true;
10982
10986
  this.transactionalFsWriteSupported = deps.transactionalFsWriteSupported === true;
10987
+ this.browserControlHttpSupported = deps.browserControlHttpSupported === true;
10983
10988
  this.defaultOpStream = deps.opStream;
10984
10989
  this.connectionInstanceId = deps.connectionInstanceId;
10985
10990
  this.resolveOperationAdmission = deps.resolveOperationAdmission;
@@ -10992,7 +10997,8 @@ var SelfhostedSession = class {
10992
10997
  subject: this.subject,
10993
10998
  resourcePolicy: this.resourcePolicy,
10994
10999
  opStream: deps.opStream,
10995
- transactionalFsWriteSupported: this.transactionalFsWriteSupported
11000
+ transactionalFsWriteSupported: this.transactionalFsWriteSupported,
11001
+ browserControlHttpSupported: this.browserControlHttpSupported
10996
11002
  }) : void 0;
10997
11003
  this.state = {
10998
11004
  agentId: deps.agentId,
@@ -11053,7 +11059,8 @@ var SelfhostedSession = class {
11053
11059
  subject: this.subject,
11054
11060
  resourcePolicy: commandPolicy ? this.resourcePolicy : void 0,
11055
11061
  opStream: this.defaultOpStream,
11056
- transactionalFsWriteSupported: this.transactionalFsWriteSupported
11062
+ transactionalFsWriteSupported: this.transactionalFsWriteSupported,
11063
+ browserControlHttpSupported: this.browserControlHttpSupported
11057
11064
  };
11058
11065
  }
11059
11066
  const resolved = await this.resolveOperationAdmission();
@@ -11087,7 +11094,8 @@ var SelfhostedSession = class {
11087
11094
  ),
11088
11095
  resourcePolicy: commandPolicy ? resourcePolicy : void 0,
11089
11096
  opStream: resolved.opStream,
11090
- transactionalFsWriteSupported: resolved.transactionalFsWriteSupported === true
11097
+ transactionalFsWriteSupported: resolved.transactionalFsWriteSupported === true,
11098
+ browserControlHttpSupported: resolved.browserControlHttpSupported === true
11091
11099
  };
11092
11100
  }
11093
11101
  async admitCommand() {
@@ -12078,6 +12086,90 @@ var SelfhostedSession = class {
12078
12086
  }
12079
12087
  return result.browserControlEnsure;
12080
12088
  }
12089
+ /** Send one request to the agent-owned controller of an exact authority
12090
+ * scope, served inside the runner over loopback without starting a process.
12091
+ * `unsupported` means this connection's runner does not serve it and nothing
12092
+ * was sent. `controller_absent` means no controller for that scope and
12093
+ * generation accepted the request, so it was not delivered and the caller may
12094
+ * ensure the controller and send again. A body too large for one reply is
12095
+ * drained from the runner's spool; the request is never repeated. */
12096
+ async browserControlHttp(request) {
12097
+ const admission = await this.admitOperation(false);
12098
+ if (!admission.browserControlHttpSupported) return { kind: "unsupported" };
12099
+ const rpcTimeoutMs = request.timeoutMs + BROWSER_CONTROL_HTTP_REPLY_GRACE_MS;
12100
+ let result;
12101
+ try {
12102
+ result = await this.call(
12103
+ {
12104
+ $case: "browserControlHttp",
12105
+ browserControlHttp: {
12106
+ scopeId: request.scopeId,
12107
+ scopeGeneration: request.scopeGeneration,
12108
+ method: request.method,
12109
+ path: request.path,
12110
+ bearerToken: request.bearerToken,
12111
+ body: request.body ?? new Uint8Array(),
12112
+ hasBody: request.body !== void 0,
12113
+ timeoutMs: request.timeoutMs,
12114
+ maxResponseBytes: String(request.maxResponseBytes)
12115
+ }
12116
+ },
12117
+ rpcTimeoutMs,
12118
+ admission
12119
+ );
12120
+ } catch (error) {
12121
+ if (error instanceof SelfhostedControlError && error.code === ErrorCode2.ERROR_CODE_NOT_FOUND) {
12122
+ return { kind: "controller_absent" };
12123
+ }
12124
+ throw error;
12125
+ }
12126
+ if (result.$case !== "browserControlHttp") {
12127
+ throw new Error(`selfhosted browserControlHttp: unexpected result ${result.$case}`);
12128
+ }
12129
+ const response = result.browserControlHttp;
12130
+ const totalBytes = Number(response.totalBytes);
12131
+ if (!Number.isSafeInteger(totalBytes) || totalBytes < response.body.byteLength || totalBytes > request.maxResponseBytes) {
12132
+ throw new Error("selfhosted browserControlHttp: response length is invalid");
12133
+ }
12134
+ let body = response.body;
12135
+ if (response.spoolId) {
12136
+ const complete = new Uint8Array(totalBytes);
12137
+ complete.set(response.body, 0);
12138
+ let offset = response.body.byteLength;
12139
+ for (; ; ) {
12140
+ const read = await this.call(
12141
+ {
12142
+ $case: "browserControlHttpRead",
12143
+ browserControlHttpRead: { spoolId: response.spoolId, offset: String(offset) }
12144
+ },
12145
+ this.timeoutMs,
12146
+ admission
12147
+ );
12148
+ if (read.$case !== "browserControlHttpRead") {
12149
+ throw new Error(`selfhosted browserControlHttpRead: unexpected result ${read.$case}`);
12150
+ }
12151
+ const part = read.browserControlHttpRead;
12152
+ if (offset + part.data.byteLength > totalBytes) {
12153
+ throw new Error("selfhosted browserControlHttpRead: response exceeds its length");
12154
+ }
12155
+ complete.set(part.data, offset);
12156
+ offset += part.data.byteLength;
12157
+ if (part.done) break;
12158
+ if (part.data.byteLength === 0) {
12159
+ throw new Error("selfhosted browserControlHttpRead: spool made no progress");
12160
+ }
12161
+ }
12162
+ if (offset !== totalBytes) {
12163
+ throw new Error("selfhosted browserControlHttpRead: response is incomplete");
12164
+ }
12165
+ body = complete;
12166
+ } else if (response.body.byteLength !== totalBytes) {
12167
+ throw new Error("selfhosted browserControlHttp: response is incomplete");
12168
+ }
12169
+ const headers = /* @__PURE__ */ new Map();
12170
+ for (const header of response.headers) headers.set(header.name.toLowerCase(), header.value);
12171
+ return { kind: "response", status: response.status, headers, body };
12172
+ }
12081
12173
  /** Open one browser-native frame producer and return its canonical relay
12082
12174
  * endpoint. This does not route through `resolveExposedPort`: that legacy
12083
12175
  * method allocates PTY/desktop resources based on fixed ports, while this op
@@ -12222,6 +12314,7 @@ var SelfhostedSandboxClient = class {
12222
12314
  operationResourcePolicySupported;
12223
12315
  operationCpuQuotaSupported;
12224
12316
  transactionalFsWriteSupported;
12317
+ browserControlHttpSupported;
12225
12318
  resolveOperationAdmission;
12226
12319
  adoptBackgroundCommand;
12227
12320
  settleBackgroundCommand;
@@ -12245,6 +12338,7 @@ var SelfhostedSandboxClient = class {
12245
12338
  this.operationResourcePolicySupported = opts.operationResourcePolicySupported;
12246
12339
  this.operationCpuQuotaSupported = opts.operationCpuQuotaSupported;
12247
12340
  this.transactionalFsWriteSupported = opts.transactionalFsWriteSupported;
12341
+ this.browserControlHttpSupported = opts.browserControlHttpSupported;
12248
12342
  this.resolveOperationAdmission = opts.resolveOperationAdmission;
12249
12343
  this.adoptBackgroundCommand = opts.adoptBackgroundCommand;
12250
12344
  this.settleBackgroundCommand = opts.settleBackgroundCommand;
@@ -12279,6 +12373,7 @@ var SelfhostedSandboxClient = class {
12279
12373
  } : {},
12280
12374
  ...this.operationCpuQuotaSupported !== void 0 ? { operationCpuQuotaSupported: this.operationCpuQuotaSupported } : {},
12281
12375
  transactionalFsWriteSupported: this.transactionalFsWriteSupported === true,
12376
+ browserControlHttpSupported: this.browserControlHttpSupported === true,
12282
12377
  ...this.resolveOperationAdmission !== void 0 ? { resolveOperationAdmission: this.resolveOperationAdmission } : {},
12283
12378
  ...this.adoptBackgroundCommand !== void 0 ? { adoptBackgroundCommand: this.adoptBackgroundCommand } : {},
12284
12379
  ...this.settleBackgroundCommand !== void 0 ? { settleBackgroundCommand: this.settleBackgroundCommand } : {},
@@ -12350,6 +12445,7 @@ async function buildSelfhostedBackendSession(deps) {
12350
12445
  } : {},
12351
12446
  ...deps.operationCpuQuotaSupported !== void 0 ? { operationCpuQuotaSupported: deps.operationCpuQuotaSupported } : {},
12352
12447
  transactionalFsWriteSupported: deps.transactionalFsWriteSupported === true,
12448
+ browserControlHttpSupported: deps.browserControlHttpSupported === true,
12353
12449
  ...deps.resolveOperationAdmission !== void 0 ? { resolveOperationAdmission: deps.resolveOperationAdmission } : {},
12354
12450
  ...deps.adoptBackgroundCommand !== void 0 ? { adoptBackgroundCommand: deps.adoptBackgroundCommand } : {},
12355
12451
  ...deps.settleBackgroundCommand !== void 0 ? { settleBackgroundCommand: deps.settleBackgroundCommand } : {},
@@ -15000,6 +15096,18 @@ var BrowserControlClient = class {
15000
15096
  "signed Channel B requires a host-fetch controller endpoint"
15001
15097
  );
15002
15098
  }
15099
+ const native = await this.requestNative(input, BROWSER_CONTROL_MAX_JSON_BYTES);
15100
+ if (native) {
15101
+ let text;
15102
+ try {
15103
+ text = new TextDecoder("utf-8", { fatal: true }).decode(native.body);
15104
+ } catch (error) {
15105
+ throw new BrowserControlProtocolError("browser controller response is not UTF-8", {
15106
+ cause: error
15107
+ });
15108
+ }
15109
+ return parseEnvelope(text, native.status);
15110
+ }
15003
15111
  if (this.session.execWithInput && (input.body === void 0 || Buffer.byteLength(JSON.stringify(input.body)) <= 32 * 1024)) {
15004
15112
  try {
15005
15113
  const response = await this.requestStream(input, BROWSER_CONTROL_MAX_JSON_BYTES);
@@ -15144,6 +15252,17 @@ var BrowserControlClient = class {
15144
15252
  "signed Channel B requires a host-fetch controller endpoint"
15145
15253
  );
15146
15254
  }
15255
+ const nativeFrame = await this.requestNative(
15256
+ input,
15257
+ input.surface === "browser" ? 24 * 1024 * 1024 : COMPUTER_SCREENSHOT_MAX_BYTES
15258
+ );
15259
+ if (nativeFrame) {
15260
+ if (nativeFrame.status < 200 || nativeFrame.status >= 300) {
15261
+ parseEnvelope(new TextDecoder().decode(nativeFrame.body), nativeFrame.status);
15262
+ throw new BrowserControlProtocolError("browser controller image response is invalid");
15263
+ }
15264
+ return controllerImageFrame(nativeFrame.body, nativeFrame.headers, input);
15265
+ }
15147
15266
  if (this.session.execWithInput) {
15148
15267
  try {
15149
15268
  const response = await this.requestStream(
@@ -15286,8 +15405,61 @@ var BrowserControlClient = class {
15286
15405
  }
15287
15406
  }
15288
15407
  async controllerPort() {
15408
+ if (!this.nativeAuthority || !this.session.ensureBrowserControl) return this.port;
15409
+ return await this.ensureControllerPort(false);
15410
+ }
15411
+ /** The agent-native transport: one in-process loopback request on the
15412
+ * Connected Machine, addressed by authority scope, with no process started.
15413
+ * Null when the placement does not serve it; the caller then keeps its
15414
+ * command transport. A controller that is not running receives nothing, so
15415
+ * it is ensured and the request sent once more whatever its method. */
15416
+ async requestNative(input, maxResponseBytes, retry = true) {
15417
+ const authority = this.nativeAuthority;
15418
+ if (!authority || !this.session.browserControlHttp || !this.session.ensureBrowserControl) {
15419
+ return null;
15420
+ }
15421
+ const method = input.method;
15422
+ if (method !== "GET" && method !== "POST" && method !== "PUT" && method !== "DELETE") {
15423
+ throw new BrowserControlProtocolError("browser controller request method is invalid");
15424
+ }
15425
+ localControllerUrl(this.port, input.path);
15426
+ const body = input.body === void 0 ? void 0 : new TextEncoder().encode(JSON.stringify(input.body));
15427
+ if (body !== void 0 && body.byteLength > BROWSER_CONTROL_MAX_JSON_BYTES) {
15428
+ throw new RangeError("browser controller request body is too large");
15429
+ }
15430
+ let outcome;
15431
+ try {
15432
+ outcome = await this.session.browserControlHttp({
15433
+ scopeId: authority.scopeId,
15434
+ scopeGeneration: authority.scopeGeneration,
15435
+ method,
15436
+ path: input.path,
15437
+ bearerToken: requireToken(input.token, "browser controller token"),
15438
+ ...body === void 0 ? {} : { body },
15439
+ timeoutMs: boundedTimeout2(input.timeoutMs ?? this.timeoutMs),
15440
+ maxResponseBytes
15441
+ });
15442
+ } catch (error) {
15443
+ if (retry && method === "GET") {
15444
+ await this.ensureControllerPort(true);
15445
+ return await this.requestNative(input, maxResponseBytes, false);
15446
+ }
15447
+ throw new BrowserControlTransportError("browser controller request transport failed", {
15448
+ cause: error
15449
+ });
15450
+ }
15451
+ if (outcome.kind === "unsupported") return null;
15452
+ if (outcome.kind === "controller_absent") {
15453
+ if (!retry) throw new BrowserControlTransportError("browser controller is not running");
15454
+ await this.ensureControllerPort(true);
15455
+ return await this.requestNative(input, maxResponseBytes, false);
15456
+ }
15457
+ return outcome;
15458
+ }
15459
+ async ensureControllerPort(replace) {
15289
15460
  if (!this.nativeAuthority || !this.session.ensureBrowserControl) return this.port;
15290
15461
  const key = nativeControllerKey(this.nativeAuthority);
15462
+ if (replace) nativeControllerPorts.delete(key);
15291
15463
  const cached = nativeControllerPorts.get(key);
15292
15464
  if (cached !== void 0) return cached;
15293
15465
  const ensured = await this.session.ensureBrowserControl({
@@ -18876,6 +19048,7 @@ function makeActiveBackendResolver(deps) {
18876
19048
  operationResourcePolicySupported: connection.operationResourcePolicySupported,
18877
19049
  operationCpuQuotaSupported: connection.operationCpuQuotaSupported,
18878
19050
  transactionalFsWriteSupported: connection.transactionalFsWriteSupported === true,
19051
+ browserControlHttpSupported: connection.browserControlHttpSupported === true,
18879
19052
  // The routing proxy caches this session by sandbox+epoch, but command
18880
19053
  // policy and runner authority are mutable. Re-read one coherent DB
18881
19054
  // snapshot only when a new exec/Git is admitted.
@@ -20381,4 +20554,4 @@ export {
20381
20554
  collectSandboxEnvironment2 as collectSandboxEnvironment,
20382
20555
  parseExposedPorts2 as parseExposedPorts
20383
20556
  };
20384
- //# sourceMappingURL=chunk-462CH77G.js.map
20557
+ //# sourceMappingURL=chunk-EK7IW2FR.js.map