a cache for slack profile pictures and emojis

feat: purge me 5 minutes after the hour for auto updating pfp

dunkirk.sh 9304bfca ce825d3f

verified
Changed files
+85 -4
src
+17 -1
README.md
···
### Usage
-
The api is pretty simple. You can get a profile picture by calling `GET /profile/:id` where `:id` is the slack user id. You can get an emoji by calling `GET /emoji/:name` where `:name` is the name of the emoji. You can also get a list of all emojis by calling `GET /emojis`. (WIP - subject to rapid change)
+
The api is pretty simple. You can get a profile picture by calling `GET /profile/:id` where `:id` is the slack user id. You can get an emoji by calling `GET /emoji/:name` where `:name` is the name of the emoji. You can also get a list of all emojis by calling `GET /emojis`.
+
+
Additionally, you can manually purge a specific user's cache with `POST /users/:user/purge` (requires authentication with a bearer token).
There are also complete swagger docs available at [`/swagger`](https://cachet.dunkirk.sh/swagger)! They are dynamically generated from the code so they should always be up to date! (The types force me to keep them up to date ^_^)
···
const emoji = await cache.getEmoji("hackshark");
const user = await cache.getUser("U062UG485EE");
+
+
// You can also purge the cache for a specific user
+
const purgeResult = await cache.purgeUserCache("U062UG485EE");
+
console.log(`Cache purged: ${purgeResult}`); // true if user was in cache and purged
```
The final bit was at this point a bit of a ridiculous one. I didn't like how heavyweight the `bolt` or `slack-edge` packages were so I rolled my own slack api wrapper. It's again fully typed and designed to be as lightweight as possible.
···
const user = await slack.getUser("U062UG485EE");
const emojis = await slack.getEmoji();
+
+
// Manually purge a specific user's cache using the API endpoint
+
const response = await fetch("https://cachet.example.com/users/U062UG485EE/purge", {
+
method: "POST",
+
headers: {
+
"Authorization": `Bearer ${process.env.BEARER_TOKEN}`
+
}
+
});
+
const result = await response.json();
+
// { message: "User cache purged", userId: "U062UG485EE", success: true }
```
<p align="center">
+18 -3
src/cache.ts
···
});
}
-
/*
+
/**
* Purges expired items from the cache
* @returns int indicating number of items purged
*/
···
return result.changes + result2.changes;
}
-
/*
+
/**
+
* Purges cache for a specific user
+
* @param userId The Slack user ID to purge from cache
+
* @returns boolean indicating if any user was purged
+
*/
+
async purgeUserCache(userId: string): Promise<boolean> {
+
try {
+
const result = this.db.run("DELETE FROM users WHERE userId = ?", [userId]);
+
return result.changes > 0;
+
} catch (error) {
+
console.error("Error purging user cache:", error);
+
return false;
+
}
+
}
+
+
/**
* Purges all items from the cache
-
* @returns int indicating number of items purged
+
* @returns Object containing purge results
*/
async purgeAll(): Promise<{
message: string;
+50
src/index.ts
···
}),
)
.use(
+
cron({
+
name: "purgeSpecificUserCache",
+
pattern: "5 * * * *", // Run at 5 minutes after each hour
+
async run() {
+
const userId = "U062UG485EE";
+
console.log(`Purging cache for user ${userId}`);
+
const result = await cache.purgeUserCache(userId);
+
console.log(
+
`Cache purge for user ${userId}: ${result ? "successful" : "no cache entry found"}`,
+
);
+
},
+
}),
+
)
+
.use(
swagger({
exclude: ["/", "favicon.ico"],
documentation: {
···
message: t.String(),
users: t.Number(),
emojis: t.Number(),
+
}),
+
401: t.String({ default: "Unauthorized" }),
+
},
+
},
+
)
+
.post(
+
"/users/:user/purge",
+
async ({ headers, params, set }) => {
+
if (headers.authorization !== `Bearer ${process.env.BEARER_TOKEN}`) {
+
set.status = 401;
+
return "Unauthorized";
+
}
+
+
const success = await cache.purgeUserCache(params.user);
+
+
return {
+
message: success ? "User cache purged" : "User not found in cache",
+
userId: params.user,
+
success,
+
};
+
},
+
{
+
tags: ["The Cache!"],
+
headers: t.Object({
+
authorization: t.String({
+
default: "Bearer <token>",
+
}),
+
}),
+
params: t.Object({
+
user: t.String(),
+
}),
+
response: {
+
200: t.Object({
+
message: t.String(),
+
userId: t.String(),
+
success: t.Boolean(),
}),
401: t.String({ default: "Unauthorized" }),
},