worldwide todo list: public todo list of 68 real, sourced problems (planet to street) at /projects/worldwide-todo. worldtodo schema (categories, tasks, change_requests), idempotent seed on deploy, public add/edit/delete requests with Turnstile + salted daily-rotating IP-hash rate limit, owner-only review queue (approve, edit & approve, reject) with live updates over /ws/worldtodo(-owner), JSON API, detail pages with OSM map and history; listed in projects, header, /start and sitemap
Some checks failed
Deploy production / deploy (push) Failing after 9s

This commit is contained in:
2026-10-26 01:25:59 +00:00
parent 0ee981a96b
commit 5e812271e1
58 changed files with 47689 additions and 9 deletions

View File

@@ -0,0 +1,12 @@
import { json } from '@sveltejs/kit';
import { requireOwner } from '#lib/server/owner.js';
import { queue } from '#lib/server/worldtodo/store.js';
import type { RequestHandler } from './$types';
// Owner: full requests with the current task (for diffs), stale flags and similar titles.
export const GET: RequestHandler = async (event) => {
requireOwner(event);
const raw = event.url.searchParams.get('status') ?? 'pending';
const status = (['pending', 'approved', 'rejected'] as const).find((s) => s === raw) ?? 'pending';
return json(await queue(status), { headers: { 'cache-control': 'private, no-store' } });
};

View File

@@ -0,0 +1,32 @@
import { error, json } from '@sveltejs/kit';
import { requireOwner } from '#lib/server/owner.js';
import { approveRequest } from '#lib/server/worldtodo/decide.js';
import { DecisionError } from '#lib/server/worldtodo/store.js';
import { fieldsSchema } from '#lib/server/worldtodo/validate.js';
import type { TaskFields } from '#lib/worldtodo/shared.js';
import type { RequestHandler } from './$types';
// Owner: body { note?, payload? } where payload is the full tweaked field set.
export const POST: RequestHandler = async (event) => {
requireOwner(event);
const id = Number(event.params.id);
if (!Number.isSafeInteger(id) || id <= 0) error(404, 'Not Found');
const body = ((await event.request.json().catch(() => ({}))) ?? {}) as {
note?: string;
payload?: Record<string, unknown>;
};
let tweaked: TaskFields | null = null;
if (body.payload) {
const parsed = fieldsSchema.safeParse(body.payload);
if (!parsed.success)
return json({ error: parsed.error.issues.map((i) => i.message) }, { status: 400 });
tweaked = parsed.data as TaskFields;
}
try {
const applied = await approveRequest(id, body.note, tweaked);
return json({ ok: true, ...applied });
} catch (e) {
if (e instanceof DecisionError) return json({ error: e.message }, { status: e.status });
throw e;
}
};

View File

@@ -0,0 +1,20 @@
import { error, json } from '@sveltejs/kit';
import { requireOwner } from '#lib/server/owner.js';
import { rejectRequest } from '#lib/server/worldtodo/decide.js';
import { DecisionError } from '#lib/server/worldtodo/store.js';
import type { RequestHandler } from './$types';
// Owner: body { note? }.
export const POST: RequestHandler = async (event) => {
requireOwner(event);
const id = Number(event.params.id);
if (!Number.isSafeInteger(id) || id <= 0) error(404, 'Not Found');
const body = ((await event.request.json().catch(() => ({}))) ?? {}) as { note?: string };
try {
await rejectRequest(id, body.note);
return json({ ok: true });
} catch (e) {
if (e instanceof DecisionError) return json({ error: e.message }, { status: e.status });
throw e;
}
};