mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 22:25:42 +00:00
feat: setup attachment to the freight chat
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { BadRequestException } from "@nestjs/common";
|
||||
|
||||
/**
|
||||
* Keyset cursor for paging a thread backwards from newest.
|
||||
*
|
||||
* The cursor is just a message id. The sort key is the pair `(created_at, id)` —
|
||||
* two messages can share a timestamp, and a cursor on a non-unique key either
|
||||
* re-serves or skips the tied rows — but the *timestamp half is never sent over
|
||||
* the wire*, because it cannot survive the trip.
|
||||
*
|
||||
* `support_messages.created_at` is `timestamptz(6)`; a JS `Date` holds only
|
||||
* milliseconds, so the value TypeORM hands back is already truncated. Encoding
|
||||
* that into the cursor and comparing against it would silently skip every row
|
||||
* sharing the cursor's millisecond but earlier within it (`.254100` is not
|
||||
* `< .254000`) — those rows would never appear on any page. Sending the id alone
|
||||
* and letting Postgres look the real `(created_at, id)` up keeps the comparison
|
||||
* at full precision on the server, where it was never lossy.
|
||||
*
|
||||
* Opaque on purpose (base64): clients must treat it as a token, so the sort key
|
||||
* can change without a contract change.
|
||||
*
|
||||
* The passenger API's twin encodes a timestamp because its column is
|
||||
* `TIMESTAMP(3)` — millisecond, matching JS exactly — so it has no such loss.
|
||||
* The two formats are deliberately NOT interchangeable; each app reads only its
|
||||
* own cursors.
|
||||
*/
|
||||
export function encodeMessageCursor(id: string): string {
|
||||
return Buffer.from(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): string {
|
||||
let id: string;
|
||||
try {
|
||||
id = Buffer.from(raw, "base64url").toString("utf8");
|
||||
} catch {
|
||||
throw new BadRequestException("Malformed pagination cursor.");
|
||||
}
|
||||
|
||||
// The id goes into a parameterized query, but validate the shape anyway: a
|
||||
// non-uuid can only be a mangled cursor, and failing loudly here beats an
|
||||
// empty page that reads as "start of conversation".
|
||||
if (
|
||||
!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)
|
||||
) {
|
||||
throw new BadRequestException("Malformed pagination cursor.");
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
Reference in New Issue
Block a user