diff --git a/client-electron/README.md b/client-electron/README.md index 3804fe2..7aa1c6d 100644 --- a/client-electron/README.md +++ b/client-electron/README.md @@ -34,7 +34,7 @@ We have some environment variables to control app behavior. The environment vari ## Environment Mode -In this Client project, we have two environment modes: `electron` and `web`. Business logic will be different in these two modes. you wrap the code in `if (import.meta.env.MODE === 'electron')` to run the code in electron mode. You can also use `if (import.meta.env.MODE === 'web')` to run the code in web mode. +In this Client project, we have two environment modes: `electron` and `web`. Business logic will be different in these two modes. you wrap the code in `if (window.electronRuntime)` to run the code in electron mode. You can also use `if (!window.electronRuntime)` to run the code in web mode. The reason why we have two environment modes is that in electron we have to use native modules for example `deeplink` to handle login callback. But in web, we have to use `window.location.href` to handle login callback. diff --git a/client-electron/electron/adb/adbDaemonUSB.ts b/client-electron/electron/adb/adbDaemonUSB.ts new file mode 100644 index 0000000..ec70bbb --- /dev/null +++ b/client-electron/electron/adb/adbDaemonUSB.ts @@ -0,0 +1,19 @@ +// import type { AdbDaemonWebUsbDevice } from '@yume-chan/adb-daemon-webusb' +// import { AdbDaemonWebUsbDeviceManager } from '@yume-chan/adb-daemon-webusb' +import { webusb } from 'usb' + +// const WebUsb: WebUSB = new WebUSB({ allowAllDevices: true }) +// const Manager: AdbDaemonWebUsbDeviceManager = new AdbDaemonWebUsbDeviceManager( +// WebUsb +// ) + +export function getDevices() { + // const devices: AdbDaemonWebUsbDevice[] = await Manager.getDevices() + // if (!devices.length) { + // alert('No device connected') + // } + + webusb.requestDevice({ filters: [] }).then(device => { + console.log(device) + }) +} diff --git a/client-electron/electron/deeplink.ts b/client-electron/electron/deeplink.ts new file mode 100644 index 0000000..d26da0b --- /dev/null +++ b/client-electron/electron/deeplink.ts @@ -0,0 +1,34 @@ +import { type BrowserWindow } from 'electron' + +export default function ( + app: Electron.App, + win: BrowserWindow | null, + ipcMain: Electron.IpcMain, + shell: Electron.Shell +) { + ipcMain.on('deeplink', (_event, url) => { + // open browser + shell.openExternal(url) + }) + + app.on('open-url', (_event, url) => { + const paramsString = url.split('://')[1] + + const kind = paramsString.split('?')[0] + + const params = new URLSearchParams(paramsString) + + if (kind === '/login') { + win?.webContents.send('loginSuccess', { + id: params.get('id'), + name: params.get('name'), + email: params.get('email'), + picture: params.get('picture'), + permissions: params.get('permissions'), + access_token: params.get('access_token'), + max_age: params.get('max_age'), + refresh_token: params.get('refresh_token') + }) + } + }) +} diff --git a/client-electron/electron/electron-env.d.ts b/client-electron/electron/electron-env.d.ts index 59e1e60..ad011a0 100644 --- a/client-electron/electron/electron-env.d.ts +++ b/client-electron/electron/electron-env.d.ts @@ -25,4 +25,6 @@ declare namespace NodeJS { // Used in Renderer process, expose in `preload.ts` interface Window { ipcRenderer: import('electron').IpcRenderer + electronRuntime: boolean + platform: NodeJS.Platform } diff --git a/client-electron/electron/keychain.ts b/client-electron/electron/keychain.ts new file mode 100644 index 0000000..a46f658 --- /dev/null +++ b/client-electron/electron/keychain.ts @@ -0,0 +1,22 @@ +import { findCredentials, getPassword, setPassword } from '@postman/node-keytar' + +export function eventGetKeyChain(icpMain: Electron.IpcMain) { + icpMain.on('get-keyChain', (event, serviceName, account) => { + getPassword(serviceName, account).then(password => { + event.returnValue = password + }) + }) + + icpMain.on('set-keyChain', (_event, serviceName, account, password) => { + setPassword(serviceName, account, password) + }) + + icpMain.on('delete-keyChain', (_event, serviceName, account) => { + setPassword(serviceName, account, '') + }) + + icpMain.handle('keyChainSync', async (_event, serviceName) => { + const credentials = await findCredentials(serviceName) + return credentials + }) +} diff --git a/client-electron/electron/main.ts b/client-electron/electron/main.ts index ce23707..9ceaa0c 100644 --- a/client-electron/electron/main.ts +++ b/client-electron/electron/main.ts @@ -1,5 +1,7 @@ import { app, BrowserWindow, ipcMain, shell } from 'electron' import path from 'node:path' +import deeplink from './deeplink' +import { eventGetKeyChain } from './keychain' // The built directory structure // @@ -10,7 +12,7 @@ import path from 'node:path' // │ │ ├── main.js // │ │ └── preload.js // │ -process.env.DIST = path.join(__dirname, '../dist') +process.env.DIST = path.join(__dirname, '../dist-renderer') process.env.VITE_PUBLIC = app.isPackaged ? process.env.DIST : path.join(process.env.DIST, '../public') @@ -42,6 +44,61 @@ function createWindow() { app.setAsDefaultProtocolClient('taobin-electron') } + let grantedDeviceThroughPermHandler: Electron.USBDevice + + win.webContents.session.on( + 'select-usb-device', + (event, details, callback) => { + // Add events to handle devices being added or removed before the callback on + // `select-usb-device` is called. + win?.webContents.session.on('usb-device-added', (_event, device) => { + console.log('usb-device-added FIRED WITH', device) + // Optionally update details.deviceList + }) + + win?.webContents.session.on('usb-device-removed', (_event, device) => { + console.log('usb-device-removed FIRED WITH', device) + // Optionally update details.deviceList + }) + + event.preventDefault() + if (details.deviceList && details.deviceList.length > 0) { + const deviceToReturn = details.deviceList.find( + device => device.vendorId === 1478 + ) + if (deviceToReturn) { + callback(deviceToReturn.deviceId) + } else { + callback() + } + } + } + ) + + win.webContents.session.setPermissionCheckHandler( + (_webContents, permission) => { + if (permission === 'usb') { + return true + } + return false + } + ) + + win.webContents.session.setDevicePermissionHandler(details => { + console.log(details) + if (details.deviceType === 'usb' && details.device.vendorId == 1478) { + if (!grantedDeviceThroughPermHandler) { + grantedDeviceThroughPermHandler = details.device as Electron.USBDevice + return true + } else if (grantedDeviceThroughPermHandler.vendorId === 1478) { + return true + } else { + return false + } + } + return false + }) + if (VITE_DEV_SERVER_URL) { win.loadURL(VITE_DEV_SERVER_URL) } else { @@ -68,17 +125,12 @@ app.on('activate', () => { } }) -app.on('open-url', (_event, url) => { - win?.webContents.send('deeplink', url) -}) - -// Create mainWindow, load the rest of the app, etc... +// Create MainWindow, load the rest of the app, etc... app.whenReady().then(() => { createWindow() -}) + // deeplink + deeplink(app, win, ipcMain, shell) -// deeplink -ipcMain.on('deeplink', (_event, url) => { - // open browser - shell.openExternal(url) + //keychain + eventGetKeyChain(ipcMain) }) diff --git a/client-electron/electron/preload.ts b/client-electron/electron/preload.ts index 76e7fca..0330325 100644 --- a/client-electron/electron/preload.ts +++ b/client-electron/electron/preload.ts @@ -4,6 +4,8 @@ import { contextBridge, ipcRenderer } from 'electron' // --------- Expose some API to the Renderer process --------- contextBridge.exposeInMainWorld('ipcRenderer', withPrototype(ipcRenderer)) +contextBridge.exposeInMainWorld('electronRuntime', true) +contextBridge.exposeInMainWorld('platform', process.platform) // `exposeInMainWorld` can't detect attributes and methods of `prototype`, manually patching it. function withPrototype(obj: Record) { diff --git a/client-electron/package-lock.json b/client-electron/package-lock.json index 3a4aa21..446a350 100644 --- a/client-electron/package-lock.json +++ b/client-electron/package-lock.json @@ -8,13 +8,24 @@ "name": "client-electron", "version": "0.0.1", "dependencies": { + "@postman/node-keytar": "^7.9.3", + "@yume-chan/adb": "^0.0.22", + "@yume-chan/adb-credential-web": "^0.0.22", + "@yume-chan/adb-daemon-webusb": "^0.0.22", + "@yume-chan/adb-scrcpy": "^0.0.22", + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/scrcpy-decoder-webcodecs": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "axios": "^1.6.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1", + "usb": "^2.11.0", "zustand": "^4.4.7" }, "devDependencies": { "@electron-forge/cli": "^7.2.0", + "@electron/rebuild": "^3.5.0", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@typescript-eslint/eslint-plugin": "^6.18.1", @@ -2687,6 +2698,18 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", @@ -2848,6 +2871,21 @@ "node": ">=14" } }, + "node_modules/@postman/node-keytar": { + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/@postman/node-keytar/-/node-keytar-7.9.3.tgz", + "integrity": "sha512-gWdxGGnqwg+bB4arSl+F+vbpE10eyfnGyTb/MrddqtQaWejWb4Dt+1MbdNGJ+pGJ16uFpiW1SFtI50Q3zAvhQA==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/@postman/node-keytar/node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, "node_modules/@remix-run/router": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.1.tgz", @@ -3061,6 +3099,11 @@ "dev": true, "optional": true }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==" + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -3295,6 +3338,135 @@ "node": ">=10.0.0" } }, + "node_modules/@yume-chan/adb": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb/-/adb-0.0.22.tgz", + "integrity": "sha512-X1HHfINMpkEXZkZ9pm9L8FqD2PytzU7T+wiZ4l3WE8r/YwfmDciV7yDE9A+h0KGJPK6dabMRC31sniu0ciwezg==", + "dependencies": { + "@yume-chan/async": "^2.2.0", + "@yume-chan/dataview-bigint-polyfill": "^0.0.22", + "@yume-chan/event": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/adb-credential-web": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-credential-web/-/adb-credential-web-0.0.22.tgz", + "integrity": "sha512-IfaGDze7C6JghKXq16ZgMmJ1MAlbnrIxm5zdskqfNZ72zgneIrA5H0R88YFq+p26LmDz1njJ3KR5CY1Ii7lMLw==", + "dependencies": { + "@yume-chan/adb": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/adb-daemon-webusb": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-daemon-webusb/-/adb-daemon-webusb-0.0.22.tgz", + "integrity": "sha512-H2Rhjb6Qu9W+LtG9sEhEJ5v+wT2cXMcLYptquJO9x4GxCpb1gytoo0DXkcXZFMUKipM5QxePjNLbUid7EUteFw==", + "dependencies": { + "@types/w3c-web-usb": "^1.0.10", + "@yume-chan/adb": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/adb-scrcpy": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-scrcpy/-/adb-scrcpy-0.0.22.tgz", + "integrity": "sha512-R+6hXJjrmdzTPoYb+xOH/ug4nX0t8+erH1Q5VT1Z4wBulDZATqWGI+UUTKK1r+x2wH6SfFX5bclKuLuGuk77Yw==", + "dependencies": { + "@yume-chan/adb": "^0.0.22", + "@yume-chan/async": "^2.2.0", + "@yume-chan/event": "^0.0.22", + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/async": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@yume-chan/async/-/async-2.2.0.tgz", + "integrity": "sha512-jatCtX1/3DsR9Vt3EB8CGFy0MNrXP5f+eNiRGHLH+LkYz7MPLzpqL/DnvXSip+Z0EKBCDnzuNuELjsKEEzcdQA==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@yume-chan/dataview-bigint-polyfill": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/dataview-bigint-polyfill/-/dataview-bigint-polyfill-0.0.22.tgz", + "integrity": "sha512-DVstotC7pt/O5jan2yT3B2WyiVShKDdWlH9uQXsfb/dGMGa1b1q3wCxVA/49p+JYQu4tOPnHUyzJQOcjBk5axw==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/event": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/event/-/event-0.0.22.tgz", + "integrity": "sha512-2aNpGeRMmcPC1CG/gDn8rVi50zs/Ffvlo8PLBBALo5CtwdkfxzKv1OQaE1JJ5Cz/qIoXI/HolvBnkiLAFY3LPA==", + "dependencies": { + "@yume-chan/async": "^2.2.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/scrcpy": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/scrcpy/-/scrcpy-0.0.22.tgz", + "integrity": "sha512-d+tLSFO9O9KGwxso3ccn/ahD7xzS5G3lOIOGVHVSloG0Jj4dP2GX18cD1wUXwLkulUM3E0apoTVYGkOR9LIYCQ==", + "dependencies": { + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/scrcpy-decoder-tinyh264": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/scrcpy-decoder-tinyh264/-/scrcpy-decoder-tinyh264-0.0.22.tgz", + "integrity": "sha512-vIIp86X9FGrEFdzBMjbEPHr/WZY5MDwP9TMlGbCcoxC2ZmnETw5QNTusmclcwTTJV2y1MRw3bQcQYQhaLprp+A==", + "dependencies": { + "@yume-chan/async": "^2.2.0", + "@yume-chan/event": "^0.0.22", + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "tinyh264": "^0.0.7", + "tslib": "^2.6.2", + "yuv-buffer": "^1.0.0", + "yuv-canvas": "^1.2.11" + } + }, + "node_modules/@yume-chan/scrcpy-decoder-webcodecs": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/scrcpy-decoder-webcodecs/-/scrcpy-decoder-webcodecs-0.0.22.tgz", + "integrity": "sha512-tlRti9pxy9QqT4BXABHRa13g0lvGHLjAyfks1Ad+iPptG1kfWlPzoTdpHQeqJO8W/rY213zffRnEZFTxuMSRmA==", + "dependencies": { + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/scrcpy-decoder-tinyh264": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "node_modules/@yume-chan/stream-extra": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/stream-extra/-/stream-extra-0.0.22.tgz", + "integrity": "sha512-cdHS6a8B6rYjLW+dlh2Q8FKOv3/y8ZAd+1bV0I1aNvoZS/vROWfQc2cf0AB0nBqM/GXlhrGbnPM+D35+0PkLBQ==", + "dependencies": { + "@yume-chan/async": "^2.2.0", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2", + "web-streams-polyfill": "^4.0.0-beta.3" + } + }, + "node_modules/@yume-chan/struct": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/struct/-/struct-0.0.22.tgz", + "integrity": "sha512-v3ETVutInqcRon0sJz8q97LxjC7+xJUx+5yowpNZlIEtbJQdQF2pgqkUXXhfZSWCUppY5Yg7foxCL+UZTSZBFA==", + "dependencies": { + "@yume-chan/dataview-bigint-polyfill": "^0.0.22", + "tslib": "^2.6.2" + } + }, "node_modules/7zip-bin": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", @@ -3626,8 +3798,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -3684,6 +3855,16 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", + "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3694,7 +3875,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -3723,7 +3903,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -3809,7 +3988,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -4360,7 +4538,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4714,7 +4891,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, "dependencies": { "mimic-response": "^3.1.0" }, @@ -4729,7 +4905,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, "engines": { "node": ">=10" }, @@ -4737,6 +4912,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4801,7 +4984,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -4816,7 +4998,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "dev": true, "engines": { "node": ">=8" } @@ -5296,7 +5477,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "dependencies": { "once": "^1.4.0" } @@ -5796,6 +5976,14 @@ "which": "bin/which" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -6069,6 +6257,25 @@ "node": ">= 10.0.0" } }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -6089,7 +6296,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6112,6 +6318,11 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -6347,6 +6558,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -6752,7 +6968,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -6830,14 +7045,12 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/interpret": { "version": "3.1.1", @@ -7714,7 +7927,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7723,7 +7935,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -7768,7 +7979,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7980,6 +8190,11 @@ "node": ">=10" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -8015,6 +8230,11 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8040,7 +8260,6 @@ "version": "3.54.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", - "dev": true, "dependencies": { "semver": "^7.3.5" }, @@ -8109,6 +8328,16 @@ "node": "^12.13 || ^14.13 || >=16" } }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -8255,7 +8484,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -8853,6 +9081,31 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8890,11 +9143,15 @@ "node": ">=10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -8941,6 +9198,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rcedit": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/rcedit/-/rcedit-4.0.1.tgz", @@ -9172,7 +9451,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9420,7 +9698,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -9469,7 +9746,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -9491,7 +9767,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -9502,8 +9777,7 @@ "node_modules/semver/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/serialize-error": { "version": "7.0.1", @@ -9569,6 +9843,49 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -9791,7 +10108,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -10041,6 +10357,37 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -10092,6 +10439,34 @@ "node": ">= 10.0.0" } }, + "node_modules/terser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10125,6 +10500,11 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, + "node_modules/tinyh264": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/tinyh264/-/tinyh264-0.0.7.tgz", + "integrity": "sha512-etkBRgYkSFBdAi2Cqk4sZgi+xWs/vhzNgvjO3z2i4WILeEmORiNqxuQ4URJatrWQ9LPNV3WPWAtzsh/LA/XL/g==" + }, "node_modules/tmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", @@ -10224,8 +10604,18 @@ "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } }, "node_modules/type-check": { "version": "0.4.0", @@ -10343,6 +10733,25 @@ "punycode": "^2.1.0" } }, + "node_modules/usb": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.11.0.tgz", + "integrity": "sha512-u5+NZ6DtoW8TIBtuSArQGAZZ/K15i3lYvZBAYmcgI+RcDS9G50/KPrUd3CrU8M92ahyCvg5e0gc8BDvr5Hwejg==", + "hasInstallScript": true, + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^7.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=12.22.0 <13.0 || >=14.17.0" + } + }, + "node_modules/usb/node_modules/node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" + }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -10373,8 +10782,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", @@ -10485,6 +10893,14 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -10629,8 +11045,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/xmlbuilder": { "version": "15.1.1", @@ -10798,6 +11213,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yuv-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yuv-buffer/-/yuv-buffer-1.0.0.tgz", + "integrity": "sha512-5r5u7g7Dbdrwao/z8c4harQIpZwaNuzXjQXtgdFxTjr5Pm2eMmxIuckkKOONEM7fkiMNkeffXs6EPNESvAVzVg==" + }, + "node_modules/yuv-canvas": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/yuv-canvas/-/yuv-canvas-1.2.11.tgz", + "integrity": "sha512-LOxjD+gUO7XeHeExFEozpTEFBlbqEZOnaHLAwx4esJ2tzSWl/S/xDRSDu1N+asxYn7ldV+HtisrYAzJXkT7Rhw==" + }, "node_modules/zustand": { "version": "4.4.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz", @@ -12697,6 +13122,18 @@ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", @@ -12817,6 +13254,22 @@ "dev": true, "optional": true }, + "@postman/node-keytar": { + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/@postman/node-keytar/-/node-keytar-7.9.3.tgz", + "integrity": "sha512-gWdxGGnqwg+bB4arSl+F+vbpE10eyfnGyTb/MrddqtQaWejWb4Dt+1MbdNGJ+pGJ16uFpiW1SFtI50Q3zAvhQA==", + "requires": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + }, + "dependencies": { + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + } + } + }, "@remix-run/router": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.1.tgz", @@ -13015,6 +13468,11 @@ "dev": true, "optional": true }, + "@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==" + }, "@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -13151,6 +13609,135 @@ "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", "dev": true }, + "@yume-chan/adb": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb/-/adb-0.0.22.tgz", + "integrity": "sha512-X1HHfINMpkEXZkZ9pm9L8FqD2PytzU7T+wiZ4l3WE8r/YwfmDciV7yDE9A+h0KGJPK6dabMRC31sniu0ciwezg==", + "requires": { + "@yume-chan/async": "^2.2.0", + "@yume-chan/dataview-bigint-polyfill": "^0.0.22", + "@yume-chan/event": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "@yume-chan/adb-credential-web": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-credential-web/-/adb-credential-web-0.0.22.tgz", + "integrity": "sha512-IfaGDze7C6JghKXq16ZgMmJ1MAlbnrIxm5zdskqfNZ72zgneIrA5H0R88YFq+p26LmDz1njJ3KR5CY1Ii7lMLw==", + "requires": { + "@yume-chan/adb": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "@yume-chan/adb-daemon-webusb": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-daemon-webusb/-/adb-daemon-webusb-0.0.22.tgz", + "integrity": "sha512-H2Rhjb6Qu9W+LtG9sEhEJ5v+wT2cXMcLYptquJO9x4GxCpb1gytoo0DXkcXZFMUKipM5QxePjNLbUid7EUteFw==", + "requires": { + "@types/w3c-web-usb": "^1.0.10", + "@yume-chan/adb": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "@yume-chan/adb-scrcpy": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-scrcpy/-/adb-scrcpy-0.0.22.tgz", + "integrity": "sha512-R+6hXJjrmdzTPoYb+xOH/ug4nX0t8+erH1Q5VT1Z4wBulDZATqWGI+UUTKK1r+x2wH6SfFX5bclKuLuGuk77Yw==", + "requires": { + "@yume-chan/adb": "^0.0.22", + "@yume-chan/async": "^2.2.0", + "@yume-chan/event": "^0.0.22", + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "@yume-chan/async": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@yume-chan/async/-/async-2.2.0.tgz", + "integrity": "sha512-jatCtX1/3DsR9Vt3EB8CGFy0MNrXP5f+eNiRGHLH+LkYz7MPLzpqL/DnvXSip+Z0EKBCDnzuNuELjsKEEzcdQA==", + "requires": { + "tslib": "^2.3.1" + } + }, + "@yume-chan/dataview-bigint-polyfill": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/dataview-bigint-polyfill/-/dataview-bigint-polyfill-0.0.22.tgz", + "integrity": "sha512-DVstotC7pt/O5jan2yT3B2WyiVShKDdWlH9uQXsfb/dGMGa1b1q3wCxVA/49p+JYQu4tOPnHUyzJQOcjBk5axw==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@yume-chan/event": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/event/-/event-0.0.22.tgz", + "integrity": "sha512-2aNpGeRMmcPC1CG/gDn8rVi50zs/Ffvlo8PLBBALo5CtwdkfxzKv1OQaE1JJ5Cz/qIoXI/HolvBnkiLAFY3LPA==", + "requires": { + "@yume-chan/async": "^2.2.0", + "tslib": "^2.6.2" + } + }, + "@yume-chan/scrcpy": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/scrcpy/-/scrcpy-0.0.22.tgz", + "integrity": "sha512-d+tLSFO9O9KGwxso3ccn/ahD7xzS5G3lOIOGVHVSloG0Jj4dP2GX18cD1wUXwLkulUM3E0apoTVYGkOR9LIYCQ==", + "requires": { + "@yume-chan/stream-extra": "^0.0.22", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "@yume-chan/scrcpy-decoder-tinyh264": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/scrcpy-decoder-tinyh264/-/scrcpy-decoder-tinyh264-0.0.22.tgz", + "integrity": "sha512-vIIp86X9FGrEFdzBMjbEPHr/WZY5MDwP9TMlGbCcoxC2ZmnETw5QNTusmclcwTTJV2y1MRw3bQcQYQhaLprp+A==", + "requires": { + "@yume-chan/async": "^2.2.0", + "@yume-chan/event": "^0.0.22", + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "tinyh264": "^0.0.7", + "tslib": "^2.6.2", + "yuv-buffer": "^1.0.0", + "yuv-canvas": "^1.2.11" + } + }, + "@yume-chan/scrcpy-decoder-webcodecs": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/scrcpy-decoder-webcodecs/-/scrcpy-decoder-webcodecs-0.0.22.tgz", + "integrity": "sha512-tlRti9pxy9QqT4BXABHRa13g0lvGHLjAyfks1Ad+iPptG1kfWlPzoTdpHQeqJO8W/rY213zffRnEZFTxuMSRmA==", + "requires": { + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/scrcpy-decoder-tinyh264": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "tslib": "^2.6.2" + } + }, + "@yume-chan/stream-extra": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/stream-extra/-/stream-extra-0.0.22.tgz", + "integrity": "sha512-cdHS6a8B6rYjLW+dlh2Q8FKOv3/y8ZAd+1bV0I1aNvoZS/vROWfQc2cf0AB0nBqM/GXlhrGbnPM+D35+0PkLBQ==", + "requires": { + "@yume-chan/async": "^2.2.0", + "@yume-chan/struct": "^0.0.22", + "tslib": "^2.6.2", + "web-streams-polyfill": "^4.0.0-beta.3" + } + }, + "@yume-chan/struct": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@yume-chan/struct/-/struct-0.0.22.tgz", + "integrity": "sha512-v3ETVutInqcRon0sJz8q97LxjC7+xJUx+5yowpNZlIEtbJQdQF2pgqkUXXhfZSWCUppY5Yg7foxCL+UZTSZBFA==", + "requires": { + "@yume-chan/dataview-bigint-polyfill": "^0.0.22", + "tslib": "^2.6.2" + } + }, "7zip-bin": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", @@ -13413,8 +14000,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -13442,6 +14028,16 @@ "postcss-value-parser": "^4.2.0" } }, + "axios": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", + "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "requires": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -13451,8 +14047,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "binary-extensions": { "version": "2.2.0", @@ -13464,7 +14059,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -13527,7 +14121,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -13923,7 +14516,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -14172,7 +14764,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, "requires": { "mimic-response": "^3.1.0" }, @@ -14180,11 +14771,15 @@ "mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" } } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -14233,8 +14828,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegates": { "version": "1.0.0", @@ -14245,8 +14839,7 @@ "detect-libc": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "dev": true + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" }, "detect-node": { "version": "2.1.0", @@ -14625,7 +15218,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -14996,6 +15588,11 @@ } } }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -15217,6 +15814,11 @@ } } }, + "follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==" + }, "foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -15231,7 +15833,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -15244,6 +15845,11 @@ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -15436,6 +16042,11 @@ "pump": "^3.0.0" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -15750,8 +16361,7 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "5.3.0", @@ -15800,14 +16410,12 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "interpret": { "version": "3.1.1", @@ -16455,14 +17063,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -16491,8 +17097,7 @@ "minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "minipass": { "version": "5.0.0", @@ -16666,6 +17271,11 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -16689,6 +17299,11 @@ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -16711,7 +17326,6 @@ "version": "3.54.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", - "dev": true, "requires": { "semver": "^7.3.5" } @@ -16760,6 +17374,11 @@ "which": "^2.0.2" } }, + "node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==" + }, "node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -16871,7 +17490,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "requires": { "wrappy": "1" } @@ -17268,6 +17886,25 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -17296,11 +17933,15 @@ "retry": "^0.12.0" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -17324,6 +17965,24 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, "rcedit": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/rcedit/-/rcedit-4.0.1.tgz", @@ -17500,7 +18159,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -17678,8 +18336,7 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", @@ -17714,7 +18371,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -17723,7 +18379,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -17731,8 +18386,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, @@ -17786,6 +18440,21 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -17968,7 +18637,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -18158,6 +18826,36 @@ } } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + } + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, "temp-file": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", @@ -18197,6 +18895,30 @@ } } }, + "terser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true, + "peer": true + } + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -18227,6 +18949,11 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, + "tinyh264": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/tinyh264/-/tinyh264-0.0.7.tgz", + "integrity": "sha512-etkBRgYkSFBdAi2Cqk4sZgi+xWs/vhzNgvjO3z2i4WILeEmORiNqxuQ4URJatrWQ9LPNV3WPWAtzsh/LA/XL/g==" + }, "tmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", @@ -18306,8 +19033,15 @@ "tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } }, "type-check": { "version": "0.4.0", @@ -18380,6 +19114,23 @@ "punycode": "^2.1.0" } }, + "usb": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.11.0.tgz", + "integrity": "sha512-u5+NZ6DtoW8TIBtuSArQGAZZ/K15i3lYvZBAYmcgI+RcDS9G50/KPrUd3CrU8M92ahyCvg5e0gc8BDvr5Hwejg==", + "requires": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^7.0.0", + "node-gyp-build": "^4.5.0" + }, + "dependencies": { + "node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" + } + } + }, "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -18405,8 +19156,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "validate-npm-package-license": { "version": "3.0.4", @@ -18464,6 +19214,11 @@ "defaults": "^1.0.3" } }, + "web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -18575,8 +19330,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "xmlbuilder": { "version": "15.1.1", @@ -18700,6 +19454,16 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true }, + "yuv-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yuv-buffer/-/yuv-buffer-1.0.0.tgz", + "integrity": "sha512-5r5u7g7Dbdrwao/z8c4harQIpZwaNuzXjQXtgdFxTjr5Pm2eMmxIuckkKOONEM7fkiMNkeffXs6EPNESvAVzVg==" + }, + "yuv-canvas": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/yuv-canvas/-/yuv-canvas-1.2.11.tgz", + "integrity": "sha512-LOxjD+gUO7XeHeExFEozpTEFBlbqEZOnaHLAwx4esJ2tzSWl/S/xDRSDu1N+asxYn7ldV+HtisrYAzJXkT7Rhw==" + }, "zustand": { "version": "4.4.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz", diff --git a/client-electron/package.json b/client-electron/package.json index e747b84..e905c50 100644 --- a/client-electron/package.json +++ b/client-electron/package.json @@ -2,24 +2,42 @@ "name": "client-electron", "private": true, "version": "0.0.1", + "author": { + "name": "Kenta420", + "email": "poomipat.c@forth.ac.th" + }, + "description": "An Application for Taobin to manage recipes and ingredients", "scripts": { - "dev": "concurrently \"npm run dev:electron\" \"npm run dev:web\"", + "dev": "concurrently \"APP_KIND=electron npm run dev:electron\" \"APP_KIND=web npm run dev:web\"", "dev:electron": "vite -c vite.config.electron.ts", "dev:web": "vite -c vite.config.web.ts --open", "build": "concurrently \"npm run build:electron\" \"npm run build:web\"", - "build:electron": "tsc && vite build -c vite.config.electron.ts --mode=production && electron-builder", - "build:web": "tsc && vite build -c vite.config.web.ts --mode=production", + "build:electron": "npm run prebuild:electron && tsc && vite build -c vite.config.electron.ts --mode=production && electron-builder", + "build:web": "npm run prebuild:web && tsc && vite build -c vite.config.web.ts --mode=production", + "prebuild:electron": "rm -rf dist-renderer && rm -rf dist-electron && vite optimize -c vite.config.electron.ts -m production", + "prebuild:web": "rm -rf dist-web && vite optimize -c vite.config.web.ts -m production", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" }, "dependencies": { + "@postman/node-keytar": "^7.9.3", + "@yume-chan/adb": "^0.0.22", + "@yume-chan/adb-credential-web": "^0.0.22", + "@yume-chan/adb-daemon-webusb": "^0.0.22", + "@yume-chan/adb-scrcpy": "^0.0.22", + "@yume-chan/scrcpy": "^0.0.22", + "@yume-chan/scrcpy-decoder-webcodecs": "^0.0.22", + "@yume-chan/stream-extra": "^0.0.22", + "axios": "^1.6.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1", + "usb": "^2.11.0", "zustand": "^4.4.7" }, "devDependencies": { "@electron-forge/cli": "^7.2.0", + "@electron/rebuild": "^3.5.0", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@typescript-eslint/eslint-plugin": "^6.18.1", diff --git a/client-electron/src/App.tsx b/client-electron/src/App.tsx index 4101fb2..0b8f85c 100644 --- a/client-electron/src/App.tsx +++ b/client-electron/src/App.tsx @@ -6,26 +6,36 @@ import { } from 'react-router-dom' import AuthCallBack from './AuthCallBack' import MainLayout from './layouts/MainLayout' -import Home from './pages/Home' +import HomePage from './pages/Home' +import LoginPage from './pages/Login' +import AndroidPage from './pages/Android' function router() { const routes: RouteObject[] = [ { path: '/', - element: ( - - - - ), + element: , children: [ + { + path: '/', + element: + }, { path: 'recipes', element:
Recipes
+ }, + { + path: 'android', + element: } ] }, { - path: '/auth/callback', + path: '/login', + element: + }, + { + path: '/callback', element: }, { @@ -38,8 +48,7 @@ function router() { ) } ] - - if (import.meta.env.MODE == 'electron') { + if (window.electronRuntime) { return createHashRouter(routes) } return createBrowserRouter(routes) diff --git a/client-electron/src/AuthCallBack.tsx b/client-electron/src/AuthCallBack.tsx index c2e7283..72e20c1 100644 --- a/client-electron/src/AuthCallBack.tsx +++ b/client-electron/src/AuthCallBack.tsx @@ -3,16 +3,24 @@ // then emit a message to the main process to close the window const AuthCallBack: React.FC = () => { const params = new URLSearchParams(window.location.search) - // emit message to main process + window.opener.postMessage( { payload: 'loginSuccess', - data: params + data: { + id: params.get('id'), + name: params.get('name'), + email: params.get('email'), + picture: params.get('picture'), + permissions: params.get('permissions') + } }, '*' ) + window.close() + return
it just call back
} diff --git a/client-electron/src/bin/scrcpy-server.bin b/client-electron/src/bin/scrcpy-server.bin new file mode 100644 index 0000000..02620a1 Binary files /dev/null and b/client-electron/src/bin/scrcpy-server.bin differ diff --git a/client-electron/src/hooks/adb.ts b/client-electron/src/hooks/adb.ts new file mode 100644 index 0000000..0a1204b --- /dev/null +++ b/client-electron/src/hooks/adb.ts @@ -0,0 +1,19 @@ +import { + type AdbDaemonWebUsbDevice, + AdbDaemonWebUsbDeviceManager +} from '@yume-chan/adb-daemon-webusb' +import { create } from 'zustand' + +interface ADB { + manager: AdbDaemonWebUsbDeviceManager | undefined + device: AdbDaemonWebUsbDevice | undefined + setDevice: (device: AdbDaemonWebUsbDevice | undefined) => void +} + +const useAdb = create(set => ({ + manager: AdbDaemonWebUsbDeviceManager.BROWSER, + device: undefined, + setDevice: device => set({ device }) +})) + +export default useAdb diff --git a/client-electron/src/hooks/userAuth.ts b/client-electron/src/hooks/userAuth.ts index 9bd27c8..4962aec 100644 --- a/client-electron/src/hooks/userAuth.ts +++ b/client-electron/src/hooks/userAuth.ts @@ -1,14 +1,40 @@ import { create } from 'zustand' +import customAxios from '../utils/customAxios' -interface UserAuth { - username: string | undefined - email: string | undefined +export interface UserInfo { + id: string + name: string + email: string + picture: string + permissions: string[] } -const userAuthStore = create(() => ({ - username: undefined, - email: undefined +interface UserAuth { + userInfo: UserInfo | null + setUserInfo: (userInfo: UserInfo | null) => void + getUserInfo: () => Promise + logout: () => void +} + +const userAuthStore = create(set => ({ + userInfo: null, + setUserInfo: userInfo => set({ userInfo }), + getUserInfo: () => { + return customAxios + .get('/user/me') + .then(res => { + set({ userInfo: res.data }) + return res.data + }) + .catch(() => { + set({ userInfo: null }) + return null + }) + }, + logout: () => { + customAxios.post('/auth/logout') + set({ userInfo: null }) + } })) -export const getUserName = userAuthStore(state => state.username) -export const getUserEmail = userAuthStore(state => state.email) +export default userAuthStore diff --git a/client-electron/src/layouts/MainLayout.tsx b/client-electron/src/layouts/MainLayout.tsx index f14b490..626e856 100644 --- a/client-electron/src/layouts/MainLayout.tsx +++ b/client-electron/src/layouts/MainLayout.tsx @@ -1,12 +1,41 @@ +import { Outlet, useNavigate } from 'react-router-dom' import Header from '../components/Header' import Sidebar from '../components/Sidebar' +import userAuthStore from '../hooks/userAuth' +import { useShallow } from 'zustand/react/shallow' +import { useCallback } from 'react' + +const MainLayout = () => { + const { userInfo, getUserInfo } = userAuthStore( + useShallow(state => ({ + userInfo: state.userInfo, + getUserInfo: state.getUserInfo + })) + ) + const navigate = useNavigate() + + // get current path + const currentPath = window.location.pathname + + useCallback(() => { + console.log(import.meta.env.NODE_ENV) + if (!userInfo && import.meta.env.NODE_ENV !== 'development') { + getUserInfo().then(userInfo => { + // if still not login then redirect to login page + if (!userInfo) { + navigate('/login?redirect=' + currentPath) + } + }) + } + }, [userInfo, getUserInfo, navigate, currentPath]) -const MainLayout = ({ children }: React.PropsWithChildren) => { return (
-
{children}
+
+ +
) } diff --git a/client-electron/src/main.tsx b/client-electron/src/main.tsx index 8a0ca26..a6efab7 100644 --- a/client-electron/src/main.tsx +++ b/client-electron/src/main.tsx @@ -9,9 +9,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render( ) -console.log(import.meta.env.MODE) - -if (import.meta.env.MODE === 'electron') { +if (window.electronRuntime) { // Remove Preload scripts loading postMessage({ payload: 'removeLoading' }, '*') @@ -20,6 +18,41 @@ if (import.meta.env.MODE === 'electron') { console.log(message) }) + window.ipcRenderer + .invoke( + 'keyChainSync', + import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_SERVICE_NAME + ) + .then(result => { + console.log(result) + }) + + // getPassword( + // import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_SERVICE_NAME, + // import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_ACCOUNT_ACCESS_TOKEN + // ).then(tokenMaxAge => { + // if (tokenMaxAge) { + // const [token, max_age] = tokenMaxAge.split(';') + // document.cookie = + // 'access_token=' + + // token + + // '; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=' + + // max_age + // } + // }) + + // getPassword( + // import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_SERVICE_NAME, + // import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_ACCOUNT_REFRESH_TOKEN + // ).then(refreshToken => { + // if (refreshToken) { + // document.cookie = + // 'refresh_token=' + + // refreshToken + + // '; Path=/; HttpOnly; SameSite=None; Secure;' + // } + // }) + // Use deep link window.ipcRenderer.on('deeplink', (_event, url) => { console.log(url) diff --git a/client-electron/src/pages/Android.tsx b/client-electron/src/pages/Android.tsx new file mode 100644 index 0000000..52336ba --- /dev/null +++ b/client-electron/src/pages/Android.tsx @@ -0,0 +1,178 @@ +import { useShallow } from 'zustand/react/shallow' +import { ADB_DEFAULT_DEVICE_FILTER } from '@yume-chan/adb-daemon-webusb' +import AdbWebCredentialStore from '@yume-chan/adb-credential-web' +import { Adb, AdbDaemonTransport } from '@yume-chan/adb' +import useAdb from '../hooks/adb' +import type { AdbScrcpyVideoStream } from '@yume-chan/adb-scrcpy' +import { AdbScrcpyClient, AdbScrcpyOptions2_1 } from '@yume-chan/adb-scrcpy' +import { WebCodecsDecoder } from '@yume-chan/scrcpy-decoder-webcodecs' +import { + ScrcpyLogLevel1_18, + ScrcpyOptions2_1, + ScrcpyVideoCodecId +} from '@yume-chan/scrcpy' +import { useState } from 'react' + +const ScreenStream: React.FC<{ child: HTMLCanvasElement }> = ({ + child +}: { + child: HTMLCanvasElement +}) => { + return
ref?.appendChild(child)}>
+} + +const AndroidPage: React.FC = () => { + const { manager, device, setDevice } = useAdb( + useShallow(state => ({ + manager: state.manager, + device: state.device, + setDevice: state.setDevice + })) + ) + + const [decoder, setDecoder] = useState() + const [client, setClient] = useState() + const [adbClient, setAdbClient] = useState(undefined) + + function attachDevice() { + manager + ?.requestDevice({ + filters: [ + { + ...ADB_DEFAULT_DEVICE_FILTER, + vendorId: 1478 + } + ] + }) + .then(selectedDevice => { + if (!selectedDevice) { + return + } else { + setDevice(selectedDevice) + } + }) + } + + function disConnectDevice() { + device?.raw.forget() + setDevice(undefined) + } + + // function reboot() { + // device?.connect().then(connection => { + // const credentialStore: AdbWebCredentialStore = new AdbWebCredentialStore() + + // AdbDaemonTransport.authenticate({ + // serial: device?.serial, + // connection, + // credentialStore: credentialStore + // }).then(transport => { + // const adb: Adb = new Adb(transport) + + // adb.power.reboot().then(() => { + // console.log('reboot success') + // }) + // }) + // }) + // } + + async function scrcpyConnect() { + // const url = new URL('../bin/scrcpy-server.bin', import.meta.url) + // const server: ArrayBuffer = await fetch(url).then(res => res.arrayBuffer()) + + const connection = await device?.connect() + + const credentialStore: AdbWebCredentialStore = new AdbWebCredentialStore() + + const transport = await AdbDaemonTransport.authenticate({ + serial: device!.serial, + connection: connection!, + credentialStore: credentialStore + }) + + const adb: Adb = new Adb(transport) + setAdbClient(adb) + // await AdbScrcpyClient.pushServer( + // adb, + // new ReadableStream({ + // start(controller) { + // controller.enqueue(new Consumable(new Uint8Array(server))) + // controller.close() + // } + // }) + // ) + + await adb.subprocess.spawn( + 'CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server 2.1' + ) + + const scrcpyOption = new ScrcpyOptions2_1({ + audio: false, + maxFps: 60, + control: false, + video: true, + logLevel: ScrcpyLogLevel1_18.Debug, + videoCodec: 'h264', + stayAwake: true, + cleanup: true + }) + const _client = await AdbScrcpyClient.start( + adb, + '/data/local/tmp/scrcpy-server.jar', + '2.1', + new AdbScrcpyOptions2_1(scrcpyOption) + ) + + setClient(_client) + } + + async function scrcpyStream() { + const videoStream: AdbScrcpyVideoStream | undefined = + await client?.videoStream + const _decoder = new WebCodecsDecoder(ScrcpyVideoCodecId.H264) + videoStream?.stream.pipeTo(_decoder.writable) + setDecoder(_decoder) + } + + function scrcpyDisconnect() { + client?.close() + setClient(undefined) + setDecoder(undefined) + } + + function rebootDevice() { + adbClient?.power.reboot() + } + + return ( +
+

This is Android Page!!!!!!!

+ {device ?

Device: {device.name}

:

No Device

} +
+ + + +
+
+ + + +
+ {decoder ? : ''} +
+ ) +} + +export default AndroidPage diff --git a/client-electron/src/pages/Home.tsx b/client-electron/src/pages/Home.tsx index 02a4546..478701e 100644 --- a/client-electron/src/pages/Home.tsx +++ b/client-electron/src/pages/Home.tsx @@ -1,51 +1,15 @@ import React from 'react' -import googleLogo from '../assets/google-color.svg' - -const Home: React.FC = () => { - console.log(import.meta.env.TAOBIN_RECIPE_MANAGER_SERVER_URL) - - const loginWithGoogle = () => { - // if is web mode then use window.open - // if is electron mode then use ipcRenderer.send to use deep link method - if (import.meta.env.MODE === 'web') { - // open new window and listen to message from window.opener - const newWindow = window.open( - import.meta.env.TAOBIN_RECIPE_MANAGER_SERVER_URL, - '_blank', - 'width=500,height=600' - ) - - // listen to message from new window - window.addEventListener('message', event => { - if (event.data.payload === 'loginSuccess') { - // close new window - newWindow?.close() - - console.log(event.data) - } - }) - } else { - window.ipcRenderer.send('deeplink', 'http://127.0.0.1:5500/test.html') - } - } +import { Link } from 'react-router-dom' +const HomePage: React.FC = () => { return (

This is Home Page!!!!!!!

-
) } -export default Home +export default HomePage diff --git a/client-electron/src/pages/Login.tsx b/client-electron/src/pages/Login.tsx new file mode 100644 index 0000000..177ff6b --- /dev/null +++ b/client-electron/src/pages/Login.tsx @@ -0,0 +1,85 @@ +import { useNavigate } from 'react-router-dom' +import googleLogo from '../assets/google-color.svg' +import userAuthStore, { type UserInfo } from '../hooks/userAuth' + +const LoginPage: React.FC = () => { + const setUserInfo = userAuthStore(state => state.setUserInfo) + const navigate = useNavigate() + + const redirectUrl = + new URLSearchParams(window.location.search).get('redirect') ?? '/' + + const loginWithGoogle = () => { + // if is web mode then use window.open + // if is electron mode then use ipcRenderer.send to use deep link method + if (window.electronRuntime) { + window.ipcRenderer.send( + 'deeplink', + import.meta.env.TAOBIN_RECIPE_MANAGER_SERVER_URL + + '/auth/google?redirect_to=' + + redirectUrl + + '&kind=electron' + ) + + window.ipcRenderer.on('loginSuccess', (_event, data) => { + console.log(data) + + setUserInfo(data satisfies UserInfo) + navigate(redirectUrl) + }) + } else { + // open new window and listen to message from window.opener + window.open( + import.meta.env.TAOBIN_RECIPE_MANAGER_SERVER_URL + + '/auth/google?redirect_to=' + + redirectUrl, + '_blank', + 'width=500,height=600' + ) + + // listen to message from new window + window.addEventListener('message', event => { + if (event.data.payload === 'loginSuccess') { + // const { access_token, max_age, refresh_token } = event.data.data + + // setPassword( + // import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_SERVICE_NAME, + // import.meta.env + // .TAOBIN_RECIPE_MANAGER_KEY_CHAIN_ACCOUNT_ACCESS_TOKEN, + // access_token + ';' + max_age + // ) + + // setPassword( + // import.meta.env.TAOBIN_RECIPE_MANAGER_KEY_CHAIN_SERVICE_NAME, + // import.meta.env + // .TAOBIN_RECIPE_MANAGER_KEY_CHAIN_ACCOUNT_REFRESH_TOKEN, + // refresh_token + // ) + + setUserInfo(event.data.data satisfies UserInfo) + + navigate(redirectUrl) + } + }) + } + } + + return ( +
+ +
+ ) +} + +export default LoginPage diff --git a/client-electron/src/services/usb.service.ts b/client-electron/src/services/usb.service.ts new file mode 100644 index 0000000..0f996d7 --- /dev/null +++ b/client-electron/src/services/usb.service.ts @@ -0,0 +1,14 @@ +import { AdbDaemonWebUsbDeviceManager } from '@yume-chan/adb-daemon-webusb' + +const Manager: AdbDaemonWebUsbDeviceManager | undefined = + AdbDaemonWebUsbDeviceManager.BROWSER + +export async function getDevices() { + if (!Manager) { + alert('WebUSB is not supported in this browser') + return + } + + const devices = await Manager.getDevices() + return devices +} diff --git a/client-electron/src/utils/customAxios.ts b/client-electron/src/utils/customAxios.ts new file mode 100644 index 0000000..44ff691 --- /dev/null +++ b/client-electron/src/utils/customAxios.ts @@ -0,0 +1,26 @@ +import axios from 'axios' + +const customAxios = axios.create({ + baseURL: import.meta.env.TAOBIN_RECIPE_MANAGER_SERVER_URL, + withCredentials: true +}) + +customAxios.interceptors.response.use( + res => res, + err => { + const originalRequest = err.config + + if (err.response.status === 401 && !originalRequest._retry) { + originalRequest._retry = true + return customAxios.get('/auth/refresh').then(res => { + if (res.status === 200) { + return customAxios(originalRequest) + } + }) + } + + return Promise.reject(err) + } +) + +export default customAxios diff --git a/client-electron/src/vite-env.d.ts b/client-electron/src/vite-env.d.ts index 11f02fe..42b9465 100644 --- a/client-electron/src/vite-env.d.ts +++ b/client-electron/src/vite-env.d.ts @@ -1 +1,9 @@ /// + +interface ImportMetaEnv { + TAOBIN_RECIPE_MANAGER_SERVER_URL: string + TAOBIN_RECIPE_MANAGER_KEY_CHAIN_SERVICE_NAME: string + TAOBIN_RECIPE_MANAGER_KEY_CHAIN_ACCOUNT_ACCESS_TOKEN: string + TAOBIN_RECIPE_MANAGER_KEY_CHAIN_ACCOUNT_REFRESH_TOKEN: string + MAIN_VITE_TEST: boolean +} diff --git a/client-electron/vite.config.electron.ts b/client-electron/vite.config.electron.ts index e7a43b0..3230caf 100644 --- a/client-electron/vite.config.electron.ts +++ b/client-electron/vite.config.electron.ts @@ -5,14 +5,20 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ - mode: 'electron', envPrefix: 'TAOBIN_RECIPE_MANAGER_', plugins: [ react(), electron({ main: { // Shortcut of `build.lib.entry`. - entry: 'electron/main.ts' + entry: 'electron/main.ts', + vite: { + build: { + rollupOptions: { + external: ['@postman/node-keytar'] + } + } + } }, preload: { // Shortcut of `build.rollupOptions.input`. diff --git a/client-electron/vite.config.web.ts b/client-electron/vite.config.web.ts index fb2166c..6bd0db0 100644 --- a/client-electron/vite.config.web.ts +++ b/client-electron/vite.config.web.ts @@ -3,12 +3,14 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ - mode: 'web', envPrefix: 'TAOBIN_RECIPE_MANAGER_', plugins: [react()], build: { outDir: 'dist-web' }, + optimizeDeps: { + exclude: ['node-keytar'] + }, server: { port: 4200 } diff --git a/server/config/config.go b/server/config/config.go index b6eb0cc..cfec16d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -1,10 +1,11 @@ package config type ServerConfig struct { - ServerPort uint `mapstructure:"SERVER_PORT"` - AllowedOrigins string `mapstructure:"ALLOWED_ORIGINS"` - ClientRedirectURL string `mapstructure:"CLIENT_REDIRECT_URL"` - ServerDomain string `mapstructure:"SERVER_DOMAIN"` - APIKey string `mapstructure:"API_KEY"` - Debug bool `mapstructure:"DEBUG_MODE"` + ServerPort uint `mapstructure:"SERVER_PORT"` + AllowedOrigins string `mapstructure:"ALLOWED_ORIGINS"` + ClientRedirectURL string `mapstructure:"CLIENT_REDIRECT_URL"` + ClientElectronRedirectURL string `mapstructure:"CLIENT_ELECTRON_REDIRECT_URL"` + ServerDomain string `mapstructure:"SERVER_DOMAIN"` + APIKey string `mapstructure:"API_KEY"` + Debug bool `mapstructure:"DEBUG_MODE"` } diff --git a/server/routers/auth.go b/server/routers/auth.go index a51bae2..fee4cf9 100644 --- a/server/routers/auth.go +++ b/server/routers/auth.go @@ -4,9 +4,7 @@ import ( "context" "crypto/rand" "encoding/base64" - "github.com/go-chi/chi/v5" - "go.uber.org/zap" - "golang.org/x/oauth2" + "encoding/json" "net/http" "net/url" "recipe-manager/config" @@ -15,6 +13,10 @@ import ( "recipe-manager/services/user" "strconv" "time" + + "github.com/go-chi/chi/v5" + "go.uber.org/zap" + "golang.org/x/oauth2" ) type AuthRouter struct { @@ -42,6 +44,10 @@ func (ar *AuthRouter) Route(r chi.Router) { stateMap["redirect_to"] = r.URL.Query().Get("redirect_to") } + if r.URL.Query().Get("kind") != "" { + stateMap["kind"] = r.URL.Query().Get("kind") + } + authURL := ar.oauth.AuthURL(state, stateMap) http.Redirect(w, r, authURL, http.StatusTemporaryRedirect) }) @@ -52,6 +58,7 @@ func (ar *AuthRouter) Route(r chi.Router) { defer cancel() var redirectTo string + var kind string state := r.URL.Query().Get("state") if state == "" { http.Error(w, "State not found", http.StatusBadRequest) @@ -65,6 +72,7 @@ func (ar *AuthRouter) Route(r chi.Router) { } redirectTo = val["redirect_to"] + kind = val["kind"] ar.oauth.RemoveState(state) } @@ -115,12 +123,62 @@ func (ar *AuthRouter) Route(r chi.Router) { ar.taoLogger.Log.Info("User Log-In Success", zap.String("userInfo", userInfo.Name), zap.String("email", userInfo.Email)) + if kind == "electron" { + value.Add("access_token", token.AccessToken) + value.Add("max_age", "3600") + value.Add("refresh_token", token.RefreshToken) + http.Redirect(w, r, ar.cfg.ClientElectronRedirectURL+"login?"+value.Encode(), http.StatusTemporaryRedirect) + return + } // redirect to frontend with token and refresh token w.Header().Add("set-cookie", "access_token="+token.AccessToken+"; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=3600") w.Header().Add("set-cookie", "refresh_token="+token.RefreshToken+"; Path=/; HttpOnly; SameSite=None; Secure") http.Redirect(w, r, ar.cfg.ClientRedirectURL+"/?"+value.Encode(), http.StatusTemporaryRedirect) }) + r.Get("/me", func(w http.ResponseWriter, r *http.Request) { + // get access token from cookie + cookie, err := r.Cookie("access_token") + if err != nil { + http.Error(w, "Access token not found", http.StatusBadRequest) + return + } + + // get userInfo info + userInfo, err := ar.oauth.GetUserInfo(r.Context(), &oauth2.Token{AccessToken: cookie.Value}) + if err != nil { + http.Error(w, "Error getting userInfo info", http.StatusBadRequest) + return + } + + // map with database + userFromDb, err := ar.userService.GetUserByEmail(r.Context(), userInfo.Email) + if err != nil { + http.Error(w, "Error while getting user data from database.", http.StatusInternalServerError) + return + } + + if userFromDb == nil { + http.Error(w, "Unauthorized, We not found your email, Please contact admin.", http.StatusUnauthorized) + return + } + + picture := userInfo.Picture + if userFromDb.Picture != "" { + picture = userFromDb.Picture + } + + value := url.Values{ + "id": {userFromDb.ID}, + "name": {userFromDb.Name}, + "email": {userInfo.Email}, + "picture": {picture}, + "permissions": {strconv.Itoa(int(userFromDb.Permissions))}, + } + + json.NewEncoder(w).Encode(value) + }) + r.Get("/refresh", func(w http.ResponseWriter, r *http.Request) { // get refresh token from query string refreshToken := r.URL.Query().Get("refresh_token")