screenshotone-validations
Version:
Validation schemes for the ScreenshotOne API requests.
428 lines (427 loc) • 20.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const joi_1 = __importDefault(require("joi"));
const screenshotone_devices_1 = __importDefault(require("screenshotone-devices"));
const validationOptions = { abortEarly: false };
const accessKeyScheme = {
access_key: joi_1.default.string().optional(),
};
const signatureScheme = {
signature: joi_1.default.string().optional(),
};
const createUriValidator = (fieldName) => {
return (value, helper) => {
try {
if (!value) {
return helper.message(`"${fieldName}" must be specified`);
}
if (value.trim().length === 0 || value.trim() !== value) {
return helper.message(`"${fieldName}" must be specified without leading and trailing white spaces`);
}
const u = new URL(value);
if (u.protocol !== "http:" && u.protocol !== "https:") {
return helper.message(`"${fieldName}" must be a valid URI with a scheme matching the http|https pattern`);
}
const withoutProtocol = value.substring((u.protocol + "//").length);
if (withoutProtocol.startsWith("http://") ||
withoutProtocol.startsWith("https://")) {
return helper.message(`"${fieldName}" must be a valid URI with a scheme matching the http|https pattern`);
}
return value;
}
catch (e) {
return helper.message(`"${fieldName}" must be a valid URI`);
}
};
};
const validUri = createUriValidator("url");
const screenshotScheme = {
// image options
image_quality: joi_1.default.when("format", {
is: joi_1.default.valid("jpeg", "jpg", "webp", "png", "tiff", "jp2", "avif", "heif"),
then: joi_1.default.number().integer().min(0).max(100).default(100),
otherwise: joi_1.default.forbidden(),
}),
image_width: joi_1.default.number().integer().optional(),
image_height: joi_1.default.number().integer().optional(),
omit_background: joi_1.default.when("format", {
is: joi_1.default.valid("png"),
then: joi_1.default.boolean().default(false),
otherwise: joi_1.default.forbidden(),
}).messages({
"any.unknown": 'The "omit_background" option is only allowed to use with image formats that support transparent backgrounds, like PNG.',
}),
// full page options
full_page: joi_1.default.boolean().default(false),
full_page_scroll: joi_1.default.when("full_page", {
is: true,
then: joi_1.default.boolean().default(true),
otherwise: joi_1.default.forbidden(),
}),
full_page_scroll_delay: joi_1.default.when("full_page_scroll", {
is: true,
then: joi_1.default.number().integer().positive().min(100).default(400),
otherwise: joi_1.default.forbidden(),
}),
full_page_scroll_by: joi_1.default.when("full_page_scroll", {
is: true,
then: joi_1.default.number().integer().positive(),
otherwise: joi_1.default.forbidden(),
}),
full_page_max_height: joi_1.default.when("full_page", {
is: true,
then: joi_1.default.number().integer().positive().optional(),
otherwise: joi_1.default.forbidden(),
}),
full_page_algorithm: joi_1.default.when("full_page", {
is: true,
then: joi_1.default.string().valid("by_sections", "default").default("default"),
otherwise: joi_1.default.forbidden(),
}),
capture_beyond_viewport: joi_1.default.when("selector", {
is: joi_1.default.string().required(),
then: joi_1.default.boolean().default(true),
otherwise: joi_1.default.boolean().default(joi_1.default.ref("full_page")),
}),
selector: joi_1.default.when("format", {
is: joi_1.default.valid("pdf"),
then: joi_1.default.forbidden(),
otherwise: joi_1.default.string().optional(),
}).messages({
"any.unknown": 'Rendering PDFs by "selector" is not allowed.',
}),
selector_algorithm: joi_1.default.when("selector", {
is: joi_1.default.string().required(),
then: joi_1.default.string().valid("clip", "default").default("default"),
otherwise: joi_1.default.forbidden(),
}),
selector_scroll_into_view: joi_1.default.when("selector", {
is: joi_1.default.string().required(),
then: joi_1.default.boolean().default(true),
otherwise: joi_1.default.forbidden(),
}),
error_on_selector_not_found: joi_1.default.boolean().default(false),
scroll_into_view: joi_1.default.string().optional(),
scroll_into_view_adjust_top: joi_1.default.number().integer().default(0),
format: joi_1.default.string()
.trim()
.lowercase()
.valid("png", "jpeg", "jpg", "webp", "gif", "jp2", "tiff", "avif", "heif", "html", "pdf", "markdown")
.default("jpg"),
metadata_image_size: joi_1.default.boolean().default(false),
clip_x: joi_1.default.number().integer().optional(),
clip_y: joi_1.default.number().integer().optional(),
clip_width: joi_1.default.number().integer().optional(),
clip_height: joi_1.default.number().integer().optional(),
vision_prompt: joi_1.default.string().optional(),
vision_max_tokens: joi_1.default.number().integer().optional(),
openai_api_key: joi_1.default.string().optional(),
pdf_margin: joi_1.default.string().optional(),
pdf_margin_top: joi_1.default.string().optional(),
pdf_margin_right: joi_1.default.string().optional(),
pdf_margin_bottom: joi_1.default.string().optional(),
pdf_margin_left: joi_1.default.string().optional(),
pdf_print_background: joi_1.default.boolean().optional(),
pdf_fit_one_page: joi_1.default.boolean().optional(),
pdf_landscape: joi_1.default.boolean().optional(),
pdf_paper_format: joi_1.default.string()
.valid("a0", "a1", "a2", "a3", "a4", "a5", "a6", "legal", "letter", "tabloid")
.optional(),
};
const commonOptionsScheme = joi_1.default.object({
// URL or HTML is required
url: joi_1.default.string().custom(validUri).optional(),
html: joi_1.default.string().optional(),
markdown: joi_1.default.string().optional(),
response_type: joi_1.default.string()
.trim()
.lowercase()
.valid("by_format", "empty", "json")
.default("by_format"),
request_gpu_rendering: joi_1.default.boolean().default(false),
fail_if_gpu_rendering_fails: joi_1.default.boolean().default(false),
include_shadow_dom: joi_1.default.boolean().default(false),
// emulation
dark_mode: joi_1.default.boolean().optional(),
reduced_motion: joi_1.default.boolean().optional(),
media_type: joi_1.default.string()
.trim()
.lowercase()
.valid("screen", "print")
.optional(),
// customization options
scripts: joi_1.default.string().optional(),
scripts_wait_until: joi_1.default.array()
.items(joi_1.default.string().valid("load", "domcontentloaded", "networkidle0", "networkidle2"))
.default([]),
styles: joi_1.default.string().optional(),
hide_selectors: joi_1.default.array().items(),
click: joi_1.default.string().optional(),
error_on_click_selector_not_found: joi_1.default.boolean().default(true),
// viewport options
viewport_device: joi_1.default.string()
.valid(...screenshotone_devices_1.default.names)
.optional(),
viewport_width: joi_1.default.number().integer().optional(),
viewport_height: joi_1.default.number().integer().optional(),
device_scale_factor: joi_1.default.number().min(1).max(5).optional(),
viewport_mobile: joi_1.default.boolean().optional(),
viewport_has_touch: joi_1.default.boolean().optional(),
viewport_landscape: joi_1.default.boolean().optional(),
// geolocation options
geolocation_latitude: joi_1.default.number().min(-90).max(90).optional(),
geolocation_longitude: joi_1.default.number().min(-180).max(180).optional(),
geolocation_accuracy: joi_1.default.number().integer().positive().optional(),
// location options
ip_country_code: joi_1.default.string()
.valid("us", "gb", "de", "it", "fr", "cn", "ca", "es", "jp", "kr", "in", "au", "br", "mx", "nz", "pe", "is", "ie")
.optional(),
servers_region: joi_1.default.string().valid("us-east").default("us-east"),
// blocking options
block_annoyances: joi_1.default.boolean().default(false),
block_cookie_banners: joi_1.default.boolean().default(false),
block_banners_by_heuristics: joi_1.default.boolean().default(false),
block_chats: joi_1.default.boolean().default(false),
block_ads: joi_1.default.boolean().default(false),
block_socials: joi_1.default.boolean().default(false),
block_trackers: joi_1.default.boolean().default(false),
block_requests: joi_1.default.array().items(joi_1.default.string()).default([]),
block_resources: joi_1.default.array()
.items(joi_1.default.string().valid("document", "stylesheet", "image", "media", "font", "script", "texttrack", "xhr", "fetch", "eventsource", "websocket", "manifest", "other"))
.default([]),
// cache options
cache: joi_1.default.boolean().default(false).optional(),
cache_ttl: joi_1.default.when("cache", {
is: true,
then: joi_1.default.number()
.integer()
.min(14400) // 4 hours
.max(2592000) // 1 month
.default(14400)
.optional(),
otherwise: joi_1.default.forbidden().messages({
"any.unknown": "The `cache_ttl` option cannot be used when the `cache` option is false or not set.",
}),
}),
cache_key: joi_1.default.when("cache", {
is: true,
then: joi_1.default.string().alphanum().min(1).max(250).optional(),
otherwise: joi_1.default.forbidden().messages({
"any.unknown": "The `cache_key` option cannot be used when the `cache` option is false or not set.",
}),
}),
// request options
user_agent: joi_1.default.string().optional(),
authorization: joi_1.default.string().optional(),
headers: joi_1.default.array().items(),
cookies: joi_1.default.array().items(),
proxy: joi_1.default.string()
// `encodeUri` allows to specify Unicode characters in the proxy URI
// it is useful when targeting is used in proxies and cities or countries are specified
// with special characters
.uri({ scheme: ["http"], encodeUri: true })
// makes sense to double-check it, since it will be anyway validated and fail if not correct
.custom(createUriValidator("proxy"))
.optional(),
attachment_name: joi_1.default.string().optional(),
bypass_csp: joi_1.default.boolean().default(false).optional(),
time_zone: joi_1.default.string().valid("America/Belize", "America/Cayman", "America/Chicago", "America/Costa_Rica", "America/Denver", "America/Edmonton", "America/El_Salvador", "America/Guatemala", "America/Guayaquil", "America/Hermosillo", "America/Jamaica", "America/Los_Angeles", "America/Mexico_City", "America/Nassau", "America/New_York", "America/Panama", "America/Port-au-Prince", "America/Santiago", "America/Tegucigalpa", "America/Tijuana", "America/Toronto", "America/Vancouver", "America/Winnipeg", "Asia/Kuala_Lumpur", "Asia/Shanghai", "Asia/Tashkent", "Europe/Berlin", "Europe/Kiev", "Europe/Lisbon", "Europe/London", "Europe/Madrid", "Pacific/Auckland", "Pacific/Majuro"),
// wait, timeout
delay: joi_1.default.number()
.integer()
.min(0)
.when("timeout", {
is: joi_1.default.number().greater(300),
then: joi_1.default.number().max(300),
otherwise: joi_1.default.number().max(30),
})
.optional(),
timeout: joi_1.default.number().when("async", {
is: true,
then: joi_1.default.number().integer().min(0).max(600).default(600),
otherwise: joi_1.default.number().integer().min(0).max(90).default(60),
}),
navigation_timeout: joi_1.default.number().integer().min(0).max(30).default(30),
wait_until: joi_1.default.array()
.items(joi_1.default.string().valid("load", "domcontentloaded", "networkidle0", "networkidle2"))
.default([]),
wait_for_selector: joi_1.default.string().optional(),
wait_for_selector_algorithm: joi_1.default.string()
.valid("at_least_one", "at_least_by_count")
.default("at_least_one")
.optional(),
fail_if_content_contains: joi_1.default.array()
.items(joi_1.default.string().optional())
.default([]),
fail_if_content_missing: joi_1.default.array()
.items(joi_1.default.string().optional())
.default([]),
fail_if_request_failed: joi_1.default.array()
.items(joi_1.default.string().optional())
.default([]),
async: joi_1.default.boolean().default(false),
webhook_url: joi_1.default.string()
.trim()
.custom(validUri)
.when("response_type", {
is: joi_1.default.string().valid("json", "by_format"),
then: joi_1.default.optional(),
otherwise: joi_1.default.forbidden(),
}),
webhook_sign: joi_1.default.boolean().default(true),
webhook_errors: joi_1.default.boolean().default(false),
external_identifier: joi_1.default.string().alphanum().min(1).max(64).optional(),
// store
store: joi_1.default.boolean().optional(),
storage_bucket: joi_1.default.string().optional(),
storage_path: joi_1.default.string().when("store", {
is: true,
then: joi_1.default.required(),
otherwise: joi_1.default.forbidden(),
}),
storage_endpoint: joi_1.default.string().uri().optional(),
storage_access_key_id: joi_1.default.string().optional(),
storage_secret_access_key: joi_1.default.string().optional(),
storage_acl: joi_1.default.string().valid("public-read", "").default(""),
storage_class: joi_1.default.string()
.valid("standard", "reduced_redundancy", "standard_ia", "onezone_ia", "intelligent_tiering", "glacier", "deep_archive", "outposts", "glacier_ir")
.default("standard"),
storage_return_location: joi_1.default.boolean().default(false),
ignore_host_errors: joi_1.default.boolean().default(false),
metadata_fonts: joi_1.default.boolean().default(false),
metadata_content: joi_1.default.boolean().default(false),
metadata_page_title: joi_1.default.boolean().default(false),
metadata_open_graph: joi_1.default.boolean().default(false),
metadata_http_response_status_code: joi_1.default.boolean()
.default(false)
.when("url", {
is: joi_1.default.exist(),
then: joi_1.default.boolean(),
otherwise: joi_1.default.forbidden(),
}),
metadata_http_response_headers: joi_1.default.boolean().default(false).when("url", {
is: joi_1.default.exist(),
then: joi_1.default.boolean(),
otherwise: joi_1.default.forbidden(),
}),
metadata_icon: joi_1.default.boolean().default(false),
}).oxor("ip_country_code", "proxy");
const optionsScheme = commonOptionsScheme.append(screenshotScheme);
const withEssentialsOptionsScheme = optionsScheme.or("html", "url", "markdown");
const bulkScheme = joi_1.default.object({
optimize: joi_1.default.boolean().default(false),
execute: joi_1.default.boolean().default(false),
options: joi_1.default.object(),
requests: joi_1.default.array().items(withEssentialsOptionsScheme).min(1).max(20),
});
const withHtmlOrUrlOrMarkdownRequired = commonOptionsScheme.or("html", "url", "markdown");
const animateScheme = withHtmlOrUrlOrMarkdownRequired
.append({
format: joi_1.default.string()
.trim()
.lowercase()
.valid("mp4", "avi", "mov", "webm", "gif")
.default("mp4"),
duration: joi_1.default.number().min(1).max(30).default(5),
omit_background: joi_1.default.when("format", {
is: joi_1.default.valid("mov"),
then: joi_1.default.boolean().default(false),
otherwise: joi_1.default.forbidden(),
}),
width: joi_1.default.number().integer().optional(),
height: joi_1.default.number().integer().optional(),
aspect_ratio: joi_1.default.string()
.trim()
.lowercase()
.valid("4:3", "16:9")
.default("4:3"),
scenario: joi_1.default.string()
.trim()
.lowercase()
.valid("", "default", "scroll")
.default("default"),
// scroll scenario parameters
scroll_duration: joi_1.default.number().min(100).default(1500),
scroll_delay: joi_1.default.number().min(0).default(500),
scroll_by: joi_1.default.number().min(1).default(1000),
scroll_start_immediately: joi_1.default.boolean().default(true),
scroll_start_delay: joi_1.default.number().min(0).default(0),
scroll_complete: joi_1.default.boolean().default(true),
scroll_back_after_duration: joi_1.default.number().integer().optional(),
scroll_back: joi_1.default.boolean().default(true),
scroll_back_algorithm: joi_1.default.string()
.trim()
.lowercase()
.valid("once", "repeat")
.default("once"),
scroll_stop_after_duration: joi_1.default.when("scroll_back", {
is: false,
then: joi_1.default.number().integer().optional(),
otherwise: joi_1.default.forbidden(),
}),
scroll_till_selector: joi_1.default.string().optional(),
scroll_till_selector_adjust_top: joi_1.default.number().integer().optional(),
scroll_try_navigate: joi_1.default.boolean().default(false).optional(),
scroll_navigate_after: joi_1.default.number().integer().optional(),
scroll_navigate_to_url: joi_1.default.string().custom(validUri).optional(),
scroll_navigate_link_hints: joi_1.default.array()
.items(joi_1.default.string().trim())
.default(["pricing", "about", "customers"])
.optional(),
scroll_to_end_after: joi_1.default.when("scenario", {
is: joi_1.default.valid("scroll"),
then: joi_1.default.number().integer().optional(),
otherwise: joi_1.default.forbidden(),
}),
clip_x: joi_1.default.when("format", {
is: joi_1.default.valid("gif"),
then: joi_1.default.number().integer().optional(),
otherwise: joi_1.default.forbidden(),
}),
clip_y: joi_1.default.when("format", {
is: joi_1.default.valid("gif"),
then: joi_1.default.number().integer().optional(),
otherwise: joi_1.default.forbidden(),
}),
clip_height: joi_1.default.when("format", {
is: joi_1.default.valid("gif"),
then: joi_1.default.number().integer().optional(),
otherwise: joi_1.default.forbidden(),
}),
clip_width: joi_1.default.when("format", {
is: joi_1.default.valid("gif"),
then: joi_1.default.number().integer().optional(),
otherwise: joi_1.default.forbidden(),
}),
scroll_easing: joi_1.default.string()
.trim()
.lowercase()
.valid("linear", "ease_in_quad", "ease_out_quad", "ease_in_out_quad", "ease_in_cubic", "ease_out_cubic", "ease_in_out_cubic", "ease_in_quart", "ease_out_quart", "ease_in_out_quart", "ease_in_quint", "ease_out_quint", "ease_in_out_quint")
.default("ease_in_out_quint"),
})
.oxor("scroll_stop_after_duration", "scroll_back_after_duration");
exports.default = {
animate: {
getScheme: animateScheme.append({
...accessKeyScheme,
...signatureScheme,
}),
postScheme: animateScheme.append({ ...accessKeyScheme }),
validationOptions,
},
bulk: {
postScheme: bulkScheme.append(accessKeyScheme),
validationOptions,
},
take: {
getScheme: withEssentialsOptionsScheme.append({
...accessKeyScheme,
...signatureScheme,
}),
postScheme: withEssentialsOptionsScheme.append({ ...accessKeyScheme }),
validationOptions,
},
};