mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Sessions page.
This commit is contained in:
parent
cd0f185f77
commit
ac60d08ee5
@ -17,7 +17,7 @@ const trackerScriptName = process.env.TRACKER_SCRIPT_NAME;
|
|||||||
|
|
||||||
const contentSecurityPolicy = [
|
const contentSecurityPolicy = [
|
||||||
`default-src 'self'`,
|
`default-src 'self'`,
|
||||||
`img-src *`,
|
`img-src * data:`,
|
||||||
`script-src 'self' 'unsafe-eval' 'unsafe-inline'`,
|
`script-src 'self' 'unsafe-eval' 'unsafe-inline'`,
|
||||||
`style-src 'self' 'unsafe-inline'`,
|
`style-src 'self' 'unsafe-inline'`,
|
||||||
`connect-src 'self' api.umami.is cloud.umami.is`,
|
`connect-src 'self' api.umami.is cloud.umami.is`,
|
||||||
|
@ -65,6 +65,8 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clickhouse/client": "^1.3.0",
|
"@clickhouse/client": "^1.3.0",
|
||||||
|
"@dicebear/collection": "^9.2.1",
|
||||||
|
"@dicebear/core": "^9.2.1",
|
||||||
"@fontsource/inter": "^4.5.15",
|
"@fontsource/inter": "^4.5.15",
|
||||||
"@prisma/client": "5.16.2",
|
"@prisma/client": "5.16.2",
|
||||||
"@prisma/extension-read-replicas": "^0.3.0",
|
"@prisma/extension-read-replicas": "^0.3.0",
|
||||||
|
@ -45,11 +45,11 @@ export function WebsiteHeader({
|
|||||||
icon: <Icons.Reports />,
|
icon: <Icons.Reports />,
|
||||||
path: '/reports',
|
path: '/reports',
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// label: formatMessage(labels.sessions),
|
label: formatMessage(labels.sessions),
|
||||||
// icon: <Icons.User />,
|
icon: <Icons.User />,
|
||||||
// path: '/sessions',
|
path: '/sessions',
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
label: formatMessage(labels.events),
|
label: formatMessage(labels.events),
|
||||||
icon: <Icons.Nodes />,
|
icon: <Icons.Nodes />,
|
||||||
@ -69,7 +69,7 @@ export function WebsiteHeader({
|
|||||||
<div className={styles.links}>
|
<div className={styles.links}>
|
||||||
{links.map(({ label, icon, path }) => {
|
{links.map(({ label, icon, path }) => {
|
||||||
const selected = path
|
const selected = path
|
||||||
? pathname.endsWith(path)
|
? pathname.includes(path)
|
||||||
: pathname.match(/^\/websites\/[\w-]+$/);
|
: pathname.match(/^\/websites\/[\w-]+$/);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
import { GridColumn, GridTable, useBreakpoint } from 'react-basics';
|
import { GridColumn, GridTable, useBreakpoint } from 'react-basics';
|
||||||
import { useFormat, useMessages } from 'components/hooks';
|
import { useFormat, useMessages } from 'components/hooks';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
|
import Profile from 'components/common/Profile';
|
||||||
|
|
||||||
export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean }) {
|
export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean }) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
@ -9,7 +11,16 @@ export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GridTable data={data} cardMode={['xs', 'sm', 'md'].includes(breakpoint)}>
|
<GridTable data={data} cardMode={['xs', 'sm', 'md'].includes(breakpoint)}>
|
||||||
<GridColumn name="id" label="ID" />
|
<GridColumn name="pic" label="" width="90px">
|
||||||
|
{row => <Profile seed={row.id} size={64} />}
|
||||||
|
</GridColumn>
|
||||||
|
<GridColumn name="id" label="ID">
|
||||||
|
{row => (
|
||||||
|
<Link href={`sessions/${row.id}`}>
|
||||||
|
{row.id} ({row.firstAt !== row.lastAt ? 'YES' : 'NO'})
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</GridColumn>
|
||||||
<GridColumn name="country" label={formatMessage(labels.country)}>
|
<GridColumn name="country" label={formatMessage(labels.country)}>
|
||||||
{row => formatValue(row.country, 'country')}
|
{row => formatValue(row.country, 'country')}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.page {
|
||||||
|
display: grid;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
import WebsiteHeader from '../../WebsiteHeader';
|
||||||
|
import SessionInfo from './SessionInfo';
|
||||||
|
import { useSession } from 'components/hooks';
|
||||||
|
import { Loading } from 'react-basics';
|
||||||
|
import styles from './SessionDetailsPage.module.css';
|
||||||
|
|
||||||
|
export default function SessionDetailsPage({
|
||||||
|
websiteId,
|
||||||
|
sessionId,
|
||||||
|
}: {
|
||||||
|
websiteId: string;
|
||||||
|
sessionId: string;
|
||||||
|
}) {
|
||||||
|
const { data, isLoading } = useSession(websiteId, sessionId);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <Loading position="page" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.page}>
|
||||||
|
<WebsiteHeader websiteId={websiteId} />
|
||||||
|
<SessionInfo data={data} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import Profile from 'components/common/Profile';
|
||||||
|
|
||||||
|
export default function SessionInfo({ data }) {
|
||||||
|
return (
|
||||||
|
<h1>
|
||||||
|
<Profile seed={data?.id} />
|
||||||
|
<dl>
|
||||||
|
<dt>ID</dt>
|
||||||
|
<dd>{data?.id}</dd>
|
||||||
|
<dt>Country</dt>
|
||||||
|
<dd>{data?.country}</dd>
|
||||||
|
<dt>City</dt>
|
||||||
|
<dd>{data?.city}</dd>
|
||||||
|
</dl>
|
||||||
|
</h1>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import SessionDetailsPage from './SessionDetailsPage';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
|
export default function WebsitePage({ params: { websiteId, sessionId } }) {
|
||||||
|
return <SessionDetailsPage websiteId={websiteId} sessionId={sessionId} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Websites',
|
||||||
|
};
|
41
src/components/common/Profile.tsx
Normal file
41
src/components/common/Profile.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { createAvatar } from '@dicebear/core';
|
||||||
|
import { lorelei } from '@dicebear/collection';
|
||||||
|
import md5 from 'md5';
|
||||||
|
|
||||||
|
const lib = lorelei;
|
||||||
|
|
||||||
|
function convertToPastel(hexColor: string, pastelFactor: number = 0.5) {
|
||||||
|
// Remove the # if present
|
||||||
|
hexColor = hexColor.replace(/^#/, '');
|
||||||
|
|
||||||
|
// Convert hex to RGB
|
||||||
|
let r = parseInt(hexColor.substr(0, 2), 16);
|
||||||
|
let g = parseInt(hexColor.substr(2, 2), 16);
|
||||||
|
let b = parseInt(hexColor.substr(4, 2), 16);
|
||||||
|
|
||||||
|
// Calculate pastel version (mix with white)
|
||||||
|
//const pastelFactor = 0.5; // Adjust this value to control pastel intensity
|
||||||
|
|
||||||
|
r = Math.floor((r + 255 * pastelFactor) / (1 + pastelFactor));
|
||||||
|
g = Math.floor((g + 255 * pastelFactor) / (1 + pastelFactor));
|
||||||
|
b = Math.floor((b + 255 * pastelFactor) / (1 + pastelFactor));
|
||||||
|
|
||||||
|
// Convert back to hex
|
||||||
|
return `#${((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Profile({ seed, size = 128, ...props }: { seed: string; size?: number }) {
|
||||||
|
const avatar = useMemo(() => {
|
||||||
|
return createAvatar(lib, {
|
||||||
|
...props,
|
||||||
|
seed,
|
||||||
|
size,
|
||||||
|
backgroundColor: [convertToPastel(md5(seed).substring(0, 6), 2).replace(/^#/, '')],
|
||||||
|
}).toDataUri();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <img src={avatar} alt="Avatar" style={{ borderRadius: '100%' }} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Profile;
|
@ -5,6 +5,7 @@ export * from './queries/useLogin';
|
|||||||
export * from './queries/useRealtime';
|
export * from './queries/useRealtime';
|
||||||
export * from './queries/useReport';
|
export * from './queries/useReport';
|
||||||
export * from './queries/useReports';
|
export * from './queries/useReports';
|
||||||
|
export * from './queries/useSession';
|
||||||
export * from './queries/useSessions';
|
export * from './queries/useSessions';
|
||||||
export * from './queries/useShareToken';
|
export * from './queries/useShareToken';
|
||||||
export * from './queries/useTeam';
|
export * from './queries/useTeam';
|
||||||
|
14
src/components/hooks/queries/useSession.ts
Normal file
14
src/components/hooks/queries/useSession.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { useApi } from './useApi';
|
||||||
|
|
||||||
|
export function useSession(websiteId: string, sessionId: string) {
|
||||||
|
const { get, useQuery } = useApi();
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['session', { websiteId, sessionId }],
|
||||||
|
queryFn: () => {
|
||||||
|
return get(`/websites/${websiteId}/sessions/${sessionId}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useSession;
|
@ -4,7 +4,7 @@ import useModified from '../useModified';
|
|||||||
|
|
||||||
export function useSessions(websiteId: string, params?: { [key: string]: string | number }) {
|
export function useSessions(websiteId: string, params?: { [key: string]: string | number }) {
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const { modified } = useModified(`websites`);
|
const { modified } = useModified(`sessions`);
|
||||||
|
|
||||||
return useFilterQuery({
|
return useFilterQuery({
|
||||||
queryKey: ['sessions', { websiteId, modified, ...params }],
|
queryKey: ['sessions', { websiteId, modified, ...params }],
|
||||||
|
42
src/pages/api/websites/[websiteId]/sessions/[sessionId].ts
Normal file
42
src/pages/api/websites/[websiteId]/sessions/[sessionId].ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import * as yup from 'yup';
|
||||||
|
import { canViewWebsite } from 'lib/auth';
|
||||||
|
import { useAuth, useCors, useValidate } from 'lib/middleware';
|
||||||
|
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||||
|
import { NextApiResponse } from 'next';
|
||||||
|
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||||
|
import { getSession } from 'queries';
|
||||||
|
|
||||||
|
export interface ReportsRequestQuery extends PageParams {
|
||||||
|
websiteId: string;
|
||||||
|
sessionId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
GET: yup.object().shape({
|
||||||
|
websiteId: yup.string().uuid().required(),
|
||||||
|
sessionId: yup.string().uuid().required(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async (
|
||||||
|
req: NextApiRequestQueryBody<ReportsRequestQuery, any>,
|
||||||
|
res: NextApiResponse,
|
||||||
|
) => {
|
||||||
|
await useCors(req, res);
|
||||||
|
await useAuth(req, res);
|
||||||
|
await useValidate(schema, req, res);
|
||||||
|
|
||||||
|
const { websiteId, sessionId } = req.query;
|
||||||
|
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
if (!(await canViewWebsite(req.auth, websiteId))) {
|
||||||
|
return unauthorized(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await getSession(websiteId, sessionId);
|
||||||
|
|
||||||
|
return ok(res, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodNotAllowed(res);
|
||||||
|
};
|
@ -1,9 +1,46 @@
|
|||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
|
import clickhouse from 'lib/clickhouse';
|
||||||
|
import { runQuery, PRISMA, CLICKHOUSE } from 'lib/db';
|
||||||
|
|
||||||
export async function getSession(id: string) {
|
export async function getSession(...args: [websiteId: string, sessionId: string]) {
|
||||||
|
return runQuery({
|
||||||
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
|
[CLICKHOUSE]: () => clickhouseQuery(...args),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function relationalQuery(websiteId: string, sessionId: string) {
|
||||||
return prisma.client.session.findUnique({
|
return prisma.client.session.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id: sessionId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function clickhouseQuery(websiteId: string, sessionId: string) {
|
||||||
|
const { rawQuery } = clickhouse;
|
||||||
|
|
||||||
|
return rawQuery(
|
||||||
|
`
|
||||||
|
select
|
||||||
|
session_id as id,
|
||||||
|
website_id as websiteId,
|
||||||
|
min(created_at) as firstAt,
|
||||||
|
max(created_at) as lastAt,
|
||||||
|
hostname,
|
||||||
|
browser,
|
||||||
|
os,
|
||||||
|
device,
|
||||||
|
screen,
|
||||||
|
language,
|
||||||
|
country,
|
||||||
|
subdivision1,
|
||||||
|
city
|
||||||
|
from website_event
|
||||||
|
where website_id = {websiteId:UUID}
|
||||||
|
and session_id = {sessionId:UUID}
|
||||||
|
group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city
|
||||||
|
`,
|
||||||
|
{ websiteId, sessionId },
|
||||||
|
).then(result => result?.[0]);
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function clickhouseQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) {
|
async function clickhouseQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) {
|
||||||
const { pagedQuery, parseFilters, getDateStringSQL } = clickhouse;
|
const { pagedQuery, parseFilters } = clickhouse;
|
||||||
const { params, dateQuery, filterQuery } = await parseFilters(websiteId, filters);
|
const { params, dateQuery, filterQuery } = await parseFilters(websiteId, filters);
|
||||||
|
|
||||||
return pagedQuery(
|
return pagedQuery(
|
||||||
@ -32,7 +32,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||||||
select
|
select
|
||||||
session_id as id,
|
session_id as id,
|
||||||
website_id as websiteId,
|
website_id as websiteId,
|
||||||
${getDateStringSQL('created_at', 'second', filters.timezone)} as createdAt,
|
min(created_at) as createdAt,
|
||||||
hostname,
|
hostname,
|
||||||
browser,
|
browser,
|
||||||
os,
|
os,
|
||||||
@ -41,13 +41,13 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||||||
language,
|
language,
|
||||||
country,
|
country,
|
||||||
subdivision1,
|
subdivision1,
|
||||||
subdivision2,
|
|
||||||
city
|
city
|
||||||
from website_event
|
from website_event
|
||||||
where website_id = {websiteId:UUID}
|
where website_id = {websiteId:UUID}
|
||||||
${dateQuery}
|
${dateQuery}
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
order by created_at desc
|
group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city
|
||||||
|
order by createdAt desc
|
||||||
`,
|
`,
|
||||||
params,
|
params,
|
||||||
pageParams,
|
pageParams,
|
||||||
|
195
yarn.lock
195
yarn.lock
@ -1381,6 +1381,199 @@
|
|||||||
debug "^3.1.0"
|
debug "^3.1.0"
|
||||||
lodash.once "^4.1.1"
|
lodash.once "^4.1.1"
|
||||||
|
|
||||||
|
"@dicebear/adventurer-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/adventurer-neutral/-/adventurer-neutral-9.2.1.tgz#0416ff71d0dd3ff391db9c9fda2acb166b074c5f"
|
||||||
|
integrity sha512-iP6Tc6CgrJt63j08i/hlyNiGEbDNgP9Ws6WKT9n/0oTU9X/DKLncGStV3uhgYPIOVQE/tw9a/GjbGjrwBlN8CQ==
|
||||||
|
|
||||||
|
"@dicebear/adventurer@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/adventurer/-/adventurer-9.2.1.tgz#3d522d2aaabe17d172ea2302bfdf62d601ebcd64"
|
||||||
|
integrity sha512-utJr8oEOwPy9y+7rIOnB7mls+2XQrc3Kdlx/ay9KBY/HEUMnwMoN/GJhg4HcyGnV+DS7VhN6JSrnwwD9+SQyBw==
|
||||||
|
|
||||||
|
"@dicebear/avataaars-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/avataaars-neutral/-/avataaars-neutral-9.2.1.tgz#61d3894f4d08d9ee3722f3a64c36725729c6aaf3"
|
||||||
|
integrity sha512-yceQMVBLimAHgZDL8VKCDGNs5JQ8BERaUMNIJXXRKEYZXlofoXZpYtcWPKQY9lmRJJznO1GX7ZK12ILnZjRPBQ==
|
||||||
|
|
||||||
|
"@dicebear/avataaars@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/avataaars/-/avataaars-9.2.1.tgz#2460fb0d7d364a12e546b40b6e56c220db71c851"
|
||||||
|
integrity sha512-WIZL7CWSsmzLswY/4ZrgtE/7EvnaNrYreLyT8hjiGyVb9J4cQaVZXSMuDIGFa5wT062AW/4/i82kh/7nh0oL+w==
|
||||||
|
|
||||||
|
"@dicebear/big-ears-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/big-ears-neutral/-/big-ears-neutral-9.2.1.tgz#dfee12787f8a0efa7b3552fca5e9f24c9102fc44"
|
||||||
|
integrity sha512-98qOCFEhbqCHeyO7ZXBAMMov8bquZt8vhtjj0YeHjGjI/OEWbA2gxq2ryv1BHSehVc/vTrd1KbHag7yYoeCDuw==
|
||||||
|
|
||||||
|
"@dicebear/big-ears@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/big-ears/-/big-ears-9.2.1.tgz#4a7f2f3d987c11d76602b6ee8b398f9dcd2ce486"
|
||||||
|
integrity sha512-BUVTonwSYiGKcnk8wdwUHZ1b34GhfzRpG1kguK4kWAKlayBq7Q+iDJlmk4Bch0XdDQc2bqFf1GQCCj+xXWRHyg==
|
||||||
|
|
||||||
|
"@dicebear/big-smile@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/big-smile/-/big-smile-9.2.1.tgz#d6cf95d34d65a393901925df370a1afbd0b0ae76"
|
||||||
|
integrity sha512-bspur+wtnlv/Z4QDvRWg9rs3snf+iuBkamkgw4nZOUFKMlZdPQGqNoh1DkycRcLXNX1Q61KM172K6bS60ZlKxw==
|
||||||
|
|
||||||
|
"@dicebear/bottts-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/bottts-neutral/-/bottts-neutral-9.2.1.tgz#cc89b1ed834b7e8b7163dee2928dc1aa74077f75"
|
||||||
|
integrity sha512-uwd+xcbRQUIHKQ1iEiLjf5RwCaVzOfBgIu2WRE+6MUaahYi6cJ0eJAs0h1q+zpgYyvqPDPDAi9j7AUwjmig0GA==
|
||||||
|
|
||||||
|
"@dicebear/bottts@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/bottts/-/bottts-9.2.1.tgz#922ccdba942d8c2c15655be0b6f25f4e9691cb80"
|
||||||
|
integrity sha512-AQQ/WKd54G9sa+TkQptcu6c+Tjfc9hitgB70uA5GqJe+w6Bal+gwY6kPm5sJ1CY2mk/UBh1rXBuauQZ25bgTcQ==
|
||||||
|
|
||||||
|
"@dicebear/collection@^9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/collection/-/collection-9.2.1.tgz#b2de84ef654ac1550458a17049b02a0013213b92"
|
||||||
|
integrity sha512-Su1eygO8llKuJ68N+xhBCzBN2Lqrsx9ZNdlvfZeH/s70RjL0raNQaI6/hRABDmlbLYwW4AjRh2lOgDdGfCp5DQ==
|
||||||
|
dependencies:
|
||||||
|
"@dicebear/adventurer" "9.2.1"
|
||||||
|
"@dicebear/adventurer-neutral" "9.2.1"
|
||||||
|
"@dicebear/avataaars" "9.2.1"
|
||||||
|
"@dicebear/avataaars-neutral" "9.2.1"
|
||||||
|
"@dicebear/big-ears" "9.2.1"
|
||||||
|
"@dicebear/big-ears-neutral" "9.2.1"
|
||||||
|
"@dicebear/big-smile" "9.2.1"
|
||||||
|
"@dicebear/bottts" "9.2.1"
|
||||||
|
"@dicebear/bottts-neutral" "9.2.1"
|
||||||
|
"@dicebear/croodles" "9.2.1"
|
||||||
|
"@dicebear/croodles-neutral" "9.2.1"
|
||||||
|
"@dicebear/dylan" "9.2.1"
|
||||||
|
"@dicebear/fun-emoji" "9.2.1"
|
||||||
|
"@dicebear/glass" "9.2.1"
|
||||||
|
"@dicebear/icons" "9.2.1"
|
||||||
|
"@dicebear/identicon" "9.2.1"
|
||||||
|
"@dicebear/initials" "9.2.1"
|
||||||
|
"@dicebear/lorelei" "9.2.1"
|
||||||
|
"@dicebear/lorelei-neutral" "9.2.1"
|
||||||
|
"@dicebear/micah" "9.2.1"
|
||||||
|
"@dicebear/miniavs" "9.2.1"
|
||||||
|
"@dicebear/notionists" "9.2.1"
|
||||||
|
"@dicebear/notionists-neutral" "9.2.1"
|
||||||
|
"@dicebear/open-peeps" "9.2.1"
|
||||||
|
"@dicebear/personas" "9.2.1"
|
||||||
|
"@dicebear/pixel-art" "9.2.1"
|
||||||
|
"@dicebear/pixel-art-neutral" "9.2.1"
|
||||||
|
"@dicebear/rings" "9.2.1"
|
||||||
|
"@dicebear/shapes" "9.2.1"
|
||||||
|
"@dicebear/thumbs" "9.2.1"
|
||||||
|
|
||||||
|
"@dicebear/core@^9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/core/-/core-9.2.1.tgz#b93800ac7e21ae955cceaa2370e7dc033a3cc557"
|
||||||
|
integrity sha512-Y3E59+3xO2UWKdf3Zt/rwMdy9r7uccTgM89Kv8aXN1vmdrnA4YYmr4jslRRRqPLVpenuT4105nkboC4rMnDgHw==
|
||||||
|
dependencies:
|
||||||
|
"@types/json-schema" "^7.0.11"
|
||||||
|
|
||||||
|
"@dicebear/croodles-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/croodles-neutral/-/croodles-neutral-9.2.1.tgz#379646cf53ba4d61b6c94c13b3ec3386359e3541"
|
||||||
|
integrity sha512-2iyr+B/y795P7cSIpFg4RjxUu6kljesKjtepvMzfeBR9xKyI84exBNHRoCTEVwOCFePmlPJX1qtw/YWM0sAPJw==
|
||||||
|
|
||||||
|
"@dicebear/croodles@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/croodles/-/croodles-9.2.1.tgz#74fa6aa8c0ee0dc303c0ad82fd78f5d6cd66610d"
|
||||||
|
integrity sha512-V7+m21BizYTGgLgxmh5dxHHADeD3gkeuPYkhKqP8Uu8jZFBgh5wKFqqfVI/XSQkx/+lRla5c6l55mymgjt4k8Q==
|
||||||
|
|
||||||
|
"@dicebear/dylan@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/dylan/-/dylan-9.2.1.tgz#997aff74b4bf112e4895463eeea0adc2456d332f"
|
||||||
|
integrity sha512-UeKz3Gxprh4bJ73Q2DjDpmjt854G3xfakc5KfeBmPV25EP+al7HCsM/HE+ZgKTSh+PPz5/mVtZQYU40pTzJEyg==
|
||||||
|
|
||||||
|
"@dicebear/fun-emoji@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/fun-emoji/-/fun-emoji-9.2.1.tgz#e88c8c2db7927d732ef2d0af3a24c4d4152a7f02"
|
||||||
|
integrity sha512-F08p+Ggdxo4Ryji+3aCJXAKnjx4rM4UMtrJU4eA2t8lAkpwFNgfGK6mpMYPnxmKULYljGOgySmw7AyWcbX8s2Q==
|
||||||
|
|
||||||
|
"@dicebear/glass@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/glass/-/glass-9.2.1.tgz#61bc231a5b0bd8d15cfa94c76ac608ab8fe98ac1"
|
||||||
|
integrity sha512-UoErQwg7/qkEKWyEDTyt8FYhw/aZryP0Tr7cwBEuxMXZ585NUTvEel0K5j9aDkBrimJVEM+jKzOFIIMAGLlR0g==
|
||||||
|
|
||||||
|
"@dicebear/icons@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/icons/-/icons-9.2.1.tgz#0ef78e8ff742bd9985a3c36cd9cbd2705449e789"
|
||||||
|
integrity sha512-0VuWohGMiv4n1nxwehYi6w+PIT9OBRlV721yNoewQWgQCrnMKBvM0cFRX9Dtg+MvwLMslQCIU3pEauEZ5FNmFA==
|
||||||
|
|
||||||
|
"@dicebear/identicon@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/identicon/-/identicon-9.2.1.tgz#aebd7b692de9a6601746ab47711359f81471841c"
|
||||||
|
integrity sha512-Dlqpn3tzqimR8KPIRkSJCKd5XwKgTLVXzT5KiY+2ysMZZQh4uJvBjVfY5SLrHDHC2a42W6EdwQxU6tFTRiKQuQ==
|
||||||
|
|
||||||
|
"@dicebear/initials@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/initials/-/initials-9.2.1.tgz#d4e435c18e48837f97086ba5210d4742594ba181"
|
||||||
|
integrity sha512-d6Shnt1LiCf9yAEck3y/w4pXG4bWYVjBFCeI43l0BAR39Mk2Dq05UEFZH5Dtj2kyfNozMjh6vG1cQyBigtamug==
|
||||||
|
|
||||||
|
"@dicebear/lorelei-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/lorelei-neutral/-/lorelei-neutral-9.2.1.tgz#5d5d6400c0e2232081f58f8d82efff00ee307b81"
|
||||||
|
integrity sha512-4YkkR697qXAYxN5N/zVsRe955QLhw0yLib2CzeBga1QXXMIkywq2nRFa3fr4toSRPl45kl1eF8J5HC17CU9inw==
|
||||||
|
|
||||||
|
"@dicebear/lorelei@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/lorelei/-/lorelei-9.2.1.tgz#b23ddb02b098578ef1bcb121c7a638795f3de89e"
|
||||||
|
integrity sha512-DNjZpUpe/CxKK8Byn1meBvRz/NJWtBizcoS2DzIIyqPYOwA5cLIa2g/qKkESvXzU9naEMkiHfMZb1RYYzN2FAA==
|
||||||
|
|
||||||
|
"@dicebear/micah@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/micah/-/micah-9.2.1.tgz#2e65fdb15b6ee6338123329c92e5afb98f694718"
|
||||||
|
integrity sha512-FK91igiVpPNhGCsfGpOgwYFKRP+FNR1V45Z4Tg/f82ux9TBdTmeoIfkgwrfhcXmCgagoYg2EAY+L72stUVapcA==
|
||||||
|
|
||||||
|
"@dicebear/miniavs@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/miniavs/-/miniavs-9.2.1.tgz#de1e571663775b4b2a30944d8033d6a8b972aca3"
|
||||||
|
integrity sha512-r0TcaSrKJDPMqMYIiXNArq9i//cZzA1yuiXJw46iTloBDTh7yL1tpnL84CDxMpQ+OZLeMiRA6jVBx0coer4vmg==
|
||||||
|
|
||||||
|
"@dicebear/notionists-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/notionists-neutral/-/notionists-neutral-9.2.1.tgz#2e77ae7330201628c4b3e4789b1aa83ffc684b82"
|
||||||
|
integrity sha512-Vi/FwMXzc1m/U2TjBnY9NHedoLbPc3BBsNQL8jPU27wdkXoyJHuXBevcUtsF0Zf8OuRbNpZKPbfYy6OYBr9qvw==
|
||||||
|
|
||||||
|
"@dicebear/notionists@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/notionists/-/notionists-9.2.1.tgz#70aa14e8846a49096648f891a625a92b04513c75"
|
||||||
|
integrity sha512-oAyvPlp3xfFnDpW3nXhdAPGVm5WYj6VW6RgdzLAHoRO2EOYDNkQruIXd+d8JYo1DMTLUbgp3onr5AF9UU2OBzw==
|
||||||
|
|
||||||
|
"@dicebear/open-peeps@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/open-peeps/-/open-peeps-9.2.1.tgz#dd9be6721ff7226e3a0286aec699fd6b0e0ad2b2"
|
||||||
|
integrity sha512-oPA/ljbPtuj2cdM0QtyJu2i24AaEMTIIk/FJbnrBK765WPnQcCZh84w+ZuInTMIfF9gYszNY34gaRD8Z6UiYxQ==
|
||||||
|
|
||||||
|
"@dicebear/personas@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/personas/-/personas-9.2.1.tgz#dfa8291ebba098e8cebdeb04a4fba9e4384c4496"
|
||||||
|
integrity sha512-OgtyT9dnY8U60sUo0SLKCFVt0+dIr3a4vR0bDs/zwK4Qb/yTdB1VPdfxq0Fwk2q1vfn9YgbDrb0YYRgMRl60qQ==
|
||||||
|
|
||||||
|
"@dicebear/pixel-art-neutral@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/pixel-art-neutral/-/pixel-art-neutral-9.2.1.tgz#457b4e038c9516e75d41c6c1efd9ff9d4099162a"
|
||||||
|
integrity sha512-GUtxJYX7/9XDgSZhkx24PB+yLcKkLHblDldvRr5xGlGxhgAovTBQFHLgCJxmUJgIaNW7pvSWCw7txguyxbBN9A==
|
||||||
|
|
||||||
|
"@dicebear/pixel-art@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/pixel-art/-/pixel-art-9.2.1.tgz#e50bcc300a43c16ad3f69de1b6bf3dad92528274"
|
||||||
|
integrity sha512-ftKPKCvnS1cJ2OvuQLmtEIwdb9PzF5C2ofWBdVI/RFvhH1BhYc3OsdQ28o90+ZJQO4fivKwfsh8MPUTaqToQ7Q==
|
||||||
|
|
||||||
|
"@dicebear/rings@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/rings/-/rings-9.2.1.tgz#ed6e930c02b09ebbd774fc104cffc5c23ffa6b4c"
|
||||||
|
integrity sha512-BlFYCaKB+wdpWWS28ZnQ/MvHeuNSRvkvWRoiw7pgS653LXx4kz/erVMmeVMSAr82y4BV+K8He2Rl2dMjuLyrXw==
|
||||||
|
|
||||||
|
"@dicebear/shapes@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/shapes/-/shapes-9.2.1.tgz#e076b9aabd67bf611e9bbf7149919000e3d74197"
|
||||||
|
integrity sha512-cQzTcYimtuiAun55uPdIIhK53QTyjWqF/YN7LqEBGBqrJuGqHZBm1HXCcj7wPpoQ3zSy/2u8Rp0Etv7+5XFzyw==
|
||||||
|
|
||||||
|
"@dicebear/thumbs@9.2.1":
|
||||||
|
version "9.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dicebear/thumbs/-/thumbs-9.2.1.tgz#174be721256e5ff97e19586a54bde8fd25468e74"
|
||||||
|
integrity sha512-ziX5HFmhiApO2k7QKj41+dGXbMdmQUUgFBYPyzTwnubhkDldJk7tpRoa5u2OsyTVDQCcPMv5mFSQpbANfmFwMg==
|
||||||
|
|
||||||
"@esbuild/android-arm64@0.17.19":
|
"@esbuild/android-arm64@0.17.19":
|
||||||
version "0.17.19"
|
version "0.17.19"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
|
||||||
@ -2600,7 +2793,7 @@
|
|||||||
expect "^29.0.0"
|
expect "^29.0.0"
|
||||||
pretty-format "^29.0.0"
|
pretty-format "^29.0.0"
|
||||||
|
|
||||||
"@types/json-schema@^7.0.12":
|
"@types/json-schema@^7.0.11", "@types/json-schema@^7.0.12":
|
||||||
version "7.0.15"
|
version "7.0.15"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user