Merge branch 'ansible' of github.com:matchu/impress-2020 into ansible
This commit is contained in:
commit
d4b115e805
12 changed files with 340 additions and 550 deletions
|
@ -160,7 +160,7 @@
|
||||||
# process. They'll be able to manage it without `sudo`, including during
|
# process. They'll be able to manage it without `sudo`, including during
|
||||||
# normal deploys, and run `pm2 monit` from their shell to see status.
|
# normal deploys, and run `pm2 monit` from their shell to see status.
|
||||||
become: yes
|
become: yes
|
||||||
command: "pm2 startup systemd {{ ansible_user_id }} --hp /home/{{ ansible_user_id }}"
|
command: "pm2 startup systemd -u {{ ansible_user_id }} --hp /home/{{ ansible_user_id }}"
|
||||||
|
|
||||||
- name: Create pm2 ecosystem file
|
- name: Create pm2 ecosystem file
|
||||||
copy:
|
copy:
|
||||||
|
@ -267,6 +267,62 @@
|
||||||
- libgif-dev
|
- libgif-dev
|
||||||
- librsvg2-dev
|
- librsvg2-dev
|
||||||
|
|
||||||
|
- name: Install Playwright system dependencies
|
||||||
|
# NOTE: I copied the package list from the source list for
|
||||||
|
# `npx playwright install-deps`, which I couldn't get running in
|
||||||
|
# Ansible as root, and besides, I prefer manually managing the
|
||||||
|
# package list over running an npm script as root!
|
||||||
|
# TODO: We're using Puppeteer now, should this list change in some way?
|
||||||
|
become: yes
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
name:
|
||||||
|
# Tools
|
||||||
|
- xvfb
|
||||||
|
- fonts-noto-color-emoji
|
||||||
|
- ttf-unifont
|
||||||
|
- libfontconfig
|
||||||
|
- libfreetype6
|
||||||
|
- xfonts-cyrillic
|
||||||
|
- xfonts-scalable
|
||||||
|
- fonts-liberation
|
||||||
|
- fonts-ipafont-gothic
|
||||||
|
- fonts-wqy-zenhei
|
||||||
|
- fonts-tlwg-loma-otf
|
||||||
|
- ttf-ubuntu-font-family
|
||||||
|
# Chromium
|
||||||
|
- fonts-liberation
|
||||||
|
- libasound2
|
||||||
|
- libatk-bridge2.0-0
|
||||||
|
- libatk1.0-0
|
||||||
|
- libatspi2.0-0
|
||||||
|
- libcairo2
|
||||||
|
- libcups2
|
||||||
|
- libdbus-1-3
|
||||||
|
- libdrm2
|
||||||
|
- libegl1
|
||||||
|
- libgbm1
|
||||||
|
- libglib2.0-0
|
||||||
|
- libgtk-3-0
|
||||||
|
- libnspr4
|
||||||
|
- libnss3
|
||||||
|
- libpango-1.0-0
|
||||||
|
- libx11-6
|
||||||
|
- libx11-xcb1
|
||||||
|
- libxcb1
|
||||||
|
- libxcomposite1
|
||||||
|
- libxdamage1
|
||||||
|
- libxext6
|
||||||
|
- libxfixes3
|
||||||
|
- libxrandr2
|
||||||
|
- libxshmfence1
|
||||||
|
|
||||||
|
- name: Enable user namespace cloning for Chromium sandboxing
|
||||||
|
become: yes
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: kernel.unprivileged_userns_clone
|
||||||
|
value: "1"
|
||||||
|
|
||||||
handlers:
|
handlers:
|
||||||
- name: Restart nginx
|
- name: Restart nginx
|
||||||
become: yes
|
become: yes
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
"easeljs": "^1.0.2",
|
"easeljs": "^1.0.2",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"framer-motion": "^4.1.11",
|
"framer-motion": "^4.1.11",
|
||||||
|
"generic-pool": "^3.8.2",
|
||||||
"graphql": "^15.5.0",
|
"graphql": "^15.5.0",
|
||||||
"honeycomb-beeline": "^2.7.4",
|
"honeycomb-beeline": "^2.7.4",
|
||||||
"immer": "^9.0.6",
|
"immer": "^9.0.6",
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
"mysql2": "^2.1.0",
|
"mysql2": "^2.1.0",
|
||||||
"next": "12.0.2",
|
"next": "12.0.2",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"playwright-core": "^1.14.0",
|
"puppeteer": "^11.0.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-autosuggest": "^10.0.2",
|
"react-autosuggest": "^10.0.2",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
|
@ -112,7 +113,6 @@
|
||||||
"inquirer": "^7.3.3",
|
"inquirer": "^7.3.3",
|
||||||
"jest-image-snapshot": "^4.3.0",
|
"jest-image-snapshot": "^4.3.0",
|
||||||
"lint-staged": "^10.5.4",
|
"lint-staged": "^10.5.4",
|
||||||
"playwright": "^1.14.0",
|
|
||||||
"prettier": "^2.0.5",
|
"prettier": "^2.0.5",
|
||||||
"react-is": "^16.13.1",
|
"react-is": "^16.13.1",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
|
|
|
@ -8,127 +8,15 @@ const beeline = require("honeycomb-beeline")({
|
||||||
disableInstrumentationOnLoad: true,
|
disableInstrumentationOnLoad: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
|
|
||||||
import connectToDb from "../../src/server/db";
|
|
||||||
|
|
||||||
async function handle(req, res) {
|
async function handle(req, res) {
|
||||||
const allNcItemNamesAndIdsPromise = loadAllNcItemNamesAndIds();
|
res.setHeader("Content-Type", "text/plain; charset=utf8");
|
||||||
|
res
|
||||||
let itemValuesByIdOrName;
|
.status(410)
|
||||||
try {
|
.send(
|
||||||
itemValuesByIdOrName = await loadWakaValuesByIdOrName();
|
"WakaGuide.com is no longer updating its values, so we no longer " +
|
||||||
} catch (e) {
|
"serve them from this endpoint. The most recent set of values is " +
|
||||||
console.error(e);
|
"archived here: https://docs.google.com/spreadsheets/d/1DRMrniTSZP0sgZK6OAFFYqpmbT6xY_Ve_i480zghOX0"
|
||||||
res.setHeader("Content-Type", "text/plain");
|
);
|
||||||
res.status(500).send("Error loading Waka data from Google Sheets API");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restructure the value data to use IDs as keys, instead of names.
|
|
||||||
const allNcItemNamesAndIds = await allNcItemNamesAndIdsPromise;
|
|
||||||
const itemValues = {};
|
|
||||||
for (const { name, id } of allNcItemNamesAndIds) {
|
|
||||||
if (id in itemValuesByIdOrName) {
|
|
||||||
itemValues[id] = itemValuesByIdOrName[id];
|
|
||||||
} else if (name in itemValuesByIdOrName) {
|
|
||||||
itemValues[id] = itemValuesByIdOrName[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache for 1 minute, and immediately serve stale data for a day after.
|
|
||||||
// This should keep it fast and responsive, and stay well within our API key
|
|
||||||
// limits. (This will cause the client to send more requests than necessary,
|
|
||||||
// but the CDN cache should generally respond quickly with a small 304 Not
|
|
||||||
// Modified, unless the data really did change.)
|
|
||||||
res.setHeader(
|
|
||||||
"Cache-Control",
|
|
||||||
"public, max-age=3600, stale-while-revalidate=86400"
|
|
||||||
);
|
|
||||||
return res.send(itemValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadAllNcItemNamesAndIds() {
|
|
||||||
const db = await connectToDb();
|
|
||||||
|
|
||||||
const [rows] = await db.query(`
|
|
||||||
SELECT items.id, item_translations.name FROM items
|
|
||||||
INNER JOIN item_translations ON item_translations.item_id = items.id
|
|
||||||
WHERE
|
|
||||||
(items.rarity_index IN (0, 500) OR is_manually_nc = 1)
|
|
||||||
AND item_translations.locale = "en"
|
|
||||||
`);
|
|
||||||
|
|
||||||
return rows.map(({ id, name }) => ({ id, name: normalizeItemName(name) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load all Waka values from the spreadsheet. Returns an object keyed by ID or
|
|
||||||
* name - that is, if the item ID is provided in the sheet, we use that as the
|
|
||||||
* key; or if not, we use the name as the key.
|
|
||||||
*/
|
|
||||||
async function loadWakaValuesByIdOrName() {
|
|
||||||
if (!process.env["GOOGLE_API_KEY"]) {
|
|
||||||
throw new Error(`GOOGLE_API_KEY environment variable must be provided`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await fetch(
|
|
||||||
`https://sheets.googleapis.com/v4/spreadsheets/` +
|
|
||||||
`1DRMrniTSZP0sgZK6OAFFYqpmbT6xY_Ve_i480zghOX0/values/NC%20Values` +
|
|
||||||
`?fields=values&key=${encodeURIComponent(process.env["GOOGLE_API_KEY"])}`
|
|
||||||
);
|
|
||||||
const json = await res.json();
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
if (json.error) {
|
|
||||||
const { code, status, message } = json.error;
|
|
||||||
throw new Error(
|
|
||||||
`Google Sheets API returned error ${code} ${status}: ${message}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
`Google Sheets API returned unexpected error: ${res.status} ${res.statusText}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the rows from the JSON response - skipping the first-row headers.
|
|
||||||
const rows = json.values.slice(1);
|
|
||||||
|
|
||||||
// Reformat the rows as a map from item name to value. We offer the item data
|
|
||||||
// as an object with a single field `value` for extensibility, but we omit
|
|
||||||
// the spreadsheet columns that we don't use on DTI, like Notes.
|
|
||||||
//
|
|
||||||
// NOTE: The Sheets API only returns the first non-empty cells of the row.
|
|
||||||
// That's why we set `""` as the defaults, in case the value/notes/etc
|
|
||||||
// aren't provided.
|
|
||||||
const itemValuesByIdOrName = {};
|
|
||||||
for (const [
|
|
||||||
itemName,
|
|
||||||
value = "",
|
|
||||||
unusedNotes = "",
|
|
||||||
unusedMarks = "",
|
|
||||||
itemId = "",
|
|
||||||
] of rows) {
|
|
||||||
const normalizedItemName = normalizeItemName(itemName);
|
|
||||||
itemValuesByIdOrName[itemId || normalizedItemName] = { value };
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemValuesByIdOrName;
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeItemName(name) {
|
|
||||||
return (
|
|
||||||
name
|
|
||||||
// Remove all spaces, they're a common source of inconsistency
|
|
||||||
.replace(/\s+/g, "")
|
|
||||||
// Lower case, because capitalization is another common source
|
|
||||||
.toLowerCase()
|
|
||||||
// Remove diacritics: https://stackoverflow.com/a/37511463/107415
|
|
||||||
// Waka has some stray ones in item names, not sure why!
|
|
||||||
.normalize("NFD")
|
|
||||||
.replace(/[\u0300-\u036f]/g, "")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleWithBeeline(req, res) {
|
async function handleWithBeeline(req, res) {
|
||||||
|
|
|
@ -22,34 +22,37 @@ const beeline = require("honeycomb-beeline")({
|
||||||
disableInstrumentationOnLoad: true,
|
disableInstrumentationOnLoad: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// To render the image, we load the /internal/assetImage page in the web app,
|
const puppeteer = require("puppeteer");
|
||||||
// a simple page specifically designed for this API endpoint!
|
const genericPool = require("generic-pool");
|
||||||
const ASSET_IMAGE_PAGE_BASE_URL = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}/internal/assetImage`
|
|
||||||
: process.env.NODE_ENV === "development"
|
|
||||||
? "http://localhost:3000/internal/assetImage"
|
|
||||||
: "https://impress-2020.openneo.net/internal/assetImage";
|
|
||||||
|
|
||||||
// TODO: We used to share a browser instamce, but we couldn't get it to reload
|
console.info(`Creating new browser instance`);
|
||||||
// correctly after accidental closes, so we're just gonna always load a
|
const browserPromise = puppeteer.launch({ headless: true });
|
||||||
// new one now. What are the perf implications of this? Does it slow down
|
|
||||||
// response time substantially?
|
// We maintain a small pool of browser pages, to manage memory usage. If all
|
||||||
async function getBrowser() {
|
// the pages are already in use, a request will wait for one of them to become
|
||||||
if (process.env["NODE_ENV"] === "production") {
|
// available.
|
||||||
// In production, we use a special chrome-aws-lambda Chromium.
|
//
|
||||||
const chromium = require("chrome-aws-lambda");
|
// NOTE: 4 pages is about where our 1-cpu prod environment maxes out. We might
|
||||||
const playwright = require("playwright-core");
|
// want to upgrade to the 2-cpu box as we add more pressure though, and
|
||||||
return await playwright.chromium.launch({
|
// then maybe we can afford more pages in the pool?
|
||||||
args: chromium.args,
|
|
||||||
executablePath: await chromium.executablePath,
|
const PAGE_POOL = genericPool.createPool(
|
||||||
headless: true,
|
{
|
||||||
});
|
create: async () => {
|
||||||
} else {
|
console.debug(`Creating a browser page`);
|
||||||
// In development, we use the standard playwright Chromium.
|
const browser = await browserPromise;
|
||||||
const playwright = require("playwright");
|
return await browser.newPage();
|
||||||
return await playwright.chromium.launch({ headless: true });
|
},
|
||||||
}
|
destroy: (page) => {
|
||||||
}
|
console.debug(`Closing a browser page`);
|
||||||
|
page.close();
|
||||||
|
},
|
||||||
|
validate: (page) => page.browser().isConnected(),
|
||||||
|
},
|
||||||
|
{ min: 4, max: 4, testOnBorrow: true, acquireTimeoutMillis: 15000 }
|
||||||
|
);
|
||||||
|
PAGE_POOL.on("factoryCreateError", (error) => console.error(error));
|
||||||
|
PAGE_POOL.on("factoryDestroyError", (error) => console.error(error));
|
||||||
|
|
||||||
async function handle(req, res) {
|
async function handle(req, res) {
|
||||||
const { libraryUrl, size } = req.query;
|
const { libraryUrl, size } = req.query;
|
||||||
|
@ -73,6 +76,9 @@ async function handle(req, res) {
|
||||||
imageBuffer = await loadAndScreenshotImage(libraryUrl, size);
|
imageBuffer = await loadAndScreenshotImage(libraryUrl, size);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
if (e.name === "TimeoutError") {
|
||||||
|
return reject(res, `Server under heavy load: ${e.message}`, 503);
|
||||||
|
}
|
||||||
return reject(res, `Could not load image: ${e.message}`, 500);
|
return reject(res, `Could not load image: ${e.message}`, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,18 +92,24 @@ async function handle(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadAndScreenshotImage(libraryUrl, size) {
|
async function loadAndScreenshotImage(libraryUrl, size) {
|
||||||
const assetImagePageUrl = new URL(ASSET_IMAGE_PAGE_BASE_URL);
|
// To render the image, we load the /internal/assetImage page in the web app,
|
||||||
|
// a simple page specifically designed for this API endpoint!
|
||||||
|
//
|
||||||
|
// NOTE: If we deploy to a host where localhost:3000 won't work, make this
|
||||||
|
// configurable with an env var, e.g. process.env.LOCAL_APP_HOST
|
||||||
|
const assetImagePageUrl = new URL(
|
||||||
|
"http://localhost:3000/internal/assetImage"
|
||||||
|
);
|
||||||
assetImagePageUrl.search = new URLSearchParams({
|
assetImagePageUrl.search = new URLSearchParams({
|
||||||
libraryUrl,
|
libraryUrl,
|
||||||
size,
|
size,
|
||||||
}).toString();
|
}).toString();
|
||||||
|
|
||||||
console.debug("Opening browser page");
|
console.debug("Getting browser page");
|
||||||
const browser = await getBrowser();
|
const page = await PAGE_POOL.acquire();
|
||||||
const page = await browser.newPage();
|
|
||||||
console.debug("Page opened, navigating to: " + assetImagePageUrl.toString());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.debug("Page ready, navigating to: " + assetImagePageUrl.toString());
|
||||||
await page.goto(assetImagePageUrl.toString());
|
await page.goto(assetImagePageUrl.toString());
|
||||||
console.debug("Page loaded, awaiting image");
|
console.debug("Page loaded, awaiting image");
|
||||||
|
|
||||||
|
@ -106,10 +118,20 @@ async function loadAndScreenshotImage(libraryUrl, size) {
|
||||||
// present, or raising the error if present.
|
// present, or raising the error if present.
|
||||||
const imageBufferPromise = screenshotImageFromPage(page);
|
const imageBufferPromise = screenshotImageFromPage(page);
|
||||||
const errorMessagePromise = readErrorMessageFromPage(page);
|
const errorMessagePromise = readErrorMessageFromPage(page);
|
||||||
const firstResultFromPage = await Promise.any([
|
let firstResultFromPage;
|
||||||
imageBufferPromise.then((imageBuffer) => ({ imageBuffer })),
|
try {
|
||||||
errorMessagePromise.then((errorMessage) => ({ errorMessage })),
|
firstResultFromPage = await Promise.any([
|
||||||
]);
|
imageBufferPromise.then((imageBuffer) => ({ imageBuffer })),
|
||||||
|
errorMessagePromise.then((errorMessage) => ({ errorMessage })),
|
||||||
|
]);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.errors) {
|
||||||
|
// If both promises failed, show all error messages.
|
||||||
|
throw new Error(error.errors.map((e) => e.message).join(", "));
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (firstResultFromPage.errorMessage) {
|
if (firstResultFromPage.errorMessage) {
|
||||||
throw new Error(firstResultFromPage.errorMessage);
|
throw new Error(firstResultFromPage.errorMessage);
|
||||||
|
@ -122,18 +144,9 @@ async function loadAndScreenshotImage(libraryUrl, size) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Tear down our resources when we're done! If it fails, log the error, but
|
// To avoid memory leaks, we destroy the page when we're done with it.
|
||||||
// don't block the success of the image.
|
// The pool will replace it with a fresh one!
|
||||||
try {
|
PAGE_POOL.destroy(page);
|
||||||
await page.close();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Error closing page after image finished", e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await browser.close();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Error closing browser after image finished", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +186,7 @@ function isNeopetsUrl(urlString) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function reject(res, message, status = 400) {
|
function reject(res, message, status = 400) {
|
||||||
res.setHeader("Content-Type", "text/plain");
|
res.setHeader("Content-Type", "text/plain; charset=utf8");
|
||||||
return res.status(status).send(message);
|
return res.status(status).send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,12 @@ const beeline = require("honeycomb-beeline")({
|
||||||
sampleRate: 10,
|
sampleRate: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
import { print as graphqlPrint } from "graphql/language/printer";
|
import { ApolloServer } from "apollo-server";
|
||||||
|
import { createTestClient } from "apollo-server-testing";
|
||||||
|
|
||||||
import connectToDb from "../../src/server/db";
|
import connectToDb from "../../src/server/db";
|
||||||
|
import { config as graphqlConfig } from "../../src/server";
|
||||||
import { renderOutfitImage } from "../../src/server/outfit-images";
|
import { renderOutfitImage } from "../../src/server/outfit-images";
|
||||||
import getVisibleLayers, {
|
import getVisibleLayers, {
|
||||||
petAppearanceFragmentForGetVisibleLayers,
|
petAppearanceFragmentForGetVisibleLayers,
|
||||||
|
@ -143,50 +144,35 @@ async function handle(req, res) {
|
||||||
return res.send(image);
|
return res.send(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
const GRAPHQL_ENDPOINT = process.env.VERCEL_URL
|
// Check out this scrappy way of making a query against server code ^_^`
|
||||||
? `https://${process.env.VERCEL_URL}/api/graphql`
|
const graphqlClient = createTestClient(new ApolloServer(graphqlConfig));
|
||||||
: process.env.NODE_ENV === "development"
|
|
||||||
? "http://localhost:3000/api/graphql"
|
|
||||||
: "https://impress-2020.openneo.net/api/graphql";
|
|
||||||
|
|
||||||
// NOTE: Unlike in-app views, we only load PNGs here. We expect this to
|
|
||||||
// generally perform better, and be pretty reliable now that TNT is
|
|
||||||
// generating canonical PNGs for every layer!
|
|
||||||
const GRAPHQL_QUERY = gql`
|
|
||||||
query ApiOutfitImage($outfitId: ID!, $size: LayerImageSize) {
|
|
||||||
outfit(id: $outfitId) {
|
|
||||||
petAppearance {
|
|
||||||
layers {
|
|
||||||
id
|
|
||||||
imageUrl(size: $size)
|
|
||||||
}
|
|
||||||
...PetAppearanceForGetVisibleLayers
|
|
||||||
}
|
|
||||||
itemAppearances {
|
|
||||||
layers {
|
|
||||||
id
|
|
||||||
imageUrl(size: $size)
|
|
||||||
}
|
|
||||||
...ItemAppearanceForGetVisibleLayers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${petAppearanceFragmentForGetVisibleLayers}
|
|
||||||
${itemAppearanceFragmentForGetVisibleLayers}
|
|
||||||
`;
|
|
||||||
const GRAPHQL_QUERY_STRING = graphqlPrint(GRAPHQL_QUERY);
|
|
||||||
|
|
||||||
async function loadLayerUrlsForSavedOutfit(outfitId, size) {
|
async function loadLayerUrlsForSavedOutfit(outfitId, size) {
|
||||||
const { errors, data } = await fetch(GRAPHQL_ENDPOINT, {
|
const { errors, data } = await graphqlClient.query({
|
||||||
method: "POST",
|
query: gql`
|
||||||
headers: {
|
query ApiOutfitImage($outfitId: ID!, $size: LayerImageSize) {
|
||||||
"Content-Type": "application/json",
|
outfit(id: $outfitId) {
|
||||||
},
|
petAppearance {
|
||||||
body: JSON.stringify({
|
layers {
|
||||||
query: GRAPHQL_QUERY_STRING,
|
id
|
||||||
variables: { outfitId, size: `SIZE_${size}` },
|
imageUrl(size: $size)
|
||||||
}),
|
}
|
||||||
}).then((res) => res.json());
|
...PetAppearanceForGetVisibleLayers
|
||||||
|
}
|
||||||
|
itemAppearances {
|
||||||
|
layers {
|
||||||
|
id
|
||||||
|
imageUrl(size: $size)
|
||||||
|
}
|
||||||
|
...ItemAppearanceForGetVisibleLayers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${petAppearanceFragmentForGetVisibleLayers}
|
||||||
|
${itemAppearanceFragmentForGetVisibleLayers}
|
||||||
|
`,
|
||||||
|
variables: { outfitId, size: `SIZE_${size}` },
|
||||||
|
});
|
||||||
|
|
||||||
if (errors && errors.length > 0) {
|
if (errors && errors.length > 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -225,7 +211,7 @@ async function loadUpdatedAtForSavedOutfit(outfitId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function reject(res, message, status = 400) {
|
function reject(res, message, status = 400) {
|
||||||
res.setHeader("Content-Type", "text/plain");
|
res.setHeader("Content-Type", "text/plain; charset=utf8");
|
||||||
return res.status(status).send(message);
|
return res.status(status).send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
/**
|
|
||||||
* /api/outfitPageSSR also serves the initial request for /outfits/:id, to
|
|
||||||
* add title and meta tags. This primarily for sharing, like on Discord or
|
|
||||||
* Twitter or Facebook!
|
|
||||||
*
|
|
||||||
* The route is configured in vercel.json, at the project root.
|
|
||||||
*
|
|
||||||
* To be honest, we probably should have built Impress 2020 on Next.js, and
|
|
||||||
* then we'd be getting realistic server-side rendering across practically the
|
|
||||||
* whole app very cheaply. But this is a good hack for what we have!
|
|
||||||
*
|
|
||||||
* TODO: We could add the basic outfit page layout and image preview, to use
|
|
||||||
* SSR to decrease time-to-first-content for the end-user, too…
|
|
||||||
*/
|
|
||||||
const beeline = require("honeycomb-beeline")({
|
|
||||||
writeKey: process.env["HONEYCOMB_WRITE_KEY"],
|
|
||||||
dataset:
|
|
||||||
process.env["NODE_ENV"] === "production"
|
|
||||||
? "Dress to Impress (2020)"
|
|
||||||
: "Dress to Impress (2020, dev)",
|
|
||||||
serviceName: "impress-2020-gql-server",
|
|
||||||
disableInstrumentationOnLoad: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
import escapeHtml from "escape-html";
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
|
|
||||||
import connectToDb from "../../src/server/db";
|
|
||||||
import { normalizeRow } from "../../src/server/util";
|
|
||||||
|
|
||||||
async function handle(req, res) {
|
|
||||||
// Load index.html as our initial page content. If this fails, it probably
|
|
||||||
// means something is misconfigured in a big way; we don't have a great way
|
|
||||||
// to recover, and we'll just show an error message.
|
|
||||||
let initialHtml;
|
|
||||||
try {
|
|
||||||
initialHtml = await loadIndexPageHtml();
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Error loading index.html:", e);
|
|
||||||
return reject(res, "Sorry, there was an error loading this outfit page!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the given outfit by ID. If this fails, it's possible that it's just a
|
|
||||||
// problem with the SSR, and the client will be able to handle it better
|
|
||||||
// anyway, so just show the standard index.html and let the app load
|
|
||||||
// normally, as if there was no error. (We'll just log it.)
|
|
||||||
let outfit;
|
|
||||||
try {
|
|
||||||
outfit = await loadOutfitData(req.query.id);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Error loading outfit data:", e);
|
|
||||||
return sendHtml(res, initialHtml, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similarly, if the outfit isn't found, we just show index.html - but with a
|
|
||||||
// 404 and a gentler log message.
|
|
||||||
if (outfit == null) {
|
|
||||||
console.info(`Outfit not found: ${req.query.id}`);
|
|
||||||
return sendHtml(res, initialHtml, 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
const outfitName = outfit.name || "Untitled outfit";
|
|
||||||
|
|
||||||
// Okay, now let's rewrite the HTML to include some outfit data!
|
|
||||||
//
|
|
||||||
// WARNING!!!
|
|
||||||
// Be sure to always use `escapeHtml` when inserting user data!!
|
|
||||||
// WARNING!!!
|
|
||||||
//
|
|
||||||
let html = initialHtml;
|
|
||||||
|
|
||||||
// Add the outfit name to the title.
|
|
||||||
html = html.replace(
|
|
||||||
/<title>(.*)<\/title>/,
|
|
||||||
`<title>${escapeHtml(outfitName)} | Dress to Impress</title>`
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add sharing meta tags just before the </head> tag.
|
|
||||||
const updatedAtTimestamp = Math.floor(
|
|
||||||
new Date(outfit.updatedAt).getTime() / 1000
|
|
||||||
);
|
|
||||||
const outfitUrl =
|
|
||||||
`https://impress-2020.openneo.net/outfits` +
|
|
||||||
`/${encodeURIComponent(outfit.id)}`;
|
|
||||||
const imageUrl =
|
|
||||||
`https://impress-outfit-images.openneo.net/outfits` +
|
|
||||||
`/${encodeURIComponent(outfit.id)}` +
|
|
||||||
`/v/${encodeURIComponent(updatedAtTimestamp)}` +
|
|
||||||
`/600.png`;
|
|
||||||
const metaTags = `
|
|
||||||
<meta property="og:title" content="${escapeHtml(outfitName)}">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
<meta property="og:image" content="${escapeHtml(imageUrl)}">
|
|
||||||
<meta property="og:url" content="${escapeHtml(outfitUrl)}">
|
|
||||||
<meta property="og:site_name" content="Dress to Impress">
|
|
||||||
<meta property="og:description" content="A custom Neopets outfit, designed on Dress to Impress!">
|
|
||||||
`;
|
|
||||||
html = html.replace(/<\/head>/, `${metaTags}</head>`);
|
|
||||||
|
|
||||||
console.info(`Successfully SSR'd outfit ${outfit.id}`);
|
|
||||||
|
|
||||||
return sendHtml(res, html);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadOutfitData(id) {
|
|
||||||
const db = await connectToDb();
|
|
||||||
const [rows] = await db.query(`SELECT * FROM outfits WHERE id = ?;`, [id]);
|
|
||||||
if (rows.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizeRow(rows[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cachedIndexPageHtml = null;
|
|
||||||
async function loadIndexPageHtml() {
|
|
||||||
if (cachedIndexPageHtml == null) {
|
|
||||||
// Request the same built copy of index.html that we're already serving at
|
|
||||||
// our homepage.
|
|
||||||
const homepageUrl = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}/`
|
|
||||||
: process.env.NODE_ENV === "development"
|
|
||||||
? "http://localhost:3000/"
|
|
||||||
: "https://impress-2020.openneo.net/";
|
|
||||||
const liveIndexPageHtml = await fetch(homepageUrl).then((res) =>
|
|
||||||
res.text()
|
|
||||||
);
|
|
||||||
cachedIndexPageHtml = liveIndexPageHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cachedIndexPageHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reject(res, message, status = 400) {
|
|
||||||
res.setHeader("Content-Type", "text/plain");
|
|
||||||
return res.status(status).send(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendHtml(res, html, status = 200) {
|
|
||||||
res.setHeader("Content-Type", "text/html");
|
|
||||||
return res.status(status).send(html);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleWithBeeline(req, res) {
|
|
||||||
beeline.withTrace(
|
|
||||||
{ name: "api/outfitPageSSR", operation_name: "api/outfitPageSSR" },
|
|
||||||
() => handle(req, res)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default handleWithBeeline;
|
|
|
@ -2,6 +2,7 @@ import React from "react";
|
||||||
import { ClassNames } from "@emotion/react";
|
import { ClassNames } from "@emotion/react";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Center,
|
Center,
|
||||||
|
@ -56,6 +57,23 @@ function HomePage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" align="center" textAlign="center" marginTop="8">
|
<Flex direction="column" align="center" textAlign="center" marginTop="8">
|
||||||
|
<Alert status="warning" maxWidth="600px">
|
||||||
|
<Box>
|
||||||
|
<strong>
|
||||||
|
The Neopets Metaverse team is no longer licensed to use this
|
||||||
|
software.
|
||||||
|
</strong>{" "}
|
||||||
|
<Box
|
||||||
|
as="a"
|
||||||
|
href="https://twitter.com/NeopetsDTI/status/1460386400839168001?s=20"
|
||||||
|
textDecoration="underline"
|
||||||
|
>
|
||||||
|
More information available here.
|
||||||
|
</Box>{" "}
|
||||||
|
Thanks for understanding!
|
||||||
|
</Box>
|
||||||
|
</Alert>
|
||||||
|
<Box height="4" />
|
||||||
<Box
|
<Box
|
||||||
width="200px"
|
width="200px"
|
||||||
height="200px"
|
height="200px"
|
||||||
|
|
|
@ -299,13 +299,24 @@ function computeOverallCachePolicy(
|
||||||
|
|
||||||
// If maxAge is 0, then we consider it uncacheable so it doesn't matter what
|
// If maxAge is 0, then we consider it uncacheable so it doesn't matter what
|
||||||
// the scope was.
|
// the scope was.
|
||||||
return lowestMaxAge && lowestMaxAgePlusSWR // FORK
|
if (lowestMaxAge && lowestMaxAgePlusSWR) {
|
||||||
? {
|
return {
|
||||||
maxAge: lowestMaxAge,
|
maxAge: lowestMaxAge,
|
||||||
staleWhileRevalidate: lowestMaxAgePlusSWR - lowestMaxAge, // FORK
|
staleWhileRevalidate: lowestMaxAgePlusSWR - lowestMaxAge, // FORK
|
||||||
scope,
|
scope,
|
||||||
}
|
};
|
||||||
: undefined;
|
} else if (scope !== CacheScope.Public) {
|
||||||
|
// TODO: It'd probably be a bit better to leave the ages unspecified if
|
||||||
|
// the hints didn't specify them, but I don't wanna mess with the
|
||||||
|
// header-writing code right now.
|
||||||
|
return {
|
||||||
|
maxAge: 0,
|
||||||
|
staleWhileRevalidate: 0,
|
||||||
|
scope,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHint(
|
function addHint(
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import DataLoader from "dataloader";
|
import DataLoader from "dataloader";
|
||||||
import fetch from "node-fetch";
|
|
||||||
import { normalizeRow } from "./util";
|
import { normalizeRow } from "./util";
|
||||||
|
|
||||||
const buildClosetListLoader = (db) =>
|
const buildClosetListLoader = (db) =>
|
||||||
|
@ -795,30 +794,6 @@ const buildItemTradesLoader = (db, loaders) =>
|
||||||
{ cacheKeyFn: ({ itemId, isOwned }) => `${itemId}-${isOwned}` }
|
{ cacheKeyFn: ({ itemId, isOwned }) => `${itemId}-${isOwned}` }
|
||||||
);
|
);
|
||||||
|
|
||||||
const buildItemWakaValueLoader = () =>
|
|
||||||
new DataLoader(async (itemIds) => {
|
|
||||||
// This loader calls our /api/allWakaValues endpoint, to take advantage of
|
|
||||||
// the CDN caching. This helps us respond a bit faster than Google Sheets
|
|
||||||
// API would, and avoid putting pressure on our Google Sheets API quotas.
|
|
||||||
// (Some kind of internal memcache or process-level cache would be a more
|
|
||||||
// idiomatic solution in a monolith server environment!)
|
|
||||||
const url = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}/api/allWakaValues`
|
|
||||||
: process.env.NODE_ENV === "production"
|
|
||||||
? "https://impress-2020.openneo.net/api/allWakaValues"
|
|
||||||
: "http://localhost:3000/api/allWakaValues";
|
|
||||||
const res = await fetch(url);
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(
|
|
||||||
`Error loading /api/allWakaValues: ${res.status} ${res.statusText}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const allWakaValues = await res.json();
|
|
||||||
|
|
||||||
return itemIds.map((itemId) => allWakaValues[itemId]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildPetTypeLoader = (db, loaders) =>
|
const buildPetTypeLoader = (db, loaders) =>
|
||||||
new DataLoader(async (petTypeIds) => {
|
new DataLoader(async (petTypeIds) => {
|
||||||
const qs = petTypeIds.map((_) => "?").join(",");
|
const qs = petTypeIds.map((_) => "?").join(",");
|
||||||
|
@ -1470,7 +1445,6 @@ function buildLoaders(db) {
|
||||||
db
|
db
|
||||||
);
|
);
|
||||||
loaders.itemTradesLoader = buildItemTradesLoader(db, loaders);
|
loaders.itemTradesLoader = buildItemTradesLoader(db, loaders);
|
||||||
loaders.itemWakaValueLoader = buildItemWakaValueLoader();
|
|
||||||
loaders.petTypeLoader = buildPetTypeLoader(db, loaders);
|
loaders.petTypeLoader = buildPetTypeLoader(db, loaders);
|
||||||
loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader(
|
loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader(
|
||||||
db,
|
db,
|
||||||
|
|
|
@ -28,14 +28,13 @@ const typeDefs = gql`
|
||||||
createdAt: String
|
createdAt: String
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This item's capsule trade value as text, according to wakaguide.com, as a
|
Deprecated: This item's capsule trade value as text, according to
|
||||||
human-readable string. Will be null if the value is not known, or if
|
wakaguide.com, as a human-readable string. **This now always returns null.**
|
||||||
there's an error connecting to the data source.
|
|
||||||
"""
|
"""
|
||||||
wakaValueText: String @cacheControl(maxAge: ${oneHour})
|
wakaValueText: String @cacheControl(maxAge: ${oneHour})
|
||||||
|
|
||||||
currentUserOwnsThis: Boolean! @cacheControl(scope: PRIVATE)
|
currentUserOwnsThis: Boolean! @cacheControl(maxAge: 0, scope: PRIVATE)
|
||||||
currentUserWantsThis: Boolean! @cacheControl(scope: PRIVATE)
|
currentUserWantsThis: Boolean! @cacheControl(maxAge: 0, scope: PRIVATE)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
How many users are offering/seeking this in their public trade lists.
|
How many users are offering/seeking this in their public trade lists.
|
||||||
|
@ -315,17 +314,9 @@ const resolvers = {
|
||||||
const item = await itemLoader.load(id);
|
const item = await itemLoader.load(id);
|
||||||
return item.createdAt && item.createdAt.toISOString();
|
return item.createdAt && item.createdAt.toISOString();
|
||||||
},
|
},
|
||||||
wakaValueText: async ({ id }, _, { itemWakaValueLoader }) => {
|
wakaValueText: () => {
|
||||||
let wakaValue;
|
// This feature is deprecated, so now we just always return unknown value.
|
||||||
try {
|
return null;
|
||||||
wakaValue = await itemWakaValueLoader.load(id);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error loading wakaValueText for item ${id}, skipping:`);
|
|
||||||
console.error(e);
|
|
||||||
wakaValue = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wakaValue ? wakaValue.value : null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
currentUserOwnsThis: async (
|
currentUserOwnsThis: async (
|
||||||
|
@ -665,8 +656,13 @@ const resolvers = {
|
||||||
itemSearchItemsLoader,
|
itemSearchItemsLoader,
|
||||||
petTypeBySpeciesAndColorLoader,
|
petTypeBySpeciesAndColorLoader,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
}
|
},
|
||||||
|
{ cacheControl }
|
||||||
) => {
|
) => {
|
||||||
|
if (currentUserOwnsOrWants != null) {
|
||||||
|
cacheControl.setCacheHint({ scope: "PRIVATE" });
|
||||||
|
}
|
||||||
|
|
||||||
let bodyId = null;
|
let bodyId = null;
|
||||||
if (fitsPet) {
|
if (fitsPet) {
|
||||||
const petType = await petTypeBySpeciesAndColorLoader.load({
|
const petType = await petTypeBySpeciesAndColorLoader.load({
|
||||||
|
@ -799,8 +795,12 @@ const resolvers = {
|
||||||
numTotalItems: async (
|
numTotalItems: async (
|
||||||
{ query, bodyId, itemKind, currentUserOwnsOrWants, zoneIds },
|
{ query, bodyId, itemKind, currentUserOwnsOrWants, zoneIds },
|
||||||
{ offset, limit },
|
{ offset, limit },
|
||||||
{ currentUserId, itemSearchNumTotalItemsLoader }
|
{ currentUserId, itemSearchNumTotalItemsLoader },
|
||||||
|
{ cacheControl }
|
||||||
) => {
|
) => {
|
||||||
|
if (currentUserOwnsOrWants != null) {
|
||||||
|
cacheControl.setCacheHint({ scope: "PRIVATE" });
|
||||||
|
}
|
||||||
const numTotalItems = await itemSearchNumTotalItemsLoader.load({
|
const numTotalItems = await itemSearchNumTotalItemsLoader.load({
|
||||||
query: query.trim(),
|
query: query.trim(),
|
||||||
bodyId,
|
bodyId,
|
||||||
|
@ -816,8 +816,12 @@ const resolvers = {
|
||||||
items: async (
|
items: async (
|
||||||
{ query, bodyId, itemKind, currentUserOwnsOrWants, zoneIds },
|
{ query, bodyId, itemKind, currentUserOwnsOrWants, zoneIds },
|
||||||
{ offset, limit },
|
{ offset, limit },
|
||||||
{ currentUserId, itemSearchItemsLoader }
|
{ currentUserId, itemSearchItemsLoader },
|
||||||
|
{ cacheControl }
|
||||||
) => {
|
) => {
|
||||||
|
if (currentUserOwnsOrWants != null) {
|
||||||
|
cacheControl.setCacheHint({ scope: "PRIVATE" });
|
||||||
|
}
|
||||||
const items = await itemSearchItemsLoader.load({
|
const items = await itemSearchItemsLoader.load({
|
||||||
query: query.trim(),
|
query: query.trim(),
|
||||||
bodyId,
|
bodyId,
|
||||||
|
|
|
@ -47,7 +47,20 @@ const typeDefs = gql`
|
||||||
user(id: ID!): User
|
user(id: ID!): User
|
||||||
userByName(name: String!): User
|
userByName(name: String!): User
|
||||||
userByEmail(email: String!, supportSecret: String!): User
|
userByEmail(email: String!, supportSecret: String!): User
|
||||||
currentUser: User
|
|
||||||
|
"""
|
||||||
|
The currently logged-in user.
|
||||||
|
"""
|
||||||
|
# Don't allow caching of *anything* nested inside currentUser, because we
|
||||||
|
# want logins/logouts always reset user data properly.
|
||||||
|
#
|
||||||
|
# TODO: If we wanted to privately cache a currentUser field, we could
|
||||||
|
# remove the maxAge condition here, and attach user ID to the GraphQL
|
||||||
|
# request URL when sending auth headers. That way, changing user
|
||||||
|
# would send different requests and avoid the old cache hits. (But we
|
||||||
|
# should leave the scope, to emphasize that the CDN cache shouldn't
|
||||||
|
# cache it.)
|
||||||
|
currentUser: User @cacheControl(maxAge: 0, scope: PRIVATE)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
236
yarn.lock
236
yarn.lock
|
@ -4564,7 +4564,7 @@ buffer@5.6.0, buffer@^5.2.0:
|
||||||
base64-js "^1.0.2"
|
base64-js "^1.0.2"
|
||||||
ieee754 "^1.1.4"
|
ieee754 "^1.1.4"
|
||||||
|
|
||||||
buffer@^5.5.0:
|
buffer@^5.2.1, buffer@^5.5.0:
|
||||||
version "5.7.1"
|
version "5.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
||||||
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
|
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
|
||||||
|
@ -4961,7 +4961,7 @@ commander@^5.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
|
||||||
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
|
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
|
||||||
|
|
||||||
commander@^6.1.0, commander@^6.2.0:
|
commander@^6.2.0:
|
||||||
version "6.2.1"
|
version "6.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
|
||||||
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
|
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
|
||||||
|
@ -5560,6 +5560,11 @@ detect-node@^2.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
||||||
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
|
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
|
||||||
|
|
||||||
|
devtools-protocol@0.0.901419:
|
||||||
|
version "0.0.901419"
|
||||||
|
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.901419.tgz#79b5459c48fe7e1c5563c02bd72f8fec3e0cebcd"
|
||||||
|
integrity sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ==
|
||||||
|
|
||||||
dicer@0.3.0:
|
dicer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
|
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
|
||||||
|
@ -5930,11 +5935,6 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||||
|
|
||||||
escape-string-regexp@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
|
|
||||||
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
|
|
||||||
|
|
||||||
escape-string-regexp@^4.0.0:
|
escape-string-regexp@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||||
|
@ -6361,17 +6361,7 @@ extglob@^2.0.4:
|
||||||
snapdragon "^0.8.1"
|
snapdragon "^0.8.1"
|
||||||
to-regex "^3.0.1"
|
to-regex "^3.0.1"
|
||||||
|
|
||||||
extract-zip@^1.7.0:
|
extract-zip@2.0.1:
|
||||||
version "1.7.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927"
|
|
||||||
integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==
|
|
||||||
dependencies:
|
|
||||||
concat-stream "^1.6.2"
|
|
||||||
debug "^2.6.9"
|
|
||||||
mkdirp "^0.5.4"
|
|
||||||
yauzl "^2.10.0"
|
|
||||||
|
|
||||||
extract-zip@^2.0.1:
|
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
|
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
|
||||||
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
|
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
|
||||||
|
@ -6382,6 +6372,16 @@ extract-zip@^2.0.1:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@types/yauzl" "^2.9.1"
|
"@types/yauzl" "^2.9.1"
|
||||||
|
|
||||||
|
extract-zip@^1.7.0:
|
||||||
|
version "1.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927"
|
||||||
|
integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==
|
||||||
|
dependencies:
|
||||||
|
concat-stream "^1.6.2"
|
||||||
|
debug "^2.6.9"
|
||||||
|
mkdirp "^0.5.4"
|
||||||
|
yauzl "^2.10.0"
|
||||||
|
|
||||||
extsprintf@1.3.0:
|
extsprintf@1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||||
|
@ -6771,6 +6771,11 @@ generate-function@^2.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-property "^1.0.2"
|
is-property "^1.0.2"
|
||||||
|
|
||||||
|
generic-pool@^3.8.2:
|
||||||
|
version "3.8.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9"
|
||||||
|
integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==
|
||||||
|
|
||||||
gensync@^1.0.0-beta.1:
|
gensync@^1.0.0-beta.1:
|
||||||
version "1.0.0-beta.1"
|
version "1.0.0-beta.1"
|
||||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
|
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
|
||||||
|
@ -6979,11 +6984,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
|
||||||
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
|
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
|
||||||
|
|
||||||
graceful-fs@^4.2.4:
|
|
||||||
version "4.2.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
|
|
||||||
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
|
|
||||||
|
|
||||||
graphql-extensions@^0.11.1:
|
graphql-extensions@^0.11.1:
|
||||||
version "0.11.1"
|
version "0.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.11.1.tgz#f543f544a047a7a4dd930123f662dfcc01527416"
|
resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.11.1.tgz#f543f544a047a7a4dd930123f662dfcc01527416"
|
||||||
|
@ -7055,9 +7055,9 @@ graphql@^14.5.3:
|
||||||
iterall "^1.2.2"
|
iterall "^1.2.2"
|
||||||
|
|
||||||
graphql@^15.5.0:
|
graphql@^15.5.0:
|
||||||
version "15.5.0"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5"
|
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.7.2.tgz#85ab0eeb83722977151b3feb4d631b5f2ab287ef"
|
||||||
integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==
|
integrity sha512-AnnKk7hFQFmU/2I9YSQf3xw44ctnSFCfp3zE0N6W174gqe9fWG/2rKaKxROK7CcI3XtERpjEKFqts8o319Kf7A==
|
||||||
|
|
||||||
gud@^1.0.0:
|
gud@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
@ -7290,6 +7290,14 @@ https-browserify@1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||||
|
|
||||||
|
https-proxy-agent@5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||||
|
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
||||||
|
dependencies:
|
||||||
|
agent-base "6"
|
||||||
|
debug "4"
|
||||||
|
|
||||||
https-proxy-agent@^3.0.0:
|
https-proxy-agent@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
|
||||||
|
@ -7298,14 +7306,6 @@ https-proxy-agent@^3.0.0:
|
||||||
agent-base "^4.3.0"
|
agent-base "^4.3.0"
|
||||||
debug "^3.1.0"
|
debug "^3.1.0"
|
||||||
|
|
||||||
https-proxy-agent@^5.0.0:
|
|
||||||
version "5.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
|
||||||
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
|
||||||
dependencies:
|
|
||||||
agent-base "6"
|
|
||||||
debug "4"
|
|
||||||
|
|
||||||
human-signals@^1.1.1:
|
human-signals@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||||
|
@ -7988,11 +7988,6 @@ jpeg-js@^0.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.1.tgz#937a3ae911eb6427f151760f8123f04c8bfe6ef7"
|
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.1.tgz#937a3ae911eb6427f151760f8123f04c8bfe6ef7"
|
||||||
integrity sha512-jA55yJiB5tCXEddos8JBbvW+IMrqY0y1tjjx9KNVtA+QPmu7ND5j0zkKopClpUTsaETL135uOM2XfcYG4XRjmw==
|
integrity sha512-jA55yJiB5tCXEddos8JBbvW+IMrqY0y1tjjx9KNVtA+QPmu7ND5j0zkKopClpUTsaETL135uOM2XfcYG4XRjmw==
|
||||||
|
|
||||||
jpeg-js@^0.4.2:
|
|
||||||
version "0.4.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b"
|
|
||||||
integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==
|
|
||||||
|
|
||||||
js-base64@^2.5.1:
|
js-base64@^2.5.1:
|
||||||
version "2.6.4"
|
version "2.6.4"
|
||||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
||||||
|
@ -9007,6 +9002,13 @@ node-fetch@2.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
|
node-fetch@2.6.5:
|
||||||
|
version "2.6.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd"
|
||||||
|
integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.6.0:
|
node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.6.0:
|
||||||
version "2.6.0"
|
version "2.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||||
|
@ -9649,6 +9651,13 @@ pixelmatch@^5.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
pngjs "^4.0.1"
|
pngjs "^4.0.1"
|
||||||
|
|
||||||
|
pkg-dir@4.2.0, pkg-dir@^4.1.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||||
|
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
||||||
|
dependencies:
|
||||||
|
find-up "^4.0.0"
|
||||||
|
|
||||||
pkg-dir@^2.0.0:
|
pkg-dir@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
|
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
|
||||||
|
@ -9663,58 +9672,11 @@ pkg-dir@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
find-up "^3.0.0"
|
find-up "^3.0.0"
|
||||||
|
|
||||||
pkg-dir@^4.1.0:
|
|
||||||
version "4.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
|
||||||
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
|
||||||
dependencies:
|
|
||||||
find-up "^4.0.0"
|
|
||||||
|
|
||||||
platform@1.3.6:
|
platform@1.3.6:
|
||||||
version "1.3.6"
|
version "1.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
|
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
|
||||||
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
|
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
|
||||||
|
|
||||||
playwright-core@^1.14.0:
|
|
||||||
version "1.14.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.14.0.tgz#af51da7b201c11eeda780e2db3f05c8bca74c8be"
|
|
||||||
integrity sha512-n6NdknezSfRgB6LkLwcrbm5orRQZSpbd8LZmlc4YrIXV0VEvJr5tzP3xlHXpiFBfTr3yoFuagldI3T7bD/8H3w==
|
|
||||||
dependencies:
|
|
||||||
commander "^6.1.0"
|
|
||||||
debug "^4.1.1"
|
|
||||||
extract-zip "^2.0.1"
|
|
||||||
https-proxy-agent "^5.0.0"
|
|
||||||
jpeg-js "^0.4.2"
|
|
||||||
mime "^2.4.6"
|
|
||||||
pngjs "^5.0.0"
|
|
||||||
progress "^2.0.3"
|
|
||||||
proper-lockfile "^4.1.1"
|
|
||||||
proxy-from-env "^1.1.0"
|
|
||||||
rimraf "^3.0.2"
|
|
||||||
stack-utils "^2.0.3"
|
|
||||||
ws "^7.4.6"
|
|
||||||
yazl "^2.5.1"
|
|
||||||
|
|
||||||
playwright@^1.14.0:
|
|
||||||
version "1.14.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.14.0.tgz#18301b11f5278a446d36b5cf96f67db36ce2cd20"
|
|
||||||
integrity sha512-aR5oZ1iVsjQkGfYCjgYAmyMAVu0MQ0i8MgdnfdqDu9EVLfbnpuuFmTv/Rb7/Yjno1kOrDUP9+RyNC+zfG3wozA==
|
|
||||||
dependencies:
|
|
||||||
commander "^6.1.0"
|
|
||||||
debug "^4.1.1"
|
|
||||||
extract-zip "^2.0.1"
|
|
||||||
https-proxy-agent "^5.0.0"
|
|
||||||
jpeg-js "^0.4.2"
|
|
||||||
mime "^2.4.6"
|
|
||||||
pngjs "^5.0.0"
|
|
||||||
progress "^2.0.3"
|
|
||||||
proper-lockfile "^4.1.1"
|
|
||||||
proxy-from-env "^1.1.0"
|
|
||||||
rimraf "^3.0.2"
|
|
||||||
stack-utils "^2.0.3"
|
|
||||||
ws "^7.4.6"
|
|
||||||
yazl "^2.5.1"
|
|
||||||
|
|
||||||
please-upgrade-node@^3.2.0:
|
please-upgrade-node@^3.2.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
|
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
|
||||||
|
@ -9732,11 +9694,6 @@ pngjs@^4.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe"
|
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe"
|
||||||
integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==
|
integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==
|
||||||
|
|
||||||
pngjs@^5.0.0:
|
|
||||||
version "5.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
|
|
||||||
integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
|
|
||||||
|
|
||||||
popmotion@9.3.5:
|
popmotion@9.3.5:
|
||||||
version "9.3.5"
|
version "9.3.5"
|
||||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.3.5.tgz#e821aff3424a021b0f2c93922db31c55cfe64149"
|
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.3.5.tgz#e821aff3424a021b0f2c93922db31c55cfe64149"
|
||||||
|
@ -9845,7 +9802,7 @@ process@~0.5.1:
|
||||||
resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
|
resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
|
||||||
integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=
|
integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=
|
||||||
|
|
||||||
progress@^2.0.0, progress@^2.0.3:
|
progress@2.0.3, progress@^2.0.0:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||||
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
||||||
|
@ -9864,15 +9821,6 @@ prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
react-is "^16.8.1"
|
react-is "^16.8.1"
|
||||||
|
|
||||||
proper-lockfile@^4.1.1:
|
|
||||||
version "4.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f"
|
|
||||||
integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==
|
|
||||||
dependencies:
|
|
||||||
graceful-fs "^4.2.4"
|
|
||||||
retry "^0.12.0"
|
|
||||||
signal-exit "^3.0.2"
|
|
||||||
|
|
||||||
proxy-addr@~2.0.5:
|
proxy-addr@~2.0.5:
|
||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
||||||
|
@ -9895,7 +9843,7 @@ proxy-agent@3:
|
||||||
proxy-from-env "^1.0.0"
|
proxy-from-env "^1.0.0"
|
||||||
socks-proxy-agent "^4.0.1"
|
socks-proxy-agent "^4.0.1"
|
||||||
|
|
||||||
proxy-from-env@^1.0.0, proxy-from-env@^1.1.0:
|
proxy-from-env@1.1.0, proxy-from-env@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
@ -9940,6 +9888,24 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||||
|
|
||||||
|
puppeteer@^11.0.0:
|
||||||
|
version "11.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-11.0.0.tgz#0808719c38e15315ecc1b1c28911f1c9054d201f"
|
||||||
|
integrity sha512-6rPFqN1ABjn4shgOICGDBITTRV09EjXVqhDERBDKwCLz0UyBxeeBH6Ay0vQUJ84VACmlxwzOIzVEJXThcF3aNg==
|
||||||
|
dependencies:
|
||||||
|
debug "4.3.2"
|
||||||
|
devtools-protocol "0.0.901419"
|
||||||
|
extract-zip "2.0.1"
|
||||||
|
https-proxy-agent "5.0.0"
|
||||||
|
node-fetch "2.6.5"
|
||||||
|
pkg-dir "4.2.0"
|
||||||
|
progress "2.0.3"
|
||||||
|
proxy-from-env "1.1.0"
|
||||||
|
rimraf "3.0.2"
|
||||||
|
tar-fs "2.1.1"
|
||||||
|
unbzip2-stream "1.4.3"
|
||||||
|
ws "8.2.3"
|
||||||
|
|
||||||
qs@6.7.0:
|
qs@6.7.0:
|
||||||
version "6.7.0"
|
version "6.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
|
@ -10484,6 +10450,13 @@ reusify@^1.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||||
|
|
||||||
|
rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||||
|
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||||
|
dependencies:
|
||||||
|
glob "^7.1.3"
|
||||||
|
|
||||||
rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
|
rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
|
||||||
version "2.7.1"
|
version "2.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||||
|
@ -10491,13 +10464,6 @@ rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.1.3"
|
glob "^7.1.3"
|
||||||
|
|
||||||
rimraf@^3.0.0, rimraf@^3.0.2:
|
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
|
||||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
|
||||||
dependencies:
|
|
||||||
glob "^7.1.3"
|
|
||||||
|
|
||||||
rimraf@~2.6.2:
|
rimraf@~2.6.2:
|
||||||
version "2.6.3"
|
version "2.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
||||||
|
@ -11019,13 +10985,6 @@ ssim.js@^3.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/ssim.js/-/ssim.js-3.5.0.tgz#d7276b9ee99b57a5ff0db34035f02f35197e62df"
|
resolved "https://registry.yarnpkg.com/ssim.js/-/ssim.js-3.5.0.tgz#d7276b9ee99b57a5ff0db34035f02f35197e62df"
|
||||||
integrity sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==
|
integrity sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==
|
||||||
|
|
||||||
stack-utils@^2.0.3:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277"
|
|
||||||
integrity sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==
|
|
||||||
dependencies:
|
|
||||||
escape-string-regexp "^2.0.0"
|
|
||||||
|
|
||||||
stacktrace-parser@0.1.10:
|
stacktrace-parser@0.1.10:
|
||||||
version "0.1.10"
|
version "0.1.10"
|
||||||
resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a"
|
resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a"
|
||||||
|
@ -11400,7 +11359,7 @@ table@^6.0.9:
|
||||||
string-width "^4.2.3"
|
string-width "^4.2.3"
|
||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
|
|
||||||
tar-fs@^2.0.0, tar-fs@^2.1.1:
|
tar-fs@2.1.1, tar-fs@^2.0.0, tar-fs@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
|
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
|
||||||
integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
|
integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
|
||||||
|
@ -11582,6 +11541,11 @@ tr46@^1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
|
tr46@~0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
|
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
|
||||||
|
|
||||||
truncate-utf8-bytes@^1.0.0:
|
truncate-utf8-bytes@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
|
resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
|
||||||
|
@ -11745,6 +11709,14 @@ unbox-primitive@^1.0.1:
|
||||||
has-symbols "^1.0.2"
|
has-symbols "^1.0.2"
|
||||||
which-boxed-primitive "^1.0.2"
|
which-boxed-primitive "^1.0.2"
|
||||||
|
|
||||||
|
unbzip2-stream@1.4.3:
|
||||||
|
version "1.4.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
|
||||||
|
integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
|
||||||
|
dependencies:
|
||||||
|
buffer "^5.2.1"
|
||||||
|
through "^2.3.8"
|
||||||
|
|
||||||
unfetch@^4.1.0:
|
unfetch@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db"
|
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db"
|
||||||
|
@ -12008,6 +11980,11 @@ watchpack@2.1.1:
|
||||||
glob-to-regexp "^0.4.1"
|
glob-to-regexp "^0.4.1"
|
||||||
graceful-fs "^4.1.2"
|
graceful-fs "^4.1.2"
|
||||||
|
|
||||||
|
webidl-conversions@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||||
|
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
|
||||||
|
|
||||||
webidl-conversions@^4.0.2:
|
webidl-conversions@^4.0.2:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||||
|
@ -12018,6 +11995,14 @@ whatwg-fetch@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
|
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
|
||||||
integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
|
integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
|
||||||
|
|
||||||
|
whatwg-url@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||||
|
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
|
||||||
|
dependencies:
|
||||||
|
tr46 "~0.0.3"
|
||||||
|
webidl-conversions "^3.0.0"
|
||||||
|
|
||||||
whatwg-url@^7.0.0:
|
whatwg-url@^7.0.0:
|
||||||
version "7.1.0"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
|
||||||
|
@ -12109,6 +12094,11 @@ write-file-atomic@^2.3.0:
|
||||||
imurmurhash "^0.1.4"
|
imurmurhash "^0.1.4"
|
||||||
signal-exit "^3.0.2"
|
signal-exit "^3.0.2"
|
||||||
|
|
||||||
|
ws@8.2.3:
|
||||||
|
version "8.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
|
||||||
|
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
|
||||||
|
|
||||||
ws@^5.2.0:
|
ws@^5.2.0:
|
||||||
version "5.2.2"
|
version "5.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"
|
||||||
|
@ -12123,11 +12113,6 @@ ws@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
async-limiter "~1.0.0"
|
async-limiter "~1.0.0"
|
||||||
|
|
||||||
ws@^7.4.6:
|
|
||||||
version "7.5.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
|
|
||||||
integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
|
|
||||||
|
|
||||||
ws@~7.4.2:
|
ws@~7.4.2:
|
||||||
version "7.4.4"
|
version "7.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
|
||||||
|
@ -12245,13 +12230,6 @@ yauzl@^2.10.0:
|
||||||
buffer-crc32 "~0.2.3"
|
buffer-crc32 "~0.2.3"
|
||||||
fd-slicer "~1.1.0"
|
fd-slicer "~1.1.0"
|
||||||
|
|
||||||
yazl@^2.5.1:
|
|
||||||
version "2.5.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35"
|
|
||||||
integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==
|
|
||||||
dependencies:
|
|
||||||
buffer-crc32 "~0.2.3"
|
|
||||||
|
|
||||||
yeast@0.1.2:
|
yeast@0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
|
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
|
||||||
|
|
Loading…
Reference in a new issue