Skip to content

Commit d50b809

Browse files
KV bindings
1 parent 7f28234 commit d50b809

File tree

11 files changed

+13839
-11514
lines changed

11 files changed

+13839
-11514
lines changed

package-lock.json

Lines changed: 2901 additions & 11486 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
"i18n": "npx paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide"
2020
},
2121
"devDependencies": {
22+
"@cloudflare/types": "^7.0.0",
23+
"@cloudflare/workers-types": "^4.20251224.0",
2224
"@eslint/compat": "^1.4.0",
2325
"@eslint/js": "^9.36.0",
2426
"@inlang/paraglide-js": "^2.3.2",
2527
"@sveltejs/adapter-cloudflare": "^7.2.4",
26-
"@sveltejs/adapter-vercel": "^6.2.0",
2728
"@sveltejs/kit": "^2.43.2",
2829
"@sveltejs/vite-plugin-svelte": "^6.2.0",
2930
"@tailwindcss/typography": "^0.5.18",
@@ -47,7 +48,6 @@
4748
"wrangler": "^4.53.0"
4849
},
4950
"dependencies": {
50-
"@vercel/analytics": "^1.6.0",
5151
"cloc": "^2.6.0-cloc",
5252
"remixicon": "^4.7.0"
5353
}

src/app.d.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1+
import type { KVNamespace } from '@cloudflare/workers-types';
2+
import type { SvelteMap } from 'svelte/reactivity';
3+
14
// See https://svelte.dev/docs/kit/types#app.d.ts
25
// for information about these interfaces
36
declare global {
47
namespace App {
58
// interface Error {}
6-
// interface Locals {}
9+
interface Locals {
10+
localmap: SvelteMap<string, number>;
11+
prodmap: KVNamespace<string>;
12+
dev: Boolean;
13+
}
714
// interface PageData {}
815
// interface PageState {}
9-
// interface Platform {}
16+
interface Platform {
17+
env: {
18+
CONCURRENCY: KVNamespace<string>;
19+
}
20+
}
1021
}
1122
}
1223

src/hooks.server.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { paraglideMiddleware } from '$lib/paraglide/server';
33
import { sequence } from '@sveltejs/kit/hooks';
44
import { isLimited } from '$lib/server/rate';
55
import { error } from '@sveltejs/kit';
6+
import { env } from '$env/dynamic/private';
7+
import { localConcurrencyMap } from '$lib/server/concurrency';
8+
import type { KVNamespace } from '@cloudflare/workers-types';
69

710
const handleParaglide: Handle = ({ event, resolve }) =>
811
paraglideMiddleware(event.request, ({ request, locale }) => {
@@ -37,4 +40,19 @@ const handleRateLimit: Handle = async ({ event, resolve }) => {
3740
return resolve(event);
3841
};
3942

40-
export const handle: Handle = sequence(handleParaglide, handleSecurity, handleRateLimit);
43+
const handleMap: Handle = async ({ event, resolve }) => {
44+
if(env.DEV == 'true') {
45+
console.log("Using local map");
46+
event.locals.localmap = localConcurrencyMap;
47+
event.locals.dev = true;
48+
}
49+
else {
50+
console.log("Using KV binding map");
51+
event.locals.prodmap = (event.platform?.env.CONCURRENCY as KVNamespace<string>);
52+
event.locals.dev = false;
53+
}
54+
55+
return resolve(event);
56+
}
57+
58+
export const handle: Handle = sequence(handleMap, handleParaglide, handleSecurity, handleRateLimit);
Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,57 @@
11
import { BEAT_FREQUENCY } from '$lib';
2+
import type { RequestEvent } from '@sveltejs/kit';
23
import { SvelteMap } from 'svelte/reactivity';
4+
import type { KVNamespace } from '@cloudflare/workers-types';
35

46
export const LAST_BEAT_AGE_FOR_ACTIVE = Math.trunc(BEAT_FREQUENCY * 1.25);
57

6-
const concurrencyMap: SvelteMap<string, number> = new SvelteMap();
8+
export let localConcurrencyMap: SvelteMap<string, number> = new SvelteMap();
79

8-
export const containsId = (key: string) => {
9-
return concurrencyMap.has(key);
10+
export const containsId = async (event: RequestEvent, key: string) => {
11+
if (event.locals.dev) return event.locals.localmap.has(key);
12+
else return ((await event.locals.prodmap.get(key)) != null);
1013
};
1114

12-
export const updateId = (key: string) => {
13-
concurrencyMap.set(key, Date.now());
15+
export const updateId = async (event: RequestEvent, key: string) => {
16+
if (event.locals.dev) event.locals.localmap.set(key, Date.now());
17+
else await event.locals.prodmap.put(key, String(Date.now()));
1418
};
1519

16-
export const removeOld = (key: string) => {
17-
concurrencyMap.delete(key);
20+
export const removeOld = async (event: RequestEvent, key: string) => {
21+
if (event.locals.dev) event.locals.localmap.delete(key);
22+
else await event.locals.prodmap.delete(key);
1823
};
1924

20-
export const getActive = () => {
25+
export const getActive = async (event: RequestEvent) => {
2126
const now = Date.now();
22-
concurrencyMap.forEach((value, key, map) => {
23-
if (now - value > LAST_BEAT_AGE_FOR_ACTIVE) {
24-
map.delete(key);
25-
}
26-
});
2727

28-
return concurrencyMap.size;
28+
if (event.locals.dev) {
29+
event.locals.localmap.forEach((value, key, map) => {
30+
if (now - value > LAST_BEAT_AGE_FOR_ACTIVE) {
31+
map.delete(key);
32+
}
33+
});
34+
return event.locals.localmap.size;
35+
}
36+
else {
37+
let keys = [];
38+
let list = undefined;
39+
do {
40+
list = await event.locals.prodmap.list({
41+
cursor: list == undefined ? undefined : list.cursor
42+
});
43+
keys.push(...list.keys);
44+
}
45+
while (!list.list_complete);
46+
let removed = 0;
47+
for (let i = 0; i < keys.length; i++) {
48+
const key = keys[i].name;
49+
const value = parseInt(await event.locals.prodmap.get(key) as string);
50+
if (now - value > LAST_BEAT_AGE_FOR_ACTIVE) {
51+
await event.locals.prodmap.delete(key);
52+
removed++;
53+
}
54+
}
55+
return list.keys.length - removed;
56+
}
2957
};

src/routes/analytics/+server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import { json } from '@sveltejs/kit';
33

44
export const POST = async (event) => {
55
let sessionId = event.cookies.get('sessionid');
6-
if (!sessionId || !containsId(sessionId)) {
6+
if (!sessionId || !(await containsId(event, sessionId))) {
77
const uuid = crypto.randomUUID();
88
event.cookies.set('sessionid', uuid, { path: '/' });
99
sessionId = uuid;
1010
console.log('New user');
1111
}
1212

13-
updateId(sessionId);
13+
await updateId(event, sessionId);
1414
//console.log("User heartbeat");
1515

1616
return json({});

src/routes/count/+server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { asyncDelay } from '$lib';
22
import { getActive } from '$lib/server/concurrency/index.js';
33
import { produce } from 'sveltekit-sse';
44

5-
export const POST = async () => {
5+
export const POST = async (event) => {
66
return produce(
77
async (payload) => {
88
while (true) {
9-
payload.emit('users', String(getActive()));
10-
await asyncDelay(100);
9+
payload.emit('users', String(await getActive(event)));
10+
await asyncDelay(500);
1111
}
1212
},
1313
{

src/routes/goodbye/+server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import { error, json } from '@sveltejs/kit';
55

66
export const POST = async (event) => {
77
const sessionId = event.cookies.get('sessionid');
8-
if (!sessionId || !containsId(sessionId)) {
8+
if (!sessionId || !(await containsId(event, sessionId))) {
99
return error(404);
1010
}
1111

12-
removeOld(sessionId);
12+
await removeOld(event, sessionId);
1313
event.cookies.delete('sessionid', { path: '/' });
1414

1515
console.log('User left');

src/routes/modals/SettingsModal.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
let { settingsModal = $bindable(false), data } = $props();
1010
1111
let hasDifferentTime = $state(false);
12-
let hasPlaylist = $state(data.playlist.length > 0);
13-
let snowAmount = $state(data.snow);
12+
let hasPlaylist = $derived(data.playlist.length > 0);
13+
let snowAmount = $derived(data.snow);
1414
</script>
1515

1616
<Modal bind:showModal={settingsModal}>

0 commit comments

Comments
 (0)