mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-22 09:57:00 +01:00
Auth and session middleware.
This commit is contained in:
parent
590a70c2ff
commit
d81ee3932d
36
components/Chart.js
vendored
36
components/Chart.js
vendored
@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useMemo, useRef, useEffect } from 'react';
|
import React, { useState, useMemo, useRef, useEffect } from 'react';
|
||||||
import ChartJS from 'chart.js';
|
import ChartJS from 'chart.js';
|
||||||
import { format, subDays, subHours, startOfHour } from 'date-fns';
|
|
||||||
import { get } from 'lib/web';
|
import { get } from 'lib/web';
|
||||||
|
import { getTimezone, getLocalTime } from 'lib/date';
|
||||||
|
|
||||||
export default function Chart({ websiteId, startDate, endDate }) {
|
export default function Chart({ websiteId, startDate, endDate }) {
|
||||||
const [data, setData] = useState();
|
const [data, setData] = useState();
|
||||||
@ -9,21 +9,7 @@ export default function Chart({ websiteId, startDate, endDate }) {
|
|||||||
const chart = useRef();
|
const chart = useRef();
|
||||||
const metrics = useMemo(() => {
|
const metrics = useMemo(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
const points = {};
|
return data.pageviews.map(({ t, y }) => ({ t: getLocalTime(t), y }));
|
||||||
const now = startOfHour(new Date());
|
|
||||||
|
|
||||||
for (let i = 0; i <= 168; i++) {
|
|
||||||
const d = new Date(subHours(now, 168 - i));
|
|
||||||
const key = format(d, 'yyyy-MM-dd-HH');
|
|
||||||
points[key] = { t: startOfHour(d).toISOString(), y: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
data.pageviews.forEach(e => {
|
|
||||||
const key = format(new Date(e.created_at), 'yyyy-MM-dd-HH');
|
|
||||||
points[key].y += 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
return points;
|
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [data]);
|
||||||
console.log(metrics);
|
console.log(metrics);
|
||||||
@ -31,8 +17,9 @@ export default function Chart({ websiteId, startDate, endDate }) {
|
|||||||
async function loadData() {
|
async function loadData() {
|
||||||
setData(
|
setData(
|
||||||
await get(`/api/website/${websiteId}/pageviews`, {
|
await get(`/api/website/${websiteId}/pageviews`, {
|
||||||
start_at: startDate,
|
start_at: +startDate,
|
||||||
end_at: endDate,
|
end_at: +endDate,
|
||||||
|
tz: getTimezone(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -47,6 +34,9 @@ export default function Chart({ websiteId, startDate, endDate }) {
|
|||||||
label: 'page views',
|
label: 'page views',
|
||||||
data: Object.values(metrics),
|
data: Object.values(metrics),
|
||||||
lineTension: 0,
|
lineTension: 0,
|
||||||
|
backgroundColor: 'rgb(38, 128, 235, 0.1)',
|
||||||
|
borderColor: 'rgb(13, 102, 208, 0.2)',
|
||||||
|
borderWidth: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -65,19 +55,13 @@ export default function Chart({ websiteId, startDate, endDate }) {
|
|||||||
{
|
{
|
||||||
type: 'time',
|
type: 'time',
|
||||||
distribution: 'series',
|
distribution: 'series',
|
||||||
|
offset: true,
|
||||||
time: {
|
time: {
|
||||||
unit: 'hour',
|
|
||||||
displayFormats: {
|
displayFormats: {
|
||||||
hour: 'ddd M/DD',
|
day: 'ddd M/DD',
|
||||||
},
|
},
|
||||||
tooltipFormat: 'ddd M/DD hA',
|
tooltipFormat: 'ddd M/DD hA',
|
||||||
},
|
},
|
||||||
ticks: {
|
|
||||||
autoSkip: true,
|
|
||||||
minRotation: 0,
|
|
||||||
maxRotation: 0,
|
|
||||||
maxTicksLimit: 7,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
yAxes: [
|
yAxes: [
|
||||||
|
8
lib/auth.js
Normal file
8
lib/auth.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { parse } from 'cookie';
|
||||||
|
import { verifySecureToken } from './crypto';
|
||||||
|
|
||||||
|
export default async req => {
|
||||||
|
const token = parse(req.headers.cookie)['umami.auth'];
|
||||||
|
|
||||||
|
return verifySecureToken(token);
|
||||||
|
};
|
11
lib/date.js
Normal file
11
lib/date.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import moment from 'moment-timezone';
|
||||||
|
import { addMinutes } from 'date-fns';
|
||||||
|
|
||||||
|
export function getTimezone() {
|
||||||
|
const tz = moment.tz.guess();
|
||||||
|
return moment.tz.zone(tz).abbr(new Date().getTimezoneOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLocalTime(t) {
|
||||||
|
return addMinutes(new Date(t), new Date().getTimezoneOffset());
|
||||||
|
}
|
36
lib/db.js
36
lib/db.js
@ -32,6 +32,16 @@ export async function getWebsite(website_uuid) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getWebsites(user_id) {
|
||||||
|
return runQuery(
|
||||||
|
prisma.website.findMany({
|
||||||
|
where: {
|
||||||
|
user_id,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function createSession(website_id, data) {
|
export async function createSession(website_id, data) {
|
||||||
return runQuery(
|
return runQuery(
|
||||||
prisma.session.create({
|
prisma.session.create({
|
||||||
@ -126,3 +136,29 @@ export async function getPageviews(website_id, start_at, end_at) {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getPageviewData(
|
||||||
|
website_id,
|
||||||
|
start_at,
|
||||||
|
end_at,
|
||||||
|
timezone = 'utc',
|
||||||
|
unit = 'day',
|
||||||
|
count = '*',
|
||||||
|
) {
|
||||||
|
return runQuery(
|
||||||
|
prisma.queryRaw(
|
||||||
|
`
|
||||||
|
select date_trunc('${unit}', created_at at time zone '${timezone}') t,
|
||||||
|
count(${count}) y
|
||||||
|
from pageview
|
||||||
|
where website_id=$1
|
||||||
|
and created_at between $2 and $3
|
||||||
|
group by 1
|
||||||
|
order by 1
|
||||||
|
`,
|
||||||
|
website_id,
|
||||||
|
start_at,
|
||||||
|
end_at,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
|
import session from './session';
|
||||||
|
import auth from './auth';
|
||||||
|
|
||||||
export function use(middleware) {
|
export function use(middleware) {
|
||||||
return (req, res) =>
|
return (req, res) =>
|
||||||
@ -13,3 +15,21 @@ export function use(middleware) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useCors = use(cors());
|
export const useCors = use(cors());
|
||||||
|
|
||||||
|
export const useSession = use(async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
req.session = await session(req);
|
||||||
|
} catch {
|
||||||
|
return res.status(400).end();
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useAuth = use(async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
req.auth = await auth(req);
|
||||||
|
} catch {
|
||||||
|
return res.status(401).end();
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getWebsite, getSession, createSession } from 'lib/db';
|
import { getWebsite, getSession, createSession } from 'lib/db';
|
||||||
import { getCountry, getDevice, getIpAddress } from 'lib/utils';
|
import { getCountry, getDevice, getIpAddress } from 'lib/request';
|
||||||
import { uuid, isValidId, verifyToken } from 'lib/crypto';
|
import { uuid, isValidId, verifyToken } from 'lib/crypto';
|
||||||
|
|
||||||
export default async req => {
|
export default async req => {
|
||||||
@ -46,6 +46,8 @@ export default async req => {
|
|||||||
session_id,
|
session_id,
|
||||||
session_uuid,
|
session_uuid,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error(`Invalid website: ${website_uuid}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@
|
|||||||
"is-localhost-ip": "^1.4.0",
|
"is-localhost-ip": "^1.4.0",
|
||||||
"jose": "^1.27.2",
|
"jose": "^1.27.2",
|
||||||
"maxmind": "^4.1.3",
|
"maxmind": "^4.1.3",
|
||||||
|
"moment-timezone": "^0.5.31",
|
||||||
"next": "9.3.5",
|
"next": "9.3.5",
|
||||||
"next-cookies": "^2.0.3",
|
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"promise-polyfill": "^8.1.3",
|
"promise-polyfill": "^8.1.3",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { savePageView, saveEvent } from 'lib/db';
|
import { savePageView, saveEvent } from 'lib/db';
|
||||||
import { useCors } from 'lib/middleware';
|
import { useCors, useSession } from 'lib/middleware';
|
||||||
import checkSession from 'lib/session';
|
|
||||||
import { createToken } from 'lib/crypto';
|
import { createToken } from 'lib/crypto';
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
await useCors(req, res);
|
await useCors(req, res);
|
||||||
|
await useSession(req, res);
|
||||||
|
|
||||||
const session = await checkSession(req);
|
const { session } = req;
|
||||||
|
|
||||||
const token = await createToken(session);
|
const token = await createToken(session);
|
||||||
const { website_id, session_id } = session;
|
const { website_id, session_id } = session;
|
||||||
const { type, payload } = req.body;
|
const { type, payload } = req.body;
|
||||||
|
12
pages/api/website.js
Normal file
12
pages/api/website.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { getWebsites } from 'lib/db';
|
||||||
|
import { useAuth } from 'lib/middleware';
|
||||||
|
|
||||||
|
export default async (req, res) => {
|
||||||
|
await useAuth(req, res);
|
||||||
|
|
||||||
|
const { user_id } = req.auth;
|
||||||
|
|
||||||
|
const websites = await getWebsites(user_id);
|
||||||
|
|
||||||
|
res.status(200).json({ websites });
|
||||||
|
};
|
@ -1,10 +1,15 @@
|
|||||||
import { getPageviews } from 'lib/db';
|
import { getPageviewData } from 'lib/db';
|
||||||
|
import { useAuth } from 'lib/middleware';
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
console.log(req.query);
|
await useAuth(req, res);
|
||||||
const { id, start_at, end_at } = req.query;
|
|
||||||
|
|
||||||
const pageviews = await getPageviews(+id, new Date(+start_at), new Date(+end_at));
|
const { id, start_at, end_at, tz } = req.query;
|
||||||
|
|
||||||
res.status(200).json({ pageviews });
|
const [pageviews, uniques] = await Promise.all([
|
||||||
|
getPageviewData(+id, new Date(+start_at), new Date(+end_at), tz, 'day', '*'),
|
||||||
|
getPageviewData(+id, new Date(+start_at), new Date(+end_at), tz, 'day', 'distinct session_id'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
res.status(200).json({ pageviews, uniques });
|
||||||
};
|
};
|
||||||
|
13
pages/api/website/[id]/summary.js
Normal file
13
pages/api/website/[id]/summary.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { getPageviews } from 'lib/db';
|
||||||
|
import { useAuth } from 'lib/middleware';
|
||||||
|
|
||||||
|
export default async (req, res) => {
|
||||||
|
await useAuth(req, res);
|
||||||
|
|
||||||
|
console.log(req.query);
|
||||||
|
const { id, start_at, end_at } = req.query;
|
||||||
|
|
||||||
|
const pageviews = await getPageviews(+id, new Date(+start_at), new Date(+end_at));
|
||||||
|
|
||||||
|
res.status(200).json({ pageviews });
|
||||||
|
};
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import cookies from 'next-cookies';
|
import { parse } from 'cookie';
|
||||||
import Layout from 'components/Layout';
|
import Layout from 'components/Layout';
|
||||||
import Chart from 'components/Chart';
|
import Chart from 'components/Chart';
|
||||||
import { verifySecureToken } from 'lib/crypto';
|
import { verifySecureToken } from 'lib/crypto';
|
||||||
|
import { subDays, endOfDay } from 'date-fns';
|
||||||
|
|
||||||
export default function HomePage({ username }) {
|
export default function HomePage({ username }) {
|
||||||
return (
|
return (
|
||||||
@ -14,8 +15,8 @@ export default function HomePage({ username }) {
|
|||||||
<div>
|
<div>
|
||||||
<Chart
|
<Chart
|
||||||
websiteId={3}
|
websiteId={3}
|
||||||
startDate={Date.now() - 1000 * 60 * 60 * 24 * 7}
|
startDate={subDays(endOfDay(new Date()), 6)}
|
||||||
endDate={Date.now()}
|
endDate={endOfDay(new Date())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Link href="/logout">
|
<Link href="/logout">
|
||||||
@ -25,8 +26,8 @@ export default function HomePage({ username }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps({ req, res }) {
|
||||||
const token = cookies(context)['umami.auth'];
|
const token = parse(req.headers.cookie)['umami.auth'];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = await verifySecureToken(token);
|
const payload = await verifySecureToken(token);
|
||||||
@ -37,8 +38,6 @@ export async function getServerSideProps(context) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
} catch {
|
} catch {
|
||||||
const { res } = context;
|
|
||||||
|
|
||||||
res.statusCode = 303;
|
res.statusCode = 303;
|
||||||
res.setHeader('Location', '/login');
|
res.setHeader('Location', '/login');
|
||||||
res.end();
|
res.end();
|
||||||
|
38
yarn.lock
38
yarn.lock
@ -1374,11 +1374,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
||||||
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
|
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
|
||||||
|
|
||||||
"@types/cookie@^0.3.3":
|
|
||||||
version "0.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803"
|
|
||||||
integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==
|
|
||||||
|
|
||||||
"@types/eslint-visitor-keys@^1.0.0":
|
"@types/eslint-visitor-keys@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||||
@ -1414,11 +1409,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
||||||
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
||||||
|
|
||||||
"@types/object-assign@^4.0.30":
|
|
||||||
version "4.0.30"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/object-assign/-/object-assign-4.0.30.tgz#8949371d5a99f4381ee0f1df0a9b7a187e07e652"
|
|
||||||
integrity sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=
|
|
||||||
|
|
||||||
"@types/parse-json@^4.0.0":
|
"@types/parse-json@^4.0.0":
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||||
@ -2662,7 +2652,7 @@ convert-source-map@^0.3.3:
|
|||||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
|
||||||
integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
|
integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
|
||||||
|
|
||||||
cookie@^0.4.0, cookie@^0.4.1:
|
cookie@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
|
||||||
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
|
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
|
||||||
@ -5511,7 +5501,14 @@ mkdirp@^1.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||||
|
|
||||||
moment@^2.10.2:
|
moment-timezone@^0.5.31:
|
||||||
|
version "0.5.31"
|
||||||
|
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.31.tgz#9c40d8c5026f0c7ab46eda3d63e49c155148de05"
|
||||||
|
integrity sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==
|
||||||
|
dependencies:
|
||||||
|
moment ">= 2.9.0"
|
||||||
|
|
||||||
|
"moment@>= 2.9.0", moment@^2.10.2:
|
||||||
version "2.27.0"
|
version "2.27.0"
|
||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
|
||||||
integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
|
integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
|
||||||
@ -5596,13 +5593,6 @@ neo-async@^2.5.0, neo-async@^2.6.1:
|
|||||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||||
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
||||||
|
|
||||||
next-cookies@^2.0.3:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/next-cookies/-/next-cookies-2.0.3.tgz#5a3eabcb6afa9b4d4ade69dfaaad749d16cd4a9a"
|
|
||||||
integrity sha512-YVCQzwZx+sz+KqLO4y9niHH9jjz6jajlEQbAKfsYVT6DOfngb/0k5l6vFK4rmpExVug96pGag8OBsdSRL9FZhQ==
|
|
||||||
dependencies:
|
|
||||||
universal-cookie "^4.0.2"
|
|
||||||
|
|
||||||
next-tick@~1.0.0:
|
next-tick@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
||||||
@ -8719,16 +8709,6 @@ unist-util-visit@^2.0.0:
|
|||||||
unist-util-is "^4.0.0"
|
unist-util-is "^4.0.0"
|
||||||
unist-util-visit-parents "^3.0.0"
|
unist-util-visit-parents "^3.0.0"
|
||||||
|
|
||||||
universal-cookie@^4.0.2:
|
|
||||||
version "4.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-4.0.3.tgz#c2fa59127260e6ad21ef3e0cdd66ad453cbc41f6"
|
|
||||||
integrity sha512-YbEHRs7bYOBTIWedTR9koVEe2mXrq+xdjTJZcoKJK/pQaE6ni28ak2AKXFpevb+X6w3iU5SXzWDiJkmpDRb9qw==
|
|
||||||
dependencies:
|
|
||||||
"@types/cookie" "^0.3.3"
|
|
||||||
"@types/object-assign" "^4.0.30"
|
|
||||||
cookie "^0.4.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
|
|
||||||
unquote@~1.1.1:
|
unquote@~1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544"
|
resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544"
|
||||||
|
Loading…
Reference in New Issue
Block a user