diff --git a/src/index.ts b/src/index.ts index 9c0c0fa..96292f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,22 @@ const development = env.NODE_ENV !== 'production'; const faviconInit = { headers: new Headers({ 'Content-Type': 'image/png' }) }; + +function getEtag(data: string) { + const sha = Bun.SHA256.hash(data); + return Buffer.from(sha.buffer).toString('base64url'); +} + +function etagResponse(etag: string, cacheControl?: string) { + const headers = new Headers(); + headers.set('ETag', etag); + if (cacheControl) headers.set('Cache-Control', cacheControl); + return new Response('', { status: 304, headers }); +} + +let entriesETag = ''; +let entriesNotModified = false; + Bun.serve({ routes: { '/': homepage, @@ -26,10 +42,21 @@ Bun.serve({ async GET(req) { if (!isAuthenticated(req)) return unauthorizedResp(); - const entries = await drizzleDB.select({ id: entry.id, name: entry.name, href: entry.href, finished: entry.finished, updated_at: entry.updatedAt }).from(entry).orderBy(desc(entry.updatedAt)); + if (entriesNotModified && req.headers.get('if-none-match') === entriesETag) { + return etagResponse(entriesETag); + } - return new Response(JSON.stringify(entries), { - headers: { 'Content-Type': 'application/json' } + entriesNotModified = true; + const entries = await drizzleDB + .select({ id: entry.id, name: entry.name, href: entry.href, finished: entry.finished, updated_at: entry.updatedAt }) + .from(entry) + .orderBy(desc(entry.updatedAt)); + + const body = JSON.stringify(entries); + entriesETag = getEtag(body); + + return new Response(body, { + headers: { 'Content-Type': 'application/json', 'ETag': entriesETag } }); }, async PUT(req) { @@ -52,6 +79,7 @@ Bun.serve({ return new Response('Invalid data, multiple matches?', { status: 400 }); } + entriesNotModified = false; return new Response(JSON.stringify({ created }), { headers: { 'Content-Type': 'application/json' } }); @@ -82,6 +110,8 @@ Bun.serve({ await drizzleDB.update(entry).set(body).where(eq(entry.id, id)).execute(); let created = false; + + entriesNotModified = false; return new Response(JSON.stringify({ created: false }), { headers: { 'Content-Type': 'application/json' } }); @@ -94,6 +124,7 @@ Bun.serve({ await drizzleDB.delete(entry).where(eq(entry.id, id)).execute(); + entriesNotModified = false; return new Response('OK'); }, }, @@ -111,6 +142,7 @@ Bun.serve({ .where(eq(entry.id, id)) .execute(); + entriesNotModified = false; return new Response('OK'); }, },