@effect-agent/platform-cloudflare 0.1.0-beta.121 → 0.1.0-beta.122
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/{InteractiveBrowser-DhOkdUx9.mjs → InteractiveBrowser-DXwmvWdA.mjs} +189 -48
- package/dist/InteractiveBrowser-DXwmvWdA.mjs.map +1 -0
- package/dist/InteractiveBrowser.mjs +1 -1
- package/dist/ProtectedBrowser.d.mts +14 -0
- package/dist/ProtectedBrowser.mjs +193 -152
- package/dist/ProtectedBrowser.mjs.map +1 -1
- package/package.json +1 -1
- package/src/InteractiveBrowser.ts +1 -1
- package/src/internal/browser-binding.ts +244 -56
- package/src/protected-browser/binding.ts +129 -50
- package/src/protected-browser/host.ts +16 -0
- package/dist/InteractiveBrowser-DhOkdUx9.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as reportBrowserCause, S as inheritBrowserReport, b as BrowserRunFailure, c as BrowserRunLiveViewResult, r as BrowserRunHandoffState, s as BrowserRunLiveViewRequest, t as BrowserRunHandoffRequest, v as BrowserRunSessionLifecycle, w as reportedBrowserError, x as browserFailure, y as BrowserRunBinding } from "./InteractiveBrowser-
|
|
1
|
+
import { C as reportBrowserCause, S as inheritBrowserReport, b as BrowserRunFailure, c as BrowserRunLiveViewResult, r as BrowserRunHandoffState, s as BrowserRunLiveViewRequest, t as BrowserRunHandoffRequest, v as BrowserRunSessionLifecycle, w as reportedBrowserError, x as browserFailure, y as BrowserRunBinding } from "./InteractiveBrowser-DXwmvWdA.mjs";
|
|
2
2
|
import { Cause, Clock, Context, Crypto, Effect, Layer, Redacted, Schema, Semaphore } from "effect";
|
|
3
3
|
import { InteractiveBrowserPolicy } from "effect-agent/interactive-browser";
|
|
4
4
|
import "puppeteer-core/lib/esm/puppeteer/puppeteer-core-browser.js";
|
|
@@ -885,169 +885,209 @@ const protectedBindingLayer = (options) => Layer.effect(BrowserRunProtectedBindi
|
|
|
885
885
|
const lifecycle = yield* BrowserRunSessionLifecycle;
|
|
886
886
|
const binding = yield* BrowserRunBinding;
|
|
887
887
|
const crypto = yield* Crypto.Crypto;
|
|
888
|
-
return {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
page = await context.newPage();
|
|
948
|
-
} else {
|
|
949
|
-
stage = "protected.resume";
|
|
950
|
-
const context = browser.browserContexts().find((candidate) => candidate.id === Redacted.value(identity.contextId));
|
|
951
|
-
if (context === void 0) throw new ProtectedTransportError({ reason: "stale-reference" });
|
|
952
|
-
const pages = await context.pages();
|
|
953
|
-
let found;
|
|
954
|
-
for (const candidate of pages) {
|
|
955
|
-
const client = await candidate.createCDPSession();
|
|
956
|
-
const info = await client.send("Target.getTargetInfo");
|
|
957
|
-
await client.detach();
|
|
958
|
-
if (info.targetInfo.targetId === Redacted.value(identity.targetId)) found = candidate;
|
|
888
|
+
return {
|
|
889
|
+
open: Effect.fn("BrowserRunProtectedTransport.open")(function* (policy, identity) {
|
|
890
|
+
const failure = () => new ProtectedBrowserError({
|
|
891
|
+
reason: "provider",
|
|
892
|
+
dispatch: "not-dispatched",
|
|
893
|
+
milestone: "none",
|
|
894
|
+
observation: "closed",
|
|
895
|
+
cleanup: "unconfirmed"
|
|
896
|
+
});
|
|
897
|
+
let sessionId = identity?.sessionId;
|
|
898
|
+
let detached = false;
|
|
899
|
+
let control;
|
|
900
|
+
let providerIdentity;
|
|
901
|
+
let browser;
|
|
902
|
+
let attachment;
|
|
903
|
+
let driver;
|
|
904
|
+
let invalid = false;
|
|
905
|
+
const runCleanup = Effect.runPromiseWith(yield* Effect.context());
|
|
906
|
+
const terminate = Effect.gen(function* () {
|
|
907
|
+
invalid = true;
|
|
908
|
+
driver?.invalidate();
|
|
909
|
+
if (sessionId === void 0) return "unconfirmed";
|
|
910
|
+
if (identity !== void 0 && driver === void 0) {
|
|
911
|
+
if (attachment !== void 0) yield* attachment.retire.pipe(Effect.interruptible, Effect.timeoutOrElse({
|
|
912
|
+
duration: "1 second",
|
|
913
|
+
orElse: () => Effect.fail(new BrowserRunFailure({
|
|
914
|
+
operation: "protected.disconnect",
|
|
915
|
+
reason: "timeout"
|
|
916
|
+
}))
|
|
917
|
+
}), Effect.catch((error) => reportBrowserCause("protected.disconnect", Cause.fail(error)).pipe(Effect.andThen(() => Effect.die(reportedBrowserError(error))))));
|
|
918
|
+
return "unconfirmed";
|
|
919
|
+
}
|
|
920
|
+
const cleanup = yield* lifecycle.close(sessionId).pipe(Effect.as("confirmed"), Effect.catchCause((cause) => reportBrowserCause("protected.close", cause).pipe(Effect.as("unconfirmed"))), Effect.interruptible, Effect.timeoutOrElse({
|
|
921
|
+
duration: "10 seconds",
|
|
922
|
+
orElse: () => reportBrowserCause("protected.close", Cause.fail(new BrowserRunFailure({
|
|
923
|
+
operation: "protected.close",
|
|
924
|
+
reason: "timeout"
|
|
925
|
+
}))).pipe(Effect.as("unconfirmed"))
|
|
926
|
+
}));
|
|
927
|
+
const connected = browser;
|
|
928
|
+
if (connected !== void 0) yield* Effect.promise(() => connected.disconnect()).pipe(Effect.catchCause((cause) => reportBrowserCause("protected.disconnect", cause)), Effect.interruptible, Effect.timeoutOrElse({
|
|
929
|
+
duration: "1 second",
|
|
930
|
+
orElse: () => reportBrowserCause("protected.disconnect", Cause.fail(new BrowserRunFailure({
|
|
931
|
+
operation: "protected.disconnect",
|
|
932
|
+
reason: "timeout"
|
|
933
|
+
})))
|
|
934
|
+
}));
|
|
935
|
+
return cleanup;
|
|
936
|
+
});
|
|
937
|
+
const close = yield* Effect.cached(terminate);
|
|
938
|
+
yield* Effect.addFinalizer(() => detached ? Effect.void : close);
|
|
939
|
+
let stage = identity === void 0 ? "protected.acquire" : "protected.connect";
|
|
940
|
+
const acquired = yield* Effect.tryPromise({
|
|
941
|
+
try: async (signal) => {
|
|
942
|
+
try {
|
|
943
|
+
sessionId = identity === void 0 ? Redacted.make(await binding.acquire(Math.min(6e5, Math.max(1e4, policy.maxElapsedMillis)), "protected.acquire")) : identity.sessionId;
|
|
944
|
+
if (signal.aborted || invalid) {
|
|
945
|
+
await runCleanup(terminate);
|
|
946
|
+
throw new ProtectedTransportError({ reason: "stale-reference" });
|
|
959
947
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
948
|
+
stage = "protected.connect";
|
|
949
|
+
attachment = binding.connect(Redacted.value(sessionId), stage, signal);
|
|
950
|
+
browser = await attachment.browser;
|
|
951
|
+
if (signal.aborted || invalid) {
|
|
952
|
+
await runCleanup(terminate);
|
|
953
|
+
throw new ProtectedTransportError({ reason: "stale-reference" });
|
|
954
|
+
}
|
|
955
|
+
let page;
|
|
956
|
+
if (identity === void 0) {
|
|
957
|
+
stage = "protected.context";
|
|
958
|
+
const context = await browser.createBrowserContext();
|
|
959
|
+
stage = "protected.page";
|
|
960
|
+
page = await context.newPage();
|
|
961
|
+
} else {
|
|
962
|
+
stage = "protected.resume";
|
|
963
|
+
const context = browser.browserContexts().find((candidate) => candidate.id === Redacted.value(identity.contextId));
|
|
964
|
+
if (context === void 0) throw new ProtectedTransportError({ reason: "stale-reference" });
|
|
965
|
+
const pages = await context.pages();
|
|
966
|
+
let found;
|
|
967
|
+
for (const candidate of pages) {
|
|
968
|
+
const client = await candidate.createCDPSession();
|
|
969
|
+
const info = await client.send("Target.getTargetInfo");
|
|
970
|
+
await client.detach();
|
|
971
|
+
if (info.targetInfo.targetId === Redacted.value(identity.targetId)) found = candidate;
|
|
972
|
+
}
|
|
973
|
+
if (found === void 0 || pages.length !== 1) throw new ProtectedTransportError({ reason: "stale-reference" });
|
|
974
|
+
page = found;
|
|
975
|
+
}
|
|
976
|
+
stage = "protected.control";
|
|
977
|
+
control = await page.createCDPSession();
|
|
978
|
+
const info = await control.send("Target.getTargetInfo");
|
|
979
|
+
stage = "protected.identity";
|
|
980
|
+
providerIdentity = Schema.decodeSync(ProtectedProviderIdentity)({
|
|
981
|
+
sessionId,
|
|
982
|
+
contextId: Redacted.make(page.browserContext().id ?? ""),
|
|
983
|
+
targetId: Redacted.make(info.targetInfo.targetId)
|
|
985
984
|
});
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
985
|
+
if (policy.network._tag !== "Unrestricted") {
|
|
986
|
+
stage = "protected.interception";
|
|
987
|
+
await page.setBypassServiceWorker(true);
|
|
988
|
+
await page.setRequestInterception(true);
|
|
989
|
+
page.on("request", (request) => {
|
|
990
|
+
let allowed = false;
|
|
991
|
+
try {
|
|
992
|
+
const url = new URL(request.url());
|
|
993
|
+
allowed = policy.network._tag === "ExactHosts" && url.protocol === "https:" && !url.username && !url.password && policy.network.allowedHosts.includes(url.host);
|
|
994
|
+
} catch {}
|
|
995
|
+
(allowed && !invalid ? request.continue() : request.abort("blockedbyclient")).catch(async (cause) => {
|
|
996
|
+
invalid = true;
|
|
997
|
+
driver?.invalidate();
|
|
998
|
+
await runCleanup(reportBrowserCause("protected.interception", Cause.fail(cause)));
|
|
999
|
+
});
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
if (signal.aborted || invalid) {
|
|
1003
|
+
await runCleanup(terminate);
|
|
1004
|
+
throw new ProtectedTransportError({ reason: "stale-reference" });
|
|
1005
|
+
}
|
|
1006
|
+
return ProtectedNativeSession.of({
|
|
1007
|
+
browser,
|
|
1008
|
+
page,
|
|
1009
|
+
close,
|
|
1010
|
+
release: Effect.suspend(() => detached ? Effect.void : close.pipe(Effect.asVoid))
|
|
1011
|
+
});
|
|
1012
|
+
} catch (cause) {
|
|
1013
|
+
if (signal.aborted && !(cause instanceof ProtectedTransportError)) await runCleanup(reportBrowserCause(stage, Cause.fail(cause)));
|
|
1014
|
+
throw cause;
|
|
990
1015
|
}
|
|
991
|
-
return ProtectedNativeSession.of({
|
|
992
|
-
browser,
|
|
993
|
-
page,
|
|
994
|
-
close,
|
|
995
|
-
release: Effect.suspend(() => detached ? Effect.void : close.pipe(Effect.asVoid))
|
|
996
|
-
});
|
|
997
|
-
} catch (cause) {
|
|
998
|
-
if (signal.aborted && !(cause instanceof ProtectedTransportError)) await runCleanup(reportBrowserCause(stage, Cause.fail(cause)));
|
|
999
|
-
throw cause;
|
|
1000
|
-
}
|
|
1001
|
-
},
|
|
1002
|
-
catch: (cause) => browserFailure(stage, cause)
|
|
1003
|
-
}).pipe(Effect.timeoutOrElse({
|
|
1004
|
-
duration: Math.min(policy.maxElapsedMillis, 3e4),
|
|
1005
|
-
orElse: () => Effect.fail(new BrowserRunFailure({
|
|
1006
|
-
operation: stage,
|
|
1007
|
-
reason: "timeout"
|
|
1008
|
-
}))
|
|
1009
|
-
}), Effect.catch((error) => reportBrowserCause(stage, Cause.fail(error)).pipe(Effect.andThen(close), Effect.flatMap((cleanup) => Effect.fail(reportedBrowserError(new ProtectedBrowserError({
|
|
1010
|
-
...failure(),
|
|
1011
|
-
reason: error.reason === "timeout" ? "timeout" : "provider",
|
|
1012
|
-
cleanup: identity !== void 0 && driver === void 0 ? "not-requested" : cleanup
|
|
1013
|
-
})))))));
|
|
1014
|
-
driver = yield* makeProtectedNativeTransport(policy).pipe(Effect.provideService(ProtectedNativeSession, acquired), Effect.provideService(Crypto.Crypto, crypto));
|
|
1015
|
-
const exact = providerIdentity;
|
|
1016
|
-
if (exact === void 0) return yield* failure();
|
|
1017
|
-
return {
|
|
1018
|
-
identity: exact,
|
|
1019
|
-
driver,
|
|
1020
|
-
command: (method, parameters) => Effect.tryPromise({
|
|
1021
|
-
try: async () => {
|
|
1022
|
-
if (invalid || detached || control === void 0) throw void 0;
|
|
1023
|
-
const send = Reflect.get(control, "send");
|
|
1024
|
-
return await Reflect.apply(send, control, [method, parameters]);
|
|
1025
1016
|
},
|
|
1026
|
-
catch: (cause) => browserFailure(
|
|
1017
|
+
catch: (cause) => browserFailure(stage, cause)
|
|
1027
1018
|
}).pipe(Effect.timeoutOrElse({
|
|
1028
|
-
duration:
|
|
1019
|
+
duration: Math.min(policy.maxElapsedMillis, 3e4),
|
|
1029
1020
|
orElse: () => Effect.fail(new BrowserRunFailure({
|
|
1030
|
-
operation:
|
|
1021
|
+
operation: stage,
|
|
1031
1022
|
reason: "timeout"
|
|
1032
1023
|
}))
|
|
1033
|
-
}), Effect.catch((error) =>
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1024
|
+
}), Effect.catch((error) => {
|
|
1025
|
+
if (identity !== void 0 && driver === void 0) return reportBrowserCause(stage, Cause.fail(error)).pipe(Effect.andThen(Effect.fail(reportedBrowserError(new ProtectedBrowserError({
|
|
1026
|
+
...failure(),
|
|
1027
|
+
reason: error.reason === "timeout" ? "timeout" : "provider",
|
|
1028
|
+
cleanup: "not-requested"
|
|
1029
|
+
})))), Effect.ensuring(close));
|
|
1030
|
+
return reportBrowserCause(stage, Cause.fail(error)).pipe(Effect.andThen(close), Effect.flatMap((cleanup) => Effect.fail(reportedBrowserError(new ProtectedBrowserError({
|
|
1031
|
+
...failure(),
|
|
1032
|
+
reason: error.reason === "timeout" ? "timeout" : "provider",
|
|
1033
|
+
cleanup
|
|
1034
|
+
})))));
|
|
1035
|
+
}));
|
|
1036
|
+
driver = yield* makeProtectedNativeTransport(policy).pipe(Effect.provideService(ProtectedNativeSession, acquired), Effect.provideService(Crypto.Crypto, crypto));
|
|
1037
|
+
const exact = providerIdentity;
|
|
1038
|
+
if (exact === void 0) return yield* failure();
|
|
1039
|
+
return {
|
|
1040
|
+
identity: exact,
|
|
1041
|
+
driver,
|
|
1042
|
+
command: (method, parameters) => Effect.tryPromise({
|
|
1043
|
+
try: async () => {
|
|
1044
|
+
if (invalid || detached || control === void 0) throw void 0;
|
|
1045
|
+
const send = Reflect.get(control, "send");
|
|
1046
|
+
return await Reflect.apply(send, control, [method, parameters]);
|
|
1047
|
+
},
|
|
1048
|
+
catch: (cause) => browserFailure("protected.command", cause)
|
|
1049
|
+
}).pipe(Effect.timeoutOrElse({
|
|
1050
|
+
duration: "10 seconds",
|
|
1051
|
+
orElse: () => Effect.fail(new BrowserRunFailure({
|
|
1052
|
+
operation: "protected.command",
|
|
1053
|
+
reason: "timeout"
|
|
1054
|
+
}))
|
|
1055
|
+
}), Effect.catch((error) => reportBrowserCause("protected.command", Cause.fail(error)).pipe(Effect.andThen(Effect.fail(reportedBrowserError(failure())))))),
|
|
1056
|
+
detach: Effect.tryPromise({
|
|
1057
|
+
try: async () => {
|
|
1058
|
+
if (invalid || detached || browser === void 0) throw void 0;
|
|
1059
|
+
await browser.disconnect();
|
|
1060
|
+
detached = true;
|
|
1061
|
+
driver?.invalidate();
|
|
1062
|
+
},
|
|
1063
|
+
catch: (cause) => browserFailure("protected.detach", cause)
|
|
1064
|
+
}).pipe(Effect.timeoutOrElse({
|
|
1065
|
+
duration: "10 seconds",
|
|
1066
|
+
orElse: () => Effect.fail(new BrowserRunFailure({
|
|
1067
|
+
operation: "protected.detach",
|
|
1068
|
+
reason: "timeout"
|
|
1069
|
+
}))
|
|
1070
|
+
}), Effect.catch((error) => reportBrowserCause("protected.detach", Cause.fail(error)).pipe(Effect.andThen(Effect.fail(reportedBrowserError(failure()))))))
|
|
1071
|
+
};
|
|
1072
|
+
}, Effect.withTracerEnabled(false)),
|
|
1073
|
+
keepAlive: Effect.fn("BrowserRunProtectedBinding.keepAlive")(function* (sessionId) {
|
|
1074
|
+
const failure = (reason) => new ProtectedBrowserError({
|
|
1075
|
+
reason,
|
|
1076
|
+
dispatch: "not-dispatched",
|
|
1077
|
+
milestone: "none",
|
|
1078
|
+
observation: "protected",
|
|
1079
|
+
cleanup: "not-requested"
|
|
1080
|
+
});
|
|
1081
|
+
const id = yield* Schema.decodeEffect(ProtectedProviderIdentity.fields.sessionId)(sessionId).pipe(Effect.mapError(() => failure("denied")));
|
|
1082
|
+
yield* binding.keepAlive(Redacted.value(id)).pipe(Effect.timeoutOrElse({
|
|
1043
1083
|
duration: "10 seconds",
|
|
1044
1084
|
orElse: () => Effect.fail(new BrowserRunFailure({
|
|
1045
|
-
operation: "protected.
|
|
1085
|
+
operation: "protected.keepAlive",
|
|
1046
1086
|
reason: "timeout"
|
|
1047
1087
|
}))
|
|
1048
|
-
}), Effect.
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1088
|
+
}), Effect.tapError((error) => reportBrowserCause("protected.keepAlive", Cause.fail(error))), Effect.mapError((error) => reportedBrowserError(failure(error.reason === "timeout" ? "timeout" : "provider"))));
|
|
1089
|
+
}, Effect.withTracerEnabled(false))
|
|
1090
|
+
};
|
|
1051
1091
|
})).pipe(Layer.provide(BrowserRunBinding.layer(options.browser)));
|
|
1052
1092
|
/** One binding implementation serves scoped tools and host-managed protected handoffs. */
|
|
1053
1093
|
const browserRunProtectedBindingLayer = (options) => Layer.effect(BrowserRunProtectedTransport)(Effect.gen(function* () {
|
|
@@ -1190,6 +1230,7 @@ const browserRunProtectedHostLayer = () => Layer.effect(BrowserRunProtectedHost)
|
|
|
1190
1230
|
};
|
|
1191
1231
|
}, Effect.withTracerEnabled(false));
|
|
1192
1232
|
return {
|
|
1233
|
+
keepAlive: binding.keepAlive,
|
|
1193
1234
|
open: (policy) => open(policy),
|
|
1194
1235
|
resume: (checkpoint) => Schema.decodeEffect(BrowserRunProtectedCheckpoint)(checkpoint).pipe(Effect.mapError(() => failure("denied")), Effect.flatMap((decoded) => open(decoded.protected.policy, decoded))),
|
|
1195
1236
|
closeSession: (id) => lifecycle.close(id).pipe(Effect.as("confirmed"), Effect.catchCause((cause) => reportBrowserCause("protected.closeSession", cause).pipe(Effect.as("unconfirmed"))))
|