✨ feat: enhance SSR cache management with dependency tracking and entry-level invalidation
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
const { cryptchaSiteId } = require("../config-client")
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} str
|
||||
@@ -9,81 +7,44 @@ function log(str) {
|
||||
}
|
||||
|
||||
/**
|
||||
* convert object to string
|
||||
* @param {any} obj object
|
||||
* @returns {string}
|
||||
*/
|
||||
function obj2str(obj) {
|
||||
if (Array.isArray(obj)) {
|
||||
return JSON.stringify(
|
||||
obj.map(function (idx) {
|
||||
return obj2str(idx)
|
||||
})
|
||||
)
|
||||
} else if (typeof obj === "object" && obj !== null) {
|
||||
var elements = Object.keys(obj)
|
||||
.sort()
|
||||
.map(function (key) {
|
||||
var val = obj2str(obj[key])
|
||||
if (val) {
|
||||
return key + ":" + val
|
||||
}
|
||||
})
|
||||
|
||||
var elementsCleaned = []
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (elements[i]) elementsCleaned.push(elements[i])
|
||||
}
|
||||
|
||||
return "{" + elementsCleaned.join("|") + "}"
|
||||
}
|
||||
|
||||
if (obj) return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* clear SSR cache
|
||||
* clear SSR cache – entry-level invalidation
|
||||
*
|
||||
* Dependencies are stored as strings: "col:id" (detail) or "col:*" (list).
|
||||
* - POST (new entry): only list deps affected → delete where "col:*"
|
||||
* - PUT/DELETE (entry): detail + list deps affected → delete where "col:id" OR "col:*"
|
||||
* - No args: full wipe (manual clear)
|
||||
*
|
||||
* @param {string} [collectionName] - collection name
|
||||
* @param {string} [entryId] - specific entry ID (for PUT/DELETE)
|
||||
* @param {string} [method] - HTTP method (POST/PUT/DELETE)
|
||||
* @returns {number}
|
||||
*/
|
||||
function clearSSRCache() {
|
||||
var info = context.db.deleteMany("ssr", {})
|
||||
context.response.header("X-SSR-Cleared", info.removed)
|
||||
return info.removed
|
||||
}
|
||||
function clearSSRCache(collectionName, entryId, method) {
|
||||
/** @type {any} */
|
||||
let filter = {}
|
||||
const m = method ? method.toUpperCase() : ""
|
||||
|
||||
function cryptchaCheck() {
|
||||
const solutionId = context.data._sId
|
||||
const solution = context.data._s
|
||||
|
||||
const body = JSON.stringify({ solution: solution })
|
||||
console.log(body)
|
||||
const resp = context.http.fetch(
|
||||
"https://cryptcha.webmakers.de/api/command?siteId=" +
|
||||
cryptchaSiteId +
|
||||
"&cmd=check&clear=1&solutionId=" +
|
||||
solutionId,
|
||||
{
|
||||
method: "POST",
|
||||
body,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
)
|
||||
const j = resp.body.json()
|
||||
|
||||
const corrent = j.status == "ok" && resp.status == 200
|
||||
if (!corrent) {
|
||||
throw {
|
||||
status: 400,
|
||||
log: false,
|
||||
error: "incorrect data",
|
||||
if (collectionName && entryId && (m === "PUT" || m === "DELETE")) {
|
||||
// entry updated or deleted: invalidate pages that reference this specific entry OR list this collection
|
||||
filter = {
|
||||
$or: [{ dependencies: collectionName + ":" + entryId }, { dependencies: collectionName + ":*" }],
|
||||
}
|
||||
} else if (collectionName) {
|
||||
// new entry (POST) or unknown method: invalidate all pages that list this collection
|
||||
filter = { dependencies: collectionName + ":*" }
|
||||
}
|
||||
return true
|
||||
// else: no args → full wipe (empty filter)
|
||||
|
||||
// @ts-ignore – filter uses MongoDB operators not in DbReadOptions type
|
||||
const info = context.db.deleteMany("ssr", { filter: filter })
|
||||
context.response.header("X-SSR-Cleared", info.removed)
|
||||
if (collectionName) {
|
||||
context.response.header("X-SSR-Cleared-Collection", collectionName)
|
||||
}
|
||||
return info.removed
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
log,
|
||||
clearSSRCache,
|
||||
obj2str,
|
||||
cryptchaCheck,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user