feat(ssr-server): enhance lookup and aggregate handling for SSR cache invalidation

- Improved parsing of `lookup` and `aggregate` options to support JSON strings and arrays.
- Added support for object format in `lookup` and `aggregate` to specify collections.
- Simplified dependency tracking for SSR cache invalidation based on new formats.
This commit is contained in:
2026-05-17 15:16:32 +00:00
parent bd8d413850
commit 349fb9b2da
4 changed files with 2136 additions and 1278 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
ADMIN_TOKEN=5bdfjc78hdxn338cuhSJ
ADMIN_ASSET_VERSION=db968ab-dirty-1779028656102
ADMIN_ASSET_VERSION=db968ab-dirty-1779030587180
+2064 -1244
View File
File diff suppressed because it is too large Load Diff
+61 -29
View File
@@ -93,42 +93,74 @@ function ssrRequest(cacheKey, endpoint, query, options) {
// Both `lookup` and `aggregate` parameters can inject data from other collections.
// We must invalidate the SSR cache if any of those referenced collections change.
if (options && options.lookup) {
const lookups = typeof options.lookup === "string" ? options.lookup.split(",") : [];
/** @type {any[]} */
let lookups = []
if (typeof options.lookup === "string") {
const trimmed = options.lookup.trim()
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
try {
const parsed = JSON.parse(trimmed)
lookups = Array.isArray(parsed) ? parsed : [parsed]
} catch (e) {
lookups = options.lookup.split(",")
}
} else {
lookups = options.lookup.split(",")
}
} else if (Array.isArray(options.lookup)) {
lookups = options.lookup
} else if (typeof options.lookup === "object" && options.lookup !== null) {
lookups = [options.lookup]
}
for (const l of lookups) {
// format: "fieldPath:collectionName"
const parts = l.split(":");
if (parts.length > 1) {
const targetCollection = parts[parts.length - 1];
if (typeof l === "object" && l !== null && l.collection) {
// @ts-ignore
context.ssrDeps[targetCollection + ":*"] = true;
context.ssrDeps[l.collection + ":*"] = true
} else if (typeof l === "string") {
// format: "fieldPath:collectionName"
const parts = l.split(":")
if (parts.length > 1) {
const targetCollection = parts[parts.length - 1]
// @ts-ignore
context.ssrDeps[targetCollection + ":*"] = true
}
}
}
}
const rawAggregate = (options && options.aggregate) || (options && options.params && options.params.aggregate);
const rawAggregate = (options && options.aggregate) || (options && options.params && options.params.aggregate)
if (rawAggregate) {
const aggregates = typeof rawAggregate === "string"
? rawAggregate.split(",")
: [];
for (const a of aggregates) {
// simple format: "collectionName:foreignField:..."
// json format: '{"collection":"comments",...}'
try {
if (a.startsWith("{")) {
const parsed = JSON.parse(a);
if (parsed && parsed.collection) {
// @ts-ignore
context.ssrDeps[parsed.collection + ":*"] = true;
}
} else {
const parts = a.split(":");
if (parts.length > 0) {
const targetCollection = parts[0];
// @ts-ignore
context.ssrDeps[targetCollection + ":*"] = true;
}
/** @type {any[]} */
let aggregates = []
if (typeof rawAggregate === "string") {
const trimmed = rawAggregate.trim()
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
try {
const parsed = JSON.parse(trimmed)
aggregates = Array.isArray(parsed) ? parsed : [parsed]
} catch (e) {
aggregates = rawAggregate.split(",")
}
} else {
aggregates = rawAggregate.split(",")
}
} else if (Array.isArray(rawAggregate)) {
aggregates = rawAggregate
} else if (typeof rawAggregate === "object" && rawAggregate !== null) {
aggregates = [rawAggregate]
}
for (const a of aggregates) {
if (typeof a === "object" && a !== null && a.collection) {
// @ts-ignore
context.ssrDeps[a.collection + ":*"] = true
} else if (typeof a === "string") {
const parts = a.split(":")
if (parts.length > 0) {
const targetCollection = parts[0]
// @ts-ignore
context.ssrDeps[targetCollection + ":*"] = true
}
} catch (e) {
// silently ignore parse errors here
}
}
}