chore: API key types (#4610)

Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
This commit is contained in:
Piyush Gupta
2025-01-17 16:06:29 +05:30
committed by GitHub
parent 21644f5ad8
commit 02b25138ef
17 changed files with 131 additions and 194 deletions

View File

@@ -1,3 +1,4 @@
import { type ApiKey } from "@prisma/client";
import { z } from "zod";
export const ZApiKey = z.object({
@@ -7,12 +8,4 @@ export const ZApiKey = z.object({
label: z.string().nullable(),
hashedKey: z.string(),
environmentId: z.string().cuid2(),
apiKey: z.string().optional(),
});
export type TApiKey = z.infer<typeof ZApiKey>;
export const ZApiKeyCreateInput = z.object({
label: z.string(),
});
export type TApiKeyCreateInput = z.infer<typeof ZApiKeyCreateInput>;
}) satisfies z.ZodType<ApiKey>;

View File

@@ -1,29 +0,0 @@
import "server-only";
import { ZId } from "@formbricks/types/common";
import { cache } from "../cache";
import { hasUserEnvironmentAccess } from "../environment/auth";
import { validateInputs } from "../utils/validate";
import { apiKeyCache } from "./cache";
import { getApiKey } from "./service";
export const canUserAccessApiKey = (userId: string, apiKeyId: string): Promise<boolean> =>
cache(
async () => {
validateInputs([userId, ZId], [apiKeyId, ZId]);
try {
const apiKeyFromServer = await getApiKey(apiKeyId);
if (!apiKeyFromServer) return false;
const hasAccessToEnvironment = await hasUserEnvironmentAccess(userId, apiKeyFromServer.environmentId);
if (!hasAccessToEnvironment) return false;
return true;
} catch (error) {
throw error;
}
},
[`canUserAccessApiKey-${userId}-${apiKeyId}`],
{ tags: [apiKeyCache.tag.byId(apiKeyId)] }
)();

View File

@@ -1,34 +0,0 @@
import { revalidateTag } from "next/cache";
interface RevalidateProps {
id?: string;
environmentId?: string;
hashedKey?: string;
}
export const apiKeyCache = {
tag: {
byId(id: string) {
return `apiKeys-${id}`;
},
byEnvironmentId(environmentId: string) {
return `environments-${environmentId}-apiKeys`;
},
byHashedKey(hashedKey: string) {
return `apiKeys-${hashedKey}-apiKey`;
},
},
revalidate({ id, environmentId, hashedKey }: RevalidateProps): void {
if (id) {
revalidateTag(this.tag.byId(id));
}
if (environmentId) {
revalidateTag(this.tag.byEnvironmentId(environmentId));
}
if (hashedKey) {
revalidateTag(this.tag.byHashedKey(hashedKey));
}
},
};

View File

@@ -1,109 +0,0 @@
import "server-only";
import { Prisma } from "@prisma/client";
import { cache as reactCache } from "react";
import { prisma } from "@formbricks/database";
import { TApiKey } from "@formbricks/types/api-keys";
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
import { ZId } from "@formbricks/types/common";
import { DatabaseError, InvalidInputError } from "@formbricks/types/errors";
import { cache } from "../cache";
import { ITEMS_PER_PAGE } from "../constants";
import { getHash } from "../crypto";
import { validateInputs } from "../utils/validate";
import { apiKeyCache } from "./cache";
export const getApiKey = reactCache(
async (apiKeyId: string): Promise<TApiKey | null> =>
cache(
async () => {
validateInputs([apiKeyId, ZString]);
if (!apiKeyId) {
throw new InvalidInputError("API key cannot be null or undefined.");
}
try {
const apiKeyData = await prisma.apiKey.findUnique({
where: {
id: apiKeyId,
},
});
return apiKeyData;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError(error.message);
}
throw error;
}
},
[`getApiKey-${apiKeyId}`],
{
tags: [apiKeyCache.tag.byId(apiKeyId)],
}
)()
);
export const getApiKeys = reactCache(
async (environmentId: string, page?: number): Promise<TApiKey[]> =>
cache(
async () => {
validateInputs([environmentId, ZId], [page, ZOptionalNumber]);
try {
const apiKeys = await prisma.apiKey.findMany({
where: {
environmentId,
},
take: page ? ITEMS_PER_PAGE : undefined,
skip: page ? ITEMS_PER_PAGE * (page - 1) : undefined,
});
return apiKeys;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError(error.message);
}
throw error;
}
},
[`getApiKeys-${environmentId}-${page}`],
{
tags: [apiKeyCache.tag.byEnvironmentId(environmentId)],
}
)()
);
export const getApiKeyFromKey = reactCache(async (apiKey: string): Promise<TApiKey | null> => {
const hashedKey = getHash(apiKey);
return cache(
async () => {
validateInputs([apiKey, ZString]);
if (!apiKey) {
throw new InvalidInputError("API key cannot be null or undefined.");
}
try {
const apiKeyData = await prisma.apiKey.findUnique({
where: {
hashedKey,
},
});
return apiKeyData;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError(error.message);
}
throw error;
}
},
[`getApiKeyFromKey-${apiKey}`],
{
tags: [apiKeyCache.tag.byHashedKey(hashedKey)],
}
)();
});

View File

@@ -18,6 +18,7 @@
".",
"../types/*.d.ts",
"../../apps/web/lib/cache/contact-attribute-key.ts",
"../../apps/web/modules/utils/hooks"
"../../apps/web/modules/utils/hooks",
"../../apps/web/lib/cache/api-key.ts"
]
}

View File

@@ -1,11 +0,0 @@
import { z } from "zod";
import { ZId } from "./common";
export const ZContact = z.object({
id: ZId,
createdAt: z.date(),
updatedAt: z.date(),
environmentId: ZId,
});
export type TContact = z.infer<typeof ZContact>;

View File

@@ -20,12 +20,6 @@ export const ZDisplayCreateInput = z.object({
export type TDisplayCreateInput = z.infer<typeof ZDisplayCreateInput>;
export const ZDisplaysWithSurveyName = ZDisplay.extend({
surveyName: z.string(),
});
export type TDisplaysWithSurveyName = z.infer<typeof ZDisplaysWithSurveyName>;
export const ZDisplayFilters = z.object({
createdAt: z
.object({