Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
160 lines
No EOL
5.1 KiB
Text
160 lines
No EOL
5.1 KiB
Text
/**
|
|
* @license
|
|
* Copyright 2017 Google Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
import { CallbackRegistry } from '../common/CallbackRegistry.js';
|
|
import { debug } from '../common/Debug.js';
|
|
import { ConnectionClosedError } from '../common/Errors.js';
|
|
import { EventEmitter } from '../common/EventEmitter.js';
|
|
import { debugError } from '../common/util.js';
|
|
import { BidiCdpSession } from './CDPSession.js';
|
|
const debugProtocolSend = debug('puppeteer:webDriverBiDi:SEND ►');
|
|
const debugProtocolReceive = debug('puppeteer:webDriverBiDi:RECV ◀');
|
|
/**
|
|
* @internal
|
|
*/
|
|
export class BidiConnection extends EventEmitter {
|
|
#url;
|
|
#transport;
|
|
#delay;
|
|
#timeout = 0;
|
|
#closed = false;
|
|
#callbacks;
|
|
#emitters = [];
|
|
constructor(url, transport, idGenerator, delay = 0, timeout) {
|
|
super();
|
|
this.#url = url;
|
|
this.#delay = delay;
|
|
this.#timeout = timeout ?? 180_000;
|
|
this.#callbacks = new CallbackRegistry(idGenerator);
|
|
this.#transport = transport;
|
|
this.#transport.onmessage = this.onMessage.bind(this);
|
|
this.#transport.onclose = this.unbind.bind(this);
|
|
}
|
|
get closed() {
|
|
return this.#closed;
|
|
}
|
|
get url() {
|
|
return this.#url;
|
|
}
|
|
pipeTo(emitter) {
|
|
this.#emitters.push(emitter);
|
|
}
|
|
#toWebDriverOnlyEvent(event) {
|
|
for (const key in event) {
|
|
if (key.startsWith('goog:')) {
|
|
delete event[key];
|
|
}
|
|
else {
|
|
if (typeof event[key] === 'object' && event[key] !== null) {
|
|
this.#toWebDriverOnlyEvent(event[key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
emit(type, event) {
|
|
if (process.env['PUPPETEER_WEBDRIVER_BIDI_ONLY'] === 'true') {
|
|
// Required for WebDriver-only testing.
|
|
this.#toWebDriverOnlyEvent(event);
|
|
}
|
|
for (const emitter of this.#emitters) {
|
|
emitter.emit(type, event);
|
|
}
|
|
return super.emit(type, event);
|
|
}
|
|
send(method, params, timeout) {
|
|
if (this.#closed) {
|
|
return Promise.reject(new ConnectionClosedError('Connection closed.'));
|
|
}
|
|
return this.#callbacks.create(method, timeout ?? this.#timeout, id => {
|
|
const stringifiedMessage = JSON.stringify({
|
|
id,
|
|
method,
|
|
params,
|
|
});
|
|
debugProtocolSend(stringifiedMessage);
|
|
this.#transport.send(stringifiedMessage);
|
|
});
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
async onMessage(message) {
|
|
if (this.#delay) {
|
|
await new Promise(f => {
|
|
return setTimeout(f, this.#delay);
|
|
});
|
|
}
|
|
debugProtocolReceive(message);
|
|
const object = JSON.parse(message);
|
|
if ('type' in object) {
|
|
switch (object.type) {
|
|
case 'success':
|
|
this.#callbacks.resolve(object.id, object);
|
|
return;
|
|
case 'error':
|
|
if (object.id === null) {
|
|
break;
|
|
}
|
|
this.#callbacks.reject(object.id, createProtocolError(object), `${object.error}: ${object.message}`);
|
|
return;
|
|
case 'event':
|
|
if (isCdpEvent(object)) {
|
|
BidiCdpSession.sessions
|
|
.get(object.params.session)
|
|
?.emit(object.params.event, object.params.params);
|
|
return;
|
|
}
|
|
// SAFETY: We know the method and parameter still match here.
|
|
this.emit(object.method, object.params);
|
|
return;
|
|
}
|
|
}
|
|
// Even if the response in not in BiDi protocol format but `id` is provided, reject
|
|
// the callback. This can happen if the endpoint supports CDP instead of BiDi.
|
|
if ('id' in object) {
|
|
this.#callbacks.reject(object.id, `Protocol Error. Message is not in BiDi protocol format: '${message}'`, object.message);
|
|
}
|
|
debugError(object);
|
|
}
|
|
/**
|
|
* Unbinds the connection, but keeps the transport open. Useful when the transport will
|
|
* be reused by other connection e.g. with different protocol.
|
|
* @internal
|
|
*/
|
|
unbind() {
|
|
if (this.#closed) {
|
|
return;
|
|
}
|
|
this.#closed = true;
|
|
// Both may still be invoked and produce errors
|
|
this.#transport.onmessage = () => { };
|
|
this.#transport.onclose = () => { };
|
|
this.#callbacks.clear();
|
|
}
|
|
/**
|
|
* Unbinds the connection and closes the transport.
|
|
*/
|
|
dispose() {
|
|
this.unbind();
|
|
this.#transport.close();
|
|
}
|
|
getPendingProtocolErrors() {
|
|
return this.#callbacks.getPendingProtocolErrors();
|
|
}
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
function createProtocolError(object) {
|
|
let message = `${object.error} ${object.message}`;
|
|
if (object.stacktrace) {
|
|
message += ` ${object.stacktrace}`;
|
|
}
|
|
return message;
|
|
}
|
|
function isCdpEvent(event) {
|
|
return event.method.startsWith('goog:cdp.');
|
|
}
|
|
//# sourceMappingURL=Connection.js.map |