diff options
| author | Yuval Adam <_@yuv.al> | 2025-07-10 13:55:01 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-07-10 13:55:23 +0200 |
| commit | 3f0837d920ba67496c5fc7f50485aed84b37d05e (patch) | |
| tree | 45548ab3defff3abfb34245e41db606caedf7e0b /src | |
| parent | c4284d7c2ab7b73af8424fcf379f44dee1682a1a (diff) | |
Simplify code'
Diffstat (limited to 'src')
| -rw-r--r-- | src/pages/api/counter.ts | 52 | ||||
| -rw-r--r-- | src/pages/api/hello.ts | 54 | ||||
| -rw-r--r-- | src/pages/index.astro | 277 | ||||
| -rw-r--r-- | src/worker.ts | 43 |
4 files changed, 57 insertions, 369 deletions
diff --git a/src/pages/api/counter.ts b/src/pages/api/counter.ts index 1d3d0b7..4f42236 100644 --- a/src/pages/api/counter.ts +++ b/src/pages/api/counter.ts @@ -6,54 +6,16 @@ interface Env { export const GET: APIRoute = async ({ locals }) => { const env = locals.runtime.env as Env; - if (!env?.COUNTER_DO) { - return new Response(JSON.stringify({ error: 'Durable Object not available' }), { - status: 500, - headers: { 'Content-Type': 'application/json' } - }); - } - - const id = env.COUNTER_DO.idFromName('global-counter'); + const id = env.COUNTER_DO.idFromName('counter'); const stub = env.COUNTER_DO.get(id); - - const response = await stub.fetch(new Request('https://counter.do/get')); - const data = await response.json(); - - return new Response(JSON.stringify(data), { - headers: { 'Content-Type': 'application/json' } - }); + const response = await stub.fetch('https://counter.do/get'); + return response; }; -export const POST: APIRoute = async ({ request, locals }) => { +export const POST: APIRoute = async ({ locals }) => { const env = locals.runtime.env as Env; - if (!env?.COUNTER_DO) { - return new Response(JSON.stringify({ error: 'Durable Object not available' }), { - status: 500, - headers: { 'Content-Type': 'application/json' } - }); - } - - const url = new URL(request.url); - const action = url.searchParams.get('action') || 'increment'; - - const id = env.COUNTER_DO.idFromName('global-counter'); + const id = env.COUNTER_DO.idFromName('counter'); const stub = env.COUNTER_DO.get(id); - - let doRequest: Request; - switch (action) { - case 'reset': - doRequest = new Request('https://counter.do/reset'); - break; - case 'increment': - default: - doRequest = new Request('https://counter.do/increment'); - break; - } - - const response = await stub.fetch(doRequest); - const data = await response.json(); - - return new Response(JSON.stringify(data), { - headers: { 'Content-Type': 'application/json' } - }); + const response = await stub.fetch('https://counter.do/increment'); + return response; };
\ No newline at end of file diff --git a/src/pages/api/hello.ts b/src/pages/api/hello.ts deleted file mode 100644 index eba198d..0000000 --- a/src/pages/api/hello.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { APIRoute } from 'astro'; - -export const GET: APIRoute = async ({ request }) => { - const url = new URL(request.url); - const name = url.searchParams.get('name') || 'World'; - - return new Response( - JSON.stringify({ - message: `Hello, ${name}!`, - timestamp: new Date().toISOString(), - method: 'GET' - }), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } - ); -}; - -export const POST: APIRoute = async ({ request }) => { - try { - const body = await request.json(); - - return new Response( - JSON.stringify({ - message: 'Data received successfully', - received: body, - timestamp: new Date().toISOString(), - method: 'POST' - }), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } - ); - } catch (error) { - return new Response( - JSON.stringify({ - error: 'Invalid JSON', - timestamp: new Date().toISOString() - }), - { - status: 400, - headers: { - 'Content-Type': 'application/json', - }, - } - ); - } -};
\ No newline at end of file diff --git a/src/pages/index.astro b/src/pages/index.astro index 363e843..ae53624 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -7,267 +7,74 @@ <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> - <meta name="generator" content={Astro.generator} /> - <title>Astro + Cloudflare Durable Objects Demo</title> + <title>Astro + Cloudflare Durable Objects</title> <style> body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - max-width: 800px; - margin: 0 auto; - padding: 2rem; - line-height: 1.6; - background: #f8fafc; - color: #334155; - } - - .container { - background: white; - padding: 2rem; - border-radius: 12px; - box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); - } - - h1 { - color: #1e293b; - margin-bottom: 1rem; - font-size: 2.5rem; - } - - .subtitle { - color: #64748b; - margin-bottom: 2rem; - font-size: 1.1rem; + font-family: system-ui, sans-serif; + max-width: 600px; + margin: 2rem auto; + padding: 1rem; + line-height: 1.5; } - .counter-section { - background: #f1f5f9; + .counter { + text-align: center; + margin: 2rem 0; padding: 2rem; + background: #f5f5f5; border-radius: 8px; - margin: 2rem 0; - text-align: center; } - .counter-display { + .count { font-size: 3rem; font-weight: bold; - color: #3b82f6; - margin: 1rem 0; - } - - .button-group { - display: flex; - gap: 1rem; - justify-content: center; - flex-wrap: wrap; + color: #0066cc; } button { - background: #3b82f6; + background: #0066cc; color: white; border: none; - padding: 0.75rem 1.5rem; - border-radius: 6px; - font-size: 1rem; + padding: 0.5rem 1rem; + margin: 0.5rem; + border-radius: 4px; cursor: pointer; - transition: background-color 0.2s; } button:hover { - background: #2563eb; - } - - button:disabled { - background: #94a3b8; - cursor: not-allowed; - } - - .reset-btn { - background: #ef4444; - } - - .reset-btn:hover { - background: #dc2626; - } - - .status { - margin-top: 1rem; - padding: 0.75rem; - border-radius: 6px; - font-size: 0.9rem; - } - - .status.loading { - background: #fef3c7; - color: #92400e; - } - - .status.error { - background: #fee2e2; - color: #b91c1c; - } - - .status.success { - background: #dcfce7; - color: #166534; - } - - .explanation { - background: #f8fafc; - padding: 1.5rem; - border-left: 4px solid #3b82f6; - margin: 2rem 0; - } - - .explanation h3 { - margin-top: 0; - color: #1e293b; - } - - code { - background: #e2e8f0; - padding: 0.25rem 0.5rem; - border-radius: 4px; - font-family: 'Monaco', 'Consolas', monospace; - font-size: 0.9rem; + background: #0052a3; } </style> </head> <body> - <div class="container"> - <h1>Astro + Cloudflare Durable Objects</h1> - <p class="subtitle">A persistent counter demonstrating Durable Objects with Astro and Cloudflare Workers</p> - - <div class="counter-section"> - <h2>Global Counter</h2> - <div class="counter-display" id="counterValue">-</div> - <div class="button-group"> - <button id="getBtn">Get Counter</button> - <button id="incrementBtn">Increment</button> - <button id="resetBtn" class="reset-btn">Reset</button> - </div> - <div id="status" class="status" style="display: none;"></div> - </div> - - <div class="explanation"> - <h3>How it works</h3> - <p>This demo showcases a <strong>Cloudflare Durable Object</strong> that maintains a persistent counter. The counter state survives across requests, deployments, and server restarts.</p> - - <h4>API Endpoints:</h4> - <ul> - <li><code>GET /api/counter</code> - Retrieve the current counter value</li> - <li><code>POST /api/counter</code> - Increment the counter by 1</li> - <li><code>POST /api/counter?action=reset</code> - Reset the counter to 0</li> - </ul> - - <h4>Key Features:</h4> - <ul> - <li><strong>Persistent Storage:</strong> Counter value persists across deployments</li> - <li><strong>Global State:</strong> Single counter instance shared across all requests</li> - <li><strong>Edge Computing:</strong> Runs at Cloudflare's edge locations</li> - <li><strong>Real-time Updates:</strong> Immediate consistency for all operations</li> - </ul> - </div> + <h1>Astro + Cloudflare Durable Objects</h1> + <p>A simple persistent counter using Durable Objects.</p> + + <div class="counter"> + <div class="count" id="count">-</div> + <button id="getBtn">Get Count</button> + <button id="incBtn">Increment</button> </div> - + + <p><strong>How it works:</strong> The counter value is stored in a Durable Object and persists across deployments.</p> + <script> - const counterValue = document.getElementById('counterValue'); - const getBtn = document.getElementById('getBtn'); - const incrementBtn = document.getElementById('incrementBtn'); - const resetBtn = document.getElementById('resetBtn'); - const status = document.getElementById('status'); - - function showStatus(message, type = 'loading') { - status.textContent = message; - status.className = `status ${type}`; - status.style.display = 'block'; - - if (type !== 'loading') { - setTimeout(() => { - status.style.display = 'none'; - }, 3000); - } - } - - function setButtonsDisabled(disabled) { - getBtn.disabled = disabled; - incrementBtn.disabled = disabled; - resetBtn.disabled = disabled; - } - - async function getCounter() { - try { - setButtonsDisabled(true); - showStatus('Getting counter value...', 'loading'); - - const response = await fetch('/api/counter'); - const data = await response.json(); - - if (response.ok) { - counterValue.textContent = data.counter; - showStatus(`Counter retrieved: ${data.counter}`, 'success'); - } else { - throw new Error(data.error || 'Failed to get counter'); - } - } catch (error) { - showStatus(`Error: ${error.message}`, 'error'); - counterValue.textContent = 'Error'; - } finally { - setButtonsDisabled(false); - } - } - - async function incrementCounter() { - try { - setButtonsDisabled(true); - showStatus('Incrementing counter...', 'loading'); - - const response = await fetch('/api/counter', { - method: 'POST' - }); - const data = await response.json(); - - if (response.ok) { - counterValue.textContent = data.counter; - showStatus(`Counter incremented to: ${data.counter}`, 'success'); - } else { - throw new Error(data.error || 'Failed to increment counter'); - } - } catch (error) { - showStatus(`Error: ${error.message}`, 'error'); - } finally { - setButtonsDisabled(false); - } + async function getCount() { + const response = await fetch('/api/counter'); + const count = await response.text(); + document.getElementById('count').textContent = count; } - - async function resetCounter() { - try { - setButtonsDisabled(true); - showStatus('Resetting counter...', 'loading'); - - const response = await fetch('/api/counter?action=reset', { - method: 'POST' - }); - const data = await response.json(); - - if (response.ok) { - counterValue.textContent = data.counter; - showStatus('Counter reset to 0', 'success'); - } else { - throw new Error(data.error || 'Failed to reset counter'); - } - } catch (error) { - showStatus(`Error: ${error.message}`, 'error'); - } finally { - setButtonsDisabled(false); - } + + async function increment() { + const response = await fetch('/api/counter', { method: 'POST' }); + const count = await response.text(); + document.getElementById('count').textContent = count; } - - getBtn.addEventListener('click', getCounter); - incrementBtn.addEventListener('click', incrementCounter); - resetBtn.addEventListener('click', resetCounter); - - // Load initial counter value - getCounter(); + + document.getElementById('getBtn').onclick = getCount; + document.getElementById('incBtn').onclick = increment; + + getCount(); </script> </body> -</html> +</html>
\ No newline at end of file diff --git a/src/worker.ts b/src/worker.ts index 5eb9d5d..52e9f5e 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -8,46 +8,19 @@ interface Env { } class CounterDurableObject extends DurableObject<Env> { - constructor(ctx: DurableObjectState, env: Env) { - super(ctx, env); - } - async fetch(request: Request): Promise<Response> { const url = new URL(request.url); - const pathname = url.pathname; - - if (pathname === '/increment') { - const currentValue = (await this.ctx.storage.get<number>('counter')) || 0; - const newValue = currentValue + 1; - await this.ctx.storage.put('counter', newValue); - - return new Response(JSON.stringify({ - counter: newValue, - timestamp: new Date().toISOString() - }), { - headers: { 'Content-Type': 'application/json' } - }); - } - if (pathname === '/get') { - const currentValue = (await this.ctx.storage.get<number>('counter')) || 0; - return new Response(JSON.stringify({ - counter: currentValue, - timestamp: new Date().toISOString() - }), { - headers: { 'Content-Type': 'application/json' } - }); + if (url.pathname === '/get') { + const count = (await this.ctx.storage.get<number>('count')) || 0; + return new Response(count.toString()); } - if (pathname === '/reset') { - await this.ctx.storage.put('counter', 0); - return new Response(JSON.stringify({ - counter: 0, - message: 'Counter reset', - timestamp: new Date().toISOString() - }), { - headers: { 'Content-Type': 'application/json' } - }); + if (url.pathname === '/increment') { + const count = (await this.ctx.storage.get<number>('count')) || 0; + const newCount = count + 1; + await this.ctx.storage.put('count', newCount); + return new Response(newCount.toString()); } return new Response('Not found', { status: 404 }); |
