From 8b4a54e7af04a52f29ded35f826b0cebf6d6fd80 Mon Sep 17 00:00:00 2001 From: Matias Kumpulainen Date: Thu, 12 Feb 2026 11:24:40 +0200 Subject: [PATCH 1/3] feat: add request country to completions --- src/lib/server/db/schema.ts | 1 + src/lib/server/helpers.ts | 5 +++++ src/routes/api/stats/+server.ts | 15 +++++++-------- 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 src/lib/server/helpers.ts diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts index 55978e2..b3ab30b 100644 --- a/src/lib/server/db/schema.ts +++ b/src/lib/server/db/schema.ts @@ -7,6 +7,7 @@ export const puzzleCompletionTable = pgTable( userId: text('user_id'), puzzleId: text('puzzle_id').notNull(), numMoves: integer('num_moves').notNull(), + country: text('country').notNull().default('XX'), attempts: integer('attempts').notNull().default(1), timestamp: timestamp('timestamp', { withTimezone: true }).notNull().defaultNow() }, diff --git a/src/lib/server/helpers.ts b/src/lib/server/helpers.ts new file mode 100644 index 0000000..eb14d77 --- /dev/null +++ b/src/lib/server/helpers.ts @@ -0,0 +1,5 @@ +import type { RequestEvent } from '@sveltejs/kit'; + +export const getRequestCountry = (e: RequestEvent) => { + return e.request.headers.get('CF-IPCountry') || 'XX'; +}; diff --git a/src/routes/api/stats/+server.ts b/src/routes/api/stats/+server.ts index 8b219ca..6448db1 100644 --- a/src/routes/api/stats/+server.ts +++ b/src/routes/api/stats/+server.ts @@ -1,6 +1,7 @@ import { db } from '$lib/server/db'; import { getPuzzleStatistics } from '$lib/server/db/handlers/stats'; import { puzzleCompletionTable } from '$lib/server/db/schema'; +import { getRequestCountry } from '$lib/server/helpers'; import { cached } from '$lib/server/kv'; import { getPlatform } from '$lib/server/miniflare'; import { Dir } from '$lib/stores/grid'; @@ -63,18 +64,15 @@ export const POST = endpoint({ eq(puzzleCompletionTable.userId, uid) ); - console.log(verified); - // TODO: maybe use transaction? const [existing] = await db.select().from(puzzleCompletionTable).where(puzzleIdAndUserId); - console.log({ existing }); - if (!existing) { await db.insert(puzzleCompletionTable).values({ puzzleId: puzzle.id, numMoves: verified.moves, - userId: uid + userId: uid, + country: getRequestCountry(e) }); console.log('inserted new', { @@ -99,7 +97,7 @@ export const POST = endpoint({ console.log('inserted better', { numMoves: verified.moves, timestamp: new Date(), - attempts: existing.attempts + 1 // increase attempts + attempts: existing.attempts + 1 }); return; @@ -107,7 +105,7 @@ export const POST = endpoint({ await db .update(puzzleCompletionTable) - .set({ attempts: existing.attempts + 1 }) // increase attempts always + .set({ attempts: existing.attempts + 1 }) // increase attempts even if result is worse .where(puzzleIdAndUserId); console.log('increased attempts'); @@ -117,7 +115,8 @@ export const POST = endpoint({ await db.insert(puzzleCompletionTable).values({ puzzleId: puzzle.id, numMoves: verified.moves, - userId: null + userId: null, + country: getRequestCountry(e) }); } }), From 3ae7c3b2165f4c521ee4ab0d1cfed8586d879934 Mon Sep 17 00:00:00 2001 From: Matias Kumpulainen Date: Thu, 12 Feb 2026 11:25:23 +0200 Subject: [PATCH 2/3] chore: add migration for country column --- drizzle/0008_sticky_harrier.sql | 1 + drizzle/meta/0008_snapshot.json | 108 ++++++++++++++++++++++++++++++++ drizzle/meta/_journal.json | 7 +++ 3 files changed, 116 insertions(+) create mode 100644 drizzle/0008_sticky_harrier.sql create mode 100644 drizzle/meta/0008_snapshot.json diff --git a/drizzle/0008_sticky_harrier.sql b/drizzle/0008_sticky_harrier.sql new file mode 100644 index 0000000..ea62949 --- /dev/null +++ b/drizzle/0008_sticky_harrier.sql @@ -0,0 +1 @@ +ALTER TABLE "puzzle_completions" ADD COLUMN "country" text DEFAULT 'XX' NOT NULL; \ No newline at end of file diff --git a/drizzle/meta/0008_snapshot.json b/drizzle/meta/0008_snapshot.json new file mode 100644 index 0000000..9cca149 --- /dev/null +++ b/drizzle/meta/0008_snapshot.json @@ -0,0 +1,108 @@ +{ + "id": "575abe9f-65f9-42e8-b6f7-9e715c4b0ad7", + "prevId": "81ed1aad-013c-4677-a86b-123dc69df522", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.puzzle_completions": { + "name": "puzzle_completions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "puzzle_id": { + "name": "puzzle_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "num_moves": { + "name": "num_moves", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'XX'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "puzzle_completion_puzzle_id_index": { + "name": "puzzle_completion_puzzle_id_index", + "columns": [ + { + "expression": "puzzle_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "puzzle_completion_id_and_user_id_index": { + "name": "puzzle_completion_id_and_user_id_index", + "columns": [ + { + "expression": "puzzle_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index a6dce4f..dabfc0d 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -57,6 +57,13 @@ "when": 1735947892500, "tag": "0007_abnormal_magus", "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1770888296796, + "tag": "0008_sticky_harrier", + "breakpoints": true } ] } \ No newline at end of file From 75631457dee7899ffb12d24f58d034203fea7554 Mon Sep 17 00:00:00 2001 From: Matias Kumpulainen Date: Thu, 12 Feb 2026 11:27:24 +0200 Subject: [PATCH 3/3] chore: run browserlist update --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e35f165..d74ad64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4591,9 +4591,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001690", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", - "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true, "funding": [ { @@ -16557,9 +16557,9 @@ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, "caniuse-lite": { - "version": "1.0.30001690", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", - "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true }, "capnp-ts": {