INIT: move uptime migration helper to own repository
This commit is contained in:
commit
4c567e247e
|
@ -0,0 +1,8 @@
|
|||
# sample configuration for uptimeRobot to kuma migration
|
||||
|
||||
# get from UptimeRobotApi
|
||||
UPTIME_ROBOT_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
KUMA_URL="http://localhost:3001"
|
||||
KUMA_USERNAME="admin"
|
||||
KUMA_PASSWORD="password2"
|
|
@ -0,0 +1,3 @@
|
|||
dist/
|
||||
node_modules/
|
||||
.env
|
|
@ -0,0 +1,53 @@
|
|||
# UptimeRobot to Kuma migration
|
||||
|
||||
We migrated from UptimeRobot to UptimeKuma, but there was no fast way to achieve this, so
|
||||
we wrote our own small migration helper.
|
||||
|
||||
## Getting started
|
||||
|
||||
Copy the `.env.sample` as `.env` and enter your UptimeRobot API key.
|
||||
|
||||
For testing, you can simply start UptimeKuma via Docker:
|
||||
|
||||
```shell
|
||||
docker run --rm -p 3001:3001 --name uptime-kuma louislam/uptime-kuma:1
|
||||
```
|
||||
|
||||
Ensure you finished the initial setup (simply open [localhost:3001](localhost:3001) in your browser) and
|
||||
updated the credentials in the `.env` file.
|
||||
|
||||
To start the migration run:
|
||||
|
||||
```bash
|
||||
# copy all your UptimeRobot monitors to your Kuma installation
|
||||
yarn copy-monitors
|
||||
|
||||
# disable all UptimeRobot monitors
|
||||
yarn disable-uptime-robot
|
||||
|
||||
# delete all your monitors from UptimeRobot
|
||||
# DANGER!!! This is can not be undone
|
||||
yarn delete-uptime-robot
|
||||
```
|
||||
|
||||
## Production Migration
|
||||
|
||||
**Important Node:** This migration helper was writen specially for our use-case. So not all UptimeRobot
|
||||
scenarios and features are implemented. So no garantie this will work 100% for you.
|
||||
|
||||
**Pro Tipp:** Before migrating, create a default notification that will get used as default.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Fetching from UptimeRobot
|
||||
|
||||
This part was quite easy, because UptimeRobot got a good REST-API to fetch all monitors from
|
||||
|
||||
### Creating the monitors in Kuma
|
||||
|
||||
This was the hard part. Currently, Kuma does not provide any form of API. In the first version of this migration
|
||||
helper, I tried to hook into the websocket connection of the UI and create monitors that way. This was really instabile
|
||||
and resulted in many non-deterministic errors.
|
||||
|
||||
For this reason I switched to Playwright. This allows us the remote-control a browser, which will create
|
||||
the monitors via the Kuma-UI.
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "kuma-migration",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"copy-monitors": "yarn build && node dist/index.js copy-monitors",
|
||||
"disable-uptime-robot": "yarn build && node dist/index.js disable-uptime-robot",
|
||||
"delete-uptime-robot": "yarn build && node dist/index.js delete-uptime-robot",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
"playwright": "^1.29.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.2.3",
|
||||
"dotenv": "^16.0.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
import dotenv from "dotenv"
|
||||
|
||||
import {
|
||||
UptimeRobotMonitor,
|
||||
UptimeRobotGetMonitorResponse,
|
||||
UptimeRobotEditMonitorResponse,
|
||||
UptimeRobotDeleteMonitorResponse
|
||||
} from "./types";
|
||||
import {chromium, Page} from 'playwright';
|
||||
import axios from "axios";
|
||||
|
||||
dotenv.config()
|
||||
|
||||
const UPTIME_ROBOT_API_KEY = process.env.UPTIME_ROBOT_API_KEY
|
||||
|
||||
const KUMA_URL = process.env.KUMA_URL
|
||||
const KUMA_USERNAME = process.env.KUMA_USERNAME
|
||||
const KUMA_PASSWORD = process.env.KUMA_PASSWORD
|
||||
|
||||
|
||||
if (
|
||||
!UPTIME_ROBOT_API_KEY ||
|
||||
!KUMA_URL ||
|
||||
!KUMA_USERNAME ||
|
||||
!KUMA_PASSWORD
|
||||
) {
|
||||
console.warn('Required env variables are missing!')
|
||||
console.warn('Copy ".env.sample" as ".env"')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const UPTIME_ROBOT_GET_MONITOR_API_PATH = "https://api.uptimerobot.com/v2/getMonitors?api_key="
|
||||
|
||||
const loadMonitorsFromUptimeRobot = async () => {
|
||||
const monitors: UptimeRobotMonitor[] = []
|
||||
|
||||
let monitorCount = 0
|
||||
let currentOffset = 0
|
||||
let totalMonitors = 9999999
|
||||
|
||||
while (monitorCount < totalMonitors) {
|
||||
const response = await axios.post(
|
||||
UPTIME_ROBOT_GET_MONITOR_API_PATH + UPTIME_ROBOT_API_KEY,
|
||||
`offset=${currentOffset}`
|
||||
)
|
||||
|
||||
const jsonResponse = response.data as UptimeRobotGetMonitorResponse
|
||||
|
||||
totalMonitors = jsonResponse.pagination.total
|
||||
currentOffset += 50
|
||||
monitorCount += jsonResponse.monitors.length
|
||||
monitors.push(...jsonResponse.monitors)
|
||||
|
||||
}
|
||||
|
||||
return monitors
|
||||
}
|
||||
|
||||
const UPTIME_ROBOT_DISABLE_MONITOR_API_PATH = "https://api.uptimerobot.com/v2/editMonitor"
|
||||
|
||||
const disableUptimeRobotMonitor = async (monitor: UptimeRobotMonitor) => {
|
||||
const response = await axios.post(
|
||||
UPTIME_ROBOT_DISABLE_MONITOR_API_PATH,
|
||||
new URLSearchParams({
|
||||
'api_key': UPTIME_ROBOT_API_KEY,
|
||||
'format': 'json',
|
||||
'id': `${monitor.id}`,
|
||||
'status': '0'
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const responseJson = response.data as UptimeRobotEditMonitorResponse
|
||||
if (responseJson?.stat === "fail") {
|
||||
console.error(`Failed to edit monitor '${monitor.friendly_name}' due to '${responseJson.error?.type}'`)
|
||||
process.exit(1)
|
||||
} else {
|
||||
console.log(`Disabled monitor "${monitor.friendly_name}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const UPTIME_ROBOT_DELETE_MONITOR_API_PATH = "https://api.uptimerobot.com/v2/deleteMonitor"
|
||||
const deleteUptimeRobotMonitor = async (monitor: UptimeRobotMonitor) => {
|
||||
const response = await axios.post(
|
||||
UPTIME_ROBOT_DELETE_MONITOR_API_PATH,
|
||||
new URLSearchParams({
|
||||
'api_key': UPTIME_ROBOT_API_KEY,
|
||||
'format': 'json',
|
||||
'id': `${monitor.id}`,
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache'
|
||||
}
|
||||
}
|
||||
)
|
||||
const responseJson = response.data as UptimeRobotDeleteMonitorResponse
|
||||
if (responseJson?.stat === "fail") {
|
||||
console.error(`Failed to delete monitor '${monitor.friendly_name}' due to '${responseJson.error?.type}'`)
|
||||
process.exit(1)
|
||||
} else {
|
||||
console.log(`Deleted monitor "${monitor.friendly_name}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const startPlaywright = async () => chromium.launch({headless: false})
|
||||
|
||||
const ensureLoggedIn = async (page: Page) => {
|
||||
const loginButton = await page.getByText("Login")
|
||||
|
||||
if (loginButton == null) {
|
||||
console.log('already logged in ...')
|
||||
return
|
||||
}
|
||||
|
||||
await page.getByPlaceholder('Username').type(KUMA_USERNAME)
|
||||
await page.getByPlaceholder('Password').type(KUMA_PASSWORD)
|
||||
|
||||
await loginButton.click()
|
||||
await page.waitForLoadState("domcontentloaded")
|
||||
}
|
||||
|
||||
const createMonitor = async (page: Page, monitor: UptimeRobotMonitor) => {
|
||||
await page.waitForLoadState('domcontentloaded')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
await page.getByText('Add New Monitor').first().click()
|
||||
|
||||
const createButton = await page.$('a:text(" Add New Monitor")')
|
||||
await createButton?.click()
|
||||
|
||||
|
||||
await page.waitForTimeout(100)
|
||||
await page.getByLabel('Friendly Name').first().fill(monitor.friendly_name)
|
||||
|
||||
switch (monitor.type) {
|
||||
case 1:
|
||||
await createMonitorHTTP(page, monitor)
|
||||
break
|
||||
case 2:
|
||||
await createMonitorKeyword(page, monitor)
|
||||
break
|
||||
case 4:
|
||||
await createMonitorPort(page, monitor)
|
||||
break
|
||||
default:
|
||||
console.log(`Monitor type ${monitor.type} of ${monitor.friendly_name} is not supported`)
|
||||
break
|
||||
}
|
||||
|
||||
await page.getByLabel('Heartbeat Interval (Check every').fill(String(monitor.interval))
|
||||
|
||||
const saveButton = await page.$('button#monitor-submit-btn')
|
||||
await saveButton?.click()
|
||||
|
||||
await page.waitForLoadState("domcontentloaded")
|
||||
await page.waitForLoadState("networkidle")
|
||||
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
console.log('Created Monitor ', monitor.friendly_name)
|
||||
}
|
||||
|
||||
const createMonitorHTTP = async (page: Page, monitor: UptimeRobotMonitor) => {
|
||||
await page.getByLabel("Monitor Type").selectOption("HTTP(s)")
|
||||
await page.getByLabel('URL').fill(monitor.url)
|
||||
}
|
||||
|
||||
const createMonitorKeyword = async (page: Page, monitor: UptimeRobotMonitor) => {
|
||||
await page.getByLabel("Monitor Type").selectOption("HTTP(s) - Keyword")
|
||||
await page.getByLabel('URL').fill(monitor.url)
|
||||
await page.getByLabel('Keyword').fill(monitor.keyword_value)
|
||||
}
|
||||
|
||||
const createMonitorPort = async (page: Page, monitor: UptimeRobotMonitor) => {
|
||||
await page.getByLabel("Monitor Type").selectOption("TCP Port")
|
||||
await page.getByLabel('Hostname').fill(monitor.url)
|
||||
await page.getByLabel('Port').fill(String(monitor.port))
|
||||
}
|
||||
|
||||
const copyMonitors = async () => {
|
||||
const monitors = await loadMonitorsFromUptimeRobot()
|
||||
console.log(`Found ${monitors.length} monitors`)
|
||||
|
||||
const browser = await startPlaywright()
|
||||
const page = await browser.newPage()
|
||||
await page.goto(KUMA_URL)
|
||||
|
||||
await ensureLoggedIn(page)
|
||||
|
||||
for (let monitor of monitors) {
|
||||
await createMonitor(page, monitor)
|
||||
}
|
||||
|
||||
await browser.close()
|
||||
}
|
||||
|
||||
const disableUptimeRobot = async () => {
|
||||
const monitors = await loadMonitorsFromUptimeRobot()
|
||||
console.log(`Found ${monitors.length} monitors`)
|
||||
|
||||
for (let monitor of monitors) {
|
||||
await disableUptimeRobotMonitor(monitor)
|
||||
}
|
||||
}
|
||||
|
||||
const deleteUptimeRobotMonitors = async () => {
|
||||
const monitors = await loadMonitorsFromUptimeRobot()
|
||||
console.log(`Found ${monitors.length} monitors`)
|
||||
|
||||
for (let monitor of monitors) {
|
||||
await deleteUptimeRobotMonitor(monitor)
|
||||
}
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
const task = process.argv[2]
|
||||
|
||||
switch (task) {
|
||||
case 'copy-monitors':
|
||||
await copyMonitors()
|
||||
break
|
||||
case 'disable-uptime-robot':
|
||||
await disableUptimeRobot()
|
||||
break
|
||||
case 'delete-uptime-robot':
|
||||
await deleteUptimeRobotMonitors()
|
||||
break
|
||||
default:
|
||||
console.error(`Task '${task} is not supported ...'`)
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
|
@ -0,0 +1,43 @@
|
|||
export interface UptimeRobotMonitor {
|
||||
id: number;
|
||||
friendly_name: string;
|
||||
url: string;
|
||||
type: number;
|
||||
sub_type: string;
|
||||
keyword_type: null;
|
||||
keyword_case_type: number;
|
||||
keyword_value: string;
|
||||
port: string;
|
||||
interval: number;
|
||||
timeout: number;
|
||||
status: number;
|
||||
create_datetime: number;
|
||||
}
|
||||
|
||||
export interface UptimeRobotPagination {
|
||||
offset: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface UptimeRobotGetMonitorResponse {
|
||||
stat: 'OK' | 'fail';
|
||||
pagination: UptimeRobotPagination;
|
||||
monitors: UptimeRobotMonitor[];
|
||||
}
|
||||
|
||||
export interface UptimeRobotEditMonitorResponse {
|
||||
stat: 'OK' | 'fail';
|
||||
error?: {
|
||||
type: 'not_authorized',
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface UptimeRobotDeleteMonitorResponse {
|
||||
stat: 'OK' | 'fail';
|
||||
error?: {
|
||||
type: 'not_authorized',
|
||||
message: string
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "NodeNext",
|
||||
"target": "ESNext",
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"sourceMap": false,
|
||||
"outDir": "dist",
|
||||
},
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@cspotcode/source-map-support@^0.8.0":
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
|
||||
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
|
||||
dependencies:
|
||||
"@jridgewell/trace-mapping" "0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@0.3.9":
|
||||
version "0.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
|
||||
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
|
||||
|
||||
"@tsconfig/node12@^1.0.7":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
|
||||
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
|
||||
|
||||
"@tsconfig/node14@^1.0.0":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
|
||||
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
|
||||
|
||||
"@tsconfig/node16@^1.0.2":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
|
||||
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||
|
||||
"@types/node@^18.11.18":
|
||||
version "18.11.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
|
||||
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
||||
|
||||
acorn-walk@^8.1.1:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.8.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
|
||||
integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
|
||||
|
||||
arg@^4.1.0:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
axios@^1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.3.tgz#31a3d824c0ebf754a004b585e5f04a5f87e6c4ff"
|
||||
integrity sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
create-require@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||
|
||||
dotenv@^16.0.3:
|
||||
version "16.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
|
||||
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
|
||||
|
||||
follow-redirects@^1.15.0:
|
||||
version "1.15.2"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
playwright-core@1.29.2:
|
||||
version "1.29.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.29.2.tgz#2e8347e7e8522409f22b244e600e703b64022406"
|
||||
integrity sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==
|
||||
|
||||
playwright@^1.29.2:
|
||||
version "1.29.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.29.2.tgz#d6a0a3e8e44f023f7956ed19ffa8af915a042769"
|
||||
integrity sha512-hKBYJUtdmYzcjdhYDkP9WGtORwwZBBKAW8+Lz7sr0ZMxtJr04ASXVzH5eBWtDkdb0c3LLFsehfPBTRfvlfKJOA==
|
||||
dependencies:
|
||||
playwright-core "1.29.2"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
ts-node@^10.9.1:
|
||||
version "10.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-support" "^0.8.0"
|
||||
"@tsconfig/node10" "^1.0.7"
|
||||
"@tsconfig/node12" "^1.0.7"
|
||||
"@tsconfig/node14" "^1.0.0"
|
||||
"@tsconfig/node16" "^1.0.2"
|
||||
acorn "^8.4.1"
|
||||
acorn-walk "^8.1.1"
|
||||
arg "^4.1.0"
|
||||
create-require "^1.1.0"
|
||||
diff "^4.0.1"
|
||||
make-error "^1.1.1"
|
||||
v8-compile-cache-lib "^3.0.1"
|
||||
yn "3.1.1"
|
||||
|
||||
typescript@^4.9.4:
|
||||
version "4.9.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
|
||||
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
|
||||
|
||||
v8-compile-cache-lib@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||
|
||||
yn@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
Loading…
Reference in New Issue