Files
express-twtkpr/src/middlewares/queryHandler/metadataHandler.ts
Eric Woodward 8658a14200 Move plugins to express-twtkpr-core-plugins package
Add plugin structure
Fix stale cache after posting
Update to v0.9.0
2026-05-12 23:43:26 -04:00

89 lines
2.3 KiB
TypeScript

import type { Request, Response } from 'express';
import type { Metadata } from 'twtxt-lib';
import {
generateEtag,
getQueryParameterArray,
getValueOrFirstEntry,
} from '../../lib/utils.js';
import { NodeCache } from '@cacheable/node-cache';
import { QueryParameters } from '../../types.js';
export interface MetadataHandler {
cache: NodeCache<unknown>;
metadataParameter: QueryParameters['metadata'];
req: Request;
res: Response;
}
/**
*
* @param req
* @param res
* @param cache
* @param metadataParameter
*/
export default function metadataHandler(
req: Request,
res: Response,
metadata: Metadata,
metadataParameter: QueryParameters['metadata']
) {
const metadataToMatch = getQueryParameterArray(req.query[metadataParameter]);
const searchTermsToMatch = [
...getQueryParameterArray(req.query.search),
...getQueryParameterArray(req.query.s),
];
const wantsJson =
req.is('json') ||
getValueOrFirstEntry(getQueryParameterArray(req.query.format)) === 'json';
if (wantsJson) res.set('content-type', 'application/json');
else res.set('content-type', 'text/plain');
const matchedMetadata = Object.keys(metadata)
.filter(
(key) =>
(!metadataToMatch.length ||
(metadataToMatch.length === 1 && metadataToMatch[0] === '') ||
metadataToMatch.includes(key)) &&
(!searchTermsToMatch.length ||
searchTermsToMatch.some((term) =>
key.includes(term) || Array.isArray(metadata[key])
? (metadata[key] as string[]).some((val) => val.includes(term))
: metadata[key].includes(term)
))
)
.reduce(
(acc, key) => {
const value = metadata[key as keyof typeof metadata];
acc[key] = Array.isArray(value)
? value.filter(
(value) =>
!searchTermsToMatch.length ||
searchTermsToMatch.some(
(term) => key.includes(term) || value.includes(term)
)
)
: value;
return acc;
},
{} as Record<string, string | string[]>
);
const result = wantsJson
? JSON.stringify(matchedMetadata)
: Object.keys(matchedMetadata)
.map((key) => {
const value = matchedMetadata[key as keyof typeof matchedMetadata];
return Array.isArray(value)
? value.map((rowVal) => `${key}: ${rowVal}`).join('\n')
: `${key}: ${value}`;
})
.join('\n');
res.set('etag', generateEtag(result)).send(result);
}