File
Blob: src/worker/repositories/routeCache.ts
| 1 | import { createLogger } from "@/worker/common"; |
| 2 | import { z } from "zod"; |
| 3 | |
| 4 | // Workers KV `ROUTES` candidate cache. Backfill and repo-mutation flows |
| 5 | // write here; the resolver reads here as a hint and re-confirms against |
| 6 | // D1. The payload deliberately omits `visibility` because KV is |
| 7 | // eventually consistent and must not be an authorization source. |
| 8 | |
| 9 | export const RouteCacheRecordSchema = z.object({ |
| 10 | repositoryId: z.string(), |
| 11 | namespaceId: z.string(), |
| 12 | doName: z.string(), |
| 13 | updatedAt: z.number(), |
| 14 | }); |
| 15 | |
| 16 | export type RouteCacheRecord = z.infer<typeof RouteCacheRecordSchema>; |
| 17 | |
| 18 | export function routeCacheKey(namespaceSlug: string, repoSlug: string): string { |
| 19 | return `repo-route:v1:${namespaceSlug}/${repoSlug}`; |
| 20 | } |
| 21 | |
| 22 | // Writes/deletes log only on success. Failures throw to the caller so |
| 23 | // surrounding handlers can attach their own context (legacyBackfill, |
| 24 | // repo create/rename/delete) - duplicating a generic error log here |
| 25 | // would just bury the operational signal. |
| 26 | export async function putRouteCacheRecord( |
| 27 | env: Env, |
| 28 | namespaceSlug: string, |
| 29 | repoSlug: string, |
| 30 | record: RouteCacheRecord |
| 31 | ): Promise<void> { |
| 32 | await env.ROUTES.put(routeCacheKey(namespaceSlug, repoSlug), JSON.stringify(record)); |
| 33 | const log = createLogger(env.LOG_LEVEL, { service: "RouteCache" }); |
| 34 | log.debug("routes:put-ok", { |
| 35 | namespaceSlug, |
| 36 | repoSlug, |
| 37 | repositoryId: record.repositoryId, |
| 38 | }); |
| 39 | } |
| 40 | |
| 41 | export async function getRouteCacheRecord( |
| 42 | env: Env, |
| 43 | namespaceSlug: string, |
| 44 | repoSlug: string |
| 45 | ): Promise<RouteCacheRecord | null> { |
| 46 | const raw = await env.ROUTES.get(routeCacheKey(namespaceSlug, repoSlug)); |
| 47 | if (!raw) return null; |
| 48 | try { |
| 49 | const parsed = RouteCacheRecordSchema.safeParse(JSON.parse(raw)); |
| 50 | if (parsed.success) return parsed.data; |
| 51 | } catch {} |
| 52 | return null; |
| 53 | } |
| 54 | |
| 55 | export async function deleteRouteCacheRecord( |
| 56 | env: Env, |
| 57 | namespaceSlug: string, |
| 58 | repoSlug: string |
| 59 | ): Promise<void> { |
| 60 | await env.ROUTES.delete(routeCacheKey(namespaceSlug, repoSlug)); |
| 61 | const log = createLogger(env.LOG_LEVEL, { service: "RouteCache" }); |
| 62 | log.debug("routes:delete-ok", { namespaceSlug, repoSlug }); |
| 63 | } |