Add Brave CDP automation, replace Oracle browser mode
Connects to user's running Brave via Chrome DevTools Protocol to automate ChatGPT interaction. Uses puppeteer-core to open a tab, send the prompt, wait for response, and extract the result. No cookies, no separate profiles, no copy/paste. Just connects to the browser where the user is already logged in. One-time setup: relaunch Brave with --remote-debugging-port=9222 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
273
node_modules/chromium-bidi/lib/cjs/bidiMapper/modules/session/SubscriptionManager.js
generated
vendored
Normal file
273
node_modules/chromium-bidi/lib/cjs/bidiMapper/modules/session/SubscriptionManager.js
generated
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
"use strict";
|
||||
/**
|
||||
* Copyright 2022 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SubscriptionManager = void 0;
|
||||
exports.cartesianProduct = cartesianProduct;
|
||||
exports.unrollEvents = unrollEvents;
|
||||
exports.difference = difference;
|
||||
const protocol_js_1 = require("../../../protocol/protocol.js");
|
||||
const uuid_js_1 = require("../../../utils/uuid.js");
|
||||
/**
|
||||
* Returns the cartesian product of the given arrays.
|
||||
*
|
||||
* Example:
|
||||
* cartesian([1, 2], ['a', 'b']); => [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
|
||||
*/
|
||||
function cartesianProduct(...a) {
|
||||
return a.reduce((a, b) => a.flatMap((d) => b.map((e) => [d, e].flat())));
|
||||
}
|
||||
/** Expands "AllEvents" events into atomic events. */
|
||||
function unrollEvents(events) {
|
||||
const allEvents = new Set();
|
||||
function addEvents(events) {
|
||||
for (const event of events) {
|
||||
allEvents.add(event);
|
||||
}
|
||||
}
|
||||
for (const event of events) {
|
||||
switch (event) {
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Bluetooth:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Bluetooth.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.BrowsingContext:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.BrowsingContext.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Input:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Input.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Log:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Log.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Network:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Network.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Script:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Script.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Speculation:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Speculation.EventNames));
|
||||
break;
|
||||
default:
|
||||
allEvents.add(event);
|
||||
}
|
||||
}
|
||||
return allEvents.values();
|
||||
}
|
||||
class SubscriptionManager {
|
||||
#subscriptions = [];
|
||||
#knownSubscriptionIds = new Set();
|
||||
#browsingContextStorage;
|
||||
constructor(browsingContextStorage) {
|
||||
this.#browsingContextStorage = browsingContextStorage;
|
||||
}
|
||||
getGoogChannelsSubscribedToEvent(eventName, contextId) {
|
||||
const googChannels = new Set();
|
||||
for (const subscription of this.#subscriptions) {
|
||||
if (this.#isSubscribedTo(subscription, eventName, contextId)) {
|
||||
googChannels.add(subscription.googChannel);
|
||||
}
|
||||
}
|
||||
return Array.from(googChannels);
|
||||
}
|
||||
getGoogChannelsSubscribedToEventGlobally(eventName) {
|
||||
const googChannels = new Set();
|
||||
for (const subscription of this.#subscriptions) {
|
||||
if (this.#isSubscribedTo(subscription, eventName)) {
|
||||
googChannels.add(subscription.googChannel);
|
||||
}
|
||||
}
|
||||
return Array.from(googChannels);
|
||||
}
|
||||
#isSubscribedTo(subscription, moduleOrEvent, browsingContextId) {
|
||||
let includesEvent = false;
|
||||
for (const eventName of subscription.eventNames) {
|
||||
// This also covers the `goog:cdp` case where
|
||||
// we don't unroll the event names
|
||||
if (
|
||||
// Event explicitly subscribed
|
||||
eventName === moduleOrEvent ||
|
||||
// Event subscribed via module
|
||||
eventName === moduleOrEvent.split('.').at(0) ||
|
||||
// Event explicitly subscribed compared to module
|
||||
eventName.split('.').at(0) === moduleOrEvent) {
|
||||
includesEvent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!includesEvent) {
|
||||
return false;
|
||||
}
|
||||
// user context subscription.
|
||||
if (subscription.userContextIds.size !== 0) {
|
||||
if (!browsingContextId) {
|
||||
return false;
|
||||
}
|
||||
const context = this.#browsingContextStorage.findContext(browsingContextId);
|
||||
if (!context) {
|
||||
return false;
|
||||
}
|
||||
return subscription.userContextIds.has(context.userContext);
|
||||
}
|
||||
// context subscription.
|
||||
if (subscription.topLevelTraversableIds.size !== 0) {
|
||||
if (!browsingContextId) {
|
||||
return false;
|
||||
}
|
||||
const topLevelContext = this.#browsingContextStorage.findTopLevelContextId(browsingContextId);
|
||||
return (topLevelContext !== null &&
|
||||
subscription.topLevelTraversableIds.has(topLevelContext));
|
||||
}
|
||||
// global subscription.
|
||||
return true;
|
||||
}
|
||||
isSubscribedTo(moduleOrEvent, contextId) {
|
||||
for (const subscription of this.#subscriptions) {
|
||||
if (this.#isSubscribedTo(subscription, moduleOrEvent, contextId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Subscribes to event in the given context and goog:channel.
|
||||
* @return {SubscriptionItem[]} List of
|
||||
* subscriptions. If the event is a whole module, it will return all the specific
|
||||
* events. If the contextId is null, it will return all the top-level contexts which were
|
||||
* not subscribed before the command.
|
||||
*/
|
||||
subscribe(eventNames, contextIds, userContextIds, googChannel) {
|
||||
// All the subscriptions are handled on the top-level contexts.
|
||||
const subscription = {
|
||||
id: (0, uuid_js_1.uuidv4)(),
|
||||
eventNames: new Set(unrollEvents(eventNames)),
|
||||
topLevelTraversableIds: new Set(contextIds.map((contextId) => {
|
||||
const topLevelContext = this.#browsingContextStorage.findTopLevelContextId(contextId);
|
||||
if (!topLevelContext) {
|
||||
throw new protocol_js_1.NoSuchFrameException(`Top-level navigable not found for context id ${contextId}`);
|
||||
}
|
||||
return topLevelContext;
|
||||
})),
|
||||
userContextIds: new Set(userContextIds),
|
||||
googChannel,
|
||||
};
|
||||
this.#subscriptions.push(subscription);
|
||||
this.#knownSubscriptionIds.add(subscription.id);
|
||||
return subscription;
|
||||
}
|
||||
/**
|
||||
* Unsubscribes atomically from all events in the given contexts and channel.
|
||||
*
|
||||
* This is a legacy spec branch to unsubscribe by attributes.
|
||||
*/
|
||||
unsubscribe(inputEventNames, googChannel) {
|
||||
const eventNames = new Set(unrollEvents(inputEventNames));
|
||||
const newSubscriptions = [];
|
||||
const eventsMatched = new Set();
|
||||
for (const subscription of this.#subscriptions) {
|
||||
if (subscription.googChannel !== googChannel) {
|
||||
newSubscriptions.push(subscription);
|
||||
continue;
|
||||
}
|
||||
// Skip user context subscriptions.
|
||||
if (subscription.userContextIds.size !== 0) {
|
||||
newSubscriptions.push(subscription);
|
||||
continue;
|
||||
}
|
||||
// Skip subscriptions when none of the event names match.
|
||||
if (intersection(subscription.eventNames, eventNames).size === 0) {
|
||||
newSubscriptions.push(subscription);
|
||||
continue;
|
||||
}
|
||||
// Skip non-global subscriptions.
|
||||
if (subscription.topLevelTraversableIds.size !== 0) {
|
||||
newSubscriptions.push(subscription);
|
||||
continue;
|
||||
}
|
||||
const subscriptionEventNames = new Set(subscription.eventNames);
|
||||
for (const eventName of eventNames) {
|
||||
if (subscriptionEventNames.has(eventName)) {
|
||||
eventsMatched.add(eventName);
|
||||
subscriptionEventNames.delete(eventName);
|
||||
}
|
||||
}
|
||||
if (subscriptionEventNames.size !== 0) {
|
||||
newSubscriptions.push({
|
||||
...subscription,
|
||||
eventNames: subscriptionEventNames,
|
||||
});
|
||||
}
|
||||
}
|
||||
// If some events did not match, it is an invalid request.
|
||||
if (!equal(eventsMatched, eventNames)) {
|
||||
throw new protocol_js_1.InvalidArgumentException('No subscription found');
|
||||
}
|
||||
// Committing the new subscriptions.
|
||||
this.#subscriptions = newSubscriptions;
|
||||
}
|
||||
/**
|
||||
* Unsubscribes by subscriptionId.
|
||||
*/
|
||||
unsubscribeById(subscriptionIds) {
|
||||
const subscriptionIdsSet = new Set(subscriptionIds);
|
||||
const unknownIds = difference(subscriptionIdsSet, this.#knownSubscriptionIds);
|
||||
if (unknownIds.size !== 0) {
|
||||
throw new protocol_js_1.InvalidArgumentException('No subscription found');
|
||||
}
|
||||
this.#subscriptions = this.#subscriptions.filter((subscription) => {
|
||||
return !subscriptionIdsSet.has(subscription.id);
|
||||
});
|
||||
this.#knownSubscriptionIds = difference(this.#knownSubscriptionIds, subscriptionIdsSet);
|
||||
}
|
||||
}
|
||||
exports.SubscriptionManager = SubscriptionManager;
|
||||
/**
|
||||
* Replace with Set.prototype.intersection once Node 20 is dropped.
|
||||
*/
|
||||
function intersection(setA, setB) {
|
||||
const result = new Set();
|
||||
for (const a of setA) {
|
||||
if (setB.has(a)) {
|
||||
result.add(a);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Replace with Set.prototype.difference once Node 20 is dropped.
|
||||
*/
|
||||
function difference(setA, setB) {
|
||||
const result = new Set();
|
||||
for (const a of setA) {
|
||||
if (!setB.has(a)) {
|
||||
result.add(a);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function equal(setA, setB) {
|
||||
if (setA.size !== setB.size) {
|
||||
return false;
|
||||
}
|
||||
for (const a of setA) {
|
||||
if (!setB.has(a)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//# sourceMappingURL=SubscriptionManager.js.map
|
||||
Reference in New Issue
Block a user