@opengeni/runtime 4.0.1 → 4.0.3-canary.36079201993001
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/{agent-RJQLKFIW.js → agent-ME6HT4DH.js} +2 -2
- package/dist/assets/codemode-client.json +1 -1
- package/dist/browser-action-json-schema.d.ts +4 -0
- package/dist/{chunk-J5AR5XAJ.js → chunk-GBVN7WSK.js} +377 -210
- package/dist/chunk-GBVN7WSK.js.map +1 -0
- package/dist/{chunk-ZG2YH25H.js → chunk-JAYHA6BF.js} +2 -2
- package/dist/{chunk-UNICCRW5.js → chunk-LZIXCZUV.js} +6 -3
- package/dist/{chunk-UNICCRW5.js.map → chunk-LZIXCZUV.js.map} +1 -1
- package/dist/{chunk-J6J3VYFW.js → chunk-OGG5NQLA.js} +597 -65
- package/dist/chunk-OGG5NQLA.js.map +1 -0
- package/dist/{chunk-SPT3PLMX.js → chunk-PRHMSM6C.js} +2 -2
- package/dist/context-compaction.d.ts +4 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.js +9 -7
- package/dist/interaction-tools.d.ts +1 -1
- package/dist/{lazy-manifest-OEYEHNVY.js → lazy-manifest-GCGUFIWP.js} +3 -3
- package/dist/{localSources-TWHTEKGO.js → localSources-FDH65AFI.js} +4 -4
- package/dist/operational-instructions.d.ts +1 -1
- package/dist/sandbox/browser-control-client.d.ts +28 -1
- package/dist/sandbox/index.d.ts +2 -2
- package/dist/sandbox/index.js +6 -6
- package/dist/sandbox/providers/modal-command-router-wire.d.ts +8 -0
- package/dist/sandbox/providers/modal.d.ts +5 -6
- package/dist/workspace-tool-gateway.js +5 -5
- package/package.json +11 -11
- package/src/browser-action-json-schema.ts +10 -0
- package/src/bundled_artifact_skills/opengeni-documents/SKILL.md +4 -1
- package/src/bundled_artifact_skills/opengeni-documents/references/api.md +20 -0
- package/src/bundled_default_skills/opengeni-client/SKILL.md +4 -1
- package/src/bundled_default_skills/opengeni-client/references/discovery-and-autonomy.md +31 -0
- package/src/bundled_default_skills/opengeni-client/references/runtime-profile-and-verification.md +32 -0
- package/src/context-compaction.ts +19 -3
- package/src/index.ts +100 -36
- package/src/interaction-tools.ts +656 -48
- package/src/operational-instructions.ts +1 -1
- package/src/sandbox/browser-control-client.ts +241 -26
- package/src/sandbox/index.ts +3 -1
- package/src/sandbox/providers/modal-command-control.ts +7 -1
- package/src/sandbox/providers/modal-command-router-wire.ts +47 -6
- package/src/sandbox/providers/modal.ts +16 -24
- package/src/sandbox/routing/routing-session.ts +4 -2
- package/dist/chunk-J5AR5XAJ.js.map +0 -1
- package/dist/chunk-J6J3VYFW.js.map +0 -1
- /package/dist/{agent-RJQLKFIW.js.map → agent-ME6HT4DH.js.map} +0 -0
- /package/dist/{chunk-ZG2YH25H.js.map → chunk-JAYHA6BF.js.map} +0 -0
- /package/dist/{chunk-SPT3PLMX.js.map → chunk-PRHMSM6C.js.map} +0 -0
- /package/dist/{lazy-manifest-OEYEHNVY.js.map → lazy-manifest-GCGUFIWP.js.map} +0 -0
- /package/dist/{localSources-TWHTEKGO.js.map → localSources-FDH65AFI.js.map} +0 -0
|
@@ -26,14 +26,14 @@ import {
|
|
|
26
26
|
truncateOutput,
|
|
27
27
|
validateCredentialPair,
|
|
28
28
|
validateRemoteSandboxPathForManifest
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-PRHMSM6C.js";
|
|
30
30
|
import {
|
|
31
31
|
NoopSnapshotSpec,
|
|
32
32
|
isNoopSnapshotSpec,
|
|
33
33
|
normalizeSandboxClientCreateArgs,
|
|
34
34
|
resolveSandboxArchiveLimits,
|
|
35
35
|
validateSandboxArchiveLimits
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-JAYHA6BF.js";
|
|
37
37
|
import {
|
|
38
38
|
Environment,
|
|
39
39
|
FileMode,
|
|
@@ -96,7 +96,7 @@ import {
|
|
|
96
96
|
shellQuote,
|
|
97
97
|
stableJsonStringify,
|
|
98
98
|
withSandboxSpan
|
|
99
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-LZIXCZUV.js";
|
|
100
100
|
|
|
101
101
|
// src/sandbox/index.ts
|
|
102
102
|
import { collectSandboxEnvironment, parseExposedPorts } from "@opengeni/config";
|
|
@@ -6567,7 +6567,7 @@ var CloudflareSandboxSession = class {
|
|
|
6567
6567
|
async materializeEntry(args) {
|
|
6568
6568
|
assertSandboxEntryMetadataSupported("CloudflareSandboxClient", args.path, args.entry, MOUNT_MANIFEST_METADATA_SUPPORT);
|
|
6569
6569
|
if (entryContainsLocalSource(args.entry)) {
|
|
6570
|
-
const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-
|
|
6570
|
+
const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-FDH65AFI.js");
|
|
6571
6571
|
await applyLocalSourceManifestEntryToState2(this.state, args.path, args.entry, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(args.runAs));
|
|
6572
6572
|
return;
|
|
6573
6573
|
}
|
|
@@ -6578,7 +6578,7 @@ var CloudflareSandboxSession = class {
|
|
|
6578
6578
|
assertSandboxManifestMetadataSupported("CloudflareSandboxClient", manifest, MOUNT_MANIFEST_METADATA_SUPPORT);
|
|
6579
6579
|
assertCloudflareManifestMountsSupported(manifest);
|
|
6580
6580
|
if (manifestContainsLocalSource(manifest)) {
|
|
6581
|
-
const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-
|
|
6581
|
+
const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-FDH65AFI.js");
|
|
6582
6582
|
await applyLocalSourceManifestToState2(this.state, manifest, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(runAs));
|
|
6583
6583
|
return;
|
|
6584
6584
|
}
|
|
@@ -15848,8 +15848,9 @@ function notifyDurableOpOwnershipTransferred(opId) {
|
|
|
15848
15848
|
storage.getStore()?.onDurableOpOwnershipTransferred?.(opId);
|
|
15849
15849
|
}
|
|
15850
15850
|
|
|
15851
|
-
// src/sandbox/
|
|
15852
|
-
import {
|
|
15851
|
+
// src/sandbox/providers/modal-command-router-wire.ts
|
|
15852
|
+
import { Client, Metadata, credentials, status } from "@grpc/grpc-js";
|
|
15853
|
+
import protobuf from "protobufjs";
|
|
15853
15854
|
|
|
15854
15855
|
// src/sandbox/provider-command-session.ts
|
|
15855
15856
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
@@ -15895,6 +15896,219 @@ function admittedProviderCommandHandle() {
|
|
|
15895
15896
|
return admission.getStore();
|
|
15896
15897
|
}
|
|
15897
15898
|
|
|
15899
|
+
// src/sandbox/providers/modal-command-router-wire.ts
|
|
15900
|
+
var modalRouterWire = protobuf.parse(`syntax = "proto3";
|
|
15901
|
+
message Identity { string task_id = 1; string exec_id = 2; }
|
|
15902
|
+
message Pty {
|
|
15903
|
+
bool enabled = 1; uint32 winsz_rows = 2; uint32 winsz_cols = 3;
|
|
15904
|
+
string env_term = 4; string env_colorterm = 5; string env_term_program = 6;
|
|
15905
|
+
int32 pty_type = 7; bool no_terminate_on_idle_stdin = 8;
|
|
15906
|
+
}
|
|
15907
|
+
message Start {
|
|
15908
|
+
string task_id = 1; string exec_id = 2; repeated string command_args = 3;
|
|
15909
|
+
int32 stdout_config = 4; int32 stderr_config = 5;
|
|
15910
|
+
optional uint32 timeout_secs = 6; optional string workdir = 7;
|
|
15911
|
+
repeated string secret_ids = 8; optional Pty pty_info = 9;
|
|
15912
|
+
bool runtime_debug = 10; string container_id = 11; map<string,string> env = 12;
|
|
15913
|
+
}
|
|
15914
|
+
message Read {
|
|
15915
|
+
string task_id = 1; string exec_id = 2; uint64 offset = 3; int32 file_descriptor = 4;
|
|
15916
|
+
}
|
|
15917
|
+
message Data { bytes data = 1; }
|
|
15918
|
+
message Poll { optional int32 code = 1; optional int32 signal = 2; }
|
|
15919
|
+
message Write {
|
|
15920
|
+
string task_id = 1; string exec_id = 2; uint64 offset = 3; bytes data = 4; bool eof = 5;
|
|
15921
|
+
}
|
|
15922
|
+
message Empty {}
|
|
15923
|
+
`).root;
|
|
15924
|
+
var prefix = "/modal.task_command_router.TaskCommandRouter/";
|
|
15925
|
+
var maxPageBytes = 64 * 1024;
|
|
15926
|
+
var maxWireBytes = 4 * 1024 * 1024;
|
|
15927
|
+
var ModalCommandStartRejectedError = class extends ProviderCommandStartRejectedError {
|
|
15928
|
+
constructor(code, cause) {
|
|
15929
|
+
super(cause);
|
|
15930
|
+
this.code = code;
|
|
15931
|
+
this.name = "ModalCommandStartRejectedError";
|
|
15932
|
+
}
|
|
15933
|
+
};
|
|
15934
|
+
var ModalCommandStartPreDispatchUnavailableError = class _ModalCommandStartPreDispatchUnavailableError extends Error {
|
|
15935
|
+
constructor(cause) {
|
|
15936
|
+
super("Modal command router was not ready before Start dispatch", { cause });
|
|
15937
|
+
this.name = "ModalCommandStartPreDispatchUnavailableError";
|
|
15938
|
+
}
|
|
15939
|
+
static async ensureReady(client, signal) {
|
|
15940
|
+
signal?.throwIfAborted();
|
|
15941
|
+
await new Promise((resolve7, reject) => {
|
|
15942
|
+
let settled = false;
|
|
15943
|
+
const finish = (error) => {
|
|
15944
|
+
if (settled) return;
|
|
15945
|
+
settled = true;
|
|
15946
|
+
signal?.removeEventListener("abort", abort);
|
|
15947
|
+
if (signal?.aborted) reject(signal.reason);
|
|
15948
|
+
else if (error) reject(new _ModalCommandStartPreDispatchUnavailableError(error));
|
|
15949
|
+
else resolve7();
|
|
15950
|
+
};
|
|
15951
|
+
const abort = () => finish();
|
|
15952
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
15953
|
+
client.waitForReady(Date.now() + 5e3, finish);
|
|
15954
|
+
if (signal?.aborted) abort();
|
|
15955
|
+
});
|
|
15956
|
+
}
|
|
15957
|
+
};
|
|
15958
|
+
function encode(type, value) {
|
|
15959
|
+
const codec = modalRouterWire.lookupType(type);
|
|
15960
|
+
return Buffer.from(codec.encode(codec.fromObject(value)).finish());
|
|
15961
|
+
}
|
|
15962
|
+
var ModalCommandRouterWire = class {
|
|
15963
|
+
client;
|
|
15964
|
+
metadata;
|
|
15965
|
+
closed = false;
|
|
15966
|
+
constructor(access, trustedRoots) {
|
|
15967
|
+
const url = new URL(access.url);
|
|
15968
|
+
if (url.protocol !== "https:" || url.username || url.password || !access.jwt)
|
|
15969
|
+
throw new Error("Modal command router requires authenticated TLS");
|
|
15970
|
+
this.client = new Client(
|
|
15971
|
+
`${url.hostname}:${url.port || "443"}`,
|
|
15972
|
+
credentials.createSsl(trustedRoots),
|
|
15973
|
+
{
|
|
15974
|
+
"grpc.max_receive_message_length": maxWireBytes,
|
|
15975
|
+
"grpc.max_send_message_length": maxWireBytes,
|
|
15976
|
+
"grpc.enable_retries": 0
|
|
15977
|
+
}
|
|
15978
|
+
);
|
|
15979
|
+
this.metadata = new Metadata();
|
|
15980
|
+
this.metadata.set("authorization", `Bearer ${access.jwt}`);
|
|
15981
|
+
}
|
|
15982
|
+
close() {
|
|
15983
|
+
this.closed = true;
|
|
15984
|
+
this.client.close();
|
|
15985
|
+
}
|
|
15986
|
+
async unary(method, requestType, responseType, request, signal) {
|
|
15987
|
+
signal?.throwIfAborted();
|
|
15988
|
+
if (this.closed) throw new Error("Modal command router is closed");
|
|
15989
|
+
return await new Promise((resolve7, reject) => {
|
|
15990
|
+
const call = this.client.makeUnaryRequest(
|
|
15991
|
+
prefix + method,
|
|
15992
|
+
(value) => encode(requestType, value),
|
|
15993
|
+
(bytes) => modalRouterWire.lookupType(responseType).decode(bytes),
|
|
15994
|
+
request,
|
|
15995
|
+
this.metadata,
|
|
15996
|
+
{ deadline: Date.now() + 3e4 },
|
|
15997
|
+
(error, result) => {
|
|
15998
|
+
signal?.removeEventListener("abort", abort);
|
|
15999
|
+
if (signal?.aborted) reject(signal.reason);
|
|
16000
|
+
else if (error) reject(error);
|
|
16001
|
+
else if (result) resolve7(result);
|
|
16002
|
+
else reject(new Error("Modal command router returned no response"));
|
|
16003
|
+
}
|
|
16004
|
+
);
|
|
16005
|
+
const abort = () => call.cancel();
|
|
16006
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
16007
|
+
if (signal?.aborted) abort();
|
|
16008
|
+
});
|
|
16009
|
+
}
|
|
16010
|
+
async start(request, signal) {
|
|
16011
|
+
if (this.closed) throw new Error("Modal command router is closed");
|
|
16012
|
+
try {
|
|
16013
|
+
await ModalCommandStartPreDispatchUnavailableError.ensureReady(this.client, signal);
|
|
16014
|
+
} catch (error) {
|
|
16015
|
+
if (this.closed) throw new Error("Modal command router is closed", { cause: error });
|
|
16016
|
+
throw error;
|
|
16017
|
+
}
|
|
16018
|
+
try {
|
|
16019
|
+
await this.unary(
|
|
16020
|
+
"TaskExecStart",
|
|
16021
|
+
"Start",
|
|
16022
|
+
"Empty",
|
|
16023
|
+
{
|
|
16024
|
+
...request,
|
|
16025
|
+
stdoutConfig: 1,
|
|
16026
|
+
stderrConfig: 1
|
|
16027
|
+
},
|
|
16028
|
+
signal
|
|
16029
|
+
);
|
|
16030
|
+
} catch (error) {
|
|
16031
|
+
const code = error?.code;
|
|
16032
|
+
if (typeof code === "number" && [
|
|
16033
|
+
status.INVALID_ARGUMENT,
|
|
16034
|
+
status.NOT_FOUND,
|
|
16035
|
+
status.PERMISSION_DENIED,
|
|
16036
|
+
status.UNAUTHENTICATED,
|
|
16037
|
+
status.UNIMPLEMENTED
|
|
16038
|
+
].includes(code))
|
|
16039
|
+
throw new ModalCommandStartRejectedError(code, error);
|
|
16040
|
+
throw error;
|
|
16041
|
+
}
|
|
16042
|
+
}
|
|
16043
|
+
async write(identity, offset, data, signal) {
|
|
16044
|
+
if (!Number.isSafeInteger(offset) || offset < 0)
|
|
16045
|
+
throw new Error("Invalid Modal stdin byte offset");
|
|
16046
|
+
await this.unary(
|
|
16047
|
+
"TaskExecStdinWrite",
|
|
16048
|
+
"Write",
|
|
16049
|
+
"Empty",
|
|
16050
|
+
{ ...identity, offset, data, eof: false },
|
|
16051
|
+
signal
|
|
16052
|
+
);
|
|
16053
|
+
}
|
|
16054
|
+
async poll(identity, signal) {
|
|
16055
|
+
const value = await this.unary("TaskExecPoll", "Identity", "Poll", identity, signal);
|
|
16056
|
+
const decoded = modalRouterWire.lookupType("Poll").toObject(value);
|
|
16057
|
+
if (decoded.code !== void 0) return decoded.code;
|
|
16058
|
+
if (decoded.signal !== void 0) return 128 + decoded.signal;
|
|
16059
|
+
return null;
|
|
16060
|
+
}
|
|
16061
|
+
async read(identity, stream, offset, waitMs, signal) {
|
|
16062
|
+
signal?.throwIfAborted();
|
|
16063
|
+
if (this.closed) throw new Error("Modal command router is closed");
|
|
16064
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isFinite(waitMs) || waitMs < 0 || waitMs > 5e4)
|
|
16065
|
+
throw new Error("Invalid Modal output read bounds");
|
|
16066
|
+
const chunks = [];
|
|
16067
|
+
let length = 0;
|
|
16068
|
+
let limited = false;
|
|
16069
|
+
return await new Promise((resolve7, reject) => {
|
|
16070
|
+
const call = this.client.makeServerStreamRequest(
|
|
16071
|
+
prefix + "TaskExecStdioRead",
|
|
16072
|
+
(value) => encode("Read", value),
|
|
16073
|
+
(bytes) => modalRouterWire.lookupType("Data").decode(bytes),
|
|
16074
|
+
{ ...identity, offset, fileDescriptor: stream === "stdout" ? 0 : 1 },
|
|
16075
|
+
this.metadata,
|
|
16076
|
+
{ deadline: Date.now() + Math.max(1, waitMs) }
|
|
16077
|
+
);
|
|
16078
|
+
const abort = () => call.cancel();
|
|
16079
|
+
const finish = (eof, error) => {
|
|
16080
|
+
signal?.removeEventListener("abort", abort);
|
|
16081
|
+
if (signal?.aborted) reject(signal.reason);
|
|
16082
|
+
else if (error) reject(error);
|
|
16083
|
+
else resolve7({ bytes: Buffer.concat(chunks, length), eof });
|
|
16084
|
+
};
|
|
16085
|
+
call.on("data", (value) => {
|
|
16086
|
+
if (limited) return;
|
|
16087
|
+
const part = Buffer.from(value.data).subarray(0, maxPageBytes - length);
|
|
16088
|
+
if (part.length) {
|
|
16089
|
+
chunks.push(part);
|
|
16090
|
+
length += part.length;
|
|
16091
|
+
}
|
|
16092
|
+
if (length === maxPageBytes) {
|
|
16093
|
+
limited = true;
|
|
16094
|
+
call.cancel();
|
|
16095
|
+
}
|
|
16096
|
+
});
|
|
16097
|
+
call.once("error", (error) => {
|
|
16098
|
+
if (limited && error.code === status.CANCELLED || error.code === status.DEADLINE_EXCEEDED)
|
|
16099
|
+
finish(false);
|
|
16100
|
+
else finish(false, error);
|
|
16101
|
+
});
|
|
16102
|
+
call.once("end", () => finish(!limited));
|
|
16103
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
16104
|
+
if (signal?.aborted) abort();
|
|
16105
|
+
});
|
|
16106
|
+
}
|
|
16107
|
+
};
|
|
16108
|
+
|
|
16109
|
+
// src/sandbox/routing/routing-session.ts
|
|
16110
|
+
import { isDeepStrictEqual } from "util";
|
|
16111
|
+
|
|
15898
16112
|
// src/sandbox/materialization-verification-error.ts
|
|
15899
16113
|
var EXPLANATIONS = {
|
|
15900
16114
|
path_not_visible: "the provider could not see the destination path",
|
|
@@ -17341,7 +17555,7 @@ var RoutingSandboxSession = class {
|
|
|
17341
17555
|
}
|
|
17342
17556
|
} catch (error) {
|
|
17343
17557
|
if (reservedProcess) {
|
|
17344
|
-
if (error instanceof ProviderCommandStartRejectedError && reservedProcess.providerCommand?.kind === "modal-router-v1") {
|
|
17558
|
+
if ((error instanceof ProviderCommandStartRejectedError || error instanceof ModalCommandStartPreDispatchUnavailableError) && reservedProcess.providerCommand?.kind === "modal-router-v1") {
|
|
17345
17559
|
const persistence = this.deps.providerCommandPersistence?.(reservedProcess);
|
|
17346
17560
|
if (persistence?.rejectSupervisedLaunch) {
|
|
17347
17561
|
try {
|
|
@@ -17349,7 +17563,7 @@ var RoutingSandboxSession = class {
|
|
|
17349
17563
|
} catch (cause) {
|
|
17350
17564
|
throw new RoutingMutationOutcomeUnknownError(
|
|
17351
17565
|
op,
|
|
17352
|
-
"Never-started provider
|
|
17566
|
+
"Never-started provider call could not settle its exact reservation",
|
|
17353
17567
|
{ cause, retainedProcess: reservedProcess }
|
|
17354
17568
|
);
|
|
17355
17569
|
}
|
|
@@ -22716,183 +22930,6 @@ var ModalCommandControl = class _ModalCommandControl {
|
|
|
22716
22930
|
}
|
|
22717
22931
|
};
|
|
22718
22932
|
|
|
22719
|
-
// src/sandbox/providers/modal-command-router-wire.ts
|
|
22720
|
-
import { Client, Metadata, credentials, status } from "@grpc/grpc-js";
|
|
22721
|
-
import protobuf from "protobufjs";
|
|
22722
|
-
var modalRouterWire = protobuf.parse(`syntax = "proto3";
|
|
22723
|
-
message Identity { string task_id = 1; string exec_id = 2; }
|
|
22724
|
-
message Pty {
|
|
22725
|
-
bool enabled = 1; uint32 winsz_rows = 2; uint32 winsz_cols = 3;
|
|
22726
|
-
string env_term = 4; string env_colorterm = 5; string env_term_program = 6;
|
|
22727
|
-
int32 pty_type = 7; bool no_terminate_on_idle_stdin = 8;
|
|
22728
|
-
}
|
|
22729
|
-
message Start {
|
|
22730
|
-
string task_id = 1; string exec_id = 2; repeated string command_args = 3;
|
|
22731
|
-
int32 stdout_config = 4; int32 stderr_config = 5;
|
|
22732
|
-
optional uint32 timeout_secs = 6; optional string workdir = 7;
|
|
22733
|
-
repeated string secret_ids = 8; optional Pty pty_info = 9;
|
|
22734
|
-
bool runtime_debug = 10; string container_id = 11; map<string,string> env = 12;
|
|
22735
|
-
}
|
|
22736
|
-
message Read {
|
|
22737
|
-
string task_id = 1; string exec_id = 2; uint64 offset = 3; int32 file_descriptor = 4;
|
|
22738
|
-
}
|
|
22739
|
-
message Data { bytes data = 1; }
|
|
22740
|
-
message Poll { optional int32 code = 1; optional int32 signal = 2; }
|
|
22741
|
-
message Write {
|
|
22742
|
-
string task_id = 1; string exec_id = 2; uint64 offset = 3; bytes data = 4; bool eof = 5;
|
|
22743
|
-
}
|
|
22744
|
-
message Empty {}
|
|
22745
|
-
`).root;
|
|
22746
|
-
var prefix = "/modal.task_command_router.TaskCommandRouter/";
|
|
22747
|
-
var maxPageBytes = 64 * 1024;
|
|
22748
|
-
var maxWireBytes = 4 * 1024 * 1024;
|
|
22749
|
-
var ModalCommandStartRejectedError = class extends ProviderCommandStartRejectedError {
|
|
22750
|
-
constructor(code, cause) {
|
|
22751
|
-
super(cause);
|
|
22752
|
-
this.code = code;
|
|
22753
|
-
this.name = "ModalCommandStartRejectedError";
|
|
22754
|
-
}
|
|
22755
|
-
};
|
|
22756
|
-
function encode(type, value) {
|
|
22757
|
-
const codec = modalRouterWire.lookupType(type);
|
|
22758
|
-
return Buffer.from(codec.encode(codec.fromObject(value)).finish());
|
|
22759
|
-
}
|
|
22760
|
-
var ModalCommandRouterWire = class {
|
|
22761
|
-
client;
|
|
22762
|
-
metadata;
|
|
22763
|
-
closed = false;
|
|
22764
|
-
constructor(access, trustedRoots) {
|
|
22765
|
-
const url = new URL(access.url);
|
|
22766
|
-
if (url.protocol !== "https:" || url.username || url.password || !access.jwt)
|
|
22767
|
-
throw new Error("Modal command router requires authenticated TLS");
|
|
22768
|
-
this.client = new Client(url.host, credentials.createSsl(trustedRoots), {
|
|
22769
|
-
"grpc.max_receive_message_length": maxWireBytes,
|
|
22770
|
-
"grpc.max_send_message_length": maxWireBytes,
|
|
22771
|
-
"grpc.enable_retries": 0
|
|
22772
|
-
});
|
|
22773
|
-
this.metadata = new Metadata();
|
|
22774
|
-
this.metadata.set("authorization", `Bearer ${access.jwt}`);
|
|
22775
|
-
}
|
|
22776
|
-
close() {
|
|
22777
|
-
this.closed = true;
|
|
22778
|
-
this.client.close();
|
|
22779
|
-
}
|
|
22780
|
-
async unary(method, requestType, responseType, request, signal) {
|
|
22781
|
-
signal?.throwIfAborted();
|
|
22782
|
-
if (this.closed) throw new Error("Modal command router is closed");
|
|
22783
|
-
return await new Promise((resolve7, reject) => {
|
|
22784
|
-
const call = this.client.makeUnaryRequest(
|
|
22785
|
-
prefix + method,
|
|
22786
|
-
(value) => encode(requestType, value),
|
|
22787
|
-
(bytes) => modalRouterWire.lookupType(responseType).decode(bytes),
|
|
22788
|
-
request,
|
|
22789
|
-
this.metadata,
|
|
22790
|
-
{ deadline: Date.now() + 3e4 },
|
|
22791
|
-
(error, result) => {
|
|
22792
|
-
signal?.removeEventListener("abort", abort);
|
|
22793
|
-
if (signal?.aborted) reject(signal.reason);
|
|
22794
|
-
else if (error) reject(error);
|
|
22795
|
-
else if (result) resolve7(result);
|
|
22796
|
-
else reject(new Error("Modal command router returned no response"));
|
|
22797
|
-
}
|
|
22798
|
-
);
|
|
22799
|
-
const abort = () => call.cancel();
|
|
22800
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
22801
|
-
if (signal?.aborted) abort();
|
|
22802
|
-
});
|
|
22803
|
-
}
|
|
22804
|
-
async start(request, signal) {
|
|
22805
|
-
try {
|
|
22806
|
-
await this.unary(
|
|
22807
|
-
"TaskExecStart",
|
|
22808
|
-
"Start",
|
|
22809
|
-
"Empty",
|
|
22810
|
-
{
|
|
22811
|
-
...request,
|
|
22812
|
-
stdoutConfig: 1,
|
|
22813
|
-
stderrConfig: 1
|
|
22814
|
-
},
|
|
22815
|
-
signal
|
|
22816
|
-
);
|
|
22817
|
-
} catch (error) {
|
|
22818
|
-
const code = error?.code;
|
|
22819
|
-
if (typeof code === "number" && [
|
|
22820
|
-
status.INVALID_ARGUMENT,
|
|
22821
|
-
status.NOT_FOUND,
|
|
22822
|
-
status.PERMISSION_DENIED,
|
|
22823
|
-
status.UNAUTHENTICATED,
|
|
22824
|
-
status.UNIMPLEMENTED
|
|
22825
|
-
].includes(code))
|
|
22826
|
-
throw new ModalCommandStartRejectedError(code, error);
|
|
22827
|
-
throw error;
|
|
22828
|
-
}
|
|
22829
|
-
}
|
|
22830
|
-
async write(identity, offset, data, signal) {
|
|
22831
|
-
if (!Number.isSafeInteger(offset) || offset < 0)
|
|
22832
|
-
throw new Error("Invalid Modal stdin byte offset");
|
|
22833
|
-
await this.unary(
|
|
22834
|
-
"TaskExecStdinWrite",
|
|
22835
|
-
"Write",
|
|
22836
|
-
"Empty",
|
|
22837
|
-
{ ...identity, offset, data, eof: false },
|
|
22838
|
-
signal
|
|
22839
|
-
);
|
|
22840
|
-
}
|
|
22841
|
-
async poll(identity, signal) {
|
|
22842
|
-
const value = await this.unary("TaskExecPoll", "Identity", "Poll", identity, signal);
|
|
22843
|
-
const decoded = modalRouterWire.lookupType("Poll").toObject(value);
|
|
22844
|
-
if (decoded.code !== void 0) return decoded.code;
|
|
22845
|
-
if (decoded.signal !== void 0) return 128 + decoded.signal;
|
|
22846
|
-
return null;
|
|
22847
|
-
}
|
|
22848
|
-
async read(identity, stream, offset, waitMs, signal) {
|
|
22849
|
-
signal?.throwIfAborted();
|
|
22850
|
-
if (this.closed) throw new Error("Modal command router is closed");
|
|
22851
|
-
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isFinite(waitMs) || waitMs < 0 || waitMs > 5e4)
|
|
22852
|
-
throw new Error("Invalid Modal output read bounds");
|
|
22853
|
-
const chunks = [];
|
|
22854
|
-
let length = 0;
|
|
22855
|
-
let limited = false;
|
|
22856
|
-
return await new Promise((resolve7, reject) => {
|
|
22857
|
-
const call = this.client.makeServerStreamRequest(
|
|
22858
|
-
prefix + "TaskExecStdioRead",
|
|
22859
|
-
(value) => encode("Read", value),
|
|
22860
|
-
(bytes) => modalRouterWire.lookupType("Data").decode(bytes),
|
|
22861
|
-
{ ...identity, offset, fileDescriptor: stream === "stdout" ? 0 : 1 },
|
|
22862
|
-
this.metadata,
|
|
22863
|
-
{ deadline: Date.now() + Math.max(1, waitMs) }
|
|
22864
|
-
);
|
|
22865
|
-
const abort = () => call.cancel();
|
|
22866
|
-
const finish = (eof, error) => {
|
|
22867
|
-
signal?.removeEventListener("abort", abort);
|
|
22868
|
-
if (signal?.aborted) reject(signal.reason);
|
|
22869
|
-
else if (error) reject(error);
|
|
22870
|
-
else resolve7({ bytes: Buffer.concat(chunks, length), eof });
|
|
22871
|
-
};
|
|
22872
|
-
call.on("data", (value) => {
|
|
22873
|
-
if (limited) return;
|
|
22874
|
-
const part = Buffer.from(value.data).subarray(0, maxPageBytes - length);
|
|
22875
|
-
if (part.length) {
|
|
22876
|
-
chunks.push(part);
|
|
22877
|
-
length += part.length;
|
|
22878
|
-
}
|
|
22879
|
-
if (length === maxPageBytes) {
|
|
22880
|
-
limited = true;
|
|
22881
|
-
call.cancel();
|
|
22882
|
-
}
|
|
22883
|
-
});
|
|
22884
|
-
call.once("error", (error) => {
|
|
22885
|
-
if (limited && error.code === status.CANCELLED || error.code === status.DEADLINE_EXCEEDED)
|
|
22886
|
-
finish(false);
|
|
22887
|
-
else finish(false, error);
|
|
22888
|
-
});
|
|
22889
|
-
call.once("end", () => finish(!limited));
|
|
22890
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
22891
|
-
if (signal?.aborted) abort();
|
|
22892
|
-
});
|
|
22893
|
-
}
|
|
22894
|
-
};
|
|
22895
|
-
|
|
22896
22933
|
// src/sandbox/providers/modal-command-control.ts
|
|
22897
22934
|
var ModalCommandControl2 = class _ModalCommandControl {
|
|
22898
22935
|
constructor(client, sandboxIdentity, root, environment) {
|
|
@@ -23063,7 +23100,8 @@ var ModalCommandControl2 = class _ModalCommandControl {
|
|
|
23063
23100
|
)
|
|
23064
23101
|
);
|
|
23065
23102
|
} catch (error) {
|
|
23066
|
-
if (!supervision || error instanceof ModalCommandStartRejectedError
|
|
23103
|
+
if (!supervision || error instanceof ModalCommandStartRejectedError || error instanceof ModalCommandStartPreDispatchUnavailableError)
|
|
23104
|
+
throw error;
|
|
23067
23105
|
}
|
|
23068
23106
|
return command;
|
|
23069
23107
|
}
|
|
@@ -23329,8 +23367,6 @@ function installModalListDirCompatibility(session) {
|
|
|
23329
23367
|
}
|
|
23330
23368
|
var MODAL_EXEC_STDIN_WRITE_PATH = "/modal.task_command_router.TaskCommandRouter/TaskExecStdinWrite";
|
|
23331
23369
|
var MODAL_EXEC_ALREADY_COMPLETED_DETAILS = /^Exec has already completed; stdin is no longer accepting writes(?: \(Error code: [A-Z0-9]+\))?$/;
|
|
23332
|
-
var MODAL_TASK_EXEC_START_PATH = "/modal.task_command_router.TaskCommandRouter/TaskExecStart";
|
|
23333
|
-
var MODAL_TASK_EXEC_START_DNS_RESOLUTION_DETAILS = /^Name resolution failed for target dns:task-[a-z0-9]+\.w\.modal\.host:443$/;
|
|
23334
23370
|
var MODAL_TASK_EXEC_START_ERROR_MAX_DEPTH = 8;
|
|
23335
23371
|
var MODAL_TASK_EXEC_START_ERROR_MAX_NODES = 64;
|
|
23336
23372
|
var MODAL_TASK_EXEC_START_ERROR_MAX_AGGREGATE_ERRORS = 32;
|
|
@@ -23352,10 +23388,7 @@ function hasContradictoryModalHttpStatus(record) {
|
|
|
23352
23388
|
}
|
|
23353
23389
|
return values.some((value) => modalHttpStatus(value) !== null);
|
|
23354
23390
|
}
|
|
23355
|
-
function
|
|
23356
|
-
return record.name === "ClientError" && record.path === MODAL_TASK_EXEC_START_PATH && (record.code === 14 || record.code === "UNAVAILABLE") && typeof record.details === "string" && MODAL_TASK_EXEC_START_DNS_RESOLUTION_DETAILS.test(record.details);
|
|
23357
|
-
}
|
|
23358
|
-
function isModalTaskExecStartDnsResolutionError(error) {
|
|
23391
|
+
function isModalTaskExecStartPreDispatchUnavailableError(error) {
|
|
23359
23392
|
const pending = [{ depth: 0, value: error }];
|
|
23360
23393
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
23361
23394
|
let inspected = 0;
|
|
@@ -23372,7 +23405,12 @@ function isModalTaskExecStartDnsResolutionError(error) {
|
|
|
23372
23405
|
let nested;
|
|
23373
23406
|
try {
|
|
23374
23407
|
const record = current.value;
|
|
23408
|
+
if (isRoutingMutationOutcomeUnknownError(current.value)) return false;
|
|
23375
23409
|
if (hasContradictoryModalHttpStatus(record)) return false;
|
|
23410
|
+
if (current.value instanceof ModalCommandStartPreDispatchUnavailableError) {
|
|
23411
|
+
matchingLeaves += 1;
|
|
23412
|
+
continue;
|
|
23413
|
+
}
|
|
23376
23414
|
nested = [];
|
|
23377
23415
|
for (const key of ["cause", "error"]) {
|
|
23378
23416
|
const value = record[key];
|
|
@@ -23385,11 +23423,7 @@ function isModalTaskExecStartDnsResolutionError(error) {
|
|
|
23385
23423
|
}
|
|
23386
23424
|
nested.push(...errors);
|
|
23387
23425
|
}
|
|
23388
|
-
if (nested.length === 0)
|
|
23389
|
-
if (!isModalTaskExecStartDnsResolutionLeaf(record)) return false;
|
|
23390
|
-
matchingLeaves += 1;
|
|
23391
|
-
continue;
|
|
23392
|
-
}
|
|
23426
|
+
if (nested.length === 0) return false;
|
|
23393
23427
|
} catch {
|
|
23394
23428
|
return false;
|
|
23395
23429
|
}
|
|
@@ -33049,6 +33083,7 @@ function shellQuote5(value) {
|
|
|
33049
33083
|
// src/sandbox/browser-control-client.ts
|
|
33050
33084
|
import { createHash as createHash7, randomUUID as randomUUID8 } from "crypto";
|
|
33051
33085
|
import { posix as posixPath2 } from "path";
|
|
33086
|
+
import { parseBrowserFrameMetadata } from "@opengeni/sdk";
|
|
33052
33087
|
import {
|
|
33053
33088
|
BROWSER_CONTROL_MAX_JSON_BYTES,
|
|
33054
33089
|
BROWSER_CONTROL_PORT as BROWSER_CONTROL_PORT2,
|
|
@@ -33063,6 +33098,8 @@ import {
|
|
|
33063
33098
|
BrowserDownloadExportReceipt,
|
|
33064
33099
|
BrowserDownloadExportRequest,
|
|
33065
33100
|
BrowserDownloadListResponse,
|
|
33101
|
+
BrowserDomReadRequest,
|
|
33102
|
+
BrowserDomReadResponse,
|
|
33066
33103
|
BrowserExternalAuthCommand,
|
|
33067
33104
|
BrowserExternalAuthResult,
|
|
33068
33105
|
BrowserObservation,
|
|
@@ -33070,6 +33107,7 @@ import {
|
|
|
33070
33107
|
BrowserProtectedAuthFillReceipt,
|
|
33071
33108
|
BrowserRevisionMaterialization,
|
|
33072
33109
|
BrowserTarget,
|
|
33110
|
+
BrowserTargetState,
|
|
33073
33111
|
BrowserWorkspaceFileStageRequest,
|
|
33074
33112
|
BrowserWorkspaceFileStageResponse,
|
|
33075
33113
|
ComputerActionCommand,
|
|
@@ -33536,7 +33574,10 @@ var BrowserControlClient = class {
|
|
|
33536
33574
|
return await this.requestJson(input);
|
|
33537
33575
|
}
|
|
33538
33576
|
async requestBytesForSession(input) {
|
|
33539
|
-
return await this.requestBytes(input);
|
|
33577
|
+
return await this.requestBytes({ ...input, surface: "computer" });
|
|
33578
|
+
}
|
|
33579
|
+
async requestBrowserBytesForSession(input) {
|
|
33580
|
+
return await this.requestBytes({ ...input, surface: "browser" });
|
|
33540
33581
|
}
|
|
33541
33582
|
async requestJson(input, retryNativeEndpoint = true) {
|
|
33542
33583
|
const requireHostFetch = this.session.requireHostFetchController === true;
|
|
@@ -33772,10 +33813,10 @@ var BrowserControlClient = class {
|
|
|
33772
33813
|
const data = await readBytes(
|
|
33773
33814
|
this.session,
|
|
33774
33815
|
responsePath,
|
|
33775
|
-
COMPUTER_SCREENSHOT_MAX_BYTES,
|
|
33816
|
+
input.surface === "browser" ? 24 * 1024 * 1024 : COMPUTER_SCREENSHOT_MAX_BYTES,
|
|
33776
33817
|
timeoutMs
|
|
33777
33818
|
);
|
|
33778
|
-
return
|
|
33819
|
+
return controllerImageFrame(data, headers, input);
|
|
33779
33820
|
} catch (error) {
|
|
33780
33821
|
if (error instanceof BrowserControlRequestError || error instanceof BrowserControlProtocolError || error instanceof RangeError) {
|
|
33781
33822
|
throw error;
|
|
@@ -33923,6 +33964,75 @@ var BrowserControlSessionClient = class {
|
|
|
33923
33964
|
})
|
|
33924
33965
|
);
|
|
33925
33966
|
}
|
|
33967
|
+
async targetState(targetId) {
|
|
33968
|
+
let state;
|
|
33969
|
+
try {
|
|
33970
|
+
state = BrowserTargetState.parse(
|
|
33971
|
+
await this.parent.requestForSession({
|
|
33972
|
+
method: "GET",
|
|
33973
|
+
path: this.targetPath(targetId, "state"),
|
|
33974
|
+
token: this.viewToken
|
|
33975
|
+
})
|
|
33976
|
+
);
|
|
33977
|
+
} catch (error) {
|
|
33978
|
+
if (!(error instanceof BrowserControlRequestError) || error.status !== 404 || error.error.code !== "resource_not_found" || error.error.message !== "route not found") {
|
|
33979
|
+
throw error;
|
|
33980
|
+
}
|
|
33981
|
+
const observation = await this.observe(targetId);
|
|
33982
|
+
state = BrowserTargetState.parse({
|
|
33983
|
+
browserSessionId: observation.browserSessionId,
|
|
33984
|
+
controllerGeneration: observation.target.controllerGeneration,
|
|
33985
|
+
targetId: observation.target.id,
|
|
33986
|
+
targetGeneration: observation.target.targetGeneration,
|
|
33987
|
+
documentGeneration: observation.target.documentGeneration,
|
|
33988
|
+
frameId: observation.frameId
|
|
33989
|
+
});
|
|
33990
|
+
}
|
|
33991
|
+
if (state.browserSessionId !== this.reference.browserSessionId || state.controllerGeneration !== this.reference.controllerGeneration || state.targetId !== targetId) {
|
|
33992
|
+
throw new BrowserControlProtocolError("browser target state belongs to another binding");
|
|
33993
|
+
}
|
|
33994
|
+
return state;
|
|
33995
|
+
}
|
|
33996
|
+
async readDom(targetId, requestInput) {
|
|
33997
|
+
const request = BrowserDomReadRequest.parse(requestInput);
|
|
33998
|
+
const result = BrowserDomReadResponse.parse(
|
|
33999
|
+
await this.parent.requestForSession({
|
|
34000
|
+
method: "POST",
|
|
34001
|
+
path: this.targetPath(targetId, "dom-read"),
|
|
34002
|
+
token: this.viewToken,
|
|
34003
|
+
body: request
|
|
34004
|
+
})
|
|
34005
|
+
);
|
|
34006
|
+
if (result.browserSessionId !== this.reference.browserSessionId || result.controllerGeneration !== this.reference.controllerGeneration || result.targetId !== targetId || result.targetGeneration !== request.expectedTargetGeneration || result.documentGeneration !== request.expectedDocumentGeneration || result.frameId !== request.expectedFrameId || result.kind !== request.kind) {
|
|
34007
|
+
throw new BrowserControlProtocolError("browser DOM read belongs to another binding");
|
|
34008
|
+
}
|
|
34009
|
+
return result;
|
|
34010
|
+
}
|
|
34011
|
+
async capture(targetId, options = {}) {
|
|
34012
|
+
const query = new URLSearchParams({
|
|
34013
|
+
format: options.format ?? "jpeg",
|
|
34014
|
+
quality: String(boundedInteger(options.quality ?? 55, 1, 100, "browser screenshot quality"))
|
|
34015
|
+
});
|
|
34016
|
+
if (options.format !== void 0 && options.format !== "jpeg" && options.format !== "png") {
|
|
34017
|
+
throw new RangeError("browser screenshot format is invalid");
|
|
34018
|
+
}
|
|
34019
|
+
if (options.fullPage !== void 0) {
|
|
34020
|
+
if (typeof options.fullPage !== "boolean") {
|
|
34021
|
+
throw new RangeError("browser screenshot fullPage is invalid");
|
|
34022
|
+
}
|
|
34023
|
+
query.set("fullPage", String(options.fullPage));
|
|
34024
|
+
}
|
|
34025
|
+
return await this.parent.requestBrowserBytesForSession({
|
|
34026
|
+
method: "GET",
|
|
34027
|
+
path: this.targetPath(targetId, `screenshot?${query}`),
|
|
34028
|
+
token: this.viewToken,
|
|
34029
|
+
expectedFrameEvidence: {
|
|
34030
|
+
browserSessionId: this.reference.browserSessionId,
|
|
34031
|
+
controllerGeneration: this.reference.controllerGeneration,
|
|
34032
|
+
targetId: requireOpaqueId(targetId, "browser target id")
|
|
34033
|
+
}
|
|
34034
|
+
});
|
|
34035
|
+
}
|
|
33926
34036
|
async readClipboard() {
|
|
33927
34037
|
return BrowserClipboard.parse(
|
|
33928
34038
|
await this.parent.requestForSession({
|
|
@@ -34256,12 +34366,69 @@ async function requestExposedControllerBytes(endpoint, input, defaultTimeoutMs)
|
|
|
34256
34366
|
throw new BrowserControlProtocolError("browser controller image response is invalid");
|
|
34257
34367
|
}
|
|
34258
34368
|
const declaredLength = Number(response.headers.get("content-length"));
|
|
34259
|
-
|
|
34260
|
-
|
|
34261
|
-
|
|
34369
|
+
const maxBytes = input.surface === "browser" ? 24 * 1024 * 1024 : COMPUTER_SCREENSHOT_MAX_BYTES;
|
|
34370
|
+
if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
|
|
34371
|
+
await response.body?.cancel("frame exceeds its byte bound").catch(() => void 0);
|
|
34372
|
+
throw new RangeError("frame exceeds its byte bound");
|
|
34373
|
+
}
|
|
34374
|
+
const data = await readBoundedFrameResponse(response, maxBytes);
|
|
34375
|
+
return controllerImageFrame(data, response.headers, input);
|
|
34376
|
+
}
|
|
34377
|
+
async function readBoundedFrameResponse(response, maxBytes) {
|
|
34378
|
+
if (!response.body) throw new BrowserControlProtocolError("browser controller image is empty");
|
|
34379
|
+
const reader = response.body.getReader();
|
|
34380
|
+
const chunks = [];
|
|
34381
|
+
let size = 0;
|
|
34382
|
+
try {
|
|
34383
|
+
for (; ; ) {
|
|
34384
|
+
const { done, value } = await reader.read();
|
|
34385
|
+
if (done) break;
|
|
34386
|
+
size += value.byteLength;
|
|
34387
|
+
if (size > maxBytes) {
|
|
34388
|
+
await reader.cancel("frame exceeds its byte bound").catch(() => void 0);
|
|
34389
|
+
throw new RangeError("frame exceeds its byte bound");
|
|
34390
|
+
}
|
|
34391
|
+
chunks.push(value);
|
|
34392
|
+
}
|
|
34393
|
+
} finally {
|
|
34394
|
+
reader.releaseLock();
|
|
34262
34395
|
}
|
|
34263
|
-
const data = new Uint8Array(
|
|
34264
|
-
|
|
34396
|
+
const data = new Uint8Array(size);
|
|
34397
|
+
let offset = 0;
|
|
34398
|
+
for (const chunk of chunks) {
|
|
34399
|
+
data.set(chunk, offset);
|
|
34400
|
+
offset += chunk.byteLength;
|
|
34401
|
+
}
|
|
34402
|
+
return data;
|
|
34403
|
+
}
|
|
34404
|
+
function controllerImageFrame(data, headers, input) {
|
|
34405
|
+
return input.surface === "browser" ? browserControlFrame(data, headers, input.expectedFrameEvidence) : computerControlFrame(data, headers, input.expectedFrameEvidence);
|
|
34406
|
+
}
|
|
34407
|
+
function browserControlFrame(data, headers, expected) {
|
|
34408
|
+
if (data.byteLength < 1 || data.byteLength > 24 * 1024 * 1024) {
|
|
34409
|
+
throw new RangeError("browser frame exceeds its byte bound");
|
|
34410
|
+
}
|
|
34411
|
+
const get = (name) => headers.get(name.toLowerCase()) ?? null;
|
|
34412
|
+
const mediaType = get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
34413
|
+
if (mediaType !== "image/jpeg" && mediaType !== "image/png") {
|
|
34414
|
+
throw new BrowserControlProtocolError("browser frame media type is invalid");
|
|
34415
|
+
}
|
|
34416
|
+
const metadataHeader = get("x-opengeni-browser-frame");
|
|
34417
|
+
if (!metadataHeader || metadataHeader.length > 64 * 1024 || !/^[A-Za-z0-9_-]+$/u.test(metadataHeader)) {
|
|
34418
|
+
throw new BrowserControlProtocolError("browser frame metadata is invalid");
|
|
34419
|
+
}
|
|
34420
|
+
let metadata;
|
|
34421
|
+
try {
|
|
34422
|
+
metadata = parseBrowserFrameMetadata(
|
|
34423
|
+
JSON.parse(Buffer.from(metadataHeader, "base64url").toString("utf8"))
|
|
34424
|
+
);
|
|
34425
|
+
} catch {
|
|
34426
|
+
throw new BrowserControlProtocolError("browser frame metadata is invalid");
|
|
34427
|
+
}
|
|
34428
|
+
if (metadata.browserSessionId !== expected.browserSessionId || metadata.controllerGeneration !== expected.controllerGeneration || metadata.targetId !== expected.targetId || metadata.mediaType !== mediaType) {
|
|
34429
|
+
throw new BrowserControlProtocolError("browser frame evidence does not match its request");
|
|
34430
|
+
}
|
|
34431
|
+
return { data, mediaType, metadataHeader, metadata };
|
|
34265
34432
|
}
|
|
34266
34433
|
function computerControlFrame(data, headers, expected) {
|
|
34267
34434
|
if (data.byteLength < 1 || data.byteLength > COMPUTER_SCREENSHOT_MAX_BYTES) {
|
|
@@ -34936,7 +35103,7 @@ async function readText(session, path, maxBytes, timeoutMs) {
|
|
|
34936
35103
|
}
|
|
34937
35104
|
async function readBytes(session, path, maxBytes, timeoutMs) {
|
|
34938
35105
|
const privatePath = absolutePrivatePath(path, "browser private binary response path");
|
|
34939
|
-
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > COMPUTER_SCREENSHOT_MAX_BYTES) {
|
|
35106
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > Math.max(24 * 1024 * 1024, COMPUTER_SCREENSHOT_MAX_BYTES)) {
|
|
34940
35107
|
throw new RangeError("browser private binary response limit is invalid");
|
|
34941
35108
|
}
|
|
34942
35109
|
const sizeMarker = `OPENGENI_BROWSER_PRIVATE_SIZE_${randomUUID8()}`;
|
|
@@ -34955,7 +35122,7 @@ async function readBytes(session, path, maxBytes, timeoutMs) {
|
|
|
34955
35122
|
"browser private binary response size"
|
|
34956
35123
|
);
|
|
34957
35124
|
if (size < 1 || size > maxBytes) {
|
|
34958
|
-
throw new RangeError("
|
|
35125
|
+
throw new RangeError("frame exceeds its byte bound");
|
|
34959
35126
|
}
|
|
34960
35127
|
const chunks = [];
|
|
34961
35128
|
for (let offset = 0; offset < size; offset += PRIVATE_READ_CHUNK_BYTES) {
|
|
@@ -38388,7 +38555,7 @@ export {
|
|
|
38388
38555
|
assertDescriptorRegistryInvariants,
|
|
38389
38556
|
modalSandboxAttributionEnvironment,
|
|
38390
38557
|
modalSandboxAttributionTags,
|
|
38391
|
-
|
|
38558
|
+
isModalTaskExecStartPreDispatchUnavailableError,
|
|
38392
38559
|
ensureModalRegistryImage,
|
|
38393
38560
|
resolveModalCheckpointProviderBindingForSession,
|
|
38394
38561
|
modalSessionMatchesCheckpointProviderBinding,
|
|
@@ -38571,4 +38738,4 @@ export {
|
|
|
38571
38738
|
collectSandboxEnvironment2 as collectSandboxEnvironment,
|
|
38572
38739
|
parseExposedPorts2 as parseExposedPorts
|
|
38573
38740
|
};
|
|
38574
|
-
//# sourceMappingURL=chunk-
|
|
38741
|
+
//# sourceMappingURL=chunk-GBVN7WSK.js.map
|