Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: breadcrumb cache issue #2215

Merged
merged 42 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6cd266b
fix:breadcrum-cache-issue
AkshayBandi027 Oct 5, 2024
babf1c3
Merge branch 'main' into fix/breadcrum-cache-issue
AkshayBandi027 Oct 6, 2024
77782f0
Merge branch 'unkeyed:main' into fix/breadcrum-cache-issue
AkshayBandi027 Oct 10, 2024
c46818e
chore:rename-revalidateMytag
AkshayBandi027 Oct 7, 2024
bd0d213
refactor: move-revalidateTag
AkshayBandi027 Oct 8, 2024
e7906ee
refactor: extract tags into reusable utility
AkshayBandi027 Oct 10, 2024
94634b4
Merge branch 'main' into fix/breadcrum-cache-issue
AkshayBandi027 Oct 11, 2024
d7dd3f3
feat: add template
chronark Oct 11, 2024
ce69a7a
Update 3_follow_the_unkey_x_account.md (#2323)
Emmarie-Ahtunan Oct 11, 2024
6f90d44
fix: capture uniqueness error and return it correctly (#2337)
chronark Oct 11, 2024
7ff38b7
docs: getVerifications instead of get (#2329)
harshsbhat Oct 11, 2024
dfffad0
Update 3_follow_the_unkey_x_account.md (#2324)
aritradevelops Oct 11, 2024
a90dbc0
fix: transaction ...: in use: for query (#2278)
Flo4604 Oct 11, 2024
b35831f
fix: handle undefined ratelimits
chronark Oct 11, 2024
789b2e5
Update 3_follow_the_unkey_x_account.md (#2338)
Devang0907 Oct 11, 2024
6e09502
fix: handle case when blogs array is empty
chronark Oct 11, 2024
8078b80
[oss.gg] side quest : added another framework; hono on cloudflare wor…
prabincankod Oct 11, 2024
4379c23
fix: weird spacing in changelog by removing the extra gap (#2340)
Khaan25 Oct 11, 2024
a74c234
oss.gg: create a template for ratelimiting a oak server in deno with …
Devansh-Baghel Oct 12, 2024
9b0c4fc
follow unkey on X #2252 (#2315)
shreenarayan123 Oct 12, 2024
8764aab
Follow the Unkey X account: @unkeydev Complete! (#2332)
Chirag8023 Oct 12, 2024
8f281d7
fix(www): analytics bento code snippet is not readable (#2311)
unrenamed Oct 12, 2024
18ef32b
Update 7_create_a_template.md
chronark Oct 12, 2024
c4def6c
Update 7_create_a_template.md
chronark Oct 12, 2024
4f903fe
chore(deps-dev): bump @content-collections/core from 0.6.2 to 0.7.2 (…
dependabot[bot] Oct 13, 2024
2aa9344
fix: order audit logs by time, show latest on top (#2295)
chronark Oct 13, 2024
9893080
feat: add template
chronark Oct 13, 2024
a4b52e4
feat: Unkey FastAPI boilerplate (#2307)
harshsbhat Oct 13, 2024
3d88ed0
feat: add template
chronark Oct 13, 2024
72799ee
feat: follow unkey on X (#2357)
Sakethpavan Oct 13, 2024
7250c94
Update 6_record_onboarding.md (#2301)
Ionfinisher Oct 13, 2024
42d1b4d
fix: reset input fields in API delete dialog after reopening (#2316)
Vardhaman619 Oct 13, 2024
cfde7e7
Update 3_follow_the_unkey_x_account.md (#2364)
Atharva-3000 Oct 13, 2024
34eabed
ci: add label
chronark Oct 13, 2024
c77e427
feat: add hover to input fields
chronark Oct 13, 2024
f1c6570
Added gaps and width for md (#2371)
rishipatel9 Oct 13, 2024
e20ffd1
docs: update overview.mdx (#2384)
eltociear Oct 13, 2024
0fa0856
oss.gg side quest 3_follow_the_unkey_x_account.md (#2399)
trinetra110 Oct 13, 2024
dff9152
feat: Following unkey acc on twitter #2407 (#2408)
kunalarya873 Oct 14, 2024
8282538
resolve merge conflicts
AkshayBandi027 Oct 14, 2024
6a05ff2
resolve merge conflicts
AkshayBandi027 Oct 14, 2024
7c51d96
chore: merge conflicts
chronark Oct 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { tags } from "@/lib/cache";

import { getTenantId } from "@/lib/auth";
import { db } from "@/lib/db";
Expand All @@ -33,6 +34,7 @@ async function AsyncPageBreadcrumb(props: PageProps) {
},
}),
["apiById"],
{ tags: [tags.api(props.params.apiId)] },
);

const api = await getApiById(props.params.apiId);
Expand Down
2 changes: 2 additions & 0 deletions apps/dashboard/app/(app)/@breadcrumb/apis/[apiId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { unstable_cache as cache } from "next/cache";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { getTenantId } from "@/lib/auth";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { Suspense } from "react";

Expand All @@ -33,6 +34,7 @@ async function AsyncPageBreadcrumb(props: PageProps) {
},
}),
["apiById"],
{ tags: [tags.api(props.params.apiId)] },
);

const api = await getApiById(props.params.apiId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { getTenantId } from "@/lib/auth";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -30,6 +31,7 @@ async function AsyncPageBreadcrumb(props: PageProps) {
},
}),
["apiById"],
{ tags: [tags.api(props.params.apiId)] },
);

const api = await getApiById(props.params.apiId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/components/ui/breadcrumb";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -19,10 +20,13 @@ type PageProps = {
};

async function AsyncPageBreadcrumb(props: PageProps) {
const getPermissionById = cache(async (permissionId: string) =>
db.query.permissions.findFirst({
where: (table, { eq }) => eq(table.id, permissionId),
}),
const getPermissionById = cache(
async (permissionId: string) =>
db.query.permissions.findFirst({
where: (table, { eq }) => eq(table.id, permissionId),
}),
["permissionById"],
{ tags: [tags.permission(props.params.permissionId)] },
);

const permissions = await getPermissionById(props.params.permissionId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/components/ui/breadcrumb";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -24,6 +25,8 @@ async function AsyncPageBreadcrumb(props: PageProps) {
await db.query.roles.findFirst({
where: (table, { eq }) => eq(table.id, roleId),
}),
["roleById"],
{ tags: [tags.role(props.params.roleId)] },
);

const role = await getWorkspaceByRoleId(props.params.roleId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/components/ui/breadcrumb";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -20,11 +21,14 @@ type PageProps = {
};

async function AsyncPageBreadcrumb(props: PageProps) {
const getNamespaceById = cache(async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
const getNamespaceById = cache(
async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
["namespaceById"],
{ tags: [tags.namespace(props.params.namespaceId)] },
);

const namespace = await getNamespaceById(props.params.namespaceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/components/ui/breadcrumb";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -20,11 +21,14 @@ type PageProps = {
};

async function AsyncPageBreadcrumb(props: PageProps) {
const getNamespaceById = cache(async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
const getNamespaceById = cache(
async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
["namespaceById"],
{ tags: [tags.namespace(props.params.namespaceId)] },
Comment on lines +24 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider implementing type-safe cache keys and tags.

Based on the PR discussion about type safety, consider implementing a type-safe wrapper for cache keys and tags to prevent typos and improve maintainability.

Example implementation:

// lib/cache/keys.ts
export const cacheKeys = {
  namespace: {
    byId: (id: string) => ["namespaceById", id] as const,
  }
} as const;

// lib/cache/tags.ts
export const cacheTags = {
  namespace: (id: string) => `namespace:${id}` as const,
} as const;

// Usage in this file:
cache(
  async (namespaceId: string) => {
    // ... query implementation
  },
  cacheKeys.namespace.byId(props.params.namespaceId),
  { tags: [cacheTags.namespace(props.params.namespaceId)] }
);

);

const namespace = await getNamespaceById(props.params.namespaceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/components/ui/breadcrumb";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -20,11 +21,15 @@ type PageProps = {
};

async function AsyncPageBreadcrumb(props: PageProps) {
const getNamespaceById = cache(async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
const getNamespaceById = cache(
async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),

["namespaceById"],
{ tags: [tags.namespace(props.params.namespaceId)] },
);

const namespace = await getNamespaceById(props.params.namespaceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/components/ui/breadcrumb";

import { BreadcrumbSkeleton } from "@/components/dashboard/breadcrumb-skeleton";
import { tags } from "@/lib/cache";
import { db } from "@/lib/db";
import { unstable_cache as cache } from "next/cache";
import { Suspense } from "react";
Expand All @@ -20,11 +21,14 @@ type PageProps = {
};

async function AsyncPageBreadcrumb(props: PageProps) {
const getNamespaceById = cache(async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
const getNamespaceById = cache(
async (namespaceId: string) =>
db.query.ratelimitNamespaces.findFirst({
where: (table, { eq, and, isNull }) =>
and(eq(table.id, namespaceId), isNull(table.deletedAt)),
}),
["namespaceById"],
{ tags: [tags.namespace(props.params.namespaceId)] },
);

const namespace = await getNamespaceById(props.params.namespaceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { z } from "zod";

import { tags } from "@/lib/cache";
import { revalidateTag } from "../../../../actions";
const formSchema = z.object({
name: z.string(),
apiId: z.string(),
Expand Down Expand Up @@ -45,6 +48,7 @@ export const UpdateApiName: React.FC<Props> = ({ api }) => {
const updateName = trpc.api.updateName.useMutation({
onSuccess() {
toast.success("Your API name has been renamed!");
revalidateTag(tags.api(api.id));
router.refresh();
},
onError(err) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use client";

import { revalidateTag } from "@/app/actions";
import { Loading } from "@/components/dashboard/loading";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter } from "@/components/ui/card";
import { tags } from "@/lib/cache";

import {
Form,
Expand Down Expand Up @@ -47,6 +49,7 @@ export const Client: React.FC<Props> = ({ permission }) => {
const updatePermission = trpc.rbac.updatePermission.useMutation({
onSuccess() {
toast.success("Permission updated");
revalidateTag(tags.permission(permission.id));
router.refresh();
},
onError(err) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";

import { revalidateTag } from "@/app/actions";
import { Loading } from "@/components/dashboard/loading";
import { Button } from "@/components/ui/button";
import {
Expand All @@ -22,6 +22,7 @@ import {
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { toast } from "@/components/ui/toaster";
import { tags } from "@/lib/cache";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogTrigger } from "@radix-ui/react-dialog";
Expand Down Expand Up @@ -59,6 +60,7 @@ export const UpdateRole: React.FC<Props> = ({ trigger, role }) => {
},
onSuccess() {
toast.success("Role updated");
revalidateTag(tags.role(role.id));
router.refresh();
setOpen(false);
},
Expand Down
5 changes: 3 additions & 2 deletions apps/dashboard/app/(app)/ratelimits/[namespaceId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from "@/lib/tinybird";
import { BarChart } from "lucide-react";
import ms from "ms";
import { notFound } from "next/navigation";
import { redirect } from "next/navigation";
import { parseAsArrayOf, parseAsString, parseAsStringEnum } from "nuqs/server";
import { Filters, type Interval } from "./filters";

Expand Down Expand Up @@ -49,7 +49,8 @@ export default async function RatelimitNamespacePage(props: {
},
});
if (!namespace || namespace.workspace.tenantId !== tenantId) {
return notFound();
redirect("/ratelimits");
return;
chronark marked this conversation as resolved.
Show resolved Hide resolved
}

const interval = intervalParser.withDefault("7d").parseServerSide(props.searchParams.interval);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use client";
import { revalidateTag } from "@/app/actions";
import { Loading } from "@/components/dashboard/loading";
import { Button } from "@/components/ui/button";
import {
Expand All @@ -12,6 +13,7 @@ import {
import { FormField } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { toast } from "@/components/ui/toaster";
import { tags } from "@/lib/cache";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useRouter } from "next/navigation";
Expand Down Expand Up @@ -45,6 +47,7 @@ export const UpdateNamespaceName: React.FC<Props> = ({ namespace }) => {
const updateName = trpc.ratelimit.namespace.update.name.useMutation({
onSuccess() {
toast.success("Your namespace name has been renamed!");
revalidateTag(tags.namespace(namespace.id));
router.refresh();
},
onError(err) {
Expand Down
8 changes: 7 additions & 1 deletion apps/dashboard/app/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"use server";
import { revalidatePath } from "next/cache";
import { revalidatePath, revalidateTag } from "next/cache";

export async function revalidate(path: string) {
revalidatePath(path, "page");
}

export async function revalidateMyTag(slug: string) {
revalidateTag(slug);
}
Comment on lines +8 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling and improve function documentation

The function should include error handling and proper documentation to improve maintainability and reliability.

Consider applying these improvements:

-export async function revalidateMyTag(slug: string) {
-  revalidateTag(slug);
-}
+/**
+ * Revalidates cache for a specific tag
+ * @param slug - The cache tag to revalidate
+ * @throws {Error} If the slug is invalid or revalidation fails
+ */
+export async function revalidateMyTag(slug: string) {
+  if (!slug || typeof slug !== 'string') {
+    throw new Error('Invalid cache tag provided');
+  }
+  try {
+    await revalidateTag(slug);
+  } catch (error) {
+    console.error('Failed to revalidate cache tag:', error);
+    throw error;
+  }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function revalidateMyTag(slug: string) {
revalidateTag(slug);
}
/**
* Revalidates cache for a specific tag
* @param slug - The cache tag to revalidate
* @throws {Error} If the slug is invalid or revalidation fails
*/
export async function revalidateMyTag(slug: string) {
if (!slug || typeof slug !== 'string') {
throw new Error('Invalid cache tag provided');
}
try {
await revalidateTag(slug);
} catch (error) {
console.error('Failed to revalidate cache tag:', error);
throw error;
}
}


export { revalidateMyTag as revalidateTag };
6 changes: 6 additions & 0 deletions apps/dashboard/lib/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const tags = {
api: (apiId: string): string => `api-${apiId}`,
permission: (permissionId: string): string => `permission-${permissionId}`,
namespace: (namespaceId: string): string => `namespace-${namespaceId}`,
role: (roleId: string): string => `role-${roleId}`,
};
4 changes: 2 additions & 2 deletions apps/www/app/glossary/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CTA } from "@/components/cta";
import { Frame } from "@/components/frame";

import { FilterableCommand } from "@/components/glossary/search";
import TermsRolodexDesktop from "@/components/glossary/terms-rolodex-desktop";
import TermsStepperMobile from "@/components/glossary/terms-stepper-mobile";
import { MDX } from "@/components/mdx-content";
import { TopLeftShiningLight, TopRightShiningLight } from "@/components/svg/background-shiny";
Expand All @@ -14,8 +16,6 @@ import Link from "next/link";
import { notFound } from "next/navigation";
import { FAQ } from "./faq";
import Takeaways from "./takeaways";
import TermsRolodexDesktop from "@/components/glossary/terms-rolodex-desktop";
import { FilterableCommand } from "@/components/glossary/search";

export const generateStaticParams = async () =>
allGlossaries.map((term) => ({
Expand Down
4 changes: 2 additions & 2 deletions apps/www/app/glossary/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import { CTA } from "@/components/cta";
import { ChangelogLight } from "@/components/svg/changelog";

import { type Glossary, allGlossaries } from "@/.content-collections/generated";
import { PrimaryButton } from "@/components/button";
import { Container } from "@/components/container";
import { FilterableCommand } from "@/components/glossary/search";
import { MeteorLinesAngular } from "@/components/ui/meteorLines";
import { LogIn } from "lucide-react";
import Link from "next/link";
import { allGlossaries, type Glossary } from "@/.content-collections/generated";
import { Zap } from "lucide-react";
import Link from "next/link";

export function GlossaryClient() {
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
Expand Down
6 changes: 3 additions & 3 deletions apps/www/components/glossary/search.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import * as React from "react";
import { Command as CommandPrimitive } from "cmdk";
import type { Glossary } from "@/.content-collections/generated";
import {
Command,
CommandEmpty,
Expand All @@ -10,8 +9,9 @@ import {
CommandList,
} from "@/components/ui/command";
import { cn } from "@/lib/utils";
import { Command as CommandPrimitive } from "cmdk";
import { useRouter } from "next/navigation";
import type { Glossary } from "@/.content-collections/generated";
import * as React from "react";

export function FilterableCommand(props: {
placeholder: string;
Expand Down
8 changes: 4 additions & 4 deletions apps/www/components/glossary/terms-rolodex-desktop.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"use client";

import { useState } from "react";
import Link from "next/link";
import type { Glossary } from "@/.content-collections/generated";
import { Button } from "@/components/ui/button";
import { ChevronUpIcon, ChevronDownIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import Link from "next/link";
import { useParams } from "next/navigation";
import type { Glossary } from "@/.content-collections/generated";
import { useState } from "react";

export default function TermsRolodexDesktop({
className,
Expand Down
Loading
Loading