diff --git a/packages/cache-widget/README.md b/packages/cache-widget/README.md
index ccb90b4..7bc2df7 100644
--- a/packages/cache-widget/README.md
+++ b/packages/cache-widget/README.md
@@ -98,6 +98,26 @@ You can customize the API endpoint URL (default - `/api/cache-widget`):
```
+### Permissions
+
+The `permissions` prop controls which UI features are available in the widget. It accepts an array of permission strings:
+
+- `"read"` - Allows viewing cache entries and their details. If not included or set to `null`, the widget will not render.
+- `"invalidate"` - Enables the "Revalidate" and "Expire" action buttons in the key details view.
+
+```tsx
+// Read-only access (default)
+
+
+// Full access with invalidation
+
+
+// Hide widget completely
+
+```
+
+> **Important**: Permissions are **UI-only** and only control what features are visible in the widget interface. For security, you **must** configure allowed methods and routes in your API endpoints. The widget will still make API requests based on what's visible in the UI, so ensure your API routes properly validate and restrict access to sensitive operations like cache invalidation.
+
## Additional
You can use the widget to view all current cache entries by layer: main, ephemeral, and persistent.
diff --git a/packages/cache-widget/src/components/details/index.tsx b/packages/cache-widget/src/components/details/index.tsx
index 0297633..8bf5ddc 100644
--- a/packages/cache-widget/src/components/details/index.tsx
+++ b/packages/cache-widget/src/components/details/index.tsx
@@ -2,17 +2,22 @@
import React, { use } from "react";
+import { type Permissions } from "../../lib/types";
import { formatBytes, formatTimestamp, formatDuration, formatDifference } from "../../lib/utils";
import { CacheKeyContext, FetchDetailsContext, SetCacheKeyContext } from "../../store/contexts";
import { Value } from "../value";
import { Loading } from "../loading";
import { ErrorMessage } from "../error";
import { Reload } from "../reload";
+import { EntryActions } from "../entry-actions";
import "./details.scss";
-import { EntryActions } from "../entry-actions";
-export const Details: React.FC = () => {
+interface DetailsProps {
+ permissions: Permissions;
+}
+
+export const Details: React.FC = ({ permissions }) => {
const { data, loading, error, reload } = use(FetchDetailsContext);
const setCacheKey = use(SetCacheKeyContext);
const cacheKey = use(CacheKeyContext);
@@ -104,7 +109,7 @@ export const Details: React.FC = () => {
)}
{data?.value && }
- {data && }
+ {data && permissions.includes("invalidate") && }
);
diff --git a/packages/cache-widget/src/lib/types.ts b/packages/cache-widget/src/lib/types.ts
index 65ff46a..f0992d0 100644
--- a/packages/cache-widget/src/lib/types.ts
+++ b/packages/cache-widget/src/lib/types.ts
@@ -23,3 +23,5 @@ export type CacheWidgetData = {
keys: string[];
keyDetails: Record;
};
+
+export type Permissions = ("read" | "invalidate")[];
diff --git a/packages/cache-widget/src/widget.tsx b/packages/cache-widget/src/widget.tsx
index eacae86..67216a9 100644
--- a/packages/cache-widget/src/widget.tsx
+++ b/packages/cache-widget/src/widget.tsx
@@ -2,6 +2,7 @@
import React from "react";
+import { type Permissions } from "./lib/types";
import { Trigger } from "./components/trigger";
import { Dialog } from "./components/dialog";
import { CloseButton } from "./components/close-button";
@@ -13,9 +14,12 @@ import { CacheWidgetProvider } from "./store/provider";
interface CacheWidgetProps {
apiUrl?: string;
+ permissions?: Permissions | null;
}
-export const CacheWidget: React.FC = ({ apiUrl = "/api/cache-widget" }) => {
+export const CacheWidget: React.FC = ({ apiUrl = "/api/cache-widget", permissions = ["read"] }) => {
+ if (permissions === null || !permissions.includes("read")) return null;
+
return (
@@ -24,7 +28,7 @@ export const CacheWidget: React.FC = ({ apiUrl = "/api/cache-w
-
+