mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(plex/utils): added Plex OAuth class
This commit is contained in:
@@ -3,13 +3,16 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon -e ts -x ts-node --project server/tsconfig.json server/index.ts",
|
"dev": "nodemon -e ts --watch server -x ts-node --project server/tsconfig.json server/index.ts",
|
||||||
"build:server": "tsc --project server/tsconfig.json",
|
"build:server": "tsc --project server/tsconfig.json",
|
||||||
"build:next": "next build",
|
"build:next": "next build",
|
||||||
"build": "yarn build:next && yarn build:server",
|
"build": "yarn build:next && yarn build:server",
|
||||||
"start": "NODE_ENV=production node dist/server/index.js"
|
"start": "NODE_ENV=production node dist/server/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tailwindcss/ui": "^0.5.0",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"bowser": "^2.10.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"next": "9.5.2",
|
"next": "9.5.2",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import '../styles/globals.css';
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }) {
|
|
||||||
return <Component {...pageProps} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyApp;
|
|
12
src/pages/_app.tsx
Normal file
12
src/pages/_app.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import '../styles/globals.css';
|
||||||
|
import App from 'next/app';
|
||||||
|
|
||||||
|
class CoreApp extends App {
|
||||||
|
public render(): JSX.Element {
|
||||||
|
const { Component, pageProps } = this.props;
|
||||||
|
return <Component {...pageProps} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CoreApp;
|
39
src/pages/plextest.tsx
Normal file
39
src/pages/plextest.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { NextPage } from 'next';
|
||||||
|
import PlexOAuth from '../utils/plex';
|
||||||
|
|
||||||
|
const plexOAuth = new PlexOAuth();
|
||||||
|
|
||||||
|
const PlexText: NextPage = () => {
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [authToken, setAuthToken] = useState<string>('');
|
||||||
|
|
||||||
|
const getPlexLogin = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const authToken = await plexOAuth.login();
|
||||||
|
setAuthToken(authToken);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span className="inline-flex rounded-md shadow-sm">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => getPlexLogin()}
|
||||||
|
disabled={loading}
|
||||||
|
className="inline-flex items-center px-6 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150"
|
||||||
|
>
|
||||||
|
{loading ? 'Loading...' : 'Plex Login'}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<div className="mt-4">Auth Token: {authToken}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlexText;
|
213
src/utils/plex.ts
Normal file
213
src/utils/plex.ts
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import Bowser from 'bowser';
|
||||||
|
|
||||||
|
interface PlexHeaders {
|
||||||
|
Accept: string;
|
||||||
|
'X-Plex-Product': string;
|
||||||
|
'X-Plex-Version': string;
|
||||||
|
'X-Plex-Client-Identifier': string;
|
||||||
|
'X-Plex-Model': string;
|
||||||
|
'X-Plex-Platform': string;
|
||||||
|
'X-Plex-Platform-Version': string;
|
||||||
|
'X-Plex-Device': string;
|
||||||
|
'X-Plex-Device-Name': string;
|
||||||
|
'X-Plex-Device-Screen-Resolution': string;
|
||||||
|
'X-Plex-Language': string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlexPin {
|
||||||
|
id: number;
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlexOAuth {
|
||||||
|
private plexHeaders?: PlexHeaders;
|
||||||
|
|
||||||
|
private pin?: PlexPin;
|
||||||
|
private popup?: Window;
|
||||||
|
|
||||||
|
private authToken?: string;
|
||||||
|
|
||||||
|
public initializeHeaders(): void {
|
||||||
|
if (!window) {
|
||||||
|
throw new Error(
|
||||||
|
'Window is not defined. Are you calling this in the browser?'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const browser = Bowser.getParser(window.navigator.userAgent);
|
||||||
|
this.plexHeaders = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'X-Plex-Product': 'Overseerr',
|
||||||
|
'X-Plex-Version': '2.0',
|
||||||
|
'X-Plex-Client-Identifier': '7f9de3ba-e12b-11ea-87d0-0242ac130003',
|
||||||
|
'X-Plex-Model': 'Plex OAuth',
|
||||||
|
'X-Plex-Platform': browser.getOSName(),
|
||||||
|
'X-Plex-Platform-Version': browser.getOSVersion(),
|
||||||
|
'X-Plex-Device': browser.getBrowserName(),
|
||||||
|
'X-Plex-Device-Name': browser.getBrowserVersion(),
|
||||||
|
'X-Plex-Device-Screen-Resolution':
|
||||||
|
window.screen.width + 'x' + window.screen.height,
|
||||||
|
'X-Plex-Language': 'en',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getPin(): Promise<PlexPin> {
|
||||||
|
if (!this.plexHeaders) {
|
||||||
|
throw new Error(
|
||||||
|
'You must initialize the plex headers clientside to login'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await axios.post(
|
||||||
|
'https://plex.tv/api/v2/pins?strong=true',
|
||||||
|
undefined,
|
||||||
|
{ headers: this.plexHeaders }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.pin = { id: response.data.id, code: response.data.code };
|
||||||
|
|
||||||
|
return this.pin;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login(): Promise<string> {
|
||||||
|
try {
|
||||||
|
this.initializeHeaders();
|
||||||
|
await this.getPin();
|
||||||
|
|
||||||
|
if (!this.plexHeaders || !this.pin) {
|
||||||
|
throw new Error('Unable to call login if class is not initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
clientID: this.plexHeaders['X-Plex-Client-Identifier'],
|
||||||
|
'context[device][product]': this.plexHeaders['X-Plex-Product'],
|
||||||
|
'context[device][version]': this.plexHeaders['X-Plex-Version'],
|
||||||
|
'context[device][platform]': this.plexHeaders['X-Plex-Platform'],
|
||||||
|
'context[device][platformVersion]': this.plexHeaders[
|
||||||
|
'X-Plex-Platform-Version'
|
||||||
|
],
|
||||||
|
'context[device][device]': this.plexHeaders['X-Plex-Device'],
|
||||||
|
'context[device][deviceName]': this.plexHeaders['X-Plex-Device-Name'],
|
||||||
|
'context[device][model]': this.plexHeaders['X-Plex-Model'],
|
||||||
|
'context[device][screenResolution]': this.plexHeaders[
|
||||||
|
'X-Plex-Device-Screen-Resolution'
|
||||||
|
],
|
||||||
|
'context[device][layout]': 'desktop',
|
||||||
|
code: this.pin.code,
|
||||||
|
};
|
||||||
|
this.openPopup({
|
||||||
|
url: `https://app.plex.tv/auth/#!?${this.encodeData(params)}`,
|
||||||
|
title: 'Plex Auth',
|
||||||
|
w: 600,
|
||||||
|
h: 700,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.pinPoll();
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async pinPoll(): Promise<string> {
|
||||||
|
const executePoll = async (
|
||||||
|
resolve: (authToken: string) => void,
|
||||||
|
reject: (e: Error) => void
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
if (!this.pin) {
|
||||||
|
throw new Error('Unable to poll when pin is not initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.get(
|
||||||
|
`https://plex.tv/api/v2/pins/${this.pin.id}`,
|
||||||
|
{ headers: this.plexHeaders }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.data?.authToken) {
|
||||||
|
this.authToken = response.data.authToken;
|
||||||
|
this.closePopup();
|
||||||
|
resolve(response.data.authToken);
|
||||||
|
} else if (!response.data?.authToken && !this.popup?.closed) {
|
||||||
|
setTimeout(executePoll, 1000, resolve, reject);
|
||||||
|
} else {
|
||||||
|
reject(new Error('Popup closed without completing login'));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.closePopup();
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise(executePoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private closePopup(): void {
|
||||||
|
this.popup?.close();
|
||||||
|
this.popup = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private openPopup({
|
||||||
|
url,
|
||||||
|
title,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
}: {
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
}): Window | void {
|
||||||
|
if (!window) {
|
||||||
|
throw new Error(
|
||||||
|
'Window is undefined. Are you running this in the browser?'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Fixes dual-screen position Most browsers Firefox
|
||||||
|
const dualScreenLeft =
|
||||||
|
window.screenLeft != undefined ? window.screenLeft : window.screenX;
|
||||||
|
const dualScreenTop =
|
||||||
|
window.screenTop != undefined ? window.screenTop : window.screenY;
|
||||||
|
const width = window.innerWidth
|
||||||
|
? window.innerWidth
|
||||||
|
: document.documentElement.clientWidth
|
||||||
|
? document.documentElement.clientWidth
|
||||||
|
: screen.width;
|
||||||
|
const height = window.innerHeight
|
||||||
|
? window.innerHeight
|
||||||
|
: document.documentElement.clientHeight
|
||||||
|
? document.documentElement.clientHeight
|
||||||
|
: screen.height;
|
||||||
|
const left = width / 2 - w / 2 + dualScreenLeft;
|
||||||
|
const top = height / 2 - h / 2 + dualScreenTop;
|
||||||
|
const newWindow = window.open(
|
||||||
|
url,
|
||||||
|
title,
|
||||||
|
'scrollbars=yes, width=' +
|
||||||
|
w +
|
||||||
|
', height=' +
|
||||||
|
h +
|
||||||
|
', top=' +
|
||||||
|
top +
|
||||||
|
', left=' +
|
||||||
|
left
|
||||||
|
);
|
||||||
|
if (newWindow) {
|
||||||
|
newWindow.focus();
|
||||||
|
this.popup = newWindow;
|
||||||
|
return this.popup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private encodeData(data: Record<string, string>): string {
|
||||||
|
return Object.keys(data)
|
||||||
|
.map(function (key) {
|
||||||
|
return [key, data[key]].map(encodeURIComponent).join('=');
|
||||||
|
})
|
||||||
|
.join('&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlexOAuth;
|
3
src/utils/typeHelpers.ts
Normal file
3
src/utils/typeHelpers.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export type Undefinable<T> = T | undefined;
|
||||||
|
export type Nullable<T> = T | null;
|
||||||
|
export type Maybe<T> = T | null | undefined;
|
@@ -1,8 +1,13 @@
|
|||||||
|
/* eslint-disable */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
purge: ['./pages/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
|
purge: ['./pages/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
variants: {},
|
variants: {},
|
||||||
plugins: [],
|
plugins: [
|
||||||
|
require('@tailwindcss/ui')({
|
||||||
|
layout: 'sidebar',
|
||||||
|
}),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
@@ -1,14 +1,10 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
@@ -18,12 +14,6 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve"
|
"jsx": "preserve"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"next-env.d.ts",
|
"exclude": ["node_modules"]
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
62
yarn.lock
62
yarn.lock
@@ -1218,6 +1218,30 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
defer-to-connect "^1.0.1"
|
defer-to-connect "^1.0.1"
|
||||||
|
|
||||||
|
"@tailwindcss/custom-forms@^0.2.1":
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/custom-forms/-/custom-forms-0.2.1.tgz#40e5ed1fff6d29d8ed1c508a0b2aaf8da96962e0"
|
||||||
|
integrity sha512-XdP5XY6kxo3x5o50mWUyoYWxOPV16baagLoZ5uM41gh6IhXzhz/vJYzqrTb/lN58maGIKlpkxgVsQUNSsbAS3Q==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.11"
|
||||||
|
mini-svg-data-uri "^1.0.3"
|
||||||
|
traverse "^0.6.6"
|
||||||
|
|
||||||
|
"@tailwindcss/typography@^0.2.0":
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.2.0.tgz#b597c83502e3c3c6641a8aaabda223cd494ab349"
|
||||||
|
integrity sha512-aPgMH+CjQiScLZculoDNOQUrrK2ktkbl3D6uCLYp1jgYRlNDrMONu9nMu8LfwAeetYNpVNeIGx7WzHSu0kvECg==
|
||||||
|
|
||||||
|
"@tailwindcss/ui@^0.5.0":
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/ui/-/ui-0.5.0.tgz#c3b274222a57484757e664bc71c4f5288461c9ad"
|
||||||
|
integrity sha512-UbKe9ti0uMXN2lmgaFgNJC/DY4s2izLaowhIn2A4AgmplC2+XzcYJ9vHLLNNXNBthDq9X+js92tpxey6dBjgfw==
|
||||||
|
dependencies:
|
||||||
|
"@tailwindcss/custom-forms" "^0.2.1"
|
||||||
|
"@tailwindcss/typography" "^0.2.0"
|
||||||
|
hex-rgb "^4.1.0"
|
||||||
|
postcss-selector-parser "^6.0.2"
|
||||||
|
|
||||||
"@types/body-parser@*":
|
"@types/body-parser@*":
|
||||||
version "1.19.0"
|
version "1.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
|
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
|
||||||
@@ -1950,6 +1974,13 @@ axe-core@^3.5.4:
|
|||||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227"
|
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227"
|
||||||
integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==
|
integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==
|
||||||
|
|
||||||
|
axios@^0.19.2:
|
||||||
|
version "0.19.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||||
|
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "1.5.10"
|
||||||
|
|
||||||
axobject-query@^2.1.2:
|
axobject-query@^2.1.2:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
||||||
@@ -2070,6 +2101,11 @@ body-parser@1.19.0:
|
|||||||
raw-body "2.4.0"
|
raw-body "2.4.0"
|
||||||
type-is "~1.6.17"
|
type-is "~1.6.17"
|
||||||
|
|
||||||
|
bowser@^2.10.0:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.10.0.tgz#be3736f161c4bb8b10958027ab99465d2a811198"
|
||||||
|
integrity sha512-OCsqTQboTEWWsUjcp5jLSw2ZHsBiv2C105iFs61bOT0Hnwi9p7/uuXdd7mu8RYcarREfdjNN+8LitmEHATsLYg==
|
||||||
|
|
||||||
boxen@^4.2.0:
|
boxen@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
|
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
|
||||||
@@ -3102,6 +3138,13 @@ debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "^2.1.1"
|
ms "^2.1.1"
|
||||||
|
|
||||||
|
debug@=3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||||
|
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||||
|
dependencies:
|
||||||
|
ms "2.0.0"
|
||||||
|
|
||||||
debug@^3.2.6:
|
debug@^3.2.6:
|
||||||
version "3.2.6"
|
version "3.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||||
@@ -4016,6 +4059,13 @@ flush-write-stream@^1.0.0:
|
|||||||
inherits "^2.0.3"
|
inherits "^2.0.3"
|
||||||
readable-stream "^2.3.6"
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
|
follow-redirects@1.5.10:
|
||||||
|
version "1.5.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||||
|
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||||
|
dependencies:
|
||||||
|
debug "=3.1.0"
|
||||||
|
|
||||||
for-in@^1.0.2:
|
for-in@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||||
@@ -4424,6 +4474,11 @@ he@1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||||
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
|
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
|
||||||
|
|
||||||
|
hex-rgb@^4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.1.0.tgz#2d5d3a2943bd40e7dc9b0d5b98903d7d17035967"
|
||||||
|
integrity sha512-n7xsIfyBkFChITGPh6FLtxNzAt2HxZLcQIY9hYH4gm2gmMQJHMguMH3E+jnmvUbSTF5QrmFnGab5Ippi+D7e/g==
|
||||||
|
|
||||||
highlight.js@^9.6.0:
|
highlight.js@^9.6.0:
|
||||||
version "9.18.3"
|
version "9.18.3"
|
||||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634"
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634"
|
||||||
@@ -5508,6 +5563,11 @@ mini-css-extract-plugin@0.8.0:
|
|||||||
schema-utils "^1.0.0"
|
schema-utils "^1.0.0"
|
||||||
webpack-sources "^1.1.0"
|
webpack-sources "^1.1.0"
|
||||||
|
|
||||||
|
mini-svg-data-uri@^1.0.3:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.2.3.tgz#e16baa92ad55ddaa1c2c135759129f41910bc39f"
|
||||||
|
integrity sha512-zd6KCAyXgmq6FV1mR10oKXYtvmA9vRoB6xPSTUJTbFApCtkefDnYueVR1gkof3KcdLZo1Y8mjF2DFmQMIxsHNQ==
|
||||||
|
|
||||||
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||||
@@ -8381,7 +8441,7 @@ tr46@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
traverse@0.6.6:
|
traverse@0.6.6, traverse@^0.6.6:
|
||||||
version "0.6.6"
|
version "0.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
|
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
|
||||||
integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=
|
integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=
|
||||||
|
Reference in New Issue
Block a user