diff --git a/package.json b/package.json
index 6001ee9c..367627e6 100644
--- a/package.json
+++ b/package.json
@@ -67,7 +67,7 @@
"@prisma/extension-read-replicas": "^0.3.0",
"@react-spring/web": "^9.7.3",
"@tanstack/react-query": "^5.12.2",
- "@umami/prisma-client": "^0.8.0",
+ "@umami/prisma-client": "^0.13.0",
"@umami/redis-client": "^0.18.0",
"chalk": "^4.1.1",
"chart.js": "^4.2.1",
diff --git a/src/app/(main)/settings/teams/TeamsTable.tsx b/src/app/(main)/settings/teams/TeamsTable.tsx
index 10866b4f..852b4ff4 100644
--- a/src/app/(main)/settings/teams/TeamsTable.tsx
+++ b/src/app/(main)/settings/teams/TeamsTable.tsx
@@ -17,6 +17,12 @@ export function TeamsTable({ data = [] }: { data: any[] }) {
{row => row.teamUser.find(({ role }) => role === ROLES.teamOwner)?.user?.username}
+
+ {row => row._count.website}
+
+
+ {row => row._count.teamUser}
+
{row => {
const { id, name, teamUser } = row;
diff --git a/src/app/(main)/settings/teams/[id]/TeamMembers.tsx b/src/app/(main)/settings/teams/[id]/TeamMembers.tsx
index 588a5a52..a84fad10 100644
--- a/src/app/(main)/settings/teams/[id]/TeamMembers.tsx
+++ b/src/app/(main)/settings/teams/[id]/TeamMembers.tsx
@@ -1,8 +1,8 @@
import useApi from 'components/hooks/useApi';
-import TeamMembersTable from './TeamMembersTable';
import useFilterQuery from 'components/hooks/useFilterQuery';
import DataTable from 'components/common/DataTable';
import useCache from 'store/cache';
+import TeamMembersTable from './TeamMembersTable';
export function TeamMembers({ teamId, readOnly }: { teamId: string; readOnly: boolean }) {
const { get } = useApi();
@@ -18,11 +18,9 @@ export function TeamMembers({ teamId, readOnly }: { teamId: string; readOnly: bo
});
return (
- <>
-
- {({ data }) => }
-
- >
+
+ {({ data }) => }
+
);
}
diff --git a/src/app/(main)/settings/teams/[id]/TeamSettings.tsx b/src/app/(main)/settings/teams/[id]/TeamSettings.tsx
index 1f92b095..c6285774 100644
--- a/src/app/(main)/settings/teams/[id]/TeamSettings.tsx
+++ b/src/app/(main)/settings/teams/[id]/TeamSettings.tsx
@@ -25,7 +25,6 @@ export function TeamSettings({ teamId }: { teamId: string }) {
return get(`/teams/${teamId}`);
}
},
- gcTime: 0,
});
const canEdit = data?.teamUser?.find(
({ userId, role }) => role === ROLES.teamOwner && userId === user.id,
diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.tsx b/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.tsx
deleted file mode 100644
index ee169886..00000000
--- a/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import useApi from 'components/hooks/useApi';
-import { useState } from 'react';
-import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle } from 'react-basics';
-import useMessages from 'components/hooks/useMessages';
-import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable';
-import Empty from 'components/common/Empty';
-import { setValue } from 'store/cache';
-import { useUser } from 'components/hooks';
-
-export function TeamWebsiteAddForm({
- teamId,
- onSave,
- onClose,
-}: {
- teamId: string;
- onSave: () => void;
- onClose: () => void;
-}) {
- const { user } = useUser();
- const { formatMessage, labels } = useMessages();
- const { get, post, useQuery, useMutation } = useApi();
- const { mutate, error } = useMutation({
- mutationFn: (data: any) => post(`/teams/${teamId}/websites`, data),
- });
- const { data: websites, isLoading } = useQuery({
- queryKey: ['websites'],
- queryFn: () => get('/websites'),
- });
- const [selected, setSelected] = useState([]);
- const hasData = websites && websites.data.length > 0;
-
- const handleSubmit = () => {
- mutate(
- { websiteIds: selected },
- {
- onSuccess: async () => {
- setValue('team:websites', Date.now());
- onSave?.();
- onClose?.();
- },
- },
- );
- };
-
- const handleSelect = id => {
- setSelected(state => (state.includes(id) ? state.filter(n => n !== id) : state.concat(id)));
- };
-
- return (
- <>
- {isLoading && !hasData && }
- {!isLoading && !hasData && }
- {hasData && (
-
- )}
- >
- );
-}
-
-export default TeamWebsiteAddForm;
diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsites.tsx b/src/app/(main)/settings/teams/[id]/TeamWebsites.tsx
index 93b0a662..d71ebd99 100644
--- a/src/app/(main)/settings/teams/[id]/TeamWebsites.tsx
+++ b/src/app/(main)/settings/teams/[id]/TeamWebsites.tsx
@@ -1,13 +1,13 @@
-import useFilterQuery from 'components/hooks/useFilterQuery';
+import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable';
import DataTable from 'components/common/DataTable';
+import useFilterQuery from 'components/hooks/useFilterQuery';
import useApi from 'components/hooks/useApi';
import useUser from 'components/hooks/useUser';
import useCache from 'store/cache';
-import WebsitesTable from '../../websites/WebsitesTable';
export function TeamWebsites({ teamId }: { teamId: string; readOnly: boolean }) {
- const { user } = useUser();
const { get } = useApi();
+ const { user } = useUser();
const modified = useCache(state => state?.['team:websites']);
const queryResult = useFilterQuery({
queryKey: ['team:websites', { teamId, modified }],
diff --git a/src/app/(main)/settings/teams/page.tsx b/src/app/(main)/settings/teams/page.tsx
index 0cdb6f7d..08e96595 100644
--- a/src/app/(main)/settings/teams/page.tsx
+++ b/src/app/(main)/settings/teams/page.tsx
@@ -1,6 +1,6 @@
+import { Metadata } from 'next';
import TeamsDataTable from './TeamsDataTable';
import TeamsHeader from './TeamsHeader';
-import { Metadata } from 'next';
export default function () {
if (process.env.cloudMode) {
@@ -16,5 +16,5 @@ export default function () {
}
export const metadata: Metadata = {
- title: 'Teams Settings | umami',
+ title: 'Teams Settings - Umami',
};
diff --git a/src/app/(main)/settings/users/UsersDataTable.tsx b/src/app/(main)/settings/users/UsersDataTable.tsx
index 2495d023..77243f60 100644
--- a/src/app/(main)/settings/users/UsersDataTable.tsx
+++ b/src/app/(main)/settings/users/UsersDataTable.tsx
@@ -3,10 +3,9 @@ import useApi from 'components/hooks/useApi';
import useFilterQuery from 'components/hooks/useFilterQuery';
import DataTable from 'components/common/DataTable';
import UsersTable from './UsersTable';
-import UsersHeader from './UsersHeader';
import useCache from 'store/cache';
-export function UsersDataTable() {
+export function UsersDataTable({ showActions }: { showActions: boolean }) {
const { get } = useApi();
const modified = useCache((state: any) => state?.users);
const queryResult = useFilterQuery({
@@ -15,10 +14,9 @@ export function UsersDataTable() {
});
return (
- <>
-
- {({ data }) => }
- >
+
+ {({ data }) => }
+
);
}
diff --git a/src/app/(main)/settings/users/UsersTable.tsx b/src/app/(main)/settings/users/UsersTable.tsx
index 4eb7fbb6..13f3b6f8 100644
--- a/src/app/(main)/settings/users/UsersTable.tsx
+++ b/src/app/(main)/settings/users/UsersTable.tsx
@@ -6,7 +6,13 @@ import useMessages from 'components/hooks/useMessages';
import useLocale from 'components/hooks/useLocale';
import UserDeleteButton from './UserDeleteButton';
-export function UsersTable({ data = [] }: { data: any[] }) {
+export function UsersTable({
+ data = [],
+ showActions = true,
+}: {
+ data: any[];
+ showActions?: boolean;
+}) {
const { formatMessage, labels } = useMessages();
const { dateLocale } = useLocale();
const breakpoint = useBreakpoint();
@@ -29,24 +35,26 @@ export function UsersTable({ data = [] }: { data: any[] }) {
})
}
-
- {row => {
- const { id, username } = row;
- return (
- <>
-
-
-
-
- >
- );
- }}
-
+ {showActions && (
+
+ {row => {
+ const { id, username } = row;
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }}
+
+ )}
);
}
diff --git a/src/app/(main)/settings/users/page.tsx b/src/app/(main)/settings/users/page.tsx
index 00ebe98c..06bb5f1e 100644
--- a/src/app/(main)/settings/users/page.tsx
+++ b/src/app/(main)/settings/users/page.tsx
@@ -1,8 +1,14 @@
-import UsersDataTable from './UsersDataTable';
import { Metadata } from 'next';
+import UsersDataTable from './UsersDataTable';
+import UsersHeader from './UsersHeader';
export default function () {
- return ;
+ return (
+ <>
+
+
+ >
+ );
}
export const metadata: Metadata = {
title: 'Users | umami',
diff --git a/src/components/messages.ts b/src/components/messages.ts
index 66ffea9c..00942b87 100644
--- a/src/components/messages.ts
+++ b/src/components/messages.ts
@@ -52,6 +52,7 @@ export const labels = defineMessages({
deleteWebsite: { id: 'label.delete-website', defaultMessage: 'Delete website' },
reset: { id: 'label.reset', defaultMessage: 'Reset' },
addWebsite: { id: 'label.add-website', defaultMessage: 'Add website' },
+ addMember: { id: 'label.add-member', defaultMessage: 'Add member' },
addDescription: { id: 'label.add-description', defaultMessage: 'Add description' },
changePassword: { id: 'label.change-password', defaultMessage: 'Change password' },
currentPassword: { id: 'label.current-password', defaultMessage: 'Current password' },
diff --git a/src/index.ts b/src/index.ts
index 7b192054..cbcef988 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,7 +18,6 @@ export * from 'components/hooks/useTimezone';
export * from 'components/hooks/useUser';
export * from 'components/hooks/useWebsite';
-export * from 'app/(main)/settings/teams/[id]/TeamWebsiteAddForm';
export * from 'app/(main)/settings/teams/[id]/TeamEditForm';
export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton';
export * from 'app/(main)/settings/teams/[id]/TeamMembers';
diff --git a/src/lib/auth.ts b/src/lib/auth.ts
index cb3d3cc7..6ec76abe 100644
--- a/src/lib/auth.ts
+++ b/src/lib/auth.ts
@@ -1,10 +1,10 @@
import { Report } from '@prisma/client';
import debug from 'debug';
import redis from '@umami/redis-client';
-import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants';
+import { PERMISSIONS, ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from 'lib/constants';
import { secret } from 'lib/crypto';
import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
-import { findTeamWebsiteByUserId, getTeamUser, getTeamWebsite } from 'queries';
+import { getTeamUser, getWebsiteById } from 'queries';
import { loadWebsite } from './load';
import { Auth } from './types';
import { NextApiRequest } from 'next';
@@ -55,8 +55,6 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri
if (user.id === website?.userId) {
return true;
}
-
- return !!(await findTeamWebsiteByUserId(websiteId, user.id));
}
export async function canViewAllWebsites({ user }: Auth) {
@@ -178,16 +176,12 @@ export async function canDeleteTeamWebsite({ user }: Auth, teamId: string, websi
return true;
}
- const teamWebsite = await getTeamWebsite(teamId, websiteId);
+ const teamWebsite = await getWebsiteById(websiteId);
- if (teamWebsite?.website?.userId === user.id) {
- return true;
- }
+ if (teamWebsite && teamWebsite.teamId === teamId) {
+ const teamUser = await getTeamUser(teamId, user.id);
- if (teamWebsite) {
- const teamUser = await getTeamUser(teamWebsite.teamId, user.id);
-
- return hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
+ return teamUser.role === ROLES.teamOwner || teamUser.role === ROLES.teamMember;
}
return false;
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 0c894634..7f7a8ea9 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -125,6 +125,7 @@ export const ROLES = {
viewOnly: 'view-only',
teamOwner: 'team-owner',
teamMember: 'team-member',
+ teamGuest: 'team-guest',
} as const;
export const PERMISSIONS = {
diff --git a/src/pages/api/auth/login.ts b/src/pages/api/auth/login.ts
index 00cb09d1..23bdb15f 100644
--- a/src/pages/api/auth/login.ts
+++ b/src/pages/api/auth/login.ts
@@ -68,7 +68,12 @@ export default async (
});
}
- log(`Login from ip ${getIpAddress(req)} with username "${username.replace(/["\r\n]/g, '')}" failed.`);
+ log(
+ `Login from ip ${getIpAddress(req)} with username "${username.replace(
+ /["\r\n]/g,
+ '',
+ )}" failed.`,
+ );
return unauthorized(res, 'message.incorrect-username-password');
}
diff --git a/src/pages/api/teams/[id]/websites/index.ts b/src/pages/api/teams/[id]/websites/index.ts
index 4e754d20..4fe11fb7 100644
--- a/src/pages/api/teams/[id]/websites/index.ts
+++ b/src/pages/api/teams/[id]/websites/index.ts
@@ -6,7 +6,6 @@ import { pageInfo } from 'lib/schema';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
import { getWebsitesByTeamId } from 'queries';
-import { createTeamWebsites } from 'queries/admin/teamWebsite';
export interface TeamWebsiteRequestQuery extends SearchFilter {
id: string;
@@ -52,17 +51,5 @@ export default async (
return ok(res, websites);
}
- if (req.method === 'POST') {
- if (!(await canViewTeam(req.auth, teamId))) {
- return unauthorized(res);
- }
-
- const { websiteIds } = req.body;
-
- const websites = await createTeamWebsites(teamId, websiteIds);
-
- return ok(res, websites);
- }
-
return methodNotAllowed(res);
};
diff --git a/src/queries/admin/team.ts b/src/queries/admin/team.ts
index 7bfbfd21..4af1dc97 100644
--- a/src/queries/admin/team.ts
+++ b/src/queries/admin/team.ts
@@ -10,8 +10,9 @@ export interface GetTeamOptions {
async function getTeam(where: Prisma.TeamWhereInput, options: GetTeamOptions = {}): Promise {
const { includeTeamUser = false } = options;
+ const { client } = prisma;
- return prisma.client.team.findFirst({
+ return client.team.findFirst({
where,
include: {
teamUser: includeTeamUser,
@@ -27,14 +28,15 @@ export function getTeamByAccessCode(accessCode: string, options: GetTeamOptions
return getTeam({ accessCode }, options);
}
-export async function createTeam(data: Prisma.TeamCreateInput, userId: string): Promise {
+export async function createTeam(data: Prisma.TeamCreateInput, userId: string): Promise {
const { id } = data;
+ const { client, transaction } = prisma;
- return prisma.transaction([
- prisma.client.team.create({
+ return transaction([
+ client.team.create({
data,
}),
- prisma.client.teamUser.create({
+ client.teamUser.create({
data: {
id: uuid(),
teamId: id,
@@ -46,7 +48,9 @@ export async function createTeam(data: Prisma.TeamCreateInput, userId: string):
}
export async function updateTeam(teamId: string, data: Prisma.TeamUpdateInput): Promise {
- return prisma.client.team.update({
+ const { client } = prisma;
+
+ return client.team.update({
where: {
id: teamId,
},
@@ -61,13 +65,22 @@ export async function deleteTeam(
teamId: string,
): Promise> {
const { client, transaction } = prisma;
+ const cloudMode = process.env.CLOUD_MODE;
+
+ if (cloudMode) {
+ return transaction([
+ client.team.update({
+ data: {
+ deletedAt: new Date(),
+ },
+ where: {
+ id: teamId,
+ },
+ }),
+ ]);
+ }
return transaction([
- client.teamWebsite.deleteMany({
- where: {
- teamId,
- },
- }),
client.teamUser.deleteMany({
where: {
teamId,
@@ -87,6 +100,7 @@ export async function getTeams(
): Promise> {
const { userId, query } = filters;
const mode = prisma.getQueryMode();
+ const { client } = prisma;
const where: Prisma.TeamWhereInput = {
...(userId && {
@@ -123,7 +137,7 @@ export async function getTeams(
...filters,
});
- const teams = await prisma.client.team.findMany({
+ const teams = await client.team.findMany({
where: {
...where,
},
@@ -131,7 +145,7 @@ export async function getTeams(
...(options?.include && { include: options?.include }),
});
- const count = await prisma.client.team.count({ where });
+ const count = await client.team.count({ where });
return { data: teams, count, ...getParameters };
}
@@ -154,6 +168,9 @@ export async function getTeamsByUserId(
},
},
},
+ _count: {
+ select: { website: true, teamUser: true },
+ },
},
},
);
diff --git a/src/queries/admin/teamUser.ts b/src/queries/admin/teamUser.ts
index c5b27a02..de29ce21 100644
--- a/src/queries/admin/teamUser.ts
+++ b/src/queries/admin/teamUser.ts
@@ -68,14 +68,6 @@ export async function deleteTeamUser(teamId: string, userId: string): Promise {
- return prisma.client.teamWebsite.findFirst({
- where: {
- teamId,
- websiteId,
- },
- include: {
- website: true,
- },
- });
-}
-
-export async function findTeamWebsiteByUserId(
- websiteId: string,
- userId: string,
-): Promise {
- return prisma.client.teamWebsite.findFirst({
- where: {
- websiteId,
- team: {
- teamUser: {
- some: {
- userId,
- },
- },
- },
- },
- });
-}
-
-export async function getTeamWebsites(teamId: string): Promise<
- (TeamWebsite & {
- team: Team & { teamUser: TeamUser[] };
- website: Website & {
- user: { id: string; username: string };
- };
- })[]
-> {
- return prisma.client.teamWebsite.findMany({
- where: {
- teamId,
- },
- include: {
- team: {
- include: {
- teamUser: {
- where: {
- role: ROLES.teamOwner,
- },
- },
- },
- },
- website: {
- include: {
- user: {
- select: {
- id: true,
- username: true,
- },
- },
- },
- },
- },
- orderBy: [
- {
- team: {
- name: 'asc',
- },
- },
- ],
- });
-}
-
-export async function createTeamWebsite(teamId: string, websiteId: string): Promise {
- return prisma.client.teamWebsite.create({
- data: {
- id: uuid(),
- teamId,
- websiteId,
- },
- });
-}
-
-export async function createTeamWebsites(teamId: string, websiteIds: string[]) {
- const currentTeamWebsites = await getTeamWebsites(teamId);
-
- // filter out websites that already exists on the team
- const addWebsites = websiteIds.filter(
- websiteId => !currentTeamWebsites.some(a => a.websiteId === websiteId),
- );
-
- const teamWebsites: Prisma.TeamWebsiteCreateManyInput[] = addWebsites.map(a => {
- return {
- id: uuid(),
- teamId,
- websiteId: a,
- };
- });
-
- return prisma.client.teamWebsite.createMany({
- data: teamWebsites,
- });
-}
-
-export async function deleteTeamWebsite(
- teamId: string,
- websiteId: string,
-): Promise {
- return prisma.client.teamWebsite.deleteMany({
- where: {
- teamId,
- websiteId,
- },
- });
-}
diff --git a/src/queries/admin/user.ts b/src/queries/admin/user.ts
index 338b9192..29d94ec8 100644
--- a/src/queries/admin/user.ts
+++ b/src/queries/admin/user.ts
@@ -105,6 +105,7 @@ export async function getUsersByTeamId(teamId: string, filter?: UserSearchFilter
include: {
teamUser: {
select: {
+ teamId: true,
role: true,
},
},
@@ -188,7 +189,27 @@ export async function deleteUser(
const teamIds = teams.map(a => a.id);
- return prisma
+ if (cloudMode) {
+ return client.transaction([
+ client.website.updateMany({
+ data: {
+ deletedAt: new Date(),
+ },
+ where: { id: { in: websiteIds } },
+ }),
+ client.user.update({
+ data: {
+ username: getRandomChars(32),
+ deletedAt: new Date(),
+ },
+ where: {
+ id: userId,
+ },
+ }),
+ ]);
+ }
+
+ return client
.transaction([
client.eventData.deleteMany({
where: { websiteId: { in: websiteIds } },
@@ -199,29 +220,6 @@ export async function deleteUser(
client.session.deleteMany({
where: { websiteId: { in: websiteIds } },
}),
- client.teamWebsite.deleteMany({
- where: {
- OR: [
- {
- websiteId: {
- in: websiteIds,
- },
- },
- {
- teamId: {
- in: teamIds,
- },
- },
- ],
- },
- }),
- client.teamWebsite.deleteMany({
- where: {
- teamId: {
- in: teamIds,
- },
- },
- }),
client.teamUser.deleteMany({
where: {
OR: [
@@ -257,33 +255,16 @@ export async function deleteUser(
],
},
}),
- cloudMode
- ? client.website.updateMany({
- data: {
- deletedAt: new Date(),
- },
- where: { id: { in: websiteIds } },
- })
- : client.website.deleteMany({
- where: { id: { in: websiteIds } },
- }),
- cloudMode
- ? client.user.update({
- data: {
- username: getRandomChars(32),
- deletedAt: new Date(),
- },
- where: {
- id: userId,
- },
- })
- : client.user.delete({
- where: {
- id: userId,
- },
- }),
+ client.website.deleteMany({
+ where: { id: { in: websiteIds } },
+ }),
+ client.user.delete({
+ where: {
+ id: userId,
+ },
+ }),
])
- .then(async data => {
+ .then(async (data: any) => {
if (cache.enabled) {
const ids = websites.map(a => a.id);
diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts
index ed166371..7789a6ec 100644
--- a/src/queries/admin/website.ts
+++ b/src/queries/admin/website.ts
@@ -260,7 +260,7 @@ export async function deleteWebsite(
},
}),
cloudMode
- ? prisma.client.website.update({
+ ? client.website.update({
data: {
deletedAt: new Date(),
},
diff --git a/src/queries/index.js b/src/queries/index.js
index 452d85a6..afec8e4e 100644
--- a/src/queries/index.js
+++ b/src/queries/index.js
@@ -1,7 +1,6 @@
export * from './admin/report';
export * from './admin/team';
export * from './admin/teamUser';
-export * from './admin/teamWebsite';
export * from './admin/user';
export * from './admin/website';
export * from './analytics/events/getEventMetrics';
diff --git a/yarn.lock b/yarn.lock
index 193806f3..a49c8003 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2597,13 +2597,15 @@
"@typescript-eslint/types" "6.14.0"
eslint-visitor-keys "^3.4.1"
-"@umami/prisma-client@^0.8.0":
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.8.0.tgz#9f866c813b15b7ab0e7632506316bf1e5d2e74cc"
- integrity sha512-ix3/75CO3eVlf1Rg0cUIjoHDFJV7nxx5sSh1NnvbjyGn8EsTpZ7fVYF874w8+ENQsaKFIMftUSGGiwvgxaZN3g==
+"@umami/prisma-client@^0.13.0":
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.13.0.tgz#00ed90adf36e8e8cb7301ab557ad617dd946188f"
+ integrity sha512-HkhwTH7cxkbqlxw6LK8QGbEaIl0aYZeVf5bUwncv68C/RaQrQ0/g9x6TzHo6uKlSgk2LtavnGwxYmjxD1fdGQw==
dependencies:
+ "@prisma/extension-read-replicas" "^0.3.0"
chalk "^4.1.2"
debug "^4.3.4"
+ sql-formatter "^15.1.2"
"@umami/redis-client@^0.18.0":
version "0.18.0"
@@ -3377,7 +3379,7 @@ commander@11.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67"
integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==
-commander@2, commander@^2.20.0, commander@^2.20.3:
+commander@2, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -3933,6 +3935,11 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
+discontinuous-range@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
+ integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==
+
doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -4793,6 +4800,11 @@ get-port-please@^3.1.1:
resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.1.tgz#2556623cddb4801d823c0a6a15eec038abb483be"
integrity sha512-3UBAyM3u4ZBVYDsxOQfJDxEa6XTbpBDrOjp4mf7ExFRt5BKs/QywQQiJsh2B+hxcZLSapWqCRvElUe8DnKcFHA==
+get-stdin@=8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
+ integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
+
get-stream@^6.0.0, get-stream@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
@@ -6308,6 +6320,11 @@ moment-timezone@^0.5.35:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
+moo@^0.5.0:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"
+ integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
+
mri@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
@@ -6353,6 +6370,16 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+nearley@^2.20.1:
+ version "2.20.1"
+ resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474"
+ integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==
+ dependencies:
+ commander "^2.19.0"
+ moo "^0.5.0"
+ railroad-diagrams "^1.0.0"
+ randexp "0.4.6"
+
next-basics@^0.39.0:
version "0.39.0"
resolved "https://registry.yarnpkg.com/next-basics/-/next-basics-0.39.0.tgz#1ec448a1c12966a82067445bfb9319b7e883dd6a"
@@ -7507,6 +7534,19 @@ raf-schd@^4.0.2:
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
+railroad-diagrams@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
+ integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==
+
+randexp@0.4.6:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
+ integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==
+ dependencies:
+ discontinuous-range "1.0.0"
+ ret "~0.1.10"
+
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -7883,6 +7923,11 @@ restore-cursor@^4.0.0:
onetime "^5.1.0"
signal-exit "^3.0.2"
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+ integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
@@ -8280,6 +8325,15 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+sql-formatter@^15.1.2:
+ version "15.1.2"
+ resolved "https://registry.yarnpkg.com/sql-formatter/-/sql-formatter-15.1.2.tgz#86df2592eedf6d422244e10e00a74380c22791b7"
+ integrity sha512-zBrLBclCNurCsQaO6yMvkXzHvv7eJPjiF8LIEQ5HdBV/x6UuWIZwqss3mlZ/6HLj+VYhFKeHpQnyLuZWG2agKQ==
+ dependencies:
+ argparse "^2.0.1"
+ get-stdin "=8.0.0"
+ nearley "^2.20.1"
+
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"