Skip to content

Commit 62de32e

Browse files
authored
Merge pull request #132 from alexdln/nic-104
nic-104 add entry invalidation tools
2 parents 949e6b8 + 4d1ef47 commit 62de32e

File tree

21 files changed

+335
-163
lines changed

21 files changed

+335
-163
lines changed

examples/base-handler/src/app/api/cache-widget/[[...segments]]/route.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
1-
import { getCacheData } from "@nimpl/cache-tools";
1+
import { createRouteHelpers } from "@nimpl/cache-tools";
22

33
// eslint-disable-next-line @typescript-eslint/no-require-imports
44
const cacheHandler = require("../../../../../cache-handler.js");
55

6-
export const GET = async (_request: Request, { params }: { params: Promise<{ segments?: string[] }> }) => {
6+
const { getCacheData, putCacheData, deleteCacheData } = createRouteHelpers(cacheHandler);
7+
8+
type RouteParams = { params: Promise<{ segments?: string[] }> };
9+
10+
export const GET = async (_request: Request, { params }: RouteParams) => {
11+
const { segments } = await params;
12+
const data = await getCacheData(segments);
13+
14+
if (!data) return new Response("", { status: 404 });
15+
16+
return new Response(JSON.stringify(data));
17+
};
18+
19+
export const PUT = async (_request: Request, { params }: RouteParams) => {
20+
const { segments } = await params;
21+
const data = await putCacheData(segments);
22+
23+
if (!data) return new Response("", { status: 404 });
24+
25+
return new Response(JSON.stringify(data));
26+
};
27+
28+
export const DELETE = async (_request: Request, { params }: RouteParams) => {
729
const { segments } = await params;
8-
const data = await getCacheData(cacheHandler, segments);
30+
const data = await deleteCacheData(segments);
931

1032
if (!data) return new Response("", { status: 404 });
1133

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
},
3232
"resolutions": {
3333
"@nimpl/cache-adapter>@nimpl/cache": "workspace:*",
34-
"@nimpl/cache-server>@nimpl/cache": "workspace:*"
34+
"@nimpl/cache-server>@nimpl/cache": "workspace:*",
35+
"@nimpl/cache-tools>@nimpl/cache": "workspace:*"
3536
},
3637
"license": "MIT",
3738
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a"

packages/cache-tools/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"url": "https://github.com/alexdln/"
4141
},
4242
"devDependencies": {
43+
"@nimpl/cache": "latest",
4344
"@rollup/plugin-commonjs": "29.0.0",
4445
"@rollup/plugin-node-resolve": "16.0.3",
4546
"@rollup/plugin-terser": "0.4.4",

packages/cache-tools/src/create-cache.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { type CacheHandler, type Metadata } from "./lib/types";
1+
import { type CacheHandler, type Metadata } from "@nimpl/cache";
2+
23
import { objectToStream, streamToRaw } from "./lib/stream";
34

45
export const cache =
Lines changed: 11 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,17 @@
1-
import { type CacheHandler, type KeysData } from "./lib/types";
2-
import { streamToRaw } from "./lib/stream";
1+
import { type CacheHandler } from "@nimpl/cache";
32

4-
export const getKeys = async (
5-
cacheHandler: CacheHandler,
6-
type: "main" | "persistent" | "ephemeral" = "main",
7-
): Promise<KeysData> => {
8-
const layers = {
9-
main: cacheHandler,
10-
persistent: cacheHandler.persistentLayer,
11-
ephemeral: cacheHandler.ephemeralLayer,
12-
};
13-
const handler = layers[type];
14-
return handler.keys();
15-
};
16-
17-
export const getKeyDetails = async (
18-
cacheHandler: CacheHandler,
19-
type: "main" | "persistent" | "ephemeral",
20-
key: string,
21-
) => {
22-
const layers = {
23-
main: cacheHandler,
24-
persistent: cacheHandler.persistentLayer,
25-
ephemeral: cacheHandler.ephemeralLayer,
26-
};
27-
const handler = layers[type];
28-
try {
29-
const cacheEntry = await handler.getEntry(key);
30-
31-
if (!cacheEntry) {
32-
return {
33-
key,
34-
metadata: null,
35-
value: null,
36-
size: 0,
37-
status: null,
38-
};
39-
}
40-
41-
const { entry, size, status } = cacheEntry;
42-
const [cacheStream, responseStream] = entry.value.tee();
43-
entry.value = cacheStream;
44-
const value = await streamToRaw(responseStream);
45-
46-
return {
47-
key,
48-
metadata: {
49-
tags: entry.tags,
50-
timestamp: entry.timestamp,
51-
stale: entry.stale,
52-
revalidate: entry.revalidate,
53-
expire: entry.expire,
54-
},
55-
value,
56-
size,
57-
status,
58-
};
59-
} catch (error) {
60-
return {
61-
key,
62-
metadata: null,
63-
value: null,
64-
size: 0,
65-
error: error instanceof Error ? error.message : "Unknown error",
66-
status: null,
67-
};
68-
}
69-
};
70-
71-
export const getCacheData = (cacheHandler: CacheHandler, segments?: string[]) => {
72-
if (!segments?.length || segments.length > 2) {
73-
return null;
74-
}
75-
const type = segments[0] as "main" | "persistent" | "ephemeral";
76-
if (!["main", "persistent", "ephemeral"].includes(type)) {
77-
return null;
78-
}
79-
if (segments.length === 1) {
80-
return getKeys(cacheHandler, type);
81-
}
82-
83-
return getKeyDetails(cacheHandler, type, segments[1]);
84-
};
85-
86-
export const updateTags = async (cacheHandler: CacheHandler, tags: string[], duration: number) => {
87-
return cacheHandler.updateTags(tags, { expire: duration });
88-
};
89-
90-
export const updateKey = async (cacheHandler: CacheHandler, key: string, duration: number) => {
91-
return cacheHandler.updateKey(key, { expire: duration });
92-
};
3+
import { type LayerType } from "./lib/types";
4+
import { getKeys, getKeyDetails } from "./lib/get-helpers";
5+
import { updateKey, updateTags } from "./lib/put-helpers";
6+
import { deleteKey } from "./lib/delete-helpers";
937

948
export const createHelpers = (cacheHandler: CacheHandler) => {
959
return {
96-
getKeys: (type: "main" | "persistent" | "ephemeral") => getKeys(cacheHandler, type),
97-
getKeyDetails: (type: "main" | "persistent" | "ephemeral", key: string) =>
98-
getKeyDetails(cacheHandler, type, key),
99-
getCacheData: (segments?: string[]) => getCacheData(cacheHandler, segments),
100-
updateTags: (tags: string[], duration: number) => updateTags(cacheHandler, tags, duration),
101-
updateKey: (key: string, duration: number) => updateKey(cacheHandler, key, duration),
10+
getKeys: (type: LayerType) => getKeys(cacheHandler, type),
11+
getKeyDetails: (type: LayerType, key: string) => getKeyDetails(cacheHandler, type, key),
12+
updateTags: (type: LayerType, tags: string[], duration: number) =>
13+
updateTags(cacheHandler, type, tags, duration),
14+
updateKey: (type: LayerType, key: string, duration: number) => updateKey(cacheHandler, type, key, duration),
15+
deleteKey: (type: LayerType, key: string) => deleteKey(cacheHandler, type, key),
10216
};
10317
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { type CacheHandler } from "@nimpl/cache";
2+
3+
import { getCacheData } from "./lib/get-helpers";
4+
import { putCacheData } from "./lib/put-helpers";
5+
import { deleteCacheData } from "./lib/delete-helpers";
6+
7+
export const createRouteHelpers = (cacheHandler: CacheHandler) => {
8+
return {
9+
getCacheData: (segments?: string[]) => getCacheData(cacheHandler, segments),
10+
putCacheData: (segments?: string[]) => putCacheData(cacheHandler, segments),
11+
deleteCacheData: (segments?: string[]) => deleteCacheData(cacheHandler, segments),
12+
};
13+
};

packages/cache-tools/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export * from "./create-cache";
22
export * from "./create-helpers";
3-
export * from "./lib/types";
3+
export * from "./create-route";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const LAYER_TYPES = ["main", "persistent", "ephemeral"] as const;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { CacheHandler } from "@nimpl/cache";
2+
3+
import { type LayerType } from "./types";
4+
import { LAYER_TYPES } from "./constants";
5+
6+
export const deleteKey = async (cacheHandler: CacheHandler, type: LayerType, key: string) => {
7+
const layers = {
8+
main: cacheHandler,
9+
persistent: cacheHandler.persistentLayer,
10+
ephemeral: cacheHandler.ephemeralLayer,
11+
};
12+
return layers[type].delete(key);
13+
};
14+
15+
export const deleteCacheData = async (cacheHandler: CacheHandler, segments?: string[]) => {
16+
if (!segments?.length || segments.length > 3) {
17+
return null;
18+
}
19+
const type = segments[0] as LayerType;
20+
if (!LAYER_TYPES.includes(type)) {
21+
return null;
22+
}
23+
if (segments[1] === "key") {
24+
await deleteKey(cacheHandler, type, segments[2]);
25+
return true;
26+
}
27+
return null;
28+
};
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { type CacheHandler } from "@nimpl/cache";
2+
3+
import { type LayerType } from "./types";
4+
import { streamToRaw } from "./stream";
5+
import { LAYER_TYPES } from "./constants";
6+
7+
export const getKeys = async (cacheHandler: CacheHandler, type: LayerType = "main"): Promise<string[]> => {
8+
const layers = {
9+
main: cacheHandler,
10+
persistent: cacheHandler.persistentLayer,
11+
ephemeral: cacheHandler.ephemeralLayer,
12+
};
13+
const handler = layers[type];
14+
return handler.keys();
15+
};
16+
17+
export const getKeyDetails = async (cacheHandler: CacheHandler, type: LayerType, key: string) => {
18+
const layers = {
19+
main: cacheHandler,
20+
persistent: cacheHandler.persistentLayer,
21+
ephemeral: cacheHandler.ephemeralLayer,
22+
};
23+
const handler = layers[type];
24+
try {
25+
const cacheEntry = await handler.getEntry(key);
26+
27+
if (!cacheEntry) {
28+
return {
29+
key,
30+
metadata: null,
31+
value: null,
32+
size: 0,
33+
status: null,
34+
};
35+
}
36+
37+
const { entry, size, status } = cacheEntry;
38+
const [cacheStream, responseStream] = entry.value.tee();
39+
entry.value = cacheStream;
40+
const value = await streamToRaw(responseStream);
41+
42+
return {
43+
key,
44+
metadata: {
45+
tags: entry.tags,
46+
timestamp: entry.timestamp,
47+
stale: entry.stale,
48+
revalidate: entry.revalidate,
49+
expire: entry.expire,
50+
},
51+
value,
52+
size,
53+
status,
54+
};
55+
} catch (error) {
56+
return {
57+
key,
58+
metadata: null,
59+
value: null,
60+
size: 0,
61+
error: error instanceof Error ? error.message : "Unknown error",
62+
status: null,
63+
};
64+
}
65+
};
66+
67+
export const getCacheData = (cacheHandler: CacheHandler, segments?: string[]) => {
68+
if (!segments?.length || segments.length > 2) {
69+
return null;
70+
}
71+
const type = segments[0] as LayerType;
72+
if (!LAYER_TYPES.includes(type)) {
73+
return null;
74+
}
75+
if (segments.length === 1) {
76+
return getKeys(cacheHandler, type);
77+
}
78+
79+
return getKeyDetails(cacheHandler, type, segments[1]);
80+
};

0 commit comments

Comments
 (0)