mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-08 16:21:09 -06:00
chore: add authorization to server actions for Actions (#868)
* poc: use server session and api key validation on deletion * feat: use server session and api key validation on deletion and creation * feat: packages/lib/apiKey for apiKey services and auth * shubham/auth-for-api-key * fix: caching * feat: handle authorization for action creation, update, delete * feat: use cached method across and wrapper for authzn check * fix: club caching methods and use authzn errors * feat: add caching in canUserAccessApiKey * feat: add caching in canUserAccessAction and use Authzn error * fix: rename action to actionClass wherever needed * fix: use cache getActionClass * fix: make changes * fix: import --------- Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
committed by
GitHub
parent
e01d5a44f4
commit
c4b4d2a312
@@ -9,11 +9,14 @@ import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { testURLmatch } from "./testURLmatch";
|
||||
import { deleteActionClass, updateActionClass } from "@formbricks/lib/services/actionClass";
|
||||
import { TActionClassInput, TActionClassNoCodeConfig } from "@formbricks/types/v1/actionClasses";
|
||||
import { CssSelector } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/(selectors)/CssSelector";
|
||||
import { PageUrlSelector } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/(selectors)/PageUrlSelector";
|
||||
import { InnerHtmlSelector } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/(selectors)/InnerHtmlSelector";
|
||||
import {
|
||||
deleteActionClassAction,
|
||||
updateActionClassAction,
|
||||
} from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/actions";
|
||||
|
||||
interface ActionSettingsTabProps {
|
||||
environmentId: string;
|
||||
@@ -77,10 +80,11 @@ export default function ActionSettingsTab({ environmentId, actionClass, setOpen
|
||||
const filteredNoCodeConfig = filterNoCodeConfig(data.noCodeConfig as NoCodeConfig);
|
||||
const updatedData: TActionClassInput = {
|
||||
...data,
|
||||
environmentId,
|
||||
noCodeConfig: filteredNoCodeConfig,
|
||||
type: "noCode",
|
||||
} as TActionClassInput;
|
||||
await updateActionClass(environmentId, actionClass.id, updatedData);
|
||||
await updateActionClassAction(environmentId, actionClass.id, updatedData);
|
||||
setOpen(false);
|
||||
router.refresh();
|
||||
toast.success("Action updated successfully");
|
||||
@@ -94,7 +98,7 @@ export default function ActionSettingsTab({ environmentId, actionClass, setOpen
|
||||
const handleDeleteAction = async () => {
|
||||
try {
|
||||
setIsDeletingAction(true);
|
||||
await deleteActionClass(environmentId, actionClass.id);
|
||||
await deleteActionClassAction(environmentId, actionClass.id);
|
||||
router.refresh();
|
||||
toast.success("Action deleted successfully");
|
||||
setOpen(false);
|
||||
|
||||
@@ -7,7 +7,6 @@ import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
import { testURLmatch } from "./testURLmatch";
|
||||
import { createActionClass } from "@formbricks/lib/services/actionClass";
|
||||
import {
|
||||
TActionClassInput,
|
||||
TActionClassNoCodeConfig,
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
import { CssSelector } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/(selectors)/CssSelector";
|
||||
import { PageUrlSelector } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/(selectors)/PageUrlSelector";
|
||||
import { InnerHtmlSelector } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/(selectors)/InnerHtmlSelector";
|
||||
import { createActionClassAction } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/actions";
|
||||
|
||||
interface AddNoCodeActionModalProps {
|
||||
environmentId: string;
|
||||
@@ -84,7 +84,7 @@ export default function AddNoCodeActionModal({
|
||||
type: "noCode",
|
||||
} as TActionClassInput;
|
||||
|
||||
const newActionClass: TActionClass = await createActionClass(environmentId, updatedData);
|
||||
const newActionClass: TActionClass = await createActionClassAction(updatedData);
|
||||
if (setActionClassArray) {
|
||||
setActionClassArray((prevActionClassArray: TActionClass[]) => [
|
||||
...prevActionClassArray,
|
||||
|
||||
@@ -1,27 +1,93 @@
|
||||
"use server";
|
||||
|
||||
import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
|
||||
import { createActionClass, deleteActionClass, updateActionClass } from "@formbricks/lib/actionClass/service";
|
||||
import { canUserAccessActionClass } from "@formbricks/lib/actionClass/auth";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { TActionClassInput } from "@formbricks/types/v1/actionClasses";
|
||||
|
||||
import {
|
||||
getActionCountInLast24Hours,
|
||||
getActionCountInLast7Days,
|
||||
getActionCountInLastHour,
|
||||
} from "@formbricks/lib/services/actions";
|
||||
import { getSurveysByActionClassId } from "@formbricks/lib/services/survey";
|
||||
import { AuthorizationError } from "@formbricks/types/v1/errors";
|
||||
|
||||
export async function deleteActionClassAction(environmentId, actionClassId: string) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessActionClass(session.user.id, actionClassId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
await deleteActionClass(environmentId, actionClassId);
|
||||
}
|
||||
|
||||
export async function updateActionClassAction(
|
||||
environmentId: string,
|
||||
actionClassId: string,
|
||||
updatedAction: Partial<TActionClassInput>
|
||||
) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessActionClass(session.user.id, actionClassId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await updateActionClass(environmentId, actionClassId, updatedAction);
|
||||
}
|
||||
|
||||
export async function createActionClassAction(action: TActionClassInput) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await hasUserEnvironmentAccess(session.user.id, action.environmentId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await createActionClass(action.environmentId, action);
|
||||
}
|
||||
|
||||
export const getActionCountInLastHourAction = async (actionClassId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessActionClass(session.user.id, actionClassId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await getActionCountInLastHour(actionClassId);
|
||||
};
|
||||
|
||||
export const getActionCountInLast24HoursAction = async (actionClassId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessActionClass(session.user.id, actionClassId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await getActionCountInLast24Hours(actionClassId);
|
||||
};
|
||||
|
||||
export const getActionCountInLast7DaysAction = async (actionClassId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessActionClass(session.user.id, actionClassId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await getActionCountInLast7Days(actionClassId);
|
||||
};
|
||||
|
||||
export const GetActiveInactiveSurveysAction = async (
|
||||
actionClassId: string
|
||||
): Promise<{ activeSurveys: string[]; inactiveSurveys: string[] }> => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessActionClass(session.user.id, actionClassId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const surveys = await getSurveysByActionClassId(actionClassId);
|
||||
const response = {
|
||||
activeSurveys: surveys.filter((s) => s.status === "inProgress").map((survey) => survey.name),
|
||||
|
||||
@@ -4,7 +4,7 @@ import ActionClassesTable from "@/app/(app)/environments/[environmentId]/(action
|
||||
import ActionClassDataRow from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/ActionRowData";
|
||||
import ActionTableHeading from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/ActionTableHeading";
|
||||
import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
|
||||
import { getActionClasses } from "@formbricks/lib/services/actionClass";
|
||||
import { getActionClasses } from "@formbricks/lib/actionClass/service";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
||||
@@ -11,22 +11,18 @@ import { AuthorizationError } from "@formbricks/types/v1/errors";
|
||||
export async function deleteApiKeyAction(id: string) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
const isAuthorized = await canUserAccessApiKey(session.user.id, id);
|
||||
|
||||
if (isAuthorized) {
|
||||
return await deleteApiKey(id);
|
||||
} else {
|
||||
throw new AuthorizationError("Not authorized");
|
||||
}
|
||||
const isAuthorized = await canUserAccessApiKey(session.user.id, id);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await deleteApiKey(id);
|
||||
}
|
||||
export async function createApiKeyAction(environmentId: string, apiKeyData: TApiKeyCreateInput) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
const isAuthorized = await hasUserEnvironmentAccess(session.user.id, environmentId);
|
||||
|
||||
if (isAuthorized) {
|
||||
return await createApiKey(environmentId, apiKeyData);
|
||||
} else {
|
||||
throw new AuthorizationError("Not authorized");
|
||||
}
|
||||
const isAuthorized = await hasUserEnvironmentAccess(session.user.id, environmentId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await createApiKey(environmentId, apiKeyData);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import SurveyEditor from "./SurveyEditor";
|
||||
import { getSurveyWithAnalytics } from "@formbricks/lib/services/survey";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/services/product";
|
||||
import { getEnvironment } from "@formbricks/lib/services/environment";
|
||||
import { getActionClasses } from "@formbricks/lib/services/actionClass";
|
||||
import { getActionClasses } from "@formbricks/lib/actionClass/service";
|
||||
import { getAttributeClasses } from "@formbricks/lib/services/attributeClass";
|
||||
import { ErrorComponent } from "@formbricks/ui";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getSurveysCached } from "@/app/api/v1/js/surveys";
|
||||
import { MAU_LIMIT } from "@formbricks/lib/constants";
|
||||
import { getActionClassesCached } from "@formbricks/lib/services/actionClass";
|
||||
import { getActionClasses } from "@formbricks/lib/actionClass/service";
|
||||
import { getEnvironment } from "@formbricks/lib/services/environment";
|
||||
import { createPerson, getMonthlyActivePeopleCount, getPersonCached } from "@formbricks/lib/services/person";
|
||||
import { getProductByEnvironmentIdCached } from "@formbricks/lib/services/product";
|
||||
@@ -101,7 +101,7 @@ export const getUpdatedState = async (
|
||||
// get/create rest of the state
|
||||
const [surveys, noCodeActionClasses, product] = await Promise.all([
|
||||
getSurveysCached(environmentId, person),
|
||||
getActionClassesCached(environmentId),
|
||||
getActionClasses(environmentId),
|
||||
getProductByEnvironmentIdCached(environmentId),
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { NextResponse } from "next/server";
|
||||
import { deleteActionClass, getActionClass, updateActionClass } from "@formbricks/lib/services/actionClass";
|
||||
import { deleteActionClass, getActionClass, updateActionClass } from "@formbricks/lib/actionClass/service";
|
||||
import { TActionClass, ZActionClassInput } from "@formbricks/types/v1/actionClasses";
|
||||
import { authenticateRequest } from "@/app/api/v1/auth";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DatabaseError } from "@formbricks/types/v1/errors";
|
||||
import { authenticateRequest } from "@/app/api/v1/auth";
|
||||
import { NextResponse } from "next/server";
|
||||
import { TActionClass, ZActionClassInput } from "@formbricks/types/v1/actionClasses";
|
||||
import { createActionClass, getActionClasses } from "@formbricks/lib/services/actionClass";
|
||||
import { createActionClass, getActionClasses } from "@formbricks/lib/actionClass/service";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
|
||||
24
packages/lib/actionClass/auth.ts
Normal file
24
packages/lib/actionClass/auth.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { hasUserEnvironmentAccess } from "../environment/auth";
|
||||
import { getActionClass } from "./service";
|
||||
import { unstable_cache } from "next/cache";
|
||||
|
||||
export const canUserAccessActionClass = async (userId: string, actionClassId: string): Promise<boolean> =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([userId, ZId], [actionClassId, ZId]);
|
||||
if (!userId) return false;
|
||||
|
||||
const actionClass = await getActionClass(actionClassId);
|
||||
if (!actionClass) return false;
|
||||
|
||||
const hasAccessToEnvironment = await hasUserEnvironmentAccess(userId, actionClass.environmentId);
|
||||
if (!hasAccessToEnvironment) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
[`users-${userId}-actionClasses-${actionClassId}`],
|
||||
{ revalidate: 30 * 60, tags: [`actionClasses-${actionClassId}`] }
|
||||
)(); // 30 minutes
|
||||
@@ -6,22 +6,15 @@ import { TActionClass, TActionClassInput, ZActionClassInput } from "@formbricks/
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import { cache } from "react";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
|
||||
const halfHourInSeconds = 60 * 30;
|
||||
|
||||
export const getActionClassCacheTag = (name: string, environmentId: string): string =>
|
||||
`environments-${environmentId}-actionClass-${name}`;
|
||||
const getActionClassCacheKey = (name: string, environmentId: string): string[] => [
|
||||
getActionClassCacheTag(name, environmentId),
|
||||
];
|
||||
|
||||
const getActionClassesCacheTag = (environmentId: string): string =>
|
||||
`environments-${environmentId}-actionClasses`;
|
||||
const getActionClassesCacheKey = (environmentId: string): string[] => [
|
||||
getActionClassesCacheTag(environmentId),
|
||||
];
|
||||
|
||||
const select = {
|
||||
id: true,
|
||||
@@ -34,33 +27,29 @@ const select = {
|
||||
environmentId: true,
|
||||
};
|
||||
|
||||
export const getActionClasses = cache(async (environmentId: string): Promise<TActionClass[]> => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
try {
|
||||
let actionClasses = await prisma.eventClass.findMany({
|
||||
where: {
|
||||
environmentId: environmentId,
|
||||
},
|
||||
select,
|
||||
orderBy: {
|
||||
createdAt: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
return actionClasses;
|
||||
} catch (error) {
|
||||
throw new DatabaseError(`Database error when fetching actions for environment ${environmentId}`);
|
||||
}
|
||||
});
|
||||
|
||||
export const getActionClassesCached = (environmentId: string) =>
|
||||
export const getActionClasses = (environmentId: string): Promise<TActionClass[]> =>
|
||||
unstable_cache(
|
||||
async () => {
|
||||
return await getActionClasses(environmentId);
|
||||
validateInputs([environmentId, ZId]);
|
||||
try {
|
||||
let actionClasses = await prisma.eventClass.findMany({
|
||||
where: {
|
||||
environmentId: environmentId,
|
||||
},
|
||||
select,
|
||||
orderBy: {
|
||||
createdAt: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
return actionClasses;
|
||||
} catch (error) {
|
||||
throw new DatabaseError(`Database error when fetching actions for environment ${environmentId}`);
|
||||
}
|
||||
},
|
||||
getActionClassesCacheKey(environmentId),
|
||||
[`environments-${environmentId}-actionClasses`],
|
||||
{
|
||||
tags: getActionClassesCacheKey(environmentId),
|
||||
tags: [getActionClassesCacheTag(environmentId)],
|
||||
revalidate: halfHourInSeconds,
|
||||
}
|
||||
)();
|
||||
@@ -96,7 +85,7 @@ export const deleteActionClass = async (
|
||||
if (result === null) throw new ResourceNotFoundError("Action", actionClassId);
|
||||
|
||||
// revalidate cache
|
||||
revalidateTag(getActionClassesCacheTag(environmentId));
|
||||
revalidateTag(getActionClassesCacheTag(result.environmentId));
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -157,8 +146,8 @@ export const updateActionClass = async (
|
||||
});
|
||||
|
||||
// revalidate cache
|
||||
revalidateTag(getActionClassCacheTag(result.name, environmentId));
|
||||
revalidateTag(getActionClassesCacheTag(environmentId));
|
||||
revalidateTag(getActionClassCacheTag(result.name, result.environmentId));
|
||||
revalidateTag(getActionClassesCacheTag(result.environmentId));
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -176,9 +165,9 @@ export const getActionClassCached = async (name: string, environmentId: string)
|
||||
},
|
||||
});
|
||||
},
|
||||
getActionClassCacheKey(name, environmentId),
|
||||
[`environments-${environmentId}-actionClasses-${name}`],
|
||||
{
|
||||
tags: getActionClassCacheKey(name, environmentId),
|
||||
tags: [getActionClassesCacheTag(environmentId)],
|
||||
revalidate: halfHourInSeconds,
|
||||
}
|
||||
)();
|
||||
@@ -2,8 +2,8 @@ import { hasUserEnvironmentAccess } from "../environment/auth";
|
||||
import { getApiKey } from "./service";
|
||||
import { unstable_cache } from "next/cache";
|
||||
|
||||
export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Promise<boolean> => {
|
||||
return await unstable_cache(
|
||||
export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Promise<boolean> =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
if (!userId) return false;
|
||||
|
||||
@@ -19,4 +19,3 @@ export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Pro
|
||||
[`users-${userId}-apiKeys-${apiKeyId}`],
|
||||
{ revalidate: 30 * 60, tags: [`apiKeys-${apiKeyId}`] }
|
||||
)(); // 30 minutes
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import { validateInputs } from "../utils/validate";
|
||||
import { TJsActionInput } from "@formbricks/types/v1/js";
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { EventType } from "@prisma/client";
|
||||
import { getActionClassCacheTag, getActionClassCached } from "../services/actionClass";
|
||||
import { getActionClassCacheTag, getActionClassCached } from "../actionClass/service";
|
||||
import { getSessionCached } from "../services/session";
|
||||
|
||||
export const getActionsByEnvironmentId = cache(
|
||||
|
||||
93
pnpm-lock.yaml
generated
93
pnpm-lock.yaml
generated
@@ -28,7 +28,7 @@ importers:
|
||||
version: 3.12.7
|
||||
turbo:
|
||||
specifier: latest
|
||||
version: 1.10.12
|
||||
version: 1.10.13
|
||||
|
||||
apps/demo:
|
||||
dependencies:
|
||||
@@ -438,7 +438,7 @@ importers:
|
||||
version: 9.0.0(eslint@8.50.0)
|
||||
eslint-config-turbo:
|
||||
specifier: latest
|
||||
version: 1.10.12(eslint@8.50.0)
|
||||
version: 1.8.8(eslint@8.50.0)
|
||||
eslint-plugin-react:
|
||||
specifier: 7.33.2
|
||||
version: 7.33.2(eslint@8.50.0)
|
||||
@@ -1151,7 +1151,7 @@ packages:
|
||||
'@babel/helper-plugin-utils': 7.22.5
|
||||
debug: 4.3.4
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.2
|
||||
resolve: 1.22.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -10677,13 +10677,13 @@ packages:
|
||||
resolution: {integrity: sha512-NB/L/1Y30qyJcG5xZxCJKW/+bqyj+llbcCwo9DEz8bESIP0SLTOQ8T1DWCCFc+wJ61AMEstj4511PSScqMMfCw==}
|
||||
dev: true
|
||||
|
||||
/eslint-config-turbo@1.10.12(eslint@8.50.0):
|
||||
resolution: {integrity: sha512-z3jfh+D7UGYlzMWGh+Kqz++hf8LOE96q3o5R8X4HTjmxaBWlLAWG+0Ounr38h+JLR2TJno0hU9zfzoPNkR9BdA==}
|
||||
/eslint-config-turbo@1.8.8(eslint@8.50.0):
|
||||
resolution: {integrity: sha512-+yT22sHOT5iC1sbBXfLIdXfbZuiv9bAyOXsxTxFCWelTeFFnANqmuKB3x274CFvf7WRuZ/vYP/VMjzU9xnFnxA==}
|
||||
peerDependencies:
|
||||
eslint: '>6.6.0'
|
||||
dependencies:
|
||||
eslint: 8.50.0
|
||||
eslint-plugin-turbo: 1.10.12(eslint@8.50.0)
|
||||
eslint-plugin-turbo: 1.8.8(eslint@8.50.0)
|
||||
dev: true
|
||||
|
||||
/eslint-import-resolver-node@0.3.9:
|
||||
@@ -10889,12 +10889,11 @@ packages:
|
||||
semver: 6.3.1
|
||||
string.prototype.matchall: 4.0.8
|
||||
|
||||
/eslint-plugin-turbo@1.10.12(eslint@8.50.0):
|
||||
resolution: {integrity: sha512-uNbdj+ohZaYo4tFJ6dStRXu2FZigwulR1b3URPXe0Q8YaE7thuekKNP+54CHtZPH9Zey9dmDx5btAQl9mfzGOw==}
|
||||
/eslint-plugin-turbo@1.8.8(eslint@8.50.0):
|
||||
resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==}
|
||||
peerDependencies:
|
||||
eslint: '>6.6.0'
|
||||
dependencies:
|
||||
dotenv: 16.0.3
|
||||
eslint: 8.50.0
|
||||
dev: true
|
||||
|
||||
@@ -13163,11 +13162,6 @@ packages:
|
||||
rgba-regex: 1.0.0
|
||||
dev: true
|
||||
|
||||
/is-core-module@2.11.0:
|
||||
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
||||
dependencies:
|
||||
has: 1.0.3
|
||||
|
||||
/is-core-module@2.13.0:
|
||||
resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
|
||||
dependencies:
|
||||
@@ -14722,7 +14716,7 @@ packages:
|
||||
is-plain-object: 2.0.4
|
||||
object.map: 1.0.1
|
||||
rechoir: 0.6.2
|
||||
resolve: 1.22.2
|
||||
resolve: 1.22.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -15145,7 +15139,7 @@ packages:
|
||||
dependencies:
|
||||
findup-sync: 2.0.0
|
||||
micromatch: 3.1.10
|
||||
resolve: 1.22.2
|
||||
resolve: 1.22.6
|
||||
stack-trace: 0.0.10
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -16561,7 +16555,7 @@ packages:
|
||||
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
|
||||
dependencies:
|
||||
hosted-git-info: 2.8.9
|
||||
resolve: 1.22.2
|
||||
resolve: 1.22.6
|
||||
semver: 5.7.2
|
||||
validate-npm-package-license: 3.0.4
|
||||
dev: true
|
||||
@@ -17625,7 +17619,7 @@ packages:
|
||||
postcss: 8.4.27
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.2
|
||||
resolve: 1.22.6
|
||||
|
||||
/postcss-js@4.0.1(postcss@8.4.27):
|
||||
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
|
||||
@@ -19921,7 +19915,7 @@ packages:
|
||||
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.11.0
|
||||
is-core-module: 2.13.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
@@ -19930,7 +19924,7 @@ packages:
|
||||
resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.11.0
|
||||
is-core-module: 2.13.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
@@ -19946,7 +19940,7 @@ packages:
|
||||
resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.11.0
|
||||
is-core-module: 2.13.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
@@ -20121,16 +20115,8 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/rollup@3.28.1:
|
||||
resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==}
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/rollup@3.5.1:
|
||||
resolution: {integrity: sha512-hdQWTvPeiAbM6SUkxV70HdGUVxsgsc+CLy5fuh4KdgUBJ0SowXiix8gANgXoG3wEuLwfoJhCT2V+WwxfWq9Ikw==}
|
||||
/rollup@3.29.4:
|
||||
resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
@@ -21999,7 +21985,7 @@ packages:
|
||||
joycon: 3.1.1
|
||||
postcss-load-config: 4.0.1(postcss@8.4.27)
|
||||
resolve-from: 5.0.0
|
||||
rollup: 3.5.1
|
||||
rollup: 3.29.4
|
||||
source-map: 0.8.0-beta.0
|
||||
sucrase: 3.32.0
|
||||
tree-kill: 1.2.2
|
||||
@@ -22053,65 +22039,64 @@ packages:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
/turbo-darwin-64@1.10.12:
|
||||
resolution: {integrity: sha512-vmDfGVPl5/aFenAbOj3eOx3ePNcWVUyZwYr7taRl0ZBbmv2TzjRiFotO4vrKCiTVnbqjQqAFQWY2ugbqCI1kOQ==}
|
||||
/turbo-darwin-64@1.10.13:
|
||||
resolution: {integrity: sha512-vmngGfa2dlYvX7UFVncsNDMuT4X2KPyPJ2Jj+xvf5nvQnZR/3IeDEGleGVuMi/hRzdinoxwXqgk9flEmAYp0Xw==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-darwin-arm64@1.10.12:
|
||||
resolution: {integrity: sha512-3JliEESLNX2s7g54SOBqqkqJ7UhcOGkS0ywMr5SNuvF6kWVTbuUq7uBU/sVbGq8RwvK1ONlhPvJne5MUqBCTCQ==}
|
||||
/turbo-darwin-arm64@1.10.13:
|
||||
resolution: {integrity: sha512-eMoJC+k7gIS4i2qL6rKmrIQGP6Wr9nN4odzzgHFngLTMimok2cGLK3qbJs5O5F/XAtEeRAmuxeRnzQwTl/iuAw==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-64@1.10.12:
|
||||
resolution: {integrity: sha512-siYhgeX0DidIfHSgCR95b8xPee9enKSOjCzx7EjTLmPqPaCiVebRYvbOIYdQWRqiaKh9yfhUtFmtMOMScUf1gg==}
|
||||
/turbo-linux-64@1.10.13:
|
||||
resolution: {integrity: sha512-0CyYmnKTs6kcx7+JRH3nPEqCnzWduM0hj8GP/aodhaIkLNSAGAa+RiYZz6C7IXN+xUVh5rrWTnU2f1SkIy7Gdg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-arm64@1.10.12:
|
||||
resolution: {integrity: sha512-K/ZhvD9l4SslclaMkTiIrnfcACgos79YcAo4kwc8bnMQaKuUeRpM15sxLpZp3xDjDg8EY93vsKyjaOhdFG2UbA==}
|
||||
/turbo-linux-arm64@1.10.13:
|
||||
resolution: {integrity: sha512-0iBKviSGQQlh2OjZgBsGjkPXoxvRIxrrLLbLObwJo3sOjIH0loGmVIimGS5E323soMfi/o+sidjk2wU1kFfD7Q==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-64@1.10.12:
|
||||
resolution: {integrity: sha512-7FSgSwvktWDNOqV65l9AbZwcoueAILeE4L7JvjauNASAjjbuzXGCEq5uN8AQU3U5BOFj4TdXrVmO2dX+lLu8Zg==}
|
||||
/turbo-windows-64@1.10.13:
|
||||
resolution: {integrity: sha512-S5XySRfW2AmnTeY1IT+Jdr6Goq7mxWganVFfrmqU+qqq3Om/nr0GkcUX+KTIo9mPrN0D3p5QViBRzulwB5iuUQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-arm64@1.10.12:
|
||||
resolution: {integrity: sha512-gCNXF52dwom1HLY9ry/cneBPOKTBHhzpqhMylcyvJP0vp9zeMQQkt6yjYv+6QdnmELC92CtKNp2FsNZo+z0pyw==}
|
||||
/turbo-windows-arm64@1.10.13:
|
||||
resolution: {integrity: sha512-nKol6+CyiExJIuoIc3exUQPIBjP9nIq5SkMJgJuxsot2hkgGrafAg/izVDRDrRduQcXj2s8LdtxJHvvnbI8hEQ==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo@1.10.12:
|
||||
resolution: {integrity: sha512-WM3+jTfQWnB9W208pmP4oeehZcC6JQNlydb/ZHMRrhmQa+htGhWLCzd6Q9rLe0MwZLPpSPFV2/bN5egCLyoKjQ==}
|
||||
/turbo@1.10.13:
|
||||
resolution: {integrity: sha512-vOF5IPytgQPIsgGtT0n2uGZizR2N3kKuPIn4b5p5DdeLoI0BV7uNiydT7eSzdkPRpdXNnO8UwS658VaI4+YSzQ==}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
turbo-darwin-64: 1.10.12
|
||||
turbo-darwin-arm64: 1.10.12
|
||||
turbo-linux-64: 1.10.12
|
||||
turbo-linux-arm64: 1.10.12
|
||||
turbo-windows-64: 1.10.12
|
||||
turbo-windows-arm64: 1.10.12
|
||||
turbo-darwin-64: 1.10.13
|
||||
turbo-darwin-arm64: 1.10.13
|
||||
turbo-linux-64: 1.10.13
|
||||
turbo-linux-arm64: 1.10.13
|
||||
turbo-windows-64: 1.10.13
|
||||
turbo-windows-arm64: 1.10.13
|
||||
dev: true
|
||||
|
||||
/tween-functions@1.2.0:
|
||||
@@ -22985,7 +22970,7 @@ packages:
|
||||
dependencies:
|
||||
esbuild: 0.18.10
|
||||
postcss: 8.4.30
|
||||
rollup: 3.28.1
|
||||
rollup: 3.29.4
|
||||
terser: 5.20.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
Reference in New Issue
Block a user