puppeteer-extra-plugin-timezone
Version:
A puppeteer-extra plugin to automatically emulate the appropriate timezones using IP reflection services.
124 lines • 4.38 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimezonePlugin = void 0;
const puppeteer_extra_plugin_1 = require("puppeteer-extra-plugin");
const constants_1 = require("./constants");
const exceptions_1 = require("./exceptions");
const provider_1 = require("./provider");
const schemas_1 = require("./schemas");
/**
* Puppeteer Extra Timezone Plugin
*
* @class
* @classdesc Reflects public IP context and adjusts Chrome timezone to match expectation.
*/
class TimezonePlugin extends puppeteer_extra_plugin_1.PuppeteerExtraPlugin {
/**
* Constructor
* Receives standard puppeteer-extra plugin config options.
*
* @param {TimezonePluginOptions} opts
*/
constructor(opts = {}) {
super(opts);
this._setFallbackTz(opts.fallbackTz);
this.ctx = new Map();
}
/**
* Describe the identifier for plugin.
* @return {string}
*/
get name() {
return constants_1.PLUGIN_NAME;
}
/**
* Accessor to previously resolved timezone strings.
* @param {BrowserId} browserId
* @return {string | undefined}
*/
getTz(browserId) {
var _a;
return (_a = this.ctx.get(browserId)) === null || _a === void 0 ? void 0 : _a.tz;
}
/**
* Upon browser launch, attempt to resolve the timezone, if not already resolved.
*
* @param {Browser} browser
* @return {Promise<void>}
*/
async onBrowser(browser) {
var _a;
const browserId = await this._getBrowserId(browser);
try {
// Create a new page to resolve ip context.
const page = await browser.newPage();
// Save the ip context result to local property for future access.
this.ctx.set(browserId, await provider_1.getTimezone(page));
// Clean up.
await page.close();
this.debug(`Detected timezone (${constants_1.IP_REFLECTION_URL}): ${this.getTz(browserId)}`, this.ctx);
browser.on("disconnected", () => this.ctx.delete(browserId));
}
catch (err) {
this.debug(`Error getting timezone for ip: ${err.message}`);
this.debug((_a = err.stack) !== null && _a !== void 0 ? _a : err);
}
}
/**
* Each new page creation event, emulate the resolved timezone.
*
* @param {Page} page
* @return {Promise<void>}
*/
async onPageCreated(page) {
var _a;
const browserId = await this._getBrowserId(page.browser());
// Get the resolved timezone or fallback timezone.
const tz = this.getTz(browserId) || this._fallbackTz;
// Do not emulate if we couldn't get any one of them.
if (!tz) {
throw new exceptions_1.TimezoneNotResolvedError(browserId);
}
// Attempt to emulate timezone based on previously resolved string.
try {
await page.emulateTimezone(tz);
this.debug(`Emulating timezone ${tz} for ${page.url()}`);
}
catch (err) {
this.debug(`Error emulating timezone for page (${page.url()}): ${err.message}`);
this.debug((_a = err.stack) !== null && _a !== void 0 ? _a : err);
}
}
/**
* Returns the unique TargetId of a given browser.
*
* @see https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-getTargetInfo
* @param {Browser} browser
* @return {Promise<BrowserId>}
* @protected
*/
async _getBrowserId(browser) {
const browserInfo = schemas_1.TargetInfoSchema.parse(await (await browser.target().createCDPSession()).send("Target.getTargetInfo"));
return browserInfo.targetInfo.targetId;
}
/**
* Set the fallback value from options or defaults.
*
* @param {string | string[] | undefined} zones
* @protected
*/
_setFallbackTz(zones) {
let fallbacks = constants_1.DEFAULT_FALLBACK_TIMEZONES;
if (zones) {
fallbacks = typeof zones === "string" ? [zones] : zones;
}
this._fallbackTz = fallbacks[Math.floor(Math.random() * fallbacks.length)];
}
}
exports.TimezonePlugin = TimezonePlugin;
/**
* Export plugin factory as default export.
* @return {TimezonePlugin}
*/
exports.default = () => new TimezonePlugin();
//# sourceMappingURL=plugin.js.map
;