ahh I see WAE is only 0.25 per mil writes
ahh I see WAE is only 0.25 per mil writes
@lumenize/proxy-fetch which offloads fetch requests to a Worker via Queues.
... dropdown. I reported as soon as I saw it. Someone at Cloudflare deleted soon after my report.Storage gone, the object lives forever thoughI have some DOs at least a month old which say they have no storage that still are "around" in CF's Durable Objects Objects list api.

@lumenize/proxy-fetchimport { DurableObject } from "cloudflare:workers"
export default {
async fetch(request, env, ctx): Promise<Response> {
const stub = env.MY_DURABLE_OBJECT.getByName("foo");
if (request.url.includes('/subscribe')) return stub.subscribe(request)
else if (request.url.includes('/message')) return await stub.message(request)
else return new Response(html, {headers: {'content-type': 'text/html'}})
},
} satisfies ExportedHandler<Env>const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Durable Object SSE Test</title>
</head>
<body>
<h1>New Durable Object SSE Test</h1>
<button id="send">Send Message</button>
<div id="log" style="margin-top: 1em; white-space: pre;"></div>
<script>
const log = (msg) => {
const el = document.getElementById('log');
el.textContent += msg + "\\n";
};
// Subscribe to the stream
const es = new EventSource('/subscribe');
es.onopen = () => log('[connected]');
es.onerror = (err) => log('[error] ' + JSON.stringify(err));
es.onmessage = (e) => log('[message] ' + e.data);
// Send a message to broadcast
document.getElementById('send').addEventListener('click', async () => {
const res = await fetch('/message', {
method: 'POST',
body: JSON.stringify({ time: new Date().toISOString() }),
headers: { 'Content-Type': 'application/json' }
});
log('[sent] ' + (await res.text()));
});
</script>
</body>
</html>
`export class MyDurableObject extends DurableObject<Env> {
encoder = new TextEncoder()
writers: Map<string, WritableStreamDefaultWriter<Uint8Array>> = new Map()
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
}
subscribe(request: Request): Response {
const stream = new IdentityTransformStream()
const writer = stream.writable.getWriter()
const id = crypto.randomUUID()
this.writers.set(id, writer)
const headers = {
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': request.headers.get('Origin')!, // secured @ worker (outside world portal)
}
// initial comment
writer.write(this.encoder.encode(`: connected\n\n`))
// clean up on abort
request.signal.addEventListener('abort', () => {
writer.close()
this.writers.delete(id)
})
return new Response(stream.readable, { headers })
}
async message(request: Request): Promise<Response> {
const data = await request.text()
for (const [_, writer] of this.writers) {
writer.write(this.encoder.encode(`data: ${data}\n\n`))
}
return new Response('good', {
status: 200,
headers: {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Origin': request.headers.get('Origin')!,
},
})
}
}