feat: compose TechLog static and mock adapters

This commit is contained in:
DongHyeonka
2026-08-15 19:36:46 +09:00
parent 708680b28e
commit 27dda3e0e3
18 changed files with 3107 additions and 1 deletions
@@ -0,0 +1,39 @@
import { StudioGatewayError } from "../../application/ports/studio-gateway-error.ts";
import type { ProblemDetails } from "../../contracts/studio/contract.ts";
import { stableStringify } from "./stable-stringify.ts";
export type CursorPayload = { binding: string; lastValue: string; lastId: string };
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
function invalid(detail: string) {
const problem: ProblemDetails = {
type: "https://techlog.local/problems/request-validation-failed", title: "Request validation failed",
status: 422, detail, code: "REQUEST_VALIDATION_FAILED", retryable: false,
fieldErrors: [{ path: "/cursor", message: detail }],
};
return new StudioGatewayError(problem);
}
export function cursorBinding(value: unknown) { return stableStringify(value); }
export function encodeCursor(payload: CursorPayload): string {
const bytes = new TextEncoder().encode(stableStringify(payload));
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
}
export function decodeCursor(cursor: string, binding: string): CursorPayload {
try {
const base64 = cursor.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(cursor.length / 4) * 4, "=");
const bytes = Uint8Array.from(atob(base64), (character) => character.charCodeAt(0));
const parsed = JSON.parse(new TextDecoder().decode(bytes)) as Partial<CursorPayload>;
if (parsed.binding !== binding || typeof parsed.lastValue !== "string" || typeof parsed.lastId !== "string" || !UUID.test(parsed.lastId)) {
throw invalid("Cursor does not match the normalized filters and sort.");
}
return parsed as CursorPayload;
} catch (error) {
if (error instanceof StudioGatewayError) throw error;
throw invalid("Cursor is malformed.");
}
}