feat: send dashboard read-model deltas

This commit is contained in:
2026-08-11 12:36:29 +00:00
parent c737ee2cd1
commit a2e94c3092
17 changed files with 1285 additions and 395 deletions
@@ -0,0 +1,90 @@
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { authedProcedure, router } from '../../trpc.js';
import { createReadModelDelta } from '../../services/readModelDeltaCache.js';
import { getBoardAccess } from '../board/index.js';
import { getGeneralContext } from '../general/index.js';
import { getTurnCommandTable } from '../turns/index.js';
const zRevision = z.string().regex(/^[A-Za-z0-9_-]{22}$/u);
const zContextBundleInput = z
.object({
include: z.object({
context: z.boolean(),
commandTable: z.boolean(),
boardAccess: z.boolean(),
}),
known: z
.object({
context: zRevision.optional(),
commandTable: zRevision.optional(),
boardAccess: zRevision.optional(),
})
.optional(),
forceSnapshot: z.boolean().optional(),
})
.refine((input) => Object.values(input.include).some(Boolean), {
message: 'At least one dashboard context slice must be requested.',
path: ['include'],
});
export const dashboardRouter = router({
getContextBundleDelta: authedProcedure.input(zContextBundleInput).query(async ({ ctx, input }) => {
const viewerId = ctx.auth?.user.id;
if (!viewerId) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
const currentContext = await getGeneralContext(ctx);
const generalId = currentContext?.general.id ?? null;
const [commandTable, boardAccess] = await Promise.all([
input.include.commandTable && generalId ? getTurnCommandTable(ctx, generalId) : Promise.resolve(undefined),
input.include.boardAccess && generalId ? getBoardAccess(ctx) : Promise.resolve(undefined),
]);
const context = input.include.context ? currentContext : undefined;
const [contextDelta, commandTableDelta, boardAccessDelta] = await Promise.all([
context === undefined
? Promise.resolve(undefined)
: createReadModelDelta({
store: ctx.redis,
profile: ctx.profile.name,
viewerId,
slice: `main-context:${generalId ?? 'none'}`,
value: context,
knownRevision: input.known?.context,
forceSnapshot: input.forceSnapshot,
}),
commandTable === undefined
? Promise.resolve(undefined)
: createReadModelDelta({
store: ctx.redis,
profile: ctx.profile.name,
viewerId,
slice: `main-command-table:${generalId}`,
value: commandTable,
knownRevision: input.known?.commandTable,
forceSnapshot: input.forceSnapshot,
}),
boardAccess === undefined
? Promise.resolve(undefined)
: createReadModelDelta({
store: ctx.redis,
profile: ctx.profile.name,
viewerId,
slice: `main-board-access:${generalId}`,
value: boardAccess,
knownRevision: input.known?.boardAccess,
forceSnapshot: input.forceSnapshot,
}),
]);
return {
context: contextDelta,
commandTable: commandTableDelta,
boardAccess: boardAccessDelta,
};
}),
});