@opencode/browse 0.0.6-dev.25 → 0.0.6-dev.28

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.
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  opencodeBrowserVersion2,
3
3
  opencodeBrowserBuildId2
4
- } from "./main-sdmv8gfv.mjs";
4
+ } from "./main-4t3a1fw9.mjs";
5
5
  import {
6
6
  dataRoot,
7
7
  oldStoreMarker,
8
8
  fromCheckout,
9
9
  cliCommand,
10
+ PUBLIC_STORE_ID,
10
11
  storeConfig,
11
12
  devExtension,
12
13
  storeUrl,
@@ -18,7 +19,7 @@ import {
18
19
  setStoredMode,
19
20
  autoUpdateStatus,
20
21
  createAutoUpdater
21
- } from "./main-hh2mneh8.mjs";
22
+ } from "./main-8ncff5jp.mjs";
22
23
  import {
23
24
  extensionProtocolVersion,
24
25
  minExtensionProtocolVersion,
@@ -42,7 +43,7 @@ import {
42
43
  relayToken,
43
44
  secretsEqual,
44
45
  ensurePrivateDirectory
45
- } from "./main-tf22ynec.mjs";
46
+ } from "./main-x8w3s3rv.mjs";
46
47
  import {
47
48
  ExecuteRequest,
48
49
  SessionAdoptRequest,
@@ -56,7 +57,6 @@ import {
56
57
  NetworkStartRequest,
57
58
  NetworkSessionRequest,
58
59
  NetworkStopRequest,
59
- DeadboltLoginsRequest,
60
60
  AuthProfileRequest,
61
61
  AuthRefreshRequest,
62
62
  AuthRunRequest,
@@ -92,7 +92,7 @@ import {
92
92
  isRestrictedTarget2,
93
93
  isRestrictedUrl2,
94
94
  dataUrlDocument2
95
- } from "./main-7pxrvrp0.mjs";
95
+ } from "./main-8h1nwn45.mjs";
96
96
  import {
97
97
  relayHostname,
98
98
  isLocalPeer,
@@ -114,7 +114,7 @@ import {
114
114
  wrapToken,
115
115
  installedDevExtension,
116
116
  syncDevExtension
117
- } from "./main-e83a20ce.mjs";
117
+ } from "./main-xg3r1ze3.mjs";
118
118
  import {
119
119
  SettingsInputError,
120
120
  parseSettingChanges,
@@ -122,17 +122,6 @@ import {
122
122
  settingsToExtension,
123
123
  describeSettings,
124
124
  describeChanges,
125
- DeadboltError,
126
- readClient,
127
- connect,
128
- parseDeadboltName,
129
- originOnSite,
130
- pickLogin,
131
- originsFromPatterns,
132
- listLogins,
133
- pickPasskey,
134
- isBase64Url,
135
- randomName,
136
125
  terminateChildProcess,
137
126
  SecretCollector,
138
127
  looksLikeTokenSegment,
@@ -152,16 +141,16 @@ import {
152
141
  checkNavigationUrl,
153
142
  readSecret,
154
143
  secretText
155
- } from "./main-xj8td7qw.mjs";
144
+ } from "./main-rsqahh12.mjs";
156
145
  import {
157
146
  defaultJournalBaseDir,
158
147
  makeJournalEntry,
159
148
  appendJournalEntry,
160
149
  startJournalRetention
161
- } from "./main-mm82qqzb.mjs";
150
+ } from "./main-tfkqwwrb.mjs";
162
151
  import {
163
152
  createUpdateWatcher2
164
- } from "./main-spqvtmdy.mjs";
153
+ } from "./main-scyv26xb.mjs";
165
154
 
166
155
  // src/relay.ts
167
156
  import crypto10 from "node:crypto";
@@ -4220,15 +4209,6 @@ async function detectChallenge(page, options) {
4220
4209
  recommendation: current.kind === "block" ? "stop" : "handoff"
4221
4210
  };
4222
4211
  }
4223
- var requestEvents = new Set(["request", "requestfinished", "requestfailed", "response", "websocket", "route"]);
4224
- function pageHookCall(fn, args) {
4225
- const name = typeof fn.name === "string" ? fn.name.replace(/^bound /, "") : "";
4226
- if (["route", "routeFromHAR", "routeWebSocket", "addInitScript", "exposeBinding", "exposeFunction", "newCDPSession", "waitForRequest", "waitForResponse"].includes(name))
4227
- return `${name}()`;
4228
- if (["on", "once", "addListener", "prependListener", "waitForEvent"].includes(name) && typeof args[0] === "string" && requestEvents.has(args[0]))
4229
- return `${name}("${args[0]}")`;
4230
- return;
4231
- }
4232
4212
  function pageVisibleApiSourceWarnings(code) {
4233
4213
  const warnings = [];
4234
4214
  for (const name of ["addInitScript", "exposeFunction", "exposeBinding"]) {
@@ -8738,9 +8718,7 @@ function buildSandboxGlobals(deps) {
8738
8718
  stop: (target) => stop(target ?? page)
8739
8719
  },
8740
8720
  secrets: {
8741
- type: (target, name, typeOptions) => deps.secrets.typeSecret(page, target, name, typeOptions),
8742
- signIn: (signInOptions) => deps.secrets.signIn(page, signInOptions),
8743
- usePasskey: (passkeyOptions) => deps.secrets.usePasskey(passkeyOptions?.page ?? page, passkeyOptions)
8721
+ type: (target, name, typeOptions) => deps.secrets.typeSecret(page, target, name, typeOptions)
8744
8722
  },
8745
8723
  handoffTracker
8746
8724
  };
@@ -8748,554 +8726,6 @@ function buildSandboxGlobals(deps) {
8748
8726
 
8749
8727
  // src/execute/secrets-bridge.ts
8750
8728
  import { Effect as Effect10 } from "effect";
8751
-
8752
- // src/auth/sign-in.ts
8753
- var googleSite = "accounts.google.com";
8754
- var handoffHint = 'Hand it to the user with handoff("Finish signing in, then click Continue"), then check the page.';
8755
- var readPageScript = () => {
8756
- const limit = 20000;
8757
- const all = [];
8758
- const walk = (root) => {
8759
- for (const element of Array.from(root.querySelectorAll("*"))) {
8760
- if (all.length >= limit)
8761
- return;
8762
- all.push(element);
8763
- if (element.shadowRoot)
8764
- walk(element.shadowRoot);
8765
- }
8766
- };
8767
- walk(document);
8768
- const visible = (element) => {
8769
- const rect = element.getBoundingClientRect();
8770
- if (rect.width < 2 || rect.height < 2)
8771
- return false;
8772
- const style = getComputedStyle(element);
8773
- if (style.visibility === "hidden" || style.display === "none" || Number(style.opacity) < 0.05)
8774
- return false;
8775
- return !element.closest("[hidden], [inert], [aria-hidden='true']");
8776
- };
8777
- const describe = (element) => {
8778
- const input = element;
8779
- const labelled = (element.getAttribute("aria-labelledby") ?? "").split(/\s+/).filter(Boolean).map((id) => element.ownerDocument.getElementById(id)?.textContent ?? "").join(" ");
8780
- return [
8781
- element.getAttribute("aria-label"),
8782
- labelled,
8783
- Array.from(input.labels ?? []).map((label) => label.textContent).join(" "),
8784
- input.placeholder,
8785
- input.name,
8786
- element.id,
8787
- element.getAttribute("autocomplete"),
8788
- element.getAttribute("data-testid")
8789
- ].filter(Boolean).join(" ").toLowerCase().replace(/\s+/g, " ");
8790
- };
8791
- const ownText = (element) => `${element.innerText ?? element.textContent ?? ""} ${element.getAttribute("aria-label") ?? ""} ${element.value && element.type === "submit" ? element.value : ""}`.trim().toLowerCase().replace(/\s+/g, " ");
8792
- const inputs = all.filter((element) => element instanceof HTMLInputElement && !element.disabled && !element.readOnly && visible(element) && !["hidden", "checkbox", "radio", "submit", "button", "image", "reset", "file", "range", "color", "search"].includes(element.type));
8793
- const autocomplete = (element) => (element.getAttribute("autocomplete") ?? "").toLowerCase();
8794
- const password = inputs.find((element) => element.type === "password" && !/new-password/.test(autocomplete(element)) && !/confirm|repeat|re-?enter|new password|retype/.test(describe(element)));
8795
- const codeWords = /one[- ]?time|\botp\b|totp|\b2fa\b|\bmfa\b|two[- ]factor|verification|security code|auth\w* code|passcode|\bpin\b|digit|\bcode\b/;
8796
- const singleBoxes = inputs.filter((element) => element.maxLength === 1 && element.type !== "password");
8797
- const otpSingle = inputs.find((element) => element !== password && element.maxLength !== 1 && (autocomplete(element).includes("one-time-code") || codeWords.test(describe(element)) && !/zip|postal|promo|coupon|country|area|referral|invite/.test(describe(element))));
8798
- const otp = singleBoxes.length >= 4 && singleBoxes.length <= 8 ? singleBoxes : otpSingle ? [otpSingle] : [];
8799
- const usernameCandidates = inputs.filter((element) => element !== password && !otp.includes(element) && ["text", "email", "tel", ""].includes(element.type) && (/username|email|webauthn/.test(autocomplete(element)) || element.type === "email" || /user|e-?mail|login|identifier|account|phone|handle/.test(describe(element))) && !/search|newsletter|subscribe|coupon|promo/.test(describe(element)));
8800
- const form = password?.form ?? null;
8801
- const username = usernameCandidates.find((element) => form && element.form === form) ?? usernameCandidates[0] ?? null;
8802
- const clickables = all.filter((element) => (element instanceof HTMLButtonElement || element instanceof HTMLAnchorElement || element.getAttribute("role") === "button" || element.getAttribute("role") === "link" || element instanceof HTMLInputElement && (element.type === "submit" || element.type === "button")) && visible(element) && !element.disabled);
8803
- const byText = (pattern) => clickables.find((element) => pattern.test(ownText(element)));
8804
- const field = otp[0] ?? password ?? username ?? null;
8805
- const submitFor = (target) => {
8806
- if (!target)
8807
- return null;
8808
- const owner = target.form;
8809
- if (owner) {
8810
- const inForm = clickables.filter((element) => element.form === owner || owner.contains(element));
8811
- const typed = inForm.find((element) => element instanceof HTMLButtonElement && element.type === "submit" || element instanceof HTMLInputElement && element.type === "submit");
8812
- if (typed)
8813
- return typed;
8814
- }
8815
- const words = /^(sign ?in|log ?in|login|next|continue|verify|submit|confirm|done|weiter|suivant)\b/;
8816
- const following = clickables.filter((element) => target.compareDocumentPosition(element) & Node.DOCUMENT_POSITION_FOLLOWING);
8817
- return following.find((element) => words.test(ownText(element))) ?? clickables.find((element) => words.test(ownText(element))) ?? null;
8818
- };
8819
- const frames = Array.from(document.querySelectorAll("iframe")).filter(visible);
8820
- const captchaFrame = frames.find((frame) => {
8821
- const src = frame.src;
8822
- if (/size=invisible/.test(src) || frame.closest(".grecaptcha-badge"))
8823
- return false;
8824
- if (/challenges\.cloudflare\.com/.test(src)) {
8825
- const response = frame.ownerDocument.querySelector("input[name='cf-turnstile-response']");
8826
- return !response?.value;
8827
- }
8828
- return /\/recaptcha\/(api2|enterprise)\/(anchor|bframe)|hcaptcha\.com|arkoselabs|funcaptcha|geo\.captcha-delivery|captcha/.test(src);
8829
- });
8830
- const captchaWidget = all.find((element) => /^(px-captcha|sec-cpt-if|ddv1-captcha-container)$/.test(element.id) && visible(element));
8831
- const errors = all.filter((element) => (element.getAttribute("role") === "alert" || element.getAttribute("aria-live") === "assertive" || /(^|[\s_-])(error|alert|invalid)([\s_-]|$)/i.test(typeof element.className === "string" ? element.className : "")) && visible(element));
8832
- const handles = {
8833
- password: password ?? null,
8834
- username,
8835
- otp,
8836
- submit: submitFor(field),
8837
- passwordToggle: byText(/use (your )?password|(sign|log) ?in with (a |your )?password|enter (your )?password( instead)?|password instead|try another way/) ?? null,
8838
- google: byText(/(sign ?in|log ?in|continue|sign ?up) (with|using|via) google|^google$/) ?? null,
8839
- signInLink: byText(/^(sign ?in|log ?in|login)$/) ?? null,
8840
- passkeyButton: byText(/(sign ?in|log ?in|continue) (with|using) (a |your )?passkey|use (a |your )?passkey|^passkey$/) ?? null
8841
- };
8842
- const state = {
8843
- captcha: captchaFrame ? captchaFrame.src.slice(0, 120) : captchaWidget ? `#${captchaWidget.id}` : null,
8844
- hasPassword: Boolean(password),
8845
- hasUsername: Boolean(username),
8846
- usernameFilled: username?.value ?? "",
8847
- otpCount: otp.length,
8848
- hasPasswordToggle: Boolean(handles.passwordToggle),
8849
- hasGoogle: Boolean(handles.google),
8850
- hasSignInLink: Boolean(handles.signInLink),
8851
- hasPasskeyButton: Boolean(handles.passkeyButton),
8852
- text: `${document.title}
8853
- ${document.body?.innerText ?? ""}`.slice(0, 4000).toLowerCase(),
8854
- errorText: errors.map((element) => element.innerText ?? "").join(" ").replace(/\s+/g, " ").trim().slice(0, 120)
8855
- };
8856
- return { state, handles };
8857
- };
8858
- async function element(read, name) {
8859
- const property = await read.handles.getProperty(name);
8860
- return property.asElement() ?? undefined;
8861
- }
8862
- async function otpElements(read) {
8863
- const list = await read.handles.getProperty("otp");
8864
- const properties = await list.getProperties();
8865
- const elements = [];
8866
- for (const [key, value] of properties) {
8867
- if (!/^\d+$/.test(key))
8868
- continue;
8869
- const handle = value.asElement();
8870
- if (handle)
8871
- elements.push(handle);
8872
- }
8873
- return elements;
8874
- }
8875
- async function readFrame(frame) {
8876
- try {
8877
- const handles = await frame.evaluateHandle(readPageScript);
8878
- const state = await (await handles.getProperty("state")).jsonValue();
8879
- return { frame, state, handles: await handles.getProperty("handles") };
8880
- } catch {
8881
- return;
8882
- }
8883
- }
8884
- var actionable = (state) => Boolean(state.captcha || state.otpCount || state.hasPassword || state.hasUsername || state.hasPasswordToggle || state.hasGoogle || state.hasPasskeyButton);
8885
- async function readPage(page, site) {
8886
- const main = await readFrame(page.mainFrame());
8887
- if (main && actionable(main.state))
8888
- return main;
8889
- for (const frame of page.frames()) {
8890
- if (frame === page.mainFrame())
8891
- continue;
8892
- let origin;
8893
- try {
8894
- origin = new URL(frame.url()).origin;
8895
- } catch {
8896
- continue;
8897
- }
8898
- if (!originOnSite(origin, site))
8899
- continue;
8900
- const read = await readFrame(frame);
8901
- if (read && actionable(read.state))
8902
- return read;
8903
- }
8904
- return main;
8905
- }
8906
- var delay3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8907
- function defaultSite(url) {
8908
- let parsed;
8909
- try {
8910
- parsed = new URL(url);
8911
- } catch {
8912
- return;
8913
- }
8914
- if (parsed.protocol !== "https:" && parsed.protocol !== "http:")
8915
- return;
8916
- const host = parsed.hostname.toLowerCase();
8917
- if (parsed.protocol === "http:" || /^[\d.]+$/.test(host) || host.includes(":") || host === "localhost" || host.endsWith(".localhost"))
8918
- return parsed.origin;
8919
- const labels = host.split(".");
8920
- const twoLevel = labels.length >= 3 && /^(co|com|org|net|gov|ac|edu|ne|or)$/.test(labels.at(-2)) && labels.at(-1).length === 2;
8921
- return labels.slice(twoLevel ? -3 : -2).join(".");
8922
- }
8923
- function codeKind(text) {
8924
- if (/authenticator|authentication app|auth app|google authenticator|\btotp\b|one-time password app|security key app|2fa app|your app/.test(text))
8925
- return "totp";
8926
- if (/\bsms\b|text message|texted|we (just )?sent|sent (a|the|you a) code|sent to|check your (email|inbox|phone)|by email|via email|phone call|call you|ending in|whatsapp/.test(text))
8927
- return "sent";
8928
- return "unknown";
8929
- }
8930
- function verificationKind(text) {
8931
- if (/approve (the|this|your) (sign|log)|check your phone|tap yes|duo push|push notification|approve (it|the request)|waiting for (your )?approval|open the .{0,20} app on your/.test(text))
8932
- return "push_approval";
8933
- if (/new device|unrecognized device|unfamiliar device|verify (it'?s|that it'?s) you|confirm (it'?s|your identity|that it'?s you)|verify your identity|security check/.test(text))
8934
- return "new_device";
8935
- if (/security question/.test(text))
8936
- return "security_question";
8937
- return;
8938
- }
8939
- function needsUser(step, why) {
8940
- return { status: "needs_user", step, reason: `${why} ${handoffHint}` };
8941
- }
8942
- async function clickHandle(handle) {
8943
- await handle.scrollIntoViewIfNeeded().catch(() => {});
8944
- await handle.click({ timeout: 5000 }).catch(async () => {
8945
- await handle.evaluate((node) => node.click());
8946
- });
8947
- }
8948
- async function domSignature(frame) {
8949
- return await frame.evaluate(() => `${document.querySelectorAll("input, iframe, [role='alert']").length}:${document.body?.innerText.length ?? 0}`).catch(() => "");
8950
- }
8951
- async function waitForProgress(page, field, timeoutMs) {
8952
- const url = page.url();
8953
- const until = Date.now() + timeoutMs;
8954
- const frame = await field?.ownerFrame().catch(() => null) ?? page.mainFrame();
8955
- const before = await domSignature(frame);
8956
- while (Date.now() < until) {
8957
- await delay3(250);
8958
- if (page.isClosed())
8959
- return true;
8960
- if (page.url() !== url) {
8961
- await page.waitForLoadState("domcontentloaded", { timeout: Math.max(1, until - Date.now()) }).catch(() => {});
8962
- return true;
8963
- }
8964
- if (field && !await field.isVisible().catch(() => false))
8965
- return true;
8966
- const now = await domSignature(frame);
8967
- if (before && now && now !== before) {
8968
- await delay3(400);
8969
- return true;
8970
- }
8971
- }
8972
- return false;
8973
- }
8974
- async function clearSecretInputs(frames, fields = []) {
8975
- const clearScript = () => {
8976
- const own = (element) => {
8977
- const input = element;
8978
- if (!(input instanceof HTMLInputElement) || !input.value)
8979
- return;
8980
- const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
8981
- if (setter)
8982
- setter.call(input, "");
8983
- else
8984
- input.value = "";
8985
- input.dispatchEvent(new Event("input", { bubbles: true }));
8986
- input.dispatchEvent(new Event("change", { bubbles: true }));
8987
- };
8988
- const all = [];
8989
- const walk = (root) => {
8990
- for (const element of Array.from(root.querySelectorAll("input"))) {
8991
- const input = element;
8992
- if (input.type === "password" || /one-time-code/i.test(input.autocomplete) || input.maxLength === 1 && input.type !== "checkbox" && input.type !== "radio")
8993
- all.push(input);
8994
- }
8995
- for (const host of Array.from(root.querySelectorAll("*")))
8996
- if (host.shadowRoot)
8997
- walk(host.shadowRoot);
8998
- };
8999
- walk(document);
9000
- for (const element of all)
9001
- own(element);
9002
- };
9003
- for (const field of fields) {
9004
- await field.evaluate((node) => {
9005
- const input = node;
9006
- if (!(input instanceof HTMLInputElement) || !input.value)
9007
- return;
9008
- Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set?.call(input, "");
9009
- input.dispatchEvent(new Event("input", { bubbles: true }));
9010
- input.dispatchEvent(new Event("change", { bubbles: true }));
9011
- }).catch(() => {});
9012
- }
9013
- for (const frame of new Set(frames)) {
9014
- if (frame.isDetached())
9015
- continue;
9016
- await frame.evaluate(clearScript).catch(() => {});
9017
- }
9018
- }
9019
- async function submit(read, field) {
9020
- const button = await element(read, "submit");
9021
- if (button)
9022
- await clickHandle(button);
9023
- else
9024
- await field.press("Enter");
9025
- }
9026
- async function signIn(deps, options = {}) {
9027
- const timeoutMs = options.timeoutMs ?? 90000;
9028
- const deadline = Date.now() + timeoutMs;
9029
- let page = deps.page;
9030
- if (options.site !== undefined && (typeof options.site !== "string" || !options.site))
9031
- return { status: "failed", step: "start", reason: "site must be a host like example.com or an origin" };
9032
- const startSite = options.site?.toLowerCase() ?? defaultSite(page.url());
9033
- if (!startSite)
9034
- return { status: "failed", step: "start", reason: "The page isn't on a website; navigate to the site's sign-in page first, or pass {site}." };
9035
- const siteSpec = { site: startSite, ...options.username ? { username: options.username } : {} };
9036
- const typedFrames = new Set;
9037
- const typedFields = [];
9038
- const tracked = {
9039
- ...deps,
9040
- type: async (handles, spec, field) => {
9041
- for (const handle of handles) {
9042
- const frame = await handle.ownerFrame().catch(() => null);
9043
- if (frame)
9044
- typedFrames.add(frame);
9045
- if (field !== "username")
9046
- typedFields.push(handle);
9047
- }
9048
- return await deps.type(handles, spec, field);
9049
- }
9050
- };
9051
- let result;
9052
- try {
9053
- const onSite = (() => {
9054
- try {
9055
- return originOnSite(new URL(page.url()).origin, startSite);
9056
- } catch {
9057
- return false;
9058
- }
9059
- })();
9060
- if (!onSite) {
9061
- const start = /^https?:\/\//.test(startSite) ? startSite : `https://${startSite}/`;
9062
- await page.goto(start, { waitUntil: "domcontentloaded", timeout: Math.min(30000, timeoutMs) });
9063
- }
9064
- if (options.username && deps.passkeys)
9065
- await deps.passkeys.select(page, startSite, options.username).catch(() => {});
9066
- result = await run2(tracked, page, siteSpec, deadline, 0);
9067
- return result;
9068
- } catch (error) {
9069
- result = fromError(error, "start");
9070
- return result;
9071
- } finally {
9072
- if (result?.status !== "signed_in" && typedFrames.size > 0)
9073
- await clearSecretInputs(typedFrames, typedFields);
9074
- if (options.username && deps.passkeys && !page.isClosed())
9075
- await deps.passkeys.select(page, startSite, "").catch(() => {});
9076
- }
9077
- }
9078
- function fromError(error, step) {
9079
- if (error instanceof DeadboltError) {
9080
- if (error.code === "not_granted")
9081
- return { status: "not_granted", step, reason: error.message };
9082
- if (error.code === "locked")
9083
- return { status: "needs_user", step, reason: error.message };
9084
- return { status: "failed", step, reason: `${error.code}: ${error.message}` };
9085
- }
9086
- const message = error instanceof Error ? error.message : String(error);
9087
- if (/domain_not_allowed/.test(message))
9088
- return { status: "failed", step, reason: message.replace(/^secrets\.\w+: /, "") };
9089
- return { status: "failed", step, reason: message.slice(0, 300) };
9090
- }
9091
- async function run2(deps, startPage, siteSpec, deadline, depth) {
9092
- const page = startPage;
9093
- let step = "start";
9094
- let googleSpec;
9095
- let clickedSignInLink = false;
9096
- let toggles = 0;
9097
- let lastSignature = "";
9098
- let repeats = 0;
9099
- let passkeyClicks = 0;
9100
- const started = Date.now();
9101
- const needsChoice = async () => {
9102
- if (siteSpec.username || !deps.passkeys)
9103
- return;
9104
- const choices = await deps.passkeys.choiceSince(page, started).catch(() => {
9105
- return;
9106
- });
9107
- if (!choices || choices.length === 0)
9108
- return;
9109
- return { status: "needs_choice", step: "passkey", reason: `Several passkeys can sign in to ${siteSpec.site}; call again with { username } set to one of the choices.`, choices };
9110
- };
9111
- const specFor = (url) => {
9112
- let origin;
9113
- try {
9114
- origin = new URL(url).origin;
9115
- } catch {
9116
- return;
9117
- }
9118
- if (originOnSite(origin, siteSpec.site))
9119
- return siteSpec;
9120
- if (googleSpec && originOnSite(origin, googleSite))
9121
- return googleSpec;
9122
- return;
9123
- };
9124
- while (Date.now() < deadline) {
9125
- if (page.isClosed())
9126
- return step === "start" ? { status: "failed", step, reason: "The page closed." } : { status: "signed_in", step: "done", reason: "The sign-in window closed after the last step." };
9127
- await page.waitForLoadState("domcontentloaded", { timeout: Math.max(1, Math.min(15000, deadline - Date.now())) }).catch(() => {});
9128
- const url = page.url();
9129
- const spec = specFor(url);
9130
- if (!spec) {
9131
- if (step === "start")
9132
- return { status: "failed", step, reason: `The page is on ${safeOrigin(url)}, not ${siteSpec.site}.` };
9133
- return needsUser("provider", `The sign-in moved to ${safeOrigin(url)}, which isn't ${siteSpec.site}${googleSpec ? " or Google" : ""}.`);
9134
- }
9135
- const choice = await needsChoice();
9136
- if (choice)
9137
- return choice;
9138
- let read;
9139
- const settleUntil = Math.min(deadline, Date.now() + (step === "start" ? 8000 : 5000));
9140
- while (true) {
9141
- read = await readPage(page, spec.site);
9142
- if (read && actionable(read.state) || Date.now() >= settleUntil)
9143
- break;
9144
- await delay3(300);
9145
- }
9146
- if (!read) {
9147
- await delay3(300);
9148
- continue;
9149
- }
9150
- const state = read.state;
9151
- const signature = `${url}|${state.hasUsername}|${state.hasPassword}|${state.otpCount}|${state.usernameFilled.length}`;
9152
- repeats = signature === lastSignature ? repeats + 1 : 0;
9153
- lastSignature = signature;
9154
- if (repeats >= 2) {
9155
- return { status: "failed", step, reason: state.errorText ? `The site didn't accept the ${step === "code" ? "code" : step}: ${state.errorText}` : `The page didn't move on after the ${step} step.` };
9156
- }
9157
- if (state.captcha)
9158
- return needsUser(step, `A captcha is showing (${state.captcha}).`);
9159
- const challenge = await deps.challenge(page).catch(() => {
9160
- return;
9161
- });
9162
- if (challenge && challenge.kind !== "non-interactive") {
9163
- return challenge.kind === "block" ? { status: "failed", step, reason: `The site blocked the visit (${challenge.vendor}).` } : needsUser(step, `A ${challenge.vendor} bot check is showing.`);
9164
- }
9165
- if (state.otpCount > 0) {
9166
- const kind = codeKind(state.text);
9167
- if (kind === "sent")
9168
- return needsUser("code", "The site sent a one-time code by SMS, email or call.");
9169
- const logins = await deps.logins(new URL(read.frame.url()).origin).catch(() => []);
9170
- const hasTotp = logins.some((login) => login.hasTotp && login.granted && (!login.fields || login.fields.includes("totp")) && (!spec.username || login.username?.toLowerCase() === spec.username.toLowerCase()));
9171
- if (!hasTotp)
9172
- return needsUser("code", kind === "totp" ? "The site asks for an authenticator code, and the granted login has no one-time password." : "The site asks for a one-time code.");
9173
- const boxes = await otpElements(read);
9174
- step = "code";
9175
- await deps.type(boxes, spec, "totp");
9176
- if (!await waitForProgress(page, boxes[0], 1500)) {
9177
- const stillThere = await boxes[0].isVisible().catch(() => false);
9178
- if (stillThere)
9179
- await submit(read, boxes.at(-1));
9180
- await waitForProgress(page, boxes[0], 15000);
9181
- }
9182
- continue;
9183
- }
9184
- if (state.hasPassword) {
9185
- const passwordField = await element(read, "password");
9186
- const usernameField = await element(read, "username");
9187
- if (usernameField && !state.usernameFilled)
9188
- await deps.type([usernameField], spec, "username");
9189
- step = "password";
9190
- await deps.type([passwordField], spec, "password");
9191
- await submit(read, passwordField);
9192
- await waitForProgress(page, passwordField, 15000);
9193
- continue;
9194
- }
9195
- if (state.hasUsername) {
9196
- const usernameField = await element(read, "username");
9197
- await deps.type([usernameField], spec, "username");
9198
- step = "identifier";
9199
- await submit(read, usernameField);
9200
- await waitForProgress(page, usernameField, 15000);
9201
- continue;
9202
- }
9203
- if (state.hasPasswordToggle && toggles < 2) {
9204
- toggles += 1;
9205
- await clickHandle(await element(read, "passwordToggle"));
9206
- await waitForProgress(page, undefined, 2000);
9207
- continue;
9208
- }
9209
- if (state.hasGoogle && !googleSpec && depth === 0 && spec === siteSpec) {
9210
- const siteLogins = await deps.logins(new URL(read.frame.url()).origin).catch(() => []);
9211
- const viaGoogle = siteLogins.find((login) => login.signIn?.provider === "google");
9212
- const googleLogins = (await deps.logins(`https://${googleSite}`).catch(() => [])).filter((login) => login.granted);
9213
- const account = siteSpec.username ?? viaGoogle?.signIn?.account;
9214
- const googleLogin = googleLogins.find((login) => !account || login.username?.toLowerCase() === account.toLowerCase()) ?? (googleLogins.length === 1 ? googleLogins[0] : undefined);
9215
- if (googleLogin && (viaGoogle || !siteLogins.some((login) => login.granted && login.hasPassword))) {
9216
- if (!deps.allowed(`https://${googleSite}/`))
9217
- return needsUser("provider", `Signing in uses Google, but ${googleSite} isn't in this session's allowlist (add it with session_allowlist).`);
9218
- googleSpec = { site: googleSite, ...googleLogin.username ? { username: googleLogin.username } : {} };
9219
- step = "provider";
9220
- const popupPromise = deps.context.waitForEvent("page", { timeout: 5000 }).catch(() => {
9221
- return;
9222
- });
9223
- await clickHandle(await element(read, "google"));
9224
- const popup = await popupPromise;
9225
- if (popup) {
9226
- await popup.waitForLoadState("domcontentloaded").catch(() => {});
9227
- const result = await runProvider(deps, popup, googleSpec, deadline);
9228
- if (result.status !== "signed_in")
9229
- return result;
9230
- await waitForProgress(page, undefined, 5000);
9231
- } else {
9232
- await waitForProgress(page, undefined, 1e4);
9233
- }
9234
- continue;
9235
- }
9236
- }
9237
- if (state.hasPasskeyButton && passkeyClicks < 1) {
9238
- const origin = new URL(read.frame.url()).origin;
9239
- const passkeys = await deps.passkeyAccounts(origin).catch(() => []);
9240
- const granted = spec.username ? pickPasskey(passkeys, spec.username) !== undefined : passkeys.some((passkey) => passkey.granted);
9241
- if (granted) {
9242
- passkeyClicks += 1;
9243
- step = "passkey";
9244
- const before = page.url();
9245
- await clickHandle(await element(read, "passkeyButton"));
9246
- const until = Math.min(deadline, Date.now() + 1e4);
9247
- while (Date.now() < until && !page.isClosed() && page.url() === before) {
9248
- const picked = await needsChoice();
9249
- if (picked)
9250
- return picked;
9251
- await delay3(250);
9252
- }
9253
- await page.waitForLoadState("domcontentloaded").catch(() => {});
9254
- continue;
9255
- }
9256
- }
9257
- const verification = verificationKind(state.text);
9258
- if (verification)
9259
- return needsUser("verify", verification === "push_approval" ? "The site waits for a push approval on another device." : verification === "security_question" ? "The site asks a security question." : "The site wants to verify a new device or that it's really the user.");
9260
- if (step !== "start" && codeKind(state.text) === "sent")
9261
- return needsUser("code", "The site sent a one-time code by SMS, email or call.");
9262
- if (step === "start") {
9263
- if (state.hasSignInLink && !clickedSignInLink) {
9264
- clickedSignInLink = true;
9265
- await clickHandle(await element(read, "signInLink"));
9266
- await waitForProgress(page, undefined, 8000);
9267
- continue;
9268
- }
9269
- if (state.hasGoogle)
9270
- return needsUser("provider", "The page offers Sign in with Google, but Deadbolt grants no Google login for it.");
9271
- return { status: "failed", step, reason: "No sign-in form found on this page. Open the site's sign-in page first." };
9272
- }
9273
- if (state.errorText && /incorrect|wrong|invalid|doesn'?t match|not recognized|couldn'?t find|try again/i.test(state.errorText)) {
9274
- return { status: "failed", step, reason: `The site refused the sign-in: ${state.errorText}` };
9275
- }
9276
- if (spec === googleSpec && spec !== siteSpec)
9277
- return needsUser("provider", "Google shows a screen to choose an account or to give consent.");
9278
- return { status: "signed_in", step: "done", reason: `Signed in to ${spec.site}: no sign-in field is left after the ${step} step.` };
9279
- }
9280
- return { status: "failed", step: "start", reason: "The sign-in didn't finish in time." };
9281
- }
9282
- async function runProvider(deps, popup, spec, deadline) {
9283
- const result = await run2({ ...deps, page: popup }, popup, spec, deadline, 1);
9284
- if (result.status !== "signed_in")
9285
- return result;
9286
- if (!popup.isClosed())
9287
- await popup.waitForEvent("close", { timeout: Math.max(1, Math.min(20000, deadline - Date.now())) }).catch(() => {});
9288
- return popup.isClosed() ? result : needsUser("provider", "Google's sign-in window stayed open (an account choice or consent screen).");
9289
- }
9290
- function safeOrigin(url) {
9291
- try {
9292
- return new URL(url).origin;
9293
- } catch {
9294
- return url.slice(0, 80);
9295
- }
9296
- }
9297
-
9298
- // src/execute/secrets-bridge.ts
9299
8729
  var isOpaqueDocumentUrl = (url) => /^(?:about|data|blob):/i.test(url);
9300
8730
  var frameOrigin = (url) => {
9301
8731
  try {
@@ -9312,8 +8742,6 @@ var elementHasFocus = (handle) => handle.evaluate((node) => {
9312
8742
  class ExecuteSecretsBridge {
9313
8743
  deps;
9314
8744
  typedSecrets = new Map;
9315
- deadboltConnection;
9316
- pageHooks = new Set;
9317
8745
  constructor(deps) {
9318
8746
  this.deps = deps;
9319
8747
  }
@@ -9371,9 +8799,6 @@ class ExecuteSecretsBridge {
9371
8799
  async typeSecret(page, target, name, options = {}) {
9372
8800
  if (typeof name !== "string" || !name)
9373
8801
  throw new Error("secrets.type(target, name): name must be the name of a stored secret");
9374
- const deadboltSpec = parseDeadboltName(name);
9375
- if (deadboltSpec)
9376
- return await this.typeDeadboltSecret(page, target, name, deadboltSpec, options);
9377
8802
  const secret = await Effect10.runPromise(readSecret(name)).catch((error) => {
9378
8803
  throw new Error(`secrets.type: ${error instanceof Error ? error.message : "could not read the secret"}`);
9379
8804
  });
@@ -9428,158 +8853,6 @@ class ExecuteSecretsBridge {
9428
8853
  await handle.dispose().catch(() => {});
9429
8854
  }
9430
8855
  }
9431
- refuseWithPageHooks(label) {
9432
- if (this.pageHooks.size === 0)
9433
- return;
9434
- throw new Error(`${label}: page_hooks: this session's code used ${[...this.pageHooks].sort().join(", ")}, which could capture what is typed, so Deadbolt passwords and codes aren't typed here. Reset the session (session_reset) and sign in before setting those up. Nothing was typed.`);
9435
- }
9436
- deadbolt() {
9437
- const client = readClient();
9438
- if (!this.deadboltConnection || !client || this.deadboltConnection.client.id !== client.id || this.deadboltConnection.client.token !== client.token) {
9439
- this.deadboltConnection = connect(client ? { client } : {});
9440
- }
9441
- return this.deadboltConnection;
9442
- }
9443
- sessionAllows(url) {
9444
- const patterns = this.deps.allowedOrigins();
9445
- return !patterns || patterns.length === 0 || checkUrl(url, parseOriginPatterns(patterns)).allowed;
9446
- }
9447
- async typeDeadbolt(handles, spec, field, label) {
9448
- if (!["username", "password", "totp"].includes(field))
9449
- throw new Error(`${label}: field must be "username", "password" or "totp"`);
9450
- if (handles.length === 0)
9451
- throw new Error(`${label}: target_not_editable: no field to type into`);
9452
- if (field !== "username")
9453
- this.refuseWithPageHooks(label);
9454
- const frame = await handles[0].ownerFrame();
9455
- if (!frame)
9456
- throw new Error(`${label}: target_not_editable: the field is not in a frame`);
9457
- for (const handle of handles.slice(1)) {
9458
- if (await handle.ownerFrame() !== frame)
9459
- throw new Error(`${label}: target_not_editable: the code boxes are in different frames`);
9460
- }
9461
- const checkOrigin = () => {
9462
- const url = frame.url();
9463
- const origin = frameOrigin(url);
9464
- if (isOpaqueDocumentUrl(url) || !originOnSite(origin, spec.site)) {
9465
- throw new Error(`${label}: domain_not_allowed: the field's frame is ${origin}, which is not on ${spec.site}. Nothing was typed.`);
9466
- }
9467
- if (!this.sessionAllows(url)) {
9468
- throw new Error(`${label}: domain_not_allowed: the field's frame is ${origin}, which is outside this session's domain allowlist. Nothing was typed.`);
9469
- }
9470
- return origin;
9471
- };
9472
- const origin = checkOrigin();
9473
- for (const handle of handles) {
9474
- if (!await handle.isEditable().catch(() => false))
9475
- throw new Error(`${label}: target_not_editable: the target is not an editable field. Nothing was typed.`);
9476
- }
9477
- const connection = this.deadbolt();
9478
- const login = pickLogin(await connection.logins(origin), spec.site, spec.username, field);
9479
- const values = await connection.fill(origin, login, [field]);
9480
- const value = values[field];
9481
- if (!value)
9482
- throw new DeadboltError("not_found", `The Deadbolt login for ${spec.site} has no ${field}.`);
9483
- const name = `deadbolt:${spec.site}${login.username ? `/${login.username}` : ""} ${field}`;
9484
- if (field !== "username") {
9485
- this.typedSecrets.set(value, name);
9486
- this.deps.networkCapture.addRedaction(value);
9487
- }
9488
- const characters = handles.length === 1 ? [value] : Array.from(value);
9489
- if (handles.length > 1 && characters.length !== handles.length) {
9490
- throw new Error(`${label}: target_not_editable: ${handles.length} code boxes for a ${characters.length}-character code. Nothing was typed.`);
9491
- }
9492
- for (const [index, handle] of handles.entries()) {
9493
- await handle.fill("");
9494
- await handle.focus();
9495
- if (!await elementHasFocus(handle)) {
9496
- throw new Error(`${label}: target_not_editable: the field did not keep focus.`);
9497
- }
9498
- checkOrigin();
9499
- await frame.page().keyboard.insertText(characters[index]);
9500
- }
9501
- if (!this.deps.allowedOrigins()?.length) {
9502
- this.deps.addWarningOnce(`A Deadbolt login was typed in a session without a domain allowlist. A prompt-injected page could steer this session elsewhere after the value is in the page: set one with session_allowlist (or \`session allow\`) before signing in.`);
9503
- }
9504
- return { origin, login };
9505
- }
9506
- async typeDeadboltSecret(page, target, name, spec, options) {
9507
- const field = options.field ?? "password";
9508
- if (field !== "username" && options.submit !== true) {
9509
- throw new Error(`secrets.type: submit_required: a Deadbolt ${field} is typed only with { submit: true }, which submits the form in the same call and clears the field afterwards. Prefer secrets.signIn(). Nothing was typed.`);
9510
- }
9511
- const locator = typeof target === "string" ? page.locator(target) : target;
9512
- if (!locator || typeof locator.elementHandle !== "function") {
9513
- throw new Error("secrets.type(target, name): target must be a selector string or a Locator");
9514
- }
9515
- const handle = await locator.elementHandle({ timeout: options.timeout ?? 1e4 });
9516
- const frame = await handle.ownerFrame();
9517
- let typed = false;
9518
- try {
9519
- const { origin } = await this.typeDeadbolt([handle], spec, field, "secrets.type").catch((error) => {
9520
- if (error instanceof DeadboltError)
9521
- throw new Error(`secrets.type: ${error.code}: ${error.message} Nothing was typed.`);
9522
- throw error;
9523
- });
9524
- typed = true;
9525
- if (options.submit !== true)
9526
- return { typed: true, name, origin, field };
9527
- const submitControl = await handle.evaluateHandle((node) => {
9528
- const form = node.form;
9529
- if (!form)
9530
- return null;
9531
- return form.querySelector("button[type=submit], input[type=submit], button:not([type])");
9532
- });
9533
- const button = submitControl.asElement();
9534
- if (button)
9535
- await button.click({ timeout: 5000 }).catch(() => handle.press("Enter"));
9536
- else
9537
- await handle.press("Enter");
9538
- const progressed = await waitForProgress(frame?.page() ?? page, handle, 15000);
9539
- return { typed: true, name, origin, field, submitted: true, progressed };
9540
- } finally {
9541
- if (typed && field !== "username")
9542
- await clearSecretInputs(frame ? [frame] : [], [handle]);
9543
- await handle.dispose().catch(() => {});
9544
- }
9545
- }
9546
- async usePasskey(page, options) {
9547
- const site = typeof options?.site === "string" ? options.site.trim().toLowerCase() : "";
9548
- const username = typeof options?.username === "string" ? options.username.trim() : "";
9549
- if (!site || !username)
9550
- throw new Error("secrets.usePasskey({ site, username }): site and username are required");
9551
- if (!this.deps.passkeys)
9552
- throw new Error("secrets.usePasskey: passkeys aren't available in this relay");
9553
- this.deps.passkeys.select(await pageTargetId(page), site, username);
9554
- return { selected: true, site, username };
9555
- }
9556
- async signIn(page, options = {}) {
9557
- if (options !== null && typeof options !== "object")
9558
- throw new Error("secrets.signIn(options): options must be an object like { site, username }");
9559
- const site = typeof options?.site === "string" ? options.site : undefined;
9560
- const username = typeof options?.username === "string" ? options.username : undefined;
9561
- const timeoutMs = typeof options?.timeoutMs === "number" && options.timeoutMs > 0 ? Math.min(options.timeoutMs, 300000) : undefined;
9562
- return await signIn({
9563
- page,
9564
- context: page.context(),
9565
- type: async (handles, spec, field) => (await this.typeDeadbolt(handles, spec, field, "secrets.signIn")).login,
9566
- logins: (origin) => this.deadbolt().logins(origin),
9567
- passkeyAccounts: async (origin) => (await this.deadbolt().site(origin)).passkeys,
9568
- challenge: async (target) => {
9569
- const outcome = await detectChallenge(target, { waitMs: challengeWaitMs() }).catch(() => {
9570
- return;
9571
- });
9572
- return outcome && outcome.status === "blocked" ? outcome : undefined;
9573
- },
9574
- allowed: (url) => this.sessionAllows(url),
9575
- ...this.deps.passkeys ? {
9576
- passkeys: {
9577
- select: async (target, passkeySite, passkeyUsername) => this.deps.passkeys.select(await pageTargetId(target), passkeySite, passkeyUsername),
9578
- choiceSince: async (target, since) => this.deps.passkeys.choiceSince(await pageTargetId(target), since)
9579
- }
9580
- } : {}
9581
- }, { ...site ? { site } : {}, ...username ? { username } : {}, ...timeoutMs ? { timeoutMs } : {} });
9582
- }
9583
8856
  }
9584
8857
 
9585
8858
  // src/network-capture.ts
@@ -10475,7 +9748,6 @@ class ExecuteSandbox extends DefaultPageHost {
10475
9748
  this.secrets = new ExecuteSecretsBridge({
10476
9749
  networkCapture: this.networkCapture,
10477
9750
  allowedOrigins: () => this.options.allowedOrigins?.(),
10478
- ...this.options.passkeys ? { passkeys: this.options.passkeys } : {},
10479
9751
  addWarningOnce: (warning) => this.addWarningOnce(warning)
10480
9752
  });
10481
9753
  this.realm = this.allowNode ? undefined : this.createRealm();
@@ -10488,9 +9760,6 @@ class ExecuteSandbox extends DefaultPageHost {
10488
9760
  return new ExecuteRealm({
10489
9761
  onHostCall: (fn, receiver, args) => {
10490
9762
  this.addWarningOnce(pageVisibleApiWarning(fn, receiver, args));
10491
- const hook = pageHookCall(fn, args);
10492
- if (hook)
10493
- this.secrets.pageHooks.add(hook);
10494
9763
  }
10495
9764
  });
10496
9765
  }
@@ -10640,7 +9909,6 @@ class ExecuteSandbox extends DefaultPageHost {
10640
9909
  sandbox.realm?.dispose();
10641
9910
  sandbox.realm = sandbox.allowNode ? undefined : sandbox.createRealm();
10642
9911
  sandbox.state = sandbox.realm?.state ?? {};
10643
- sandbox.secrets.pageHooks.clear();
10644
9912
  const browser = sandbox.browser;
10645
9913
  sandbox.browser = undefined;
10646
9914
  sandbox.unbindDefaultPage(sandbox.defaultPageTargetId, {
@@ -10946,36 +10214,36 @@ function unsignedInteger(value) {
10946
10214
  }
10947
10215
  return Buffer.from(bytes);
10948
10216
  }
10949
- function element2(id, payload) {
10217
+ function element(id, payload) {
10950
10218
  return Buffer.concat([id, variableInteger(payload.length), payload]);
10951
10219
  }
10952
10220
  function mjpegMatroskaHeader(width, height) {
10953
- const ebmlHeader = element2(ebml, Buffer.concat([
10954
- element2(ebmlVersion, unsignedInteger(1)),
10955
- element2(ebmlReadVersion, unsignedInteger(1)),
10956
- element2(ebmlMaxIdLength, unsignedInteger(4)),
10957
- element2(ebmlMaxSizeLength, unsignedInteger(8)),
10958
- element2(docType, Buffer.from("matroska")),
10959
- element2(docTypeVersion, unsignedInteger(4)),
10960
- element2(docTypeReadVersion, unsignedInteger(2))
10221
+ const ebmlHeader = element(ebml, Buffer.concat([
10222
+ element(ebmlVersion, unsignedInteger(1)),
10223
+ element(ebmlReadVersion, unsignedInteger(1)),
10224
+ element(ebmlMaxIdLength, unsignedInteger(4)),
10225
+ element(ebmlMaxSizeLength, unsignedInteger(8)),
10226
+ element(docType, Buffer.from("matroska")),
10227
+ element(docTypeVersion, unsignedInteger(4)),
10228
+ element(docTypeReadVersion, unsignedInteger(2))
10961
10229
  ]));
10962
- const streamInfo = element2(info, Buffer.concat([
10963
- element2(timestampScale, unsignedInteger(1e6)),
10964
- element2(muxingApp, Buffer.from("opencode-browser")),
10965
- element2(writingApp, Buffer.from("opencode-browser"))
10230
+ const streamInfo = element(info, Buffer.concat([
10231
+ element(timestampScale, unsignedInteger(1e6)),
10232
+ element(muxingApp, Buffer.from("opencode-browser")),
10233
+ element(writingApp, Buffer.from("opencode-browser"))
10966
10234
  ]));
10967
- const track = element2(trackEntry, Buffer.concat([
10968
- element2(trackNumber, unsignedInteger(1)),
10969
- element2(trackUid, unsignedInteger(1)),
10970
- element2(trackType, unsignedInteger(1)),
10971
- element2(flagLacing, unsignedInteger(0)),
10972
- element2(codecId, Buffer.from("V_MJPEG")),
10973
- element2(video, Buffer.concat([
10974
- element2(pixelWidth, unsignedInteger(width)),
10975
- element2(pixelHeight, unsignedInteger(height))
10235
+ const track = element(trackEntry, Buffer.concat([
10236
+ element(trackNumber, unsignedInteger(1)),
10237
+ element(trackUid, unsignedInteger(1)),
10238
+ element(trackType, unsignedInteger(1)),
10239
+ element(flagLacing, unsignedInteger(0)),
10240
+ element(codecId, Buffer.from("V_MJPEG")),
10241
+ element(video, Buffer.concat([
10242
+ element(pixelWidth, unsignedInteger(width)),
10243
+ element(pixelHeight, unsignedInteger(height))
10976
10244
  ]))
10977
10245
  ]));
10978
- return Buffer.concat([ebmlHeader, segment, unknownSize, streamInfo, element2(tracks, track)]);
10246
+ return Buffer.concat([ebmlHeader, segment, unknownSize, streamInfo, element(tracks, track)]);
10979
10247
  }
10980
10248
  function mjpegMatroskaFrame(timestampMs, durationMs, frameLength) {
10981
10249
  const blockHeader = Buffer.concat([
@@ -10985,8 +10253,8 @@ function mjpegMatroskaFrame(timestampMs, durationMs, frameLength) {
10985
10253
  Buffer.from([0, 0]),
10986
10254
  Buffer.from([0])
10987
10255
  ]);
10988
- const clusterTimestamp = element2(timestamp, unsignedInteger(timestampMs));
10989
- const duration = element2(blockDuration, unsignedInteger(Math.max(1, durationMs)));
10256
+ const clusterTimestamp = element(timestamp, unsignedInteger(timestampMs));
10257
+ const duration = element(blockDuration, unsignedInteger(Math.max(1, durationMs)));
10990
10258
  const groupHeader = Buffer.concat([
10991
10259
  blockGroup,
10992
10260
  variableInteger(blockHeader.length + frameLength + duration.length),
@@ -14330,28 +13598,6 @@ function handleAuthRequest(options) {
14330
13598
  }
14331
13599
  function handleCliRequest(options) {
14332
13600
  return Effect22.gen(function* () {
14333
- if (options.pathname === "/cli/deadbolt/logins" && options.request.method === "POST") {
14334
- const request = yield* decodeRequest(DeadboltLoginsRequest, yield* readJsonBody2(options.request), "deadbolt logins");
14335
- const sessionId = request.sessionId;
14336
- const patterns = sessionId ? options.sessions.allowedOrigins(sessionId) : undefined;
14337
- const pageOrigins = options.registry.listRootTargets().filter((target) => sessionId !== undefined && target.opencodeBrowserSessionId === sessionId).flatMap((target) => {
14338
- try {
14339
- const url = new URL(target.targetInfo.url);
14340
- const allowed = !patterns || patterns.length === 0 || checkUrl(url.href, parseOriginPatterns(patterns)).allowed;
14341
- return (url.protocol === "https:" || url.protocol === "http:") && allowed ? [url.origin] : [];
14342
- } catch {
14343
- return [];
14344
- }
14345
- });
14346
- const origins = Array.from(new Set([...patterns && patterns.length > 0 ? originsFromPatterns(patterns) : [], ...pageOrigins]));
14347
- const listing = yield* Effect22.promise(() => listLogins(origins));
14348
- sendJson2(options.response, {
14349
- ...listing,
14350
- origins,
14351
- ...patterns && patterns.length > 0 ? {} : { note: "This session has no domain allowlist, so only the sites of its open pages were checked. Set one with session_allowlist to see the logins for the sites it may visit." }
14352
- });
14353
- return;
14354
- }
14355
13601
  if (options.pathname === "/cli/sessions" && options.request.method === "GET") {
14356
13602
  sendJson2(options.response, { sessions: options.sessions.listSummaries() });
14357
13603
  return;
@@ -14831,285 +14077,6 @@ async function paceKey(tab, params) {
14831
14077
  tab.lastKeyAt = Date.now();
14832
14078
  }
14833
14079
 
14834
- // src/auth/passkey-bridge.ts
14835
- var selectionTtlMs = 2 * 60000;
14836
- var maxPayloadBytes = 64 * 1024;
14837
- function hookSource(binding, reply) {
14838
- return `(() => {
14839
- const BINDING = ${JSON.stringify(binding)};
14840
- const REPLY = ${JSON.stringify(reply)};
14841
- // Chrome adds a binding only to the documents that exist when it is added (without Runtime.enable, which pages can
14842
- // detect), so the relay adds it again after every navigation. Take it off the global object as soon as it shows up.
14843
- let send = null;
14844
- const capture = () => {
14845
- if (send) return send;
14846
- const binding = globalThis[BINDING];
14847
- if (typeof binding === "function") {
14848
- send = binding;
14849
- try { delete globalThis[BINDING]; } catch {}
14850
- }
14851
- return send;
14852
- };
14853
- capture();
14854
- document.addEventListener("readystatechange", capture);
14855
- if (window !== window.top) return;
14856
- const container = globalThis.CredentialsContainer && CredentialsContainer.prototype;
14857
- if (!container || typeof container.get !== "function" || globalThis[REPLY]) return;
14858
- const originalGet = container.get;
14859
- const pending = new Map();
14860
- let nextId = 1;
14861
- const toBytes = (value) => value instanceof ArrayBuffer ? new Uint8Array(value) : ArrayBuffer.isView(value) ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength) : null;
14862
- const encode = (value) => {
14863
- const bytes = toBytes(value);
14864
- if (!bytes) return null;
14865
- let text = "";
14866
- for (const byte of bytes) text += String.fromCharCode(byte);
14867
- return btoa(text).replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/, "");
14868
- };
14869
- const decode = (text) => {
14870
- const binary = atob(text.replace(/-/g, "+").replace(/_/g, "/") + "===".slice((text.length + 3) % 4));
14871
- const bytes = new Uint8Array(binary.length);
14872
- for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
14873
- return bytes.buffer;
14874
- };
14875
- const assertion = (result) => {
14876
- const value = (v) => ({ value: v, enumerable: true });
14877
- const response = Object.create(AuthenticatorAssertionResponse.prototype, {
14878
- clientDataJSON: value(decode(result.client_data_json)),
14879
- authenticatorData: value(decode(result.authenticator_data)),
14880
- signature: value(decode(result.signature)),
14881
- userHandle: value(result.user_handle ? decode(result.user_handle) : null),
14882
- });
14883
- const json = {
14884
- id: result.credential_id, rawId: result.credential_id, type: "public-key", authenticatorAttachment: "platform",
14885
- response: { clientDataJSON: result.client_data_json, authenticatorData: result.authenticator_data, signature: result.signature, ...(result.user_handle ? { userHandle: result.user_handle } : {}) },
14886
- clientExtensionResults: {},
14887
- };
14888
- return Object.create(PublicKeyCredential.prototype, {
14889
- id: value(result.credential_id),
14890
- rawId: value(decode(result.credential_id)),
14891
- type: value("public-key"),
14892
- authenticatorAttachment: value("platform"),
14893
- response: value(response),
14894
- getClientExtensionResults: { value: () => ({}) },
14895
- toJSON: { value: () => json },
14896
- });
14897
- };
14898
- Object.defineProperty(globalThis, REPLY, {
14899
- value: (id, result) => {
14900
- const entry = pending.get(id);
14901
- if (!entry) return;
14902
- pending.delete(id);
14903
- if (result && result.ok) {
14904
- try { entry.resolve(assertion(result.assertion)); } catch (error) { entry.reject(new DOMException("The passkey answer was malformed.", "NotAllowedError")); }
14905
- } else {
14906
- entry.reject(new DOMException("The operation either timed out or was not allowed.", "NotAllowedError"));
14907
- }
14908
- },
14909
- });
14910
- const get = { get(options) {
14911
- const publicKey = options && options.publicKey;
14912
- if (!publicKey || options.mediation === "conditional" || options.password || options.federated || options.identity || options.otp) return originalGet.call(this, options);
14913
- const challenge = encode(publicKey.challenge);
14914
- if (!challenge) return Promise.reject(new TypeError("publicKey.challenge must be a BufferSource"));
14915
- const allowCredentials = Array.isArray(publicKey.allowCredentials) ? publicKey.allowCredentials.map((credential) => encode(credential && credential.id)).filter(Boolean) : [];
14916
- const signal = options.signal;
14917
- if (signal && signal.aborted) return Promise.reject(signal.reason ?? new DOMException("The operation was aborted.", "AbortError"));
14918
- return new Promise(async (resolve, reject) => {
14919
- const id = nextId++;
14920
- pending.set(id, { resolve, reject });
14921
- if (signal) signal.addEventListener("abort", () => { if (pending.delete(id)) reject(signal.reason ?? new DOMException("The operation was aborted.", "AbortError")); }, { once: true });
14922
- for (let tries = 0; tries < 60 && !capture(); tries++) await new Promise((wake) => setTimeout(wake, 50));
14923
- if (!send) {
14924
- pending.delete(id);
14925
- return reject(new DOMException("The operation either timed out or was not allowed.", "NotAllowedError"));
14926
- }
14927
- send(JSON.stringify({ id, challenge, rpId: typeof publicKey.rpId === "string" ? publicKey.rpId : undefined, allowCredentials, userVerification: typeof publicKey.userVerification === "string" ? publicKey.userVerification : "preferred" }));
14928
- });
14929
- } }.get;
14930
- Object.defineProperty(container, "get", { value: get, writable: true, configurable: true, enumerable: true });
14931
- })();`;
14932
- }
14933
- function parsePasskeyRequest(payload) {
14934
- if (typeof payload !== "string" || payload.length > maxPayloadBytes)
14935
- return;
14936
- let value;
14937
- try {
14938
- value = JSON.parse(payload);
14939
- } catch {
14940
- return;
14941
- }
14942
- if (!value || typeof value !== "object")
14943
- return;
14944
- const { id, challenge, rpId, allowCredentials, userVerification } = value;
14945
- if (typeof id !== "number" || !Number.isSafeInteger(id) || id < 1)
14946
- return;
14947
- if (!isBase64Url(challenge, 1024) || challenge.length < 16)
14948
- return;
14949
- if (rpId !== undefined && (typeof rpId !== "string" || rpId.length > 253 || !/^[a-z0-9.-]+$/i.test(rpId)))
14950
- return;
14951
- if (!Array.isArray(allowCredentials) || allowCredentials.length > 64 || !allowCredentials.every((entry) => isBase64Url(entry, 1400)))
14952
- return;
14953
- const verification = typeof userVerification === "string" && ["required", "preferred", "discouraged"].includes(userVerification) ? userVerification : "preferred";
14954
- return { id, challenge, ...rpId ? { rpId: rpId.toLowerCase() } : {}, allowCredentials, userVerification: verification };
14955
- }
14956
- function rpIdAllowed(origin, rpId) {
14957
- let url;
14958
- try {
14959
- url = new URL(origin);
14960
- } catch {
14961
- return false;
14962
- }
14963
- const host = url.hostname.toLowerCase();
14964
- const secure = url.protocol === "https:" || url.protocol === "http:" && (host === "localhost" || host.endsWith(".localhost") || /^127\.\d+\.\d+\.\d+$/.test(host) || host === "[::1]");
14965
- if (!secure)
14966
- return false;
14967
- if (rpId === undefined)
14968
- return true;
14969
- return host === rpId || rpId.includes(".") && host.endsWith(`.${rpId}`);
14970
- }
14971
-
14972
- class PasskeyBridge {
14973
- installs = new Map;
14974
- selections = new Map;
14975
- choices = new Map;
14976
- options;
14977
- constructor(options) {
14978
- this.options = options;
14979
- }
14980
- async install(tabId) {
14981
- const connected = this.options.connected ?? (() => readClient() !== undefined);
14982
- if (!connected())
14983
- return false;
14984
- const install = { binding: randomName("__b"), reply: randomName("__r") };
14985
- this.installs.set(tabId, install);
14986
- try {
14987
- await this.options.send(tabId, "Runtime.addBinding", { name: install.binding });
14988
- await this.options.send(tabId, "Page.addScriptToEvaluateOnNewDocument", { source: hookSource(install.binding, install.reply), runImmediately: true });
14989
- this.options.log?.("passkey.install", { tabId });
14990
- return true;
14991
- } catch (error) {
14992
- this.installs.delete(tabId);
14993
- this.options.log?.("passkey.install.failed", { tabId, error: error instanceof Error ? error.message : String(error) });
14994
- return false;
14995
- }
14996
- }
14997
- navigated(tabId) {
14998
- const install = this.installs.get(tabId);
14999
- if (!install)
15000
- return;
15001
- this.options.send(tabId, "Runtime.addBinding", { name: install.binding }).catch(() => {});
15002
- }
15003
- select(tabId, site, username, now = Date.now()) {
15004
- this.selections.set(tabId, { site, username, expiresAt: now + selectionTtlMs });
15005
- }
15006
- clearSelection(tabId) {
15007
- this.selections.delete(tabId);
15008
- }
15009
- choiceSince(tabId, since) {
15010
- const event = this.choices.get(tabId);
15011
- return event && event.at >= since ? event.choices : undefined;
15012
- }
15013
- forget(tabId) {
15014
- this.installs.delete(tabId);
15015
- this.selections.delete(tabId);
15016
- this.choices.delete(tabId);
15017
- }
15018
- handleEvent(tabId, method, params, fromRoot) {
15019
- if (method !== "Runtime.bindingCalled")
15020
- return false;
15021
- const install = this.installs.get(tabId);
15022
- if (!install || params?.name !== install.binding)
15023
- return false;
15024
- this.options.log?.("passkey.request", { tabId, fromRoot });
15025
- if (!fromRoot)
15026
- return true;
15027
- const contextId = params.executionContextId;
15028
- if (typeof contextId !== "number")
15029
- return true;
15030
- this.answer(tabId, install, contextId, params.payload);
15031
- return true;
15032
- }
15033
- async answer(tabId, install, contextId, payload) {
15034
- const request = parsePasskeyRequest(payload);
15035
- if (!request) {
15036
- this.options.log?.("passkey.refused", { tabId, reason: "malformed request" });
15037
- return;
15038
- }
15039
- let result;
15040
- try {
15041
- result = { ok: true, assertion: await this.assert(tabId, contextId, request) };
15042
- this.options.log?.("passkey.signed", { tabId });
15043
- } catch (error) {
15044
- result = { ok: false };
15045
- this.options.log?.("passkey.refused", { tabId, reason: error instanceof DeadboltError ? error.code : error instanceof Error ? error.message : "failed" });
15046
- }
15047
- await this.options.send(tabId, "Runtime.evaluate", {
15048
- expression: `globalThis[${JSON.stringify(install.reply)}]?.(${request.id}, ${JSON.stringify(result)})`,
15049
- contextId,
15050
- returnByValue: true
15051
- }).catch(() => {});
15052
- }
15053
- async assert(tabId, contextId, request) {
15054
- const top = await this.options.send(tabId, "Runtime.evaluate", { expression: "window === top", contextId, returnByValue: true });
15055
- if (top.result?.value !== true)
15056
- throw new Error("not the top frame");
15057
- const tree = await this.options.send(tabId, "Page.getFrameTree", {});
15058
- const frame = tree.frameTree?.frame;
15059
- const url = typeof frame?.url === "string" ? frame.url : "";
15060
- let origin = typeof frame?.securityOrigin === "string" ? frame.securityOrigin : "";
15061
- try {
15062
- if (!origin || origin === "null")
15063
- origin = new URL(url).origin;
15064
- } catch {
15065
- throw new Error("no origin");
15066
- }
15067
- if (!rpIdAllowed(origin, request.rpId))
15068
- throw new Error("rpId not allowed for the origin");
15069
- const patterns = this.options.allowedOrigins(tabId);
15070
- if (patterns && patterns.length > 0 && !checkUrl(url, parseOriginPatterns(patterns)).allowed)
15071
- throw new Error("outside the session allowlist");
15072
- const deadbolt = (this.options.deadbolt ?? (() => connect()))();
15073
- const selection = this.selections.get(tabId);
15074
- this.selections.delete(tabId);
15075
- let login;
15076
- if (selection && selection.expiresAt >= Date.now() && originOnSite(origin, selection.site)) {
15077
- const passkey = pickPasskey((await deadbolt.site(origin)).passkeys, selection.username);
15078
- if (!passkey)
15079
- throw new DeadboltError("not_granted", `No granted passkey for ${selection.username} on ${selection.site}`);
15080
- login = passkey.ref;
15081
- }
15082
- const assertion = await deadbolt.passkeyGet({
15083
- origin,
15084
- ...request.rpId ? { rpId: request.rpId } : {},
15085
- challenge: request.challenge,
15086
- allowCredentials: request.allowCredentials,
15087
- userVerification: request.userVerification,
15088
- ...login !== undefined ? { login } : {}
15089
- }).catch((error) => {
15090
- if (error instanceof DeadboltError && error.code === "choose_passkey") {
15091
- const offered = (error.detail.choices ?? []).map((choice) => ({
15092
- ...choice.username ? { username: choice.username } : {},
15093
- ...choice.displayName ? { displayName: choice.displayName } : {}
15094
- }));
15095
- this.choices.set(tabId, { at: Date.now(), choices: offered });
15096
- }
15097
- throw error;
15098
- });
15099
- for (const value of [assertion.credentialId, assertion.clientDataJson, assertion.authenticatorData, assertion.signature, assertion.userHandle ?? ""]) {
15100
- if (!isBase64Url(value, 16384))
15101
- throw new Error("Deadbolt's assertion isn't base64url");
15102
- }
15103
- return {
15104
- credential_id: assertion.credentialId,
15105
- client_data_json: assertion.clientDataJson,
15106
- authenticator_data: assertion.authenticatorData,
15107
- signature: assertion.signature,
15108
- ...assertion.userHandle ? { user_handle: assertion.userHandle } : {}
15109
- };
15110
- }
15111
- }
15112
-
15113
14080
  // src/cdp/protected-frames.ts
15114
14081
  import { Predicate as Predicate18 } from "effect";
15115
14082
  var navigationIntentMethods = new Set(["Page.frameRequestedNavigation", "Page.frameScheduledNavigation", "Page.frameStartedNavigating"]);
@@ -15353,7 +14320,7 @@ function guardCdpMethod(context) {
15353
14320
  return `browse blocked ${context.method}: ${reason}. This command is always blocked by the relay.`;
15354
14321
  }
15355
14322
  if (context.method.startsWith("WebAuthn.")) {
15356
- return `browse blocked ${context.method}: agents can't drive WebAuthn or add virtual authenticators. Passkey sign-ins in agent tabs use the logins the user granted in Deadbolt. This command is always blocked by the relay.`;
14323
+ return `browse blocked ${context.method}: agents can't drive WebAuthn or add virtual authenticators. This command is always blocked by the relay.`;
15357
14324
  }
15358
14325
  if (context.method === "Page.bringToFront" && !allowsForeground()) {
15359
14326
  return "browse blocked Page.bringToFront: it raises the user's browser window over their work. Use handoff() when the user needs to act in the tab, or set OPENCODE_BROWSER_ALLOW_FOREGROUND=1 on the relay to allow it.";
@@ -16006,7 +14973,6 @@ function createExtensionEventHandler(options) {
16006
14973
  handoffs,
16007
14974
  recordingRelay,
16008
14975
  flightRecorder,
16009
- passkeys,
16010
14976
  navigationGuard,
16011
14977
  ghostCursor,
16012
14978
  tabActivity,
@@ -16315,8 +15281,6 @@ function createExtensionEventHandler(options) {
16315
15281
  if (sourceSessionId && method !== "Target.attachedToTarget" && method !== "Target.detachedFromTarget" && method !== "Target.targetInfoChanged" && (suppressedChildSessions.has(sourceSessionId) || sourceChild && !shouldExposeChildTarget(sourceChild))) {
16316
15282
  return;
16317
15283
  }
16318
- if (passkeys.handleEvent(tabId, method, params, sourceSessionId === undefined || sourceSessionId === target.sessionId))
16319
- return;
16320
15284
  if (flightRecorder.handleDebuggerEvent({ tabId, method, params }) || recordingRelay.handleDebuggerEvent({ tabId, method, params }))
16321
15285
  return;
16322
15286
  if (sourceSessionId === undefined || sourceSessionId === target.sessionId)
@@ -16449,7 +15413,6 @@ function createExtensionEventHandler(options) {
16449
15413
  Effect27.runPromise(Effect27.ignore(ghostCursor.documentCreated(tabId))).catch(() => {});
16450
15414
  contextDebugLog?.(`main-frame-navigated frame=${boundedToken(frameId)} loader=${boundedToken(getString2(frame, "loaderId"))} ${targetDiagnosticIdentity(registry, target)} ${summarizeDiagnosticUrl(frameUrl)}`);
16451
15415
  registry.updateTargetUrl(tabId, frameUrl);
16452
- passkeys.navigated(tabId);
16453
15416
  blankNavigationWaiters.get(tabId)?.(frameUrl, getString2(frame, "loaderId"));
16454
15417
  Effect27.runPromise(Effect27.ignore(sendDebuggerCommand({ tabId, method: "Emulation.setFocusEmulationEnabled", params: { enabled: tabActivity.isFocused(tabId) } }))).catch(() => {});
16455
15418
  }
@@ -17156,7 +16119,6 @@ function createTabPresentation(options) {
17156
16119
  registry,
17157
16120
  browsers,
17158
16121
  handoffs,
17159
- passkeys,
17160
16122
  tabActivity,
17161
16123
  mainFrameIdsByTab,
17162
16124
  sendToExtension,
@@ -17379,9 +16341,6 @@ function createTabPresentation(options) {
17379
16341
  if (committedTarget.opencodeBrowserSessionId) {
17380
16342
  pruneInvisibleAnnouncementsForSession(committedTarget.opencodeBrowserSessionId);
17381
16343
  }
17382
- if (committedTarget.owner === "relay" && committedTarget.opencodeBrowserSessionId) {
17383
- passkeys.install(tabId);
17384
- }
17385
16344
  if (browsers.browserTab(tabId)?.link.rpc.connected) {
17386
16345
  refreshTabGrouping(tabId);
17387
16346
  }
@@ -18148,9 +17107,8 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18148
17107
  const browserId = crypto10.randomUUID();
18149
17108
  const endpointUrl = `http://${formatHostForUrl2(host)}:${port}`;
18150
17109
  const additionalChromeExtensionOrigins = new Set(options.additionalExtensionOrigins ?? []);
18151
- const storeId = storeConfig().id;
18152
- if (storeId)
18153
- additionalChromeExtensionOrigins.add(`chrome-extension://${storeId}`);
17110
+ const storeId = storeConfig().id ?? PUBLIC_STORE_ID;
17111
+ additionalChromeExtensionOrigins.add(`chrome-extension://${storeId}`);
18154
17112
  const sessionCatalog = options.sessionCatalogPath === null ? undefined : new SessionCatalog(options.sessionCatalogPath ?? defaultSessionCatalogPath(port));
18155
17113
  let catalogWritesEnabled = false;
18156
17114
  const registry = new TargetRegistry;
@@ -18195,14 +17153,6 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18195
17153
  const handoffs = new HandoffRegistry;
18196
17154
  const ownersAcrossReconnect = new Map;
18197
17155
  const sweptBrowsers = new Set;
18198
- const passkeys = new PasskeyBridge({
18199
- send: (tabId, method, params) => Effect34.runPromise(sendDebuggerCommand({ tabId, method, params })),
18200
- allowedOrigins: (tabId) => {
18201
- const sessionId = registry.tabTargets.get(tabId)?.opencodeBrowserSessionId;
18202
- return sessionId ? sessions.allowedOrigins(sessionId) : undefined;
18203
- },
18204
- log: (event, fields) => relayLog(event, fields)
18205
- });
18206
17156
  const recordingRelay = new RecordingRelay({
18207
17157
  sendToExtension: (command) => Effect34.runPromise(sendToExtension(command)),
18208
17158
  sendDebuggerCommand: (command) => Effect34.runPromise(sendDebuggerCommand(command)),
@@ -18237,7 +17187,6 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18237
17187
  registry,
18238
17188
  browsers,
18239
17189
  handoffs,
18240
- passkeys,
18241
17190
  tabActivity,
18242
17191
  mainFrameIdsByTab,
18243
17192
  sendToExtension,
@@ -18304,22 +17253,6 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18304
17253
  onDefaultTargetChange,
18305
17254
  allowedOrigins: () => sessions.allowedOrigins(id),
18306
17255
  drainGuardWarnings: () => navigationGuard.drainWarnings(id),
18307
- passkeys: {
18308
- select: (targetId, site, username) => {
18309
- const target = registry.targetsByTargetId.get(targetId);
18310
- if (!target || !("owner" in target) || target.owner !== "relay" || target.opencodeBrowserSessionId !== id) {
18311
- throw new Error("secrets.usePasskey: passkeys are answered only in tabs this session opened");
18312
- }
18313
- if (username)
18314
- passkeys.select(target.tabId, site, username);
18315
- else
18316
- passkeys.clearSelection(target.tabId);
18317
- },
18318
- choiceSince: (targetId, since) => {
18319
- const target = registry.targetsByTargetId.get(targetId);
18320
- return target && target.opencodeBrowserSessionId === id ? passkeys.choiceSince(target.tabId, since) : undefined;
18321
- }
18322
- },
18323
17256
  isRecordingTarget: (targetId) => {
18324
17257
  const target = registry.targetsByTargetId.get(targetId);
18325
17258
  return target !== undefined && isTabRecorded(target.tabId);
@@ -18515,7 +17448,6 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18515
17448
  navigationGuard.forgetTab(tabId);
18516
17449
  ghostCursor.forget(tabId);
18517
17450
  forgetTab(tabId);
18518
- passkeys.forget(tabId);
18519
17451
  for (const [sessionId, childTabId] of suppressedChildSessions) {
18520
17452
  if (childTabId === tabId)
18521
17453
  suppressedChildSessions.delete(sessionId);
@@ -18596,7 +17528,6 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18596
17528
  handoffs,
18597
17529
  recordingRelay,
18598
17530
  flightRecorder,
18599
- passkeys,
18600
17531
  navigationGuard,
18601
17532
  ghostCursor,
18602
17533
  tabActivity,