mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 13:10:56 +00:00
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { BadRequestException } from '@nestjs/common';
|
|
|
|
/**
|
|
* Keyset cursor for paging a thread backwards from newest.
|
|
*
|
|
* The sort key is the pair `(createdAt, id)`, not `createdAt` alone: two
|
|
* messages can share a millisecond, and a cursor on a non-unique key either
|
|
* re-serves or skips the tied rows depending which side of the boundary they
|
|
* land on. The id breaks ties with a stable total order.
|
|
*
|
|
* Deliberately a twin of the freight API's `message-cursor.ts`, not a shared
|
|
* import: the two APIs share no runtime package, and @edr/types is Nest-free by
|
|
* design (this throws Nest exceptions). The wire format matches so a client can
|
|
* treat both chats identically — keep them in step if either changes.
|
|
*/
|
|
export interface MessageCursor {
|
|
createdAt: Date;
|
|
id: string;
|
|
}
|
|
|
|
export function encodeMessageCursor(cursor: MessageCursor): string {
|
|
return Buffer.from(`${cursor.createdAt.toISOString()}|${cursor.id}`, 'utf8').toString(
|
|
'base64url',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Parse a client-supplied cursor. Rejects anything malformed rather than
|
|
* silently falling back to "first page" — a corrupted cursor that degrades to
|
|
* page 1 makes an infinite scroll loop forever over the same rows.
|
|
*/
|
|
export function decodeMessageCursor(raw: string): MessageCursor {
|
|
let decoded: string;
|
|
try {
|
|
decoded = Buffer.from(raw, 'base64url').toString('utf8');
|
|
} catch {
|
|
throw new BadRequestException('Malformed pagination cursor.');
|
|
}
|
|
|
|
const separator = decoded.lastIndexOf('|');
|
|
if (separator === -1) {
|
|
throw new BadRequestException('Malformed pagination cursor.');
|
|
}
|
|
|
|
const createdAt = new Date(decoded.slice(0, separator));
|
|
const id = decoded.slice(separator + 1);
|
|
if (Number.isNaN(createdAt.getTime()) || !id) {
|
|
throw new BadRequestException('Malformed pagination cursor.');
|
|
}
|
|
|
|
return { createdAt, id };
|
|
}
|