mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-22 00:52:50 -06:00
fix: add authorisation for tags actions (#897)
* 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 tag creation, updation & deletion * fix: use cached wrapper * fix: club caching methods and use authzn errors * feat: add caching in canUserAccessApiKey * fix: suggrsted changes and authzn for response as well * fix: work on suggested changes * fix broken lock file --------- Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
committed by
GitHub
parent
a9c8e99cd4
commit
8c0aba82e5
@@ -4,7 +4,7 @@ import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
|
||||
|
||||
import { capitalizeFirstLetter } from "@/lib/utils";
|
||||
import { getPerson } from "@formbricks/lib/services/person";
|
||||
import { getResponsesByPersonId } from "@formbricks/lib/services/response";
|
||||
import { getResponsesByPersonId } from "@formbricks/lib/response/service";
|
||||
import { getSessionCount } from "@formbricks/lib/services/session";
|
||||
|
||||
export default async function AttributesSection({ personId }: { personId: string }) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import ResponseTimeline from "@/app/(app)/environments/[environmentId]/people/[personId]/(responseSection)/ResponseTimeline";
|
||||
import { getResponsesByPersonId } from "@formbricks/lib/services/response";
|
||||
import { getResponsesByPersonId } from "@formbricks/lib/response/service";
|
||||
import { getSurveys } from "@formbricks/lib/services/survey";
|
||||
import { TEnvironment } from "@formbricks/types/v1/environment";
|
||||
import { TResponseWithSurvey } from "@formbricks/types/v1/responses";
|
||||
|
||||
@@ -1,15 +1,38 @@
|
||||
"use server";
|
||||
|
||||
import { deleteTag, mergeTags, updateTagName } from "@formbricks/lib/services/tag";
|
||||
import { deleteTag, mergeTags, updateTagName } from "@formbricks/lib/tag/service";
|
||||
import { canUserAccessTag } from "@formbricks/lib/tag/auth";
|
||||
import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AuthorizationError } from "@formbricks/types/v1/errors";
|
||||
|
||||
export const deleteTagAction = async (tagId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessTag(session.user.id, tagId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await deleteTag(tagId);
|
||||
};
|
||||
|
||||
export const updateTagNameAction = async (tagId: string, name: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessTag(session.user.id, tagId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await updateTagName(tagId, name);
|
||||
};
|
||||
|
||||
export const mergeTagsAction = async (originalTagId: string, newTagId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorizedForOld = await canUserAccessTag(session.user.id, originalTagId);
|
||||
const isAuthorizedForNew = await canUserAccessTag(session.user.id, newTagId);
|
||||
if (!isAuthorizedForOld || !isAuthorizedForNew) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await mergeTags(originalTagId, newTagId);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import EditTagsWrapper from "./EditTagsWrapper";
|
||||
import SettingsTitle from "../SettingsTitle";
|
||||
import { getEnvironment } from "@formbricks/lib/services/environment";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/services/tag";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
|
||||
import { getTagsOnResponsesCount } from "@formbricks/lib/services/tagOnResponse";
|
||||
|
||||
export default async function MembersSettingsPage({ params }) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RESPONSES_LIMIT_FREE } from "@formbricks/lib/constants";
|
||||
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { getSurveyResponses } from "@formbricks/lib/services/response";
|
||||
import { getSurveyResponses } from "@formbricks/lib/response/service";
|
||||
import { getSurveyWithAnalytics } from "@formbricks/lib/services/survey";
|
||||
import { getTeamByEnvironmentId } from "@formbricks/lib/services/team";
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
"use server";
|
||||
|
||||
import { deleteResponse } from "@formbricks/lib/services/response";
|
||||
import { deleteResponse } from "@formbricks/lib/response/service";
|
||||
import { updateResponseNote, resolveResponseNote } from "@formbricks/lib/services/responseNote";
|
||||
import { createTag } from "@formbricks/lib/services/tag";
|
||||
import { addTagToRespone, deleteTagFromResponse } from "@formbricks/lib/services/tagOnResponse";
|
||||
import { createTag } from "@formbricks/lib/tag/service";
|
||||
import { addTagToRespone, deleteTagOnResponse } from "@formbricks/lib/services/tagOnResponse";
|
||||
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
|
||||
import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AuthorizationError } from "@formbricks/types/v1/errors";
|
||||
import { canUserAccessResponse } from "@formbricks/lib/response/auth";
|
||||
import { canUserAccessTagOnResponse } from "@formbricks/lib/tagOnResponse/auth";
|
||||
|
||||
export const updateResponseNoteAction = async (responseNoteId: string, text: string) => {
|
||||
await updateResponseNote(responseNoteId, text);
|
||||
@@ -14,17 +20,41 @@ export const resolveResponseNoteAction = async (responseNoteId: string) => {
|
||||
};
|
||||
|
||||
export const deleteResponseAction = async (responseId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessResponse(session.user.id, responseId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await deleteResponse(responseId);
|
||||
};
|
||||
|
||||
export const createTagAction = async (environmentId: string, tagName: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await hasUserEnvironmentAccess(session.user.id, environmentId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await createTag(environmentId, tagName);
|
||||
};
|
||||
|
||||
export const addTagToResponeAction = async (responseId: string, tagId: string) => {
|
||||
export const createTagToResponeAction = async (responseId: string, tagId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessTagOnResponse(session.user.id, tagId, responseId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await addTagToRespone(responseId, tagId);
|
||||
};
|
||||
|
||||
export const removeTagFromResponseAction = async (responseId: string, tagId: string) => {
|
||||
return await deleteTagFromResponse(responseId, tagId);
|
||||
export const deleteTagOnResponseAction = async (responseId: string, tagId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const isAuthorized = await canUserAccessTagOnResponse(session.user.id, tagId, responseId);
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await deleteTagOnResponse(responseId, tagId);
|
||||
};
|
||||
|
||||
@@ -9,9 +9,9 @@ import { useRouter } from "next/navigation";
|
||||
import { Button } from "@formbricks/ui";
|
||||
import { TTag } from "@formbricks/types/v1/tags";
|
||||
import {
|
||||
addTagToResponeAction,
|
||||
createTagToResponeAction,
|
||||
createTagAction,
|
||||
removeTagFromResponseAction,
|
||||
deleteTagOnResponseAction,
|
||||
} from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/actions";
|
||||
|
||||
interface ResponseTagsWrapperProps {
|
||||
@@ -38,7 +38,7 @@ const ResponseTagsWrapper: React.FC<ResponseTagsWrapperProps> = ({
|
||||
|
||||
const onDelete = async (tagId: string) => {
|
||||
try {
|
||||
await removeTagFromResponseAction(responseId, tagId);
|
||||
await deleteTagOnResponseAction(responseId, tagId);
|
||||
|
||||
router.refresh();
|
||||
} catch (e) {
|
||||
@@ -89,7 +89,7 @@ const ResponseTagsWrapper: React.FC<ResponseTagsWrapperProps> = ({
|
||||
tagName: tag.name,
|
||||
},
|
||||
]);
|
||||
addTagToResponeAction(responseId, tag.id).then(() => {
|
||||
createTagToResponeAction(responseId, tag.id).then(() => {
|
||||
setSearchValue("");
|
||||
setOpen(false);
|
||||
router.refresh();
|
||||
@@ -121,7 +121,7 @@ const ResponseTagsWrapper: React.FC<ResponseTagsWrapperProps> = ({
|
||||
},
|
||||
]);
|
||||
|
||||
addTagToResponeAction(responseId, tagId).then(() => {
|
||||
createTagToResponeAction(responseId, tagId).then(() => {
|
||||
setSearchValue("");
|
||||
setOpen(false);
|
||||
router.refresh();
|
||||
|
||||
@@ -8,7 +8,7 @@ import { REVALIDATION_INTERVAL, SURVEY_BASE_URL } from "@formbricks/lib/constant
|
||||
import ResponsesLimitReachedBanner from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/components/ResponsesLimitReachedBanner";
|
||||
import { getEnvironment } from "@formbricks/lib/services/environment";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/services/product";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/services/tag";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
|
||||
|
||||
export default async function Page({ params }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions";
|
||||
import { REVALIDATION_INTERVAL, SURVEY_BASE_URL } from "@formbricks/lib/constants";
|
||||
import { getEnvironment } from "@formbricks/lib/services/environment";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/services/product";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/services/tag";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
|
||||
import { getServerSession } from "next-auth";
|
||||
|
||||
export default async function Page({ params }) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { responses } from "@/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
import { sendToPipeline } from "@/lib/pipelines";
|
||||
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { updateResponse } from "@formbricks/lib/services/response";
|
||||
import { updateResponse } from "@formbricks/lib/response/service";
|
||||
import { getSurvey } from "@formbricks/lib/services/survey";
|
||||
import { ZResponseUpdateInput } from "@formbricks/types/v1/responses";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
import { sendToPipeline } from "@/lib/pipelines";
|
||||
import { InvalidInputError } from "@formbricks/types/v1/errors";
|
||||
import { capturePosthogEvent } from "@formbricks/lib/posthogServer";
|
||||
import { createResponse } from "@formbricks/lib/services/response";
|
||||
import { createResponse } from "@formbricks/lib/response/service";
|
||||
import { getSurvey } from "@formbricks/lib/services/survey";
|
||||
import { getTeamDetails } from "@formbricks/lib/services/teamDetails";
|
||||
import { TResponse, TResponseInput, ZResponseInput } from "@formbricks/types/v1/responses";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { NextResponse } from "next/server";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
import { deleteResponse, getResponse, updateResponse } from "@formbricks/lib/services/response";
|
||||
import { deleteResponse, getResponse, updateResponse } from "@formbricks/lib/response/service";
|
||||
import { TResponse, ZResponseUpdateInput } from "@formbricks/types/v1/responses";
|
||||
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
|
||||
import { getSurvey } from "@formbricks/lib/services/survey";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { getEnvironmentResponses } from "@formbricks/lib/services/response";
|
||||
import { getEnvironmentResponses } from "@formbricks/lib/response/service";
|
||||
import { authenticateRequest } from "@/app/api/v1/auth";
|
||||
import { DatabaseError } from "@formbricks/types/v1/errors";
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { hasUserEnvironmentAccess } from "../environment/auth";
|
||||
import { getApiKey } from "./service";
|
||||
import { unstable_cache } from "next/cache";
|
||||
@@ -5,7 +7,7 @@ import { unstable_cache } from "next/cache";
|
||||
export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Promise<boolean> =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
if (!userId) return false;
|
||||
validateInputs([userId, ZId], [apiKeyId, ZId]);
|
||||
|
||||
const apiKeyFromServer = await getApiKey(apiKeyId);
|
||||
if (!apiKeyFromServer) return false;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
|
||||
export const hasUserEnvironmentAccess = async (userId: string, environmentId: string) => {
|
||||
return await unstable_cache(
|
||||
async () => {
|
||||
if (!userId) return false;
|
||||
validateInputs([userId, ZId], [environmentId, ZId]);
|
||||
const environment = await prisma.environment.findUnique({
|
||||
where: {
|
||||
id: environmentId,
|
||||
|
||||
28
packages/lib/response/auth.ts
Normal file
28
packages/lib/response/auth.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { hasUserEnvironmentAccess } from "../environment/auth";
|
||||
import { getResponse, getResponseCacheTag } from "./service";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { getSurvey } from "../services/survey";
|
||||
|
||||
export const canUserAccessResponse = async (userId: string, responseId: string): Promise<boolean> =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([userId, ZId], [responseId, ZId]);
|
||||
|
||||
if (!userId) return false;
|
||||
|
||||
const response = await getResponse(responseId);
|
||||
if (!response) return false;
|
||||
|
||||
const survey = await getSurvey(response.surveyId);
|
||||
if (!survey) return false;
|
||||
|
||||
const hasAccessToEnvironment = await hasUserEnvironmentAccess(userId, survey.environmentId);
|
||||
if (!hasAccessToEnvironment) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
[`users-${userId}-responses-${responseId}`],
|
||||
{ revalidate: 30 * 60, tags: [getResponseCacheTag(responseId)] }
|
||||
)(); // 30 minutes
|
||||
@@ -12,7 +12,7 @@ import { TTag } from "@formbricks/types/v1/tags";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { cache } from "react";
|
||||
import "server-only";
|
||||
import { getPerson, transformPrismaPerson } from "./person";
|
||||
import { getPerson, transformPrismaPerson } from "../services/person";
|
||||
import { captureTelemetry } from "../telemetry";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
@@ -78,6 +78,8 @@ const responseSelection = {
|
||||
|
||||
export const getResponsesCacheTag = (surveyId: string) => `surveys-${surveyId}-responses`;
|
||||
|
||||
export const getResponseCacheTag = (responseId: string) => `responses-${responseId}`;
|
||||
|
||||
export const getResponsesByPersonId = async (personId: string): Promise<Array<TResponse> | null> => {
|
||||
validateInputs([personId, ZId]);
|
||||
try {
|
||||
@@ -15,7 +15,7 @@ import { z } from "zod";
|
||||
import { captureTelemetry } from "../telemetry";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { getDisplaysCacheTag } from "./displays";
|
||||
import { getResponsesCacheTag } from "./response";
|
||||
import { getResponsesCacheTag } from "../response/service";
|
||||
|
||||
// surveys cache key and tags
|
||||
const getSurveysCacheKey = (environmentId: string): string => `environments-${environmentId}-surveys`;
|
||||
|
||||
@@ -2,6 +2,9 @@ import { prisma } from "@formbricks/database";
|
||||
import { TTagsCount } from "@formbricks/types/v1/tags";
|
||||
import { cache } from "react";
|
||||
|
||||
export const getTagOnResponseCacheTag = (tagId: string, responseId: string) =>
|
||||
`tagsOnResponse-${tagId}-${responseId}`;
|
||||
|
||||
export const addTagToRespone = async (responseId: string, tagId: string) => {
|
||||
try {
|
||||
const tagOnResponse = await prisma.tagsOnResponses.create({
|
||||
@@ -16,7 +19,7 @@ export const addTagToRespone = async (responseId: string, tagId: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteTagFromResponse = async (responseId: string, tagId: string) => {
|
||||
export const deleteTagOnResponse = async (responseId: string, tagId: string) => {
|
||||
try {
|
||||
const deletedTag = await prisma.tagsOnResponses.delete({
|
||||
where: {
|
||||
|
||||
24
packages/lib/tag/auth.ts
Normal file
24
packages/lib/tag/auth.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { hasUserEnvironmentAccess } from "../environment/auth";
|
||||
import { getTag } from "./service";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
|
||||
export const canUserAccessTag = async (userId: string, tagId: string): Promise<boolean> =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([userId, ZId], [tagId, ZId]);
|
||||
|
||||
const tag = await getTag(tagId);
|
||||
if (!tag) return false;
|
||||
|
||||
const hasAccessToEnvironment = await hasUserEnvironmentAccess(userId, tag.environmentId);
|
||||
if (!hasAccessToEnvironment) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
[`${userId}-${tagId}`],
|
||||
{
|
||||
revalidate: 30 * 60, // 30 minutes
|
||||
}
|
||||
)();
|
||||
@@ -16,6 +16,20 @@ export const getTagsByEnvironmentId = cache(async (environmentId: string): Promi
|
||||
}
|
||||
});
|
||||
|
||||
export const getTag = async (tagId: string): Promise<TTag | null> => {
|
||||
try {
|
||||
const tag = await prisma.tag.findUnique({
|
||||
where: {
|
||||
id: tagId,
|
||||
},
|
||||
});
|
||||
|
||||
return tag;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createTag = async (environmentId: string, name: string): Promise<TTag> => {
|
||||
try {
|
||||
const tag = await prisma.tag.create({
|
||||
24
packages/lib/tagOnResponse/auth.ts
Normal file
24
packages/lib/tagOnResponse/auth.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { canUserAccessResponse } from "../response/auth";
|
||||
import { canUserAccessTag } from "../tag/auth";
|
||||
import { getTagOnResponseCacheTag } from "../services/tagOnResponse";
|
||||
|
||||
export const canUserAccessTagOnResponse = async (
|
||||
userId: string,
|
||||
tagId: string,
|
||||
responseId: string
|
||||
): Promise<boolean> =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([userId, ZId], [tagId, ZId], [responseId, ZId]);
|
||||
|
||||
const isAuthorizedForTag = await canUserAccessTag(userId, tagId);
|
||||
const isAuthorizedForResponse = await canUserAccessResponse(userId, responseId);
|
||||
|
||||
return isAuthorizedForTag && isAuthorizedForResponse;
|
||||
},
|
||||
[`users-${userId}-tagOnResponse-${tagId}-${responseId}`],
|
||||
{ revalidate: 30 * 60, tags: [getTagOnResponseCacheTag(tagId, responseId)] }
|
||||
)();
|
||||
36
pnpm-lock.yaml
generated
36
pnpm-lock.yaml
generated
@@ -1,5 +1,9 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -434,7 +438,7 @@ importers:
|
||||
version: 9.0.0(eslint@8.50.0)
|
||||
eslint-config-turbo:
|
||||
specifier: latest
|
||||
version: 1.10.14(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)
|
||||
@@ -10673,13 +10677,13 @@ packages:
|
||||
resolution: {integrity: sha512-NB/L/1Y30qyJcG5xZxCJKW/+bqyj+llbcCwo9DEz8bESIP0SLTOQ8T1DWCCFc+wJ61AMEstj4511PSScqMMfCw==}
|
||||
dev: true
|
||||
|
||||
/eslint-config-turbo@1.10.14(eslint@8.50.0):
|
||||
resolution: {integrity: sha512-ZeB+IcuFXy1OICkLuAplVa0euoYbhK+bMEQd0nH9+Lns18lgZRm33mVz/iSoH9VdUzl/1ZmFmoK+RpZc+8R80A==}
|
||||
/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.14(eslint@8.50.0)
|
||||
eslint-plugin-turbo: 1.8.8(eslint@8.50.0)
|
||||
dev: true
|
||||
|
||||
/eslint-import-resolver-node@0.3.9:
|
||||
@@ -10885,12 +10889,11 @@ packages:
|
||||
semver: 6.3.1
|
||||
string.prototype.matchall: 4.0.8
|
||||
|
||||
/eslint-plugin-turbo@1.10.14(eslint@8.50.0):
|
||||
resolution: {integrity: sha512-sBdBDnYr9AjT1g4lR3PBkZDonTrMnR4TvuGv5W0OiF7z9az1rI68yj2UHJZvjkwwcGu5mazWA1AfB0oaagpmfg==}
|
||||
/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
|
||||
|
||||
@@ -22036,70 +22039,58 @@ packages:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
|
||||
/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.13:
|
||||
resolution: {integrity: sha512-eMoJC+k7gIS4i2qL6rKmrIQGP6Wr9nN4odzzgHFngLTMimok2cGLK3qbJs5O5F/XAtEeRAmuxeRnzQwTl/iuAw==}
|
||||
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
|
||||
/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.13:
|
||||
resolution: {integrity: sha512-0iBKviSGQQlh2OjZgBsGjkPXoxvRIxrrLLbLObwJo3sOjIH0loGmVIimGS5E323soMfi/o+sidjk2wU1kFfD7Q==}
|
||||
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
|
||||
/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.13:
|
||||
resolution: {integrity: sha512-nKol6+CyiExJIuoIc3exUQPIBjP9nIq5SkMJgJuxsot2hkgGrafAg/izVDRDrRduQcXj2s8LdtxJHvvnbI8hEQ==}
|
||||
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
|
||||
/turbo@1.10.13:
|
||||
resolution: {integrity: sha512-vOF5IPytgQPIsgGtT0n2uGZizR2N3kKuPIn4b5p5DdeLoI0BV7uNiydT7eSzdkPRpdXNnO8UwS658VaI4+YSzQ==}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
turbo-darwin-64: 1.10.13
|
||||
turbo-darwin-arm64: 1.10.13
|
||||
@@ -22107,7 +22098,6 @@ packages:
|
||||
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:
|
||||
@@ -23974,7 +23964,3 @@ packages:
|
||||
/zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
dev: false
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
Reference in New Issue
Block a user