Merge branch 'dev' into analytics

This commit is contained in:
Francis Cao 2024-02-19 12:34:33 -08:00
commit c1786069eb
50 changed files with 161 additions and 113 deletions

View File

@ -63,7 +63,7 @@
"dependencies": {
"@clickhouse/client": "^0.2.2",
"@fontsource/inter": "^4.5.15",
"@prisma/client": "5.7.0",
"@prisma/client": "5.9.1",
"@prisma/extension-read-replicas": "^0.3.0",
"@react-spring/web": "^9.7.3",
"@tanstack/react-query": "^5.12.2",
@ -98,7 +98,7 @@
"next-basics": "^0.39.0",
"node-fetch": "^3.2.8",
"npm-run-all": "^4.1.5",
"prisma": "5.7.0",
"prisma": "5.9.1",
"react": "^18.2.0",
"react-basics": "^0.122.0",
"react-beautiful-dnd": "^13.1.0",

View File

@ -1,5 +1,4 @@
import { Button } from 'react-basics';
import Head from 'next/head';
import Link from 'next/link';
import Script from 'next/script';
import WebsiteSelect from 'components/input/WebsiteSelect';
@ -73,9 +72,6 @@ export function TestConsole({ websiteId }: { websiteId: string }) {
return (
<Page isLoading={isLoading} error={error}>
<Head>
<title>{website ? `${website.name} | Umami Console` : 'Umami Console'}</title>
</Head>
<PageHeader title="Test console">
<WebsiteSelect websiteId={website?.id} onSelect={handleChange} />
</PageHeader>

View File

@ -16,5 +16,5 @@ export default async function ({ params: { websiteId } }) {
}
export const metadata: Metadata = {
title: 'Test Console | Umami',
title: 'Test Console',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Dashboard | Umami',
title: 'Dashboard',
};

View File

@ -1,3 +1,4 @@
import { Metadata } from 'next';
import App from './App';
import NavBar from './NavBar';
import Page from 'components/layout/Page';
@ -17,3 +18,10 @@ export default function ({ children }) {
</App>
);
}
export const metadata: Metadata = {
title: {
template: '%s | Umami',
default: 'Umami',
},
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Profile | Umami',
title: 'Profile',
};

View File

@ -11,5 +11,5 @@ export default function ReportsPage({ teamId }: { teamId: string }) {
);
}
export const metadata = {
title: 'Reports | Umami',
title: 'Reports',
};

View File

@ -6,5 +6,5 @@ export default function ({ params: { reportId } }) {
}
export const metadata: Metadata = {
title: 'Reports | Umami',
title: 'Reports',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Create Report | Umami',
title: 'Create Report',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Event Data Report | Umami',
title: 'Event Data Report',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Funnel Report | Umami',
title: 'Funnel Report',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Insights Report | Umami',
title: 'Insights Report',
};

View File

@ -6,5 +6,5 @@ export default function ({ params: { teamId } }: { params: { teamId: string } })
}
export const metadata: Metadata = {
title: 'Reports | Umami',
title: 'Reports',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Create Report | Umami',
title: 'Retention Report',
};

View File

@ -1,4 +1,5 @@
import SettingsLayout from './SettingsLayout';
import { Metadata } from 'next';
export default function ({ children }) {
if (process.env.cloudMode) {
@ -7,3 +8,10 @@ export default function ({ children }) {
return <SettingsLayout>{children}</SettingsLayout>;
}
export const metadata: Metadata = {
title: {
template: '%s | Settings | Umami',
default: 'Settings | Umami',
},
};

View File

@ -2,7 +2,7 @@
import TeamsDataTable from './TeamsDataTable';
import TeamsHeader from './TeamsHeader';
export default function TeamsPage() {
export default function TeamsSettingsPage() {
return (
<>
<TeamsHeader />

View File

@ -6,5 +6,5 @@ export default function ({ params: { teamId } }) {
}
export const metadata: Metadata = {
title: 'Team members - Umami',
title: 'Team Members',
};

View File

@ -6,5 +6,5 @@ export default function ({ params: { teamId } }) {
}
export const metadata: Metadata = {
title: 'Teams Settings - Umami',
title: 'Teams Details',
};

View File

@ -6,5 +6,5 @@ export default function ({ params: { teamId } }) {
}
export const metadata: Metadata = {
title: 'Teams Websites - Umami',
title: 'Teams Websites',
};

View File

@ -1,10 +1,10 @@
import { Metadata } from 'next';
import TeamsPage from './TeamsPage';
import TeamsSettingsPage from './TeamsSettingsPage';
export default function () {
return <TeamsPage />;
return <TeamsSettingsPage />;
}
export const metadata: Metadata = {
title: 'Teams Settings - Umami',
title: 'Teams',
};

View File

@ -2,7 +2,7 @@
import UsersDataTable from './UsersDataTable';
import UsersHeader from './UsersHeader';
export default function UsersPage() {
export default function UsersSettingsPage() {
return (
<>
<UsersHeader />

View File

@ -6,5 +6,5 @@ export default function ({ params: { userId } }) {
}
export const metadata: Metadata = {
title: 'User Settings - Umami',
title: 'User Settings',
};

View File

@ -1,9 +1,9 @@
import { Metadata } from 'next';
import UsersPage from './UsersPage';
import UsersSettingsPage from './UsersSettingsPage';
export default function () {
return <UsersPage />;
return <UsersSettingsPage />;
}
export const metadata: Metadata = {
title: 'Users | Umami',
title: 'Users',
};

View File

@ -4,21 +4,19 @@ import DataTable from 'components/common/DataTable';
import { useWebsites } from 'components/hooks';
export function WebsitesDataTable({
userId,
teamId,
allowEdit = true,
allowView = true,
showActions = true,
children,
}: {
userId?: string;
teamId?: string;
allowEdit?: boolean;
allowView?: boolean;
showActions?: boolean;
children?: ReactNode;
}) {
const queryResult = useWebsites({ userId, teamId });
const queryResult = useWebsites({ teamId });
return (
<DataTable queryResult={queryResult}>

View File

@ -1,15 +0,0 @@
'use client';
import { useLogin } from 'components/hooks';
import WebsitesDataTable from './WebsitesDataTable';
import WebsitesHeader from './WebsitesHeader';
export default function WebsitesPage({ teamId }: { teamId: string }) {
const { user } = useLogin();
return (
<>
<WebsitesHeader teamId={teamId} allowCreate={user.role !== 'view-only'} />
<WebsitesDataTable teamId={teamId} userId={user.id} allowEdit={true} />
</>
);
}

View File

@ -0,0 +1,12 @@
'use client';
import WebsitesDataTable from './WebsitesDataTable';
import WebsitesHeader from './WebsitesHeader';
export default function WebsitesSettingsPage({ teamId }: { teamId: string }) {
return (
<>
<WebsitesHeader teamId={teamId} />
<WebsitesDataTable teamId={teamId} />
</>
);
}

View File

@ -10,7 +10,15 @@ import ShareUrl from './ShareUrl';
import { useMessages } from 'components/hooks';
import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider';
export function WebsiteSettings({ websiteId, openExternal = false }) {
export function WebsiteSettings({
websiteId,
hostUrl,
openExternal = false,
}: {
websiteId: string;
hostUrl?: string;
openExternal?: boolean;
}) {
const website = useContext(WebsiteContext);
const { formatMessage, labels, messages } = useMessages();
const [tab, setTab] = useState<Key>('details');
@ -39,7 +47,7 @@ export function WebsiteSettings({ websiteId, openExternal = false }) {
<Item key="data">{formatMessage(labels.data)}</Item>
</Tabs>
{tab === 'details' && <WebsiteEditForm websiteId={websiteId} onSave={handleSave} />}
{tab === 'tracking' && <TrackingCode websiteId={websiteId} />}
{tab === 'tracking' && <TrackingCode websiteId={websiteId} hostUrl={hostUrl} />}
{tab === 'share' && <ShareUrl websiteId={websiteId} onSave={handleSave} />}
{tab === 'data' && <WebsiteData websiteId={websiteId} onSave={handleSave} />}
</>

View File

@ -2,7 +2,7 @@
import WebsiteProvider from 'app/(main)/websites/[websiteId]/WebsiteProvider';
import WebsiteSettings from './WebsiteSettings';
export default function WebsitePage({ websiteId }: { websiteId: string }) {
export default function WebsiteSettingsPage({ websiteId }: { websiteId: string }) {
return (
<WebsiteProvider websiteId={websiteId}>
<WebsiteSettings websiteId={websiteId} />

View File

@ -1,10 +1,10 @@
import WebsitePage from './WebsitePage';
import WebsiteSettingsPage from './WebsiteSettingsPage';
import { Metadata } from 'next';
export default async function ({ params: { websiteId } }) {
return <WebsitePage websiteId={websiteId} />;
return <WebsiteSettingsPage websiteId={websiteId} />;
}
export const metadata: Metadata = {
title: 'Website settings - Umami',
title: 'Website',
};

View File

@ -1,10 +1,10 @@
import { Metadata } from 'next';
import WebsitesPage from './WebsitesPage';
import WebsitesSettingsPage from './WebsitesSettingsPage';
export default function ({ params: { teamId } }: { params: { teamId: string } }) {
return <WebsitesPage teamId={teamId} />;
return <WebsitesSettingsPage teamId={teamId} />;
}
export const metadata: Metadata = {
title: 'Websites Settings | Umami',
title: 'Websites',
};

View File

@ -1,5 +1,10 @@
import TeamProvider from './TeamProvider';
import { Metadata } from 'next';
export default function ({ children, params: { teamId } }) {
return <TeamProvider teamId={teamId}>{children}</TeamProvider>;
}
export const metadata: Metadata = {
title: 'Teams',
};

View File

@ -1,3 +1,8 @@
import Page from 'app/(main)/reports/page';
import { Metadata } from 'next';
export default Page;
export const metadata: Metadata = {
title: 'Team Reports',
};

View File

@ -1,5 +1,10 @@
import TeamSettingsLayout from './TeamSettingsLayout';
import { Metadata } from 'next';
export default function ({ children, params: { teamId } }) {
return <TeamSettingsLayout teamId={teamId}>{children}</TeamSettingsLayout>;
}
export const metadata: Metadata = {
title: 'Team Settings',
};

View File

@ -1,12 +1,15 @@
'use client';
import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader';
import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable';
import { useLogin } from 'components/hooks';
export default function WebsitesPage({ teamId }: { teamId: string; userId: string }) {
const { user } = useLogin();
export default function WebsitesPage({ teamId, userId }: { teamId: string; userId: string }) {
return (
<>
<WebsitesHeader teamId={teamId} />
<WebsitesDataTable teamId={teamId} userId={userId} allowEdit={false} />
<WebsitesHeader teamId={teamId} allowCreate={user.role !== 'view-only'} />
<WebsitesDataTable teamId={teamId} allowEdit={false} />
</>
);
}

View File

@ -1,3 +1,4 @@
'use client';
import { Loading } from 'react-basics';
import { usePathname } from 'next/navigation';
import Page from 'components/layout/Page';

View File

@ -6,5 +6,5 @@ export default async function ({ params: { websiteId } }) {
}
export const metadata: Metadata = {
title: 'Event Data | Umami',
title: 'Event Data',
};

View File

@ -1,6 +1,10 @@
'use client';
import WebsiteDetails from './WebsiteDetails';
import { Metadata } from 'next';
export default function WebsitePage({ params: { websiteId } }) {
return <WebsiteDetails websiteId={websiteId} />;
}
export const metadata: Metadata = {
title: 'Websites',
};

View File

@ -1,5 +1,10 @@
import WebsiteRealtimePage from './WebsiteRealtimePage';
import { Metadata } from 'next';
export default function ({ params: { websiteId } }) {
return <WebsiteRealtimePage websiteId={websiteId} />;
}
export const metadata: Metadata = {
title: 'Real-time',
};

View File

@ -1,5 +1,10 @@
import WebsiteReportsPage from './WebsiteReportsPage';
import { Metadata } from 'next';
export default function ({ params: { websiteId } }) {
return <WebsiteReportsPage websiteId={websiteId} />;
}
export const metadata: Metadata = {
title: 'Website Reports',
};

View File

@ -6,5 +6,5 @@ export default function ({ params: { teamId, userId } }) {
}
export const metadata: Metadata = {
title: 'Websites | Umami',
title: 'Websites',
};

View File

@ -32,5 +32,8 @@ export default function ({ children }) {
}
export const metadata: Metadata = {
title: 'umami',
title: {
template: '%s | Umami',
default: 'Umami',
},
};

View File

@ -6,5 +6,5 @@ export default async function () {
}
export const metadata: Metadata = {
title: 'Login | Umami',
title: 'Login',
};

View File

@ -6,5 +6,5 @@ export default function () {
}
export const metadata: Metadata = {
title: 'Logout | Umami',
title: 'Logout',
};

View File

@ -1,10 +1,5 @@
import SharePage from './SharePage';
import { Metadata } from 'next';
export default function ({ params: { shareId } }) {
return <SharePage shareId={shareId[0]} />;
}
export const metadata: Metadata = {
title: 'umami',
};

View File

@ -23,6 +23,7 @@ export function Pager({ page, pageSize, count, onPageChange, className }: PagerP
const handlePageChange = (value: number) => {
const nextPage = page + value;
if (nextPage > 0 && nextPage <= maxPage) {
onPageChange(nextPage);
}

View File

@ -13,8 +13,9 @@ export function useWebsites(
return useFilterQuery({
queryKey: ['websites', { userId, teamId, modified, ...params }],
queryFn: () => {
queryFn: (data: any) => {
return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId || user.id}/websites`, {
...data,
...params,
});
},

View File

@ -7,12 +7,10 @@ import styles from './WebsiteSelect.module.css';
export function WebsiteSelect({
websiteId,
teamId,
userId,
onSelect,
}: {
websiteId?: string;
teamId?: string;
userId?: string;
onSelect?: (key: any) => void;
}) {
const { formatMessage, labels, messages } = useMessages();
@ -21,7 +19,7 @@ export function WebsiteSelect({
const { data: website } = useWebsite(selectedId as string);
const queryResult = useWebsites({ teamId, userId }, { query, pageSize: 5 });
const queryResult = useWebsites({ teamId }, { query, pageSize: 5 });
const renderValue = () => {
return website?.name;

View File

@ -24,7 +24,7 @@ export function ActiveUsers({
const count = useMemo(() => {
if (websiteId) {
return data?.[0]?.x || 0;
return data?.x || 0;
}
return value !== undefined ? value : 0;

View File

@ -13,7 +13,7 @@ export async function getActiveVisitors(...args: [websiteId: string]) {
async function relationalQuery(websiteId: string) {
const { rawQuery } = prisma;
return rawQuery(
const result = await rawQuery(
`
select count(distinct session_id) x
from website_event
@ -22,6 +22,8 @@ async function relationalQuery(websiteId: string) {
`,
{ websiteId, startAt: subMinutes(new Date(), 5) },
);
return result[0] ?? null;
}
async function clickhouseQuery(websiteId: string): Promise<{ x: number }> {

View File

@ -1948,51 +1948,51 @@
"@parcel/watcher-win32-ia32" "2.3.0"
"@parcel/watcher-win32-x64" "2.3.0"
"@prisma/client@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.7.0.tgz#c29dd9a16e100902eb2d2443d90fee2482d2aeac"
integrity sha512-cZmglCrfNbYpzUtz7HscVHl38e9CrUs31nrVoGUK1nIPXGgt8hT4jj2s657UXcNdQ/jBUxDgGmHyu2Nyrq1txg==
"@prisma/client@5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.9.1.tgz#d92bd2f7f006e0316cb4fda9d73f235965cf2c64"
integrity sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==
"@prisma/debug@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.7.0.tgz#abdb2060be4fe819e73e2683cf1b039841566198"
integrity sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==
"@prisma/debug@5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.9.1.tgz#906274e73d3267f88b69459199fa3c51cd9511a3"
integrity sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==
"@prisma/engines-version@5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9":
version "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9.tgz#777827898f1bfe6a76b17fbe7d9600cf543c4cc1"
integrity sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==
"@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64":
version "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64.tgz#54d2164f28d23e09d41cf9eb0bddbbe7f3aaa660"
integrity sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==
"@prisma/engines@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.7.0.tgz#a32e232819b66bd9dee7500b455781742dc54b2f"
integrity sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==
"@prisma/engines@5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.9.1.tgz#767539afc6f193a182d0495b30b027f61f279073"
integrity sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==
dependencies:
"@prisma/debug" "5.7.0"
"@prisma/engines-version" "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9"
"@prisma/fetch-engine" "5.7.0"
"@prisma/get-platform" "5.7.0"
"@prisma/debug" "5.9.1"
"@prisma/engines-version" "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64"
"@prisma/fetch-engine" "5.9.1"
"@prisma/get-platform" "5.9.1"
"@prisma/extension-read-replicas@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@prisma/extension-read-replicas/-/extension-read-replicas-0.3.0.tgz#2842a7c928f957c1dd58a6256104797596d43426"
integrity sha512-F9+rSmYday6GT2qjhJtkZcBOpLO5LtpvFcMGqrBDHf+78LEdSuxfFjOxYlNuqk4B+th62yxpbhfpmB9/Mca14Q==
"@prisma/fetch-engine@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.7.0.tgz#7d2795828b692b02707e7ab6876f6227a68fc309"
integrity sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==
"@prisma/fetch-engine@5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.9.1.tgz#5d3b2c9af54a242e37b3f9561b59ab72f8e92818"
integrity sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==
dependencies:
"@prisma/debug" "5.7.0"
"@prisma/engines-version" "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9"
"@prisma/get-platform" "5.7.0"
"@prisma/debug" "5.9.1"
"@prisma/engines-version" "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64"
"@prisma/get-platform" "5.9.1"
"@prisma/get-platform@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.7.0.tgz#eb81011f537c2d10c0225278cd5165a82d0b57c8"
integrity sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==
"@prisma/get-platform@5.9.1":
version "5.9.1"
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.9.1.tgz#a66bb46ab4d30db786c84150ef074ab0aad4549e"
integrity sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==
dependencies:
"@prisma/debug" "5.7.0"
"@prisma/debug" "5.9.1"
"@react-spring/animated@~9.7.3":
version "9.7.3"
@ -7444,12 +7444,12 @@ pretty-bytes@^5.6.0:
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
prisma@5.7.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.7.0.tgz#3c1c56d392b5d1137de954edefa4533fa092663e"
integrity sha512-0rcfXO2ErmGAtxnuTNHQT9ztL0zZheQjOI/VNJzdq87C3TlGPQtMqtM+KCwU6XtmkoEr7vbCQqA7HF9IY0ST+Q==
prisma@5.9.1:
version "5.9.1"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.9.1.tgz#baa3dd635fbf71504980978f10f55ea11068f6aa"
integrity sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==
dependencies:
"@prisma/engines" "5.7.0"
"@prisma/engines" "5.9.1"
promise.series@^0.2.0:
version "0.2.0"